How to send a file AND other POST data with Synapse - file

Delphi used: 2007.
Hello,
I have a simple web page with two text input and one file input. Now, for the form to be sent, both the text inputs and the file input have to be filled. With Synapse, I know how to upload a file (HttpPostFile) and how to post data (HttpMethod). However, I don't know how to do both.
After looking at the source code of Synapse, I guess I have to "format" my data with boundaries or something like that. I guess I should have one boundary for my input file and another boundary for my text inputs. I found an article on the subject, but it's about sending email attachments. I tried to reproduce what they said with Synapse, with no results.
Code for HttpPostFile:
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;
Thank you.

Your code is close. You are only sending your file field but not your text fields. To do all three, try this instead:
function HttpPostFile(const URL, InputText1FieldName, InputText1, InputText2FieldName, InputText2, InputFileFieldName, InputFileName: string; InputFileData: TStream; ResultData: TStrings): Boolean;
var
HTTP: THTTPSend;
Bound: string;
begin
Bound := IntToHex(Random(MaxInt), 8) + '_Synapse_boundary';
HTTP := THTTPSend.Create;
try
WriteStrToStream(HTTP.Document,
'--' + Bound + CRLF +
'Content-Disposition: form-data; name=' + AnsiQuotedStr(InputText1FieldName, '"') + CRLF +
'Content-Type: text/plain' + CRLF +
CRLF);
WriteStrToStream(HTTP.Document, InputText1);
WriteStrToStream(HTTP.Document,
CRLF +
'--' + Bound + CRLF +
'Content-Disposition: form-data; name=' + AnsiQuotedStr(InputText2FieldName, '"') + CRLF +
'Content-Type: text/plain' + CRLF +
CRLF);
WriteStrToStream(HTTP.Document, InputText2);
WriteStrToStream(HTTP.Document,
CRLF +
'--' + Bound + CRLF +
'Content-Disposition: form-data; name=' + AnsiQuotedStr(InputFileFieldName, '"') + ';' + CRLF +
#9'filename=' + AnsiQuotedStr(InputFileName, '"') + CRLF +
'Content-Type: application/octet-string' + CRLF +
CRLF);
HTTP.Document.CopyFrom(InputFileData, 0);
WriteStrToStream(HTTP.Document,
CRLF +
'--' + Bound + '--' + CRLF);
HTTP.MimeType := 'multipart/form-data; boundary=' + Bound;
Result := HTTP.HTTPMethod('POST', URL);
if Result then
ResultData.LoadFromStream(HTTP.Document);
finally
HTTP.Free;
end;
end;
If you switch to Indy, you can use its TIdMultipartFormDataStream class:
function HttpPostFile(const URL, InputText1FieldName, InputText1, InputText2FieldName, InputText2, InputFileFieldName, InputFileName: string; InputFileData: TStream; ResultData: TStrings): Boolean;
var
HTTP: TIdHTTP;
Input: TIdMultipartFormDataStream;
Output: TMemoryStream;
begin
Result := False;
try
Output := TMemoryStream.Create;
try
HTTP := TIdHTTP.Create;
try
Input := TIdMultipartFormDataStream.Create;
try
Input.AddFormField(InputText1FieldName, InputText1);
Input.AddFormField(InputText2FieldName, InputText2);
Input.AddFormField(InputFileFieldName, 'application/octet-stream', '', InputFileData, InputFileName);
HTTP.Post(URL, Input, Output);
finally
Input.Free;
end;
finally
HTTP.Free;
end;
Output.Position := 0;
ResultData.LoadFromStream(Output);
Result := True;
finally
Output.Free;
end;
except
end;
end;

I also use synapse in my projects. To be make my work simple and faster with Synapse, I wrote THTTPSendEx class, that gives fast speed of using and minimum of code and more features.
Currently it's a beta version.
It's views like Indy.
Create THTTPSendEx class.
Create methods OnBeginWork, OnWork, OnWorkEnd from it prototypes(see pas file), and assign it to created class. Thats all what you need, and just call GET, POST functions of the class.
I also implement multipart-fomdata for fast file posting in this format as TMultipartFormDataStream class.
With it you can easy write files and fields.
Example of using:
var
HTTP:THTTPSendEx;
Data:TMultipartFormDataStream;
sHTML:string; //Recived HTML code from web
begin
HTTP:=THTTPSEndEx.Create;
Data:=TMultipartFormDataStream.Create;
try
Data.AddFile('myFile','Path to the local file(No UNC paths)');
Data.DataEnd;
if HTTP.Post('URL HERE',Data,sHTML) then
begin
//Connection established
//Check HTTP response
if HTTP.IsSuccessfull then //HTTP returns "200 OK" code.
begin
ShowMessage('File successfully posted to the server.');
end;
end else
begin
ShowMessage('Can not establish a connection to the server...'+#13+'Network is not avaliable or server socket does not exist.');
end;
finally
FreeAndNil(HTTP);
FreeAndNil(Data);
end;
end;
You can see it at my web-site.
If you have any ideas for this, please write it's as a comment to project page.
Sorry for mistakes in english.

Related

Delphi - Load files & folders to TreeView ( using IOUtils )

How can I properly organize the loading of a specific path of the file system (Windows) in TreeView?
For example:
load files & folders to TreeView (with IOUtils)
(*
tv_zapis: TTreeView
uses
System.IOUtils,
System.Types;
*)
procedure TF1.tb_ReDirectClick(Sender: TObject);
{ ReDirect ( Reorganization Directoris ) dirs & files to TTreeView }
procedure DFToTv(_Tv: TTreeView;
withNode: TTreeNode;
dfPath: string);
var
InsNode: TTreeNode;
Short_Name,
Short_EXT: string; // '*.txt' - delete
sPath: string;
arMask: TStringDynArray;
FilterTN: TDirectory.TFilterPredicate;
SO: TSearchOption;
s: TShiftState;
begin
sPath := Trim(dfPath);
SO := TSearchOption.soAllDirectories; // Search for All Directories in dir
FilterTN := // Filter for Find files
function(const Path: string; const SearchRec: TSearchRec): Boolean
var
nDir, // name Folder ( ! not full path )
sDF: string;
fAtts: TFileAttributes;
begin
nDir := TPath.GetFileName(Path); { Path Name - name of 'folder' }
sDF := IncludeTrailingPathDelimiter(Path) + SearchRec.Name ; // + '\' + SearchRec.Name
// Ignor find dir '_Setting'
if (SearchRec.Name = APL_nameS) or (nDir = APL_nameS)
then exit(False);
{ Browse a file and read its attributes }
fAtts := TPath.GetAttributes(sDF, False);
if (TFileAttribute.faDirectory in fAtts) then
begin
{ if path ' FOLDER ' }
Short_Name := SearchRec.Name;
// ??????????
InsNode := withNode.Parent;
if (InsNode = nil) then
begin
// ShowMessage( ' 1 ? ' );
// ??????????
//if (InsNode.Text = tNode.Text) then
InsNode := _Tv.Items.AddChild(withNode, Short_Name)
//else
// InsNode := _Tv.Items.AddChild(InsNode, Short_Name);
end
else
begin
ShowMessage( ' 2 ? ' );
// ??????????
InsNode := _Tv.Items.AddChild(InsNode, Short_Name);
end;
InsNode.ImageIndex := 1;
InsNode.SelectedIndex := 2;
Exit(True);
end
else
begin
{ if path ' File ' }
Short_EXT := AnsiUpperCase(ExtractFileExt(SearchRec.Name));
if (Short_EXT = '.TXT') then
Short_Name := ChangeFileExt(SearchRec.Name , '')
else
Short_Name := SearchRec.Name;
ShowMessage( ' 3 ? ' );
// ??????????
InsNode := _Tv.Items.AddChild(InsNode.Parent, Short_Name);
if (Short_EXT = '.TXT') then
begin
InsNode.ImageIndex := 3;
InsNode.SelectedIndex := 4;
end
else
begin
InsNode.ImageIndex := 5;
InsNode.SelectedIndex := 5;
end;
Exit(True);
end;
end;
{ FIND FOLDER & File }
arMask := TDirectory.GetFileSystemEntries(sPath, SO, FilterTN);
Application.ProcessMessages;
//Screen.Cursor := crDefault;
// ShowMessage(' All Good :))) ');
(*
ShowMessage( 'sDF - ' + '`' + sDF + '`' + sLineBreak + sLineBreak +
'Path - ' + Path + sLineBreak + sLineBreak +
'SearchRec.Name - ' + '`' + SearchRec.Name + '`' + sLineBreak
);
*)
end;
var
tNode: TTreeNode;
nodeChild: Boolean;
begin
if (DirectoryExists(APL_Files) = False) then Exit;
tv_zapis.Items.Item[0].Selected := True;
Screen.Cursor := crHourGlass;
tv_zapis.Items.BeginUpdate;
try
tv_zapis.Items.Clear;
tNode := tv_zapis.Items.AddChild(nil, 'Dominant_Folder');
begin
DFToTv (tv_zapis, tNode, APL_Files);
end;
finally
tv_zapis.Items.EndUpdate;
Screen.Cursor := crDefault;
end;
end;
Everything functions correctly, but the path does not display correctly on the TreeView (tv_zapis).

Delphi: Timer in Service Stops my FileReader

I am writing a Service that has a Timer which should check every 60 seconds if a Line has a particular number. Here is the code of the timer:
procedure TConnectionChecker.Timer2Timer(Sender: TObject);
var
myFile: TextFile;
sLine: string;
fileOpenLog: TStreamWriter;
fileOpenLogName, fileOpenLogPathName: string;
begin
ExePath := TPath.GetDirectoryName(GetModuleName(HInstance));
filename:= 'restult.txt';
filePath:= TPath.Combine(exePath, 'OutputFile');
filePathName:= TPath.Combine(filePath, filename);
fileOpenLogName:= 'Log_fileOpen.txt';
serviceLogPath:= TPath.Combine(exePath, 'LogFiles');
fileOpenLogPathName:= TPath.Combine(serviceLogPath, fileOpenLogName);
fileOpenLog := TStreamWriter.Create(TFileStream.Create(fileOpenLogPathName, fmCreate or fmShareDenyWrite));
if not FileExists(filePathName) then
begin
fileOpenLog.WriteLine('File not found');
TServiceThread.Current.Terminate;
fileOpenLog.Free;
end;
fileOpenLog.WriteLine('File found');
try
AssignFile(myFile, filePathName);
Reset(myFile);
fileOpenLog.WriteLine('File opened');
while NOT eof(myFile) do
begin
PingWorkedAufrufe:= PingWorkedAufrufe + 1;
readln(myFile, sLine);
fileOpenLog.WriteLine('Read Line: ' + sLine);
checkIfPingWorked(sLine);
end;
fileOpenLog.WriteLine('EOF');
finally
CloseFile(myFile);
end;
fileOpenLog.Free;
end;
And here is the code of my Procedure: checkIfPingWorked:
procedure TConnectionChecker.checkIfPingWorked(ALine: String);
var
AValue, StartOfLineToFind: String;
checkIfPingWorkedLog: TStreamWriter;
checkIfPingWorkedLogName, checkIfPingWorkedLogPathName: string;
begin
ExePath := TPath.GetDirectoryName(GetModuleName(HInstance));
StartOfLineToFind:= ' Pakete: Gesendet =';
ip:= '...';
fileName:= 'restult.txt';
filepath:= TPath.Combine(exePath, 'OutputFile');
filepathname:= TPath.Combine(filepath, fileName);
serviceLogPath:= TPath.Combine(exePath, 'LogFiles');
checkIfPingWorkedLogName:= 'Log_checkIfPingWorked.txt';
checkIfPingWorkedLogPathName := TPath.Combine(serviceLogPath, checkIfPingWorkedLogName);
checkIfPingWorkedLog := TStreamWriter.Create(TFileStream.Create(checkIfPingWorkedLogPathName, fmCreate or fmShareDenyWrite));
checkIfPingWorkedLog.WriteLine('Zeilen werden überprüft');
if Pos(StartOfLineToFind, ALine) = 1 then
begin
AValue:= Copy(ALine, 39, 1);
if AValue = IntToStr(5) then
checkIfPingWorkedLog.WriteLine('Success')
else
begin
checkIfPingWorkedLog.WriteLine('Error');
//Writing E-Mail...
//Authentifizierung
IdSMTP1.AuthType := TIdSMTPAuthenticationType.satDefault;
//Benutzerdaten für Authentifizierung
IdSMTP1.Username := '...';
IdSMTP1.Password := '...';
//Server-Daten
IdSMTP1.Host := '...';
IdSMTP1.Port := ...;
IdSMTP1.Connect;
try
IdMessage1.From.Address := '';
IdMessage1.Recipients.EMailAddresses := '';
//IdMessage1.CCList.EMailAddresses := '';
//IdMessage1.BCCList.EMailAddresses := '';
IdMessage1.Subject := '--AUTOMATISCHE BENACHRICHTIGUNG--';
IdMessage1.Body.Text := 'Der PC mit der IP: ' + ip + ' konnte nicht mehr erreicht werden';
IdSMTP1.Send(IdMessage1);
finally
IdSMTP1.Disconnect;
end;
checkIfPingWorkedLog.WriteLine('Email sent');
TServiceThread.Current.Terminate;
end;
end;
checkIfPingWorkedLog.Free;
end;
But I can only read the first two lines and then it stops.
Important to say is that I originally wrote this as a normal Program. And it worked fine. Now I am converting it into a Windows Service.
The Problem was, that I created everywhere and everytime new Log Files.
Now I Create one Log file on Service Create:
procedure TConnectionChecker.ServiceCreate(Sender: TObject);
var
logFilePathName, logFileName, exePath, logFilePath: String;
begin
ExePath := TPath.GetDirectoryName(GetModuleName(HInstance));
logFileName:= 'log_connectionTest.txt';
logFilePath:= TPath.Combine(exePath, 'logFile');
logFilePathName:= TPath.Combine(logFilePath, logFileName);
if not TDirectory.Exists(logFilePath) then
TDirectory.CreateDirectory(logFilePath);
swLogFile:= TStreamWriter.Create(TFileStream.Create(logFilePathName, fmCreate or fmShareDenyWrite));
end;
And I made a procedure where I ask for 2 params (destination and text) and write the line to the Log file.:
procedure TConnectionChecker.WriteToLog(destination, Text: string);
begin
swLogFile.WriteLine('[' + DateTimeToStr(now) + '] ' + destination + ' schreibt: ' + text);
end;
Finally I can call it in every procedure:
WriteToLog('checkIfPingWorked', 'Success')

creating a file in google cloud storage - IOError: Buffer is closed

I created a python script to pull the data from facebookads API and create a file in google cloud storage by using google app engine.
getting the following error while writing the data to google cloud storage but data is displaying properly on web browser:
IOError: Buffer is closed.
After some research I understood that, this error will come when not able to recognize end of the lin ("\n") , so it treats the entire file as a single line and raise "Buffer is Closed" error.
So I added following code and now displaying rows properly on web browser but still getting error while writing into gcs.
data1=data.replace("\n", "<br />")
Code:
class get_region_insights(webapp.RequestHandler):
_apptitle = None
_projectid = None
_projectnumber = None
def get(self):
#bucket_name = os.environ.get('BUCKET_NAME', app_identity.get_default_gcs_bucket_name())
cfg=appsettings()
for i in cfg._templates:
id=int(i['_id'])
if id == 7:
### Read variables from config file
bucket_name = i['_gcsbucket']
bucket = '/' + bucket_name
filename = bucket + '/' + i['_filename'] + str(time.strftime("%d_%m_%Y")) + ".csv"
ad_acct=i['_ad_acct']
app_id = i['_app_id']
app_secret = i['_app_secret']
access_token = i['_access_token']
needed_keys=ast.literal_eval(i['_needed_keys'])
self.tmp_filenames_to_clean_up = []
u = date.today()
sub_days = 1
s = u - timedelta(sub_days)
until = str(u)
since = str(s)
params = {
'fields': [
FBAdsInsights.Field.account_id,
FBAdsInsights.Field.campaign_id,
FBAdsInsights.Field.campaign_name,
FBAdsInsights.Field.adset_id,
FBAdsInsights.Field.adset_name,
FBAdsInsights.Field.impressions,
FBAdsInsights.Field.spend,
FBAdsInsights.Field.actions,
FBAdsInsights.Field.action_values,
],
'filtering': [
{
'field': 'action_type',
'operator': 'IN',
'value': ["link_click","comment", "post_reaction", "post", "offsite_conversion.fb_pixel_purchase"] #custom rule filter
},
],
'level': 'adset',
'time_range': {
'since': since, #user input field
'until': until #specify dynamic date range between (today() - (days_entered)) and today()
},
'time_increment': 1,
'breakdowns': ['region'],
'action_breakdowns': ['action_type'],
}
### Initializing Google cloud Storage Object
write_retry_params = _gcs.RetryParams(backoff_factor=1.1)
gcs_file=_gcs.open(filename, 'w', content_type='text/plain',retry_params=write_retry_params)
### Facebook Initialization
session=FacebookSession(app_id,app_secret,access_token)
api=FacebookAdsApi(session)
FacebookAdsApi.set_default_api(api)
ad_account = FBAdAccount(ad_acct)
stats = ad_account.get_insights(params=params,async=True)
stats.remote_read()
while stats[AdReportRun.Field.async_percent_completion] < 100:
time.sleep(1)
stats.remote_read()
time.sleep(1)
stats1 = stats.get_result()
x = [x for x in stats1]
### Printing the result and writing to Google Cloud Storage
for i in x:
for k in i['actions']:
if k['action_type'] == "offsite_conversion.fb_pixel_purchase":
Purchase_Facebook_Pixel = k['value']
if k['action_type'] == "comment":
post_comment= k['value']
if k['action_type'] == "link_click":
link_click=k['value']
if k['action_type'] == "post":
post_share=k['value']
if k['action_type'] == "post_reaction":
post_reaction=k['value']
for m in i['action_values']:
if m['action_type'] == "offsite_conversion.fb_pixel_purchase" :
Purchase_Conversion_Value_Facebook_Pixel=m['value']
data=(i['account_id'] + "," + i['adset_id'] + "," + i['campaign_id'] + "," + i['date_start'] + "," + i['date_stop'] + ","+ i['impressions']+ "," + i['region'] + ","+ i['spend']+ "," + link_click + "," + Purchase_Facebook_Pixel + "," + Purchase_Conversion_Value_Facebook_Pixel+"\n")
data1=data.replace("\n", "<br />")
self.response.write(data.replace("\n", "<br />"))
#self.response.write("\n"+i['account_id'] + "," + i['adset_id'] + "," + i['adset_name'] + "," + i['age'] + "," + i['campaign_id'] + "," +i['campaign_name'] + "," + i['date_start'] + "," + i['date_stop'] + ","+i['gender'] + ","+ i['impressions']+","+ i['spend']+ "," + link_click + "," + post_comment + "," + post_share + "," + post_reaction + "," + Purchase_Facebook_Pixel + "," + Purchase_Conversion_Value_Facebook_Pixel+"\n")
gcs_file.write(data1.encode('utf-8'))
gcs_file.close()
self.tmp_filenames_to_clean_up.append(filename)
You are opening the cloud storage file outside your loop, but then you close inside the loop.
### Initializing Google cloud Storage Object
write_retry_params = _gcs.RetryParams(backoff_factor=1.1)
gcs_file=_gcs.open(filename, 'w', content_type='text/plain',retry_params=write_retry_params)
### Facebook Initialization
...
### Printing the result and writing to Google Cloud Storage
for i in x:
# do stuff with data
...
gcs_file.write(data1.encode('utf-8'))
gcs_file.close() # <-- closing the file buffer
self.tmp_filenames_to_clean_up.append(filename)
If you want to write one file for each loop iteration, open and close the file inside the loop.
If you want to to write all the data to a single file, open and close the file outside the loop.

Reading directory in delphi 7 gives nothing

I'm a delphi noob, and I simply try to read the the files in a directory (I will be doing sth with this files later).
I tried ouple methods, and nothing works - there is simply nothing outputed.
directoryPath := exePath + 'XML_out\'; //correct directory
wiadomosc := wiadomosc + sLineBreak + sLineBreak + 'FILES IN DIRECTORY:' + directoryPath; //will output correct directory
//first method
directoryEOFound:= False;
if FindFirst(directoryPath, faAnyFile, directoryRes) = 0 then
wiadomosc := wiadomosc + sLineBreak + 'DIRECTORY N)T FOUND' + sLineBreak //should save info about directory not found but return nothing
// exit //exit is killing app, like directory was not found.... but directory is there
else
while not directoryEOFound do begin
wiadomosc := wiadomosc + sLineBreak + directoryRes.Name; //gives nothing
directoryEOFound:= FindNext(directoryRes) <> 0;
end;
FindClose(directoryRes) ;
//second method
if FindFirst(directoryPath, faAnyFile, directoryRes) = 0 then try
repeat
if (directoryRes.Name = '.') or (directoryRes.Name = '..') then
continue;
wiadomosc := wiadomosc + sLineBreak + 'file: ' + directoryRes.Name; //gives nothing, i dont think its initiated
until FindNext(directoryRes) <> 0;
finally
SysUtils.FindClose(directoryRes);
end;
Neither method works, so maybe its a OS matter? (windows 7 64 bit) No errors in compilation offcourse.
You need to include a pattern to search for files. Replace
directoryPath := exePath + 'XML_out\';
with
directoryPath := exePath + 'XML_out\*';
The first block of code is odd. It appears to give up when FindFirst returns 0. But the 0 return value indicates success. So that condition is wrong. The second block of code looks reasonable.

Understanding encrypting a file, using LockBox 3 and Delphi XE2

So my current task involves taking a given string of text (Ex: ABC123) and encrypting it using LockBox3's EncryptString(source, target) function. I can successfully encrypt the string and get the output to save to a .txt file.
The next step in this process is to then use LockBox3's EncryptFile(source, target) function to take the .txt containing my already-encrypted string and encrypting said file using AES-128 (same as the string encryption but with diff password)
Basically, I can get the string to encrypt correctly and output to a .txt file. I then request that the user grab the .txt, and bring it into my program. The program then attempts to take that file and encrypt it further. When I do this, I get a file to output.. however when I go to decrypt said file the resulting .txt does not contain the original text.. or any text for that matter. I am basically confused as to how I should be going about encrypting the .txt file. Any suggestions? I apologize if this question/code is not specific enough. Please let me know what else, if anything I need to make clear about the situation in order to better help you guys understand what I'm struggling with! Thanks!
EDIT1:
Alright everyone, thanks for the suggestions. To clarify:
The stream I have in the decryption process is to be used later, so that after I have decrypted the file, I can read from it and decrypt the remaining encrypted (from the first step) string.
To clarify further:
My codec (Codec1) for encrypting the string is using AES-128 with CBC, with a tag of "0" and an AsymetricKeySize of 1024 (which, Im pretty sure is irrelevant for this type of encryption correct?) My codec for encrypting FILES (Codec2 above) has the same settings, however the passwords for Codec1 and Codec2 are different. Basically, I am using Codec1 to encrypt a string and write it to a .txt, and then I am using Codec2 to encrypt said file.. eventually decrypt it and use the Stream to read from said file and decrypt that string using Codec1 again.
my file encryption/decryption code:
String Encryption:
procedure TForm1.Button1Click(Sender: TObject);
begin
codec1.Password := WORD_1;
//Begin encryption
sPlainText := Serial_number.Number; //Store Serial Number of machine
codec1.EncryptString(sPlainText,CipherText); //Encrypt (base64)
listbox2.Clear;
listbox2.AddItem(Ciphertext, AnsiCipher);
end;
Write encrypted string to a file and save it:
saveDialog := TSaveDialog.Create(self);
saveDialog.Title := 'Choose location to save Authentication Code';
saveDialog.InitialDir := 'C:\';
saveDialog.DefaultExt := '';
saveDialog.FilterIndex := 1;
saveDialog.Execute();
glb_fileName1 := saveDialog.FileName;
//open stream and write cipher to a .txt of chosen location
try
Stream := TFileStream.Create(saveDialog.GetNamePath + saveDialog.FileName + '.txt', fmOpenReadWrite);
except
Stream := TFileStream.Create(saveDialog.GetNamePath + saveDialog.FileName + '.txt', fmCreate);
end;
for k := 1 to (Length(CipherText)) do
buff[k] := byte(CipherText[k]);
ptr := #buff[1];
Stream.WriteBuffer(ptr^, Length(CipherText));
Stream.Free;
saveDialog.Free;
Grab location of .txt for file encryption:
procedure TForm1.Button4Click(Sender: TObject);
var
fileName : string;
holder_obj : TSerial_number;
begin
holder_obj := Tserial_number.Create;
listbox4.Clear;
if OpenTextFileDialog1.Execute() then
fileName := OpenTextFileDialog1.FileName;
listbox4.AddItem(filename, holder_obj);
end;
File Encryption:
Codec2.Password := WORD_2;
sCrypt := glb_fileName1 + '_enc.txt';
Codec2.EncryptFile(glb_fileName1+'.txt', sCrypt);
Grab Encrypted File for decryption:
procedure TForm1.Button3Click(Sender: TObject);
var
holder_obj : TSerial_number;
begin
holder_obj := Tserial_number.Create;
listbox3.Clear;
if OpenTextFileDialog1.Execute() then
glb_fileName2 := OpenTextFileDialog1.FileName;
listbox3.AddItem(glb_filename2, holder_obj);
end;
File Decryption (opening a stream to read from the decrypted file once I have it, so that I can decrypt the encrypted string it contains):
procedure TForm1.Button5Click(Sender: TObject);
var
saveDialog : TSaveDialog;
begin
saveDialog := TSaveDialog.Create(self);
saveDialog.Title := 'Choose location to save Decrypted Authentication Code';
saveDialog.InitialDir := 'C:\';
saveDialog.DefaultExt := '';
saveDialog.Execute();
glb_fileName1:= saveDialog.FileName;
//open stream and write cipher to a .txt of chosen location
try
Stream := TFileStream.Create(saveDialog.GetNamePath + saveDialog.FileName + '.txt', fmOpenReadWrite);
except
Stream := TFileStream.Create(saveDialog.GetNamePath + saveDialog.FileName + '.txt', fmCreate);
end;
Stream.Free;
Codec2.Password := WORD_2;
Codec2.DecryptFile(glb_fileName2, saveDialog.FileName + '.txt');
saveDialog.Free;
end;
The code you provided is way to complicated to try and see what is going wrong. If you are just trying to see if the encoding/decoding works you should only need simple code like the code below. Just put a test file on your drive and hardcode the names. That will let you know that the encoding/decoding works if the InputFile.txt and Un-EncryptedFile.text are the same.
Once you have the working then you can start to build up your full routines. The code you have posted is really confusing with the globals being used between the button clicks and just named 1, 2, etc. You have streams created that do nothing and only confuse the issue more. Strip things back to the basics and get that working first.
procedure TestEncodeDecode();
begin
Codec2.Password := WORD_2;
Codec2.EncryptFile('c:\InputFile.txt', 'c:\EncryptedFile.txt');
Codec2.DecryptFile('c:\EncryptedFile.txt', 'c:\Un-EncryptedFile.txt');
end;
I too am confused about what your question is asking. At the risk of misinterpreting your question, I have assumed that you are trying:
Encrypt a string;
Store the encrypted string in a file
Encrypt the file (double encryption)
Reverse the previous steps to reconstruct the original string.
The selftest() method proves that this works.
If this interpretation is correct, please consider something like the following solution. (Tested in Delphi 2010. Not test in XE2)
unit uDoubleEncrypt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, uTPLb_CryptographicLibrary, uTPLb_BaseNonVisualComponent,
uTPLb_Codec;
type
TmfmDoubleEncrypt = class(TForm)
Codec1: TCodec;
Codec2: TCodec;
CryptographicLibrary1: TCryptographicLibrary;
btnGo: TButton;
memoLog: TMemo;
dlgSave1: TSaveDialog;
dlgOpen1: TOpenDialog;
procedure btnGoClick(Sender: TObject);
private
FFileName_Plain, FFileName_Cipher: string;
sSerial: string;
function EncryptStringWithCodec1( const sPlaintext: string): ansistring;
function GetFileName( dlgOpenX: TOpenDialog; var sFN: string): boolean;
procedure SaveAnsiStringToFile( const sFN: string; const sSerialCipherText: AnsiString);
function ReconstructSerial: string;
public
procedure Put( const LineFmt: string; const Args: array of const);
procedure Button1Click;
procedure Button4Click;
function SelfTest: boolean;
end;
var
mfmDoubleEncrypt: TmfmDoubleEncrypt;
implementation
{$R *.dfm}
procedure TmfmDoubleEncrypt.btnGoClick( Sender: TObject);
var
WORD_1, WORD_2: string;
begin
WORD_1 := 'red';
WORD_2 := 'blue';
sSerial := '123'; // Serial_number.Number; // Store Serial Number of machine
Codec1.Password := WORD_1;
Codec2.Password := WORD_2;
// Run the self test.
SelfTest;
// Clean up.
Codec1.Burn;
Codec2.Burn
// You may also want to delete temporary files here.
end;
function TmfmDoubleEncrypt.EncryptStringWithCodec1(
const sPlaintext: string): ansistring;
begin
// Assume Codec1 properties already set-up:
// 1. Password
// 2. CryptoLibrary
// 3. Cipher (at design-time)
// 4. Chain-mode
Codec1.Reset; // Normally not necessary. A defence agains the codec being left in a corrupt state.
Codec1.EncryptString( sPlaintext, result)
end;
function TmfmDoubleEncrypt.GetFileName(
dlgOpenX: TOpenDialog; var sFN: string): boolean;
begin
result := dlgOpenX.Execute;
if result then
sFN := dlgOpenX.FileName
end;
procedure TmfmDoubleEncrypt.Put(
const LineFmt: string; const Args: array of const);
begin
memoLog.Lines.Add( Format( LineFmt, Args))
end;
procedure TmfmDoubleEncrypt.SaveAnsiStringToFile(
const sFN: string; const sSerialCipherText: AnsiString);
const
Modes: array[boolean] of word = (fmCreate, fmOpenReadWrite);
var
SaveStream: TStream;
begin
SaveStream := TFileStream.Create( sFN, Modes[ FileExists( sFN)]);
try
SaveStream.Size := 0;
if sSerialCipherText <> '' then
SaveStream.WriteBuffer( sSerialCipherText[1], Length( sSerialCipherText))
finally
SaveStream.Free
end
end;
procedure TmfmDoubleEncrypt.Button1Click;
// This method is equivalent to gEdit101's Button1Click()
var
sPlainText: string;
sSerialCipherText: AnsiString;
sFN: string;
begin
sPlainText := sSerial;
sSerialCipherText := EncryptStringWithCodec1( sPlainText);
Put( 'Encrypted serial number is %s', [sSerialCipherText]);
if GetFileName( dlgOpen1, sFN) then
begin
SaveAnsiStringToFile( sFN, sSerialCipherText);
FFileName_Plain := sFN; // Store for Button4Click()
Put('encrypted serial number save to file "%s".',[sFN])
end;
end;
procedure TmfmDoubleEncrypt.Button4Click;
// This method is equivalent to gEdit101's Button4Click()
var
sPlainText: string;
sSerialCipherText: AnsiString;
sFN: string;
begin
Codec2.Reset;
FFileName_Cipher := FFileName_Plain + '_enc.dat'; // Not a text file. + '_enc.txt' would be wrong.
Codec2.EncryptFile( FFileName_Plain, FFileName_Cipher);
Put( 'Double Encrypted serial number is now stored in file "%s"', [FFileName_Cipher]);
end;
function TmfmDoubleEncrypt.ReconstructSerial: string;
var
CipherStream, PlainStream: TStream;
sEncryptedSerial: AnsiString;
begin
CipherStream := TFileStream.Create( FFileName_Cipher, fmOpenRead);
PlainStream := TMemoryStream.Create;
try
Codec2.Reset;
Codec2.DecryptStream( PlainStream, CipherStream);
PlainStream.Position := 0;
SetLength( sEncryptedSerial, PlainStream.Size);
if Length( sEncryptedSerial) > 0 then
PlainStream.ReadBuffer( sEncryptedSerial[1], Length( sEncryptedSerial));
Codec1.Reset;
Codec1.DecryptString( result, sEncryptedSerial)
finally
CipherStream.Free;
PlainStream.Free
end
end;
function TmfmDoubleEncrypt.SelfTest: boolean;
var
sRecon: string;
begin
Put('Commencing self test...',[]);
try
Button1Click; // 1st encryption
Button4Click; // 2nd encryption
sRecon := ReconstructSerial; // Reconstruction
result := sSerial = sRecon
finally
Put('Finished self test. Result = %s',[BoolToStr( result, True)]);
end;
end;
end.
The dfm for this unit is ...
object mfmDoubleEncrypt: TmfmDoubleEncrypt
Left = 0
Top = 0
Caption = 'Double Encrypt'
ClientHeight = 304
ClientWidth = 643
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
DesignSize = (
643
304)
PixelsPerInch = 96
TextHeight = 13
object btnGo: TButton
Left = 8
Top = 8
Width = 75
Height = 25
Caption = 'Go'
TabOrder = 0
OnClick = btnGoClick
end
object memoLog: TMemo
Left = 8
Top = 39
Width = 627
Height = 257
Anchors = [akLeft, akTop, akRight, akBottom]
Color = clInfoBk
ReadOnly = True
ScrollBars = ssVertical
TabOrder = 1
end
object Codec1: TCodec
AsymetricKeySizeInBits = 1024
AdvancedOptions2 = []
CryptoLibrary = CryptographicLibrary1
Left = 440
Top = 112
StreamCipherId = 'native.StreamToBlock'
BlockCipherId = 'native.AES-128'
ChainId = 'native.CBC'
end
object Codec2: TCodec
AsymetricKeySizeInBits = 1024
AdvancedOptions2 = []
CryptoLibrary = CryptographicLibrary1
Left = 536
Top = 112
StreamCipherId = 'native.StreamToBlock'
BlockCipherId = 'native.AES-128'
ChainId = 'native.CBC'
end
object CryptographicLibrary1: TCryptographicLibrary
Left = 480
Top = 48
end
object dlgSave1: TSaveDialog
InitialDir = 'C:\Temp'
Title = 'Choose location to save Authentication Code'
Left = 440
Top = 176
end
object dlgOpen1: TOpenDialog
InitialDir = 'C:\'
Left = 536
Top = 176
end
end

Resources