IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Delphi Discussion :

[D11] Problème TZCompressionStream


Sujet :

Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2013
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 18
    Par défaut [D11] Problème TZCompressionStream
    Bonjour,

    J'ai un code qui utilise TZCompressionStream, qui fonctionne sous Delphi 10.4, et qui ne fonctionne plus sous Delphi 11.
    Même en simplifiant au minimum, ça ne veut pas fonctionner : j'ai une erreur "invalid zstream operation". En debug, ça s'arrête dans la fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function TZCompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
    begin
      if (offset = 0) and (origin = soCurrent) then
      begin
        result := FZStream.total_in;
      end
      else raise EZCompressionError.Create(SZInvalid);  <== ici
    end;

    Même en simplifiant au mnimum, ça ne fonctionne pas sous D11 (mais c'est ok sur les versions précédentes) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    uses system.ZLib;
     
    procedure TForm22.Button1Click(Sender: TObject);
    var xTest : TStringStream;
    	xZip : TZCompressionStream;
    	xContenuZip : TMemoryStream;
    begin
    	xTest := TStringStream.Create('essai');
    	xTest.Position := 0;
     
    	xContenuZip := TMemoryStream.Create;
    	xZip := TZCompressionStream.Create(xContenuZip);
    	xZip.CopyFrom(xTest, xTest.Size);     <== exception
    	xZip.Free;			
    end;
    Que faut-il changer pour Delphi 11 ??

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 595
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 595
    Billets dans le blog
    65
    Par défaut
    Bonjour,

    zlib est une des choses qui a été modifiée avec D11 pour prendre en charge des trucs plus volumineux.
    Il faut certainement regarder de plus près ce que ces modifications ont apportés comme différences

    Citation Envoyé par nouveautés
    RTL : TZipFile
    Nous nous sommes concentrés sur la qualité, l'amélioration et l'optimisation des fichiers ZIP (c'est-à-dire, la classe TZipFile de la RTL). Zip64 est maintenant pris en charge et une méthode permettant de supprimer un fichier dans TZipFile a été ajoutée. Par ailleurs, TZipHeader comporte une méthode GetFIleName, TZipFile.IsValid() accepte un paramètre Stream et System.Zip fonctionne avec des fichiers d'une taille supérieure à 4 Go.

  3. #3
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 086
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    xZip.CopyFrom(xTest, 0);
    Si Count a la valeur 0, CopyFrom fixe la position dans Source à 0 avant de lire les données, puis copie tout le contenu de Source dans ce flux. Si Count est supérieur ou inférieur à 0, CopyFrom lit à partir de la position en cours dans Source.
    Attention à la spécificité de ce Stream, déjà en 10 Seattle

    La lecture d'un objet TZCompressionStream déclenche une exception de type ECompressionError, avec la chaîne de message indiquant que l'opération effectuée sur le flux est incorrecte.
    Une opération Seek déclenche également une exception ECompressionError, mais vous pouvez effectuer une opération Seek avec un déplacement nul à partir de la position en cours. Elle renvoie alors le nombre d'octets bruts non compressés qui ont été écrits dans le flux.
    En fait si on voit l'Exception dans TZCompressionStream.Seek, la cause c'est une fonction entre le TZCompressionStream.Write appelé en boucle par WriteBuffer lui même appelé en boucle par CopyFrom qui modifie la Position implicitement mais il ne faut surtout pas qu'une opération modifie explicitement la Position ou utilise Seek.
    Il faudrait vérifier pourquoi il y a un Seek incorrect car jamais le code doit invoquer Seek ou changer Position sur un TZCompressionStream, en fait, le Seek ne sert que pour implémentation du GetPosition() mais pas du tout pour effectuer un déplacement.
    Maintenant, tu dois remonter la Pile d'appel pour comprendre l'origine de ce Seek imprévu dans le TStream.CopyFrom et TStream.WriteBuffer

    Dans le cadre d'un Exe stocké en ressource et extrait à la volée, voici comme j'utilise TZCompressionStream (pour créer le fichier ressource) et TZDecompressionStream pour la décompression
    D10 Seattle, si un jour je passe en D11, faudra que je veille au grain si ton problème persiste.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    //------------------------------------------------------------------------------
    class procedure TExternalTools.RunBidule(const AFileName1, AFileName2: string);
    var
      VPath, VPathBidule: string;
      RS: TResourceStream;
      ZLib: TCustomZStream;
      FS: TFileStream;
      {$IFDEF DEBUG}
      VPathBiduleZK: string;
      FSZK: TFileStream;
      {$ENDIF DEBUG}
    begin
      VPath := ExtractFilePath(Application.ExeName);
      VPathBidule := VPath + 'Bidule.exe';
     
      {$REGION 'Compression pour mise en ressources'}
      {$IFDEF DEBUG}
      if LongBool(GetAsyncKeyState(VK_SHIFT) and $8000) then
      begin
        VPathBiduleZK := 'Bidule.rcdata';
        if PromptForFileName(VPathBidule, 'Executable Bidule|Bidule.exe', '.exe', 'Bidule à compresser', VPath) and PromptForFileName(VPathBiduleZK, 'Ressource Bidule|Bidule.rcdata', '.rcdata', 'Bidule à compresser', VPath, True) then
        begin
          FS := TFileStream.Create(VPathBidule, fmOpenRead);
          try
            try
              FSZK := TFileStream.Create(VPathBiduleZK, fmCreate);
              try
                ZLib := TZCompressionStream.Create(clMax, FSZK);
                try
                  ZLib.CopyFrom(FS, 0);
                finally
                  ZLib.Free();
                end;
              finally
                FSZK.Free();
              end;
            except
              System.IOUtils.TFile.Delete(VPathBidule);
            end;
          finally
            FS.Free();
          end;
     
          Exit;
        end;
      end;
      {$ENDIF DEBUG}
      {$ENDREGION}
     
      {$REGION 'Extraction Ressource'}
      if not FileExists(VPathBidule) then
      begin
        RS := TResourceStream.Create(HInstance, 'ZIP_Bidule', System.Types.RT_RCDATA);
        try
          ZLib := TZDecompressionStream.Create(RS);
          try
            try
              FS := TFileStream.Create(VPathBidule, fmCreate);
              try
                FS.CopyFrom(ZLib, 0);
              finally
                FS.Free();
              end;
            except
              System.IOUtils.TFile.Delete(VPathBidule);
            end;
          finally
            ZLib.Free();
          end;
        finally
          RS.Free();
        end;
      end;
      {$ENDREGION}
     
      ShellExecute(Screen.ActiveForm.Handle, 'open', PChar(VPathBidule), PChar(Format('"%s" "%s"', [AFileName1, AFileName2])), PChar(VPath), SW_SHOW);
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    si je ne m'abuse c'est lié à une optimisation de CopyFrom qui cherche à déterminer la taille du flux, or la taille d'un flux est obtenu par Seek justement...
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2013
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 18
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    xZip.CopyFrom(xTest, 0);
    Attention à la spécificité de ce Stream, déjà en 10 Seattle
    Que je mettes 0, ou que je mettes xTest.Size, ça ne changera rien : dès le début de la fonction CopyFrom, il y a un test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      if Count <= 0 then
      begin
        Source.Position := 0;
        Count := Source.Size;
      end;
    Par contre, si je compares CopyFrom entre Delphi 10.4 et Delphi 11, la fonction a été modifiée, et elle appelle maintenant "Size", qui fait un Seek(0, soEnd) ... donc j'ai droit à l'exception.

  6. #6
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 086
    Par défaut
    Si c'est un Seek sur Source ce n'est pas un problème
    Mais un Seek sur Self, grosse erreur !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 595
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 595
    Billets dans le blog
    65

Discussions similaires

  1. Problème d'installation oracle 8.1.7 sous NT
    Par Anonymous dans le forum Installation
    Réponses: 7
    Dernier message: 02/08/2002, 14h18
  2. Problème d'impression
    Par IngBen dans le forum C++Builder
    Réponses: 7
    Dernier message: 22/05/2002, 11h37
  3. Problème avec la mémoire virtuelle
    Par Anonymous dans le forum CORBA
    Réponses: 13
    Dernier message: 16/04/2002, 16h10
  4. Réponses: 6
    Dernier message: 25/03/2002, 21h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo