Delphi - conversion among charactersets - explanation and how to do it? [duplicate] - delphi

This question already has an answer here:
SetThreadLocale for the entire Delphi application
(1 answer)
Closed 6 years ago.
My Delphi program does not retrieve the right characters. SetThreadLocale for the entire Delphi application is the context of my problem. I am using Firebird 1.5 charset NONE database which contains WIN1257 data. I am using Delphi 10 Seattle IBX componentes to retrieve data from this database. Usually I use my program on Windows with one of the Baltic locale for non-Unicode programs. But sometimes I need to run my program on Windows with Russian locale (WIN1251 characterset).
And I am stuck with the following problem: database varchar field contains character ā, which is retrieved in Delphi code (fieldname.asString) as \u0101 when the program is run with Baltic locale, but it is retrievied (fieldname.asString) as \u0432 when the program is run with Russian locale, but I need it to be displayed as \u0101 in Russian case as well.
I have tried to set all the connection parameters to TIBDatabase but failed to achieve my goal. So - now I have idea to do translation: I can detect that program is running under Russian locale and in that case I can apply special conversion function like MyConvert(fieldname.asString) to convert \u0432 into \u0101 and something like this for all the characters.
The question is - is there such conversion function available and how to use it? What is the algorithm that determines the bijection \u0432 <-> \u0101?
Migration to the unicode database is not my option.
Current question tries to solve the same core problem as SetThreadLocale for the entire Delphi application but with different approach. I have not managed to set thread locale for my application and therefore I decided to make character conversion and this question is - how to do it?
Added: https://en.wikipedia.org/wiki/Windows-1251 and https://en.wikipedia.org/wiki/Windows-1257 palettes show that a has E2 position and this position in both palettes have different, but known Unicode characters, so the mapping is known and there is no single formula how to express it, it should be done character by character basis.

The following function is the answer I sought:
function MyConversionFunction(AChar: Char): Char;
begin
case Ord(AChar) of
//A_
$045E: Result:=Char($00A2);
$0408: Result:=Char($00A3);
$00A4: Result:=Char($00A4);
$00A6: Result:=Char($00A6);
$00A7: Result:=Char($00A7);
$0401: Result:=Char($00D8);
$00A9: Result:=Char($00A9);
$0404: Result:=Char($0156);
$00AB: Result:=Char($00AB);
$00AC: Result:=Char($00AC);
$00AD: Result:=Char($00AD);
$00AE: Result:=Char($00AE);
$0407: Result:=Char($00C6);
//B_
$0406: Result:=Char($00B2);
$0456: Result:=Char($00B3);
$0491: Result:=Char($00B4);
$0451: Result:=Char($00F8);
$2116: Result:=Char($00B9);
$0454: Result:=Char($0157);
$0458: Result:=Char($00BC);
$0405: Result:=Char($00BD);
$0455: Result:=Char($00BE);
$0457: Result:=Char($00E6);
//C_
$0410: Result:=Char($0104);
$0411: Result:=Char($012E);
$0412: Result:=Char($0100);
$0413: Result:=Char($0106);
$0414: Result:=Char($00C4);
$0415: Result:=Char($00C5);
$0416: Result:=Char($0118);
$0417: Result:=Char($0112);
$0418: Result:=Char($010C);
$0419: Result:=Char($00C9);
$041A: Result:=Char($0179);
$041B: Result:=Char($0116);
$041C: Result:=Char($0122);
$041D: Result:=Char($0136);
$041E: Result:=Char($012A);
$041F: Result:=Char($013B);
//D_
$0420: Result:=Char($0160);
$0421: Result:=Char($0143);
$0422: Result:=Char($0145);
$0423: Result:=Char($00D3);
$0424: Result:=Char($014C);
$0425: Result:=Char($00D5);
$0426: Result:=Char($00D6);
$0427: Result:=Char($00D7);
$0428: Result:=Char($0172);
$0429: Result:=Char($0141);
$042A: Result:=Char($015A);
$042B: Result:=Char($016A);
$042C: Result:=Char($00DC);
$042D: Result:=Char($017B);
$042E: Result:=Char($017D);
$042F: Result:=Char($00DF);
//E_
$0430: Result:=Char($0105);
$0431: Result:=Char($012F);
$0432: Result:=Char($0101);
$0433: Result:=Char($0107);
$0434: Result:=Char($00E4);
$0435: Result:=Char($00E5);
$0436: Result:=Char($0119);
$0437: Result:=Char($0113);
$0438: Result:=Char($010D);
$0439: Result:=Char($00E9);
$043A: Result:=Char($017A);
$043B: Result:=Char($0117);
$043C: Result:=Char($0123);
$043D: Result:=Char($0137);
$043E: Result:=Char($012B);
$043F: Result:=Char($013C);
//F_
$0440: Result:=Char($0161);
$0441: Result:=Char($0144);
$0442: Result:=Char($0146);
$0443: Result:=Char($00F3);
$0444: Result:=Char($014D);
$0445: Result:=Char($00F5);
$0446: Result:=Char($00F6);
$0447: Result:=Char($00F7);
$0448: Result:=Char($0173);
$0449: Result:=Char($0142);
$044A: Result:=Char($015B);
$044B: Result:=Char($016B);
$044C: Result:=Char($00FC);
$044D: Result:=Char($017C);
$044E: Result:=Char($017E);
$044F: Result:=Char($02D9);
else Result:=AChar;
end;
end;

Related

Delphi 2007 - Compile errors on updating Indy from 10.5.1.1 to 10.6.2.0

I recently updated the stock Indy that installs with Delphi 2007 (I think it is 10.5.1.1) with 10.6.2.0, which I downloaded from GitHub.
I'm now getting a compile error:
EAttachmentFileNotFound.IfFalse (FileExists (parActualAttachmentFileID), 'File ' + parActualAttachmentFileID + ' not found.') ;
Error: E2003 Undeclared identifier: 'IfFalse'
The fragment is from my own code but I'm pretty sure that bit came from something I found probably on S/Overflow.
I received a couple of other errors also:
SMTPClient.AuthType := atDefault ;
Error: E2003 Undeclared identifier: 'atDefault'
and
SMTPClient.OnWork := EmailThread.EmailOnWork ;
Error: E2010 Incompatible types: 'Int64' and 'Integer'
but the first is a member that was renamed, and the second a data type that was changed. While these were a simple enough workaround, I'm left wondering
whether there was ever a "breaking changes" document generated.
maybe I accidentally somehow got the wrong source set.
EAttachmentFileNotFound is not a standard Indy exception, so it must be coming from your own code, or another 3rd party library.
Delphi 2007 was released almost 16 years ago. A lot has changed in Indy during that time. In fact, I think the changes you mention were actually made prior to, or maybe around, the release of Delphi 2007 (as they already existed in Indy's code in early 2008).
For instance:
in EIdException, the If(True|False) methods were removed (I don't know when exactly that change happened). In which case, you will have to use your own if and raise expressions now, eg:
if not FileExists(parActualAttachmentFileID) then
raise EAttachmentFileNotFound.Create('File ' + parActualAttachmentFileID + ' not found.');
in TIdComponent, the AWorkCount/Max parameters of the OnWork... events were changed from Integer to Int64 in 2006 (see OnWork Events changed to 64 bit on Indy's blog).
in TIdSMTP, the atDefault value was renamed to satDefault (again, I don't know exactly when this change was made).
So, you need to update your code accordingly.
I'm left wondering whether there was ever a "breaking changes" document generated.
No such document was ever created, no. However, changes that affect user code are typically announced on Indy's blog, under the Changelog category.

Delphi App Upgrade from Delphi 10 Seattle to Delphi 13.3.3 Rio - SQL Server Db Column with Space(s) not working in ClientDataSet and SimpleDataSet

We are upgrading our Working Delphi App from Delphi 10 Seattle to Delphi 13.3.3 Rio - SQL Server Db Column with Space(s)
The code associated with this issue works as intended in Delphi 10 Seattle and SQLServer.
The problem is that the Column "Image Type" has a space in its name.
I am looking to solve the space in column names for ClientDataSet and SimpleDataSet
This applies to other table that we have. I know that a parameterized SQL would work as a workaround.
The following Insert SQL Execute statements work as intended.
INSERT INTO tblImages ("Line","Image Type","Image") VALUES ('1','jpg','imageBlobValue')
or
INSERT INTO tblImages ([Line],[Image Type],[Image]) VALUES ('1','jpg','imageBlobValue')
The following Insert via ClientDataSet Does not
//Query
SQLQueryInsert.Cose;
SQLQueryInsert.SQL:='SELECT "Line","Image Type","Image" FROM tblImages';//Oracle & Other SQLs
SQLQueryInsert.SQL:='SELECT [Line],[Image Type],[Image] from tblImages';//SQLServer
SQLQueryInsert.Open;
//Set Non parameterized values
//DataSet
ClientDataSettblImages.Close;
ClientDataSettblImages.Open;
ClientDataSettblImages.Insert;
ClientDataSettblImages['Line']:='1';
ClientDataSettblImages['Image Type']:='jpg';
ClientDataSettblImages['Image']:='imageBlobValue';
//Apply Updates
ClientDataSettblImages.Post;
If ClientDataSettblImages.ChangeCount > 0 then
Begin
ClientDataSettblImages.ApplyUpdates(-1);
End
If I look at the text output of SQLMonitor I can see the following:
Error: SQL State: 1, SQL Error Code: 156, Level: 15, Procedure: , Line: 2
Incorrect syntax near the keyword 'Type'.
ClientDataSet & SimpleDataSet have the same issue. I can see that the problem is the column with the space called "Image Type". The insert via the ClientDataSet works fine without the column "Image Type".
This either looks like a ClientDataSet bug or I'm missing a simple detail somewhere.
Looks like the answer is to add the following Parameter to SQLConnection: UseQuoteChar=True. The Application is now working as intended.

Fast Report fr3 File loading Error in Delphi

I have question about loading *.fr3 in DelphiXE5,
I designed a report and pointed some text to Memo inside of Fast Report everything was ok until I want to load fast Report file from out site App it works for my PC perfectly but when I install client side it gets Error like this Photo include in this message
And the code I used is:
begin
frxReport1.LoadFromFile(ExtractFilePath(Application.ExeName)+'R1.fr3');
frxReport1.PrepareReport();
frxReport1.ShowReport();
end;
Error message:
'18/89765' is not a valid floatin point value
'238/11039' is not a valid floatin point value
'275/90569' is not a valid floatin point value
'41984/5614698264' is not a valid floatin point value
'41984/5618072454' is not a valid floatin point value
'94/48825' is not a valid floatin point value
I found the problem, the problem was Microsoft windows 8.1
I'm using Microsoft Windows 8.1, Delphi Xe 5 and Fast-report 4.15.6
First I made a report in fast report without any change and then run my app in windows 7 save as Fast-report to file and then use in all version of Microsoft Windows, thanks a lot
The problem has been originated form Regional Settings.
Win 8.1 automatically changes decimal separator as '.' to '/' in Persian language, even in fast reports.
The Microsoft has to figure this problem out.
step 1: open frxutils.pas from fastreport lib
step 2: function frxStrToFloat(s: String): Extended;
step 3: relapse this code: [',', '.']) with [',', '.','/']

invalid request BLR at offset 163

I have the following error in the Firebird Database. version 2.5.2
invalid request BLR at offset 163
function F_ENCODEDATE is not defined
module name or entrypoint could not be found
Error while parsing procedure GETMONTHSBYYEAR's BLR
Until last week everything was functioning correctly. This UDF exists on the disk. How can I debug this problem? Anyone can help me to sort out this problem.
PS: What I did so far to fix:
Backup / restore - no result. (any structure problem is fixed in my opinion after a BK/Restore).
Comment all dependencies, drop UDF function, recreate again - no result.
Potential problems could be that he UDF dll is inaccessible for the server (eg due to permissions, or the UDF restriction config in firebird.conf), or you have installed a 64 bit version of Firebird and your UDF is 32 bit (or vice versa), so Firebird cannot load the DLL.

Reconcile Error: Has anyone had problems with truncated error messages?

I'm here again to ask for a help to you. This time I believe that few will respond given the great particularity of the problem which I will relate. I'm starting in the world of DataSnap, and still have things I do not understand how this error I will relate.
My Delphi is XE (version 1, Update1). I am using Postgres which generates error messages in Portuguese (Portuguese Brazil) and for this reason the error messages have accents. The connection components are ZeosLib package.
I am using a dialog box "reconcile error" to display errors arising from the application of updates and to test, I tried to insert a record that already existed, thus violating a unique key and thus displaying the reconcile error dialog.
In the memo of the dialog, the message that appears is truncated, ie cut. Check it out:
ERRO: duplicar valor da chave viola a restrição de unicidade "uc_usu_va_login"
DETAIL: Chave (va_login)=(admin) já existe.
CONTEXT: comando SQL "INSERT INTO USUARIOS (VA_NOME
,VA_LOGIN
,CH
But actually what should be returned is this:
ERRO: duplicar valor da chave viola a restrição de unicidade "uc_usu_va_login"
DETAIL: Chave (va_login)=(admin) já existe.
CONTEXT: comando SQL "INSERT INTO USUARIOS (VA_NOME
,VA_LOGIN
,CH_SENHA
,VA_EMAIL)
VALUES (pVA_NOME
,pVA_LOGIN
,pCH_SENHA
,pVA_EMAIL)"
PL/pgSQL function "idu_usuarios" line 7 at comando SQL
I have done a debug on the server to see if the problem is ZeosLib, but I found that the error message generated on the server is complete, proving that ZeosLib does not truncate the message. Everything is unicode. All strings are WideString (the default) on both my program and in ZeosLib.
As you know, to be thrown on the server, the exception is forwarded to the client, roughly speaking, by DataSnap, and on the client, the Reconcile method of TClientDataSet verify if there were problems and then throw the famous exception EReconcileError that can be handled in the OnReconcileError event of TClientDataSet, therefore I believe that the message is being truncated by DataSnap.
On the client I debug the Reconcile method (DBClient.pas) and immediately before the exception is thrown the flow enters a function within a cpp source code that I think part of the library midas.dll, MidasLib.obj more specifically, since I am using this strategy, not to have to distribute the DLL with my application.
Check(FDSBase.Reconcile_MD(FReconcileDataSet.FDSBase, FDeltaPacket, VarToDataPacket(Results), Integer(Self), RCB));
This call is done at line 1952 of the unit DBClient.pas on Delphi XE Update1. Pressing F7, the debugger enters a source C++ (cpp), so I believe it is within the midaslib.obj. How I do not understand C++ well, I press Shift-F8 to exit the current method and return the next instruction, that is already inside the event OnReconcileError!! Therefore, the truncation must be done within the function I mentioned, within a cpp source, within midaslib.
My intention is to make the Reconcile Error dialog a tool not only for the final user but to support personals, providing separately information of Error, Details and Context. This helps a lot to discover a problem.
The problem now is to make the message appear in full. Has anyone had this kind of problem with messages being truncated by midas?
Also another point DSClient.pas I could extract the error message as it is passed to the exception:
'Erro SQL: ERRO: duplicar valor da chave viola a restrição de unicidade "uc_usu_va_login"'#$A'DETAIL: Chave (va_login)=(admin) já existe.'#$A'CONTEXT: comando SQL "INSERT INTO USUARIOS (VA_NOME'#$A' ,VA_LOGIN'#$A' ,CH'
If you remove the quotes and replace #$A (1 character) by a white space (one character), you will see that the string has exactly 255 characters!!
I also discovered that the "GetErrorString" in dspickle.cpp uses the constant DBIMAXMSGLEN which is defined in bdetypes.h as 127 (half of 255). As we are in the world of Unicode, it would not be a question of increasing this value to 255 in order to have two bytes per character? This is only a guess...
I leave the question in the air because I lack the knowledge to understand C++ :) Who can help, just look at the function implementation "GetErrorString" in dspickle.cpp. There is this:
LoadString((HINSTANCE)hDll, iErrCode, pString, DBIMAXMSGLEN)
pString is the error message and DBIMAXMSGLEN = 127.
Contradicting the opinion of others I decided to tweak further and finally figured out how to increase the number of characters in the "Reconcile" error message. As I thought the problem was in midas.dll, or more specifically the sources that make up the midas dll because the same set of sources can create MidasLib, which does not require a midas dll. To resolve I had to install the Delphi C++ personality to compile the midas.
After finding the line of the error, I discovered that there is even a request for repairs to the QC (http://qc.embarcadero.com/wc/qcmain.aspx?d=84960) which seems to have been ignored by the staff of Embarcadero, as that the "Resolution" as is "Deferred to Next Rel" (Deferred to Next Release) but the request is from 2010 and I'm using Delphi XE which in my opinion should have the solution but here I am correcting by myself ;)
The problem is inside the method "Clone" of the "DSBASE" class, inside source "ds.cpp" at line 2133 (Delphi XE, Update1). Below is the code block. The red line is the problematic line:
// Set the third field for the error string.
LdStrCpy((pCHAR)pFldDes->szName, szdsERRMESSAGE);
pFldDes->iFldType = fldZSTRING;
pFldDes->iUnits1 = 255; // Increased on request.. DBIMAXMSGLEN;
pFldDes++;
Note that it is very interesting the problem line. It has a constant value of 255, which limits the size of the error messages and a comment "Increased on request". Also note that next to the comment, there is a constant DBIMAXMSGLEN, which I had found and already suspected as being responsible for the problem, but as it was not being used I changed the value of DBIMAXMSGLEN but the error message always came without changes. It is worth mentioning that there is a semicolon (;) after DBIMAXMSGLEN which leads me to think that before (I do not know when) this line was one that was just after my fix:
pFldDes->iUnits1 = DBIMAXMSGLEN;
It's as if someone had deliberately set the field value to 255, removing the previous implementation that was really dynamic and seemingly more correct. After performing the replacement of the line I increased the value of DBIMAXMSGLEN to 1024. DBIMAXMSGLEN is declared "bdetypes.h" as a define. After correcting the line went like this:
#define DBIMAXMSGLEN 1024 // Max message len
After these two changes in "ds.cpp" and "bdetypes.h" I build, test, and the result was as expected: the error message was presented in full in the Reconcile dialog.
To the brave who want to try if they have seen this problem, you need the sources of MIDAS, which comes with Delphi from 2010 if I remember correctly. Good luck to all.

Resources