Portable Unformatted Input/Output

Normally, unformatted input/output is not portable between different machine architectures because of differences in the way various machines represent binary data. However, it is possible to produce binary files that are portable by specifying the XDR keyword with the OPEN procedures. XDR (for eXternal Data Representation) is a scheme under which all binary data is written using a standard "canonical" representation. All machines supporting XDR understand this standard representation and have the ability to convert between it and their own internal representation.

XDR represents a compromise between the extremes of unformatted and formatted input/output:

XDR Considerations

The primary differences in the way IDL input/output procedures work with XDR files, as opposed to files opened normally are as follows:

IDL XDR Conventions for Programmers

IDL uses certain conventions for reading and writing XDR files. If your only use of XDR is through IDL, you do not need to be concerned about these conventions because IDL takes care of it for you. However, programmers who want to create IDL-compatible XDR files from other languages need to know the actual XDR routines used by IDL for various data types. The following table summarizes this information.

Table 18-13: XDR Routines Used by IDL

Data Type
XDR routine

Byte

xdr_bytes()

Integer

xdr_short()

Long

xdr_long()

Float

xdr_float()

Double

xdr_double()

Complex

xdr_complex()

String

xdr_counted_string()

Double Complex

xdr_dcomplex()

Unsigned Integer

xdr_u_short()

Unsigned Long

xdr_u_long()

64-bit Integer

xdr_long_long_t()

Unsigned 64-bit Integer

xdr_u_long_long_t()

The routines used for type COMPLEX, DCOMPLEX, and STRING are not primitive XDR routines. Their definitions are as follows:

bool_t xdr_complex(xdrs, p) 
     XDR *xdrs; 
     struct complex { float r, i} *p; 
{ 
  return(xdr_float(xdrs, (char *) &p->r) && 
         xdr_float(xdrs, (char *) &p->i)); 
} 
bool_t xdr_dcomplex(xdrs, p) 
     XDR *xdrs; 
     struct dcomplex { double r, i} *p; 
{ 
  return(xdr_double(xdrs, (char *) &p->r) && 
         xdr_double(xdrs, (char *) &p->i)); 
} 
bool_t xdr_counted_string(xdrs, p) 
     XDR *xdrs; 
     char **p; 
{ 
  int input = (xdrs->x_op == XDR_DECODE); 
  short length; 
 
  /* If writing, obtain the length */ 
  if (!input) length = strlen(*p); 
 
  /* Transfer the string length */ 
  if (!xdr_short(xdrs, (char *) &length)) return(FALSE); 
 
  /* If reading, obtain room for the string */ 
  if (input) 
  { 
      *p = malloc((unsigned) (length + 1)); 
         *p[length] = '\0'; /* Null termination */ 
  } 
  /* If the string length is nonzero, transfer it */ 
  return(length ? xdr_string(xdrs, p, length) : TRUE); 
} 

Example: Reading C-Generated XDR Data with IDL

The following C program produces a file containing different types of data using XDR. The usual error checking is omitted for the sake of brevity.

#include <stdio.h> 
#include <rpc/rpc.h> 
[ xdr_complex() and xdr_counted_string() included here ] 
 
main() 
{ 
   static struct {      /* Output data */ 
        unsigned char c; 
        short s; 
        long l; 
        float f; 
        double d; 
        struct complex { float r, i } cmp;  
        char *str; 
    } 
    data = {1, 2, 3, 4, 5.0, { 6.0, 7.0}, "Hello" }; 
    u_int c_len = sizeof(unsigned char); /* Length of a char */ 
    char *c_data = (char *) &data.c;     /* Addr of byte field */ 
    FILE *outfile;                       /* stdio stream ptr */ 
    XDR xdrs;                            /* XDR handle */ 
 
   /* Open stdio stream and XDR handle */ 
    outfile = fopen("data.dat", "w"); 
    xdrstdio_create(&xdrs, outfile, XDR_ENCODE); 
 
/* Output the data */ 
    (void) xdr_bytes(&xdrs, &c_data, &c_len, c_len); 
    (void) xdr_short(&xdrs, (char *) &data.s); 
    (void) xdr_long(&xdrs, (char *) &data.l); 
    (void) xdr_float(&xdrs, (char *) &data.f); 
    (void) xdr_double(&xdrs, (char *) &data.d); 
    (void) xdr_complex(&xdrs, (char *) &data.cmp); 
    (void) xdr_counted_string(&xdrs, &data.str); 
 
/* Close XDR handle and stdio stream */ 
    xdr_destroy(&xdrs); 
    (void) fclose(outfile); 
} 

Running this program creates the file data.dat containing the XDR data. The following IDL statements can be used to read this file and print its contents:

;Create structure containing correct types. 
DATA={S, C:0B, S:0, L:0L, F:0.0, D:0.0D, CMP:COMPLEX(0), STR:''} 
 
;Open the file for input. 
OPENR, /XDR, 1, 'data.dat' 
 
;Read the data. 
READU, 1, DATA 
 
;Close the file. 
CLOSE, 1 
 
;Show the results. 
PRINT, DATA 

Executing these IDL statements produces the output:

{   1       2           3      4.00000       5.0000000 
(      6.00000,      7.00000) Hello} 

For further details about XDR, consult the XDR documentation for your machine. Sun users should consult their Network Programming manual.