View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0004635 | JEDI VCL | 00 JVCL Components | public | 2008-12-22 08:40 | 2009-07-08 14:10 |
Reporter | wesson | Assigned To | obones | ||
Priority | normal | Severity | minor | Reproducibility | sometimes |
Status | resolved | Resolution | fixed | ||
Product Version | Daily / GIT | ||||
Target Version | Fixed in Version | 3.38 | |||
Summary | 0004635: Under non unicode versions of Delphi AppStorage classes may fail to properly save / reload unicode strings | ||||
Description | This apply to D2007 and below, and under a Japanese version of Windows. Some stored wide (unicode) strings might be garbaged by the JvRegistryAppStorage component. Internally, unicode string are converted into UTF-8 strings. however, when these strings are stored to and loaded from the registry, they are considered as ANSI strings - so windows may apply some sort of conversion with the current user default code page. Problem is that, for japanese users (and maybe other like chinese ...), the codepage-based conversion may misinterpret UTF-8 formatted string, such as when the string is reloaded from the registry, it might have been changed by windows. This may corrupt stored pathes containing unicode characters. For instance we store a path to user's documents, and user name has some japanese characters. | ||||
Additional Information | Solution might be to implement virtual methods DoReadWideString and DoWriteWideString in base class (on the model of DoReadString and DoWriteString), and override them in JvRegistryAppStorage class with direct access to widestring registry storage (to avoid the use of UTF-8 formatted strings in registry) | ||||
Tags | No tags attached. | ||||
|
Issue added as requested by Obones in notes of issue 4586 " As to the ReadWideString/WriteWriteString functions, please create a new issue with more details for them " |
|
Could you provide diff for both the base class and the registry storage class? |
|
Hello, any news? |
|
sorry for the delay, I forgot this. I'll add this asap |
|
Any News? |
2009-06-29 10:35
|
jvRegistryStorage_safe_widestring.patch (4,726 bytes)
Index: run/JvAppRegistryStorage.pas =================================================================== --- run/JvAppRegistryStorage.pas (revision 12353) +++ run/JvAppRegistryStorage.pas (working copy) @@ -1,4 +1,4 @@ -{----------------------------------------------------------------------------- +{----------------------------------------------------------------------------- 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 @@ -120,6 +120,8 @@ procedure DoWriteString(const Path: string; const Value: string); override; function DoReadBinary(const Path: string; Buf: TJvBytes; BufSize: Integer): Integer; override; procedure DoWriteBinary(const Path: string; const Buf: TJvBytes; BufSize: Integer); override; + function DoReadWideString(const Path: string; const Default: Widestring): Widestring; override; + procedure DoWriteWideString(const Path: string; const Value: Widestring); override; class function GetStorageOptionsClass: TJvAppStorageOptionsClass; override; public constructor Create(AOwner: TComponent); override; @@ -514,6 +516,33 @@ RegWriteString(FRegHKEY, SubKey, ValueName, Value); end; +function TJvAppRegistryStorage.DoReadWideString(const Path: string; const Default: Widestring): Widestring; +var + SubKey: string; + ValueName: string; +begin + SplitKeyPath(Path, SubKey, ValueName); + try + Result := RegReadWideStringDef(FRegHKEY, SubKey, ValueName, Default); + except + on E: EJclRegistryError do + if StorageOptions.DefaultIfReadConvertError then + Result := Default + else + raise; + end; +end; + +procedure TJvAppRegistryStorage.DoWriteWideString(const Path: string; const Value: Widestring); +var + SubKey: string; + ValueName: string; +begin + SplitKeyPath(Path, SubKey, ValueName); + CreateKey(SubKey); + RegWriteWideString(FRegHKEY, SubKey, ValueName, Value); +end; + function TJvAppRegistryStorage.DoReadBinary(const Path: string; Buf: TJvBytes; BufSize: Integer): Integer; var SubKey: string; Index: run/JvAppStorage.pas =================================================================== --- run/JvAppStorage.pas (revision 12353) +++ run/JvAppStorage.pas (working copy) @@ -349,6 +349,14 @@ function DoReadString(const Path: string; const Default: string): string; virtual; abstract; { Stores an string value. } procedure DoWriteString(const Path: string; const Value: string); virtual; abstract; + + { Retrieves the specified string value. If the value is not found, the Default will be + returned. If the value is not a string (or can't be converted to a string an EConvertError + exception will be raised. } + function DoReadWideString(const Path: string; const Default: Widestring): Widestring; virtual; + { Stores an string value. } + procedure DoWriteWideString(const Path: string; const Value: Widestring); virtual; + { Retrieves the specified value into a buffer. The result holds the number of bytes actually retrieved. } function DoReadBinary(const Path: string; Buf: TJvBytes; BufSize: Integer): Integer; virtual; abstract; @@ -1745,11 +1753,27 @@ Result := DoReadFloat(Path, Default); end; +function TJvCustomAppStorage.DoReadWideString(const Path: string; + const Default: Widestring): Widestring; +begin + {$IFDEF COMPILER12_UP} + Result := UTF8ToWideString(RawByteString(ReadString(Path, string(UTF8Encode(Default))))); + {$ELSE} + Result := UTF8Decode(ReadString(Path, UTF8Encode(Default))); + {$ENDIF COMPILER12_UP} +end; + procedure TJvCustomAppStorage.DoWriteDateTime(const Path: string; Value: TDateTime); begin DoWriteFloat(Path, Value); end; +procedure TJvCustomAppStorage.DoWriteWideString(const Path: string; + const Value: Widestring); +begin + DoWriteString(Path,string(UTF8Encode(Value))); +end; + procedure TJvCustomAppStorage.DoError(const msg: string); begin if Assigned(OnError) then @@ -3220,17 +3244,13 @@ function TJvCustomAppStorage.ReadWideString(const Path: string; const Default: WideString = ''): WideString; begin - {$IFDEF COMPILER12_UP} - Result := UTF8ToWideString(RawByteString(ReadString(Path, string(UTF8Encode(Default))))); - {$ELSE} - Result := UTF8Decode(ReadString(Path, UTF8Encode(Default))); - {$ENDIF COMPILER12_UP} + Result := DoReadWideString(Path,Default); end; procedure TJvCustomAppStorage.WriteWideString(const Path: string; const Value: WideString); begin - WriteString(Path, string(UTF8Encode(Value))); + DoWriteWideString(Path,Value); end; {$ENDIF COMPILER6_UP} |
|
Finally it is here, attached patch build on revision 12353 The base AppStorage class receive 2 additionnal virtual methods to handle widestrings, The registry AppStorage class override these methods to explicitly call RegReadWideString/RegWriteWideString for WideString storage, instead of converting WideString to UTF8 string and load/store them using RegReadString/RegWriteString Please note that starting from Delphi 2009 , this is no longer required |
|
This is now in SVN. |
Date Modified | Username | Field | Change |
---|---|---|---|
2008-12-22 08:40 | wesson | New Issue | |
2008-12-22 08:44 | wesson | Note Added: 0015171 | |
2008-12-23 00:41 | obones | Relationship added | related to 0004586 |
2008-12-23 00:42 | obones | Note Added: 0015177 | |
2008-12-23 00:42 | obones | Status | new => feedback |
2009-04-29 11:19 | obones | Note Added: 0015440 | |
2009-04-29 15:36 | wesson | Note Added: 0015482 | |
2009-06-28 16:53 | jfudickar | Note Added: 0015728 | |
2009-06-29 10:35 | wesson | File Added: jvRegistryStorage_safe_widestring.patch | |
2009-06-29 10:41 | wesson | Note Added: 0015732 | |
2009-07-03 17:30 | obones | Status | feedback => acknowledged |
2009-07-08 14:10 | obones | Note Added: 0015780 | |
2009-07-08 14:10 | obones | Status | acknowledged => resolved |
2009-07-08 14:10 | obones | Fixed in Version | => Daily / SVN |
2009-07-08 14:10 | obones | Resolution | open => fixed |
2009-07-08 14:10 | obones | Assigned To | => obones |