[NEWSboard IBMi Forum]
Seite 1 von 2 1 2 Letzte
  1. #1
    Registriert seit
    Apr 2020
    Beiträge
    8

    BLOB mit BASE64 encoden für REST Service im IBM i IWS

    Hallo zusammen



    Ich habe die Anforderung aus einem BLOB Feld einer AS400 Tabelle, welches ein Programmobjekt für eine Android App beinhält (ca. 5 MB), mittels REST Service über den IBM i integrated web services server, dieses als BASE64 String zur Verfügung zu stellen.



    Grundsätzlich dachte ich, das mit folgendem SQL zu machen, aber das funktioniert leider nicht, da der BLOB Inhalt zu groß ist. SYSTOOLS.BASE64ENCODE ist auf 2732 Zeichen beschränkt.



    Code:
    Select cast(systools.base64encode(Datei) AS clob ccsid 1208) as Datei from Versionsverwaltung
    
    where programm = 'StaplerTerminal.apk' and versionsnr = '1.0.5';


    Daher war dann mein Ansatz, das BLOB Feld in einem CLOB (CCSID 1208) als BASE64 zu speichern. Dies wollte ich mittels apr_base64_encode_binary bewerkstelligen. Die Funktion habe ich aus einem Foreneintrag übernommen. Nur komme ich auf keinen grünen Zweig, da ich, egal was ich anstelle, immer falsche BASE64 Daten erzeuge.



    Code:
    dcl-s Blob sqltype(BLOB:16773100);                 
    
    dcl-s Clob sqltype(CLOB:16773100) CCSID(1208);     
    
    dcl-s DateiClob sqltype(CLOB:16773100) CCSID(1208);
    
    dcl-s ClobOut sqltype(CLOB:16773100) CCSID(1208);  
    
    dcl-s   LocString   like(Clob);      
    
    dcl-s   LocBase64   like(Clob);      
    
    
    
    exec sql                                                           
    
       select datei into :Blob,  
    
       from Versionsverwaltung                                          
    
       where  programm = trim(:Programm) and versionsnr = trim(:Version)
    
       limit 1;                                                         
    
    
    
    if sqlcode = 0;
    
      ClobOut = getBase64(Blob);                                          
    
      ClobOut_Len = %len(%trimr(ClobOut));                                
    
      exec sql                                                             
    
        update Versionsverwaltung set DateiClob = :ClobOut                
    
        where aktuell='1' and                                             
    
       where  programm = trim(:Programm) and versionsnr = trim(:Version);
    
    endif;
    
    
    
    *inlr = *on;   
    
    return;        
    
     
    
    //  _______________________________________________________________
    
    //  getBASE64 Encoded String   ____________________________________
    
                                                                      
    
     dcl-proc getBase64;                                              
    
       dcl-pi *n     like(Clob) rtnparm; // Encoded String            
    
         PiString    like(Blob);                                      
    
       end-pi;                                                        
    
                                                                      
    
       dcl-s   LocString   like(Blob) inz;     // Source String       
    
       dcl-s   LocBase64   like(Clob) inz;     // Encoded String      
    
       dcl-s   Loclength   int(10);            // StringLength        
    
       dcl-s   LocEnclen   int(10);            // EncodedLength       
    
                                                                      
    
       LocString = %trimr(PiString);                                  
    
       LocLength = %len(%trimr(LocString));       // String-Length    
    
                                                                      
    
       LocEnclen = encbase64bin(%addr(LocBase64): // Encode Base64    
    
                                %addr(LocString):LocLength);          
    
                                                                      
    
       if LocEnclen > *zero;                      // Encoded Length   
    
         return %subst(LocBase64:1:LocEnclen - 1);// without last null
    
       else;                                                          
    
         return *blanks;             
    
       endif;                        
    
                                     
    
     end-proc;


    Hat jemand eine Idee, was ich hier falsch mache oder ist meine Herangehensweise falsch? Bin für jeden Tipp dankbar.



    Grüße, Ingo

  2. #2
    Registriert seit
    Jan 2003
    Beiträge
    746
    Von Scott Clement gibt es ein "Base64 Encode/Decode for ILE RPG":
    https://www.scottklement.com/base64/

    Falls Du ein Beispiel brauchst, müsste ich eins raussuchen...

    (nedoisiswuascht ;- )

  3. #3
    Registriert seit
    Feb 2001
    Beiträge
    20.207
    Dies könnte auch mit deinem Basiscode der Quelle zusammenhängen.
    Du speicherst das zwar als Blob, aber ist es auch Codepage 1252 oder UTF8?
    Vielleicht ist es ja auch EBCDIC (273, o.ä.), somit kommt beim Decode auch nur EBCDIC wieder raus.
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  4. #4
    Registriert seit
    Apr 2020
    Beiträge
    8
    Da geb ich dir grundsätzlich recht, was die Codepages betrifft. Mich verwirrt nur, dass das SQL (getestet mit kleinem Programmobjekt) richtig codierte Daten zurückliefert.

    Select cast(systools.base64encode(Datei) AS clob ccsid 1208) as Datei from Versionsverwaltung
    where programm = 'StaplerTerminal.apk' and versionsnr = '1.0.5';

  5. #5
    Registriert seit
    Feb 2001
    Beiträge
    20.207
    Das ist schon korrekt wenn du auf dem selben System codierst und decodierst.
    Da du BAS64 aber wohl mit Nicht-IBMi austauschen willst wollen die wohl beim dekodieren keinen EBCDIC-Code.
    Du kodierst das A in 273 und dekodierst dies in UTF8 (1252) = Á

    Die andere Frage ist, nimmt Scott auch dieselbe Base64-Zeichenfolge wie die Windows-Welt?

    https://de.wikipedia.org/wiki/Base64
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  6. #6
    Registriert seit
    Aug 2014
    Beiträge
    179
    Hallo Ingo,
    die Anforderung ist nicht so ganz einfach, weil man hier leicht an die 16MB Grenze im RPG stößt. Deine Idee ist schon richtig mit der API apr_base64_encode_binary, denn die kann auch über Pointer anprogrammiert werden und da ist die Grenze viel größer. Ich habe eine Lösung gebaut, die für CLOB Daten funktioniert. BLOB geht genauso. Es ist zu beachten, dass die API die Daten im UTF8 Format = CCSID(*UTF8) verlangt.

    Damit es mit dem Compilieren einfacher ist, habe ich ein CL gebaut, das ein BNDDIR für die BASE64 API's erstellt

    Code:
    /*********************************************************************/
    /*                                                                   */
    /* CREATE BASUTL BINDING-DIRECTORY - BASE64                          */
    /*                                                                   */
    /******************                                                  */
    /* R.ROSS 03.2017 *                                                  */
    /*********************************************************************/
    
       PGM
    
       DCL        VAR(&LIB) TYPE(*CHAR) LEN(10) VALUE(DEVO)
    
       MONMSG     MSGID(CPF0000)
    
    /*********************************************************************/
    /* VERARBEITUNG                                                      */
    /*********************************************************************/
    
       DLTBNDDIR  BNDDIR(&LIB/BASUTL)
       CRTBNDDIR  BNDDIR(&LIB/BASUTL) TEXT('BASE64 Utilities')
    
       ADDBNDDIRE BNDDIR(&LIB/BASUTL) OBJ((QSYSDIR/QAXIS10HT *SRVPGM))
    
    /*********************************************************************/
    /* ENDE                                                              */
    /*********************************************************************/
       ENDE:      ENDPGM
    /*********************************************************************/
    Anbei das RPG für das Erzeugen von BASE64-Daten aus CLOB oder BLOB

    Code:
             ctl-opt main(main) alloc(*teraspace) bnddir('BASUTL');
          //------------------------------------------------------------------//
          //                                                                  //
          // Encode BASE64 with Pointer                                       //
          //                                                                  //
          //-----------------                                                 //
          // R.Ross 04.2020 *                                                 //
          //------------------------------------------------------------------//
          // BASE64 - Encode String - SRVPGM(QSYSDIR/QAXIS10HT)               //
          //------------------------------------------------------------------//
    
             dcl-pr encBase64Bin int(10) extproc('apr_base64_encode_binary');
                     PiEnc_p     pointer value;           // Encoded-Pointer
                     PiSrc_p     pointer value;           // Source-Pointer
                     PiSrclen    int(10) value;           // Source-Length
             end-pr;
    
          //------------------------------------------------------------------//
          // MemCopy                                                          //
          //------------------------------------------------------------------//
    
             dcl-pr memcpy       extproc(*dclcase);
                     mctarget    pointer value;
                     mcsource    pointer value;
                     mclength    uns(10) value;
             end-pr;
    
          //------------------------------------------------------------------//
          // Array BASE64 Ergebnis                                            //
          //------------------------------------------------------------------//
    
             dcl-ds  DsBase64    qualified;
                      String_p   pointer;
                      Length     int(10);
             end-ds;
    
          //------------------------------------------------------------------//
          // Main                                                             //
          //------------------------------------------------------------------//
             dcl-proc Main;
    
             dcl-s   LocClob     SQLType(CLOB:5000000) ccsid(*utf8); // 5 MB
             dcl-s   LocClob64   SQLType(CLOB:5000000) ccsid(*utf8); // 5 MB
    
               exec sql set :LocClob = 'test';
    
          // Daten in BASE64 codieren
    
               DsBase64 = encodeBase64(%addr(LocClob_data):LocClob_len);
    
          // BASE64-Daten aus Pointer in CLOB LocClob64 laden - test -> dGVzdA==
    
               memcpy(%addr(LocClob64_data):DsBase64.String_p:DsBase64.Length);
               LocClob64_len = DsBase64.Length;
    
             end-proc;
          //------------------------------------------------------------------//
          // Encode Data to BASE64                                            //
          //------------------------------------------------------------------//
             dcl-proc encodeBase64;
             dcl-pi *n           likeds(DsBase64);        // Encoded Data
                     PiString_p  pointer const;           // String Pointer
                     PiLength    int(10) const;           // String Length
             end-pi;
    
             dcl-ds  PsBase64    likeds(DsBase64) inz;
    
             dcl-s   LocEnclen   int(10);                 // Encoded Length
    
               if PiLength < 50;
                  PsBase64.String_p = %alloc(PiLength * 10); // alloc Pointer
                else;
                  PsBase64.String_p = %alloc(PiLength * 5);  // alloc Pointer
               endif;
    
               LocEnclen =
                  encBase64Bin(PsBase64.String_p:PiString_p:PiLength);
    
               if LocEnclen > *zero;                       // Encoded Length
                  PsBase64.Length = LocEnclen - 1;         // without last null
               endif;
    
               return PsBase64;
    
             end-proc;
          //------------------------------------------------------------------//
    Bei Fragen kannst Du dich gern an mich wenden

    Herzliche Grüße
    Rainer

  7. #7
    Registriert seit
    Aug 2014
    Beiträge
    179
    Hallo Ingo,

    noch ein Tipp. Bei einem CLOB-Feld wie diesem

    dcl-s Clob sqltype(CLOB:16773100) CCSID(1208);

    erzeugt der Compiler eine Struktur mit 2 Feldern

    CLOB_Data für die Daten und
    CLOB_LEN für die Länge der Daten

    In diesem Fall musst Du die Adresse der Daten nicht mit %Addr(CLOB)
    sondern mit %Addr(CLOB_Data) an die Prozedur übergeben.

    @Forum - wenn es eine einfachere Lösung gibt, dann lasst es mich wissen.

    Herzliche Grüße
    Rainer

  8. #8
    Registriert seit
    Apr 2020
    Beiträge
    8
    Hallo Rainer

    Ja, das war's, danke gleich mal. Hab mit CLOB anstelle von CLOB_Data das Eincoding gemacht. Steht dann auch der richtig codierte Inhalt in der RPG Clob Variablen. Aber eine Frage hab ich noch, wenn ich nun die CLOB Spalte (utv-8) in der Tabelle mittels SQL mit dieser Hostvariablen aktualisiere steht da Schrott drinnen. Muss ich da noch irgendwo konvertieren?

    Soll BASE64: UEsDBBQAAAAIACEIIQLtOXirrAE
    Ist BASE64:
    䅢Ă˜AAɁÅɉؓ����AŒŁA偁A觕

    lg, Ingo


  9. #9
    Registriert seit
    Feb 2001
    Beiträge
    20.207
    Wie schaust du dir den Inhalt an?
    Base64 beibt ASCII-Code!
    Im Debugger kannst du das nur Hex kontrollieren.
    Wenn du den Base64-Wert per SQL in eine UTF-8 -Spalte schreibst kannst du ihn per SQL in 273 wieder ansehen.

    Du kannst den Inhalt auch temporär in eine Char/UCS2-Variable schieben. Die Umwandlung erfolgt dann auch automatisch.
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  10. #10
    Registriert seit
    Apr 2020
    Beiträge
    8
    Im Debug sehe ich den richtigen Inhalt

    Code:
     EVAL locClob64                                                          LOCCLOB64_LEN OF LOCCLOB64 = 7206264                                   
     LOCCLOB64_DATA OF LOCCLOB64 =                                          
               ....5...10...15...20...25...30...35...40...45...50...55...60 
          1   'UEsDBBQAAAAIACEIIQLtOXirrAEAAEkEAAAVAAAAYXNzZXRzL0VNREtDb25m'
         61   'aWcueG1sjVNLb5tAEL5Xyn+Ycq3AYKdNZGFHkZ1WVUVVyaSHXqzJMuBVYNda'
        121   '1k7Jr+/gxyYo0FbitDPfY74Z4pvfVQl7MrXUauZFQegBKaEzqYqZd59+9q+9'
        181   'm3n83vfTjayBP1SAO6uhIEUGLWWQabGrSNkAFhtUBdXAZdu2nytQYQMCdzWB'
    Variablendefinition: dcl-s LocClob64 sqltype(CLOB:16773100) CCSID(*UTF8);

    Jobdefinitionsattribute:
    Code:
    Sprachen-ID . . . . . . . . . . . . . . . . . . . :   DEU     Landes- oder Regions-ID . . . . . . . . . . . . . :   AT      
    ID des codierten Zeichensatzes (CCSID)  . . . . . :   65535   
    Standard-ID des codierten Zeichensatzes . . . . . :   273     
    Steuerung für Zeichen-ID  . . . . . . . . . . . . :   *DEVD
    Die Abfrage und das Ergebnis der Daten über Webservice IWS sieht dann so aus:

    Click image for larger version. 

Name:	2020-04-27 13_26_04-Clipboard.jpg 
Views:	17 
Size:	30,9 KB 
ID:	566

    Click image for larger version. 

Name:	2020-04-27 13_22_53-Clipboard.jpg 
Views:	12 
Size:	44,6 KB 
ID:	565


    lg, Ingo

  11. #11
    Registriert seit
    Aug 2014
    Beiträge
    179
    Hallo Ingo,

    soll der Webservice ungefähr so aussehen?

    http://www.myhofi.com/myapp/webbase64.pgm?data=test

    in diesem Fall wandelt er den String "test" richtig in "dGVzdA==" um

  12. #12
    Registriert seit
    Apr 2020
    Beiträge
    8
    Hallo Rainer

    Ja, genau so sollte er aussehen, nur bei mir kommt immer folgendes raus:

    { "DATEI" : "䅢Ă˜AAɁÅɉؓ����AŒŁA偁A觕����ՙţĂ��惤??����œ??N胘��??ƈ�� 夥威∧����Մ��љNa????��??鴗??��礁????��蘩??...
    lg, Ingo

Similar Threads

  1. BLOB mit BASE64 encoden für REST Service im IBM i IWS
    By ismiavoiwuascht in forum NEWSboard Programmierung
    Antworten: 0
    Letzter Beitrag: 25-04-20, 11:18
  2. BLOB Feld
    By mk in forum IBM i Hauptforum
    Antworten: 3
    Letzter Beitrag: 19-06-19, 08:26
  3. REST Web-Service unter V6R1
    By Flappes in forum NEWSboard Programmierung
    Antworten: 2
    Letzter Beitrag: 22-05-17, 12:22
  4. Clob to Blob
    By dschroeder in forum IBM i Hauptforum
    Antworten: 14
    Letzter Beitrag: 31-08-16, 16:32
  5. Wie kann man eine url encoden/decoden?
    By dschroeder in forum NEWSboard Programmierung
    Antworten: 5
    Letzter Beitrag: 01-10-14, 11:52

Tags for this Thread

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • You may not post attachments
  • You may not edit your posts
  •