  private void initMetadata(String xml) throws FormatException, IOException {
    LIFHandler handler = new LIFHandler();
    xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><LEICA>" + xml + 
      "</LEICA>";
    for (int i=0; i<xml.length(); i++) {
      char c = xml.charAt(i);
      if (Character.isISOControl(c) || !Character.isDefined(c)) {
        xml = xml.replace(c, ' ');
      }
    }
    try {
      SAXParser parser = SAX_FACTORY.newSAXParser();
      parser.parse(new ByteArrayInputStream(xml.getBytes()), handler);
    }
    catch (ParserConfigurationException exc) {
      throw new FormatException(exc);
    }
    catch (SAXException exc) {
      throw new FormatException(exc);
    }
    Vector elements = new Vector();
    seriesNames = new Vector();
    status("Populating native metadata");
    StringTokenizer st = new StringTokenizer(xml, ">");
    while (st.hasMoreTokens()) {
      String token = st.nextToken();
      elements.add(token.substring(1));
    }
    String token = (String) elements.get(0);
    String key = token.substring(0, token.indexOf("\""));
    String value = token.substring(token.indexOf("\"") + 1, token.length()-1);
    addMeta(key, value);
    int ndx = 1;
    int numDatasets = 0;
    Vector widths = new Vector();
    Vector heights = new Vector();
    Vector zs = new Vector();
    Vector ts = new Vector();
    Vector channels = new Vector();
    Vector bps = new Vector();
    Vector extraDims = new Vector();
    String prefix = "";
    while (ndx < elements.size()) {
      token = (String) elements.get(ndx);
      if (token.startsWith("ScannerSettingRecord")) {
        if (token.indexOf("csScanMode") != -1) {
          int index = token.indexOf("Variant") + 7;
          String ordering = token.substring(index + 2,
            token.indexOf("\"", index + 3));
          ordering = ordering.toLowerCase();
          if (ordering.indexOf("x") == -1 || ordering.indexOf("y") == -1 ||
            ordering.indexOf("xy") == -1)
          {
            int xPos = ordering.indexOf("x");
            int yPos = ordering.indexOf("y");
            int zPos = ordering.indexOf("z");
            int tPos = ordering.indexOf("t");
            if (xPos < 0) xPos = 0;
            if (yPos < 0) yPos = 1;
            if (zPos < 0) zPos = 2;
            if (tPos < 0) tPos = 3;
            int x = ((Integer) widths.get(widths.size() - 1)).intValue();
            int y = ((Integer) heights.get(widths.size() - 1)).intValue();
            int z = ((Integer) zs.get(widths.size() - 1)).intValue();
            int t = ((Integer) ts.get(widths.size() - 1)).intValue();
            int[] dimensions = {x, y, z, t};
            x = dimensions[xPos];
            y = dimensions[yPos];
            z = dimensions[zPos];
            t = dimensions[tPos];
            widths.setElementAt(new Integer(x), widths.size() - 1);
            heights.setElementAt(new Integer(y), heights.size() - 1);
            zs.setElementAt(new Integer(z), zs.size() - 1);
            ts.setElementAt(new Integer(t), ts.size() - 1);
          }
        }
        else if (token.indexOf("dblVoxel") != -1) {
          int index = token.indexOf("Variant") + 7;
          String size = token.substring(index + 2,
            token.indexOf("\"", index + 3));
          float cal = Float.parseFloat(size) * 1000000;
          if (token.indexOf("X") != -1) xcal.add(new Float(cal));
          else if (token.indexOf("Y") != -1) ycal.add(new Float(cal));
          else if (token.indexOf("Z") != -1) zcal.add(new Float(cal));
        }
      }
      else if (token.startsWith("Element Name")) {
        seriesNames.add(token.substring(token.indexOf("=") + 2,
          token.length() - 1));
        numDatasets++;
        int numChannels = 0;
        int extras = 1;
        while (token.indexOf("/ImageDescription") == -1) {
          if (token.indexOf("=") != -1) {
            if (token.startsWith("Element Name")) {
              seriesNames.setElementAt(token.substring(token.indexOf("=") + 2,
                token.length() - 1), seriesNames.size() - 1);
              prefix = (String) seriesNames.get(seriesNames.size() - 1);
            }
            Hashtable tmp = new Hashtable();
            while (token.length() > 2) {
              key = token.substring(0, token.indexOf("\"") - 1);
              value = token.substring(token.indexOf("\"") + 1,
                token.indexOf("\"", token.indexOf("\"") + 1));
              token = token.substring(key.length() + value.length() + 3);
              key = key.trim();
              value = value.trim();
              tmp.put(key, value);
            }
            if (tmp.get("ChannelDescription DataType") != null) {
              numChannels++;
              if (numChannels == 1) {
                bps.add(new Integer((String) tmp.get("Resolution")));
                String sMin = (String) tmp.get("Min");
                String sMax = (String) tmp.get("Max");
                if (sMin != null && sMax != null) {
                  double min = Double.parseDouble(sMin);
                  double max = Double.parseDouble(sMax);
                  channelMins.add(new Integer((int) min));
                  channelMaxs.add(new Integer((int) max));
                }
              }
            }
            else if (tmp.get("DimensionDescription DimID") != null) {
              int w = Integer.parseInt((String) tmp.get("NumberOfElements"));
              int id = Integer.parseInt((String)
                tmp.get("DimensionDescription DimID"));
              switch (id) {
                case 1:
                  widths.add(new Integer(w));
                  break;
                case 2:
                  heights.add(new Integer(w));
                  break;
                case 3:
                  zs.add(new Integer(w));
                  break;
                case 4:
                  ts.add(new Integer(w));
                  break;
                default:
                  extras *= w;
              }
            }
          }
          ndx++;
          if (elements != null && ndx < elements.size()) {
            token = (String) elements.get(ndx);
          }
          else break;
        }
        extraDims.add(new Integer(extras));
        if (numChannels == 0) numChannels++;
        channels.add(new Integer(numChannels));
        if (widths.size() < numDatasets && heights.size() < numDatasets) {
          numDatasets--;
        }
        else {
          if (widths.size() < numDatasets) widths.add(new Integer(1));
          if (heights.size() < numDatasets) heights.add(new Integer(1));
          if (zs.size() < numDatasets) zs.add(new Integer(1));
          if (ts.size() < numDatasets) ts.add(new Integer(1));
          if (bps.size() < numDatasets) bps.add(new Integer(8));
        }
      }
      ndx++;
    }
    numDatasets = widths.size();
    bitsPerPixel = new int[numDatasets];
    extraDimensions = new int[numDatasets];
    status("Populating metadata");
    MetadataStore store = getMetadataStore();
    core = new CoreMetadata(numDatasets);
    Arrays.fill(core.orderCertain, true);
    validBits = new int[numDatasets][];
    for (int i=0; i<numDatasets; i++) {
      core.sizeX[i] = ((Integer) widths.get(i)).intValue();
      core.sizeY[i] = ((Integer) heights.get(i)).intValue();
      core.sizeZ[i] = ((Integer) zs.get(i)).intValue();
      core.sizeC[i] = ((Integer) channels.get(i)).intValue();
      core.sizeT[i] = ((Integer) ts.get(i)).intValue();
      core.currentOrder[i] =
        (core.sizeZ[i] > core.sizeT[i]) ? "XYCZT" : "XYCTZ";
      bitsPerPixel[i] = ((Integer) bps.get(i)).intValue();
      extraDimensions[i] = ((Integer) extraDims.get(i)).intValue();
      if (extraDimensions[i] > 1) {
        if (core.sizeZ[i] == 1) core.sizeZ[i] = extraDimensions[i];
        else core.sizeT[i] *= extraDimensions[i];
        extraDimensions[i] = 1;
      }
      core.littleEndian[i] = true;
      core.rgb[i] = core.sizeC[i] > 1 && core.sizeC[i] < 4;
      core.interleaved[i] = true;
      core.imageCount[i] = core.sizeZ[i] * core.sizeT[i];
      if (!core.rgb[i]) core.imageCount[i] *= core.sizeC[i];
      validBits[i] = new int[core.sizeC[i] != 2 ? core.sizeC[i] : 3];
      for (int j=0; j<validBits[i].length; j++) {
        validBits[i][j] = bitsPerPixel[i];
      }
      while (bitsPerPixel[i] % 8 != 0) bitsPerPixel[i]++;
      switch (bitsPerPixel[i]) {
        case 8:
          core.pixelType[i] = FormatTools.UINT8;
          break;
        case 16:
          core.pixelType[i] = FormatTools.UINT16;
          break;
        case 32:
          core.pixelType[i] = FormatTools.FLOAT;
          break;
      }
      Integer ii = new Integer(i);
      String seriesName = (String) seriesNames.get(i);
      if (seriesName == null || seriesName.trim().length() == 0) {
        seriesName = "Series " + (i + 1);
      }
      store.setImage(seriesName, null, null, ii);
      store.setPixels(
        new Integer(core.sizeX[i]), 
        new Integer(core.sizeY[i]), 
        new Integer(core.sizeZ[i]), 
        new Integer(core.sizeC[i]), 
        new Integer(core.sizeT[i]), 
        new Integer(core.pixelType[i]), 
        new Boolean(!core.littleEndian[i]), 
        core.currentOrder[i], 
        ii, 
        null); 
      Float xf = i < xcal.size() ? (Float) xcal.get(i) : null;
      Float yf = i < ycal.size() ? (Float) ycal.get(i) : null;
      Float zf = i < zcal.size() ? (Float) zcal.get(i) : null;
      store.setDimensions(xf, yf, zf, null, null, ii);
      for (int j=0; j<core.sizeC[i]; j++) {
        store.setLogicalChannel(j, null, null, null, null, null, null, ii);
      }
      String zoom = (String) getMeta(seriesName + " - dblZoom");
      store.setDisplayOptions(zoom == null ? null : new Float(zoom),
        new Boolean(core.sizeC[i] > 1), new Boolean(core.sizeC[i] > 1),
        new Boolean(core.sizeC[i] > 2), new Boolean(isRGB()), null,
        null, null, null, null, ii, null, null, null, null, null);
      Enumeration keys = metadata.keys();
      while (keys.hasMoreElements()) {
        String k = (String) keys.nextElement();
        boolean use = true; 
        for (int j=0; j<seriesNames.size(); j++) {
          if (j != i && k.startsWith((String) seriesNames.get(i))) {
            use = false;
            break;
          }
        }
        if (use) core.seriesMetadata[i].put(k, metadata.get(k));
      }
    }
  }

  private void initMetadata(String xml) throws FormatException, IOException {
    LIFHandler handler = new LIFHandler();
    xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><LEICA>" + xml + 
      "</LEICA>";
    for (int i=0; i<xml.length(); i++) {
      char c = xml.charAt(i);
      if (Character.isISOControl(c) || !Character.isDefined(c)) {
        xml = xml.replace(c, ' ');
      }
    }
    try {
      SAXParser parser = SAX_FACTORY.newSAXParser();
      parser.parse(new ByteArrayInputStream(xml.getBytes()), handler);
    }
    catch (ParserConfigurationException exc) {
      throw new FormatException(exc);
    }
    catch (SAXException exc) {
      throw new FormatException(exc);
    }
    Vector elements = new Vector();
    seriesNames = new Vector();
    status("Populating native metadata");
    StringTokenizer st = new StringTokenizer(xml, ">");
    while (st.hasMoreTokens()) {
      String token = st.nextToken();
      elements.add(token.substring(1));
    }
    String token = (String) elements.get(0);
    String key = token.substring(0, token.indexOf("\""));
    String value = token.substring(token.indexOf("\"") + 1, token.length()-1);
    addMeta(key, value);
    int ndx = 1;
    int numDatasets = 0;
    Vector widths = new Vector();
    Vector heights = new Vector();
    Vector zs = new Vector();
    Vector ts = new Vector();
    Vector channels = new Vector();
    Vector bps = new Vector();
    Vector extraDims = new Vector();
    String prefix = "";
    while (ndx < elements.size()) {
      token = (String) elements.get(ndx);
      if (token.startsWith("ScannerSettingRecord")) {
        if (token.indexOf("csScanMode") != -1) {
          int index = token.indexOf("Variant") + 7;
          String ordering = token.substring(index + 2,
            token.indexOf("\"", index + 3));
          ordering = ordering.toLowerCase();
          if (ordering.indexOf("x") == -1 || ordering.indexOf("y") == -1 ||
            ordering.indexOf("xy") == -1)
          {
            int xPos = ordering.indexOf("x");
            int yPos = ordering.indexOf("y");
            int zPos = ordering.indexOf("z");
            int tPos = ordering.indexOf("t");
            if (xPos < 0) xPos = 0;
            if (yPos < 0) yPos = 1;
            if (zPos < 0) zPos = 2;
            if (tPos < 0) tPos = 3;
            int x = ((Integer) widths.get(widths.size() - 1)).intValue();
            int y = ((Integer) heights.get(widths.size() - 1)).intValue();
            int z = ((Integer) zs.get(widths.size() - 1)).intValue();
            int t = ((Integer) ts.get(widths.size() - 1)).intValue();
            int[] dimensions = {x, y, z, t};
            x = dimensions[xPos];
            y = dimensions[yPos];
            z = dimensions[zPos];
            t = dimensions[tPos];
            widths.setElementAt(new Integer(x), widths.size() - 1);
            heights.setElementAt(new Integer(y), heights.size() - 1);
            zs.setElementAt(new Integer(z), zs.size() - 1);
            ts.setElementAt(new Integer(t), ts.size() - 1);
          }
        }
        else if (token.indexOf("dblVoxel") != -1) {
          int index = token.indexOf("Variant") + 7;
          String size = token.substring(index + 2,
            token.indexOf("\"", index + 3));
          float cal = Float.parseFloat(size) * 1000000;
          if (token.indexOf("X") != -1) xcal.add(new Float(cal));
          else if (token.indexOf("Y") != -1) ycal.add(new Float(cal));
          else if (token.indexOf("Z") != -1) zcal.add(new Float(cal));
        }
      }
      else if (token.startsWith("Element Name")) {
        seriesNames.add(token.substring(token.indexOf("=") + 2,
          token.length() - 1));
        numDatasets++;
        int numChannels = 0;
        int extras = 1;
        while (token.indexOf("/ImageDescription") == -1) {
          if (token.indexOf("=") != -1) {
            if (token.startsWith("Element Name")) {
              seriesNames.setElementAt(token.substring(token.indexOf("=") + 2,
                token.length() - 1), seriesNames.size() - 1);
              prefix = (String) seriesNames.get(seriesNames.size() - 1);
            }
            Hashtable tmp = new Hashtable();
            while (token.length() > 2) {
              key = token.substring(0, token.indexOf("\"") - 1);
              value = token.substring(token.indexOf("\"") + 1,
                token.indexOf("\"", token.indexOf("\"") + 1));
              token = token.substring(key.length() + value.length() + 3);
              key = key.trim();
              value = value.trim();
              tmp.put(key, value);
            }
            if (tmp.get("ChannelDescription DataType") != null) {
              numChannels++;
              if (numChannels == 1) {
                bps.add(new Integer((String) tmp.get("Resolution")));
                String sMin = (String) tmp.get("Min");
                String sMax = (String) tmp.get("Max");
                if (sMin != null && sMax != null) {
                  double min = Double.parseDouble(sMin);
                  double max = Double.parseDouble(sMax);
                  channelMins.add(new Integer((int) min));
                  channelMaxs.add(new Integer((int) max));
                }
              }
            }
            else if (tmp.get("DimensionDescription DimID") != null) {
              int w = Integer.parseInt((String) tmp.get("NumberOfElements"));
              int id = Integer.parseInt((String)
                tmp.get("DimensionDescription DimID"));
              switch (id) {
                case 1:
                  widths.add(new Integer(w));
                  break;
                case 2:
                  heights.add(new Integer(w));
                  break;
                case 3:
                  zs.add(new Integer(w));
                  break;
                case 4:
                  ts.add(new Integer(w));
                  break;
                default:
                  extras *= w;
              }
            }
          }
          ndx++;
          if (elements != null && ndx < elements.size()) {
            token = (String) elements.get(ndx);
          }
          else break;
        }
        extraDims.add(new Integer(extras));
        if (numChannels == 0) numChannels++;
        channels.add(new Integer(numChannels));
        if (widths.size() < numDatasets && heights.size() < numDatasets) {
          numDatasets--;
        }
        else {
          if (widths.size() < numDatasets) widths.add(new Integer(1));
          if (heights.size() < numDatasets) heights.add(new Integer(1));
          if (zs.size() < numDatasets) zs.add(new Integer(1));
          if (ts.size() < numDatasets) ts.add(new Integer(1));
          if (bps.size() < numDatasets) bps.add(new Integer(8));
        }
      }
      ndx++;
    }
    numDatasets = widths.size();
    bitsPerPixel = new int[numDatasets];
    extraDimensions = new int[numDatasets];
    status("Populating metadata");
    MetadataStore store = getMetadataStore();
    core = new CoreMetadata(numDatasets);
    Arrays.fill(core.orderCertain, true);
    validBits = new int[numDatasets][];
    for (int i=0; i<numDatasets; i++) {
      core.sizeX[i] = ((Integer) widths.get(i)).intValue();
      core.sizeY[i] = ((Integer) heights.get(i)).intValue();
      core.sizeZ[i] = ((Integer) zs.get(i)).intValue();
      core.sizeC[i] = ((Integer) channels.get(i)).intValue();
      core.sizeT[i] = ((Integer) ts.get(i)).intValue();
      core.currentOrder[i] =
        (core.sizeZ[i] > core.sizeT[i]) ? "XYCZT" : "XYCTZ";
      bitsPerPixel[i] = ((Integer) bps.get(i)).intValue();
      extraDimensions[i] = ((Integer) extraDims.get(i)).intValue();
      if (extraDimensions[i] > 1) {
        if (core.sizeZ[i] == 1) core.sizeZ[i] = extraDimensions[i];
        else core.sizeT[i] *= extraDimensions[i];
        extraDimensions[i] = 1;
      }
      core.littleEndian[i] = true;
      core.rgb[i] = core.sizeC[i] > 1 && core.sizeC[i] < 4;
      core.interleaved[i] = true;
      core.imageCount[i] = core.sizeZ[i] * core.sizeT[i];
      if (!core.rgb[i]) core.imageCount[i] *= core.sizeC[i];
      validBits[i] = new int[core.sizeC[i] != 2 ? core.sizeC[i] : 3];
      for (int j=0; j<validBits[i].length; j++) {
        validBits[i][j] = bitsPerPixel[i];
      }
      while (bitsPerPixel[i] % 8 != 0) bitsPerPixel[i]++;
      switch (bitsPerPixel[i]) {
        case 8:
          core.pixelType[i] = FormatTools.UINT8;
          break;
        case 16:
          core.pixelType[i] = FormatTools.UINT16;
          break;
        case 32:
          core.pixelType[i] = FormatTools.FLOAT;
          break;
      }
      Integer ii = new Integer(i);
      String seriesName = (String) seriesNames.get(i);
      if (seriesName == null || seriesName.trim().length() == 0) {
        seriesName = "Series " + (i + 1);
      }
      store.setImage(seriesName, null, null, ii);
      store.setPixels(
        new Integer(core.sizeX[i]), 
        new Integer(core.sizeY[i]), 
        new Integer(core.sizeZ[i]), 
        new Integer(core.sizeC[i]), 
        new Integer(core.sizeT[i]), 
        new Integer(core.pixelType[i]), 
        new Boolean(!core.littleEndian[i]), 
        core.currentOrder[i], 
        ii, 
        null); 
      Float xf = i < xcal.size() ? (Float) xcal.get(i) : null;
      Float yf = i < ycal.size() ? (Float) ycal.get(i) : null;
      Float zf = i < zcal.size() ? (Float) zcal.get(i) : null;
      store.setDimensions(xf, yf, zf, null, null, ii);
      for (int j=0; j<core.sizeC[i]; j++) {
        store.setLogicalChannel(j, null, null, null, null, null, null, ii);
      }
      String zoom = (String) getMeta(seriesName + " - dblZoom");
      store.setDisplayOptions(zoom == null ? null : new Float(zoom),
        new Boolean(core.sizeC[i] > 1), new Boolean(core.sizeC[i] > 1),
        new Boolean(core.sizeC[i] > 2), new Boolean(isRGB()), null,
        null, null, null, null, ii, null, null, null, null, null);
      Enumeration keys = metadata.keys();
      while (keys.hasMoreElements()) {
        String k = (String) keys.nextElement();
        boolean use = true; 
        for (int j=0; j<seriesNames.size(); j++) {
          if (j != i && k.startsWith((String) seriesNames.get(j))) {
            use = false;
            break;
          }
        }
        if (use) core.seriesMetadata[i].put(k, metadata.get(k));
      }
    }
  }
