Subversion Repositories oidconverter

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*###################################################################
  2. ###                                                               ###
  3. ### Object ID converter. Matthias Gaertner, 06/1999               ###
  4. ### Converted to plain 'C' 07/2001                                ###
  5. ###                                                               ###
  6. ### Enhanced version by Daniel Marschall, ViaThinkSoft 06/2011    ###
  7. ### -- NEW 1.2: 2.48 can also be encoded!                         ###
  8. ### -- NEW 1.2: UUIDs (128-bit) are now supported!                ###
  9. ###             (requires GMPLib)                                 ###
  10. ### -- NEW 1.3: Length can now have more than 1 byte              ###
  11. ### -- AS WELL AS SEVERAL BUG FIXES                               ###
  12. ###                                                               ###
  13. ### To compile with gcc simply use:                               ###
  14. ###   gcc -O2 -o oid oid.c -lgmp -lm                              ###
  15. ###                                                               ###
  16. ### To compile using cl, use:                                     ###
  17. ###   cl -DWIN32 -O1 oid.c (+ include gmp library)                ###
  18. ###                                                               ###
  19. ### Freeware - do with it whatever you want.                      ###
  20. ### Use at your own risk. No warranty of any kind.                ###
  21. ###                                                               ###
  22. ###################################################################*/
  23. /* $Version: 1.3$ */
  24.  
  25. // MAJOR PROBLEMS:
  26. // - Long OIDS: Buffer overflow in abBinary[] without any segfault?
  27.  
  28. // MINOR PROBLEMS:
  29. // - A wrong error message is shown when trying to encode "-0.0" or "x"
  30.  
  31. // NICE TO HAVE:
  32. // - makefile / linuxpackage
  33. // - better make functions instead of putting everything in main() with fprintf...
  34.  
  35. // NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
  36. // - Remove command line limitation (to allow unlimited long OIDs)
  37. // - Is it possible to detect overflows and therefore output errors?
  38.  
  39. // -------------------------------------------------------
  40.  
  41. // Allows OIDs which are bigger than "long"
  42. // Compile with "gcc oid.c -lgmp -lm"
  43. #define is_gmp
  44.  
  45. #include <stdio.h>
  46. #include <string.h>
  47. #include <stdlib.h>
  48.  
  49. #ifdef is_gmp
  50. #include <gmp.h>
  51. #endif
  52.  
  53. #include <stdbool.h>
  54.  
  55. #ifndef __STRNICMP_LOCAL
  56. #ifdef WIN32
  57. #define __STRNICMP_LOCAL strnicmp
  58. #else
  59. #define __STRNICMP_LOCAL strncasecmp
  60. #endif
  61. #endif
  62.  
  63. char                    abCommandLine[4096]; // TODO: Supersize me
  64. unsigned char   abBinary[128]; // TODO: Supersize me (?)
  65. unsigned int    nBinary = 0;
  66.  
  67.  
  68. #ifdef is_gmp
  69. static void MakeBase128( mpz_t l, int first ) {
  70.         if ( mpz_cmp_si(l, 127) > 0 ) {
  71.                 mpz_t l2;
  72.                 mpz_init(l2);
  73.                 mpz_div_ui(l2, l, 128);
  74.                 MakeBase128( l2 , 0 );
  75.         }
  76.         mpz_mod_ui(l, l, 128);
  77.         if ( first ) {
  78.                 abBinary[nBinary++] = mpz_get_ui(l);
  79.         } else {
  80.                 abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
  81.         }
  82. }
  83. #else
  84. static void MakeBase128( unsigned long l, int first ) {
  85.         if ( l > 127 ) {
  86.                 MakeBase128( l / 128, 0 );
  87.         }
  88.         l %= 128;
  89.         if ( first ) {
  90.                 abBinary[nBinary++] = (unsigned char)l;
  91.         } else {
  92.                 abBinary[nBinary++] = 0x80 | (unsigned char)l;
  93.         }
  94. }
  95. #endif
  96.  
  97. int main( int argc, char **argv ) {
  98.         char *fOutName = NULL;
  99.         char *fInName = NULL;
  100.         FILE *fOut = NULL;
  101.  
  102.         int n = 1;
  103.         int nMode = 0;  /* dotted->hex */
  104.         int nCHex = 0;
  105.         int nAfterOption = 0;
  106.  
  107.         if ( argc == 1 ) {
  108.                 fprintf( stderr,
  109.                 "OID encoder/decoder 1.3 - Matthias Gaertner 1999/2001, Daniel Marschall 2011 - Freeware\n"
  110.                 #ifdef is_gmp
  111.                 "GMP Edition\n"
  112.                 #endif
  113.                 "\nUsage:\n"
  114.                 " OID [-C] [-o<outfile>] {-i<infile>|2.999.1}\n"
  115.                 "   converts dotted form to ASCII HEX DER output.\n"
  116.                 " OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
  117.                 "   decodes ASCII HEX DER and gives dotted form.\n" );
  118.                 return 1;
  119.         }
  120.  
  121.         while ( n < argc ) {
  122.                 if ( !nAfterOption && argv[n][0] == '-' ) {
  123.                         if ( argv[n][1] == 'x' ) {
  124.                                 nMode = 1;      /* hex->dotted */
  125.                                 if ( argv[n][2] != '\0' ) {
  126.                                         argv[n--] += 2;
  127.                                         nAfterOption = 1;
  128.                                 }
  129.                         } else if ( argv[n][1] == 'C' ) {
  130.                                 nMode = 0;
  131.                                 nCHex = 1;
  132.  
  133.                                 if ( argv[n][2] != '\0' ) {
  134.                                         argv[n--] += 2;
  135.                                         nAfterOption = 1;
  136.                                 }
  137.                         } else if ( argv[n][1] == 'o' ) {
  138.                                 if ( argv[n][2] != '\0' ) {
  139.                                         fOutName = &argv[n][2];
  140.                                 } else if ( n < argc-1 ) {
  141.                                         fOutName = argv[++n];
  142.                                 } else {
  143.                                         fprintf(stderr,"Incomplete command line.\n");
  144.                                 }
  145.                         } else if ( argv[n][1] == 'i' ) {
  146.                                 if ( argv[n][2] != '\0' ) {
  147.                                         fInName = &argv[n][2];
  148.                                 } else if ( n < argc-1 ) {
  149.                                         fInName = argv[++n];
  150.                                 } else {
  151.                                         fprintf(stderr,"Incomplete command line.\n");
  152.                                 }
  153.                         }
  154.                 } else {
  155.                         if ( fInName != NULL ) {
  156.                                 break;
  157.                         }
  158.  
  159.                         nAfterOption = 1;
  160.                         if ( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 ) {
  161.                                 fprintf(stderr,"Command line too long.\n");
  162.                                 return 2;
  163.                         }
  164.                         strcat( abCommandLine, argv[n] );
  165.                         if ( n != argc - 1 && nMode != 1 ) {
  166.                                 strcat( abCommandLine, "." );
  167.                         }
  168.                 }
  169.                 n++;
  170.         }
  171.  
  172.         if ( fInName != NULL && nMode == 1 ) {
  173.                 FILE *fIn = fopen( fInName, "rb" );
  174.                 size_t nRead = 0;
  175.                 if ( fIn == NULL ) {
  176.                         fprintf(stderr,"Unable to open input file %s.\n", fInName );
  177.                         return 11;
  178.                 }
  179.                 nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
  180.                 abCommandLine[nRead] = '\0';
  181.                 fclose( fIn );
  182.         } else if ( fInName != NULL && nMode == 0 ) {
  183.                 FILE *fIn = fopen( fInName, "rt" );
  184.                 if ( fIn == NULL ) {
  185.                         fprintf(stderr,"Unable to open input file %s.\n", fInName );
  186.                         return 11;
  187.                 }
  188.                 fgets( abCommandLine, sizeof(abCommandLine), fIn );
  189.                 fclose( fIn );
  190.         }
  191.  
  192.         while ( nMode == 1 )    /* better if */
  193.         {
  194.                 /* hex->dotted */
  195.                 /*printf("Hex-In: %s\n", abCommandLine );*/
  196.  
  197.                 char *p = abCommandLine;
  198.                 char *q = p;
  199.  
  200.                 unsigned char *pb = NULL;
  201.                 unsigned int nn = 0;
  202.                 #ifdef is_gmp
  203.                 mpz_t ll;
  204.                 mpz_init(ll);
  205.                 #else
  206.                 unsigned long ll = 0;
  207.                 #endif
  208.                 bool fOK = false;
  209.                 int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
  210.  
  211.                 while ( *p ) {
  212.                         if ( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
  213.                                 *q++ = *p;
  214.                         }
  215.                         p++;
  216.                 }
  217.                 *q = '\0';
  218.  
  219.                 if ( strlen( abCommandLine ) % 2 != 0 ) {
  220.                         fprintf(stderr, "Encoded OID must have even number of hex digits!\n" );
  221.                         return 2;
  222.                 }
  223.  
  224.                 if ( strlen( abCommandLine ) < 3 ) {
  225.                         fprintf(stderr, "Encoded OID must have at least three bytes!\n" );
  226.                         return 2;
  227.                 }
  228.  
  229.                 nBinary = 0;
  230.                 p = abCommandLine;
  231.  
  232.                 while ( *p ) {
  233.                         unsigned char b;
  234.  
  235.                         // Interpret upper nibble
  236.                         if ( p[0] >= 'A' && p[0] <= 'F' ) {
  237.                                 b = (p[0] - 'A' + 10) * 16;
  238.                         } else if ( p[0] >= 'a' && p[0] <= 'f' ) {
  239.                                 b = (p[0] - 'a' + 10) * 16;
  240.                         } else if ( p[0] >= '0' && p[0] <= '9' ) {
  241.                                 b = (p[0] - '0') * 16;
  242.                         } else {
  243.                                 fprintf(stderr, "Must have hex digits only!\n" );
  244.                                 return 2;
  245.                         }
  246.  
  247.                         // Interpret lower nibble
  248.                         if ( p[1] >= 'A' && p[1] <= 'F' ) {
  249.                                 b += (p[1] - 'A' + 10);
  250.                         } else if ( p[1] >= 'a' && p[1] <= 'f' ) {
  251.                                 b += (p[1] - 'a' + 10);
  252.                         } else if ( p[1] >= '0' && p[1] <= '9' ) {
  253.                                 b += (p[1] - '0');
  254.                         } else {
  255.                                 fprintf(stderr, "Must have hex digits only!\n" );
  256.                                 return 2;
  257.                         }
  258.  
  259.                         abBinary[nBinary++] = b;
  260.                         p += 2;
  261.                 }
  262.  
  263.                 /*printf("Hex-In: %s\n", abCommandLine );*/
  264.  
  265.                 if ( fOutName != NULL ) {
  266.                         fOut = fopen( fOutName, "wt" );
  267.                         if ( fOut == NULL ) {
  268.                                 fprintf(stderr,"Unable to open output file %s\n", fOutName );
  269.                                 return 33;
  270.                         }
  271.                 } else {
  272.                         fOut = stdout;
  273.                 }
  274.  
  275.                 pb = abBinary;
  276.                 nn = 0;
  277.                 #ifdef is_gmp
  278.                 mpz_init(ll);
  279.                 #else
  280.                 ll = 0;
  281.                 #endif
  282.                 fOK = false;
  283.                 fSub = 0;
  284.  
  285.                 // 0 = Universal Class Identifier Tag
  286.                 // 1 = Length part (may have more than 1 byte!)
  287.                 // 2 = First two arc encoding
  288.                 // 3 = Encoding of arc three and higher
  289.                 unsigned char part = 0;
  290.  
  291.                 unsigned char lengthbyte_count = 0;
  292.                 unsigned char lengthbyte_pos = 0;
  293.                 bool lengthfinished = false;
  294.  
  295.                 while ( nn < nBinary ) {
  296.                         if ( part == 0 ) { // Class Tag
  297.                                 unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
  298.                                 switch ( cl ) {
  299.                                         default:
  300.                                         case 0: fprintf(fOut,"UNIVERSAL"); break;
  301.                                         case 1: fprintf(fOut,"APPLICATION"); break;
  302.                                         case 2: fprintf(fOut,"CONTEXT"); break;
  303.                                         case 3: fprintf(fOut,"PRIVATE"); break;
  304.                                 }
  305.                                 fprintf(fOut," OID");
  306.                                 part++;
  307.                         } else if ( part == 1 ) { // Length
  308.  
  309.                                 // Find out the length and save it into ll
  310.  
  311.                                 // 2nd Byte
  312.                                 // 0x00 .. 0x7F => The actual length
  313.                                 // 0x80 + n => The length is spread over the following 'n' bytes
  314.                                 // (Unknown: Is 'n' limited or can it be until 0xFF is reached?)
  315.                                 // (Unknown: How is length=0x80 (=0 following bytes define the length) defined? Is it the same as 0x00?)
  316.  
  317.                                 if (nn == 1) { // The first length byte
  318.                                         lengthbyte_pos = 0;
  319.                                         if ( (*pb & 0x80) != 0 ) {
  320.                                                 // 0x80 + n => The length is spread over the following 'n' bytes
  321.                                                 lengthfinished = false;
  322.                                                 lengthbyte_count = *pb & 0x7F;
  323.                                                 fOK = false;
  324.                                         } else {
  325.                                                 // 0x00 .. 0x7F => The actual length
  326.                                                 #ifdef is_gmp
  327.                                                 mpz_set_ui(ll, *pb);
  328.                                                 #else
  329.                                                 ll = *pb;
  330.                                                 #endif
  331.                                                 lengthfinished = true;
  332.                                                 lengthbyte_count = 0;
  333.                                                 fOK = true;
  334.                                         }
  335.                                 } else {
  336.                                         if (lengthbyte_count > lengthbyte_pos) {
  337.                                                 #ifdef is_gmp
  338.                                                 mpz_mul_ui(ll, ll, 0x100);
  339.                                                 mpz_add_ui(ll, ll, *pb);
  340.                                                 #else
  341.                                                 ll *= 0x100;
  342.                                                 ll += *pb;
  343.                                                 #endif
  344.                                                 lengthbyte_pos++;
  345.                                         }
  346.  
  347.                                         if (lengthbyte_count == lengthbyte_pos) {
  348.                                                 lengthfinished = true;
  349.                                                 fOK = true;
  350.                                         }
  351.                                 }
  352.  
  353.                                 if (lengthfinished) { // The length is now in ll
  354.                                         #ifdef is_gmp
  355.                                         if ( mpz_cmp_ui(ll,  nBinary - 2 - lengthbyte_count) != 0 ) {
  356.                                                 fprintf(fOut,"\n");
  357.                                                 if ( fOut != stdout ) {
  358.                                                         fclose( fOut );
  359.                                                 }
  360.                                                 fprintf(stderr,"\nInvalid length (%d entered, but %s expected)\n", nBinary - 2, mpz_get_str(NULL, 10, ll) );
  361.                                                 return 3;
  362.                                         }
  363.                                         mpz_set_ui(ll, 0); // reset for later usage
  364.                                         #else
  365.                                         if ( ll != nBinary - 2 - lengthbyte_count ) {
  366.                                                 fprintf(fOut,"\n");
  367.                                                 if ( fOut != stdout ) {
  368.                                                         fclose( fOut );
  369.                                                 }
  370.                                                 fprintf(stderr,"\nInvalid length (%d entered, but %d expected)\n", nBinary - 2, ll );
  371.                                                 return 3;
  372.                                         }
  373.                                         ll = 0; // reset for later usage
  374.                                         #endif
  375.                                         fOK = true;
  376.                                         part++;
  377.                                 }
  378.                         } else if ( part == 2 ) { // First two arcs
  379.                                 int first = *pb / 40;
  380.                                 int second = *pb % 40;
  381.                                 if (first > 2) {
  382.                                         first = 2;
  383.                                         fprintf(fOut,".%d", first );
  384.  
  385.                                         if ( (*pb & 0x80) != 0 ) {
  386.                                                 // 2.48 and up => 2+ octets
  387.                                                 #ifdef is_gmp
  388.                                                 mpz_add_ui(ll, ll, (*pb & 0x7F));
  389.                                                 #else
  390.                                                 ll += (*pb & 0x7F);
  391.                                                 #endif
  392.                                                 fSub = 80;
  393.                                                 fOK = false;
  394.                                         } else {
  395.                                                 // 2.0 till 2.47 => 1 octet
  396.                                                 second = *pb - 80;
  397.                                                 fprintf(fOut,".%d",second);
  398.                                                 fOK = true;
  399.                                                 #ifdef is_gmp
  400.                                                 mpz_set_ui(ll, 0);
  401.                                                 #else
  402.                                                 ll = 0;
  403.                                                 #endif
  404.                                         }
  405.                                 } else {
  406.                                         // 0.0 till 0.37 => 1 octet
  407.                                         // 1.0 till 1.37 => 1 octet
  408.                                         fprintf(fOut,".%d.%d", first, second );
  409.                                         fOK = true;
  410.                                         #ifdef is_gmp
  411.                                         mpz_set_ui(ll, 0);
  412.                                         #else
  413.                                         ll = 0;
  414.                                         #endif
  415.                                 }
  416.                                 part++;
  417.                         } else if ( part == 3 ) { // Arc three and higher
  418.                                 if ( (*pb & 0x80) != 0 ) {
  419.                                         #ifdef is_gmp
  420.                                         mpz_mul_ui(ll, ll, 128);
  421.                                         mpz_add_ui(ll, ll, (*pb & 0x7F));
  422.                                         #else
  423.                                         ll *= 128;
  424.                                         ll += (*pb & 0x7F);
  425.                                         #endif
  426.                                         fOK = false;
  427.                                 } else {
  428.                                         #ifdef is_gmp
  429.                                         mpz_mul_ui(ll, ll, 128);
  430.                                         mpz_add_ui(ll, ll, *pb);
  431.                                         mpz_sub_ui(ll, ll, fSub);
  432.                                         fprintf(fOut,".%s", mpz_get_str(NULL, 10, ll) );
  433.                                         mpz_set_ui(ll, 0);
  434.                                         #else
  435.                                         ll *= 128;
  436.                                         ll += *pb;
  437.                                         ll -= fSub;
  438.                                         fprintf(fOut,".%lu", ll );
  439.                                         ll = 0;
  440.                                         #endif
  441.                                         fSub = 0;
  442.                                         fOK = true;
  443.                                 }
  444.                         }
  445.  
  446.                         pb++;
  447.                         nn++;
  448.                 }
  449.  
  450.                 if ( !fOK ) {
  451.                         fprintf(fOut,"\n");
  452.                         if ( fOut != stdout ) {
  453.                                 fclose( fOut );
  454.                         }
  455.                         fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
  456.                         return 4;
  457.                 } else {
  458.                         fprintf(fOut,"\n");
  459.                 }
  460.  
  461.                 if ( fOut != stdout ) {
  462.                         fclose( fOut );
  463.                 }
  464.                 break;
  465.         };
  466.  
  467.         while ( nMode == 0 )    /* better if */
  468.         {
  469.                 /* dotted->hex */
  470.                 /* printf("OID.%s\n", abCommandLine ); */
  471.  
  472.                 char *p = abCommandLine;
  473.                 unsigned char cl = 0x00;
  474.                 char *q = NULL;
  475.                 int nPieces = 1;
  476.                 int n = 0;
  477.                 unsigned char b = 0;
  478.                 unsigned int nn = 0;
  479.                 #ifdef is_gmp
  480.                 mpz_t l;
  481.                 #else
  482.                 unsigned long l = 0;
  483.                 #endif
  484.                 bool isjoint = false;
  485.  
  486.                 if ( __STRNICMP_LOCAL( p, "UNIVERSAL.", 10 ) == 0 ) {
  487.                         p+=10;
  488.                 } else if ( __STRNICMP_LOCAL( p, "APPLICATION.", 12 ) == 0 ) {
  489.                         cl = 0x40;
  490.                         p+=12;
  491.                 } else if ( __STRNICMP_LOCAL( p, "CONTEXT.", 8 ) == 0 ) {
  492.                         cl = 0x80;
  493.                         p+=8;
  494.                 } else if ( __STRNICMP_LOCAL( p, "PRIVATE.", 8 ) == 0 ) {
  495.                         cl = 0xC0;
  496.                         p+=8;
  497.                 }
  498.  
  499.                 if ( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 ) {
  500.                         p+=4;
  501.                 }
  502.  
  503.                 q = p;
  504.                 nPieces = 1;
  505.                 while ( *p ) {
  506.                         if ( *p == '.' ) {
  507.                                 nPieces++;
  508.                         }
  509.                         p++;
  510.                 }
  511.  
  512.                 n = 0;
  513.                 b = 0;
  514.                 p = q;
  515.                 while ( n < nPieces ) {
  516.                         q = p;
  517.                         while ( *p ) {
  518.                                 if ( *p == '.' ) {
  519.                                         break;
  520.                                 }
  521.                                 p++;
  522.                         }
  523.  
  524.                         #ifdef is_gmp
  525.                         mpz_init(l);
  526.                         #else
  527.                         l = 0;
  528.                         #endif
  529.                         if ( *p == '.' ) {
  530.                                 *p = 0;
  531.                                 #ifdef is_gmp
  532.                                 mpz_set_str(l, q, 10);
  533.                                 #else
  534.                                 l = (unsigned long) atoi( q );
  535.                                 #endif
  536.                                 q = p+1;
  537.                                 p = q;
  538.                         } else {
  539.                                 #ifdef is_gmp
  540.                                 mpz_set_str(l, q, 10);
  541.                                 #else
  542.                                 l = (unsigned long) atoi( q );
  543.                                 #endif
  544.                                 q = p;
  545.                         }
  546.  
  547.                         /* Digit is in l. */
  548.                         if ( n == 0 ) {
  549.                                 #ifdef is_gmp
  550.                                 if (mpz_cmp_ui(l, 2) > 0) {
  551.                                 #else
  552.                                 if (l > 2) {
  553.                                 #endif
  554.                                         fprintf(stderr,"\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
  555.                                         return 5;
  556.                                 }
  557.                                 #ifdef is_gmp
  558.                                 b += 40 * mpz_get_ui(l);
  559.                                 isjoint = mpz_cmp_ui(l, 2) == 0;
  560.                                 #else
  561.                                 b = 40 * ((unsigned char)l);
  562.                                 isjoint = l == 2;
  563.                                 #endif
  564.                         } else if ( n == 1 ) {
  565.                                 #ifdef is_gmp
  566.                                 if ((mpz_cmp_ui(l, 39) > 0) && (!isjoint)) {
  567.                                 #else
  568.                                 if ((l > 39) && (!isjoint)) {
  569.                                 #endif
  570.                                         fprintf(stderr,"\nEncoding error. The second level is limited to 0..39 for top level arcs 0 and 1.\n");
  571.                                         return 5;
  572.                                 }
  573.  
  574.                                 #ifdef is_gmp
  575.                                 if (mpz_cmp_ui(l, 47) > 0) {
  576.                                         mpz_add_ui(l, l, 80);
  577.                                         MakeBase128( l, 1 );
  578.                                 } else {
  579.                                         b += mpz_get_ui(l);
  580.                                         abBinary[nBinary++] = b;
  581.                                 }
  582.                                 #else
  583.                                 if (l > 47) {
  584.                                         l += 80;
  585.                                         MakeBase128( l, 1 );
  586.                                 } else {
  587.                                         b += ((unsigned char) l);
  588.                                         abBinary[nBinary++] = b;
  589.                                 }
  590.                                 #endif
  591.                         } else {
  592.                                 MakeBase128( l, 1 );
  593.                         }
  594.                         n++;
  595.                 }
  596.  
  597.                 if (n < 2) {
  598.                         fprintf(stderr,"\nEncoding error. The minimum depth of an encodeable OID is 2. (e.g. 2.999)\n");
  599.                         return 5;
  600.                 }
  601.  
  602.                 if ( fOutName != NULL ) {
  603.                         fOut = fopen( fOutName, "wt" );
  604.                         if ( fOut == NULL ) {
  605.                                 fprintf(stderr,"Unable to open output file %s\n", fOutName );
  606.                                 return 33;
  607.                         }
  608.                 } else {
  609.                         fOut = stdout;
  610.                 }
  611.  
  612.                 if ( nCHex ) {
  613.                         fprintf(fOut,"\"\\x%02X\\x%02X", cl | 6, nBinary );
  614.                 } else {
  615.                         fprintf(fOut,"%02X %02X ", cl | 6, nBinary );
  616.                 }
  617.                 nn = 0;
  618.                 while ( nn < nBinary ) {
  619.                         unsigned char b = abBinary[nn++];
  620.                         if ( nn == nBinary ) {
  621.                                 if ( nCHex ) {
  622.                                         fprintf(fOut,"\\x%02X\"\n", b );
  623.                                 } else {
  624.                                         fprintf(fOut,"%02X\n", b );
  625.                                 }
  626.                         } else {
  627.                                 if ( nCHex ) {
  628.                                         fprintf(fOut,"\\x%02X", b );
  629.                                 } else {
  630.                                         fprintf(fOut,"%02X ", b );
  631.                                 }
  632.                         }
  633.                 }
  634.                 if ( fOut != stdout ) {
  635.                         fclose( fOut );
  636.                 }
  637.                 break;
  638.         }
  639.  
  640.         return 0;
  641. }
  642.  
  643. /* */
  644.  
  645.