Données corrompues suite à l'encodage base 64

RPG (3 et 4, free), CL, SQL, etc...
Répondre
DanielGCA
Messages : 6
Enregistré le : mar. 07 mai 2024, 10:34:15

Données corrompues suite à l'encodage base 64

Message par DanielGCA »

Bonjour,

Dans un rpg ile, le programme génère un code mime en utilisant la library BASE64 et la fonction base64_encode;
Le résultat est ensuite écrit dans un fichier UTF-8 dans l'IFS.

Dans certains cas où la cause est encore indéterminée, il n'est pas possible avec ce code mime de restituer le pdf original,
avec en résultat un pdf vide (mais avec le bon nombre de pages).

Le travail est lancé en ccsid 297.
Dans un même travail certains code mime sont "corrects" (donnent donc le pdf original) alors que d'autres sont "faux".

De plus l'encodage sur notre machine et sur celle d'un tiers sont différents mais reproduisent le même pdf.

Sauriez-vous si la version d'OS, le niveau de PTF sont à vérifier ? S'agirait-il de paramètres systèmes différents ?

Comment s'assurer qu'un code mime est correct ? (coder et décoder ou autre?)

merci d'avance,

Daniel GARCIA.

nbonnet
Messages : 232
Enregistré le : mar. 11 sept. 2018, 08:20:13
Localisation : Lyon

Re: Données corrompues suite à l'encodage base 64

Message par nbonnet »

Bonjour,

Je recommanderai aujourd'hui d'utiliser la fonction SQL d'encodage en base64 : https://www.ibm.com/docs/en/i/7.6.0?top ... e64-encode

La plupart du temps, les problèmes viennent de la gestion des CCSID ;
- à l'entrée dans la fonction : elle attend du binaire (*hex ou 65535). Si les données sont lues et stockées dans des variables CHAR avec un CCSID cela peut modifier la valeur avant encodage
- à la sortie : on récupère une CHAR qui ne contient que des caractères ASCII de base, vous pouvez normalement l'utiliser dans n'importe quel CCSID
- si vous écrivez sur l'IFS le résultat, voir le CCSID du fichier généré
- qui peut aussi être altéré lors du transport

Pour moi le CCSID du job a peu d'importance du moment que vous pouvez utiliser CAST en SQL ou indiquer un CCSID sur vos variables RPG si besoin
Nathanaël

DanielGCA
Messages : 6
Enregistré le : mar. 07 mai 2024, 10:34:15

Re: Données corrompues suite à l'encodage base 64

Message par DanielGCA »

Bonjour M BONNET,

Merci pour votre réponse.
Je vais essayer d'encoder via les fonctions SQL,
Je mettrai le résultat sur le fil :)

Hurri
Messages : 68
Enregistré le : lun. 02 nov. 2020, 16:04:59

Re: Données corrompues suite à l'encodage base 64

Message par Hurri »

Bonjour,

Pour que l'encodage fonctionne il faut que le code de base et le code d'arrivée soient tout le temps les mêmes.
Vous parlez du CCSID du job. Mais ce qui importe c'est le CCSID des champs en entrée et en sortie.
Nous avons personnellement des champs en CCSID 1147 (le même que 297 mais avec le symbole €) car notre système de base est en CCSID 1147, mais aussi des champs en CCSID 1208 (UTF-8) sur nos fichiers récents, car nos interfaces basculent en Web.
Autre chose à prendre en compte, le fichier en sortie.
Il existe, et il est bien défini en UTF-8 ? Là aussi, ce n'est pas toujours évident, plusieurs outils n'affichant pas le même résultat...
Si j'utilise la commande WRKLNK par exemple, le fichier apparait en code 1252 (Windows), alors que si je l'ouvre avec un éditeur dédié, il est bien défini avec un entête et des attributs UTF-8.

Pour ce qui est de générer des PDF, nous utilisons pour notre part l'outil dédié PDFLib.
C'est un peu lourd car il faut tout traiter en code, mais le résultat est toujours celui qu'on attend, avec une vitesse d'exécution fort appréciable, et pour un coût de licence raisonnable, quand on voit celui d'autres outils.

DanielGCA
Messages : 6
Enregistré le : mar. 07 mai 2024, 10:34:15

Re: Données corrompues suite à l'encodage base 64

Message par DanielGCA »

Bonjour Hurri,

Merci pour votre retour.

J'ai, sur les conseils de Nathanaël utilisé les ordres de QSYS2.
J'ai créé un programme qui lit un pdf, encode en base 64 et créer un fichier UTF-8 en un seul ordre SQL,
J'ai créé un programme qui lit un pdf, encode en base 64 dans une zone en deux ordres SQL
pour ensuite stocker le résultat dans un fichier UTF-8 (ceci étant utile lorsqu'on veut intégrer le résultat base64 dans un fichier existant par ailleurs (exemple typique du moment, la facture ubl)

Je vous mets ci-dessous les sources de ces deux programmes et vais tâcher de passer cette discussion en résolu.
Merci encore à tous.

un seul ordre SQl de fichier pdf à fichier UTF-8 (Base64)

Code : Tout sélectionner

**free       
        ctl-opt datedit(*DMY/) dftname(TSTBASE64) decedit('0,')
         option(*srcstmt:*nodebugIO);

       // Déclaration de variable
        dcl-s Ret char(1);

       // Déclaration des variables hôtes pour interagir avec le fichier IFS
        dcl-s MonPdf_In  sqltype(BLOB_FILE);
        dcl-s MonB64_Out sqltype(CLOB_FILE);

       // Chemin d'accès des fichiers sur l'IFS
        dcl-s cheminPdfIn  varchar(256);
        dcl-s cheminTxtOut varchar(256);

       // Initialisation
        exec sql
          set option commit = *none;

       // Configuration des chemins
        cheminPdfIn  = '/home/garcida/felec/FactureTest11.pdf';
        cheminTxtOut = '/home/garcida/felec/FactureTestMIME11.txt';

       // -----------------------------------------------------------------
       // 1. Configuration du fichier d'entrée (Le PDF binaire)
       // -----------------------------------------------------------------
        MonPdf_In_Name = %trim(cheminPdfIn);
        MonPdf_In_NL   = %len(%trim(MonPdf_In_Name));
        MonPdf_In_FO   = SQFRD; // SQFRD = Lecture seule (Read)

       // -----------------------------------------------------------------
       // 2. Configuration du fichier de sortie (Le texte encodé Base64)
       // -----------------------------------------------------------------
        MonB64_Out_Name = %trim(cheminTxtOut);
        MonB64_Out_NL   = %len(%trim(MonB64_Out_Name));
        MonB64_Out_FO   = SQFCRT; // SQFCRT = Créer/Écraser le fichier (Create)

       // Execution du SQL pour encoder le fichier
        exec sql
          SET :MonB64_Out = QSYS2.BASE64_ENCODE(:MonPdf_In);

       // Vérification du résultat
        if SqlCode < 0;
        // Une erreur est survenue lors du traitement SQL
        // dsply ('Erreur SQL : ' + %char(SqlCode));
           Ret = '0';
        else;
        // dsply 'Fichier PDF encodé en Base64 avec succès !';
           Ret = '1';
        endif;

       *inLR = *On;
       Return; 
Le programme pour passer par une zone intermédiaire

Code : Tout sélectionner

**free
ctl-opt dftactgrp(*no) actgrp('TEST') BndDir('QC2LE');

// Déclaration de la variable de référence de fichier SQL pour le PDF d'origine
dcl-s pdf_file varchar(256) Inz('/home/garcida/felec/factureTest11.pdf');

// Variable pour réceptionner la chaîne binaire récupérée lors de la lecture du fichier pdf
dcl-s Bin_Read      sqltype(BLOB:32000);   // Ajustez la taille max selon vos PDF
// Variable pour réceptionner la chaîne finale encodée en Base64
dcl-s base64_result sqltype(CLOB:45000);   // Ajustez la taille max selon vos besoins
// Message d'erreur
dcl-s msgText varchar(32740);              // Erreur SQL en clair

// Fonctions sur les fichiers IFS
// ==============================
// --- Ouverture d'un fichier
 dcl-pr fOpen pointer ExtProc( '_C_IFS_fopen' );   //Renvoi handle fichier
   *n pointer Value Options(*String);              //Fichier (avec répertoire)
   *n pointer Value Options(*String);              //Mode ouverture
 end-pr;
// --- Ecriture d'une ligne dans le fichier
 dcl-pr fPutS int(10) ExtProc( '_C_IFS_fputs' );   //Renvoi code retour opération
   *n pointer Value Options(*String);              //Texte à enregistrer
   *n pointer Value;                               //handle du fichier
 end-pr;
// --- Fermeture d'un fichier
 dcl-pr fClose int(10) ExtProc( '_C_IFS_fclose' ); //Renvoi code retour opération
   *n pointer Value;                               //handle du fichier
 end-pr;
//--- Suppression d'un fichier
  dcl-pr unlink int(10) ExtProc( 'unlink' );        //Renvoi code retour opération
   *n pointer Value Options(*String);               //Fichier (avec répertoire)
  end-pr;

// --- Infos fichier
  dcl-s FILE_o pointer Inz(*null); //handle du fichier IFS
  dcl-s String char(50000);        //texte à écrire dans le fichier IFS
  dcl-s rc int(10) Inz;            //code retour à l'écriture et fermeture du fichier IFS
  dcl-s NomFic varchar(256) Inz;   //Nom du fichier à générer

// Moniteur des erreurs SQL
exec sql
  whenever sqlerror do erreur_sql();

// 1. Lecture et encodage du PDF directement en SQL
exec sql
  select line into :Bin_Read from table(QSYS2.IFS_READ_BINARY(:pdf_file));

// 2. Lecture et encodage du PDF directement en SQL
exec sql
  Values QSYS2.BASE64_ENCODE(:Bin_Read)
  into :base64_result;

// 3. Création d'un fichier en sortie (UTF-8)
//  --- Nom du fichier à générer
  Clear NomFic;
  NomFic = '/home/garcida/felec/factureTestB6411.txt';

// --- Suppression du fichier précédent
  rc = unlink( %trim(NomFic) );

// --- Création du fichier en écriture
  FILE_o = fOPen(%trimr(NomFic):'w, o_ccsid=1208');

// --- Signaler l'erreur d'ouverture du fichier
  If FILE_o = *Null;
     dsply 'Erreur création fichier' ;
     return ;
  Endif;
  rc = fClose(FILE_o);
  FILE_o = fOPen(%trimr(NomFic):'w, o_ccsid=0');

// --- Ecriture avec conversion EBCDIC -> UTF-8
  String = %trimr(base64_result_data);
  rc = fPutS(%trimr(String):FILE_o);

// --- Fermeture du fichier
  rc = fClose(FILE_o);

// Fin de programme
*inlr = *on;
return;

dcl-proc erreur_sql;
  dcl-pi *n;
  end-pi;
  // Traitement des erreurs (Vérifiez le SQLCODE / SQLSTATE)
  exec sql
    GET DIAGNOSTICS CONDITION 1 :msgText = MESSAGE_TEXT;
  return;
end-proc; 

Répondre