Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Unicode + BASE64? (https://www.delphipraxis.net/98013-unicode-base64.html)

blackdrake 20. Aug 2007 19:19


Unicode + BASE64?
 
Hallo.

Wieder mal eine meiner vielen Fragen zu Unicode bzw. WideStrings...

Ich möchte einen WideString etwas chiffrieren, sodass dieser nicht direkt über einen HexEditor ausgelesen werden kann. Soll nur eine leichte Chiffrierung wie z.B. BASE64 sein. Jetzt hab ich hier eine schöne Unit für BASE64 gefunden: http://www.delphipraxis.net/internal...ect.php?t=1153 . Diese akzeptiert aber nur Strings als Eingabe. Wenn ich jetzt aber einen Unicode-Widestring habe, würden Nicht-ANSI-Zeichen bei der Abwärtscovertierung verloren gehen. Kennt jemand ein WideString-BASE64 oder ist das totaler Schwachsinn, was ich hier rede? Leider weiß ich gar nicht, wie ein WideString eigentlich funktioniert, da ich bis jetzt nur wenig damit gearbeitet habe. showmessage(copy(mein_widestring, ..., ...)) hat aus irgendeinem Grund ANSI-Strings widergegeben... irgendwie versteh ich die Funktionsweise nicht ganz. :gruebel:

Gruß
blackdrake

Zacherl 20. Aug 2007 19:49

Re: Unicode + BASE64?
 
Base64 würde ich dir auf jeden Fall nicht raten .. nimm eine einfache XOR Verschlüsselung oder die RCx Unit von Hagen. Wenn du Base64 verwendest kannst du das verschleiern auch gleich lassen :P

blackdrake 20. Aug 2007 21:10

Re: Unicode + BASE64?
 
Hallo.

Danke für den Tipp. Ich schau mir das mal an.

Gruß
blackdrake

blackdrake 24. Aug 2007 23:47

Re: Unicode + BASE64?
 
Hallo.

Ich will nun DEC für die Verschlüsselung nutzen.

Dort gibt es eine Funktion der Art Verschlüsselung(input: string): string.

Ist es damit überhaupt möglich, einen WideString zu speichern?

Kann es sein, dass bei der Umwandlung WideString -> String -> WideString alle Unicode-Zeichen (z.B. asiatische) verloren gehen? Ich kapiere es einfach nicht, wie ein WideString funktioniert. Eigentlich könnte der String bei der WideString -> String Umwandlung ja auch der String doppelt so lang werden, damit z.B. asiatische Zeichen nicht verloren gehen.

Wie muss ich das jetzt machen?

Gruß
blackdrake

Bernhard Geyer 25. Aug 2007 07:10

Re: Unicode + BASE64?
 
Konvertiere einfach den String nach UTF8. Dürfte die einfachste Lösung sein. Oder du findest eine Funktion die mit Speicherbereichen (also Typlos) arbeitet und die Daten byteweise "anfaßt"

phXql 25. Aug 2007 09:16

Re: Unicode + BASE64?
 
Du musst nur den Widestring in ein Byte-Array umwandeln und dann das Array verschlüsseln.
Beim Entschlüsseln lädst du das Byte-Array, entschlüsselst es und wandelst es dann in einen Widestring um.

blackdrake 25. Aug 2007 13:30

Re: Unicode + BASE64?
 
Hallo.

Bytearray? Wie soll ich das machen? Copy() funktioniert ja nur mit Strings. Somit kann ich keinen dynamischen "array of bytes" erstellen und ihn dann mit einer "for"-Schleife unter verwendung von "copy" füllen.

Gruß
blackdrake

phXql 25. Aug 2007 14:03

Re: Unicode + BASE64?
 
Weiss nich wie das mit Delphi geht. In C# könnt ichs dir sagen ;)

Zacherl 25. Aug 2007 14:17

Re: Unicode + BASE64?
 
Na du deklarierst dir ein Array of Char (Char UND Byte = 0..255) verwendest SetLength(ByteArray, Length(UnicodeStr)) und kopierst mittels Copy(@ByteArray[0], @UnicodeStr[1], Length(UnicodeStr)) das ganze ins Array.

Dann kannst du der Funktion zum verschlüsseln einfach das ByteArray übergeben. Da dieses als Array of Char deklariert ist und somit nichts anderes als in String ist sollte Delphi das akzeptieren. Ansonsten einfach vorher nach String() typecasten.

blackdrake 25. Aug 2007 14:27

Re: Unicode + BASE64?
 
Mhh... so in etwa? Hier sagt er, es seien inkompatible Typen. :(

Delphi-Quellcode:
function WideStringToString_Lossyless(UnicodeStr: WideString): string;
var
  ByteArray: Array of Char; // Array of Byte
begin
  SetLength(ByteArray, Length(UnicodeStr));
  ByteArray := Copy(@ByteArray[0], @UnicodeStr[1], Length(UnicodeStr));
  result := string(ByteArray);
end;

Zacherl 25. Aug 2007 14:57

Re: Unicode + BASE64?
 
Welche Zeile genau?

blackdrake 25. Aug 2007 14:59

Re: Unicode + BASE64?
 
Bei der Copy-Zeile. Ich glaube 2tes Argument.

Zacherl 25. Aug 2007 15:00

Re: Unicode + BASE64?
 
Dann versuch mal nur @UnicodeStr oder UnicodeStr[0] .. keine Ahnung wie sich das genau verhält.

Bernhard Geyer 25. Aug 2007 15:10

Re: Unicode + BASE64?
 
Zitat:

Zitat von blackdrake
Mhh... so in etwa? Hier sagt er, es seien inkompatible Typen. :(

[delphi]function WideStringToString_Lossyless(UnicodeStr: WideString): string;

Vergiss diesen Versuch! Ein String ist ein String und ein WideString ist ein WideString! Falls du des doch hinbekommst wirst du bei jeder Funktion scheitern die als Stopper ein #$00 am Ende des Strings erwartet.

blackdrake 25. Aug 2007 15:29

Re: Unicode + BASE64?
 
Wie soll ich denn sonst das Problem lösen? Ich muss den WideString ja irgendwie in einen String umwandeln, diesen dann ver- und entschlüsseln und diese Umwandlung danach wieder Rückgängig machen, ohne dass Informationen verloren gehen. Die Grundproblematik ist doch klar, oder? Das ich einen japanischen Text von WideString nicht nach String umwandeln kann, ohne dass dieser nur komische Zeichen enthält, ist mir klar.

Edit: Außerdem gilt #00 bei Strings bzw. #00#00 bei WideStrings ja nur speicherintern bzw bei Streams. Nach der Verschlüsselung hab ich ja nichts mehr dergleichen. Wenn ich einen String "test" habe, ist ja das #00 auch nur innerhalb des RAMs da und nicht im String selbst.

phXql 25. Aug 2007 15:33

Re: Unicode + BASE64?
 
Wieso musst du den Widestring in einen String umwandeln? Das geht nicht, da gehen dir Zeichen verloren. Du musst den Widestring in ein Byte-Array umwandeln und dieses dann verschlüsseln.

Das geht doch bestimmt über irgendwelche Pointer-tricks mit CopyMem(). Aber da kenn ich mich nicht wirklich aus. Ich gehe Pointern aus dem Weg ;)

blackdrake 25. Aug 2007 15:40

Re: Unicode + BASE64?
 
Das meine ich ja, mit Byte-Array zwischenstufe. Der String soll aufgebläht sein, sodass eben keine Informationen verloren gehen. Ist unter Umständen das vorher genannte UTF-8 das, was ich suche?

Wie gesagt, die strings sollen nur als Übergang dienen, weil die Verschlüsselungsroutine nur strings annimmt. Sie sollen keinen Sinn ergeben.

CopyMem() gibt's als Funktion nicht. Und Copy() dient trotz seiner Bezeichnung nur zum Abschneiden von Strings.

phXql 25. Aug 2007 15:46

Re: Unicode + BASE64?
 
Ist CopyMem nicht so n toller Win32-API-Call?

Dass die Verschlüsselungsroutine nur Strings annimmt, is schon ein bisschen doof, wenn man Unicode verarbeiten will. Kannste die nicht auf ein byte-Array umschreiben?

Ein WideChar ist ja 16 Bit, ein normaler Char nur 8 Bit. Wenn du nun von deinem Widechar jeweils die ersten 8 Bit (Hi) in den ersten Char und die letzten 8 Bit (Lo) in den nächsten char kopierst, dann hast du einen doppelt so langen String, aber ohne Verlust von Informationen. Diesen kannst du dann verschlüsseln. Aber ich weiss nicht, ob eventuelle #0 im String Delphi durcheinanderbringen (aber ich denke, Delphi verwaltet die Strings anders als C mit den null-terminierten Strings)...

blackdrake 25. Aug 2007 16:02

Re: Unicode + BASE64?
 
Danke für den Hinweis.

Delphi hat keine Probleme mit Strings und #0. Man hat lediglich Probleme wenn man einen solchen String ausgeben möchte. Er wirkt wie abgeschnitten, was er aber nicht ist.

Folgendes Funktioniert nun:

Delphi-Quellcode:
function WideStringToString_Lossyless(UnicodeStr: WideString): string;
var
  ByteArray: Array of Char;
begin
  SetLength(ByteArray, Length(UnicodeStr));
  CopyMemory(@ByteArray[0], @UnicodeStr[1], Length(UnicodeStr));
  result := string(ByteArray);
end;
Jetzt bin ich nur noch am rumprobieren mit der Reverse-Funktion:

Delphi-Quellcode:
function DoubleStringToWideString(DoubleString: WideString): widestring;
var
  ByteArray: Array of WideChar;
begin
  SetLength(ByteArray, Length(DoubleString) div 2);
  CopyMemory(@DoubleString[1], @ByteArray[0], Length(ByteArray));
  result := widestring(ByteArray);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // Sollte exakt ANSI "test" sein
  showmessage(DoubleStringToWideString(WideStringToString_Lossyless('test')));
end;
Diese funktioniert aber nicht ganz...

Bernhard Geyer 25. Aug 2007 16:14

Re: Unicode + BASE64?
 
Wie schon gesagt: Entweder du suchst dir eine Funktion die mit einfachen Pointer + Längenangabe arbeitet oder du wandelst den String nach UTF8 um und hast das Ergebnis dan in einen String.

Deine Hacker-Funktionen werden scheitern wenn dein bisher ausgesuchte Base64-Methode geziehlt ein #$00 als Stop-Byte annimmt.

Schon mal überlegt ob die Zeile
Delphi-Quellcode:
SetLength(ByteArray, Length(UnicodeStr));
richtig ist wenn eine WideString-Character 2 Bytes einnimmt :gruebel:

Zacherl 25. Aug 2007 16:27

Re: Unicode + BASE64?
 
Als Hintergrundinformation: Ein String ist ein Array of Char = Array of Byte. Insofern haben Strings überhaupt keine Probleme mit #0. Der Datentyp welcher damit Probleme hat, weil er ihn als Trennzeichen ansieht ist PChar, bzw PAnsiChar.

Bernhard Geyer 25. Aug 2007 16:34

Re: Unicode + BASE64?
 
Zitat:

Zitat von Zacherl
Als Hintergrundinformation: Ein String ist ein Array of Char = Array of Byte. Insofern haben Strings überhaupt keine Probleme mit #0. Der Datentyp welcher damit Probleme hat, weil er ihn als Trennzeichen ansieht ist PChar, bzw PAnsiChar.

Nicht zu vergesend die Referenzzählung usw. Für Grundlagen wäre die Erklärung von dsdt vermutlich hilfreich.


Und da wir nicht wissen ob die zu verwendenten Base64-Funktion intern mit PChar's gearbeitet wird bzw. irgendwelche WinAPI-Funktionen aufgerufen werden wäre es mit Vorsicht zu genießen eine Widestring per Speicher-Copy in einen String zu "konvertieren".

blackdrake 25. Aug 2007 16:46

Re: Unicode + BASE64?
 
Mensch, ist das ein Ärger mit Unicode + Delphi :? Die Fragestellung ist so simpel und die Lösung komplex.

Hilft folgendes zur Klärung der "Problem mit #0"-Frage?

Delphi-Quellcode:
type
  Binary        = String; // LongString with Binary Contens

function TDECCipher.EncodeBinary(const Source: Binary; Format: TDECFormatClass): Binary;
begin
  SetLength(Result, Length(Source));
  Encode(Source[1], Result[1], Length(Source));
  Result := ValidFormat(Format).Encode(Result);
end;

procedure TDECCipher.Encode(const Source; var Dest; DataSize: Integer);
  // ...
  procedure EncodeECBx(S,D: PByteArray; Size: Integer);
  // ...
begin
  //...
  EncodeECBx(@Source, @Dest, DataSize);
  //...
end;
Ich kenne mich mit Pointern nicht so wirklich aus...

Bernhard Geyer 25. Aug 2007 16:59

Re: Unicode + BASE64?
 
Aus dem Bauch heraus:

Delphi-Quellcode:
function EncodeWideString(const Source: WideString; Format: TDECFormatClass): String;
var
  iSize: Integer;
begin
  iSize := Length(Source)*SizeOf(WideChar);
  SetLength(Result, iSize);
  Encode(Source[1], Result[1], iSize);
  Result := ValidFormat(Format).Encode(Result);
end;

blackdrake 25. Aug 2007 20:48

Re: Unicode + BASE64?
 
Ich probiere jetzt schon seit 3:30h alle verschiedenen Varianten rum und nichts funktioniert :( Mir fällt bald mein Abendessen aus dem Gesicht.

UTF8 hab ich auch schon probiert, auch negativ

Ich habe für die Verschlüsselungsfunktion auch ein Gegenstück entwickelt, doch dann herausgefunden, dass der Entschlüsselungskern nur Strings nehmen will.

Desweiteren habe ich herausgefunden, dass meine Funktion nicht geht:

Delphi-Quellcode:
function WideStringToDoubleLongString(UnicodeStr: WideString): string;
var
  ByteArray: Array of Char;
  PWC: PWideChar;
begin
  SetLength(ByteArray, Length(UnicodeStr) * sizeof(WideChar));
  PWC := PWideChar(UnicodeStr);
  CopyMemory(@ByteArray[0], @PWC, Length(UnicodeStr) * sizeof(WideChar));
  result := string(ByteArray);
end;

function ReadNullTerminatedWideString(const Stream: TStream): WideString;
var
  S: WideString;
  WC: WideChar;
begin
  S := '';
  repeat
    Stream.ReadBuffer(WC, 2);
    if (WC <> #0) then
      S := S + WC;
  until WC = #0;
  Result := S;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  test: TFileStream;
  ws: widestring;
  s: string;
begin
  test := TFileStream.Create('c:\uni.txt', fmOpenRead or fmShareDenyNone);
  ws := ReadNullTerminatedWideString(test);
  s := WideStringToDoubleLongString(ws);
  test.free;

  deletefile('c:\uni2.txt');
  test := TFileStream.Create('c:\uni2.txt', fmCreate);
  test.writebuffer(s, length(s));
  test.free;
end;
Dieser Code soll einfach nur uni.txt (42 Byte) mit Inhalt

testこれはちょうどテストであtest[null][null]

nach uni2.txt "kopieren". Erst wenn dies Funktioniert, kann ich weiter machen.

Die Größe der Ausgabedatei uni2.txt stimmt. Es sind 40 Byte (keine Null-Terminierung, deswegen nicht 42). Aber der Inhalt stimmt nicht:

ꡈí渊C๰ê拯B揭B๰ê椂C

Weiß denn niemand, wie ich die Inhalte eines WideStrings vorrübergehend in einen String lagern kann?

Gruß
blackdrake

Bernhard Geyer 25. Aug 2007 21:00

Re: Unicode + BASE64?
 
Delphi-Quellcode:
Desweiteren habe ich herausgefunden, dass meine Funktion nicht geht:
Ist ja auch klar. Du versuchst jedliche "Compiler-Magic" bezüglich Referenzzählung bei Strings mit der Holzhammermethode (Harte Casts) zu erschlagen.

Schon mal überlegt das deine lokale Variable
Delphi-Quellcode:
ByteArray: Array of Char;
automatisch beim verlassen der Funktion WideStringToDoubleLongString Speichertechnisch freigegeben wird und du dann als result-Parameter einen Nirvana-Pointer hast?


Und fürs einlesen von Unicode-Textdateien (Neue Frage -> Neuer Thread) gibt es das ElPack, die TNTWare-Controls oder entsprechende Funktionen in der CodeLib (welche das ist lass ich dir jetzt mal selbst suchen).


Zitat:

Zitat von blackdrake
Weiß denn niemand, wie ich die Inhalte eines WideStrings vorrübergehend in einen String lagern kann?

Nein, das geht nicht ohne die schon diskutierten Auswirkungen!!!!!!

Hast du überhaupt meinen letzten Post gelesen wie du die DEC-Methode mit Widestrings aufrufen könntest?

Olli 25. Aug 2007 21:18

Re: Unicode + BASE64?
 
Zitat:

Zitat von Zacherl
Als Hintergrundinformation: Ein String ist ein Array of Char = Array of Byte. Insofern haben Strings überhaupt keine Probleme mit #0. Der Datentyp welcher damit Probleme hat, weil er ihn als Trennzeichen ansieht ist PChar, bzw PAnsiChar.

Ein Datentyp sieht garnix als Trennzeichen an, denn er ist nur ein Modell anhand dessen wir uns vorstellen können was abgeht. Das AnsiString sich in einen PChar (resp. PAnsiChar) und WideString in einen PWideChar wandeln läßt - und das oft genug implizit - sollte uns zu denken geben. String[X] mit X <= 255 ist tatsächlich ein "array of char", für den Rest hat Bernhard schon alles wichtige gesagt.

Wieso funktioniert denn UTF8 nicht?

http://msdn2.microsoft.com/en-us/library/ms776413.aspx und http://msdn2.microsoft.com/en-us/library/ms776420.aspx sollten doch die Lösung beinhalten.

UTF8 wäre auch bei wenigen speziellen Zeichen (bspw. dt. Sprache) speichereffizienter als andere Unicode-Kodierungen.

blackdrake 25. Aug 2007 23:15

Re: Unicode + BASE64?
 
Hallo.

UTF8Decode() und UTF8Encode() haben nur Schrott ausgegeben.

EDIT: Außerdem sind diese Funktionen von der Codepage abhängig. Ich will ja den String nicht verwenden, um ihn anzeigen zu lassen, sondern ihn nur als Container verwenden, der die Inhalte des WideStrings besitzt. Er ist doppelt so groß und kann #0 enthalten, was aber DEC egal ist.

Zitat:

Zitat von Bernhard Geyer
Hast du überhaupt meinen letzten Post gelesen wie du die DEC-Methode mit Widestrings aufrufen könntest?

Doch und ich bin auch drauf eingegangen. Kodieren kann sein, dass es funktioniert, aber das Gegenstück funktioniert eben nicht, weil der Entschlüsselungskern der hochkomplizierten DEC Library nur strings als Eingabe versteht. Ich habe alleine da 3 Stunden mit verbracht, alles mögliche durchzuprobieren und bin zu keinem Ergebnis gekommen.

Das mit dem Einlesen der Unicode-Datei dient nur als Beispiel, damit ich einen japanischen Vorlagetext habe, mit dem ich testen kann. Ich brauche keine VCL, um einen WideString von einem Stream einzulesen.

Zitat:

Zitat von Bernhard Geyer
Nein, das geht nicht ohne die schon diskutierten Auswirkungen!!!!!!

DEC hat bei Strings mit enthaltenen #0 keine Probleme gemacht. Wieso soll ich dann keine WideString-Umwandlung machen können?

Tut mir leid, dass ich mich hier so wenig auskenne. Aber es muss doch möglich sein, dass man einen WideString verschlüsselt. Man kann doch nicht die ganze DEC umschreiben, weil die Kernfunktionen nur strings annehmen.

Versteht ihr die Grundproblematik nicht?

WideString mit 10 Zeichen á 2 Bytes -> Char-Array -> String mit 20 Zeichen -> Verschlüsselter Text (keine Probleme mit #0!!!)
Verschlüsselter Text (keine Probleme mit #0!!!) -> String mit 20 Zeichen -> Char-Array -> WideString mit 10 Zeichen á 2 Bytes

Was soll daran unmöglich sein, 20 Bytes Widestring in 20 Bytes String umzuwandeln? Ob ein #0 in der Mitte vorkommt, ist dem DEC, das binäre Daten akzeptiert, egal.

Ich kann als Hobbyprogrammierer nur die Dinge, die ich mir selbst angeeignet habe. Also wäre ich dankbar, wenn ich Code anstatt von großen Sprüchen oder Fachbegriffen bekommen würde. Die helfen mir nichts. Es kann nicht sein, dass man 20 Bytes nicht in 20 Bytes umwandeln kann!!! Im Arbeitsspeicher sehen diese 20 Bytes alle gleich aus, egal ob sie als WideString oder als String interpretiert werden!

Gruß
blackdrake

blackdrake 25. Aug 2007 23:24

Re: Unicode + BASE64?
 
Zitat:

Zitat von Bernhard Geyer
Schon mal überlegt das deine lokale Variable
Delphi-Quellcode:
ByteArray: Array of Char;
automatisch beim verlassen der Funktion WideStringToDoubleLongString Speichertechnisch freigegeben wird und du dann als result-Parameter einen Nirvana-Pointer hast?

Bist du dir da ganz sicher? Ich sage result := string(ByteArray).

ByteArray wird genommen und als String umgewandelt. Und ein String ist kein Pointer. Folglich zeigt result nicht ins leere. Oder nicht?

Bitte zeig mir lieber, wie man mit Codebeispielen es besser macht, anstatt an meinem Code rumzumeckern. Ich bin kein Fachinformatiker, aber ich sehe hier nicht, dass result ein Pointer ist. Result ist außerdem vom Typ "string". Folglich kein Pointer, der ins nichts zeigen kann.

Gruß
blackdrake

Zacherl 25. Aug 2007 23:40

Re: Unicode + BASE64?
 
Am einfachsten wäre doch:

Delphi-Quellcode:
var
  Str: String;
  ByteArray: Array of Char;
  // ..
begin
  // ..
  SetLength(Str, Length(ByteArray) -1);
  Copy(@Str[1], @ByteArray[0], Length(ByteArray));
end;
Wobei ICH auch glaube, dass String(ByteArray) funktioniert. Warum probierst dus nicht einfach aus?

blackdrake 25. Aug 2007 23:49

Re: Unicode + BASE64?
 
Hallo.

Wo ist da der Eingabe-Unicode-String? CopyMemory verwende ich ja bereits. Im Beitrag #25 ( http://www.delphipraxis.net/internal...=767710#767710 ) habe ich ja das ganze Beispiel beigelegt, das man direkt Testen kann.

Ich lese eine Unicodedatei ein, wandle den x Byte WideString in einen x Byte String und speichere anschließend den String. Speichern und Laden funktioniert, aber die Dateien sind unterschiedlich!

Die entscheidende Zeile ist ja:

Delphi-Quellcode:
PWC := PWideChar(UnicodeStr);
CopyMemory(@ByteArray[0], @PWC, Length(UnicodeStr) * sizeof(WideChar));
Wobei ich auch schreiben könnte (was aber Probleme bei UnicodeStr = '' machen kann)

Delphi-Quellcode:
CopyMemory(@ByteArray[0], @UnicodeStr[1], Length(UnicodeStr) * sizeof(WideChar));
Ich sehe in dieser Funktion: 20 Bytes von Position @UnicodeStr zu Position @ByteArray kopieren. Das muss doch funktionieren. Ich verstehe gar nicht, wieso etwas völlig verschiedenes rauskommt. Er muss den Inhalt vom WideString in den String schreiben. Auf die #0 in der Mitte kommt es hier wie gesagt gar nicht an. Das Problem ist hier was anderes.

Gruß
blackdrake

Olli 25. Aug 2007 23:55

Re: Unicode + BASE64?
 
Zitat:

Zitat von blackdrake
UTF8Decode() und UTF8Encode() haben nur Schrott ausgegeben.

EDIT: Außerdem sind diese Funktionen von der Codepage abhängig. Ich will ja den String nicht verwenden, um ihn anzeigen zu lassen, sondern ihn nur als Container verwenden, der die Inhalte des WideStrings besitzt. Er ist doppelt so groß und kann #0 enthalten, was aber DEC egal ist.

Überhaupt mal den Links gefolgt? Die Codepage kann man bei den verlinkten Funktionen nämlich auch sehr wohl angeben.

Und nein, wenn du asiatische Zeichen hast, sind es eben keine Nullen im "HiByte", weil dann nämlich der Platz gebraucht wird um eine eindeutige Zuordnung zu gewährleisten. Das ist ja das ganze Dilemma.

blackdrake 26. Aug 2007 00:01

Re: Unicode + BASE64?
 
Hallo. Mit den Funktionen hatte ich mich schon vergebens beschäftigt. Ich will ja hier codepageunabhängig konvertieren. Dass bei Unicodezeichen der Hi-Byte besetzt ist (außer es handelt sich um die ANSI-Zeichen, die im Unicode mit enthalten sind), ist mir klar. Ich will ja Lo- UND Hi-Byte in einen String packen. Dieser soll keinen Sinn ergeben, sondern nur dazu dienen, um korrekt verschlüsselt zu werden. Der String ist aufgebläht und doppelt so groß, wie ich schon beschrieben habe. Folglich ist die Codepage völlig egal. Es soll lediglich der Speicherinhalt des WideStrings in den String kopiert werden, wodurch dieser doppelt so groß wird. Ich erwähne das mit dem #0, weil hier einige behaupten, es würde dadurch nur zu Problemen kommen, was aber in meinem Fall eben nicht so ist, da DEC als Eingabe Strings mit enthaltenem #0 akzeptiert.

Olli 26. Aug 2007 00:32

Re: Unicode + BASE64?
 
Hinzu:
Delphi-Quellcode:
var
as: AnsiString; // Ausgabe
ws: WideString; // Eingabe
begin
  SetLength(as, Length(ws));
  CopyMemory(@as[1], @ws[1], Length(as));
end;
Rückzu:
Delphi-Quellcode:
var
as: AnsiString; // Eingabe
ws: WideString; // Ausgabe
begin
  SetLength(ws, Length(as div sizeof(WideChar)));
  CopyMemory(@ws[1], @as[1], Length(ws) * sizeof(WideChar));
end;
Und nein, das macht keine Probleme bei einem leeren WideString, weil Delphi die "automagisch" nullterminiert, womit immer eine Null da sein sollte.

blackdrake 26. Aug 2007 00:42

Re: Unicode + BASE64?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo.

Danke für die Codeteile. Leider funktioniert es auch nicht ganz. Ich habe auch ergänzend sizeof(WideChar) dazugehängt.

"testこれはちょうどテストであtes" wird bei deinem Beispiel zu "ₘî淪C๰ê" (nur halb so lang weil *2 vergessen, was aber jetzt auch erstmal egal ist).

Probier es selbst aus:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);

  function ReadNullTerminatedWideString(const Stream: TStream): WideString;
  var
    S: WideString;
    WC: WideChar;
  begin
    S := '';
    repeat
      Stream.ReadBuffer(WC, 2);
      if (WC <> #0) then
        S := S + WC;
    until WC = #0;
    Result := S;
  end;

var
  test: TFileStream;
  ws: widestring;
  ans: AnsiString;
begin
  test := TFileStream.Create('c:\uni.txt', fmOpenRead or fmShareDenyNone);
  ws := ReadNullTerminatedWideString(test);

  SetLength(ans, Length(ws));
  CopyMemory(@ans[1], @ws[1], Length(ans));

  test.free;

  deletefile('c:\uni2.txt');
  test := TFileStream.Create('c:\uni2.txt', fmCreate);
  test.writebuffer(ans, length(ans));
  test.free;
end;
Die Datei c:\uni.txt muss den Text

testこれはちょうどテストであtes[NULL][NULL]

enthalten.

Außerdem habe ich noch sowas hier probiert. Ebenfalls alles ohne Erfolg!

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);

  function ReadNullTerminatedWideString(const Stream: TStream): WideString;
  var
    S: WideString;
    WC: WideChar;
  begin
    S := '';
    repeat
      Stream.ReadBuffer(WC, 2);
      if (WC <> #0) then
        S := S + WC;
    until WC = #0;
    Result := S;
  end;

var
  test: TFileStream;
  ws: widestring;
  s: string;
  PWC: PWideChar;
  data: array of pchar; // string, array of char und pchar gingen auch nicht
begin
  test := TFileStream.Create('c:\uni.txt', fmOpenRead or fmShareDenyNone);
  ws := ReadNullTerminatedWideString(test);

  PWC := PWideChar(ws);

  //Data := GetMemory(Length(ws) * sizeof(WideChar));

  SetLength(Data, Length(ws) * sizeof(WideChar));

  // Hab schon mit und ohne @ sowie mit und ohne [0] ausprobiert, ging alles nicht
  CopyMemory(@Data[0], @PWC, Length(ws) * sizeof(WideChar));

  s := string(Data);

  test.free;

  deletefile('c:\uni2.txt');
  test := TFileStream.Create('c:\uni2.txt', fmCreate);
  test.writebuffer(s, length(s));
  test.free;
end;
Ob es jetzt sinnvoll ist oder nicht, was ich hier mache. Ist eigentlich egal. Aber irgendwie muss es doch funktionieren, dass man per CopyMemory einen Variableninhalt von x nach y kopiert. Hier ist irgendwo der Wurm drin!! :( :(

EDIT

Ich demonstriere nochmal, dass meine Lese- / Schreibfunktionen nicht schuld sind. Es wird ein WideString korrekt eingelesen und anschließend wieder geschrieben.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);

  function ReadNullTerminatedWideString(const Stream: TStream): WideString;
  var
    S: WideString;
    WC: WideChar;
  begin
    S := '';
    repeat
      Stream.ReadBuffer(WC, 2);
      if (WC <> #0) then
        S := S + WC;
    until WC = #0;
    Result := S;
  end;

var
  test: TFileStream;
  ws: widestring;
  pwc: pwidechar;
begin
  test := TFileStream.Create('c:\uni.txt', fmOpenRead or fmShareDenyNone);
  ws := ReadNullTerminatedWideString(test);
  test.free;

  deletefile('c:\uni2.txt');
  test := TFileStream.Create('c:\uni2.txt', fmCreate);
  pwc := PWideChar(ws);
  test.write(pwc^, length(ws) * sizeof(widechar));
  test.WriteBuffer(#00#00, 2);
  test.free;
end;
uni.txt und uni2.txt sind danach absolut identisch. Es liegt wie gesagt bei der Umwandlung des WideStrings in einen doppelt großen Ansi-String.

Gruß
blackdrake

Olli 26. Aug 2007 04:21

Re: Unicode + BASE64?
 
Kann es leider nicht ausprobieren, da ich kein Delphi installiert habe. Da werde ich mich wohl aus der Diskussion ausklinken müssen, wenn ich nichts sinnvolles beitragen kann.

Bernhard Geyer 26. Aug 2007 13:51

Re: Unicode + BASE64?
 
Wenn ich noch den Donwload zu der Unit für TDECCipher hätte, hätte ich schnell mal ein Lösung gezimmert.

blackdrake 26. Aug 2007 13:52

Re: Unicode + BASE64?
 
Hier kannst du DEC herunterladen: http://www.michael-puff.de/Developer...agen_Reddmann/

blackdrake 26. Aug 2007 17:27

Re: Unicode + BASE64?
 
Hallo.

Nach 2 Tagen rumprobieren und verzweifeln, bin ich doch noch auf einen grünen Zweig gekommen. Wie ich bereits zuvor behauptet habe und was hier quasi jeder bestritten hat, funktioniert es doch, einen WideString in einen aufgeblähten AnsiString zu lagern und umgekehrt.

Der Code sieht so aus:

Delphi-Quellcode:
// WideString-Inhalte in einen AnsiString schreiben (dieser ist 2-Mal so groß)

function WideStringToDoubleLongAnsiString(ws: WideString): AnsiString;
var
  i: integer;
  wc: widechar;
begin
  result := '';
  for i := 1 to length(ws) do
  begin
    copymemory(@wc, @ws[i], sizeof(wc));
    result := result + chr(lo(ord(wc))) + chr(hi(ord(wc)));
  end;
end;

function DoubleLongAnsiStringToWideString(dls: AnsiString): WideString;

  // [url]http://www.delphipraxis.net/post27809.html[/url]
  function HexToInt(HexNum: string): LongInt;
  begin
    Result:=StrToInt('$' + HexNum);
  end;

  function BuildWideChar(char2, char1: char): WideChar;
  begin
    result := widechar(hextoint(inttohex(ord(char1), 2)+inttohex(ord(char2), 2)));
  end;

var
  i: integer;
  c: array [0..1] of char;
begin
  i := -2;
  result := '';
  repeat
    i := i + 2;
    if i >= length(dls) then break;
    copymemory(@c[0], @dls[i+1], sizeof(c));
    result := result + BuildWideChar(c[0], c[1]);
  until false;
end;
Ich hoffe dass diese Funktionen all denen viel Arbeit abnehmen, die das selbe Problem (WideString mit einer String-Funktion zu bearbeiten) haben.

Ich kann hier perfekt einen WideString in einen doppelt so großen AnsiString packen, diesen mit DEC (das nur Strings annimmt) verschlüsseln und das ganze dann wieder rückwärts laufen lassen. Somit habe ich einen WideString ver- und entschlüsselt.

Und angenommen, es würde Probleme mit #0 oder was-weiß-ich-was geben, dann ersetze ich einfach chr() mit inttohex() und hänge somit die Hexadezimalen Werte der Wide-Char-Halbierungen hinereinander (FFFE1F...). Dann wäre der AnsiString 4 Mal so groß und würde keine binären Zeichen mehr enthalten, aber dann gibt es absolut keine Probleme mehr! Hier ist der Beispielcode:

Delphi-Quellcode:
// Hexadezimale WideString-Inhalte in einen AnsiString schreiben (dieser ist 4-Mal so groß)

function WideStringToHexAnsiString(ws: WideString): AnsiString;
var
  i: integer;
  wc: widechar;
begin
  result := '';
  for i := 1 to length(ws) do
  begin
    copymemory(@wc, @ws[i], sizeof(wc));
    result := result + inttohex(lo(ord(wc)), 2) + inttohex(hi(ord(wc)), 2);
  end;
end;

function HexAnsiStringToWideString(dls: AnsiString): WideString;

  // [url]http://www.delphipraxis.net/post27809.html[/url]
  function HexToInt(HexNum: string): LongInt;
  begin
    Result:=StrToInt('$' + HexNum);
  end;

  function BuildWideChar(char2, char1: char): WideChar;
  begin
    result := widechar(hextoint(inttohex(ord(char1), 2)+inttohex(ord(char2), 2)));
  end;

var
  i: integer;
  c: array [0..3] of char;
begin
  i := -4;
  result := '';
  repeat
    i := i + 4;
    if i >= length(dls) then break;
    copymemory(@c[0], @dls[i+1], sizeof(c));
    result := result + BuildWideChar(Chr(HexToInt(c[0]+c[1])), Chr(HexToInt(c[2]+c[3])));
  until false;
end;
Ich danke denen, die sich mit dem Problem beschäftigt haben und mir Codeteile gegeben haben anstelle von großen Sprüchen. Auch bedanke ich mich bei den C-Leuten, die mich auf die CopyMemory Idee gebracht haben.

PS: Wäre doch was für die CodeLib, oder?

Gruß
blackdrake

Zacherl 26. Aug 2007 17:46

Re: Unicode + BASE64?
 
Kleine Zwischenfrage: Hagens DEC besitzt doch auch eine EncodeBinary Funktion .. kann man der nicht den WideString ohne Weiteres übergeben?


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:28 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz