/******************************************************************************
* Copyright 1996-2013 United States Government as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All Rights Reserved.
******************************************************************************/
/*
 * This program is for converting a cdf.dtd or cdf.xsd compliant XML file 
 * to a CDF file. The SAX parser is used for parsing the document.
 *
 * Modified: May 20, 2015 (ML) Changed exit status to 0 if ends successfully.
 *                             1, otherwise.
 */ 
import java.lang.reflect.*;
import gsfc.nssdc.cdf.*;
import gsfc.nssdc.cdf.util.*;

import java.io.*; 
import java.util.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler; 
import org.xml.sax.helpers.*;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;

public class CDFML2CDF extends DefaultHandler implements CDFConstants {
    private static final int NONE = 0, GAttributes = 1, 
			     VAttributes = 2, VarRecordData = 3,
                             VarElementData = 4, VarRecordTypeData = 5,
                             VarAttributeEntryData = 6,
                             GlobalAttributeEntryData = 7;
    private static String[] CDFelements = { // order of frequency in cdfml
              "record", "element", "entry", "variable", "attribute",
              "cdfVarInfo", "cdfVAttributes", "cdfVarData", "cdfGAttributes",
              "CDF", "cdfFileInfo",
//            "dateTime", "string", "float", "double","byte",
//            "unsignedByte", "short", "unsignedShort",
//            "int", "unsignedInt", "long", "unsignedLong",
              "Value", "array", "choice", "complextype" };
    private static String newCDFName = null;
    private static boolean removeOldCDF = false;
    private static boolean loadData = true;
    private static boolean backward = false;
    private static boolean progressReport = false;
    private static boolean validateCDFML = false;
    private static boolean entryNumFlag;
    private static boolean valueElement;
    private static String cdfmlFileName;
    private static String outputDir = null;
    private static String defaultStrDelimiter = "@~";

    private CDF cdf;
    private Variable var;
    private Entry entry;
    private Attribute attribute;
    private String cdfName, varName, attrName;
    private String elementDelimiter, indexString, multiDelimiter;
    private String xsdType = null;
    private long attrNum, varNum, scope, varDataType,
                 entryDataType, numElements, recNum;
    private long[] dimSizes, dimVariances, dimIndex;
    private long[] dimIndices, dimCounts, dimIntervals;
    private long recCount, recInterval;
    private long dim, recVariance;
    private int phyDims, physicalSize;
    private Object dataObject;
    private long entryNum = -1;
    private int inScope;
    private boolean entryBlock, recordBlock, elementBlock, processElement;
    private boolean arrayBlock;
    private boolean choiceBlock;
    private Stack stack;
    private CDFML2CDF aXML2CDF;
    private StringBuffer dataBuffer;
    private StringBuffer dataBuffer2;
    private long lastUpdated = -1L;

    public static void main(String argv[]) {

        if (argv.length < 1) CDFML2CDF.howto();
        
	int i = 0;
	while (i < argv.length) {
	  if (argv[i].charAt(0) == '-' || 
	      (i != argv.length-1 && argv[i].charAt(0) == '/')) {
	    if (argv[i].substring(1).equalsIgnoreCase("delete")) {
	      removeOldCDF = true;
	      i++;
            } else if (argv[i].substring(1).equalsIgnoreCase("nodelete")) {
              removeOldCDF = false;
              i++;
            } else if (argv[i].substring(1).equalsIgnoreCase("validate")) {
              validateCDFML = true;
              i++;
            } else if (argv[i].substring(1).equalsIgnoreCase("novalidate")) {
              validateCDFML = false;
              i++;
            } else if (argv[i].substring(1).equalsIgnoreCase("progress")) {
              progressReport = true;
              i++;
	    } else if (argv[i].length() > 4 && 
	               argv[i].substring(1,4).equalsIgnoreCase("cdf")) {
	      newCDFName = argv[i].substring(5);
	      i++;
	    } else if (argv[i].length() > 7 && 
	               argv[i].substring(1,7).equalsIgnoreCase("output")) {
	      newCDFName = argv[i].substring(8);
	      i++;
            } else if (argv[i].substring(1).equalsIgnoreCase("data")) {
              loadData = true;
              i++;
            } else if (argv[i].substring(1).equalsIgnoreCase("nodata")) {
              loadData = false;
              i++;
            } else if (argv[i].substring(1).equalsIgnoreCase("backward")) {
              backward = true;
              i++;
            } else if (argv[i].substring(1).equalsIgnoreCase("nobackward")) {
              backward = false;
              i++; 
	    } else 
	      CDFML2CDF.howto();
	  } else 
	    cdfmlFileName = argv[i++];
	}
	if (cdfmlFileName == null) CDFML2CDF.howto();
	CDFML2CDF.checkCDFMLFile(cdfmlFileName);
	if (newCDFName != null) CDFML2CDF.checkCDFFile(newCDFName);
	CDFML2CDF tmp = new CDFML2CDF();

    }

    CDFML2CDF() {

	aXML2CDF = this;
	System.err.println("\nStart processing");
        multiDelimiter = null;
        valueElement = false;
	aXML2CDF.startProcessing();
    }

    /**
     * Checks whether the specified XML document exists. 
     */

    private static void checkCDFMLFile(String cdfml) {

        File cdfmlFile = new File (cdfml);
        if (!cdfmlFile.exists()) {
          System.err.println("*** Error: cdfml file:"+cdfmlFile+
                             " does not exist! ***");
          System.exit(1);
	}

    }

    /**
     * Checks whether the passed file is a directory name or a CDF file.
     * If deleting the existing CDF file is specified, that file will be
     * deleted. 
     */

    private static void checkCDFFile(String cdfFile) {

	if (cdfFile == null) return;
	File aFile = new File(cdfFile);
	if (aFile.isDirectory()) {
	  if (cdfFile.endsWith(System.getProperty("file.separator")))
	    outputDir = cdfFile;
	  else
	    outputDir = cdfFile + System.getProperty("file.separator"); 
	  return;
	}
        String file1 = null, file2 = null;
        if (cdfFile.indexOf(".cdf") == -1 && cdfFile.indexOf(".CDF") == -1) {
          file1 = new StringBuffer(cdfFile).append(".cdf").toString();
          file2 = new StringBuffer(cdfFile).append(".CDF").toString();
        } else {
          file1 = cdfFile;
        }
        File cdfFile1 = new File(file1);
        boolean check2 = true;
        if (cdfFile1.exists()) {
          if (removeOldCDF) {
            cdfFile1.delete();
            check2 = false;
          } else {
            System.err.println("\nError... CDF: "+file1+" already exists...");
            System.exit(1);
          }
        }
        if (check2 && file2 != null) {
          check2 = false;
          File cdfFile2 = new File(file2);
          if (cdfFile2.exists()) {
            if (removeOldCDF) {
              cdfFile2.delete();
            } else {
              System.err.println("\nError... CDF: "+file2+" already exists...");
              System.exit(1);
            }
          }
        }
    }

    /**
     * Set up the necessary steps and ready to scan and process the XML document.
     */

    private void startProcessing() {

	dimSizes = null;
	dimVariances = null;
	dimIndices = null;
	inScope = NONE; 
	dataBuffer = new StringBuffer();
	dataBuffer2 = new StringBuffer();
	stack = new Stack();
        Throwable t1;

        try {
	    XMLReader parser = XMLReaderFactory.createXMLReader();
	    if (validateCDFML)
	      parser.setFeature("http://xml.org/sax/features/validation", true);
	    parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
	    parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
	    parser.setFeature("http://xml.org/sax/features/external-general-entities", false);
	    parser.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
	    parser.setErrorHandler(aXML2CDF);
            parser.setContentHandler(aXML2CDF);
	    parser.parse(new InputSource(CDFML2CDF.fileToURL(
                                                  new File(cdfmlFileName))));
        } catch (Throwable t) {
            System.err.println("**ERROR**: unable to handle/accept the XML"+
                               " file: "+cdfmlFileName);
            System.exit(1);
        }
        StringBuffer fName = new StringBuffer(cdfName);
        if (cdfName.indexOf(".cdf") == -1 && cdfName.indexOf(".CDF") == -1)
          fName.append(".cdf");
        System.err.println("Completed!  CDF file: "+fName.toString()+
                           " is created.");
        System.err.println("");
        System.exit(0);

    }     

    //===========================================================
    // SAX DocumentHandler methods
    //===========================================================     

    public void startDocument() {

    }     

    public void endDocument() {

    }     

    public void startElement(String namespaceURI,
                             String lName, // local name
                             String qName, // qualified name
                             Attributes attrs) throws SAXException {

        String eName = lName; // element name
        xsdType = null;
           if (attrs != null) {
             for (int i = 0; i < attrs.getLength(); i++) {
                  String aName = attrs.getLocalName(i); // Attr name
                if ("".equals(aName)) aName = attrs.getQName(i);
                  String value = attrs.getValue(i);
                  if (value.toLowerCase().indexOf("xsd:") == 0) {
                     xsdType = value.toLowerCase().substring(4);
                  }
             }
           }

        if ("".equals(eName)) eName = qName; // namespaceAware = false
	for (int i = 0; i < CDFelements.length; i++) {
	  if (eName.equalsIgnoreCase(CDFelements[i])) {
	    try {
	      dataBuffer.setLength(0);
	      handleStartCDFelement(eName, attrs);
	      break;
	    } catch (CDFException e) {
	      System.err.println("\n ***** CDFException 1..: "+e);
	      System.exit(1);
	    }
	  } 
	}

    }     

    public void endElement(String namespaceURI,
                           String sName, // simple name
                           String qName  // qualified name
                          ) throws SAXException {

	String elementName;
	if ("".equals(sName)) elementName = qName;
	else elementName = sName;
        for (int i = 0; i < CDFelements.length; i++) {
          if (elementName.equalsIgnoreCase(CDFelements[i])) {
	    try {
              handleEndCDFelement(elementName);
              break;
            } catch (CDFException e) {
              System.err.println("\n ****** CDFException 2..: "+e);
	      System.exit(1);
            }
          }
        }
	dataBuffer.setLength(0);

    }     

    public void characters(char buf[], int offset, int len) 
                throws SAXException {

        // buffer the characters in case they are broken down in several 
	// callbacks.
	dataBuffer.append(buf, offset, len);

    }

    /**
     * Ignorable whitespace. 
     */

    public void ignorableWhitespace(char ch[], int start, int length) {

    } // ignorableWhitespace(char[],int,int);

    //
    // ErrorHandler methods
    //

    /**
     * Warning. 
     */

    public void warning(SAXParseException ex) {

        System.err.println("[Warning] "+
                           getLocationString(ex)+": "+
                           ex.getMessage());
    }

    /**
     * Error. 
     */

    public void error(SAXParseException ex) {

        System.err.println("[Error] "+
                           getLocationString(ex)+": "+
                           ex.getMessage());

    }

    /**
     * Fatal error. 
     */

    public void fatalError(SAXParseException ex) throws SAXException {

        System.err.println("[Fatal Error] "+
                           getLocationString(ex)+": "+
                           ex.getMessage());
    }

    /**
     * Returns a string of the location. 
     */

    private String getLocationString(SAXParseException ex) {

        StringBuffer str = new StringBuffer();

        String systemId = ex.getSystemId();
        if (systemId != null) {
            int index = systemId.lastIndexOf('/');
            if (index != -1)
                systemId = systemId.substring(index + 1);
            str.append(systemId);
        }
        str.append(':');
        str.append(ex.getLineNumber());
        str.append(':');
        str.append(ex.getColumnNumber());

        return str.toString();

    } // getLocationString(SAXParseException):String

    //===========================================================
    // Utility Methods ...
    //===========================================================     
    // 

    /**
     * A start tag for a valid CDF element is encountered. 
     */ 

    private void handleStartCDFelement(String s, Attributes attrs) 
			throws CDFException, SAXException {

	stack.push(s);
        if (s.equalsIgnoreCase("variable")) setVariable(attrs);
        else if (s.equalsIgnoreCase("cdfVarInfo")) createVariable(attrs);
        else if (s.equalsIgnoreCase("cdfVAttributes")) {
           scope = VARIABLE_SCOPE;
           inScope = VAttributes;
	} else if (s.equalsIgnoreCase("cdfVarData")) recNum = 0;
        else if (s.equalsIgnoreCase("attribute")) createAttribute(attrs);
        else if (s.equalsIgnoreCase("entry")) {
	   if (entryBlock)
             throw new SAXException("entry element error: previous entry not "+
                                    "closed");
	   entryBlock = true;
           entryDataType = -1;
	   setEntry(attrs);
           if (multiDelimiter == null) {
             if (entryDataType == CDF_CHAR || entryDataType == CDF_UCHAR)
               multiDelimiter = defaultStrDelimiter;
             else
               multiDelimiter = new String(" ");
           }
        } else if (s.equalsIgnoreCase("value")) {  // do nothing
           valueElement = true;
	   processElement = false;
           if (attrs != null) {
             for (int i = 0; i < attrs.getLength(); i++) {
                  String aName = attrs.getLocalName(i); // Attr name
                if ("".equals(aName)) aName = attrs.getQName(i);
             }
           }
           if (scope == GLOBAL_SCOPE) inScope = GlobalAttributeEntryData;
           else {
             if (inScope != VarRecordData) inScope = VarAttributeEntryData;
           }
        } else if (s.equalsIgnoreCase("record")) {
           if (recordBlock)
             throw new SAXException("record element error: previous record"+
                                    " not closed");
	   elementDelimiter = null;
           recordBlock = true;
	   processElement = false;
           setRecord(attrs);
           if (multiDelimiter == null) {
             if (varDataType == CDF_CHAR || varDataType == CDF_UCHAR)
               multiDelimiter = defaultStrDelimiter;
             else
               multiDelimiter = new String(" ");
           }
           inScope = VarRecordData;
        } else if (s.equalsIgnoreCase("array")) {
           if (!arrayBlock) {
	     if (elementDelimiter != null) 
               multiDelimiter = new String(elementDelimiter);
             else {
               if ((entryBlock && (entryDataType == CDF_CHAR || entryDataType == CDF_UCHAR)) ||
                   (recordBlock && (varDataType == CDF_CHAR || varDataType == CDF_UCHAR)))
                 multiDelimiter = defaultStrDelimiter;
               else 
                 multiDelimiter = new String(" ");
             }
             arrayBlock = true;
	     processElement = false;
           } 
        } else if (s.equalsIgnoreCase("element")) {
	   if (elementBlock) 
             throw new SAXException("element error: previous data element not"+
                                    " closed");
	   elementBlock = true;
	   processElement = true;
           if (attrs != null) {
             for (int i = 0; i < attrs.getLength(); i++) {
                  String aName = attrs.getLocalName(i); // Attr name
                if ("".equals(aName)) aName = attrs.getQName(i);
                if (aName.equalsIgnoreCase("index"))
                  indexString = attrs.getValue(i);
		else if (aName.equalsIgnoreCase("elementDelimiter"))
		  elementDelimiter = attrs.getValue(i);
             }
           } else {
	     throw new SAXException("Index is missing for single element data");
	   }
	   inScope = VarElementData;
	} else if (s.equalsIgnoreCase("CDF")) createCDF(attrs);
	else if (s.equalsIgnoreCase("cdfFileInfo")) setCDF(attrs);
	else if (s.equalsIgnoreCase("cdfGAttributes")) {
	  	scope = GLOBAL_SCOPE;
		inScope = GAttributes;
	}
        else if (s.equalsIgnoreCase("choice")) return;
        else if (s.equalsIgnoreCase("complexType")) return;
    }

    /**
     * A end tag for a valid CDF element is encountered. 
     */

    private void handleEndCDFelement(String s) throws CDFException, SAXException {
	if (!stack.peek().equals(s)) 
	  throw new SAXException("parsing problem...the start element:"+
                                 stack.peek()+
                                 " doesn't match to the close element "+s); 
	stack.pop();
        if (s.equalsIgnoreCase("value")) {
            /* New schema */
            packData();
        } else if (s.equalsIgnoreCase("record")) {
	  if (processElement) {
	      recNum++;
	      return;
	  }
          /* If from old schema, get the data. */
          if (!valueElement) packData();
          inScope = VarRecordData;
          if (varDataType == -1)
              varDataType = GetMyCDFData.xsdTypeToCDFType(xsdType);
          if (varDataType == 100)
             varDataType = xsdDateTimeToCDFEpoch(dataBuffer2.toString());
          if (varDataType == -1) {
             System.err.println("ERROR... Variable data type can not be defined...");
             System.err.println("Abort...");
             System.exit(1);
          }
          try {
              processCDFEntryORVarData();
              inScope = NONE;
	      elementDelimiter = null;
              multiDelimiter = null;
              valueElement = false;
              dataBuffer2.setLength(0);
          } catch (SAXException e) {
              System.err.println("\n SAXException....: "+e);
              System.exit(1);
          }
          if (choiceBlock == true) {
            choiceBlock = false;
            recordBlock = false;
          } else
            recordBlock = false;
          arrayBlock = false;
        } else if (s.equalsIgnoreCase("array")) {
	} else if (s.equalsIgnoreCase("entry")) {
          /* If from old schema, get the data. */
          if (!valueElement) packData();
          if (entryDataType == -1)
              entryDataType = GetMyCDFData.xsdTypeToCDFType(xsdType);
          if (entryDataType == 100)
             entryDataType = xsdDateTimeToCDFEpoch(dataBuffer2.toString());
          if (entryDataType == -1) {
             System.err.println("ERROR... Entry data type can not be defined...");
             System.err.println("Abort...");
             System.exit(1);
          }
          if (elementDelimiter != null) multiDelimiter = elementDelimiter;
          else {
            if (entryDataType == CDF_CHAR || entryDataType == CDF_UCHAR)
                 multiDelimiter = defaultStrDelimiter;
            else multiDelimiter = " ";
          }
          try {
                processCDFEntryORVarData();
		elementDelimiter = null;
                entryBlock = false;
                choiceBlock = false;
            arrayBlock = false;
                dataBuffer2.setLength(0);
                valueElement = false;
                multiDelimiter = null;
          } catch (SAXException e) {
            System.err.println("\n SAXException....: "+e);
            System.exit(1);
          }
        } else if (s.equalsIgnoreCase("element")) {
	  elementBlock = false;
	  if (dataBuffer.length() == 0) return;
	  try {
	    processCDFEntryORVarData();
            inScope = NONE;
	    elementDelimiter = null;
          } catch (SAXException e) {
            System.err.println("\n SAXException....: "+e);
            System.exit(1);
          }
	} else if (s.equalsIgnoreCase("variable")) {
	  dimSizes = null;
	  dimVariances = null;
	  dimIndices = null; 
	  dimCounts = null;
	  dimIntervals = null;
	} else if (s.equalsIgnoreCase("cdfVariables")) {
          inScope = NONE;
          return;
        }
        else if (s.equalsIgnoreCase("cdfVAttributes")) {
          inScope = NONE;
          return;
        }
        else if (s.equalsIgnoreCase("attribute")) return;
        else if (s.equalsIgnoreCase("cdfGAttributes")) return;
        else if (s.equalsIgnoreCase("cdfVarData")) {
          if (progressReport)
            System.err.println("    Completed loading the data");
          return;
        }
	else if (s.equalsIgnoreCase("cdfFileInfo")) return;
	else if (s.equalsIgnoreCase("CDF")) closeCDF();
        else if (s.equalsIgnoreCase("choice")) return;
        else if (s.equalsIgnoreCase("complextype")) return;
    }

    /**
     * A data, either an attribute entry or record value(s), is ready to 
     * be processed.                                                     
     */

    private void processCDFEntryORVarData() throws SAXException {
        if (dataBuffer2.length() == 0) return;
        String tmp;
        tmp = dataBuffer2.toString();
        if (((inScope == GAttributes || inScope == VAttributes) &&
             (entryDataType != CDF_CHAR && entryDataType != CDF_UCHAR)) ||
            (loadData && 
             (inScope == VarRecordData || inScope == VarElementData) &&
             (varDataType != CDF_CHAR && varDataType != CDF_UCHAR ))) {
	  tmp = tmp.trim();
          if (tmp.length() > 0 && !valueElement) tmp = handleNumbers(tmp);
	}
        try {
          if (inScope == GAttributes || inScope == VAttributes ||
              inScope == GlobalAttributeEntryData ||
              inScope == VarAttributeEntryData) {
            createEntry(tmp);
          } else if (loadData) {
		 if (inScope == VarRecordData) loadVarRecordData(tmp);
		 else if (inScope == VarElementData)
                         loadVarElementData(tmp);
		 else if (inScope == VarAttributeEntryData)
                         loadAttributeEntryData(tmp, false);
                 else if (inScope == VarAttributeEntryData)
                         loadAttributeEntryData(tmp, true);
	       }
        } catch (CDFException e) {
          System.err.println("\n CDFException 3..: "+e);
	  System.exit(1);
        }
        dataBuffer.setLength(0);
    }

    /**
     * The data is a non-char type. Need to remove heading/trailing spaces 
     * if they are there. Also re-arrange the multiple data that each one  
     * is separated by a space or delimiter.
     */ 

    private String handleNumbers(String s) {

	StringBuffer stb = new StringBuffer();
	if (elementDelimiter != null) {
	  s = removeSpaces(s, elementDelimiter);
	  String[] splits = s.split(elementDelimiter, -1);
          for (int i = 0; i < splits.length; ++i) {
	    String tmp = splits[i];
	    if (tmp.length() == 0) continue;
	    stb.append(tmp).append(" ");
	  }
          stb.setLength(stb.length()-1);
	} else {
          StringTokenizer st = new StringTokenizer(s);
	  int iTokens = st.countTokens();
          if (iTokens > 0) {
            while (st.hasMoreTokens())
              stb.append(st.nextToken()).append(" ");
            stb.setLength(stb.length()-1);
          }
	}
        return stb.toString();
    }

    /**
     * It constructs the cdf file name based on the provided path and 
     * name. Checks if the new CDF file already exists. A new CDF is  
     * created.
     */
  
    private void createCDF(Attributes attrs) throws CDFException {

	if (newCDFName != null &&
	    outputDir == null) cdfName = newCDFName;
	else {
          if (attrs != null) {
            for (int i = 0; i < attrs.getLength(); i++) {
              String aName = attrs.getLocalName(i); // Attr name
              if ("".equals(aName)) aName = attrs.getQName(i);
              if (aName.equalsIgnoreCase("name")) 
		cdfName = attrs.getValue(i);
	    }
          }
	  cdfName = cdfName.substring(cdfName.lastIndexOf(
			      System.getProperty("file.separator"))+1);
	  if (outputDir != null)
		cdfName = outputDir + cdfName;
	  CDFML2CDF.checkCDFFile(cdfName);
        }

	if (backward) 
	  CDF.setFileBackward(BACKWARDFILEon);
	cdf  = CDF.create(cdfName);
	entryBlock = false;
	recordBlock = false;
	
    }

    /**
     * Properly close the newly created CDF file before program ends. 
     */

    private void closeCDF() throws CDFException {
        cdf.close();

    }

    /**
     * Modify the CDF's characteristics from its defaults.           
     */

    private void setCDF(Attributes attrs) throws CDFException {

        if (attrs != null) {
          for (int i = 0; i < attrs.getLength(); i++) {
              String aName = attrs.getLocalName(i); // Attr name
              if ("".equals(aName)) aName = attrs.getQName(i);
              if (aName.equalsIgnoreCase("fileFormat")) {
		long format = CDFUtils.getLongFormat(attrs.getValue(i));
		cdf.setFormat(format);
	      } else if (aName.equalsIgnoreCase("compression")) {
		String tmpCmp = attrs.getValue(i);
		long compression, compressionLevel;
		if (tmpCmp.length() > 4 &&
                    tmpCmp.substring(0, 4).equalsIgnoreCase("gzip")) {
		  compression = CDFUtils.getLongCompressionType(
                                                      tmpCmp.substring(0,4));
		  compressionLevel = new Long(tmpCmp.substring(5)).longValue();
		} else {
		  compression = CDFUtils.getLongCompressionType(tmpCmp);
		  if (compression == NO_COMPRESSION) compressionLevel = 0;
		  else compressionLevel = 1;
		}
		cdf.setCompression(compression, new long[] {compressionLevel});
	      } else if (aName.equalsIgnoreCase("majority")) {
		long majority = CDFUtils.getLongMajority(attrs.getValue(i));
		cdf.setMajority(majority);
	      } else if (aName.equalsIgnoreCase("encoding")) {
		long encoding = CDFUtils.getLongEncoding(attrs.getValue(i));
		cdf.setEncoding(encoding);
              } else if (aName.equalsIgnoreCase("NEGtoPOSfp0")) {
                long nEGtoPOSfp0;
		if (attrs.getValue(i).equalsIgnoreCase("ENABLE"))
                  nEGtoPOSfp0 = NEGtoPOSfp0on;
		else nEGtoPOSfp0 = NEGtoPOSfp0off;
                cdf.selectNegtoPosfp0(nEGtoPOSfp0);
              } else if (aName.equalsIgnoreCase("checksum")) {
                long checksum = CDFUtils.getLongChecksum(attrs.getValue(i));
                cdf.setChecksum(checksum);
              } else if (aName.equalsIgnoreCase("leapsecondlastupdated")) {
                String lastUpdatedStr = attrs.getValue(i);
                if (lastUpdatedStr.indexOf("-") == -1)
                  lastUpdated = new Long(lastUpdatedStr).longValue();
                else {
                  long yy, mm, dd;
                  yy = new Long(lastUpdatedStr.substring(0,4)).longValue();
                  mm = new Long(lastUpdatedStr.substring(5,7)).longValue();
                  dd = new Long(lastUpdatedStr.substring(8,10)).longValue();
                  lastUpdated = yy * 10000 + mm * 100 + dd;
                }
                cdf.setLeapSecondLastUpdated(lastUpdated);
              } else if (aName.equalsIgnoreCase("CDFCacheSize")) {
                long cdfCacheSize = new Long(attrs.getValue(i)).longValue();
                cdf.selectCDFCacheSize(cdfCacheSize);
              } else if (aName.equalsIgnoreCase("CompressCacheSize")) {
                long compressCacheSize = new Long(attrs.getValue(i)).longValue();
                cdf.selectCompressCacheSize(compressCacheSize);
              } else if (aName.equalsIgnoreCase("StageCacheSize")) {
                long stageCacheSize = new Long(attrs.getValue(i)).longValue();
                cdf.selectStageCacheSize(stageCacheSize);
	      }
          }
        }

    }

    /**
     * Create a new global attribute or a variable attribute if it is not 
     * already created.                                                   
     */

    private void createAttribute(Attributes attrs) throws CDFException {

        if (attrs != null) {
          for (int i = 0; i < attrs.getLength(); i++) {
              String aName = attrs.getLocalName(i); // Attr name
              if ("".equals(aName)) aName = attrs.getQName(i);
              if (aName.equalsIgnoreCase("name")) {
                attrName = attrs.getValue(i);
                attrName = (String) GetMyCDFData.replaceFromXMLStringName ((Object)attrName);
              }
          }
        }
        elementDelimiter = null;
        if (scope == GLOBAL_SCOPE) {
	  attribute  = Attribute.create(cdf, attrName, GLOBAL_SCOPE);
	  if (progressReport)
	    System.err.println("  Created global attribute: "+attrName+
			       " and start loading entries"); 
	} else { // Variable attribute
	  long id = cdf.getAttributeID(attrName);
	  if (id == -1) // do not yet exist 
	    attribute  = Attribute.create(cdf, attrName, VARIABLE_SCOPE);
	  else // already created
	    attribute  = cdf.getAttribute(id);
	}
    }

    /**
     * Set the characterisitcs of an attribute entry.        
     */

    private void setEntry(Attributes attrs) {

	entryNumFlag = false;
        entryDataType = -1;
        elementDelimiter = null;
        if (attrs != null) {
          for (int i = 0; i < attrs.getLength(); i++) {
              String aName = attrs.getLocalName(i); // Attr name
              if ("".equals(aName)) aName = attrs.getQName(i);
              if (aName.equalsIgnoreCase("entryNum")) { // global attribute
		entryNumFlag = true;                    // entry only
                entryNum = new Long(attrs.getValue(i)).longValue();
              } else if (aName.equalsIgnoreCase("cdfDatatype")) {
                entryDataType = CDFUtils.getDataTypeValue(attrs.getValue(i));
              } else if (aName.equalsIgnoreCase("numElements")) {
		numElements = new Long(attrs.getValue(i)).longValue();
              } else if (aName.equalsIgnoreCase("elementDelimiter")) {
		elementDelimiter = attrs.getValue(i);
	      }
          }
        }
    }

    /**
     * Set the characterisitcs of an attribute record.        
     */

    private void setRecord(Attributes attrs) {

        elementDelimiter = null;
        if (attrs != null) {
          for (int i = 0; i < attrs.getLength(); i++) {
              String aName = attrs.getLocalName(i); // Attr name
              if ("".equals(aName)) aName = attrs.getQName(i);
              if (aName.equalsIgnoreCase("recNum")) {
                recNum = new Long(attrs.getValue(i)).longValue();
              } else if (aName.equalsIgnoreCase("elementDelimiter")) {
		elementDelimiter = attrs.getValue(i);
	      }
          }
        }
    }

    /**
     * Create an entry with the provided data.                
     */

    private void createEntry(String tmp) throws CDFException {

	Object entryValue = createEntryObject(tmp);
	if (entryValue != null)
          if (scope == GAttributes) {    // use the provided entry number or
	    if (!entryNumFlag) entryNum++; // auto-increase the previous one 
            Entry.create(attribute, entryNum, entryDataType, entryValue);
          } else {
            Entry.create(attribute, var.getID(), entryDataType, entryValue);
          }
    }

    /**
     * Create a proper object based on the data type and the provided 
     * data. The object is an array of comparable type.               
     */
 
    private Object createEntryObject(String str) throws CDFException {

        String[] splits;
        splits = str.split(multiDelimiter, -1);
        int iTokens = splits.length;
	Object entryValue = null;
        if (entryDataType == CDF_INT1 || entryDataType == CDF_BYTE) {
	  entryValue = new byte[iTokens];
	  for (int i = 0; i < iTokens; i++) 
	    ((byte[]) entryValue)[i] = new Byte(splits[i]).byteValue();
        } else if (entryDataType == CDF_INT2 || entryDataType == CDF_UINT1) {
	  entryValue = new short[iTokens];
          for (int i = 0; i < iTokens; i++)
            ((short[]) entryValue)[i] = new Short(splits[i]).shortValue();
        } else if (entryDataType == CDF_INT4 || entryDataType == CDF_UINT2) {
	  entryValue = new int[iTokens];
          for (int i = 0; i < iTokens; i++)
            ((int[]) entryValue)[i] = new Integer(splits[i]).intValue();
        } else if (entryDataType == CDF_UINT4 || entryDataType == CDF_INT8) {
	  entryValue = new long[iTokens];
          for (int i = 0; i < iTokens; i++)
            ((long[]) entryValue)[i] = new Long(splits[i]).longValue();
        } else if (entryDataType == CDF_REAL4 || entryDataType == CDF_FLOAT) {
	  entryValue = new float[iTokens];
          for (int i = 0; i < iTokens; i++)
            ((float[]) entryValue)[i] = new Float(splits[i]).floatValue();
        } else if (entryDataType == CDF_REAL8 ||
                   entryDataType == CDF_DOUBLE) {
	  entryValue = new double[iTokens];
          for (int i = 0; i < iTokens; i++)
            ((double[]) entryValue)[i] = new Double(splits[i]).doubleValue();
        } else if (entryDataType == CDF_CHAR || entryDataType == CDF_UCHAR) {
          String newStr = (String)
                             GetMyCDFData.replaceFromXMLStringData((String)str);
          splits = newStr.split(multiDelimiter, -1);
          String myStr = (String) newStr;
          if (iTokens > 1) {
            String[] strs = new String[iTokens];
            for (int i = 0; i < iTokens; i++) {
              strs[i] = splits[i];
            }
            entryValue = strs;
          } else
            entryValue = newStr;
        } else if (entryDataType == CDF_EPOCH) {
          double[] entryValueX;
          String str2 = splits[0];
          if (str2.indexOf("-") == -1) {
            entryValueX = new double[iTokens];
            for (int i = 0; i < iTokens; i++) {
              ((double[]) entryValueX)[0] = new Double(splits[i]).doubleValue();
            }
          } else {
            if (str2.length() == 11) {
              entryValueX = new double[iTokens/2];
              for (int i = 0; i < iTokens/2; i++) {
                str2 = new String(splits[2*i]+" "+splits[2*i+1]);
                entryValueX[i] = Epoch.parse(str2);
              }
            } else { /* ISO 8601 format. */
              entryValueX = new double[iTokens];
              for (int i = 0; i < iTokens; i++) {
                if (str2.length() == 24)
                    entryValueX[i] = Epoch.parse3(splits[i]);
                else if (str2.length() == 23)
                    entryValueX[i] = Epoch.parse4(splits[i]);
              }
            }
          }
          entryValue = entryValueX;
        } else if (entryDataType == CDF_EPOCH16) {
          String str2 = splits[0];
          double[] entryValueX;
          if (str2.indexOf("-") == -1) {
            entryValueX = new double[iTokens];
            for (int i = 0; i < iTokens; i++) {
              entryValueX[i] = new Double(splits[i]).doubleValue();
            }
          } else {
            double[] twoDouble = new double[2];
            if (str2.indexOf("\"") > -1)
                 str2 = str2.replaceAll("\"", " ").trim();
            if (str2.length() == 11) {
              entryValueX = new double[iTokens];
              String str3 = str2 + " " + splits[1];
              if (str3.indexOf("\"") > -1)
                 str3 = str3.replaceAll("\"", " ").trim();
              for (int i = 0; i < iTokens/2; i++) {   
                twoDouble = (double[]) Epoch16.parse(str3);
                entryValueX[2*i] = twoDouble[0];
                entryValueX[2*i+1] = twoDouble[1];
              }
            } else { /* ISO 8601 format. */
              entryValueX = new double[2*iTokens];
              for (int i = 0; i < iTokens; i++) {
                if (str2.length() == 36)
                  twoDouble = (double[]) Epoch16.parse3(str2);
                else {
                  if (str2.length() == 32)
                    twoDouble = (double[]) Epoch16.parse4(str2);
                  else if (str2.length() == 33) 
                    twoDouble = (double[]) Epoch16.parse4(str2.substring(0,33));
                  else {
                    System.err.println("*** Error: cdfml file has an invalid"+
                                       " epoch16 data: "+str2);
                    System.exit(1);
                  }
                }
                entryValueX[2*i] = twoDouble[0];
                entryValueX[2*i+1] = twoDouble[1];
              }
            }
          }
          entryValue = entryValueX;
        } else if (entryDataType == CDF_TIME_TT2000) {
          entryValue = new long[iTokens];
          for (int i = 0; i < iTokens; i++) {
            String str2;
            if (splits[i].indexOf("\"") > -1)
              str2 = splits[i].replaceAll("\"", " ").trim();
            else
              str2 = splits[i];
            if (str2.indexOf("-") == -1) 
              ((long[]) entryValue)[i] = new Long(str).longValue();
            else {
	      if ((int)lastUpdated == -1 || (int)lastUpdated == 0) 
                  ((long[]) entryValue)[i] = CDFTT2000.fromUTCstring(str2);
	      else
	        ((long[]) entryValue)[i] =
                   CDFTT2000.parseTT2000withBasedLeapDay(splits[i],
                                                         (int)lastUpdated);
            }
          }
        } else
	  entryValue = null;
	return entryValue;

    }

    /**
     * Acquires the variable name from the variable element's attribute. 
     */

    private void setVariable(Attributes attrs) {

        if (attrs != null) {
          for (int i = 0; i < attrs.getLength(); i++) {
              String aName = attrs.getLocalName(i); // Attr name
              if ("".equals(aName)) aName = attrs.getQName(i);
              if (aName.equalsIgnoreCase("name")) {
                varName = attrs.getValue(i);
                varName = (String) GetMyCDFData.replaceFromXMLStringName ((Object) varName);
              }
          }
        }

    }

    /**
     * A variable's characterists are acquired from the attributes of the 
     * cdfVarInfo element. A variable is created and its defaults are     
     * reset if any optional attributes are provided.                     
     */

    private void createVariable(Attributes attrs) throws CDFException {
	long compression = 0, compressionLevel = 0;
	boolean dimSizesFlag, dimVariancesFlag;
	boolean compressionFlag, padValueFlag;
	boolean sparseRecordsFlag, blockingFactorFlag, initialRecordsFlag;
	boolean cacheSizeFlag, reservePercentFlag, recordsAllocateFlag;
	Object padValue = null;
	long sparseRecords = -1;
	long blockingFactor = -1;
	long initialRecords = -1;
	long recordsAllocate = -1;
	long cacheSize = -1;
	long reservePercent = -1;

        if (attrs != null) {
	  dimSizesFlag = false;
	  dimVariancesFlag = false;
	  compressionFlag = false;
	  padValueFlag = false;
	  sparseRecordsFlag = false;
	  blockingFactorFlag = false;
	  initialRecordsFlag = false;
	  recordsAllocateFlag = false;
          cacheSizeFlag = false;
          reservePercentFlag = false;
	  varDataType = -1;
	  dim = -1;
          for (int i = 0; i < attrs.getLength(); i++) {
              String aName = attrs.getLocalName(i); // Attr name
              if ("".equals(aName)) aName = attrs.getQName(i);
              if (aName.equalsIgnoreCase("cdfDatatype")) {
                varDataType = CDFUtils.getDataTypeValue(attrs.getValue(i));
              } else if (aName.equalsIgnoreCase("dim")) {
                dim = new Long(attrs.getValue(i)).longValue();
		int dimNo = (int) (dim > 0 ? dim : 1);
		dimSizes = new long[dimNo];
		dimVariances = new long[dimNo];
		dimIndex = new long[dimNo];
              } else if (aName.equalsIgnoreCase("dimSizes")) {
		dimSizesFlag = true;
                String tmp = attrs.getValue(i);
	        StringTokenizer st = new StringTokenizer(tmp, ",");
		int iTokens = st.countTokens();
		if (dim != -1) {
		  if (dim != iTokens) {
		    st = new StringTokenizer(tmp, " ");
		    iTokens = st.countTokens();
		    if (dim != iTokens) {
		      System.err.println("Var:"+varName+" dim="+dim+
                                         " dimSizes="+iTokens+" don't match");
		      return;
		    }
		  }
		}
		if (dimSizes == null) dimSizes = new long[st.countTokens()];
	        if (!"".equals(tmp) && iTokens > 0) {
		   int ii = 0;
	           while (st.hasMoreTokens()) 
		     dimSizes[ii++] = new Long((String)st.nextToken()).
                                          longValue();
		} else
                  dimSizes[0] = 0;
              } else if (aName.equalsIgnoreCase("dimVariances")) {
		dimVariancesFlag = true;
                String tmp = attrs.getValue(i);
                StringTokenizer st = new StringTokenizer(tmp, ",");
                int iTokens = st.countTokens();
                if (dim != -1) {
                  if (dim != iTokens) {
                    st = new StringTokenizer(tmp, " ");
                    iTokens = st.countTokens();
                    if (dim != iTokens) {
                      System.err.println("Var:"+varName+" dim="+dim+
                                         " dimVariances="+iTokens+
                                         " don't match");
                      return;
                    }
                  }
                }
		if (dimVariances == null)
                  dimVariances = new long[st.countTokens()];
                if (!"".equals(tmp) && iTokens > 0) {
                   int ii = 0;
                   while (st.hasMoreTokens()) {
                     if (((String)st.nextToken()).equalsIgnoreCase("VARY")) 
			dimVariances[ii] = VARY;
                     else
			dimVariances[ii] = NOVARY;
		     ii++;
                   }
                } else
                dimVariances[0] = 0;
              } else if (aName.equalsIgnoreCase("recVariance")) {
                if ((attrs.getValue(i)).equalsIgnoreCase("VARY"))
		  recVariance = VARY;
                else
		  recVariance = NOVARY;
              } else if (aName.equalsIgnoreCase("numElements")) {
                numElements = new Long(attrs.getValue(i)).longValue();
              } else if (aName.equalsIgnoreCase("compression")) {
                String tmpCmp = attrs.getValue(i);
                if (tmpCmp.length() > 4 && 
                    tmpCmp.substring(0, 4).equalsIgnoreCase("gzip")) {
                  compression = CDFUtils.getLongCompressionType(
                                                      tmpCmp.substring(0,4));
                  compressionLevel = new Long(tmpCmp.substring(5)).longValue();
                } else {
                  compression = CDFUtils.getLongCompressionType(tmpCmp);
                  if (compression == NO_COMPRESSION) compressionLevel = 0;
                  else compressionLevel = 1;
                }
		compressionFlag = true;
              } else if (aName.equalsIgnoreCase("sparseRecords")) {
                sparseRecordsFlag = true;
                sparseRecords = CDFUtils.getLongSparseRecord(attrs.getValue(i));
              } else if (aName.equalsIgnoreCase("blockingFactor")) {
                blockingFactorFlag = true;
                blockingFactor = new Long(attrs.getValue(i)).longValue();
              } else if (aName.equalsIgnoreCase("numInitialRecords")) {
                initialRecordsFlag = true;
                initialRecords = new Long(attrs.getValue(i)).longValue();
              } else if (aName.equalsIgnoreCase("numRecordsAllocate")) {
		if (!compressionFlag) {
                  recordsAllocateFlag = true;
                  recordsAllocate = new Long(attrs.getValue(i)).longValue();
		}
              } else if (aName.equalsIgnoreCase("cacheSize")) {
                cacheSizeFlag = true;
                cacheSize = new Long(attrs.getValue(i)).longValue();
              } else if (aName.equalsIgnoreCase("reservePercent")) {
		if (compressionFlag) {
                  reservePercentFlag = true;
                  reservePercent = new Long(attrs.getValue(i)).longValue();
		}
              } else if (aName.equalsIgnoreCase("padValue")) {
		padValueFlag = true;
                String tmp = attrs.getValue(i);
		if (varDataType == CDF_INT1 || varDataType == CDF_BYTE) {
		  padValue = new Byte(tmp);
		} else if (varDataType == CDF_INT2 ||
                           varDataType == CDF_UINT1) {
		  padValue = new Short(tmp);
		} else if (varDataType == CDF_INT4 ||
                           varDataType == CDF_UINT2) {
		  padValue = new Integer(tmp);
		} else if (varDataType == CDF_UINT4 ||
                           varDataType == CDF_INT8) {
		  padValue = new Long(tmp);
		} else if (varDataType == CDF_REAL4 ||
                           varDataType == CDF_FLOAT) {
		  padValue = new Float(tmp);
		} else if (varDataType == CDF_REAL8 ||
                           varDataType == CDF_DOUBLE) {
		  padValue = new Double(tmp);
		} else if (varDataType == CDF_CHAR ||
                           varDataType == CDF_UCHAR) {
                  padValue = (String)
                             GetMyCDFData.replaceFromXMLStringData(tmp);
		} else if (varDataType == CDF_EPOCH) {
                  if (tmp.indexOf("-") == -1)
                    padValue = new Double(tmp);
                  else {
                    if (tmp.length() == 24 &&
                        !tmp.substring(23).equalsIgnoreCase("Z") )
		      padValue = new Double(Epoch.parse(tmp));
                    else /* ISO 8601 format. */
                      if (tmp.length() == 24)
                        padValue = new Double(Epoch.parse3(tmp));
                      else if (tmp.length() == 23)
                        padValue = new Double(Epoch.parse4(tmp));
                      else
                        padValue = new Double(tmp);
                  }
                } else if (varDataType == CDF_EPOCH16) {
                  padValue = new double[2];
                  if (tmp.length() == 36 &&
                      !tmp.substring(35).equalsIgnoreCase("Z"))
		    padValue = Epoch16.parse(tmp);
                  else { /* ISO 8601 format. */
                    if (tmp.length() == 36)
                      padValue = Epoch16.parse3(tmp);
                    else if (tmp.length() == 32)
                      padValue = Epoch16.parse4(tmp);
                    else if (tmp.length() == 33)
                      padValue = Epoch16.parse4(tmp.substring(0,33));
                    else {
                      System.err.println("*** Error: cdfml file has an"+
                                         " invalid epoch16 data: "+tmp);
                      System.exit(1);
                    }
                  }
                } else if (varDataType == CDF_TIME_TT2000) {
                    if (tmp.indexOf("-") == -1) 
                      padValue = new Long(tmp);
                    else {
		      if ((int)lastUpdated == -1 || (int)lastUpdated == 0)
                        padValue = new Long(CDFTT2000.fromUTCstring(tmp));
		      else
                        padValue = new Long(
                                     CDFTT2000.parseTT2000withBasedLeapDay(tmp,
                                                          (int)lastUpdated));
                    }
                }
              }
          }
	  if (dim > 0) { 
	    if (!dimSizesFlag || !dimVariancesFlag) {
		System.err.println("\nError... dimSizes or dimVariances not "+
                                   "provided for variable:"+varName+"!");
		return;
	    } 
	    phyDims = (int) dim;
	    physicalSize = 1;
	    for (int i = 0; i < dim; i++) physicalSize *= (int) dimSizes[i];
	  } else {
	     dimSizes[0] = 1;
	     dimVariances[0] = VARY;
             phyDims = 1;
             physicalSize = 1;
          }
	  var = Variable.create(cdf, varName, varDataType, numElements, dim,
                                dimSizes, recVariance, dimVariances);
	  if (progressReport) {
	    String tail = (loadData) ? " and start loading its data" : " ";
	    System.err.println("  Created variable "+var.getID()+": "+
                               varName+tail);
	  }
	  if (compressionFlag) 
		var.setCompression(compression, new long[] {compressionLevel});
	  if (padValueFlag) var.setPadValue(padValue);
	  if (sparseRecordsFlag) var.setSparseRecords(sparseRecords);
          if (blockingFactorFlag) var.setBlockingFactor(blockingFactor);
	  if (cacheSizeFlag) var.selectCacheSize(cacheSize);
	  if (reservePercentFlag) var.selectReservePercent(reservePercent);
	  if (initialRecordsFlag && (initialRecords > 0)) 
	    var.setInitialRecords(initialRecords);
	  if (recordsAllocateFlag && (recordsAllocate > 0)) 
  	    var.allocateRecords(recordsAllocate);
        }

    }

    /**
     * Converts a full variable record data, single or multiple values, 
     * into a proper object and loads the object into the variable.     
     * It needs to reset the arrays that are used for the variable's    
     * dimension information which time a new variable is encountered.  
     */ 

    private void loadVarRecordData(String tmp) throws CDFException {
        int ij;
        String pmt = new String(tmp);
        String[] st;
        st = tmp.split(multiDelimiter, -1);
        int iTokens = st.length;
	recInterval = 1;
	recCount = 1;
	if (dimIndices == null) {
          dimIndices = new long[phyDims];
          dimCounts = new long[phyDims];
          dimIntervals = new long[phyDims];
	  for (int i = 0; i < phyDims; i++) {
            dimIndices[i] = 0;
            dimCounts[i] = dimSizes[i];
            dimIntervals[i] = 1;
	  }
	  dataObject = createObject(phyDims, dimSizes, varDataType);
        }
	Object dataValues = null;
        int items;
        if (varDataType == CDF_INT1 || varDataType == CDF_BYTE) {
	  dataValues = (byte[]) convertNumberData(iTokens, st, varDataType);
        } else if (varDataType == CDF_INT2 || varDataType == CDF_UINT1) {
	  dataValues = (short[]) convertNumberData(iTokens, st, varDataType);
        } else if (varDataType == CDF_INT4 || varDataType == CDF_UINT2) {
	  dataValues = (int[]) convertNumberData(iTokens, st, varDataType);
        } else if (varDataType == CDF_UINT4 || varDataType == CDF_INT8) {
	  dataValues = (long[]) convertNumberData(iTokens, st, varDataType);
        } else if (varDataType == CDF_REAL4 || varDataType == CDF_FLOAT) {
	  dataValues = (float[]) convertNumberData(iTokens, st, varDataType);
        } else if (varDataType == CDF_REAL8 || varDataType == CDF_DOUBLE) {
	  dataValues = (double[]) convertNumberData(iTokens, st, varDataType);
        } else if (varDataType == CDF_CHAR || varDataType == CDF_UCHAR) {
	  dataValues = new byte[(int)(physicalSize*numElements)];
	  byte sp = (byte) 0;
	  for (ij = 0; ij < physicalSize*numElements; ij++) 
	     ((byte[]) dataValues)[ij] = (byte) sp;
	  if (elementDelimiter != null) { // multiple data entries assumed
            if (!valueElement) tmp = removeSpaces(tmp, elementDelimiter);
            String[] st2;
            st2 = tmp.split(multiDelimiter, -1);
	    String aTemp;
	    ij = 0;
	    iTokens = 0;
            for (int ik = 0; ik < st2.length; ++ik) {
              aTemp = st2[ik];
              if (aTemp.length() == 0) continue;
              System.arraycopy(aTemp.getBytes(), 0, (byte[]) dataValues,
                               (int) (ij*numElements), aTemp.length());
              ij++;
              iTokens++;
              if (ij == physicalSize) break;
            }
	  } else {
            String[] st2;
            st2 = tmp.split(multiDelimiter, -1);
            String aTemp;
            ij = 0;
            iTokens = 0;
            for (int ik = 0; ik < st2.length; ++ik) {
              aTemp = st2[ik];
              if (aTemp.length() == 0) continue;
              System.arraycopy(aTemp.getBytes(), 0, (byte[]) dataValues,
                               (int) (ij*numElements), aTemp.length());
              ij++;
              iTokens++;
              if (ij == physicalSize) break;
            }
          }
        } else if (varDataType == CDF_EPOCH) {
          String[] itok;
          double[] dataValuesX;
          itok = tmp.split(multiDelimiter, -1);
          String tmp1 = itok[0];
          String epoch;
          if (tmp1.indexOf("-") == -1) {
            dataValuesX = new double[iTokens];
            for (ij = 0; ij < iTokens; ++ij)
              dataValuesX[ij] = 
                                  new Double(itok[ij]).doubleValue();
          } else {
            if (tmp1.length() == 11) { // in "mmm-dd-yyyy hh:mm:ss.sss" form
              items = iTokens / 2;
	      dataValuesX = new double[items];
	      for (ij = 0; ij < items; ++ij) {
                epoch = itok[2*ij] + " " + itok[2*ij+1];
	        dataValuesX[ij] = Epoch.parse(epoch);
              }
            } else { /* ISO 8601 format. */
              dataValuesX = new double[iTokens];
              for (ij = 0; ij < iTokens; ++ij) {
                epoch = itok[ij];
                if (epoch.length() == 24)
                  dataValuesX[ij] = Epoch.parse3(epoch);
                else
                  dataValuesX[ij] = Epoch.parse4(epoch);
              }
            }
          }
          dataValues = dataValuesX;
        } else if (varDataType == CDF_EPOCH16) {
           String[] itok;
           itok = tmp.split(multiDelimiter, -1);
           Object twoDouble = new double[2];
           String strx = itok[0];
           if (strx.length() == 11) { // in mmm-dd-yyyy form
             items =  iTokens / 2;
	     dataValues = new double[iTokens];
	     for (ij = 0; ij < items; ij++) {
               String epoch16 = itok[2*ij] + " " + itok[2*ij+1];
	       twoDouble = Epoch16.parse(epoch16);
	       ((double[]) dataValues)[2*ij] = ((double[]) twoDouble)[0];
	       ((double[]) dataValues)[2*ij+1] = ((double[]) twoDouble)[1];
	     }
           } else { /* ISO 8601 format. */
             String str = itok[0];
             dataValues = new double[iTokens*2];
             int ik;
             for (ij = 0, ik = 0; ij < iTokens; ij++) {
               if (str.length() == 32) twoDouble = Epoch16.parse4(str);
               else if (str.length() == 33)
                  twoDouble = Epoch16.parse4(str.substring(0,33));
               else {
                 System.err.println("*** Error: cdfml file has an invalid "+
                                    "epoch16 data: "+str);
                 System.exit(1);
               }
               ((double[]) dataValues)[ik++] = ((double[]) twoDouble)[0];
               ((double[]) dataValues)[ik++] = ((double[]) twoDouble)[1];
             }
           }
        } else if (varDataType == CDF_TIME_TT2000) {
           dataValues = new long[iTokens];
           String[] tok2;
           tok2 = tmp.split(multiDelimiter, -1);
           String tmp1 = tok2[0];

           if (tmp1.indexOf("-") == -1) {
            for (ij = 0; ij < iTokens; ++ij)
              ((long[]) dataValues)[ij] = new Long(tok2[ij]).longValue();
           } else {
             for (ij = 0; ij < iTokens; ++ij) {
	       if ((int)lastUpdated == -1 || (int)lastUpdated == 0) 
                 ((long[]) dataValues)[ij] = 
                          CDFTT2000.fromUTCstring(tok2[ij]);
  	       else
                 ((long[]) dataValues)[ij] = 
                          CDFTT2000.parseTT2000withBasedLeapDay(tok2[ij],
                                                             (int)lastUpdated);
	     }
           }
        }
	if (dataValues != null) {
	  var.putHyperData(recNum, recCount, recInterval,
			   dimIndices, dimCounts, dimIntervals,
			   dataValues);
	  recNum++;
	}

    }

    /**
     * Similar to loadVarRecordData. But, it only writes one data value at 
     * a time. Indices are provided through the attribute.                 
     */

    private void loadVarElementData(String tmp) throws CDFException {
	StringTokenizer st = new StringTokenizer(indexString, ",");
	int iTokens = st.countTokens();

	for (int i = 0; i < phyDims; i++) 
	  dimIndex[i] = new Long(st.nextToken()).longValue();

	Object dataValue = null;
        if (varDataType == CDF_INT1 || varDataType == CDF_BYTE) {
	  dataValue = new Byte(tmp);
        } else if (varDataType == CDF_INT2 || varDataType == CDF_UINT1) {
	  dataValue = new Short(tmp);
        } else if (varDataType == CDF_INT4 || varDataType == CDF_UINT2) {
	  dataValue = new Integer(tmp);
        } else if (varDataType == CDF_UINT4 || varDataType == CDF_INT8) {
	  dataValue = new Long(tmp);
        } else if (varDataType == CDF_REAL4 || varDataType == CDF_FLOAT) {
	  dataValue = new Float(tmp);
        } else if (varDataType == CDF_REAL8 || varDataType == CDF_DOUBLE) {
	  dataValue = new Double(tmp);
        } else if (varDataType == CDF_CHAR || varDataType == CDF_UCHAR) {
          tmp = (String) GetMyCDFData.replaceFromXMLStringData((String)tmp);
	  if (tmp.length() > numElements)
            dataValue = tmp.substring(0, (int) numElements);
	  else dataValue = tmp;
        } else if (varDataType == CDF_EPOCH) {
          if (tmp.indexOf("-") == -1)
            dataValue = new Double(tmp.trim());
          else {
            if (tmp.trim().length() != 23)
	      dataValue = new Double(Epoch.parse(tmp));
            else /* ISO 8601 format. */
              dataValue = new Double(Epoch.parse4(tmp));
          }
        } else if (varDataType == CDF_EPOCH16) {
          dataValue = new double[2];
          if (tmp.trim().length() != 32 && tmp.trim().length() != 33)
	    dataValue = Epoch16.parse(tmp);
          else { /* ISO 8601 format. */
            if (tmp.trim().length() == 32) dataValue = Epoch16.parse4(tmp);
            else if (tmp.trim().length() == 33)
              dataValue = Epoch16.parse4(tmp.substring(0,33));
            else {
              System.err.println("*** Error: cdfml file has an invalid"+
                                 " epoch16 data: "+tmp);
              System.exit(1);
            }
          }
        } else if (varDataType == CDF_TIME_TT2000) {
          if (tmp.indexOf("-") == -1)
            dataValue = new Long(tmp.trim());
          else {
	    if ((int)lastUpdated == -1 || (int)lastUpdated == 0)
              dataValue = new Long(CDFTT2000.fromUTCstring(tmp));
	    else
              dataValue = 
               new Long(CDFTT2000.parseTT2000withBasedLeapDay(tmp,
                                                          (int)lastUpdated));
          }
        }
	if (dataValue != null) 
	  var.putSingleData(recNum, dimIndex, dataValue);

    }

    /**
     * Find out the CDF epoch data type from a dateValue string.
     */

    private long findDateValueDataType(String tmp) {
        tmp = tmp.trim();
        int len = tmp.length();
        StringTokenizer st = new StringTokenizer(tmp, " ");
        int iTokens = st.countTokens();
        long dataType = -1;
        if (len <= 24) dataType = CDF_EPOCH;
        else if (len <= 30) dataType = CDF_TIME_TT2000;
        else if (len <= 36) dataType = CDF_EPOCH16;
        else {
           String firstOne = st.nextToken();
           int len2 = firstOne.length();
           int len3;
           if (len2 == 11) { // as mmm-dd-yyyy form
             len3 = (len - (iTokens / 2 - 1)) / (iTokens / 2);
             if (len == 24) dataType = CDF_EPOCH;
             else dataType = CDF_EPOCH16;
           } else {
             len3 = (len - 1) / iTokens;
             if (len3 <= 24) dataType = CDF_EPOCH;
             else if (len3 <= 30) dataType = CDF_TIME_TT2000;
             else if (len3 <= 36) dataType = CDF_EPOCH16;
           }
        }
        return dataType;
     }

     /**
     * Write out the variable's attribute entry.
     */

    private void loadAttributeEntryData(String tmp, boolean gAttr)
                                        throws CDFException {
        tmp = tmp.trim();
        int len = tmp.length();
        String[] st;
        st = tmp.split(multiDelimiter, -1);
        int iTokens = st.length;
        int i;
	Object dataValue = null;
        if (entryDataType == CDF_INT1 || entryDataType == CDF_BYTE) {
          if (iTokens == 1)
	    dataValue = new Byte(tmp);
          else {
            byte[] dataValue2 = new byte[iTokens];
            for (i = 0; i < iTokens; ++i)
              dataValue2[i] = new Byte(st[i]).byteValue();
            dataValue = dataValue2;
          }
        } else if (entryDataType == CDF_INT2 || entryDataType == CDF_UINT1) {
          if (iTokens == 1)
            dataValue = new Short(tmp);
          else {
            short[] dataValue2 = new short[iTokens];
            for (i = 0; i < iTokens; ++i)
              dataValue2[i] = new Short(st[i]).shortValue();
            dataValue = dataValue2;
          }
        } else if (entryDataType == CDF_INT4 || entryDataType == CDF_UINT2) {
          if (iTokens == 1)
            dataValue = new Integer(tmp);
          else {
            int[] dataValue2 = new int[iTokens];
            for (i = 0; i < iTokens; ++i)
              dataValue2[i] = new Integer(st[i]).intValue();
            dataValue = dataValue2;
          }
        } else if (entryDataType == CDF_UINT4 || entryDataType == CDF_INT8) {
          if (iTokens == 1)
            dataValue = new Long(tmp);
          else {
            long[] dataValue2 = new long[iTokens];
            for (i = 0; i < iTokens; ++i)
              dataValue2[i] = new Long(st[i]).longValue();
            dataValue = dataValue2;
          }
        } else if (entryDataType == CDF_REAL4 || entryDataType == CDF_FLOAT) {
          if (iTokens == 1)
            dataValue = new Float(tmp);
          else {
            float[] dataValue2 = new float[iTokens];
            for (i = 0; i < iTokens; ++i)
              dataValue2[i] = new Float(st[i]).floatValue();
            dataValue = dataValue2;
          }
        } else if (entryDataType == CDF_REAL8 ||
                   entryDataType == CDF_DOUBLE) {
          if (iTokens == 1)
            dataValue = new Double(tmp);
          else {
            double[] dataValue2 = new double[iTokens];
            for (i = 0; i < iTokens; ++i)
              dataValue2[i] = new Double(st[i]).doubleValue();
            dataValue = dataValue2;
          }
        } else if (entryDataType == CDF_CHAR || entryDataType == CDF_UCHAR) {
          dataValue = (String) GetMyCDFData.replaceFromXMLStringData(tmp);
        } else if (entryDataType == CDF_EPOCH) {
          if (tmp.indexOf("-") == -1) {
            if (iTokens == 1)
              dataValue = new Double(tmp.trim());
            else {
              double[] dataValue2 = new double[iTokens];
              for (i = 0; i < iTokens; ++i)
                dataValue2[i] = new Double(st[i]).doubleValue();
              dataValue = dataValue2;
            }
          } else {
            if (tmp.substring(len-1).toLowerCase().equals("z")) {
              if (iTokens == 1)
                dataValue = new Double(Epoch.parse3(tmp));
              else {
                double[] dataValue2 = new double[iTokens];
                for (i = 0; i < iTokens; ++i) 
                  dataValue2[i] = Epoch.parse3(st[i]);
                dataValue = dataValue2;
              }
            } else {
              if (!tmp.substring(10,11).toLowerCase().equals("t")) {
                iTokens = iTokens / 2;
                if (iTokens == 1)
                  dataValue = new Double(Epoch.parse(tmp));
                else {
                  double[] dataValue2 = new double[iTokens];
                  for (i = 0; i < iTokens; ++i)
                    dataValue2[i] = Epoch.parse(st[2*i]+" "+
                                                st[2*i+1]);
                  dataValue = dataValue2;
                }
              } else {
                if (iTokens == 1)
                  dataValue = new Double(Epoch.parse4(tmp));
                else {
                  double[] dataValue2 = new double[iTokens];
                  for (i = 0; i < iTokens; ++i)
                    dataValue2[i] = Epoch.parse4(st[i]);
                  dataValue = dataValue2;
                }
              }
            }
          }
        } else if (entryDataType == CDF_EPOCH16) {
          double[] epoch16 = new double[2];
          if (tmp.substring(len-1).toLowerCase().equals("z")) {
            if (iTokens == 1) {
              if (len == 36) 
                dataValue = Epoch16.parse3(tmp);
              else
                dataValue = Epoch16.parse4(tmp.substring(0,32));
            } else {
              double[] dataValue2 = new double[2*iTokens];
              if (((len-iTokens+1)%36) == 0) { // encode3
                for (i = 0; i < iTokens; ++i) {
                  epoch16 = (double[]) Epoch16.parse3(st[i]);
                  dataValue2[i*2] = epoch16[0];
                  dataValue2[i*2+1] = epoch16[1];
                }
              } else {
                for (i = 0; i < iTokens; ++i) {
                  epoch16 = (double[]) Epoch16.parse4(st[i].
                                                      substring(0,32));
                  dataValue2[i*2] = epoch16[0];
                  dataValue2[i*2+1] = epoch16[1];
                }
              }
              dataValue = dataValue2;
            }
          } else {
            if (!tmp.substring(10,11).toLowerCase().equals("t")) {
              iTokens = iTokens / 2;
              if (iTokens == 1) 
                dataValue = Epoch16.parse(tmp);
              else {
                double[] dataValue2 = new double[iTokens*2];
                for (i = 0; i < iTokens; ++i) {
                  epoch16 = (double[]) Epoch16.parse(st[2*i]+" "+
                                                     st[2*i+1]);
                  dataValue2[i*2] = epoch16[0];
                  dataValue2[i*2+1] = epoch16[1];
                }
                dataValue = dataValue2;
              }
            } else { //parse4
              if (iTokens == 1) 
                dataValue = Epoch16.parse4(tmp);
              else {
                double[] dataValue2 = new double[iTokens];
                for (i = 0; i < iTokens; ++i) {
                  epoch16 =(double[])  Epoch16.parse4(st[i]);
                  dataValue2[i*2] = epoch16[0];
                  dataValue2[i*2+1] = epoch16[1];
                }
                dataValue = dataValue2;
              }
            }
          }
        } else if (entryDataType == CDF_TIME_TT2000) {
          if (tmp.indexOf("-") == -1) {
            if (iTokens == 1)
              dataValue = new Long(tmp.trim());
            else {
              long[] dataValue2 = new long[iTokens];
              for (i = 0; i < iTokens; ++i)
                dataValue2[i] = new Long(st[i]).longValue();
              dataValue = dataValue2;
            }
          } else {
            if (iTokens == 1) {
              if (tmp.substring(len-1).toLowerCase().equals("z"))
                dataValue = new Long(CDFTT2000.parse(tmp.substring(0,29)));
              else
                dataValue = new Long(CDFTT2000.parse(tmp));
            } else {
              long[] dataValue2 = new long[iTokens];
              if (((len-iTokens)%29) == 0) {
                for (i = 0; i < iTokens; ++i)
                  dataValue2[i] = CDFTT2000.parse(st[i]);
              } else {
                for (i = 0; i < iTokens; ++i) 
                  dataValue2[i] = 
                           CDFTT2000.parse(st[i].substring(0,29));
              }
              dataValue = dataValue2;
            }
          }
        }
	if (dataValue != null) {
          if (gAttr)
            Entry.create(attribute, entry.getID(), entryDataType, dataValue);
          else 
            Entry.create(attribute, var.getID(), entryDataType, dataValue);
        }
    }

    /**
     * An object representing the full variable record data is created based 
     * on its CDF data type and dimensionality. The object can be           
     * multi-dimensional.                                                  
     */

    private Object createObject(long dims, long[] dimSizes, long dataType) 
		   throws CDFException {

	Object one = null;
	Class arrayClass = null;
	int[] newDimsSizes = new int[(int)dims];
	for (int i=0; i<dims; i++) newDimsSizes[i] = (int) dimSizes[i];
	if (dataType == CDF_EPOCH16) {
	  if (dims == 0) 
	    newDimsSizes[0] = 2;
	  else
	    newDimsSizes[(int)dims-1] = 2 * newDimsSizes[(int)dims-1];
	}
    
        switch ((int)dataType) {
          case (int)CDF_CHAR:
          case (int)CDF_UCHAR:
            arrayClass = new String().getClass();
            break;
          case (int)CDF_BYTE:
          case (int)CDF_INT1:  arrayClass = Byte.TYPE;          break;
          case (int)CDF_INT2:
          case (int)CDF_UINT1: arrayClass = Short.TYPE;         break;
          case (int)CDF_INT4:
          case (int)CDF_UINT2: arrayClass = Integer.TYPE;       break;
          case (int)CDF_UINT4:
          case (int)CDF_INT8:
          case (int)CDF_TIME_TT2000: arrayClass = Long.TYPE;    break;
          case (int)CDF_REAL4:
          case (int)CDF_FLOAT: arrayClass = Float.TYPE;         break;
          case (int)CDF_REAL8:
          case (int)CDF_DOUBLE:
          case (int)CDF_EPOCH: 
	  case (int)CDF_EPOCH16: arrayClass = Double.TYPE;      break;
          default:
            break;
        } /* switch (dataType) */

        try {
            one = Array.newInstance(arrayClass, newDimsSizes);
        } catch (Exception e) {
            throw new CDFException(BAD_ARGUMENT);
        }
	return one;

    }

    /**
     * The data values that will be filled into one single variable record is 
     * moved to an 1-dimensional array of similar data type. This deals with
     * only number data.
     */

    private Object convertNumberData(int itemCounts, String[] st,
                                     long dataType) throws CDFException {

        Object one = null;

        switch ((int)dataType) {
          case (int)CDF_CHAR:
          case (int)CDF_UCHAR:
	    one = new String[itemCounts];
	    for (int i = 0; i< itemCounts; i++) {
              String str = st[i];
              ((String[]) one)[i] = (String)
                                  GetMyCDFData.replaceFromXMLStringData(str);
            }
            break;
          case (int)CDF_BYTE:
          case (int)CDF_INT1:  
		one = new byte[itemCounts];
		for (int i = 0; i< itemCounts; i++) 
		  ((byte[]) one)[i] = new Byte(st[i]).byteValue();
	        break;
          case (int)CDF_INT2:
          case (int)CDF_UINT1: 
                one = new short[itemCounts];          
                for (int i = 0; i< itemCounts; i++)
                  ((short[]) one)[i] = new Short(st[i]).shortValue();
                break;
          case (int)CDF_INT4:
          case (int)CDF_UINT2:
                one = new int[itemCounts];          
                for (int i = 0; i< itemCounts; i++)
                  ((int[]) one)[i] = new Integer(st[i]).intValue();
                break;
          case (int)CDF_UINT4: 
          case (int)CDF_INT8: 
                one = new long[itemCounts];          
                for (int i = 0; i< itemCounts; i++)
                  ((long[]) one)[i] = new Long(st[i]).longValue();
                break;
          case (int)CDF_REAL4:
          case (int)CDF_FLOAT:
                one = new float[itemCounts];          
                for (int i = 0; i< itemCounts; i++)
                  ((float[]) one)[i] = new Float(st[i]).floatValue();
                break;
          case (int)CDF_REAL8:
          case (int)CDF_DOUBLE:
                one = new double[itemCounts];          
                for (int i = 0; i< itemCounts; i++)
                  ((double[]) one)[i] = 
                                 new Double(st[i]).doubleValue();
                break;
          default:
            break;
        } /* switch (dataType) */
        return one;

    }

    /**
     * Translates a file into a common URL form.
     */

    private static String fileToURL(File f) throws IOException {

        String temp;
        if (!f.exists())
          throw new IOException("No such file: "+f.getName());
        temp = f.getAbsolutePath();
        if (File.separatorChar != '/')
          temp = temp.replace(File.separatorChar, '/');
        if (!temp.startsWith("/"))
          temp = "/" + temp;
        if (!temp.endsWith("/") && f.isDirectory())
          temp = temp + "/";
        return "file:"+temp;

    }

    /**
     * It assumes that each data is delimited by a pair of delimiters, a 
     * preceding and a trailing one. It would remove any spaces between the
     * trailing delimiter from a preceding data and the preceding delimiter
     * from its following data.
     */

    private String removeSpaces(String tmp, String delimiter) {
	
        StringBuffer sb = new StringBuffer();
        if (tmp.indexOf(delimiter) == -1) return tmp;
        int dellen = delimiter.length();
        int loc1 = 0, loc2 = -1, len = tmp.length();
        int locX = -1;
        if (len == 0) return null;
        while (loc1 < len) {
          locX = tmp.substring(loc1).indexOf(delimiter);
          if (locX != -1) {
            loc1 = loc1 + locX;
            locX = tmp.substring(loc1+dellen).indexOf(delimiter);
            if (locX != -1) {
              loc2 = loc1 + dellen + locX;
              sb.append(tmp.substring(loc1, loc2+dellen));
              loc1 = loc2+dellen;
            } else 
              break;
          } else 
            break;
        }
        return sb.toString();
   
    }  

    /**
     * It provides the how-to information to properly use the program.
     */

    private static void howto() {
	
	System.err.println(" "); 
	System.err.println("Description:");
	System.err.println("    This program converts a cdfml (an XML) file that conforms to the");
        System.err.println("    cdf.dtd or cdf.xsd into a CDF file.");
	System.err.println(" ");
        System.err.println("Usage: java [-Dorg.xml.sax.driver=...] CDFML2CDF [Options] xmlFileName");
	System.err.println(" ");
	System.err.println("    The SAX2 parser is used to parse the XML document. ");
	System.err.println("    The default SAX2 parser can be set up through a system resource ");
	System.err.println("    at SAX2 JAR file's META-INF/services/org.xml.sax.driver if ");
        System.err.println("    your SAX2 distribution supports it through the class loader."); 
	System.err.println("    Otherwise, the system property for org.xml.sax.driver has to be");
	System.err.println("    set for the parser. The parser classes are JVM/SAX2-dependent.");
        System.err.println("    If Sun's Java V1.4 and above is used, you don't have to specify");
        System.err.println("    the parser as its Crimson will be used as the default.\n");
	System.err.println("    For Xerces: org.apache.xerces.parsers.SAXParser");
	System.err.println("        Crimson (SUN 1.4): org.apache.crimson.parser.XMLReaderImpl");
	System.err.println("        AElfred2: gnu.xml.aelfred2.XmlReader (validating) or ");
	System.err.println("                  gnu.xml.aelfred2.SAXDriver (non-validating)");
	System.err.println("        Oracle: oracle.xml.parser.v2.SAXParser");
	System.err.println(" ");
	System.err.println("Options: ");
        System.err.println("   -[no]Validate       Whether to validate the XML file during the process. ");
        System.err.println("                       It's parser dependent. -noValidate is the default. ");
	System.err.println("   -[no]Delete         Whether to delete the CDF file if it already exists. ");
	System.err.println("                       -noDelete is the default. ");
	System.err.println("   -[cdf | output]:[cdfFileName | cdfDirecotry]");
        System.err.println("                       A new CDF file name or directory to replace the given");
	System.err.println("                       name at element's name attribute in the XML file. No"); 
	System.err.println("                       \".cdf\" extension is needed. If providing an existing");
	System.err.println("                       directory, the directory is to combine with the XML's");
	System.err.println("                       CDF element's name attribute to constitute the full");
	System.err.println("                       pathname.");
	System.err.println("   -[no]Data           Whether to load the variable record data values if they");
	System.err.println("                       are in the XML file to the CDF file. -Data is the");
        System.err.println("                       default.");
	System.err.println("   -[no]Backward       Whether to create the CDF in an older, V2.7, version,");
	System.err.println("                       instead of the current library V3.* version. -noBackward");
        System.err.println("                       is the default. ");
        System.err.println("   -[no]Progress       Whether to display the progress.");
        System.err.println("                       -noProgress is the default. ");
	System.err.println(" ");
        System.err.println("Examples: \n");
	System.err.println(" 1) java CDFML2CDF -Validate testcdfml.xml ");
	System.err.println("         if your JAR file's META-INF/services/org.xml.sax.driver is defined,");
	System.err.println("         such as Xerces and AElfred2's parsers. ");
        System.err.println(" 2) java -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser CDFML2CDF"); 
        System.err.println("         -Delete -CDF:test1 testcdfml.xml ");
	System.err.println("         use Xerces's Parser and create a CDF file, test1.cdf. "); 
        System.err.println(" 3) java -Dorg.xml.sax.driver=org.apache.crimson.parser.XMLReaderImpl CDFML2CDF");
        System.err.println("         -CDF:test1 -noData testcdfml.xml ");
	System.err.println("         use Sun's Java V1.4 and create test1.cdf but passing the variable");
        System.err.println("         record data.");
        System.err.println(" 4) java -Dorg.xml.sax.driver=oracle.xml.parser.v2.SAXParser CDFML2CDF");
        System.err.println("         -CDF:/home/mydir -delete -noData myCDFML.xml ");
	System.err.println("          use Oracle's parser and create /home/mydir/xxxx.cdf where xxxx comes");
	System.err.println("          from the name attribute at the CDF element in myCDFML.xml."); 
	System.err.println(" ");
        System.exit(0);
        
    }

    /**
     * Translates a file into a common URL form.
     */

    private void packData() {
          String tmp = dataBuffer.toString().trim();
          if (dataBuffer2.length() == 0) {
              if (tmp.length() > 0)
                 dataBuffer2.append(tmp);
          } else {
            if (tmp.length() > 0)
              dataBuffer2.append(multiDelimiter).append(tmp);
          }
    }

    /**
     * Determine a xsd's dateTime to CDF epoch data type.
     */

    private long xsdDateTimeToCDFEpoch(String dateTime) {

          /* 
           * If dateTime is one of these popular forms:
           *   2017-09-19T01:00:00.000 or 2017-09-19T01:00:00.000Z or
           *   19-SEP-2017 01:00:00.000
           *   then it is determined to be CDF_EPOCH
           * If dateTime is one of these popular forms:
           *   2017-09-19T01:00:00.000000000 or
           *   2017-09-19T01:00:00.000000000Z or
           *   then it is determined to be CDF_TIME_TT2000
           * If dateTime is one of these popular forms:
           *   2017-09-19T01:00:00.000000000000 or
           *   2017-09-19T01:00:00.000000000000Z or
           *   19-SEP-2017 01:00:00.000.000.000.000
           *   then it is determined to be CDF_EPOCH16
           * Otherwise, CDF_EPOCH is the default. It may not work, though.
           */
          String tmp;
          dateTime = dateTime.toLowerCase();
          StringTokenizer st;
          st = new StringTokenizer(dateTime, " ");
          tmp = st.nextToken();
          int len = tmp.length();
          if (len == 11)
            tmp = new StringBuffer(tmp).append(" ").
                                        append(st.nextToken()).toString();
          if (tmp.endsWith("z")) tmp = tmp.substring(0, tmp.length()-1);
          len = tmp.length();
          if (len == 23 || len == 24) return CDF_EPOCH;
          else if (len == 29) return CDF_TIME_TT2000;
          else if (len == 32 || len == 36) return CDF_EPOCH16;
          else return CDF_EPOCH;
    }

}

