How to use TMemo for email message body in Delphi - delphi

I have a TMemo object with about 30 lines (some text, some blank lines) of text in it representing the message body of an email I want the application to send. In the code below I'm passing the text in the TMemo object to IdMessage1.Body.Text (Indy 10), but my resulting email message body appears that it's just one continuous line wrapped. I would like to see the spacing I have that contains some blank lines. If I copy the contents from the Lines parameter of the TMemo and paste it into a text editor I can see the CR & LF at the end of the lines.
Does the CR & LF get stripped off in this translation, should I be using a different component rather than TMemo for this, or am I passing the lines in the TMemo to the IdMessage1.Body.Text incorrectly?
IdMessage1.Body.Text := EmailBodyMemo.Text;
IdMessage1.ContentType := 'text/html';

The TMemo.Text property returns the entire content as a single string without any "soft" (word-wrapping) line breaks inserted between each line, only "hard" line breaks (explicit CR/LF characters).
Use this instead:
IdMessage1.Body.Text := EmailBodyMemo.Lines.Text;
Lines.Text returns a string that has each line separated by Lines.LineBreak (CRLF by default on Windows).
Or better, use this instead:
IdMessage1.Body := EmailBodyMemo.Lines;
Which is the same as doing this:
IdMessage1.Body.Assign(EmailBodyMemo.Lines);

Related

How to assign (display) Unicode UTF-32 (Miscellaneous Symbols and Pictographs) to TLabel.Caption?

I want to display 📍 (U+1F4CD - round pushpin) in a TLabel caption (lblLocation) displaying something like : "📍 Pretoria, South Africa", but I keep getting a weird block-like thing instead.
I have tried pasting the character directly into my source code, but this also results in a weird block-like thing (my source code is UTF-8 encoded).
Before Pasting 📍:
Directly after pasting 📍:
I have also tried using ConvertFromUtf32(), per How to convert unicode codepoint like U+1F4DB to char?.
lblLocation.Caption := lblLocation.Caption + ConvertFromUtf32(StrToInt('$1F4CD'));
Running the above code gives this in the caption of the TLabel:
The character that you are trying to display does not have a glyph in the font that you are using. You need to find a font that does have a glyph for this character.

How to write txt-file in blob

There is Firebird table with 2 blob fields- blob_binary field(subtype=0) and blob_Text field(subtype=1,utf-8).
DB has utf-encoding. Connection has utf encoding.
Version of Delphi is 10.2.3. I use FireDac components for data access. Server is Firebird 3.
App must write data from text-file(utf-8) to both blob-fields of "Content" table.
Text file, what I must write in blobs, contains text on English, Russian and Georgian languages(see image).
Project and DB files, with editing permission
Code below writes text in binary blob field but characters are strange(not ??? simbols. Maybe Ansi characters?).
Code for save text-file in Blob_Binary field:
ID:=Query1.FieldByName('Content_id').asInteger;
OpenDialog1.Execute;
Query1.Close;
Query1.SQL.Text := 'SELECT * FROM content where Content_id=:id';
Query1.Params[0].AsInteger:=ID;
Query1.open;
Query1.Edit;
(Query1.FieldByName('BLOB_BINARY') as TBlobField).LoadFromFile(OpenDialog1.FileName);
Query1.Post;
When I save text file in binary blob field then:
1) if I saved text file in encoding utf-BOM I get in binary blob normal text and
2) strange characters if I choose for text file encoding utf.
But when I use the same code for writing data in text blob field data appears strange like chinese characters (see image).
What do I wrong? How to correct this code to write in both fields utf characters?
I tried another solutions but result is the same. For example:
ID:=Query1.FieldByName('Content_id').asInteger;
OpenDialog1.Execute;
Query1.Close;
Query1.SQL.Text := 'Update content set Blob_Text=:Blob_Text where
Content_id=:id';
Query1.Params[0].DataType := ftBlob;
Query1.Params[0].AsStream := TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
Query1.Params[1].AsInteger:=ID;
Query1.ExecSQL;
Update1: As I realised, if I save txt-file as "unicode" in noteped(or ucs-2 LE BOM in noteped++) it is saved fine in text blob, chines characters disappeared. Similarly, txt-file in binary blob is saved fine if it is in utf-BOM encoding. Although it's very uncomfortable not be able to save file in utf-8.
What you're seeing is known as mojibake, caused by interpreting text in a different encoding than the one it was originally written in. When you get random CJK (Chinese/Japanese/Korean) characters, it usually comes from incorrectly interpreting 8-bit (ASCII, ANSI, UTF-8, etc) encoded text as UTF-16. Have a look at your string types and the string types going into and coming out of the database, and check for compiler warnings about ANSI and Unicode string type mismatches, and you should be able to get to the bottom of this fairly quickly.
I have a same bug with ADOQuery and Firebird 2.5 Blob Field Sub_Type 1 (Text)
String fields are converted fine, blobs are not.
If I change connection to IBX, all works fine
Solved by:
SettingsTEXT.AsString := UTF8Decode(SettingsTEXT.AsString)

How to count characters in RichEdit without two characters that every new line gives?

I have problem with counting characters in richedit (Delphi XE).
For every new line as a result i get two characters more but in text they not exists.
Example: Here are 15 characters, but richedit gives 17 because of new line.
line zero
line one
Is there solution for this?
Remove CR/LFs and get the count of the remaining characters. An example:
NumChars := Length(StringReplace(RichEdit1.Text, sLineBreak, '', [rfReplaceAll]));

Error because of quote char after converting file to string with Delphi XE?

I have incorrect result when converting file to string in Delphi XE. There are several ' characters that makes the result incorrect. I've used UnicodeFileToWideString and FileToString from http://www.delphidabbler.com/codesnip and my code :
function LoadFile(const FileName: TFileName): ansistring;
begin
with TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite) do
begin
try
SetLength(Result, Size);
Read(Pointer(Result)^, Size);
// ReadBuffer(Result[1], Size);
except
Result := '';
Free;
end;
Free;
end;
end;
The result between Delphi XE and Delphi 6 is different. The result from D6 is correct. I've compared with result of a hex editor program.
Your output is being produced in the style of the Delphi debugger, which displays string variables using Delphi's own string-literal format. Whatever function you're using to produce that output from your own program has actually been fixed for Delphi XE. It's really your Delphi 6 output that's incorrect.
Delphi string literals consist of a series of printable characters between apostrophes and a series of non-printable characters designated by number signs and the numeric values of each character. To represent an apostrophe, write two of them next to each other. The printable and non-printable series of characters can be written right not to each other; there's no need to concatenate them with the + operator.
Here's an excerpt from the output you say is correct:
#$12'O)=ù'dlû'#6't
There are four lone apostrophes in that string, so each one either opens or closes a series of printable characters. We don't necessarily know which is which when we start reading the string at the left because the #, $, 1, and 2 characters are all printable on their own. But if they represent printable characters, then the 0, ), =, and ù characters are in the non-printable region, and that can't be. Therefore, the first apostrophe above opens a printable series, and the #$12 part represents the character at code 18 (12 in hexadecimal). After the ù is another apostrophe. Since the previous one opened a printable string, this one must close it. But the next character after that is d, which is not #, and therefore cannot be the start of a non-printable character code. Therefore, this string from your Delphi 6 code is mal-formed.
The correct version of that excerpt is this:
#$12'O)=ù''dlû'#6't
Now there are three lone apostrophes and one set of doubled apostrophes. The problematic apostrophe from the previous string has been doubled, indicating that it is a literal apostrophe instead of a printable-string-closing one. The printable series continues with dlû. Then it's closed to insert character No. 6, and then opened again for t. The apostrophe that opens the entire string, at the beginning of the file, is implicit.
You haven't indicated what code you're using to produce the output you've shown, but that's where the problem was. It's not there anymore, and the code that loads the file is correct, so the only place that needs your debugging attention is any code that depended on the old, incorrect format. You'd still do well to replace your code with that of Robmil since it does better at handling (or not handling) exceptions and empty files.
Actually, looking at the real data, your problem is that the file stores binary data, not string data, so interpreting this as a string is not valid at all. The only reason it works at all in Delphi 6 is that non-Unicode Delphi allows you to treat binary data and strings the same way. You cannot do this in Unicode Delphi, nor should you.
The solution to get the actual text from within the file is to read the file as binary data, and then copy any values from this binary data, one byte at a time, to a string if it is a "valid" Ansi character (printable).
I will suggest the code:
function LoadFile(const FileName: TFileName): AnsiString;
begin
with TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite) do
try
SetLength(Result, Size);
if Size > 0 then
Read(Result[1], Size);
finally
Free;
end;
end;

Reading a newline character from a socket in Delphi

I'm working on a program in Delphi that has to conform to the ADC standard protocol. This protocol specifies that each line is terminated with a newline character (#10#13 OR sLineBreak). The problem is that the newline character doesn't seem to be surviving the trip from the server to the program. Reading the data from the socket seems to simply give it all as one massive line. I was thinking it was something to do with the way the program displayed debug messages (to a TMemo object), but a Pos(sLineBreak, Buf) always returns 0 (meaning it couldn't find the string).
My code:
procedure OnRead(Sender: TObject; Socket: TCustomWinSocket);
begin
//read all the data from the socket
while Socket.ReceiveLength > 0 do
Buf := Buf + Socket.ReceiveText;
//use only complete lines
while Pos(sLineBreak, Buf) > 0 do begin
//parsing stuff
end;
end;
Also, the server doesn't have to send the commands in different steps, it can send them all at once with newlines in them, hence the need to read the entire socket in, then go through it as opposed to assuming one command per socket read.
The protocol specification says "a newline (codepoint 0x0a) ends each message." That's a single character. In Delphi syntax, it's #10 or #$a.
The usual value for sLineBreak on Windows is #13#10 — the carriage return comes first, then the newline. The sequence #10#13 is not a line break on any platform I'm aware of.
Everything displays as one line in your memo control because you're receiving only newline characters, without the carriage returns, and TMemo expects both characters to end a line. It's the same as if you'd loaded a Unix-style text file in Notepad.
Hmm, the page you link seems to firmly state in the message syntax that new line is a single char:
eol ::= #x0a
while sLineBreak is two chars on Windows as you state.

Resources