Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi String mit gzip (ent)zippen (https://www.delphipraxis.net/89090-string-mit-gzip-ent-zippen.html)

Muetze1 26. Mär 2007 18:36

Re: String mit gzip (ent)zippen
 
Memo.Text kannst du der Funktion nicht übergeben, da es eine Property ist. Damit können dahinter Getter/Setter liegen (was hierbei auch der Fall ist) und der Funktion als Stringspeicherplatz eine Methode bzw. deren Code zu geben ist nicht vorteilhaft. Du musst mit Zwischenwerten als Strings arbeiten oder du nutzt den Delphi-Referenz durchsuchenTStringStream.

MatthiasR 19. Mär 2009 10:30

Re: String mit gzip (ent)zippen
 
Liste der Anhänge anzeigen (Anzahl: 2)
2 Jahre sind vergangen und ich stehe wieder vor demselben Problem. Ich lese über ein Kartenterminal Daten von einer Smartcard ein (der eGK, wenns jemanden interessiert :wink: ), von denen es heißt, es handele sich um "gezippte XML-Dateien". "Die Basis für das Zippen ist die Software "gzip"."

Mit den bisher in diesem Thread genannten Lösungsansätzen hatte ich irgendwie kein Glück, bei der ZLib-Funktion erhalte ich wieder den Fehler "Ungültige Zeigeroperation". Ich habe auch schon die ZLib von hier ausprobiert und den Beispielcode auf meine Zwecke abgeändert, aber auch da erhalte ich einen Fehler.

Frage: gibt es irgendwo ein kleines Tool, das mir einen komprimierten String entpackt und anzeigt, damit ich sehen kann, ob die Daten, die ich versuche zu entpacken, überhaupt valide sind? Ich habe die gezippten Strings mal als txt-Dateien unten angehängt, vielleicht kann ja einer von euch mal sein Glück versuchen? Die Standard-Entpack-Programme erwarten solche Daten ja in einem entsprechenden Archiv mit Dateiheader usw. die bringen mich da wohl nicht wirklich weiter.

Vielen Dank schonmal im Voraus!

gammatester 19. Mär 2009 11:44

Re: String mit gzip (ent)zippen
 
Das sind keine gültigen gzip-Files gemäß gzip-spec, denn sie beginnen nicht mit $1f $8b, obwohl diese beiden gzip-ID-Bytes ziemlich am Anfang der Dateien zu finden sind.

Was bedeutet denn genau:
Zitat:

"Die Basis für das Zippen ist die Software "gzip"."
Sieht nach stiller Postaus: ich kenne jemanden, dessen Berater ziemlich sicher ist, einen Programmierer zu kennen, der gehört hat, daß das gzip ist.

Selbst wenn man die Bytes vor den ID-Bytes löscht, kommt nichts Gültiges raus, auch zpipe kommt nicht damit zurecht.

Gammatester

MatthiasR 19. Mär 2009 13:22

Re: String mit gzip (ent)zippen
 
Zitat:

Zitat von gammatester
Was bedeutet denn genau:
Zitat:

"Die Basis für das Zippen ist die Software "gzip"."
Sieht nach stiller Postaus: ich kenne jemanden, dessen Berater ziemlich sicher ist, einen Programmierer zu kennen, der gehört hat, daß das gzip ist.

Die Formulierung stammt aus der Beschreibung des Kartenterminal-Hertstellers, wie die Daten von der Smartcard auszulesen sind. Und sie ist in der Tat nicht wirklich aussagekräftig, daher habe ich sie auch einfach nur im O-Ton wiedergegeben.

Danke dass du dir die Mühe gemacht hast, die Dateien mal etwas unter die Lupe zu nehmen. Ich sehe dadurch nun zwei Möglichkeiten:

1. Was ich von der Karte ausgelesen habe, war schlichtweg Murks, der sich gar nicht erst dekomprimieren lässt.

2. Was ich von der Karte ausgelesen habe, war KEIN Murks, bedarf aber vor dem Dekomprimieren noch einer (oder diverser) Überarbeitung(en), wie Header abschneiden, Trailer abschneiden, mit 4711 multiplizieren oder weiß der Teufel.

3. Der Karteninhalt ist unbrauchbar, was ich aber bereits ausschließen kann, da das Kartenterminal auf seinem eingebauten Display bereits einige Daten der Karte anzeigen kann. Es muss es also selbst bereits geschafft haben, sie korrekt zu lesen und die Daten zu dekomprimieren.

Ich habe auch mal den Kartenterminal-Hersteller kontaktiert, ob die mir da weiterhelfen können. Vielleicht sehen die den Fehler auf Anhieb...

MatthiasR 23. Mär 2009 09:01

Re: String mit gzip (ent)zippen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Also: wie gammatester und ich eindeutig festgestellt haben, handelt es sich bei den von mir ausgelesenen Daten um valide gzip-Konstrukte, lediglich mit einem zusätzlichen Header vor dem gzip-Header '0x1F8B08'. Schneidet man diesen ab und speichert den verbleibenden String in einer Datei mit Endung ".gz", so kann man diese z.B. mittels 7zip entpacken.

Allerdings habe ich es immernoch nicht hingekriegt, den resultierenden gzip-String in meiner Anwendung mittels ZLib zu entpacken.

Der von himitsu gepostete Algorithmus
Delphi-Quellcode:
Uses ZLib;

Function CompressString(Input: String): String;
  Var Buffer: Pointer;
    BufSize: Integer;

  Begin
    Buffer := nil;
    Try
      CompressBuf(Input[1], Length(Input), Buffer, BufSize);
      SetLength(Result, BufSize);
      Move(Buffer^, Result[1], BufSize);
    Finally
      If Buffer <> nil Then FreeMem(Buffer);
    End;
  End;

Function DeCompressString(Input: String): String;
  Var Buffer: Pointer;
    BufSize: Integer;

  Begin
    Buffer := nil;
    Try
      DeCompressBuf(Input[1], Length(Input), 0, Buffer, BufSize);
      SetLength(Result, BufSize);
      Move(Buffer^, Result[1], BufSize);
    Finally
      If Buffer <> nil Then FreeMem(Buffer);
    End;
  End;
liefert mir bei DeCompressBuf immer eine ungültige Zeigeroperation. Was mache ich nur falsch???

Anbei noch die "richtigen" gzip-Dateien, vielleicht kann einer von euch nochmal sein Glück versuchen?!?

PS: Die resultierenden Daten sind reine Testdaten einer fiktiven Person, falls sich jemand Sorgen bezüglich des Datenschutz machen sollte :wink: .

Assertor 29. Mär 2009 21:32

Re: String mit gzip (ent)zippen
 
Hi,

es gibt ein Update für zLibEx, welches nun nativ mit GZip umgehen kann (zLibExGZ). Vielleicht hilft das weiter.

Gruß Assertor

MatthiasR 31. Mär 2009 15:10

Re: String mit gzip (ent)zippen
 
Habe ich gerade mal ausprobiert. Die Funktionen
Delphi-Quellcode:
{*****************************************************************************
*  GZDecompressStr                                                          *
*                                                                            *
*  pre-conditions                                                           *
*    s = compressed data string in gzip format                              *
*                                                                            *
*  post-conditions                                                          *
*    fileName  = filename                                                  *
*    comment   = comment                                                   *
*    dateTime  = date/time                                                 *
*                                                                            *
*  return                                                                   *
*    uncompressed data string                                               *
*****************************************************************************}

function GZDecompressStr(const s: AnsiString; var fileName,
  comment: AnsiString; var dateTime: TDateTime): String; overload;

function GZDecompressStr(const s: AnsiString): String; overload;
sollten ja eigentlich genau dafür gedacht sein, einen string im gzip-Format zu entpacken. Ich bekomme jedoch immer einen "data error", keinen blassen Schimmer, warum das nicht klappt. Ich übergebe die komprimierten Daten ab dem gzip-Header "#$1F#$8B" bis zum Ende der Daten (incl. der ganzen Nullen am Schluss).

Assertor 31. Mär 2009 16:08

Re: String mit gzip (ent)zippen
 
Hi Infect,

Zitat:

Zitat von Infect
function GZDecompressStr(const s: AnsiString; var fileName,
comment: AnsiString; var dateTime: TDateTime): String; overload;

function GZDecompressStr(const s: AnsiString): String; overload;[/delphi]
sollten ja eigentlich genau dafür gedacht sein, einen string im gzip-Format zu entpacken.

Das ist schonmal verkehrt. Du arbeitest mit Binärdaten, wenn Du die in einen AnsiString packen willst, muß Du bezüglich Codepages und automatischer Konvertierung (aka D2009) aufpassen.

Zitat:

Zitat von Infect
Ich bekomme jedoch immer einen "data error", keinen blassen Schimmer, warum das nicht klappt. Ich übergebe die komprimierten Daten ab dem gzip-Header "#$1F#$8B" bis zum Ende der Daten (incl. der ganzen Nullen am Schluss).

Ja, nimm doch mal einen Stream stattdessen. Gerade mit Deinen Rohdaten getestet, geht einwandfrei...

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  InStream,
  OutStream: TMemoryStream;
begin
  InStream := TMemoryStream.Create;
  OutStream := TMemoryStream.Create;
  try
    InStream.LoadFromFile('D:\Downloads\VersichertenDaten.gz');
    InStream.Position := 0;
    GZDecompressStream(InStream, OutStream);
    OutStream.Position := 0;
    mmo1.Lines.LoadFromStream(OutStream); // mmo1 ist ein Memo auf dem Testform
  finally
    OutStream.Free;
    InStream.Free;
  end;
end;
Das ging jetzt aber in den Bereich "Grundlagen" von Delphi und hat wenig mit gzip zu tun ;)

Gruß Assertor

MatthiasR 1. Apr 2009 10:42

Re: String mit gzip (ent)zippen
 
Also zu allererstmal die Frohebotschaft, dass es nun endlich funktioniert! Ich habe vorher immer mit dem TStringStream gearbeitet, statt TMemoryStream, und das hat irgendwie nicht so funktioniert, wie ich mir das vorgestellt habe. Aber so, wie du es beschrieben hast, klappt es auch bei mir.

Nun aber zum Thema AnsiString und Binärdaten etc.: wenn das ganze Probleme mit Codepages usw. geben kann, wieso arbeiten dann die entsprechenden Kompressionsfunktionen mit den gleichen Datentypen?
Delphi-Quellcode:
{*****************************************************************************
*  GZCompressStr                                                            *
*                                                                            *
*  pre-conditions                                                           *
*    s         = uncompressed data string                                  *
*    fileName  = filename                                                  *
*    comment   = comment                                                   *
*    dateTime  = date/time                                                 *
*                                                                            *
*  return                                                                   *
*    compressed data string in gzip format                                  *
*****************************************************************************}

function GZCompressStr(const s: String; const fileName,
  comment: AnsiString; dateTime: TDateTime): AnsiString; overload;

function GZCompressStr(const s: String): AnsiString; overload;
Es wird ein ganz normaler String übergeben, der mit gzip komprimiert werden soll, und man erhält anschließend einen komprimierten AnsiString im gzip-Format, der ja auch nichts anderes als Binärdaten enthält, oder?!? Wo liegt der Denkfehler?

Aber erstmal Danke, dass du mir da auf die Sprünge geholfen hast, nun geht es endlich so, wie ich mir das vorgestellt habe!!!

Assertor 1. Apr 2009 11:37

Re: String mit gzip (ent)zippen
 
Hi Infect,

Zitat:

Zitat von Infect
Also zu allererstmal die Frohebotschaft, dass es nun endlich funktioniert! [...]
Aber so, wie du es beschrieben hast, klappt es auch bei mir.
[...]
Aber erstmal Danke, dass du mir da auf die Sprünge geholfen hast, nun geht es endlich so, wie ich mir das vorgestellt habe!!!

Das freut mich :)

Zitat:

Zitat von Infect
Nun aber zum Thema AnsiString und Binärdaten etc.: wenn das ganze Probleme mit Codepages usw. geben kann, wieso arbeiten dann die entsprechenden Kompressionsfunktionen mit den gleichen Datentypen?

[...]

Es wird ein ganz normaler String übergeben, der mit gzip komprimiert werden soll, und man erhält anschließend einen komprimierten AnsiString im gzip-Format, der ja auch nichts anderes als Binärdaten enthält, oder?!? Wo liegt der Denkfehler?

Ja, die Funktionen sind auch richtig - es lassen sich ja auch prinzipiell Binärdaten in AnsiStrings erfassen.

Das Probleme ist aber: Wie bekommst Du die Daten unverändert in und aus dem String.

In Delphi 2009 wurde deswegen der RawByteString eingeführt, damit unter keinen Umständen Veränderungen am String durchgeführt werden. Dies erfolgt im Hintergrund durch die Festlegung der CodePage auf:

Delphi-Quellcode:
type
  RawbyteString = type AnsiString($ffff);
Genau darin liegt/lag aber das Problem von manchem Code vor Delphi 2009: Der AnsiString wurde zum Speichern von Daten verwendet, was sich bei der Umstellung von Source und Komponenten in Delphi 2009 rächte. Zwei Hauptprobleme dabei sind: 1) Konvertierung zur Laufzeit / Compiler-Magic und 2) die Länge von Chars (wegen der damalig festen Annahme von 1 Char = 1 Byte).

Bei jeder Zuweisung eines AnsiString kannst Du nicht sicher sein, daß die CodePage nicht abweicht und somit eine Konvertierung des Strings durchgeführt wird. Wenn der String nun Daten hält, werden diese ungültig.

Wenn Du, wie in meinem Beispielcode, direkt am Stream arbeitest umgehst Du diese Probleme.

Natürlich kannst Du auch eine Funktion schreiben, die die Daten in einem AnsiString/RawByteString einliest und dann die zLib Funktionen für AnsiStrings verwenden. Aber da wären einige Sachen wegen oben genannter Probleme zu beachten.

Gruß Assertor


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:09 Uhr.
Seite 2 von 3     12 3      

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