• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Guru: Practicing Safe Hex in RPG

    March 2, 2020 Jon Paris

    In this tip I’m going to address a question that arises regularly on RPG-oriented Internet lists, namely: “Is there an easy way to convert a character string to its hexadecimal equivalent?”

    One answer, of course, would be to write your own routine using lookup tables, but there is a far easier way. We can take advantage of the system’s hex MI APIs. These were originally surfaced for use by C and C++ but, thanks to the joys of ILE, can be used by any ILE language. Not only that, RPG’s prototyping support makes them really easy to use. In fact, not only can you easily convert from a character representation to its hex equivalent, you can also go the other way, i. e., take a hex string and convert it to characters. Indeed, these APIs are not limited to character data but can work with any “chunk” of memory which means they can be used to encode/decode images, PDFs, etc. More on this later in the section “An Alternative Prototype?”

    Suppose I need to create the hex equivalent of the character string ‘ABCDE’. The resulting hex string should be ‘C1C2C3C4C5′ since X’C1’ is the hex value for ‘A’ in EBCDIC, X’C2′ is the value for ‘B’ and so on. Similarly my name (Jon Paris) would convert to ‘D1969540D7819989A2’.

    The two procedures that enable these conversions are cvtch, which converts from hex pairs to their corresponding character representation, and cvthc, which converts individual characters to their corresponding hex pair. If you want to know the full details of these procedures you can find them, and many others, documented in the manual ILE C/C++ for AS/400 MI Library Reference.

    The names for these procedures can be a little misleading, and the manual description needs careful reading to understand which does what. For example, you might think that the name cvtch means “convert character to hex” based on its name. In fact it does the exact opposite, a fact made a little clearer by the full IBM title for the API, which is “Convert Eight Bit Character to Hex Nibbles.” OK . . . so that doesn’t make it that much more obvious! The full title should probably be “Convert Eight Bit Character Representation of a Hex Digit to the Corresponding Hex Nibble.” Of course even that only makes sense if you know that a nibble (or nybble as it is sometimes spelled) is four bits — half a byte. Half a byte is a nibble!

    Let’s start by looking at the prototype for cvthc.

    dcl-pr CharToHex ExtProc('cvthc');
       hexResult    Char(65534)  Options(*VarSize);
       charInput    Char(32767)  Options(*VarSize);
       charNibbles  Int(10)  Value;
    End-Pr;
    

    There are a few points to note here:

    First, I named the prototype CharToHex rather than use the actual API name. This helps avoid misunderstandings due to the somewhat misleading name and makes it more obvious what the API does.

    Second, I have defined both the input (charInput) and output (hexResult) parameters with Options(*VarSize) so that fields smaller than the declared maximum can be used. Note that the output parameter must always be twice the length of the input since two output characters will be generated for each input character. It is also worth noting that you can make the lengths pretty much anything you like.

    The third parameter will contain the length of the input field in nibbles, i.e., the length of the input field multiplied by two.

    Let’s look at the process in action.

        dcl-s  textString  Char(24);
           dcl-s  hexString   Char(48);
           dcl-s  length      int(10);
        Dsply  ('Enter Max 24 char string') ' ' textString;
           // Calculate the number of hex nibbles in the input
        length = %Size(textString) * 2;
        CharToHex ( hexString : textString : length );
           Dsply 'Hex result is:';
           Dsply hexstring;
    

    <A> Defines the three variables used.

    <B> The program requests an input string of up to 24 characters.

    <C> This calculates the length in nibbles of the input string.

    <D> We then call CharToHex() to perform the conversion and display the results. If you are thinking that I could have simply specified %Size(textString) * 2 as the length parameter rather than calculate it separately (doing away with the length field) you are quite correct.

    CharToHex ( hexString : textString : %Size(textString) * 2 );
    

    The prototype for the reverse procedure HexToChar (cvtch) is, as you might expect, basically the same. As before the result is placed in the first parameter, and the input is taken from the second parameter. You can see the call below beneath the prototype. The length of the input is passed in the third parameter. Note that this is the actual length in bytes and there’s no need to multiply by two.

    dcl-pr HexToChar ExtProc('cvtch');
         charResult  Char(32767)  Options(*VarSize);
         hexInput    Char(65534)  Options(*VarSize);
         hexLength   Int(10)  Value;
    End-Pr;
    ...
    HexToChar ( textString : hexString : %Size(hexString));
    

    An Alternative Prototype?

    If you are experienced in working with prototypes for C-style APIs may have been surprised by the prototypes I showed earlier. From reading the documentation you would probably have expected to see something more like this:

    dcl-pr cvtch ExtProc('cvtch');     
       charResult  pointer  Value;     
       hexInput    pointer  Value;     
       hexLength   Int(10)  Value;     
    End-Pr;                            
    

    Indeed that is a technically accurate representation of the APIs definition. So why did I choose to use a different prototype, and why do both of them work?

    The reason I chose to use a different prototype for my main example is simply that in my opinion it makes the invocation more “RPG like.” What I mean by that is best explained by showing what the invocation of this version would have to look like:

    HexToChar ( %Addr(textString) : %Addr(hexString) : %Size(hexString));
    

    As you can see, it requires that we pass the address of each parameter rather than simply reference the field. So how come my first version works? Simply put, when you pass a variable by reference, which is what we are doing in the original example, a pointer to that variable is passed to the called routine. And that is exactly the same thing that we are doing when we pass %Addr() when the prototype defines the parameter as a pointer passed by value. That is, passing a variable by reference is the same as passing a pointer to that variable by value.

    So do I ever use this second version? Yes. I use this when I am working with dynamic storage, since I already have a pointer to the storage. I also use it when processing fields in teraspace that exceed 16Mbs because such fields that are too large to define directly in RPG.

    In the code package that accompanies this tip (which can be downloaded here) there is an example of allocating a large amount of storage (17Mb) and processing it with these procedures.

    Wrap It Up

    If you look at the MI reference I mentioned earlier, you will see that are a number of other low-level MI APIs available to the RPG programmer. If you have a need for any of these and encounter any issues, please let me know.

    Jon Paris is one of the world’s foremost experts on programming on the IBM i platform. A frequent author, forum contributor, and speaker at User Groups and technical conferences around the world, he is also an IBM Champion and a partner at Partner400 and System i Developer. He hosts the RPG & DB2 Summit twice per year with partners Susan Gantner and Paul Tuohy.

    RELATED STORIES

    Fundamentals: Parameter Passing

    Parameter Passing Fundamentals Of Programs Versus Procedures

    Where Does Data Live? The New Basics

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags: Tags: 400guru, API, FHG, Four Hundred Guru, IBM i, ILE, RPG

    Sponsored by
    Maxava

    Migrate IBM i with Confidence

    Tired of costly and risky migrations? Maxava Migrate Live minimizes disruption with seamless transitions. Upgrading to Power10 or cloud hosted system, Maxava has you covered!

    Learn More

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Please Take The 2020 State of Modernization Survey Boadway’s 25-Year Performance Shows No Let Up

    9 thoughts on “Guru: Practicing Safe Hex in RPG”

    • Vectorspace says:
      March 2, 2020 at 8:49 am

      You can also get the hex equivalent of a character string using SQL function hex. In SQLRPGLE:
      fromStr = ‘Jon Paris’;
      exec sql set :hexStr = hex(:fromStr);
      //hexStr will be ‘D1969540D7819989A2’;

      Reply
      • Jon Paris says:
        March 3, 2020 at 10:02 am

        Hi Vectorspace.

        I just _knew_ someone would say SQL and I had intended to mention it but there were two reasons why I ignored it. For one it seems to be oriented more towards providing a visual representation of binary data for debugging rather than being a “real” function. Reason I say that is that it can only handle relatively small fields and only goes in one direction – there is no FromHex option. Or am I missing something ?

        Reply
    • Chris Pando says:
      March 2, 2020 at 3:03 pm

      I use the cvthc/cvtch myself, but it’s not difficult in RPG (with, as you said, a lookup table).

      * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
      * *
      * … convert 10u 0 interger into 8a hex *
      * *
      * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
      p cvtToHex b
      d pi 8a
      d fromInt 10u 0 Value

      d $I s 5s 0
      d toHex s 8a
      /free
      For $I = 1 to 8;
      %SubSt( toHex : 9 – $I : 1 ) = hexValues( %Rem(fromInt:16) + 1 );
      fromInt = %Div(fromInt:16);
      EndFor;
      Return toHex;
      /end-free
      p cvtToHex e

      with hexValues defined as:

      d hexValues s 1a CtData PerRcd(16) Dim(16)

      and populated with:

      **
      0123456789ABCDEF

      Example

      fromInt = 83,613,360

      toHex = ’04FBD6B0′

      Reply
      • Jon Paris says:
        March 3, 2020 at 10:06 am

        Hi Chris,

        Sorry – can’t use your version – it is against my principals to use compile-time data

        Thanks for submitting that though.

        P.S. Unless you are back on V6 you don’t need the /Free any more.

        Reply
        • Jon Paris says:
          March 3, 2020 at 10:08 am

          Darn it – there is supposed to be a “grin” tag after the compile-time data bit. The silly commenting machine removed it!

          Reply
    • Stéphane Yelle says:
      March 6, 2020 at 6:32 pm

      The link to the code package does not work. (404)

      http://www.partner400.com/examples/ITJTip_HexConversion.txt

      Reply
      • Jon Paris says:
        April 30, 2020 at 9:30 am

        My apologies Stéphane – I know I copied it to my IFS but it was not where it should have been! It is there now if you would like to try again.

        And my apologies for taking so long to respond – I was only notified of the problem today.

        Reply
    • Manuel Ortiz says:
      April 15, 2020 at 7:29 pm

      Nice article Jon. Very enjoyable and useful.

      Reply
      • Jon Paris says:
        April 30, 2020 at 9:31 am

        Thanks Manuel – glad you found it useful.

        Reply

    Leave a Reply Cancel reply

TFH Volume: 30 Issue: 15

This Issue Sponsored By

  • Computer Keyes
  • Manta Technologies
  • Northeast User Groups Conference
  • COMMON
  • Fresche Solutions

Table of Contents

  • Big Blue Raises IBM i Software Maintenance Fees Modestly
  • Boadway’s 25-Year Performance Shows No Let Up
  • Guru: Practicing Safe Hex in RPG
  • Please Take The 2020 State of Modernization Survey
  • IBM i PTF Guide, Volume 22, Number 9

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • POWERUp 2025 –Your Source For IBM i 7.6 Information
  • Maxava Consulting Services Does More Than HA/DR Project Management – A Lot More
  • Guru: Creating An SQL Stored Procedure That Returns A Result Set
  • As I See It: At Any Cost
  • IBM i PTF Guide, Volume 27, Number 19
  • IBM Unveils Manzan, A New Open Source Event Monitor For IBM i
  • Say Goodbye To Downtime: Update Your Database Without Taking Your Business Offline
  • i-Rays Brings Observability To IBM i Performance Problems
  • Another Non-TR “Technology Refresh” Happens With IBM i TR6
  • IBM i PTF Guide, Volume 27, Number 18

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle