/*****************************************************************************
* Copyright 1996-2013 United States Government as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All Rights Reserved.
******************************************************************************/

import java.io.*;
import java.text.*;
import java.util.*;
import java.lang.*;
import java.lang.reflect.*;
import java.math.*;
import gsfc.nssdc.cdf.*;
import gsfc.nssdc.cdf.util.*;
import javax.json.*;

/****************************************************************************
  Description:
    This program exports the contents of a CDF file(s) into a Json file
 
    For single CDF file, the file is specified at the last of the auguments. 
    The name of the input CDF file is used as the default output file name.
    Alternatively, use "fileNames" option to specify the CDf file(s) for
    conversions.

  Usage: java CDF2Json [Options] [cdfFileName] 
 
  Options: 
 
     -fileNames:fileNames
         fileNames: specifies a text file that contains the names of CDF files
                    for converting into a single Json file.
		    If this option is used, there is no need for entering
		    cdfFileName
 
     -globalAttrs:[yes | no]   yes is the default.
         -globalAttrs:yes extracts all global attributes
         -globalAttrs:no doesn't extract global attributes
 
     -varAttrs:[yes | no]   yes is the default.
         -varAttrs:yes extracts each variable's attributes
         -varAttrs:no doesn't extract each variable's attributes
 
     -entryDataType:[yes | no]  no is the default.
        [ N/A if globalAttrs and varAttrs is no ]
        When globalAttr or varAttr is yes, attribute entry data is extracted and
         -entryDataType:yes extracts entry's non-char data type
         -entryDataType:no doesn't extract entry's data type
        This is new option. Json file with entry's data type will not be handled
        by older Json2CDF program.
 
     -vars:var1,var2,... 
         -vars:var1,var2,... extracts only the specified variables with
                             variable names separated by a single comma
 
     -varData:[yes | nrv | no]   no is the default.
         -varData:yes outputs all variables' data
         -varData:nrv outputs only non-record varying (nrv) variables' data
         -varData:no  doesn't output any variable's data
 
     -8bytestostr:[yes | no]   no is the default.
         -8bytestostr:yes Outputs the 8-byte data, CDF_INT8 or 
                          CDF_DOUBLE|REAL8, to a string
         -8bytestostr:no  Outputs the 8-byte data as it.
         If the 8-byte data is too big, it can cause an issue for other
         program that can't handle such large value. Also, Java can't handle
         a large double value properly - missing precision or some sort,
 
     -output:[outputFileName | STDOUT]
         outputFileName: The output Json file name. An extension of ".json"
                         is appended if it is not specified. If this option is
                         not specified, the input cdfFileName for a single file
                         or fileNmaes for a group of files is used for the
                         output Json file  name.
         -output:STDOUT displays the Json output on the screen.
 
     -format:[yes | no | prefer]   prefer is the default.
         -format:yes uses the variable's FORMAT attribute to encode the data
         -format:prefer uses the variable's FORMAT attribute to encode the data
                        However, if the FORMAT is not properly defined, it is
                        not used.
         -format:no  uses the general Java data encoding form

     -encodeepoch:[yes | no]   yes is the default.
         -encodeepoch:yes encodes the CDF epoch data
         -encodeepoch:no  shows the CDF epoch data in its original form

     -[showProgress | Progress]
         This option displays the processing progress on the screen.  
         It shows how many CDF variables are there to process and which
         variable is being processed.
 
     -withZ
         This option works with CDF epoch data by adding an extra "Z" to
         the end of date/time of ISO 8601 form.

     -delete
         Over-ride the existing Json file.

     -debug
         Display the specifications to run the application. 

     -nofullpath
         Specifies to use only the file name portion of the entered path name 
         for each CDF in the Json file.

     -showfile
         Specifies to display the CDF file name(s) being processed. 

 The Json file, produced from CDF2Json class, has the following form. It 
 differs slightly from the origial converter, which only handled a single
 CDF. The CDFname is a part in CDFFileInfo attribute. 

 <PRE> 
 CDFname1:    <== CDF file name key
   CDFFileInfo:
     FileVersion:.....
     Format:.....
     Majority:...
     Encoding:.....
   CDFglobalAttributes:
     Gattr_name1:
       entry#:value
       ...
       ...
     Gattr_name2:
       entry#:value
       ...
       ...
   ...
   ...
   CDFVariables:
     VarName1:  <== Variable name key
       VarDescription:
         DataType:....
         ...
         ...
       VarAttributes:
         VALIDMIN:.... or, VALIDMIN: DataType:... Value:.....
         VALIDMAX:.... or, VALIDMAX: DataTYpe:... Value:.....
         ...
         ...
       VarData:
       ...
     VarName2:
       VarDescription:
         DataType:....
         ...
         ...
       VarAttributes:
         VALIDMIN:....
         VALIDMAX:....
         ...
         ...
       VarData:
         ...
   EmptyAttributes:  <== Exists if there are defined attributes but no values
     GlobalAttributes: [...]
     VariableAttributes: [...]

 CDFname2:
   ...
   ...
 ... 
 ...
 </PRE> 

 This class is based on JNI-based cdfjava.jar and javax.json.jar.
 
 HISTORY:
      Jan 30, 2022     Mike Liu         Initial version.
      Jan 15, 2025     Mike Liu         Modified to use CDFData's 1D raw data,
                                        instead of multi-dimension data.
 *****************************************************************************/

public class CDF2Json implements CDFConstants {

    private static CDF cdf = null;
    private static boolean  debug = false;

    private static String  inFile = null,      /* Input file name            */
                           outFile = null,     /* Output file name           */
                           varData = "no",     /* Extract variable data      */
                           globalAttrs = "yes",/* Extract global attributes  */
                           format = "prefer",  /* Use FORMAT attribute       */
                           encodeEpoch = "yes",/* Encode epoch data */
                           varAttrs = "yes",   /* Extract variable attributes*/
                           attrEntryDT = "no", /* Extract attribute entry's */
                                               /* data type */
                           int8tostr = "no";   /* Convert entry of CDF_INT8 */
                                               /* data type's value to string*/

    private static boolean showProgress = false;
    private static boolean withz = false;
    private static boolean delete = false;
    private static boolean fullpath = true;
    private static boolean encodeEp = true;
    private static boolean showfile = false;
    private static JsonObjectBuilder CDFJsonObject0 = Json.createObjectBuilder();
    private static JsonObjectBuilder CDFJsonObject = null;
    private static int varCount = -1;
    private static String[] varNames;
    private static String[] fileNames = null;
    private static int numFiles = 0;
    private static String item0 = "CDF";
    private static String item1 = "CDFFileInfo";
    private static String item2 = "CDFglobalAttributes";
    private static String item3 = "CDFVariables";
    private static String item4 = "VarDescription";
    private static String item5 = "VarAttributes";
    private static String item6 = "VarData";
    private static String item7 = "EmptyAttributes";
    private static String item8 = "GlobalAttributes";
    private static String item9 = "VariableAttributes";
    private static String separator = System.getProperty("file.separator");
    private static int toshow = 0;

    public static void main(String[] args) throws Exception {

        try {
            parseCmdLine(args);

            if (outFile == null) 
                outFile = getDefaultOutputFileName();

            if (!delete) {
                if (new File(outFile).exists()) {
                    System.out.println("ERROR... output file:"+outFile+
                                       " already exists. ");
                    System.exit(1);
                }
            }
            int ix;
            for (ix = 0; ix < numFiles; ++ix) {
              String originalInputFilename = fileNames[ix];
              if (showfile) System.out.println(fileNames[ix]);
              cdf = CDF.open(originalInputFilename, READONLYoff);

              CDFJsonObject = Json.createObjectBuilder();
              JsonArrayBuilder two = printCDFFileInfo(originalInputFilename);
              if (two != null) {
                CDFJsonObject.add (item1, two);
                two = null;
              }

              if (globalAttrs.equals("yes")) {
                JsonArrayBuilder three = printGlobalAttributes();
              if (three != null) {
                CDFJsonObject.add (item2, three);
                three = null;
              }

              JsonArrayBuilder four = printVariables();
              if (four != null) {
                CDFJsonObject.add (item3, four);
                four = null;
              }

              JsonArrayBuilder five = printEmptyAttributes();
              if (five != null)
                CDFJsonObject.add (item7, five);
                five = null;
              }

              cdf.close();

              String cdfnameKey = null;
              if (fullpath)
                cdfnameKey = (!originalInputFilename.endsWith(".cdf") &&
                              !originalInputFilename.endsWith(".CDF")) ?
                              originalInputFilename+".cdf" :
                              originalInputFilename;
              else {
                int loc = originalInputFilename.lastIndexOf(separator);
                if (loc == -1) 
                  cdfnameKey = (!originalInputFilename.endsWith(".cdf") &&
                              !originalInputFilename.endsWith(".CDF")) ?
                              originalInputFilename+".cdf" :
                              originalInputFilename;
                else {
                  String filenamex = originalInputFilename.substring(loc+1);
                  cdfnameKey = (!filenamex.endsWith(".cdf") &&
                                !filenamex.endsWith(".CDF")) ?
                                filenamex+".cdf" : filenamex;
                }
              } 
              CDFJsonObject0.add (cdfnameKey, CDFJsonObject);
            }
            OutputStream os = new FileOutputStream(outFile);
            JsonWriter jsonWriter = Json.createWriter(os);
            jsonWriter.writeObject(CDFJsonObject0.build());
            jsonWriter.close();

        } catch (Exception e) {
            if (cdf != null) cdf.close();
            System.out.println ("Exception occurred in main.\n"+e);
        }
    }


    /*********************************************************/
    /*  Parse the command line input that is in the form of  */
    /*     java CDF2Json [Options] cdfFileName               */
    /*                                                       */
    /*  See the top of this file for a detailed description  */
    /*  of the Options.                                      */
    /*********************************************************/
    private static void parseCmdLine (String[] args) {
        String numSpaces = null;
        int which = 0;
        String[] tmpArr = new String[100];

        if (args.length == 0) { // No input is given (i.e. java CDF2Json)
            usage();
            exit("");
        } else {                  // Process options
            for (int i=0; i < args.length; i++) {
                 if (args[i].indexOf(":") == -1 && 
                     args[i].charAt(0) != '-') {
                     if (which == 0) which = 1;
                     if (which == 1) {
                       tmpArr[numFiles] = args[i];
                       ++numFiles;
                       if (!CDFUtils.cdfFileExists(args[i])) { 
                         System.out.println ("** Error: file '"+args[i]+
                                             "' does not exist **");
                         System.exit (1); 
		       }
                       if (numFiles == 1) inFile = args[i];
		       continue;
                     } else {
                       System.out.println("** Error: File(s) already specified"+
                                          " in option \"fileNames\"...");
		       System.exit(1);
                     }
                 }
                 int loc = args[i].indexOf(":");
                 if (args[i].toLowerCase().startsWith("-filenames:")) {
                       if (which == 0) which = 2;
                       if (which == 2) {
			 String fileTxt = args[i].substring(loc+1);
                         if (fileTxt.toLowerCase().endsWith(".txt"))
                           inFile = fileTxt.substring(0, fileTxt.length()-4);
                         else if (fileTxt.toLowerCase().endsWith(".text"))
                           inFile = fileTxt.substring(0, fileTxt.length()-5);
                         else
                           inFile = fileTxt;
			 readFileNames (fileTxt);
                       } else {
                         System.out.println("** Error: File(s) already "+
                                            "specified in the command line...");
		         System.exit(1);
                       }
                 }
                 else if (args[i].toLowerCase().startsWith("-vardata:")) {
                         varData = args[i].substring(loc+1).toLowerCase();
                         if (!varData.equals("yes") && 
                             !varData.equals("nrv") && 
                             !varData.equals("no")) 
                            exit("** Error: Invalid \"-varData:"+varData+
                                 "\" entered. **\n"); 
                 }
                 else if (args[i].toLowerCase().startsWith("-globalattrs:")) {
                         globalAttrs = args[i].substring(loc+1).toLowerCase();
                         if (!globalAttrs.equals("yes") &&
                             !globalAttrs.equals("no"))
                            exit("** Error: Invalid \"-globalattrs :"+
                                 globalAttrs+"\" entered. **\n");
                 }
                 else if (args[i].toLowerCase().startsWith("-varattrs:")) {
                         varAttrs = args[i].substring(loc+1).toLowerCase();
                         if (!varAttrs.equals("yes") &&
                             !varAttrs.equals("no"))
                            exit("** Error: Invalid \"-varattrs:"+varAttrs+
                                 "\" entered. **\n");
                 }
                 else if (args[i].toLowerCase().
                                  startsWith("-entrydatatype:")) {
                         attrEntryDT = args[i].substring(loc+1).toLowerCase();
                         if (!attrEntryDT.equals("yes") &&
                             !attrEntryDT.equals("no"))
                            exit("** Error: Invalid \"-entrydatatype:"+
                                 attrEntryDT+"\" entered. **\n");
                 }
                 else if (args[i].toLowerCase().
                                  startsWith("-8bytestostr:")) {
                         int8tostr = args[i].substring(loc+1).toLowerCase();
                         if (!int8tostr.equals("yes") &&
                             !int8tostr.equals("no"))
                            exit("** Error: Invalid \"-8bytestostr:"+int8tostr+
                                 "\" entered. **i\n");
                 }
                 else if (args[i].toLowerCase().startsWith("-format:")) {
                         format = args[i].substring(loc+1).toLowerCase();
                         if (!format.equals("yes") &&
                             !format.equals("no") &&
                             !format.equals("prefer"))
                            exit("** Error: Invalid \"-format:"+format+
                                 "\" entered. **\n");
                 }
                 else if (args[i].toLowerCase().startsWith("-encodeepoch:")) {
                         encodeEpoch = args[i].substring(loc+1).toLowerCase();
                         if (!encodeEpoch.equals("yes") &&
                             !encodeEpoch.equals("no"))
                            exit("** Error: Invalid \"-encodeepoch:"+
                                 encodeEpoch+"\" entered. \n**");
                         else {
                           if (encodeEpoch.equals("no"))
                             encodeEp = false;
                         }
                 }
                 else if (args[i].toLowerCase().startsWith("-vars:")) {
                         String names = args[i].substring(6);
                         int e;
                         varCount = 1;
                         for (e = 0; e < names.length(); e++) {
                           if (names.charAt(e) == ',') varCount++;
                         }
                         varNames = new String[varCount];
                         StringBuffer tmp = new StringBuffer(names);
                         for (e = 0; e < varCount; ++e) {
                            int dstr = tmp.indexOf(",");
                            if (dstr != -1) {
                              varNames[e] = tmp.substring(0, dstr).toString();
                              tmp = new StringBuffer(tmp.substring(dstr+1));
                            } else {
                              varNames[e] = new String(tmp);
                            }
                         }
                 }
                 else if (args[i].toLowerCase().startsWith("-output:") ||
                          args[i].toLowerCase().startsWith("-json:")) {
                         outFile = args[i].substring(loc+1);
                         if (outFile.equalsIgnoreCase("stdout"))
                             outFile = "STDOUT";
                         else { 
                             if (!outFile.toLowerCase().endsWith(".json"))
                                 outFile = outFile + ".json";
                         }
                 }
                 else if (args[i].equalsIgnoreCase("-showprogress") ||
                              args[i].equalsIgnoreCase("-progress")) {
                         showProgress = true;
                 }
                 else if (args[i].equalsIgnoreCase("-withz")) {
                         withz = true;
                 }
                 else if (args[i].toLowerCase().startsWith("-debug")) {
                         debug = true;
                 }
                 else if (args[i].equalsIgnoreCase("-delete")) {
                         delete = true;
                 }
                 else if (args[i].equalsIgnoreCase("-nofullpath")) {
                         fullpath = false;
                 }
                 else if (args[i].equalsIgnoreCase("-showfile")) {
                         showfile = true;
                 }
                 else {
                    System.out.println ("** Error: Invalid/missing option"+
                          " entered for \""+args[i]+"\" \n"+
                          "   Use \"java CDF2Json\" to read the help "+
                          "information.\n");
                    System.exit(1);
                 }
            }
        }
        if (debug) {
            for (int i=0; i < args.length; i++)
                 System.out.println ("args["+i+"] = "+args[i]);
            System.out.println ("inFile="+inFile+", outputFile="+outFile+
                                ", globalattrs= "+globalAttrs+ 
                                ", varAttrs= "+varAttrs+ 
                                ", attrentrydatetype= "+attrEntryDT+ 
                                ", 8bytestostr= "+int8tostr+ 
                                ", vars= all"+
                                ", vardata= "+varData+ 
                                ", showProgress="+showProgress+
                                ", withz="+withz+
                                ", showfile="+showfile+
                                ", delete="+delete);
        }

        if (inFile == null) exit ("** Error: CDF file name not specified **");

        if (which == 1) {
          fileNames = new String[numFiles];
          System.arraycopy(tmpArr, 0, fileNames, 0, numFiles);
        } 
        
    }


    /************************************************************************
     *  If a compression is specified, print the compression type and its
     *  compression level.  The compression level is printed only if
     *  the compression method is GZIP.
     ************************************************************************/
    private static String printCompression (long cType,
                                            long[] compressionLevel) {
        if (cType != CDFConstants.NO_COMPRESSION) {
          String compression = CDFUtils.getStringCompressionType(cType);
          if (cType != CDFConstants.GZIP_COMPRESSION)
            return compression;
          else
            return compression+"."+compressionLevel[0];
        } else
          return null;
    }


    /************************************/
    /*  Print the CDF file information  */
    /************************************/
    private static JsonArrayBuilder printCDFFileInfo (String theFile) {
        try {
          String version = cdf.getVersion();
          String fileFormat = CDFUtils.getStringFormat(cdf);
          String majority = CDFUtils.getStringMajority(cdf);
          String encoding = CDFUtils.getStringEncoding(cdf);
          String checksum = CDFUtils.getStringChecksum(cdf);
          long lastUpdated = CDFUtils.getLeapSecondLastUpdated(cdf);

          JsonArrayBuilder infos = Json.createArrayBuilder();

          JsonObjectBuilder versionO = Json.createObjectBuilder().
                                                  add("FileVersion", version);
          infos.add(versionO.build());
          
          JsonObjectBuilder formatx = Json.createObjectBuilder().add("Format",
                                                                    fileFormat);
          infos.add(formatx.build());

          long   cType = cdf.getCompressionType();
          long[] compressionLevel = cdf.getCompressionParms();
          String comp = printCompression(cType, compressionLevel);
          if (comp != null) {
            JsonObjectBuilder compress = Json.createObjectBuilder().
                                                    add("Compression", comp);
            infos.add(compress.build());
          }

          JsonObjectBuilder majorityO = Json.createObjectBuilder().
                                                   add("Majority", majority);
          infos.add(majorityO.build());

          JsonObjectBuilder encodingO = Json.createObjectBuilder().
                                                   add("Encoding", encoding);
          infos.add(encodingO.build());

	  if (!checksum.toLowerCase().equals("none")) {
            JsonObjectBuilder chksum = Json.createObjectBuilder().
                                                    add("checksum", checksum);
            infos.add(chksum.build());
          }

          if (lastUpdated > -1) {
              long yy, mm, dd;
              yy = (long) (lastUpdated / 10000);
              mm = (long) ((lastUpdated - yy * 10000) / 100);
              dd = lastUpdated - yy * 10000 - mm * 100;
              JsonObjectBuilder leap = Json.createObjectBuilder().add(
                                       "LeapsecondLastUpdated",yy+"-"+
                                       (mm<10?"0":"")+mm+"-"+(dd<10?"0":"")+dd);
              infos.add(leap.build());
          }

          return infos;

      } catch (Exception e) {
          System.out.println ("** Error occurred in printCDFFileInfo");
          System.out.println (e);
          System.exit (1);
      }
      return null;
    }


    /*************************************/
    /*  Print the CDF global attributes  */
    /*************************************/
    private static JsonArrayBuilder printGlobalAttributes () {
        try {
            Attribute a = null;
            String    attrName = null;
            int       i;
            long      numAttrs = cdf.getNumGattrs();
            Vector    ga = cdf.getGlobalAttributes();

            if (numAttrs > 0) {
                JsonArrayBuilder entries = Json.createArrayBuilder();
                JsonArrayBuilder globals = Json.createArrayBuilder();
                for (Enumeration e = ga.elements() ; e.hasMoreElements() ;) {
                    a = (Attribute) e.nextElement();
                    attrName = a.getName();
                    long n   = a.getNumEntries();
                    if (n == 0) continue;
                    Vector ent = a.getEntries();
                    for (Enumeration e1=ent.elements(); e1.hasMoreElements();) {
                       Entry entry = (Entry) e1.nextElement();
                       if (entry != null) {
                         long eDataType = entry.getDataType();
                         long eNumElems = entry.getNumElements();
                         Object data = entry.getData();
                         String entryID = String.valueOf(entry.getID());
                         if (attrEntryDT.equals("no") ||
                             eDataType == CDF_CHAR || eDataType == CDF_UCHAR) {
                          JsonObjectBuilder entryO = Json.createObjectBuilder();
                          entryO = (JsonObjectBuilder) printSingleData (
                                               (Object)entryO, entryID, data,
                                               eDataType, eNumElems, -1,
                                               (withz?"Z":""), null, null,
                                               false);
                          entries.add (entryO.build());
                         } else {
                           JsonArrayBuilder infos = printAttrEntryInfo (
                                                      eDataType, eNumElems,
                                                      data, -1, null, null);
                           if (infos != null)
                             entries.add (Json.createObjectBuilder().
                                          add(entryID, infos).build());
                         }
                      }
                    }
                    JsonObjectBuilder global1 = Json.createObjectBuilder().
                                                     add(attrName, entries);
                    globals.add(global1.build());
                }
                return globals;
            }

        } catch (Exception e) {
            System.out.println ("** Error occurred in printGlobalAttributes");
            System.out.println (e);
            System.exit (1);
        }
        return null;
    }


    /*************************************************************************  
     *  Print the following information for each variable in a CDF file:
     *    - variable information (e.g. dimensionality, dimesnion sizes, etc.)
     *    - variable attributes
     *    - variable data
     ************************************************************************/
    private static JsonArrayBuilder printVariables () {

        long numVars = 0;
        Variable v = null;

        try {
            int i = 1;
            numVars = cdf.getNumVars();

            if (numVars > 0) {
               JsonArrayBuilder variables = Json.createArrayBuilder();

               Vector  vars = cdf.getVariables();
               String cFormat = null;

               for (Enumeration e = vars.elements() ; e.hasMoreElements() ;) {
                   v = (Variable) e.nextElement();
                   String varName = v.getName();
                   Object fillVal = null;
                   if (!format.toLowerCase().equals("no")) {
                     String formatA;
                     try {
                       String format0 = (String) v.getEntryData("FORMAT");
                       if (format0.trim().length() == 0) formatA = null;
                       else formatA = format0.trim();
                     } catch (CDFException xx) {
                       formatA = null;
                     }
                     if (formatA != null) cFormat = toCformat(formatA);
                   }
                   try {
                     fillVal = v.getEntryData("FILLVAL");
                   } catch (CDFException xx) {
                     try {
                       fillVal = v.getPadValue();
                     } catch (CDFException xy) {
                       fillVal = null;
                     }
                   }
                   boolean toPrint = true;
                   if (varCount > 0) {
                     toPrint = false;
                     for (int jj = 0; jj < varCount; ++jj) {
                       if (varName.equals(varNames[jj])) {
                         toPrint = true;
                         break;
                       }
                     }
                   }
                   if (toPrint) {
                     if (showProgress) {
                       long maxRec = v.getMaxWrittenRecord() + 1;
                       System.out.print ("Variable "+i+": "+varName+" of "+
                                         (varCount>0?varCount:numVars)+
                                         " ("+(maxRec<10?" ":"")+maxRec+
                                         " record(s)): ");
                       i++;
                     }

                     JsonArrayBuilder variable = Json.createArrayBuilder();
                     JsonObjectBuilder variableO = Json.createObjectBuilder();
                     JsonArrayBuilder one = printVarInfo(v, cFormat);
                     if (one != null) {
                       variable.add(Json.createObjectBuilder().
                                           add(item4, one).build());
                       one = null;
                     }

                     if (varAttrs.equals("yes")) {
                       JsonArrayBuilder two = printVarAttributes(v, cFormat,
                                                                 fillVal);
                       if (two != null) {
                         variable.add(Json.createObjectBuilder().
                                             add(item5, two).build());
                         two = null;
                       }
                     }

                     if (varData.equals("yes") ||
                         (varData.equals("nrv") &&
                          !(v.getRecVariance()))) {
                       JsonArrayBuilder three = printVarData(v, cFormat,
                                                             fillVal);
                       if (three != null) {
                         variable.add(Json.createObjectBuilder().
                                             add(item6, three).build());
                         three = null;
                       }
                     }

                     variableO.add(varName, variable);
                     variables.add(variableO);
                     variable = null;
                     variableO = null;
                   }
               }
               return variables;
            }

        } catch (Exception e) {
            System.out.println ("** Error occurred in printVariables");
            System.out.println ("** # of variables: "+numVars);
            System.out.println ("** variable: "+v.getName());
            System.out.println (e);
            System.exit (1);
        }
        return null;
    }


    /*************************************************************************
     *  Print the CDF variable information.
     ************************************************************************/
    private static JsonArrayBuilder printVarInfo (Variable v, String formatV) {
        try {
            String  recVariance, sparseRecord, variance;
            int     i;
            long    dataType, numDims, numElements, blockingFactor;
            long    numRecords, maxWrittenRec;
            long[]  dimSizes = {1L}, dimVariances;
            Object  padValue = null;
            String  varName, strDataType;

            JsonArrayBuilder infos = Json.createArrayBuilder();
            dataType         = v.getDataType();
            strDataType = CDFUtils.getStringDataType(dataType);
            JsonObjectBuilder vd = Json.createObjectBuilder().
                                        add("DataType",strDataType);
            infos.add (vd.build());
            if (showProgress) {
              if (v.getName().length() < 9)
                System.out.print ("\t\t"+strDataType+"/");
              else
                System.out.print ("\t"+strDataType+"/");
            }

            numElements      = v.getNumElements();
            JsonObjectBuilder ne = Json.createObjectBuilder().
                                        add("NumElements",numElements);
            infos.add (ne.build());
            if (showProgress) {
                System.out.print (numElements);
                if (dataType == CDF_TIME_TT2000) System.out.print ("  ");
                else System.out.print ("\t");
            }

            numDims          = v.getNumDims();
            dimSizes         = v.getDimSizes();
            dimVariances     = v.getDimVariances();

            long numDimsN;
            long[] dimSizesN = new long[(int)CDF_MAX_DIMS];
            numDimsN = 0;
            for (i = 0; i < numDims; i++) {
              if (dimVariances[i] == CDFConstants.VARY &&
                  dimSizes[i] > 1) {
                dimSizesN[(int)numDimsN] = dimSizes[i];
                ++numDimsN;
              }
            }

            JsonObjectBuilder nd = Json.createObjectBuilder().
                                        add("NumDims",numDims);
            infos.add (nd.build());
            if (showProgress)
                System.out.print (numDims+":[");
            if (numDims > 0) {
              JsonObjectBuilder ds = Json.createObjectBuilder();
              JsonArrayBuilder dsO = Json.createArrayBuilder();
              for (i=0; i < numDims; i++) {
                 if (i > 0) {
                         if (showProgress)
                             System.out.print (",");
                  }    
                  dsO.add(dimSizes[i]);
                  if (showProgress)
                      System.out.print (dimSizes[i]);
              }
              ds.add("DimSizes",dsO);
              infos.add (ds.build());
            }
            if (showProgress)
                System.out.print ("]   "+(numDims==0?" ":""));

            recVariance      = v.getRecVariance() ? "VARY" : "NOVARY";
            JsonObjectBuilder rv = Json.createObjectBuilder().
                                        add("RecVariance",recVariance);
            infos.add (rv.build());
            if (showProgress) {
                if (recVariance.equalsIgnoreCase("vary"))
                    System.out.print ("T/");
                else
                    System.out.print ("F/");
            }

            if (numDims > 0) {
              JsonObjectBuilder dv = Json.createObjectBuilder();
              JsonArrayBuilder dvO = Json.createArrayBuilder();
              for (i=0; i < numDims; i++) {
                   dvO.add("VARY");
                   if (showProgress) {
                       System.out.print ("T");
                   }
              }
              dv.add("DimVariances",dvO);
              infos.add (dv.build());
            }

            if (showProgress) System.out.println ("");

            long   cType = v.getCompressionType();
            long[] compressionLevel = v.getCompressionParms();
            String comp = printCompression (cType, compressionLevel);
            if (comp != null) {
              JsonObjectBuilder compO = Json.createObjectBuilder().
                                             add("Compression",comp);
              infos.add (compO.build());
            }
            numRecords       = v.getNumWrittenRecords();
            sparseRecord     = CDFUtils.getStringSparseRecord(v).toLowerCase();
            if (sparseRecord.equals("none")) {
                if (numRecords > 0) {		
                  JsonObjectBuilder nw = Json.createObjectBuilder().
                                              add("NumWrittenRecords",
                                                  numRecords);
                  infos.add (nw.build());
                }
            }
            else {
                maxWrittenRec   = v.getMaxWrittenRecord();
                JsonObjectBuilder sr = Json.createObjectBuilder().
                                            add("SparseRecords",sparseRecord);
                infos.add (sr.build());
                JsonObjectBuilder nw = Json.createObjectBuilder().
                                            add("NumWrittenRecords",numRecords);
                infos.add (nw.build());
                JsonObjectBuilder mw = Json.createObjectBuilder().
                                            add("MaxWrittenRec",maxWrittenRec);
                infos.add (mw.build());
            }

            if (v.checkPadValueExistence()) {    // Pad value has been defined
                JsonObjectBuilder pv = Json.createObjectBuilder();
                padValue         = v.getPadValue();
                pv = (JsonObjectBuilder) printSingleData ((Object)pv,
                                         "PadValue", padValue, dataType,
                                         numElements, -1, (withz?"Z":""),
                                         formatV, null, false);
                infos.add (pv.build());
            }

            blockingFactor   = v.getBlockingFactor();
            if (blockingFactor > 0) {
                JsonObjectBuilder bf = Json.createObjectBuilder().
                                           add("BlockingFactor",blockingFactor);
                infos.add (bf.build());
            }
            return infos;

        } catch (Exception e) {
            System.out.println ("** Error occurred in printVariables");
            System.out.println (e);
            System.exit (1);
        }
        return null;
    }


    /*************************************************************************
     *  Print the CDF variable attributes
     ************************************************************************/
    private static JsonArrayBuilder printVarAttributes (Variable v,
                                                        String formatT,
                                                        Object fillVal) {
        Attribute a = null;
        Entry entry = null;
        String    attrName = null;

        try {
            /**************************************************************
                Check and see if there are any variable attributes that
                are associated with the passed Variable.                   
             **************************************************************/
            Vector   va = v.getAttributes();
            if (va.size() == 0) return null;      
            long vDataType = v.getDataType();
            /*******************************************/
            /*  Process and print variable attributes  */
            /*******************************************/
            JsonArrayBuilder entries = Json.createArrayBuilder();
            for (Enumeration e=va.elements(); e.hasMoreElements();) {
                 a = (Attribute) e.nextElement();
                 attrName = a.getName();
                 try {
                   entry = a.getEntry(v);
                   if (entry != null) {
                      long eDataType = entry.getDataType();
                      long eNumElements = entry.getNumElements();
                      Object data = entry.getData();
                      if (attrEntryDT.equals("no") || 
                          eDataType == CDF_CHAR || eDataType == CDF_UCHAR) {
                        JsonObjectBuilder entryO = Json.createObjectBuilder();
                        entryO = (JsonObjectBuilder) printSingleData (
                                             (Object)entryO, attrName, data,
                                             eDataType, eNumElements, vDataType,
                                             (withz?"Z":""), formatT, fillVal,
                                             false);           
                        entries.add (entryO.build());
                      } else {
                        JsonArrayBuilder infos = printAttrEntryInfo (
                                                  eDataType, eNumElements,
                                                  data, vDataType, formatT,
                                                  fillVal);
                       if (infos != null)
                         entries.add (Json.createObjectBuilder().
                                        add(attrName, infos).build());
                      }
                   }
                 } catch (CDFException ex) {
                 }
            }
            return entries;


        } catch (Exception e) {
            System.out.println ("** Error occurred in printVarAttributes");
            System.out.println ("attr= "+attrName+" entry ="+entry.getName());
            System.out.println (e);
            System.exit (1);
        }
        return null;
    }


    /*************************************************************************
     *  Print the CDF variable entry information, along with its data type
     ************************************************************************/
    private static JsonArrayBuilder printAttrEntryInfo (
                                                 long dataType,
                                                 long numElements,
                                                 Object data,
                                                 long vDataType,
                                                 String formatT,
                                                 Object fillVal) {
        try {
            JsonArrayBuilder entries = Json.createArrayBuilder();
            String strDataType = CDFUtils.getStringDataType(dataType);
            JsonObjectBuilder entry0 = Json.createObjectBuilder().
                                                add("DataType",strDataType);
            entries.add (entry0.build());
            JsonObjectBuilder entry1 = Json.createObjectBuilder();
            entry1 = (JsonObjectBuilder) printSingleData (
                                           (Object)entry1, "Value", data,
                                           dataType, numElements, vDataType,
                                           (withz?"Z":""), formatT, fillVal,
                                           false);           
            entries.add (entry1.build());
            return entries;
        } catch (Exception e) {
            System.out.println ("** Error occurred in printAttrEntryInfo");
            System.out.println (e);
            System.exit (1);
        }
        return null;
    }


    /*************************************************************************
     *  Print the empty attributes.
     ************************************************************************/
    private static JsonArrayBuilder printEmptyAttributes () {

        Vector gAttributes = cdf.getGlobalAttributes();
        Vector vAttributes = cdf.getVariableAttributes();
        JsonArrayBuilder eattrs = null;
        JsonArrayBuilder gattrs = null;
        JsonArrayBuilder vattrs = null;

        int ix;
        ix = 0;
        for (Enumeration e=gAttributes.elements(); e.hasMoreElements();) {
          Attribute a = (Attribute)e.nextElement();
          long num = a.getNumEntries();
          if (num != 0) continue;
          ++ix;
          if (ix == 1) {
            gattrs = Json.createArrayBuilder();
          }
          gattrs.add(a.getName());
        }
        if (ix != 0) {
          eattrs = Json.createArrayBuilder();
          eattrs.add(Json.createObjectBuilder().add("GlobalAttributes",
                                                    gattrs).build());
        }
 
        ix = 0;
        for (Enumeration e=vAttributes.elements(); e.hasMoreElements();) {
          Attribute a = (Attribute)e.nextElement();
          long num = a.getNumEntries();
          if (num != 0) continue;
          ++ix;
          if (ix == 1) {
            vattrs = Json.createArrayBuilder();
          }
          vattrs.add(a.getName());
        }
        if (ix != 0) {
          if (eattrs == null)
            eattrs = Json.createArrayBuilder();
          eattrs.add(Json.createObjectBuilder().add("VariableAttributes",
                                                    vattrs).build());
        }

        return eattrs;
    }

    /*************************************************************************
     *  Print the variable data.
     ************************************************************************/
    private static JsonArrayBuilder printVarData (Variable v, String formatT,
                                                  Object fillVal) {
        try {
            long    maxRec, numDims, numElements, numValuesToRead, dataType;
            long    recCount;
            boolean recVary;
            long[]  dimSizes = {1L}, dimVariances;
            long[]  dimIndices   = {0L};
            long[]  dimIntervals = {1L};
            long numDimsN = 0;
            long[] dimSizesN = null;
            maxRec = v.getMaxWrittenRecord();
            /*******************************************************
               if varData = "no", do not extract variable data.
               if maxRec < 0, then the variable doesn't have data.
            ********************************************************/
            if (maxRec < 0) { 
                return null;
            }

            recVary      = v.getRecVariance();
            numDims      = v.getNumDims();
            dimSizes     = v.getDimSizes();
            numElements  = v.getNumElements();
            dataType     = v.getDataType();
            dimVariances = v.getDimVariances();
            numValuesToRead = 1;
            if (numDims > 0) {
                dimIntervals = new long[dimSizes.length];
                dimIndices   = new long[dimSizes.length];
                dimSizesN    = new long[dimSizes.length];
                int j = 0;
                numDimsN = 0;
                for (int i=0; i < dimSizes.length; i++) {
                     if (dimVariances[i] == VARY) {
                       ++numDimsN;
                       dimSizesN[j] = dimSizes[i];
                       ++j;
                     }
                     dimIntervals[i] = 1;
                     dimIndices[i]   = 0;
                     numValuesToRead *= dimSizes[i];
                }
            }

            JsonArrayBuilder records = Json.createArrayBuilder();

            /********************************************************/
            /*  maxRec represents the last record number for this   */
            /*  variable, not the number of records.                */
            /*                                                      */
            /*  NOTE: maxRec starts at 0, so if the value of maxRec */
            /*        is 2, the actual number of records is 3.      */
            /*        If there are no records exists, the value of  */
            /*        maxRec is -1.                                 */
            /********************************************************/
            long numRecordsToRead, recNo;
            long sparseRecord = v.getSparseRecords();
            CDFData cdfdata;
            numRecordsToRead = maxRec + 1;

            cdfdata = v.getHyperDataObject((long) 0, numRecordsToRead, 1L,
                                           dimIndices, dimSizes,
                                           dimIntervals);
            // Get the status of the last CDF call
            long status = cdf.getStatus();
            Object dataArray = cdfdata.getData();
            records = printVarAllData (numRecordsToRead, cdfdata,
                                       dataType, (int)numDimsN,
                                       dimSizes, numElements,
                                       (withz?"Z":""), formatT, fillVal);
            cdfdata = null;
            dataArray = null;
            return records;

        } catch (Exception e) {
            System.out.println ("** Error occurred in printVarData");
            System.out.println ("variable: "+v.getName());
            System.out.println (e);
            System.exit (1);
        }
        return null;
    }


    /*************************************************************************
     *  This method returns the output file name if one is not provided 
     *  through the -output option from the command line. 
     ************************************************************************/
    private static String getDefaultOutputFileName () {
        String fileName;
        int    loc1 = inFile.lastIndexOf(".cdf");
        int    loc2 = inFile.lastIndexOf(".CDF");
        boolean extCDF = inFile.endsWith(".cdf") ||
                         inFile.endsWith(".CDF");

        // Input file name given from the command line doesn't have
        // .cdf or .CDF extension in it.  
        if (!extCDF) 
            fileName = inFile + ".json";

        else { // Remove the .cdf or .CDF extension
            if (loc1 != -1) {
                fileName = inFile.substring(0,loc1);
                fileName = fileName + ".json";
            }
            else {
                fileName = inFile.substring(0,loc2);
                fileName = fileName + ".json";
            }
        }
        if (!fullpath) {
          int loc = fileName.lastIndexOf(separator);
          if (loc != -1)
            fileName = fileName.substring(loc+1);
        }
        return fileName;
    }


    /*************************************************************************
     *  This method removes the file path from the given file name and
     *  returns the file name.
     ************************************************************************/
    private static String removeFilePath (String fileName) {
        int loc = fileName.lastIndexOf(separator);
        fileName = fileName.substring(loc+1);

        return fileName;
    }


    /************************************************************************* 
     *  If an invalid option is entered from the command line, this routine 
     *  is invoked to print an appropriate message followed by its proper
     *  syntax.
     ************************************************************************/
    private static void exit (String msg) {
        if (!msg.equals("")) System.out.println (msg);
        System.exit(1);
    }


    /************************************************************************* 
     *  Print the proper syntax for invoking this program. 
     ************************************************************************/
    private static void usage() {
       System.out.println ("\nDescription:");
       System.out.println ("    This program exports the contents of a CDF "+
                           "file(s) into a single Json file.");
       System.out.println ("    The Json file will have an \".json\" extension"+
                           " if it is not specified. ");
       System.out.println (" ");
       System.out.println ("Usage: java CDF2Json [Options] [cdfFile1 "+
                           "cdfFile2 ...]");
       System.out.println ("");
       System.out.println ("    cdfFile1 cdfFile2 .... ");
       System.out.println ("       Command line input CDF file(s) for "+
                           "conversion. A maximum of 100 ");
       System.out.println ("       files can be specified.");
       System.out.println ("       If the \"output\" option is not specified,"+
                           " the first file in the list is");
       System.out.println ("       used as the the output Json file name.");
       System.out.println ("       Alternatively, use \"fileNames\" option "+
                           "to specify a text file");
       System.out.println ("       that contains the CDF name(s) for "+
                           "conversion. Command line file(s) and");
       System.out.println ("       fileNames option are mutually exclusive.");
       System.out.println (" ");
       System.out.println ("Options:");
       System.out.println (" ");
       System.out.println ("   -fileNames:fileNames");
       System.out.println ("       fileNames is a text file that contains the "+
                           "input CDF file name(s)");
       System.out.println ("       for converting into a Json file. With this "+
                           "option, there is no need to");
       System.out.println ("       enter the file(s) in the command line."+
                           "If the output Json file is not");
       System.out.println ("       specified, this file is used as the name "+
                           "of the Json output.");
       System.out.println (" ");
       System.out.println ("   -globalAttrs:[yes | no].");
       System.out.println ("      -globalAttrs:yes, the default, extracts all "+
                           "global attributes.");
       System.out.println ("      -globalAttrs:no doesn't extract global "+
                           "attributes.");
       System.out.println (" ");
       System.out.println ("   -varAttrs:[yes | no]. ");
       System.out.println ("      -varAttrs:yes, the default, extracts each "+
                           "variable's attributes.");
       System.out.println ("      -varAttrs:no doesn't extract variable's "+
                           "attributes.");
       System.out.println (" ");
       System.out.println ("   -entryDataType:[yes | no].  ");
       System.out.println ("     Only applicable when \"-globalAttrs:yes\" or "+
                           "\"-varAttrs:yes\" ");
       System.out.println ("     The entry value is shown, with or without "+
                           "data type.");
       System.out.println ("      -entryDataType:yes shows entry's "+
                           "non-char data type.");
       System.out.println ("      -entryDataType:no, the default, doesn't "+
                           "show entry's data type.");
       System.out.println ("     Note: This is a new option. A Json file "+
                           "with entry's data type will not");
       System.out.println ("           be handled by the older Json2CDF "+
                           "program.");
       System.out.println (" ");
       System.out.println ("   -8bytestostr:[yes | no].  ");
       System.out.println ("     Entry or data value of CDF_INT8 or "+
                           "CDF_DOUBLE|CDF_REAL8 data type is");
       System.out.println ("     presented in a string.");
       System.out.println ("      -8bytestostr:yes converts the value to "+
                           "string.");
       System.out.println ("      -8bytestostr:no, the default, doesn't "+
                           "convert.");
       System.out.println ("     Note: This new option may help applications "+
                           "that have issues with large");
       System.out.println ("           8-byte integers/doubles. A Json file "+
                           "with \"string\" number will not");
       System.out.println ("           be handled by the older Json2CDF program.");
       System.out.println (" ");
       System.out.println ("   -vars:var1,var2,....");
       System.out.println ("      -vars:var1,var2,... extracts only the "+
                           "specified variables with");
       System.out.println ("                           variable names "+
                           "separated by a single ','.");
       System.out.println (" ");
       System.out.println ("   -varData:[yes | nrv | no].");
       System.out.println ("      -varData:yes outputs all variables' data. "+
                           "Warning: The output file can be very large.");
       System.out.println ("      -varData:nrv outputs only non-record "+
                           "varying (nrv) variables' data.");
       System.out.println ("      -varData:no, the default, doesn't output "+
                           "any variable's data."); 
       System.out.println (" ");
       System.out.println ("   -format:[yes | no | prefer].");
       System.out.println ("      -format:yes uses variable attribute FORMAT "+
                           "to encode data"); 
       System.out.println ("      -format:prefer, the default, uses variable "+
                           "attribute FORMAT to encode data."); 
       System.out.println ("                     However, if its FORMAT is not"+
                           " properly defined, it"); 
       System.out.println ("                     is treated as \"no\".");
       System.out.println ("      -format:no uses Java internal encoding to "+
                           "encode data");
       System.out.println ("     Note: The format is only relevant to "+
                           "floating-point values.");
       System.out.println (" ");
       System.out.println ("   -encodeepoch:[yes | no].");
       System.out.println ("      -encodeepoch:yes, the default, encodes CDF "+
                           "epoch data value to time string.");
       System.out.println ("      -encodeepoch:no  shows CDF epoch value in "+
                           "its original data form.");
       System.out.println (" ");
       System.out.println ("   -[output | json]:outputFileName");
       System.out.println ("      The name of the input CDF file is used "+
                           "as the default output file.");
       System.out.println ("      name.  Use this option to specify a "+
                           "different output file name.");
       System.out.println (" ");
       System.out.println ("   -[showProgress | Progress]");
       System.out.println ("      This option displays the processing "+
                           "progress on the screen.");
       System.out.println ("      It shows how many CDF variables are there "+
                           "to process and which");
       System.out.println ("      variable is being processed.");
       System.out.println (" ");
       System.out.println ("   -debug");
       System.out.println ("      Displays the specifications to "+
                           "run the application.");
       System.out.println (" ");
       System.out.println ("   -withZ");
       System.out.println ("      Adding \"Z\" to the encoded CDF epoch data "+
                           "of ISO 8601 form.");
       System.out.println ("");
       System.out.println ("   -delete");
       System.out.println ("      Over-ride the existing Json file.");
       System.out.println ("");
       System.out.println ("   -nofullpath");
       System.out.println ("      Only use the file name portion of the "+
                           "entered full path name as");
       System.out.println ("      the key to each CDF in the Json output. ");
       System.out.println ("");
       System.out.println ("   -showfile");
       System.out.println ("      Display the file name(s) being processed.");
       System.out.println ("");
       System.out.println ("NOTE:");
       System.out.println ("");
       System.out.println ("  1. Variable's non-varying dimension(s) is "+
                           "ignored. A varying dimension");
       System.out.println ("     with a size of only 1 is also considered a "+
                           "non-varying dimension.");
       System.out.println ("  2. NaN|-NaN and INF|-INF, valid floating-point "+
                           "values in CDF, but are not");
       System.out.println ("     allowed in Json. They are replaced by strings"+
                           " \"NaN\"|\"-NaN\" and ");
       System.out.println ("     \"INF\"|\"-INF\". Try to avoid using any of"+
                           " these as it might cause");
       System.out.println ("     unexpected results if such Json file is"+
                           " converted back to CDF.");
       System.out.println ("  3. Only value, without the data type, from "+
                           "meta-data is presented in the");
       System.out.println ("     Json output.");
       System.out.println ("  4. Use CDFJsonReader to display the Json file "+
                           "in a easy to read form.");
       System.out.println ("");
       System.out.println ("Examples: ");

       System.out.println ("   java CDF2Json test.cdf (same as "+
                           "java CDF2Json -json:test.json test.cdf)");
       System.out.println ("   java CDFJsonReader test.json ");
       System.out.println (" ");
       System.out.println ("The CDF's Json file has the following form: ");
       System.out.println (" ");
       System.out.println (" CDFname1:    <== CDF file name key\n"+
                           "   CDFFileInfo:\n"+
                           "     FileVersion:.....\n"+
                           "     Format:.....\n"+
                           "     Majority:...\n"+
                           "     Encoding:.....\n"+
                           "   CDFglobalAttributes:\n"+ 
                           "     Gattr_name1:\n"+
                           "       entry#:value\n"+
                           "       ...\n"+
                           "       ...\n"+
                           "     Gattr_name2:\n"+
                           "       entry#:value\n"+
                           "       ...\n"+
                           "       ...\n"+
                           "   ...\n"+
                           "   ...\n"+
                           "   CDFVariables:\n"+
                           "     VarName1:  <== Variable name key\n"+
                           "       VarDescription:\n"+
                           "         DataType:....\n"+
                           "         ...\n"+
                           "         ...\n"+
                           "       VarAttributes:\n"+
                           "         VALIDMIN:.... or VALIDMIN: DataType:.. Value:...\n"+
                           "         VALIDMAX:.... or VALIDMAX: DataType:.. Value:...\n"+
                           "         ...\n"+
                           "         ...\n"+
                           "       VarData:\n"+
                           "       ...\n"+
                           "     VarName2:\n"+
                           "       VarDescription:\n"+
                           "         DataType:....\n"+
                           "         ...\n"+
                           "         ...\n"+
                           "       VarAttributes:\n"+
                           "         VALIDMIN:....\n"+
                           "         VALIDMAX:....\n"+
                           "         ...\n"+
                           "         ...\n"+
                           "       VarData:\n"+
                           "         ...\n"+
                           "   EmptyAttributes:  <== Exists if there are "+
                                                 "attributes defined but no values\n"+
                           "     GlobalAttributes: [...]\n"+
                           "     VariableAttributes: [...]\n"+
                           " \n"+
                           " CDFname2:\n"+
                           "   ...\n"+
                           "   ...\n"+
                           " ...\n"+
                           " ...\n"+
                           " ");
    }

    /************************************************************************* 
     *  Output an object from all ecords with multi-dimensional data values
     *  to a JsonArray (called by printVarData). 
     ************************************************************************/

    private static JsonArrayBuilder printVarAllData (long numRecs,
                                                     Object cdfdata,
                                                     long dataType,
                                                     int nDims,
                                                     long[] dimSizesL,
                                                     long numElems,
                                                     String addZ,
                                                     String formatT,
                                                     Object fillVal) {

        Object data1DArray = ((CDFData)cdfdata).getRawData();
        String signature =  CDFUtils.getSignature(data1DArray);
        int recValues = 1;
        int[] dimSizes = new int[nDims];
        int nDimsN = 0;
        for (int i = 0; i < nDims; ++i) {
          if (dimSizesL[i] > 1) {
            dimSizes[nDimsN] = (int) dimSizesL[i];
            ++nDimsN;
          }
        }
        for (int i=0; i<(int)nDimsN;i++) {
           recValues *= dimSizes[i];
        }
        JsonArrayBuilder jArray0 = Json.createArrayBuilder();
        JsonArrayBuilder jArray = null;
        byte[] chb = new byte[(int)numElems];
        int iy;
        if (nDimsN == 0) jArray = Json.createArrayBuilder();
        for (int k=0; k < numRecs; ++k) {
          if (nDimsN > 0 || jArray == null) jArray = Json.createArrayBuilder();
          for (int i=0; i<recValues; i++) {
            switch ((int)dataType) {
              case (int)CDF_CHAR:
              case (int)CDF_UCHAR:
                  System.arraycopy((byte[])data1DArray,
                                   (int)numElems*(k*recValues+i), 
                                   chb, 0, (int)numElems);
                  int inum = (int) numElems;
                  if (chb[inum-1] == 0) {
                    for (iy = inum; iy > 0; --iy) {
                      if (chb[iy-1] != 0) {
                        inum = iy;
                        break;
                      }
                    }
                    if (iy == 0) inum = 0;
                  }
                  if (inum == 0)
                    jArray.add("");
                  else
                    jArray.add(new String(chb, 0, inum));
                  break;
              case (int)CDF_BYTE:
              case (int)CDF_INT1:
                  byte i1;
                  if (signature.charAt(0) == '[')
                    i1 = (byte) Array.get((byte[])data1DArray, i+k*recValues);
                  else
                    i1 = ((Byte)data1DArray).byteValue();
                  jArray.add(i1);
                  break;
              case (int)CDF_INT2:
                  short i2;
                  if (signature.charAt(0) == '[')
                    i2 = (short) Array.get((short[])data1DArray, i+k*recValues);
                  else
                    i2 = ((Short)data1DArray).shortValue();
                  jArray.add(i2);
                  break;
              case (int)CDF_UINT1:
                  short u1;
                  if (signature.charAt(0) == '[')
                    u1 = (short) Array.get((short[])data1DArray, i+k*recValues);
                  else
                    u1 = (short) ((Short)data1DArray).shortValue();
                  jArray.add((u1>=0)? u1 : (u1+256));
                  break;
              case (int)CDF_INT4:
                  int i4;
                  if (signature.charAt(0) == '[')
                    i4 = (int) Array.get((int[])data1DArray, i+k*recValues);
                  else
                    i4 = ((Integer)data1DArray).intValue();
                  jArray.add(i4);
                  break;
              case (int)CDF_UINT2:
                  int u2;
                  if (signature.charAt(0) == '[')
                    u2 = (int) Array.get((int[])data1DArray, i+k*recValues);
                  else
                    u2 = ((Integer)data1DArray).intValue();
                  jArray.add((u2>=0)? u2 : (u2+65536));
                  break;
              case (int)CDF_UINT4:
                  long u4;
                  if (signature.charAt(0) == '[')
                    u4 = (long) Array.get((long[])data1DArray, i+k*recValues);
                  else
                    u4 = ((Long)data1DArray).longValue();
                  jArray.add((u4>=0)? u4 : (u4+4294967296L));
                  break;
              case (int)CDF_INT8:
              case (int)CDF_TIME_TT2000:
                  long i8;
                  if (signature.charAt(0) == '[')
                    i8 = (long) Array.get((long[])data1DArray, i+k*recValues);
                  else
                    i8 = ((Long)data1DArray).longValue();
                  if (dataType == CDF_INT8) {
                    if (int8tostr.equals("no"))
                      jArray.add(i8);
                    else {
                      StringBuffer sb = new StringBuffer();
                      sb.append("").append(i8);
                      jArray.add(sb.toString());
                    }
                  } else {
                    if (encodeEp)
                      jArray.add(CDFTT2000.encode(i8));
                    else {
                      if (int8tostr.equals("no"))
                        jArray.add(i8);
                      else {
                        StringBuffer sb = new StringBuffer();
                        sb.append("").append(i8);
                        jArray.add(sb.toString());
                      }
                    }
                  }
                  break;
              case (int)CDF_REAL4:
              case (int)CDF_FLOAT:
                  float f4;
                  if (signature.charAt(0) == '[')
                    f4 = (float) Array.get((float[])data1DArray, i+k*recValues);
                  else
                    f4 = (float) ((Float)data1DArray).floatValue();
                  if (Float.isNaN(f4))
                    jArray.add ("NaN");
                  else if (Float.isNaN(-f4))
                    jArray.add ("-NaN");
                  else if (Float.isInfinite(f4))
                    jArray.add ("INF");
                  else if (Float.isInfinite(-f4))
                    jArray.add ("-INF");
                  else if (formatT == null || f4 == -1.0E30f || f4 == 1.0E30f ||
                                              f4 == -1.0E31f || f4 == 1.0E31f) {
                    String aVal = Float.toString(f4);
                    jArray.add(Double.valueOf(aVal));
                  } else {
                    try {
                      String sd = String.format(formatT, f4);
                      jArray.add(Double.valueOf(sd));
                    } catch (Exception ec) {
                      String aVal = Float.toString(f4);
                      jArray.add(Double.valueOf(aVal));
                    }
                  }
                  break;
              case (int)CDF_REAL8:
              case (int)CDF_DOUBLE:
                  double f8;
                  if (signature.charAt(0) == '[')
                    f8 = (double) Array.get((double[])data1DArray, i+k*recValues);
                  else
                    f8 = (double) ((Double)data1DArray);
                  if (Double.isNaN(f8))
                    jArray.add ("NaN");
                  else if (Double.isNaN(-f8))
                    jArray.add ("-NaN");
                  else if (Double.isInfinite(f8))
                    jArray.add ("INF");
                  else if (Double.isInfinite(-f8))
                    jArray.add ("-INF");
                  else if (f8 == -1.0E30 || f8 == 1.0E30 ||
                           f8 == -1.0E31 || f8 == 1.0E31) {
                    String aVal = Double.toString(f8);
                    jArray.add(Double.valueOf(aVal));
                  } else if (formatT == null) {
                    String aVal = Double.toString(f8);
                    jArray.add (Double.valueOf(aVal));
                  } else {
                    try {
                      String sd = String.format(formatT, f8);
                      if (int8tostr.equals("no"))
                        jArray.add(Double.valueOf(sd));
                      else {
                        StringBuffer sb = new StringBuffer();
                        BigDecimal bdd = new BigDecimal(f8);
                        sb.append("").append(String.format(formatT, bdd));
                        if (sb.toString().matches("\\d+")) sb.append(".0");
                        jArray.add (sb.toString().trim());
                      }
                    } catch (Exception ec) {
                      jArray.add(f8);
                    }
                  }
                  break;
              case (int)CDF_EPOCH:
                  double d2;
                  if (signature.charAt(0) == '[')
                    d2 = (double) Array.get((double[])data1DArray,
                                            i+k*recValues);
                  else
                    d2 = ((Double)data1DArray);
                  if (encodeEp)
                    jArray.add(Epoch.encode4(d2)+addZ);
                  else
                    jArray.add(d2);
                  break;
              case (int)CDF_EPOCH16:
                  double tmp[] = new double[2];
                  tmp[0] = (double) Array.get((double[])data1DArray,
                                              2*(i+k*recValues));
                  tmp[1] = (double) Array.get((double[])data1DArray,
                                              2*(i+k*recValues)+1);
                  if (encodeEp)
                      jArray.add(Epoch16.encode4(tmp)+addZ);
                  else {
                      JsonArrayBuilder epoch16 = Json.createArrayBuilder();
                      epoch16.add(tmp[0]);
                      epoch16.add(tmp[1]);
                      jArray.add(epoch16.build());
                  }
                  break;
              default:
                  break;
            } /* switch (dataType) */
          } // for values loop
          if (numRecs == 1)
            jArray0 = jArray;
          else {
            if (nDimsN > 0) // 1 rec in each [....] line
              jArray0.add(jArray);
          }
        } // for records loop
        if (nDimsN == 0) jArray0.add(jArray);
        return jArray0;
    }

    // used to determine the boundaries
    private static long product (int [] array, int start, int stop) {

        long product = 1;
        for (int i=start; i<stop; i++)
        if (array[i] > 1) product *= array[i];

        return product;
    }

    private static boolean validORscaleORfill (String name) {

        if (name == null) return false;
        String name2 = name.toLowerCase();
        if (name2.equals("validmin") || name2.equals("validmax") ||
            name2.equals("scalemin") || name2.equals("scalemax") ||
            name2.equals("fillval"))
          return true;
        else 
          return false;
    }

    private static boolean isEpochDataType (long dataType) {

        if (dataType == CDF_EPOCH || dataType == CDF_EPOCH ||
            dataType == CDF_TIME_TT2000) return true;
        else return false;
    }

    /************************************************************************* 
     *  Output an object with a single data value or an array of values to
     *  a JsonObject (called by printGlobalAttributes and printVarAttributes)
     *  or JsonArray (called by printVarData). 
     ************************************************************************/
    
    private static Object printSingleData (Object jsonObject, String name,
                                           Object data, long dataType,
                                           long numDims, long dataType2,
                                           String addZ, String formatT,
                                           Object fillVal, boolean single) {
        /* dataType: entry data type for global or variable attribute */
        /* dataType2: variable data type if for variable attributes */

        int iflag;
        if (dataType == CDF_EPOCH) iflag = 1;
        else if (dataType == CDF_EPOCH16) iflag = 2;
        else if (dataType == CDF_TIME_TT2000) iflag = 3;
        else iflag = 0;
        int  i, arrayLength, jj = 1;
        if (iflag == 2) jj = 2;
        boolean multi = false;

        String signature = CDFUtils.getSignature(data);
        JsonObjectBuilder jObject = Json.createObjectBuilder();
        JsonArrayBuilder  jArray = Json.createArrayBuilder();
        if (jsonObject instanceof JsonObjectBuilder) 
          jObject = (JsonObjectBuilder) jsonObject;
        else
          jArray = (JsonArrayBuilder) jsonObject;
        if (signature.charAt(0) == '[') {
          arrayLength = Array.getLength(data);
          if (iflag == 2) arrayLength = arrayLength / 2;
          if (arrayLength > 1) multi = true;
        }
        if (multi) {
            JsonArrayBuilder  jArray2 = Json.createArrayBuilder();
            arrayLength = Array.getLength(data);
            for (i=0; i < arrayLength; i=i+jj) {
                 if (signature.charAt(1) == 'B')
                     jArray2.add (Array.getByte(data,i));

                 else if (signature.charAt(1) == 'S')
                     jArray2.add (Array.getShort(data,i));

                 else if (signature.charAt(1) == 'I')
                     jArray2.add (Array.getInt(data,i));

                 else if (signature.charAt(1) == 'J') {
                     long val = (long) Array.getLong(data,i);
                     if (iflag == 3 || (isEpochDataType(dataType2) &&
                                        validORscaleORfill(name))) {
                       if (encodeEp)
                         jArray2.add (CDFTT2000.encode(val)+addZ);
                       else {
                         if ((iflag == 3 || isEpochDataType(dataType2)) &&
                             int8tostr.equals("yes")) {
                           StringBuffer sb = new StringBuffer();
                           sb.append("").append(val);
                           jArray2.add (sb.toString());
                         } else
                           jArray2.add (val);
                       }
                     } else {
                       if (dataType == CDF_INT8 && int8tostr.equals("yes")) {
                           StringBuffer sb = new StringBuffer();
                           sb.append("").append(val);
                           jArray2.add (sb.toString());
                       } else
                         jArray2.add (val);
                     }

                 } else if (signature.charAt(1) == 'F') {
                     float ff = Array.getFloat(data,i);
                     if (Float.isNaN(ff))
                       jArray2.add ("NaN");
                     else if (Float.isNaN(-ff))
                       jArray2.add ("-NaN");
                     else if (Float.isInfinite(ff))
                       jArray2.add ("INF");
                     else if (Float.isInfinite(-ff))
                       jArray2.add ("-INF");
                     else {
                       String aVal = Float.toString(ff);
                       if (formatT == null || ff == -1.0E30f || ff == 1.0E30f ||
                                              ff == -1.0E31f || ff == 1.0E31f) {
                         jArray2.add (Double.valueOf(aVal));
                       } else {
                         try {
                           String sd = String.format(formatT, ff);
                           jArray2.add (Double.valueOf(sd));
                         } catch (Exception ex) {
                           jArray2.add (Double.valueOf(aVal));
                         }
                       }
                     }
                 } else if (signature.charAt(1) == 'D') {
                     double dd = Array.getDouble(data,i);
                     if (iflag == 1 || (isEpochDataType(dataType2) && 
                                        validORscaleORfill(name))) {
                       if (encodeEp)
                         jArray2.add (Epoch.encode4(dd)+addZ);
                       else
                         jArray2.add (dd);
                     } else if (iflag == 2 || (isEpochDataType(dataType2) &&
                                               validORscaleORfill(name))) {
                       double[] mmm = new double[2];
                       mmm[0] = Array.getDouble(data,i);
                       mmm[1] = Array.getDouble(data,i+1);
                       if (encodeEp)
                         jArray2.add (Epoch16.encode4(mmm)+addZ);
                       else {
                         JsonArrayBuilder epoch16 = Json.createArrayBuilder();
                         epoch16.add (mmm[0]);
                         epoch16.add (mmm[1]);
                         jArray2.add (epoch16.build());
                       }
                     } else {
                       if (Double.isNaN(dd))
                         jArray2.add ("NaN"); // jArray2.add (Double.NaN);
                       else if (Double.isNaN(-dd))
                         jArray2.add ("-NaN"); // jArray2.add (-Double.NaN);
                       else if (Double.isInfinite(dd))
                         jArray2.add ("INF"); // jArray2.add (Double.POSITIVE_INFINITY);
                       else if (Double.isInfinite(-dd))
                         jArray2.add ("-INF"); // jArray2.add (Double.NEGATIVE_INFINITY);
                       else {
                         if (dd == -1.0E30 || dd == 1.0E30 ||
                             dd == -1.0E31 || dd == 1.0E31) {
                           String aVal = Double.toString(dd);
                           jArray2.add (Double.valueOf(aVal));
                         } else if (formatT == null) {
                           String aVal = Double.toString(dd);
                           if (int8tostr.equals("no"))
                             jArray2.add (aVal);
                           else {
                             StringBuffer sb = new StringBuffer();
                             BigDecimal bddd = new BigDecimal(dd);
                             sb.append("").append(bddd.toString());
                             if (sb.toString().matches("\\d+")) sb.append(".0");
                             jArray2.add (sb.toString());
                           }
                         } else {
                           try {
                             String sd = String.format(formatT, dd);
                             if (int8tostr.equals("no"))
                               jArray2.add (Double.valueOf(sd));
                             else {
                               StringBuffer sb = new StringBuffer();
                               BigDecimal bd = new BigDecimal(dd);
                               sb.append("").append(String.format(formatT,bd));
                               if (sb.toString().matches("\\d+")) sb.append(".0");
                               jArray2.add (sb.toString().trim());
                             }
                           } catch (Exception ex) {
                             jArray2.add (dd);
                           }
                         }
                       }
                     }
                 }
                 else if (signature.indexOf("String") != -1)
                     jArray2.add (((String[])data)[i]);
            }
            if (name != null)
              return jObject.add(name, jArray2);
            else {
              if (single) return jArray2;
              else  return jArray.add(jArray2);
            }
        } else {
          if (signature.charAt(0) == '[' && iflag != 2)
            data = Array.get(data, 0);
          if (iflag == 1) {
            if (name != null) {
              if (encodeEp)
                return jObject.add(name,
                                   Epoch.encode4(((Double)data))+addZ);
              else
                return jObject.add(name, ((Double)data));
            } else {
              if (encodeEp)
                return jArray.add(Epoch.encode4(((Double)data))+addZ);
              else
                return jArray.add(((Double)data));
            }
          } else if (iflag == 2) {
            if (name != null) {
              if (encodeEp)
                return jObject.add(name, Epoch16.encode4((double[])data)+addZ);
              else {
                JsonArrayBuilder epoch16 = Json.createArrayBuilder();
                epoch16.add(((double[])data)[0]);
                epoch16.add(((double[])data)[1]);
                return jObject.add(name, epoch16.build());
              }
            } else {
              if (encodeEp)
                return jArray.add(Epoch16.encode4(((double[])data))+addZ);
              else {
                JsonArrayBuilder epoch16 = Json.createArrayBuilder();
                epoch16.add(((double[])data)[0]);
                epoch16.add(((double[])data)[1]);
                return jArray.add(epoch16.build());
              }
            }
          } else if (iflag == 3) {
            long val = (long) ((Long)data).longValue();
            if (name != null) {
              if (encodeEp)
                return jObject.add(name, CDFTT2000.encode(val)+addZ);
              else {
                if (int8tostr.equals("no"))
                  return jObject.add (name, val);
                else {
                  StringBuffer sb = new StringBuffer();
                  sb.append("").append(val);
                  return jObject.add (name, sb.toString());
                }
              }
            } else {
              if (encodeEp)
                return jArray.add(CDFTT2000.encode(val)+addZ);
              else {
                if (int8tostr.equals("no"))
                  return jArray.add (val);
                else {
                  StringBuffer sb = new StringBuffer();
                  sb.append("").append(val);
                  return jArray.add (sb.toString());
                }
              }
            }
          } else {
            if (signature.indexOf("Byte") != -1) {
              int value = ((Byte)data).intValue();
              if (name != null)
                return jObject.add(name, value);
              else
                return jArray.add(value);
            } else if (signature.indexOf("Short") != -1) {
              int value = ((Short)data).intValue();
              if (name != null)
                return jObject.add(name, value);
              else
                return jArray.add(value);
            } else if (signature.indexOf("Int") != -1) {
              int value = ((Integer)data).intValue();
              if (name != null)
                return jObject.add(name, value);
              else
                return jArray.add(value);
            } else if (signature.indexOf("Long") != -1) {
              long value = ((Long)data).longValue();
              if (name != null) {
                if (dataType == CDF_INT8 && int8tostr.equals("yes")) {
                  StringBuffer sb = new StringBuffer();
                  sb.append("").append(value);
                  return jObject.add (name, sb.toString());
                } else 
                  return jObject.add (name, value);
              } else {
                if (dataType == CDF_INT8 && int8tostr.equals("yes")) {
                  StringBuffer sb = new StringBuffer();
                  sb.append("").append(value);
                  return jArray.add (sb.toString());
                } else
                  return jArray.add (value);
              }
            } else if (signature.indexOf("Float") != -1) {
              float ff = ((Float)data).floatValue();
              if (Float.isNaN(ff)) {
                if (name != null)
                  return jObject.add (name, "NaN");
                else
                  return jArray.add ("NaN");
              } else if (Float.isNaN(-ff)) {
                if (name != null)
                  return jObject.add (name, "-NaN");
                else
                  return jArray.add ("-NaN");
              } else if (Float.isInfinite(ff)) {
                if (name != null)
                  return jObject.add (name, "INF");
                else
                  return jArray.add ("INF");
              } else if (Float.isInfinite(-ff)) {
                if (name != null) 
                  return jObject.add (name, "-INF");
                else
                  return jArray.add ("-INF");
              } else {
                String aVal = Float.toString(ff);
                if (name != null) {
                  if (formatT == null || ff == 1.0E30f || ff == -1.0E30f ||
                                         ff == 1.0E31f || ff == -1.0E31f) {
                    return jObject.add(name, Double.valueOf(aVal));
                  } else {
                    try {
                      String sd = String.format(formatT, ff);
                      return jObject.add(name, Double.valueOf(sd));
                    } catch (Exception ex) {
                      return jObject.add (name, Double.valueOf(aVal));
                    }
                  }
                } else {
                  if (formatT == null) {
                    return jArray.add(Double.valueOf(aVal));
                  } else {
                    try {
                      String sd = String.format(formatT, ff);
                      return jArray.add(Double.valueOf(sd));
                    } catch (Exception ex) {
                      return jArray.add (Double.valueOf(aVal));
                    }
                  }
                }
              }
            } else if (signature.indexOf("Double") != -1) {
              double dd = ((Double)data).doubleValue();
              if (Double.isNaN(dd)) {
                if (name != null)
                  return jObject.add (name, "NaN");
                else
                  return jArray.add ("NaN");
              } else if (Double.isNaN(-dd)) {
                if (name != null)
                  return jObject.add (name, "NaN");
                else
                  return jArray.add ("-NaN");
              } else if (Double.isInfinite(dd)) {
                if (name != null)
                  return jObject.add (name, "INF");
                else
                  return jArray.add ("INF");
              } else if (Double.isInfinite(-dd)) {
                if (name != null)
                  return jObject.add (name, "-INF");
                else
                  return jArray.add ("-INF");
              } else {
                if (name != null) {
                  String aVal = Double.toString(dd);
                  if (dd == -1.0E30 || dd == 1.0E30 ||
                      dd == -1.0E31 || dd == 1.0E31) {
                    return jObject.add(name, Double.valueOf(aVal));
                  } else if (formatT == null) {
                    if (isEpochDataType(dataType2) && validORscaleORfill(name))
                      return jObject.add(name, Epoch.encode4(dd)+addZ);
                    else {
                      if (int8tostr.equals("no"))
                        return jObject.add (name, Double.valueOf(aVal));
                      else {
                        StringBuffer sb = new StringBuffer();
                        BigDecimal bddd = new BigDecimal(dd);
                        sb.append("").append(bddd.toString());
                        if (sb.toString().matches("\\d+")) sb.append(".0");
                        return jObject.add (name, sb.toString());
                      }
                    }
                  } else {
                    try {
                      String sd = String.format(formatT, dd);
                      if (isEpochDataType(dataType2) &&
                          validORscaleORfill(name)) {
                        return jObject.add(name, Epoch.encode4(
                                                 Double.valueOf(sd))+addZ);
                      } else {
                        if (int8tostr.equals("no"))
                          return jObject.add (name, Double.valueOf(sd));
                        else {
                          StringBuffer sb = new StringBuffer();
                          BigDecimal bddd = new BigDecimal(dd);
                          String val = String.format(formatT, bddd);
                          sb.append("").append(val);
                          if (sb.toString().matches("\\d+")) sb.append(".0");
                          return jObject.add (name, sb.toString().trim());
                        }
                      }
                    } catch (Exception ec) {
                      if (isEpochDataType(dataType2) &&
                          validORscaleORfill(name))
                        return jObject.add(name, Epoch.encode4(dd)+addZ);
                      else
                        return jObject.add(name, dd);
                    } 
                  }
                } else {
                  if (dd == -1.0E30 || dd == 1.0E30 ||
                      dd == -1.0E31 || dd == 1.0E31) {
                    String aVal = Double.toString(dd);
                    return jArray.add(Double.valueOf(aVal));
                  } else if (formatT == null) {
                    String aVal = Double.toString(dd);
                    return jArray.add(Double.valueOf(aVal));
                  } else {
                    try {
                      StringBuffer sb = new StringBuffer();
                      BigDecimal bddd = new BigDecimal(dd);
                      String val = String.format(formatT, bddd);
                      sb.append("").append(val);
                      if (sb.toString().matches("\\d+")) sb.append(".0");
                      return jArray.add (sb.toString().trim());
                    } catch (Exception es) {
                      return jArray.add(dd);
                    }
                  }
                }
              }
            } else if (signature.indexOf("String") != -1) {
              if (name != null)
                return jObject.add(name, (String)data);
              else
                return jArray.add((String)data);
            }
          }
        }
        return null;
    }

    private static String toCformat (String oFormat) {
       if (oFormat.charAt(0) == '%') return oFormat;
       /***********************************************************************
        *      FORTRAN format form
        * Change `oformat' to point to first non-blank, non-digit, non-`('
        * character.  This will skip over a Fortran repeat count (eg. the `20'
        * in `20F8.4' or `20(F8.4)').
        ***********************************************************************/
       oFormat = oFormat.trim();
       if (oFormat == null) return null;
       int len = oFormat.length();
       String formatY = null;
       for (int i = 0; i < len; ++i) {
         char a = oFormat.charAt(i);
         if (Character.isDigit(a) || a == '(') continue;
         formatY = oFormat.substring(i);
         if (formatY.endsWith(")")) formatY = formatY.substring(0,
                                                          formatY.length()-1);
         break;
       }
       if (formatY == null) return null;
       String cformat;
       /***********************************************************************
        * Encode C format specification.
        **********************************************************************/
       switch (formatY.charAt(0)) {
         /*********************************************************************
          * Integer/decimal.
	  ********************************************************************/
         case 'I':
         case 'i':
           cformat = formatY.substring(1);
           return "%"+cformat+"d";
         /*********************************************************************
          * Floating-point/non-scientific notation (which is called...
          ********************************************************************/
         case 'F':
         case 'f':
           cformat = formatY.substring(1);
           return "%"+cformat+"f";
         /*********************************************************************
          * Floating-point/scientific notation.
          ********************************************************************/
         case 'E':
         case 'e':
           cformat = formatY.substring(1);
           return "%"+cformat+"e";
       }
       return null;
    }

    private static void readFileNames (String fileTxt) {
       FileInputStream fIn = null;
       BufferedReader br = null;
       String line;
       int i;
       try {
           numFiles = 0;
           fIn = new FileInputStream(fileTxt);;
           br = new BufferedReader(new InputStreamReader(fIn));
           line = br.readLine();
           while (line != null) {
              if (CDFUtils.cdfFileExists(line)) ++numFiles;
              line = br.readLine();
           }
           if (numFiles == 0) {
             System.out.println("*** No CDF file(s) is found... ");
             System.exit(1);
           }
           fileNames = new String[numFiles];
           i = 0;
           fIn.getChannel().position(0);
           br = new BufferedReader(new InputStreamReader(fIn));
           line = br.readLine();
           while (line != null) {
              if (CDFUtils.cdfFileExists(line)) {
                 fileNames[i] = line;
                 ++i;
              }
              line = br.readLine();
           }
       } catch (Exception ex) {
         System.out.println("error: "+ex);
       } finally {
         try {
           if (fIn != null) fIn.close();
         } catch (Exception ey) {}
       }
    }
   
}
