/** * Will parse the BibTex-Data found when reading from reader. * * The reader will be consumed. * * Multiple calls to parse() return the same results * * @return ParserResult * @throws IOException */ public ParserResult Parse() { // If we already parsed this, just return it. if (_pr != null) return _pr; _db = new BibtexDatabase(); // Bibtex related contents. _meta = new Dictionary<string, string>(); // Metadata in comments for Bibkeeper. entryTypes = new Dictionary<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.JabrefVersion = versionNum; SetMajorMinorVersions(); } else { // No version number found. However, we have only } SkipWhitespace(); try { while (!_eof) { bool found = ConsumeUncritically('@'); if (!found) break; SkipWhitespace(); string entryType = ParseTextToken(); BibtexEntryType tp = BibtexEntryType.getType(entryType); bool 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.ToLower().Equals("preamble")) { _db.setPreamble(ParsePreamble()); } else if (entryType.ToLower().Equals("string")) { BibtexString bs = ParseString(); try { _db.addString(bs); } catch (KeyCollisionException) { _pr.AddWarning(Globals.lang("Duplicate string name") + ": " + bs.getName()); // ex.printStackTrace(); } } else if (entryType.ToLower().Equals("comment")) { StringBuilder commentBuf = ParseBracketedTextExactly(); /** * * Metadata are used to store Bibkeeper-specific * information in .bib files. * * Metadata are stored in bibtex files in the format * * @comment{jabref-meta: type:data0;data1;data2;...} * * Each comment that starts with the META_FLAG is stored * in the meta Dictionary, 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. */ // TODO: unicode escape sequences string comment = commentBuf.ToString().Replace("[\\x0d\\x0a]", ""); if (comment.Substring(0, Math.Min(comment.Length, Globals.META_FLAG.Length)).Equals( Globals.META_FLAG) || comment.Substring(0, Math.Min(comment.Length, Globals.META_FLAG_OLD.Length)) .Equals(Globals.META_FLAG_OLD)) { string rest; if (comment.Substring(0, Globals.META_FLAG.Length).Equals( Globals.META_FLAG)) rest = comment.Substring(Globals.META_FLAG.Length); else rest = comment.Substring(Globals.META_FLAG_OLD.Length); int pos = rest.IndexOf(':'); if (pos > 0) _meta.Add(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, Globals.ENTRYTYPE_FLAG.Length)).Equals( Globals.ENTRYTYPE_FLAG)) { CustomEntryType typ = CustomEntryType.parseEntryType(comment); entryTypes.Add(typ.getName().ToLower(), 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.ToLower()); // 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. * * 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); bool duplicateKey = _db.insertEntry(be); if (duplicateKey) // JZTODO lyrics _pr.AddDuplicateKey(be.getCiteKey()); /*_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) { _pr.AddWarning(Globals.lang("Error occured when parsing entry") + ": '" + ex.Message + "'. " + 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()); } }
public void CheckEntryTypes(ParserResult _pr) { foreach (BibtexEntry be in _db.getEntries()){ if (be.getType() is UnknownEntryType) { // Look up the unknown type name in our map of parsed types: object o = entryTypes[(be.getType().getName().ToLower())]; if (o != null) { BibtexEntryType type = (BibtexEntryType) o; be.setType(type); } else { // System.out.println("Unknown entry type: // "+be.getType().getName()); _pr .AddWarning(Globals.lang("unknown entry type") + ": " + be.getType().getName() + ". " + Globals.lang("Type set to 'other'") + "."); be.setType(BibtexEntryType.OTHER.Instance); } } } }