How can i run a loop procedure in background? - delphi

I created a procedure to update an SQLite DB. The procedure runs in a loop until the list is finished. The problem is, when I run the procedure, the program stops responding
How can I run this procedure in the background, without crashing the program?
procedure TForm1.domainupdate;
var
I, J, K, svr: integer ;
domain1, domain2: string ;
expiry: string;
sl: TStringList;
fs: TFormatSettings;
s: string;
dt: TDatetime;
ds : TFormatSettings;
memo : tmemo;
begin
DM.Qdomains.First;
while not DM.Qdomains.Eof do begin
for J := Length (DM.Qdomains.FieldByName('domain').AsString) downto 2 do begin
if DM.Qdomains.FieldByName('domain').AsString [J] = '.' then begin // search host.co.uk
if domain1 = '' then
domain1 := Copy (DM.Qdomains.FieldByName('domain').AsString, J + 1, 99) + IcsSpace
// found uk
else begin
domain2 := Copy (DM.Qdomains.FieldByName('domain').AsString, J + 1, 99) + IcsSpace ;
// found co.uk
Break ;
end;
end;
end;
FWhoisServers := TStringList.Create;
for I := 0 to Length(WhoisNames) - 1 do
FWhoisServers.add(WhoisNames[I]);
FHost := 'whois.ripe.net' ;
K := -1 ;
if FWhoisServers.Count > 0 then begin
for I := 0 to FWhoisServers.Count - 1 do
begin
if (Pos (domain1, FWhoisServers [I]) = 1) then K := I ;
if (Pos (domain2, FWhoisServers [I]) = 1) then
begin
K := I ;
break ;
end ;
end;
if K >= 0 then begin
J := Pos (IcsSpace, FWhoisServers [K]) ;
end;
end;
if K < 0 then begin
end;
IdWhois1.host := Copy (FWhoisServers [K], J + 1, 99) ;
Memo:=TMemo.Create(nil);
Memo.Visible:=false;
memo.Lines.text := IdWhois1.WhoIs(DM.Qdomains.FieldByName('domain').AsString);
begin
sl := TStringList.Create;
try
sl.Assign(Memo.Lines);
for I := 0 to sl.Count-1 do begin
sl[I] := TrimLeft(sl[I]);
end;
sl.NameValueSeparator := ':';
for I := Low(FieldNames) to High(FieldNames) do begin
expiry := Trim(sl.Values[FieldNames[I]]);
if expiry <> '' then
Break;
end;
finally
sl.Free;
end;
if expiry = '' then
exit
else
s := expiry;
fs := TFormatSettings.Create;
fs.DateSeparator := '-';
fs.TimeSeparator := ':';
fs.shortdateformat := 'yyyy-mm-dd';
fs.ShortTimeFormat := 'hh:nn:ss';
dt := StrToDatetime(s, fs);
ds.DateSeparator := '/';
ds.TimeSeparator := ':';
ds.ShortDateFormat := 'dd/mm/yyyy';
ds.longtimeFormat := 'hh:mm:ss';
end;
end;
//********************************************************
//********************************************************
//if edit1.text <> '' then DM.Qdomains.Open;
DM.Qdomains.Edit;
DM.Qdomains.FieldByName('domain').AsString :=
DM.Qdomains.FieldByName('domain').AsString;
DM.Qdomains.FieldByName('expiry').AsString := datetimetostr(dt, ds);
DM.Qdomains.FieldByName('whois').AsString :=
IdWhois1.WhoIs(DM.Qdomains.FieldByName('domain').AsString);
DM.Qdomains.FieldByName('update').AsString := DatetimeToStr(now);
DM.Qdomains.Post;
DM.Qdomains.Next;
end;

Move the logic into a separate worker thread, synchronizing with the main UI thread only when absolutely needed (ie, to show the results). You need to do this anyway if you ever plan on running this code on Android, since you can't perform network operations on the main UI thread.
Also, get rid of the TMemo that the code is creating, it is not needed at all. All you are using it for is to parse the Whois result into a TStringList, which you can do directly. And, you are leaking the TMemo and never showing it to the user anyway.
Try something more like this:
procedure TForm1.DomainUpdate;
var
I, J, K: Integer;
domain, domain1, domain2, host, whois, expiry: string;
sl: TStringList;
fs, ds: TFormatSettings;
dt: TDatetime;
begin
// TODO: perform the DB query here instead of in the main thread...
DM.Qdomains.First;
while not DM.Qdomains.Eof do begin
domain := DM.Qdomains.FieldByName('domain').AsString;
domain1 := '';
domain2 := '';
for J := Length(domain) downto 2 do begin
if domain[J] = '.' then begin // search host.co.uk
if domain1 = '' then
domain1 := Copy(domain, J + 1, MaxInt) + IcsSpace
// found uk
else begin
domain2 := Copy(domain, J + 1, MaxInt) + IcsSpace;
// found co.uk
Break;
end;
end;
end;
FWhoisServers := TStringList.Create;
try
for I := 0 to Length(WhoisNames) - 1 do
FWhoisServers.Add(WhoisNames[I]);
host := 'whois.ripe.net';
K := -1;
if FWhoisServers.Count > 0 then begin
for I := 0 to FWhoisServers.Count - 1 do
begin
if (Pos(domain1, FWhoisServers[I]) = 1) then K := I;
if (Pos(domain2, FWhoisServers[I]) = 1) then
begin
K := I;
Break;
end;
end;
if K >= 0 then begin
J := Pos(IcsSpace, FWhoisServers[K]);
host := Copy(FWhoisServers[K], J + 1, MaxInt);
end;
end;
IdWhois1.Host := host;
finally
FWhoisServers.Free;
end;
expiry := '';
sl := TStringList.Create;
try
whois := IdWhois1.WhoIs(domain);
sl.Text := whois;
for I := 0 to sl.Count-1 do begin
sl[I] := TrimLeft(sl[I]);
end;
sl.NameValueSeparator := ':';
for I := Low(FieldNames) to High(FieldNames) do begin
expiry := Trim(sl.Values[FieldNames[I]]);
if expiry <> '' then
Break;
end;
finally
sl.Free;
end;
if expiry <> '' then begin
fs := TFormatSettings.Create;
fs.DateSeparator := '-';
fs.TimeSeparator := ':';
fs.ShortDateFormat := 'yyyy-mm-dd';
fs.ShortTimeFormat := 'hh:nn:ss';
dt := StrToDateTime(expiry, fs);
ds := TFormatSettings.Create;
ds.DateSeparator := '/';
ds.TimeSeparator := ':';
ds.ShortDateFormat := 'dd/mm/yyyy';
ds.LongTimeFormat := 'hh:mm:ss';
DM.Qdomains.Edit;
try
DM.Qdomains.FieldByName('domain').AsString := domain;
DM.Qdomains.FieldByName('expiry').AsString := DateTimeToStr(dt, ds);
DM.Qdomains.FieldByName('whois').AsString := whois;
DM.Qdomains.FieldByName('update').AsString := DateTimeToStr(Now);
DM.Qdomains.Post;
except
DM.Qdomains.Cancel;
raise;
end;
end;
DM.Qdomains.Next;
end;
end;
...
TThread.CreateAnonymousThread(DomainUpdate).Start;

Related

How to load TTreeView items from database along with its items image index

I have saved my TreeView inside my DataBase by using the next :
var
BlobField :TField;
Query:TADOQuery;
Stream:TStream;
...
try
Query.SQL.Text := 'Select TOP(1) * From MyTable';
DBQueryConnect(Query); // I used this Procedure to connect the Query to the database
try
Query.First;
Query.Edit;
try
BlobField := Query.FieldByName('MyField') as TField;
Stream := Query.CreateBlobStream(BlobField, bmWrite);
try
MyTreeView.SaveToStream(Stream,TEncoding.UTF8);
finally
Stream.Free;
end;
Query.Post;
except
Query.Cancel;
raise;
end;
finally
Query.Close;
end;
finally
Query.Free;
end;
end;
and I loaded back the TTreeView form the DataBase by using the next :
...
var
Query:TADOQuery;
Stream:TStream;
begin
Query:=TADOQuery.Create(Self);
try
Query.SQL.Add('Select * From MyTable') ;
DBQueryConnect(Query);
Query.First;
Stream:=Query.CreateBlobStream(Query.FieldByName('MyField'), bmread);
MyTreeView.LoadFromStream(Stream);
Stream.Free;
finally
Query.Free;
end;
how can I retrive the imageindex for my TreeView items from the saved data ..
Thank you .
Perharps we can modify exsisting SaveTreeToStream and LoadTreeFromStream like this :
function GetBufStart(Buffer,idxSeparator: string; var Level,ImageIndex: Integer): string;
var
Pos: Integer;
sidx:String;
begin
Pos := 1;
Level := 0;
ImageIndex := -1;
while (CharInSet(Buffer[Pos], [' ', #9])) do
begin
Inc(Pos);
Inc(Level);
end;
Result := Copy(Buffer, Pos, Length(Buffer) - Pos + 1);
//Check Image Index
pos:=System.SysUtils.AnsiPos(idxSeparator,Result);
if Pos>0 then begin
sidx:=copy(result,Pos + Length(idxSeparator), length(result) - Pos + 1);
ImageIndex := StrToIntDef(sidx,-1);
Result := Copy(Result, 1, Pos - 1);
end;
end;
procedure LoadTreeFromStream(Nodes:TTreeNodes; Stream:TStream; Encoding:TEncoding; idxSeparator:String='|||');
var
List: TStringList;
ANode, NextNode: TTreeNode;
ALevel, i, ImageIndex: Integer;
CurrStr: string;
begin
List := TStringList.Create;
Nodes.BeginUpdate;
try
try
Nodes.Clear;
List.LoadFromStream(Stream, Encoding);
ANode := nil;
for i := 0 to List.Count - 1 do
begin
CurrStr := GetBufStart(PChar(List[i]), idxSeparator, ALevel, ImageIndex);
if ANode = nil then
ANode := Nodes.AddChild(nil, CurrStr)
else if ANode.Level = ALevel then
ANode := Nodes.AddChild(ANode.Parent, CurrStr)
else if ANode.Level = (ALevel - 1) then
ANode := Nodes.AddChild(ANode, CurrStr)
else if ANode.Level > ALevel then
begin
NextNode := ANode.Parent;
while NextNode.Level > ALevel do
NextNode := NextNode.Parent;
ANode := Nodes.AddChild(NextNode.Parent, CurrStr);
end
else raise Exception.CreateFmt('Invalid level (%d) for item "%s"', [ALevel, CurrStr]);
ANode.ImageIndex:=ImageIndex;
end;
finally
Nodes.EndUpdate;
List.Free;
end;
except
Nodes.Owner.Invalidate; // force repaint on exception
raise;
end;
end;
procedure SaveTreeToStream(Nodes:TTreeNodes; Stream:Tstream; Encoding:TEncoding; idxSeparator:String='|||');
const
TabChar = #9;
EndOfLine = #13#10;
var
I: Integer;
ANode: TTreeNode;
NodeStr: TStringBuilder;
Buffer, Preamble: TBytes;
begin
if Nodes.Count > 0 then
begin
if Encoding = nil then
Encoding := TEncoding.Default;
//Buffer := Encoding.GetBytes('');
Preamble := Encoding.GetPreamble;
if Length(Preamble) > 0 then
Stream.WriteBuffer(Preamble{$IFNDEF CLR}[0]{$ENDIF}, Length(Preamble));
NodeStr := TStringBuilder.Create(1024);
try
ANode := Nodes[0];
while ANode <> nil do
begin
NodeStr.Length := 0;
for I := 0 to ANode.Level - 1 do
NodeStr.Append(TabChar);
NodeStr.Append(ANode.Text);
NodeStr.Append(idxSeparator);
NodeStr.Append(ANode.ImageIndex);
NodeStr.Append(EndOfLine);
Buffer := Encoding.GetBytes(NodeStr.ToString);
Stream.Write(Buffer{$IFNDEF CLR}[0]{$ENDIF}, Length(Buffer));
ANode := ANode.GetNext;
end;
finally
NodeStr.Free;
end;
end;
end;
You can replace
MyTreeView.SaveToStream(Stream,TEncoding.UTF8);
with
SaveTreeToStream(MyTreeView.Items,Stream,TEncoding.UTF8);
and MyTreeView.LoadFromStream(Stream); with LoadTreeFromStream(MyTreeView.Items,Stream,TEncoding.UTF8);

epson code misread as string output

Printing using Epson codes in Delphi Tokyo.
Function PrintRawData (built in to Winapi.Winspool library) appears to misread codes like 'ESC C' or 'ESC #' and prints 'C' and '#' instead of the prompts associated with said codes (Select page length & Initialise Printer).
procedure TFrmPrint.PageLen(hPrn : THandle); // Page length in Inches
var
Commalist : Array[1..20] of SmallInt;
istart, icomma, i : SmallInt;
ss, cr : UTF8String;
def : UTF8String;
Data : Array [0..255] of AnsiChar;
begin
ss := '';
cr := ' ';
cr[1] := #13; cr[2] := #10;
if not DM2.Q_PRNGen.Locate('PrAction','PAGELENIN',[loCaseInsensitive]) then
begin
ShowMessage('PAGELENIN Action not coded for Printer');
exit;
end;
ss := Trim(DM2.Q_PRNGen.Fields.FieldByName('ESCCODE').AsString);
icomma := 0;
istart := 1;
for i:=1 to Length(ss) do
begin
if ss[i] = ',' then
begin
inc(icomma);
Commalist[icomma] := StrToIntDef(Copy(ss,istart,i-istart),0);
istart := i + 1;
end;
end;
inc(icomma);
i := Length(ss);
Commalist[icomma] := StrToIntDef(Copy(ss,istart,i-istart+1),0);
def := '';
for i:=1 to icomma do
begin
def := def + ' ';
def[i] := AnsiChar(CommaList[i]);
// def := Def + IntToHex(CommaList[i],1);
end;
// ss := def + cr;
ss := def;
for i:=1 to Length(ss) do Data[i-1] := AnsiChar(ss[i]);
if frmPrint.PrintRawData(hPrn,#Data,Length(ss)) < 0 then
begin
ShowMessage('PrintRawData Failed');
frmPrint.EndRawPrintPage(hPrn);
frmPrint.EndRawPrintJob(hPrn);
exit;
end;
end;
It is under my assumption that the error lies within PrintRawData.
PrintRawData is listed here:
function TFrmPrint.PrintRawData(hPrn : THandle; Buffer : pointer; NumBytes : SpoolInt) : integer;
var
BytesWritten : DWORD;
begin
if NumBytes = 0 then
begin
Result := 1;
exit;
end;
if not WritePrinter(hPrn, Buffer, NumBytes, BytesWritten) then
begin
Result := -1;
exit;
end;
if NumBytes <> BytesWritten then
begin
Result := -1;
exit;
end;
Result := 1;
end;

Delphi changing Chars in string - missunderstood behavior - XE3

I'm doing a code on some kind of encoder/decoder, and can't figure out the strange behavior for more than 2 days now... I hope someone might understand and explain to me why is happening, whatever it is...
Here's the main code, which does the thing (I removed the form's info, buttons etc, just the core to avoid garbage)
unit Encoder;
//
interface
//
var
Enc : array [1..71] of Record
Char: Char;
Encr: string;
Enc: array [1..5] of Char;
end;
EncodeBuffer: TStringList;
implementation
{$R *.dfm}
procedure TEncrypter.Encode;
var
s, t, u, h, h2, h3, h4, h5: integer;
begin
s := EncodeBuffer.Count;
h := 0;
h2 := 1;
h3 := 2;
h4 := 3;
h5 := 4;
while h < s do
begin
t := EncodeBuffer.Strings[h].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h] := EncodeBuffer.Strings[h].Replace(EncodeBuffer.Strings[h].Chars[u], EncodeChar(EncodeBuffer.Strings[h].Chars[u], 1));
end;
end;
h := h + 5;
end;
while h2 < s do
begin
t := EncodeBuffer.Strings[h2].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h2] := EncodeBuffer.Strings[h2].Replace(EncodeBuffer.Strings[h2].Chars[u], EncodeChar(EncodeBuffer.Strings[h2].Chars[u], 2));
end;
end;
h2 := h2 + 5;
end;
while h3 < s do
begin
t := EncodeBuffer.Strings[h3].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h3] := EncodeBuffer.Strings[h3].Replace(EncodeBuffer.Strings[h3].Chars[u], EncodeChar(EncodeBuffer.Strings[h3].Chars[u], 3));
end;
end;
h3 := h3 + 5;
end;
while h4 < s do
begin
t := EncodeBuffer.Strings[h4].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h4] := EncodeBuffer.Strings[h4].Replace(EncodeBuffer.Strings[h4].Chars[u], EncodeChar(EncodeBuffer.Strings[h4].Chars[u], 4));
end;
end;
h4 := h4 + 5;
end;
while h5 < s do
begin
t := EncodeBuffer.Strings[h5].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h5] := EncodeBuffer.Strings[h5].Replace(EncodeBuffer.Strings[h5].Chars[u], EncodeChar(EncodeBuffer.Strings[h5].Chars[u], 5));
end;
end;
h5 := h5 + 5;
end;
end;
procedure TEncrypter.Decode;
var
s, t, u, h, h2, h3, h4, h5: integer;
begin
s := EncodeBuffer.Count;
h := 0;
h2 := 1;
h3 := 2;
h4 := 3;
h5 := 4;
while h < s do
begin
t := EncodeBuffer.Strings[h].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h] := EncodeBuffer.Strings[h].Replace(EncodeBuffer.Strings[h].Chars[u], DecodeChar(EncodeBuffer.Strings[h].Chars[u], 1));
end;
end;
h := h + 5;
end;
while h2 < s do
begin
t := EncodeBuffer.Strings[h2].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h2] := EncodeBuffer.Strings[h2].Replace(EncodeBuffer.Strings[h2].Chars[u], DecodeChar(EncodeBuffer.Strings[h2].Chars[u], 2));
end;
end;
h2 := h2 + 5;
end;
while h3 < s do
begin
t := EncodeBuffer.Strings[h3].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h3] := EncodeBuffer.Strings[h3].Replace(EncodeBuffer.Strings[h3].Chars[u], DecodeChar(EncodeBuffer.Strings[h3].Chars[u], 3));
end;
end;
h3 := h3 + 5;
end;
while h4 < s do
begin
t := EncodeBuffer.Strings[h4].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h4] := EncodeBuffer.Strings[h4].Replace(EncodeBuffer.Strings[h4].Chars[u], DecodeChar(EncodeBuffer.Strings[h4].Chars[u], 4));
end;
end;
h4 := h4 + 5;
end;
while h5 < s do
begin
t := EncodeBuffer.Strings[h5].Length;
if t > 0 then
begin
for u := 0 to t-1 do
begin
EncodeBuffer.Strings[h5] := EncodeBuffer.Strings[h5].Replace(EncodeBuffer.Strings[h5].Chars[u], DecodeChar(EncodeBuffer.Strings[h5].Chars[u], 5));
end;
end;
h5 := h5 + 5;
end;
end;
function TEncrypter.EncodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
for t := 1 to 71 do
begin
if Sign = enc[t].Char then
begin
Result := enc[t].Enc[Encoder];
Break;
end
else
Result := Sign;
end;
end;
function TEncrypter.DecodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
for t := 1 to 71 do
begin
if Sign = enc[t].Enc[Encoder] then
begin
Result := enc[t].Char;
Break;
end
else
Result := Sign;
end;
end;
I have an Enc array created on FormCreate event, which fills Enc[1 to 71].Char and Enc[1 to 71].Enc[1 to 5] with random char order;
The code is made (or at least should be) so that it uses different encode list from array for each 5th line (line 1 enc[x].enc[1], line 2 enc[x].enc[2], and then line 5 enc[x].enc[5], and line 6 back to enc[x].enc[1] and so on...)
If I encode 5 lines from Memo1, which are:
Memo1
Memo2
Memo3
Memo4
Memo5
I get some random words with 5 chars each, however when decoding it back, I get returned
Memo1
Memo2
memo3
Memo4
Memo5
(notice the lower m letter in 3rd line);
If I then encode this again, I get the exact same encoded stringlist as in the first case, only that here, the 3rd line's 3rd char! (wtf?) is changed with the same as the firstone is.
so, for Memo3 I get q7M0e, and for memo3 I get q7q0e, which makes no sense to me, as the position of a char should be the same, as far as I understand by the code.
Is there anything I'm missing here, noticable in the code above??
Comment if there's a need for me to paste the complete form's (unit's) code and exe example, I'll give it on a web and link to that...
Edit:
Here's the "key", by which I'm encoding/decoding: http://txt.do/128b
There are several problems with your approach.
One problem is with your use of String.Replace(), which replaces ALL occurrences of one Char with another Char. Once you replace a given Char, you can potentially replace that same index with a different value later on in your loops, thus trashing your data while you are looping.
Another problem is your decoding logic. You are allowing each un-encoded Char to be encoded with one of 5 different Chars. If those encoded Char values are duplicated at all across your Enc[1..71].Enc array for the same value of Encoder, you will not be able to know which Enc[1..71].Char to use for decoding. It is not enough that your arrays are simply random, but they also need to be unique for the same value of Encoder.
Also, your loops are redundant and overly complicated. They can be greatly simplified.
Try something more like this instead:
function TEncrypter.EncodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
for t := 1 to 71 do
begin
if Sign = Enc[t].Char then
begin
Result := Enc[t].Enc[Encoder];
Exit;
end;
end;
Result := Sign;
end;
function TEncrypter.DecodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
for t := 1 to 71 do
begin
if Sign = Enc[t].Enc[Encoder] then
begin
Result := Enc[t].Char;
Exit;
end;
end;
Result := Sign;
end;
procedure TEncrypter.Encode;
var
t, u, h: integer;
s: String;
begin
for h := 0 to EncodeBuffer.Count-1 do
begin
s := EncodeBuffer.Strings[h];
t := Length(s);
if t > 0 then
begin
for u := 0 to t-1 do
begin
s[u+1] := EncodeChar(s[u+1], (h mod 5) + 1);
end;
EncodeBuffer.Strings[h] := s;
end;
end;
end;
procedure TEncrypter.Decode;
var
t, u, h: integer;
s: String;
begin
for h := 0 to EncodeBuffer.Count-1 do
begin
s := EncodeBuffer.Strings[h];
t := Length(s);
if t > 0 then
begin
for u := 0 to t-1 do
begin
s[u+1] := DecodeChar(s[u+1], (h mod 5) + 1);
end;
EncodeBuffer.Strings[h] := s;
end;
end;
end;
// FormCreate
var
I, J, K, L: Integer;
Temp: Array[1..71] of Char;
NumInTemp: Integer;
begin
...
// initialize Enc[].Char as needed...
for I := 1 to 71 do
begin
Enc[I].Char := ...;
end;
// uniquely initialize each Enc[].Enc array for one value of Encoder...
for I := 1 to 5 do
begin
for J := 1 to 71 do
Temp[J] := ...; // must be unique for this iteration of I...
NumInTemp := 71;
// randomly assign Temp array to Enc[I].Enc array
for J := 1 to 71 do
begin
K := 1 + Random(NumInTemp);
Enc[J].Enc[I] := Temp[K];
for L := K+1 to NumInTemp do
Temp[L-1] := Temp[L];
Dec(NumInTemp);
end;
end;
...
end;
If you then expand your arrays to allow all printable ASCII characters, not just 71 of them, then the code gets a little simpler:
var
Enc : array [32..126] of Record
Char: Char;
Encr: string;
Enc: array [1..5] of Char;
end;
EncodeBuffer: TStringList;
function TEncrypter.EncodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
if (Sign >= #32) and (Sign <= #126) then
Result := Enc[Ord(Sign)].Enc[Encoder]
else
Result := Sign;
end;
function TEncrypter.DecodeChar(Sign: Char; Encoder: integer) : Char;
var
t: integer;
begin
for t := Low(Enc) to High(Enc) do
begin
if Sign = Enc[t].Enc[Encoder] then
begin
Result := Enc[t].Char;
Exit;
end;
end;
Result := Sign;
end;
procedure TEncrypter.Encode;
var
u, h: integer;
s: String;
begin
for h := 0 to EncodeBuffer.Count-1 do
begin
s := EncodeBuffer.Strings[h];
for u := Low(s) to High(s) do
s[u] := EncodeChar(s[u], (h mod 5) + 1);
EncodeBuffer.Strings[h] := s;
end;
end;
procedure TEncrypter.Decode;
var
u, h: integer;
s: String;
begin
for h := 0 to EncodeBuffer.Count-1 do
begin
s := EncodeBuffer.Strings[h];
for u := Low(s) to High(s) do
s[u] := DecodeChar(s[u], (h mod 5) + 1);
EncodeBuffer.Strings[h] := s;
end;
end;
// FormCreate
var
I, J, K, L: Integer;
Temp: Array[32..126] of Char;
NumInTemp: Integer;
begin
...
for I := Low(Enc) to High(Enc) do
Enc[I].Char := Char(I);
for I := 1 to 5 do
begin
for J := Low(Temp) to High(Temp) do
Temp[J] := Char(J);
NumInTemp := Length(Temp);
for J := Low(Enc) to High(Enc) do
begin
K := Low(Temp) + Random(NumInTemp);
Enc[J].Enc[I] := Temp[K];
for L := K+1 to (Low(Temp)+NumInTemp) do
Temp[L-1] := Temp[L];
Dec(NumInTemp);
end;
end;
end;
And if you set up a separate decoder table instead of using Enc[].Enc, you can simplify TEncrypter.DecodeChar() to a similar lookup that TEncrypter.EncodeChar() uses, without having to use a loop at all. I will leave that as an exercise for you.
Let's say I start with a string "abc".
I want to replace all "a" with "c", replace all "b" with "Q", and replace all "c" with "7".
Perhaps I would write:
S := 'abc';
S := S . Replace ( 'a', 'c' );
S := S . Replace ( 'b', 'Q' );
S := S . Replace ( 'c', '7' );
The result is '7Q7'. Oops! Why wasn't "a" replaced with "c"?
Well, it was.
After the first call to Replace, S was 'cbc'.
After the second call, S was 'cQc'.
The last call replaced both 'c's with '7'.
I imagine you are doing the same sort of thing here.
I couldn't give you the specific results of your code character for character unless we saw how you were populating the Enc structure.

programatically extract the file name from a Download Link using delphi

How i can extract the file name from a Download Link using Delphi
Example
http://pj-mirror01.mozilla.org/pub/mozilla.org/firefox/releases/3.6/win32/es-CL/Firefox%20Setup%203.6.exe
The result must be
Firefox Setup 3.6.exe
Try this
function GetURLFilename(const FilePath:String;Const Delimiter:String='/'):String;
var I: Integer;
begin
I := LastDelimiter(Delimiter, FILEPATH);
Result := Copy(FILEPATH, I + 1, MaxInt);
Result := UrlDecode(Result);
end;
URlDecode was copied from http://www.torry.net/dpfl/dzurl.html and looks like
function UrlDecode(const EncodedStr: String): String;
var
I: Integer;
begin
Result := '';
if Length(EncodedStr) > 0 then
begin
I := 1;
while I <= Length(EncodedStr) do
begin
if EncodedStr[I] = '%' then
begin
Result := Result + Chr(HexToInt(EncodedStr[I+1]
+ EncodedStr[I+2]));
I := Succ(Succ(I));
end
else if EncodedStr[I] = '+' then
Result := Result + ' '
else
Result := Result + EncodedStr[I];
I := Succ(I);
end;
end;
end;
function HexToInt(HexStr: String): Int64;
var RetVar : Int64;
i : byte;
begin
HexStr := UpperCase(HexStr);
if HexStr[length(HexStr)] = 'H' then
Delete(HexStr,length(HexStr),1);
RetVar := 0;
for i := 1 to length(HexStr) do begin
RetVar := RetVar shl 4;
if HexStr[i] in ['0'..'9'] then
RetVar := RetVar + (byte(HexStr[i]) - 48)
else
if HexStr[i] in ['A'..'F'] then
RetVar := RetVar + (byte(HexStr[i]) - 55)
else begin
Retvar := 0;
break;
end;
end;
Result := RetVar;
end;

Delphi SearchText Issue

For some reason, using
SearchText := 'Program Files';
ReplaceText := 'Program Files (x86)';
SearchAndReplace(SearchText, ReplaceText);
Would do absolutely nothing, it just won't change text, works fine when using any other text.
Is this some sort of "Reserve" word? Or ( ) is what makes it do not work?
procedure Tfc_Great.SearchAndReplace
(InSearch, InReplace: string) ;
var X, ToEnd : integer;
oldCursor : TCursor;
begin
oldCursor := Screen.Cursor;
Screen.Cursor := crHourglass;
with RichEdit1 do
begin
X := 0;
ToEnd := length(Text) ;
X := FindText(inSearch, X, ToEnd, []) ;
while X <> -1 do
begin
SetFocus;
SelStart := X;
SelLength := length(inSearch) ;
SelText := InReplace;
X := FindText(inSearch,
X + length(InReplace),
ToEnd, []) ;
end;
end;
Screen.Cursor := oldCursor;
end;
Try to assign the output ;)
SearchText := 'Program Files';
ReplaceText := 'Program Files (x86)';
ResultText := SearchAndReplace(Text, SearchText, ReplaceText);
with
function SearchAndReplace
(sSrc, sLookFor, sReplaceWith : string) : string;
var
nPos, nLenLookFor : integer;
begin
nPos := Pos(sLookFor, sSrc) ;
nLenLookFor := Length(sLookFor) ;
while (nPos > 0) do begin
Delete(sSrc, nPos, nLenLookFor) ;
Insert(sReplaceWith, sSrc, nPos) ;
nPos := Pos(sLookFor, sSrc) ;
end;
Result := sSrc;
end;

Resources