Ejemplo n.º 1
0
  /**
   * Will parse the BibTex-Data found when reading from reader.
   *
   * <p>The reader will be consumed.
   *
   * <p>Multiple calls to parse() return the same results
   *
   * @return ParserResult
   * @throws IOException
   */
  public ParserResult parse() throws IOException {

    // If we already parsed this, just return it.
    if (_pr != null) return _pr;

    _db = new BibtexDatabase(); // Bibtex related contents.
    _meta = new HashMap<String, String>(); // Metadata in comments for Bibkeeper.
    entryTypes = new HashMap<String, BibtexEntryType>(); // To store custem entry types parsed.
    _pr = new ParserResult(_db, _meta, entryTypes);

    // First see if we can find the version number of the JabRef version that
    // wrote the file:
    String versionNum = readJabRefVersionNumber();
    if (versionNum != null) {
      _pr.setJabrefVersion(versionNum);
      setMajorMinorVersions();
    } else {
      // No version number found. However, we have only
    }

    skipWhitespace();

    try {
      while (!_eof) {
        boolean found = consumeUncritically('@');
        if (!found) break;
        skipWhitespace();
        String entryType = parseTextToken();
        BibtexEntryType tp = BibtexEntryType.getType(entryType);
        boolean isEntry = (tp != null);
        // Util.pr(tp.getName());
        if (!isEntry) {
          // The entry type name was not recognized. This can mean
          // that it is a string, preamble, or comment. If so,
          // parse and set accordingly. If not, assume it is an entry
          // with an unknown type.
          if (entryType.toLowerCase().equals("preamble")) {
            _db.setPreamble(parsePreamble());
          } else if (entryType.toLowerCase().equals("string")) {
            BibtexString bs = parseString();
            try {
              _db.addString(bs);
            } catch (KeyCollisionException ex) {
              _pr.addWarning(Globals.lang("Duplicate string name") + ": " + bs.getName());
              // ex.printStackTrace();
            }
          } else if (entryType.toLowerCase().equals("comment")) {
            StringBuffer commentBuf = parseBracketedTextExactly();
            /**
             * Metadata are used to store Bibkeeper-specific information in .bib files.
             *
             * <p>Metadata are stored in bibtex files in the format
             *
             * @comment{jabref-meta: type:data0;data1;data2;...}
             *     <p>Each comment that starts with the META_FLAG is stored in the meta HashMap,
             *     with type as key. Unluckily, the old META_FLAG bibkeeper-meta: was used in JabRef
             *     1.0 and 1.1, so we need to support it as well. At least for a while. We'll always
             *     save with the new one.
             */
            String comment = commentBuf.toString().replaceAll("[\\x0d\\x0a]", "");
            if (comment
                    .substring(0, Math.min(comment.length(), GUIGlobals.META_FLAG.length()))
                    .equals(GUIGlobals.META_FLAG)
                || comment
                    .substring(0, Math.min(comment.length(), GUIGlobals.META_FLAG_OLD.length()))
                    .equals(GUIGlobals.META_FLAG_OLD)) {

              String rest;
              if (comment.substring(0, GUIGlobals.META_FLAG.length()).equals(GUIGlobals.META_FLAG))
                rest = comment.substring(GUIGlobals.META_FLAG.length());
              else rest = comment.substring(GUIGlobals.META_FLAG_OLD.length());

              int pos = rest.indexOf(':');

              if (pos > 0) _meta.put(rest.substring(0, pos), rest.substring(pos + 1));
              // We remove all line breaks in the metadata - these
              // will have been inserted
              // to prevent too long lines when the file was
              // saved, and are not part of the data.
            }

            /**
             * A custom entry type can also be stored in a
             *
             * @comment:
             */
            if (comment
                .substring(0, Math.min(comment.length(), GUIGlobals.ENTRYTYPE_FLAG.length()))
                .equals(GUIGlobals.ENTRYTYPE_FLAG)) {

              CustomEntryType typ = CustomEntryType.parseEntryType(comment);
              entryTypes.put(typ.getName().toLowerCase(), typ);
            }
          } else {
            // The entry type was not recognized. This may mean that
            // it is a custom entry type whose definition will
            // appear
            // at the bottom of the file. So we use an
            // UnknownEntryType
            // to remember the type name by.
            tp = new UnknownEntryType(entryType.toLowerCase());
            // System.out.println("unknown type: "+entryType);
            isEntry = true;
          }
        }

        if (isEntry) // True if not comment, preamble or string.
        {
          /**
           * Morten Alver 13 Aug 2006: Trying to make the parser more robust. If an exception is
           * thrown when parsing an entry, drop the entry and try to resume parsing. Add a warning
           * for the user.
           *
           * <p>An alternative solution is to try rescuing the entry for which parsing failed, by
           * returning the entry with the exception and adding it before parsing is continued.
           */
          try {
            BibtexEntry be = parseEntry(tp);

            boolean duplicateKey = _db.insertEntry(be);
            if (duplicateKey) // JZTODO lyrics
            _pr.addWarning(
                  Globals.lang("duplicate BibTeX key")
                      + ": "
                      + be.getCiteKey()
                      + " ("
                      + Globals.lang("grouping may not work for this entry")
                      + ")");
            else if (be.getCiteKey() == null || be.getCiteKey().equals("")) {
              _pr.addWarning(
                  Globals.lang("empty BibTeX key")
                      + ": "
                      + be.getAuthorTitleYear(40)
                      + " ("
                      + Globals.lang("grouping may not work for this entry")
                      + ")");
            }
          } catch (IOException ex) {
            ex.printStackTrace();
            _pr.addWarning(
                Globals.lang("Error occured when parsing entry")
                    + ": '"
                    + ex.getMessage()
                    + "'. "
                    + Globals.lang("Skipped entry."));
          }
        }

        skipWhitespace();
      }

      // Before returning the database, update entries with unknown type
      // based on parsed type definitions, if possible.
      checkEntryTypes(_pr);

      return _pr;
    } catch (KeyCollisionException kce) {
      // kce.printStackTrace();
      throw new IOException("Duplicate ID in bibtex file: " + kce.toString());
    }
  }