/**
   * Adds the contents of the given stream to the data base. The stream have to contain key value
   * pairs as declared by the DTD langpack.dtd.
   *
   * @param in an InputStream to read the translation from.
   * @throws Exception
   */
  public void add(InputStream in) throws Exception {
    // Initialises the parser
    StdXMLParser parser = new StdXMLParser();
    parser.setBuilder(XMLBuilderFactory.createXMLBuilder());
    parser.setReader(new StdXMLReader(in));
    parser.setValidator(new NonValidator());

    // We get the data
    XMLElement data = (XMLElement) parser.parse();

    // We check the data
    if (!"langpack".equalsIgnoreCase(data.getName()))
      throw new Exception("this is not an IzPack XML langpack file");

    // We fill the Hashtable
    Vector children = data.getChildren();
    int size = children.size();
    for (int i = 0; i < size; i++) {
      XMLElement e = (XMLElement) children.get(i);
      String text = e.getContent();
      if (text != null && !"".equals(text)) {
        put(e.getAttribute("id"), text.trim());
      } else {
        put(e.getAttribute("id"), e.getAttribute("txt"));
      }
    }
  }
  /**
   * Returns whether the value to the given attribute is "yes" or not. If the attribute does not
   * exist, or the value is not "yes" and not "no", the default value is returned.
   *
   * @param element the XML element which contains the attribute
   * @param attribute the name of the attribute
   * @param defaultValue the default value
   * @return whether the value to the given attribute is "yes" or not
   */
  public boolean isAttributeYes(XMLElement element, String attribute, boolean defaultValue) {
    String value = element.getAttribute(attribute, (defaultValue ? YES : NO));
    if (value.equalsIgnoreCase(YES)) return true;
    if (value.equalsIgnoreCase(NO)) return false;

    return defaultValue;
  }
 /**
  * Returns the attribute for the given attribute name. If no attribute exist, an
  * InstallerException with a detail message is thrown.
  *
  * @param element XML element which should contain the attribute
  * @param attrName key of the attribute
  * @return the attribute as string
  * @throws Exception
  */
 public String getRequiredAttribute(XMLElement element, String attrName)
     throws InstallerException {
   String attr = element.getAttribute(attrName);
   if (attr == null) {
     parseError(element, "<" + element.getName() + "> requires attribute '" + attrName + "'.");
   }
   return (attr);
 }
  /**
   * Returns a XML element which represents the pack for the given name.
   *
   * @param packDestName name of the pack which should be returned
   * @return a XML element which represents the pack for the given name
   */
  public XMLElement getPackForName(String packDestName) {
    Vector packs = getSpec().getChildrenNamed(PACK_KEY);
    Iterator iter = null;
    if (packs == null) return (null);
    iter = packs.iterator();
    while (iter.hasNext()) {

      XMLElement pack = (XMLElement) iter.next();
      String packName = pack.getAttribute(PACK_NAME);
      if (packName.equals(packDestName)) return (pack);
    }
    return (null);
  }
  /** helper: process a <code>&lt;classpath&gt;</code> tag. */
  private void changeClassPath(ArrayList classpath, XMLElement child) throws Exception {
    String add = child.getAttribute("add");
    if (add != null) {
      add = this.vs.substitute(add, "plain");
      if (!new File(add).exists()) {
        if (!this.handler.emitWarning(
            "Invalid classpath", "The path " + add + " could not be found.\nCompilation may fail."))
          throw new Exception("Classpath " + add + " does not exist.");
      } else {
        classpath.add(this.vs.substitute(add, "plain"));
      }
    }

    String sub = child.getAttribute("sub");
    if (sub != null) {
      int cpidx = -1;
      sub = this.vs.substitute(sub, "plain");

      do {
        cpidx = classpath.indexOf(sub);
        classpath.remove(cpidx);
      } while (cpidx >= 0);
    }
  }
  // helper function
  private void readChoices(XMLElement element, ArrayList result) {
    Vector choices = element.getChildrenNamed("choice");

    if (choices == null) return;

    result.clear();

    Iterator choice_it = choices.iterator();

    while (choice_it.hasNext()) {
      XMLElement choice = (XMLElement) choice_it.next();

      String value = choice.getAttribute("value");

      if (value != null) {
        List osconstraints = OsConstraint.getOsList(choice);

        if (OsConstraint.oneMatchesCurrentSystem(osconstraints)) {
          result.add(this.vs.substitute(value, "plain"));
        }
      }
    }
  }
  private CompilationJob collectJobsRecursive(XMLElement node, ArrayList classpath)
      throws Exception {
    Enumeration toplevel_tags = node.enumerateChildren();
    ArrayList ourclasspath = (ArrayList) classpath.clone();
    ArrayList files = new ArrayList();

    while (toplevel_tags.hasMoreElements()) {
      XMLElement child = (XMLElement) toplevel_tags.nextElement();

      if (child.getName().equals("classpath")) {
        changeClassPath(ourclasspath, child);
      } else if (child.getName().equals("job")) {
        CompilationJob subjob = collectJobsRecursive(child, ourclasspath);
        if (subjob != null) this.jobs.add(subjob);
      } else if (child.getName().equals("directory")) {
        String name = child.getAttribute("name");

        if (name != null) {
          // substitute variables
          String finalname = this.vs.substitute(name, "plain");

          files.addAll(scanDirectory(new File(finalname)));
        }

      } else if (child.getName().equals("file")) {
        String name = child.getAttribute("name");

        if (name != null) {
          // substitute variables
          String finalname = this.vs.substitute(name, "plain");

          files.add(new File(finalname));
        }

      } else if (child.getName().equals("packdepency")) {
        String name = child.getAttribute("name");

        if (name == null) {
          System.out.println("invalid compilation spec: <packdepency> without name attribute");
          return null;
        }

        // check whether the wanted pack was selected for installation
        Iterator pack_it = this.idata.selectedPacks.iterator();
        boolean found = false;

        while (pack_it.hasNext()) {
          com.izforge.izpack.Pack pack = (com.izforge.izpack.Pack) pack_it.next();

          if (pack.name.equals(name)) {
            found = true;
            break;
          }
        }

        if (!found) {
          Debug.trace("skipping job because pack " + name + " was not selected.");
          return null;
        }
      }
    }

    if (files.size() > 0)
      return new CompilationJob(
          this.handler,
          this.idata.langpack,
          (String) node.getAttribute("name"),
          files,
          ourclasspath);

    return null;
  }