private StringBuilder parseBracketedTextExactly() throws IOException { StringBuilder value = new StringBuilder(); consume('{'); int brackets = 0; char character; char lastCharacter = '\0'; while (true) { character = (char) read(); boolean isClosingBracket = (character == '}') && (lastCharacter != '\\'); if (isClosingBracket && (brackets == 0)) { return value; } else if (isEOFCharacter(character)) { throw new IOException("Error in line " + line + ": EOF in mid-string"); } else if ((character == '{') && (!isEscapeSymbol(lastCharacter))) { brackets++; } else if (isClosingBracket) { brackets--; } value.append(character); lastCharacter = character; } }
private void parseField(BibEntry entry) throws IOException { String key = parseTextToken().toLowerCase(); skipWhitespace(); consume('='); String content = parseFieldContent(key); if (!content.isEmpty()) { if (entry.hasField(key)) { // The following hack enables the parser to deal with multiple // author or // editor lines, stringing them together instead of getting just // one of them. // Multiple author or editor lines are not allowed by the bibtex // format, but // at least one online database exports bibtex like that, making // it inconvenient // for users if JabRef didn't accept it. if (InternalBibtexFields.getFieldExtras(key).contains(FieldProperties.PERSON_NAMES)) { entry.setField(key, entry.getFieldOptional(key).get() + " and " + content); } else if (FieldName.KEYWORDS.equals(key)) { // multiple keywords fields should be combined to one entry.addKeyword(content, Globals.prefs.get(JabRefPreferences.KEYWORD_SEPARATOR)); } } else { entry.setField(key, content); } } }
private StringBuffer parseBracketedText() throws IOException { StringBuffer value = new StringBuffer(); consume('{', '('); int brackets = 0; while (!((isClosingBracketNext()) && (brackets == 0))) { int character = read(); if (isEOFCharacter(character)) { throw new IOException("Error in line " + line + ": EOF in mid-string"); } else if ((character == '{') || (character == '(')) { brackets++; } else if ((character == '}') || (character == ')')) { brackets--; } // If we encounter whitespace of any kind, read it as a // simple space, and ignore any others that follow immediately. /* * if (j == '\n') { if (peek() == '\n') value.append('\n'); } else */ if (Character.isWhitespace((char) character)) { String whitespacesReduced = skipAndRecordWhitespace(character); if (!(whitespacesReduced.isEmpty()) && !"\n\t".equals(whitespacesReduced)) { // && whitespacesReduced = whitespacesReduced.replace("\t", ""); // Remove tabulators. value.append(whitespacesReduced); } else { value.append(' '); } } else { value.append((char) character); } } consume('}', ')'); return value; }
private BibtexString parseString() throws IOException { skipWhitespace(); consume('{', '('); skipWhitespace(); LOGGER.debug("Parsing string name"); String name = parseTextToken(); LOGGER.debug("Parsed string name"); skipWhitespace(); LOGGER.debug("Now the contents"); consume('='); String content = parseFieldContent(name); LOGGER.debug("Now I'm going to consume a }"); consume('}', ')'); // Consume new line which signals end of entry skipOneNewline(); LOGGER.debug("Finished string parsing."); String id = IdGenerator.next(); return new BibtexString(id, name, content); }
private BibEntry parseEntry(String entryType) throws IOException { String id = IdGenerator.next(); BibEntry result = new BibEntry(id, entryType); skipWhitespace(); consume('{', '('); int character = peek(); if ((character != '\n') && (character != '\r')) { skipWhitespace(); } String key = parseKey(); result.setCiteKey(key); skipWhitespace(); while (true) { character = peek(); if ((character == '}') || (character == ')')) { break; } if (character == ',') { consume(','); } skipWhitespace(); character = peek(); if ((character == '}') || (character == ')')) { break; } parseField(result); } consume('}', ')'); // Consume new line which signals end of entry skipOneNewline(); return result; }
private StringBuilder parseQuotedFieldExactly() throws IOException { StringBuilder value = new StringBuilder(); consume('"'); int brackets = 0; while (!((peek() == '"') && (brackets == 0))) { int j = read(); if (isEOFCharacter(j)) { throw new IOException("Error in line " + line + ": EOF in mid-string"); } else if (j == '{') { brackets++; } else if (j == '}') { brackets--; } value.append((char) j); } consume('"'); return value; }
private String parseFieldContent(String key) throws IOException { skipWhitespace(); StringBuilder value = new StringBuilder(); int character; while (((character = peek()) != ',') && (character != '}') && (character != ')')) { if (eof) { throw new IOException("Error in line " + line + ": EOF in mid-string"); } if (character == '"') { StringBuilder text = parseQuotedFieldExactly(); value.append(fieldContentParser.format(text, key)); } else if (character == '{') { // Value is a string enclosed in brackets. There can be pairs // of brackets inside of a field, so we need to count the // brackets to know when the string is finished. StringBuilder text = parseBracketedTextExactly(); value.append(fieldContentParser.format(text, key)); } else if (Character.isDigit((char) character)) { // value is a number String number = parseTextToken(); value.append(number); } else if (character == '#') { consume('#'); } else { String textToken = parseTextToken(); if (textToken.isEmpty()) { throw new IOException( "Error in line " + line + " or above: " + "Empty text token.\nThis could be caused " + "by a missing comma between two fields."); } value.append('#').append(textToken).append('#'); } skipWhitespace(); } return value.toString(); }