FLUC Byte interface

The byte interface (access method) is based on the  element interface of FLUC and allows sequential bytewise access to original data sets as is commonly used with file-I/O in the PC world (fread, fwrite (C) or via stream classes (Java, C#, C++)). With this, all conversion options of FLAM at reading and writing original data are available. This means, for example, that you can transparently read bytewise UTF-16LE data with 0x0A00 as delimiter, even if the data come from a member of a concatenated GZIP file that is encrypted and BASE64-encoded, residing on a local disk or a foreign system (Cloud/HOST/DMZ), and the plain text of which is Latin1-encoded and 0x0D0A-terminated.

 The byte interface is provided for JavaEE and similar environments as a stream class, also via the network through our FLIES server (Remote Procedure Call). By this, it is possible to read within a webserver a FLAM4FILE as a normal stream over the network even though it resides on a mainframe and is and remains record-formatted. For implementing this securely a second FLIES server would normally be required as a gateway to connect the webserver with the main system (FLIES server as end node).

Generally speaking, youcan read from a host any kind of data sets (PS, PDS, PDSE, VSAM, FB, VB with and w/o ASA or machine control characters) and obtain the its records in the desired character set and the pertaining delimiters as a bytestream. Therefore, classical record-oriented host data sets can be read like normal sequential byte-oriented files.

The byte interface always transforms texts (format.text()) in the system-specific character set unless a particular character is specified (e.g. format.text(encoding='IBM1141')) which would be needed, for example, when comparing the data with string constants. Hence, the byte interface is a platform-independent interface for accessing files of any kind and format.

When characters are converted to the system-specific character set subject to the environment variable LANG, reading under Windows may yield Latin-1 with 0x0A as delimiter. Under UNIX it would mostly be UTF-8 with 0x0A an on a mainframe, for example, IBM1047 with 0x15. This illustrates how the byte interface transforms the Windows delimiter 0x0D0A to memory as 0x0A (format.text()) to allow string processing with no platform dependencies. Only when writing text data to disk (write.text()) the Windows-specific 0x0D0A is inserted.

Beside byte-oriented reading and writing texts (format.text()), binary data (format.binary()) and character streams (format.char()), this interface also supports sequential reading and writing of records (format.record()). Behaviour here is like that of z/OS runtime-environment (type=record). There are, however, a few subtile differences: when reading or writing FBA or VBA records one can choose between leaving ASA or machine control characters (RETAIN), ignoring them (DETACH (default)), or processing them as with printing (RPLFFD=26). With relative files you can cause a gap to be passed as an empty record or nothing to be passed. In addition, here, too, character sets can be converted. You have options for removing trailing whitespace,  processing control characters, and many more. By setting the 'size' parameter, records are truncated at buffer overflow (size > 0) or an overflow error is signalled (size = 0), allowing for repeated reading with a larger buffer.

Additional you can also read or write FLAM5 elements like records in form of a certain struture with format.element(). In this case you can overload the default converter by a deticated converter for each element. This feature allows you to validate, collapse and or convert XML elements in programming language specific data types. If you know, the next data element must contain a decimal number as string, then you can convert this XML string to an integer value for some calculations. 

When reading an FB file under Java previously fixed records can turn variable during UTF-8 conversion because of multibyte characters (ü, ä, ö, ß, ...). In this situation it is important to know the original record length. This can be assured either by delimiters (stream-oriented) or by record-lengths (record-oriented). However, such data can still be processed as fixed-length format by choosing a single or multibyte character set with fixed width (e.g. UCS-16 or UTF-32).

The byte interface lets you decide freely how the data are read and in what way they are to be presented.

 

Examples

C

The following example in C just reads a member, 'test.txt', in records from a FLAMFILE (dat.adc) - created in EBCDIC on an IBM mainframe - and writes it as UTF-16LE-text with 0x0D000A00 as delimiters into a normal binary file.

static int uiReadFlamFile(void)
{
   unsigned int       uiLen;
   void*                  pvRed=NULL;
   FILE*                 pfWrt=NULL;
   unsigned char    acBuf;

   pvRed=fcbopen("read.flam(file='dat.adc/?test.bin'"
                 " encoding='IBM1141')",
                 "format.txt(method=CRLF" 
                 " encoding='UTF-16LE')");
   if (pvRed==NULL || fcberrno) {
      printf("ERRMSG: %d - %s\n",fcberrno,fcberrms());
      printf("ERRTRC:\n%s\n",fcberrtr());
      return(-1);
   }
   pfWrt=fopen("test.txt","wb");
   if (pfWrt==NULL || errno) {
      printf("ERRMSG: %d - %s\n",errno,errormsg(errno))
      return(-1);
   }
   uiLen=fcbread(acBuf,1,sizeof(acBuf),pvRed);
   while(uiLen && fbcerrno==0) {
      fwrite(acBuf,1,uiLen,pfWrt);
      uiLen=fcbread(acBuf,1,sizeof(acBuf),pvRed);
   }
   if (pvRed!=NULL) fcbclose(pvRed);
   if (pfWrt!=NULL) fclose(pfWrt);
   return(0);
}

C++

For C++, the class flcbyt_buffer (FLCBYTBF) is available. It allows to use the byte interface via the C++ stream API:

void readFlamFile() {
   flcbyt_buffer rbuf(
      "read.flam(file='dat.adc/?test.bin' encoding='IBM1141')",
      "format.txt(method=CRLF encoding='UTF-16LE')");
   flcbyt_buffer wbuf("write.bin(file='test.txt')",
                 "format.bin()");
   std::istream in(&rbuf);
   std::ostream out(&wbuf);

   char buf[1024];

   while(in) {
      in.read(buf, 1024);
      if (!in.eof() && in.fail()) {
         std::cout << "read failed" << std::endl;
         break;
      }
      out.write(buf, in.gcount());
      if (out.fail()) {
         std::cout << "write failed" << std::endl;
         break;
      }
   }
   std::cout << wbuf.close() << std::endl;
}

Java

The following Java example implements the same functinality as the C example. But here the FLIES server is used which is running on the local system:

private void readFlamFile() throws IOException {
   InputStream flamIn = new BufferedInputStream(
      new FlamInputStream("127.0.0.1", 17996,
      "read.flam(file='dat.adc/?test.bin'"
      +" encoding='IBM1141')",
      "format.txt(method=CRLF encoding='UTF-16LE')"));
   OutputStream fileOut = new BufferedOutputStream(
      new FileOutputStream("test.txt"));
   byte[] buffer = new byte[4096];
   int len;

   try {
      while ((len = flamIn.read(buffer)) != -1)
         fileOut.write(buffer, 0, len);
   } finally {
      if (flamIn != null)
         flamIn.close();
      if (fileOut != null)
         fileOut.close();
   }
}

If nothing is specified with "format.text()", data are by default output as text stream in the respective platform-specific character set and the appropriate delimiters. This allows using identical code without changes on different platforms, and no matter on what platform the example's FLAMFILE resides, reading would always work properly.

For additional information please refer to the interface specification in the Download area.