Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make BibTex parser more robust against missing newlines #677

Merged
merged 2 commits into from
Jan 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ to [sourceforge feature requests](https://sourceforge.net/p/jabref/features/) by
### Changed

### Fixed
- Make BibTex parser more robust against missing newlines
- Fix bug that prevented the import of BibTex entries having only a key as content

### Removed

Expand Down
14 changes: 9 additions & 5 deletions src/main/java/net/sf/jabref/importer/OpenDatabaseAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ public class OpenDatabaseAction extends MnemonicAwareAction {
// upgrade actions etc. that may depend on the JabRef version that wrote the file:
private static final List<PostOpenAction> POST_OPEN_ACTIONS = new ArrayList<>();


static {
// Add the action for checking for new custom entry types loaded from
// the bib file:
Expand Down Expand Up @@ -104,14 +103,12 @@ public void actionPerformed(ActionEvent e) {
openFiles(filesToOpen, true);
}


class OpenItSwingHelper implements Runnable {

private final BasePanel basePanel;
private final boolean raisePanel;
private final File file;


OpenItSwingHelper(BasePanel basePanel, File file, boolean raisePanel) {
this.basePanel = basePanel;
this.raisePanel = raisePanel;
Expand All @@ -125,7 +122,6 @@ public void run() {
}
}


/**
* Opens the given file. If null or 404, nothing happens
*
Expand Down Expand Up @@ -447,7 +443,15 @@ private static Optional<Charset> getSuppliedEncoding(Reader reader) {
// Signature line, so keep reading and skip to next line
} else if (line.startsWith(Globals.encPrefix)) {
// Line starts with "Encoding: ", so the rest of the line should contain the name of the encoding
String encoding = line.substring(Globals.encPrefix.length());
// Except if there is already a @ symbol signalising the starting of a BibEntry
Integer atSymbolIndex = line.indexOf("@");
String encoding;
if (atSymbolIndex > 0) {
encoding = line.substring(Globals.encPrefix.length(), atSymbolIndex);
} else {
encoding = line.substring(Globals.encPrefix.length());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please always use curly braces as this makes the semantics explicit.

}

return Optional.of(Charset.forName(encoding));
} else {
// Line not recognized so stop parsing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ private String parseKey() throws IOException {
// return what we
// have found, as the key and try to restore the rest in fixKey().
return token + fixKey();
} else if (character == ',') {
} else if (character == ',' || character == '}') {
unread(character);
return token.toString();
} else if (character == '=') {
Expand Down
21 changes: 21 additions & 0 deletions src/test/java/net/sf/jabref/importer/OpenDatabaseActionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import net.sf.jabref.Globals;
import net.sf.jabref.JabRefPreferences;
import net.sf.jabref.model.database.BibDatabase;
import net.sf.jabref.model.entry.BibEntry;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
Expand All @@ -11,6 +12,7 @@
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;

public class OpenDatabaseActionTest {

Expand All @@ -21,6 +23,8 @@ public class OpenDatabaseActionTest {
private final File bibHeader = new File(OpenDatabaseActionTest.class.getResource("encoding-header.bib").getFile());
private final File bibHeaderAndSignature = new File(
OpenDatabaseActionTest.class.getResource("jabref-header.bib").getFile());
private final File bibEncodingWithoutNewline = new File(
OpenDatabaseActionTest.class.getResource("encodingWithoutNewline.bib").getFile());

@BeforeClass
public static void setUpGlobalsPrefs() {
Expand Down Expand Up @@ -82,4 +86,21 @@ public void entriesAreParsedHeaderAndSignature() throws IOException {
Assert.assertEquals("2014", db.getEntryByKey("1").getField("year"));
}

/**
* Test for #669
*/
@Test
public void correctlyParseEncodingWithoutNewline() throws IOException {
ParserResult result = OpenDatabaseAction.loadDatabase(bibEncodingWithoutNewline, defaultEncoding);
Assert.assertEquals(StandardCharsets.US_ASCII, result.getEncoding());

BibDatabase db = result.getDatabase();
Assert.assertEquals("testPreamble", db.getPreamble());

Collection<BibEntry> entries = db.getEntries();
Assert.assertEquals(1, entries.size());

BibEntry entry = entries.iterator().next();
Assert.assertEquals("testArticle", entry.getCiteKey());
}
}
123 changes: 85 additions & 38 deletions src/test/java/net/sf/jabref/importer/fileformat/BibtexParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,20 @@ public void parseRecognizesEntry() throws IOException {
Assert.assertEquals("Ed von Test", e.getField("author"));
}

@Test
public void parseRecognizesEntryOnlyWithKey() throws IOException {

ParserResult result = BibtexParser.parse(new StringReader(
"@article{test}"));

Collection<BibEntry> c = result.getDatabase().getEntries();
Assert.assertEquals(1, c.size());

BibEntry e = c.iterator().next();
Assert.assertEquals(BibtexEntryTypes.ARTICLE, e.getType());
Assert.assertEquals("test", e.getCiteKey());
}

@Test
public void parseRecognizesEntryWithWhitespaceAtBegining() throws IOException {

Expand Down Expand Up @@ -344,23 +358,23 @@ public void parseCombinesMultipleKeywordsFields() throws IOException {
@Test
public void parseRecognizesHeaderButIgnoresEncoding() throws IOException {
ParserResult result = BibtexParser.parse(new StringReader(
"This file was created with JabRef 2.1 beta 2."
+ "\n"
+ "Encoding: Cp1252"
+ "\n"
+ ""
+ "\n"
+ "@INPROCEEDINGS{CroAnnHow05,"
+ "\n"
+ " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},"
+ "\n"
+ " title = {Effective work practices for floss development: A model and propositions},"
+ "\n"
+ " booktitle = {Hawaii International Conference On System Sciences (HICSS)},"
+ "\n" + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n"
+ " timestamp = {2006.05.29}," + "\n"
+ " url = {http://james.howison.name/publications.html}" + "\n" + "}))"
));
"This file was created with JabRef 2.1 beta 2."
+ "\n"
+ "Encoding: Cp1252"
+ "\n"
+ ""
+ "\n"
+ "@INPROCEEDINGS{CroAnnHow05,"
+ "\n"
+ " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},"
+ "\n"
+ " title = {Effective work practices for floss development: A model and propositions},"
+ "\n"
+ " booktitle = {Hawaii International Conference On System Sciences (HICSS)},"
+ "\n" + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n"
+ " timestamp = {2006.05.29}," + "\n"
+ " url = {http://james.howison.name/publications.html}" + "\n" + "}))"
));
Assert.assertNull(result.getEncoding());

Collection<BibEntry> c = result.getDatabase().getEntries();
Expand All @@ -383,17 +397,17 @@ public void parseRecognizesHeaderButIgnoresEncoding() throws IOException {
@Test
public void parseRecognizesFormatedEntry() throws IOException {
ParserResult result = BibtexParser.parse(new StringReader(
"@INPROCEEDINGS{CroAnnHow05,"
+ "\n"
+ " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},"
+ "\n"
+ " title = {Effective work practices for floss development: A model and propositions},"
+ "\n"
+ " booktitle = {Hawaii International Conference On System Sciences (HICSS)},"
+ "\n" + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n"
+ " timestamp = {2006.05.29}," + "\n"
+ " url = {http://james.howison.name/publications.html}" + "\n" + "}))"
));
"@INPROCEEDINGS{CroAnnHow05,"
+ "\n"
+ " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},"
+ "\n"
+ " title = {Effective work practices for floss development: A model and propositions},"
+ "\n"
+ " booktitle = {Hawaii International Conference On System Sciences (HICSS)},"
+ "\n" + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n"
+ " timestamp = {2006.05.29}," + "\n"
+ " url = {http://james.howison.name/publications.html}" + "\n" + "}))"
));
Collection<BibEntry> c = result.getDatabase().getEntries();
Assert.assertEquals(1, c.size());

Expand All @@ -409,7 +423,7 @@ public void parseRecognizesFormatedEntry() throws IOException {
Assert.assertEquals("oezbek", e.getField("owner"));
Assert.assertEquals("2006.05.29", e.getField("timestamp"));
Assert.assertEquals("http://james.howison.name/publications.html", e.getField("url"));
}
}

@Test
public void parseRecognizesFieldValuesInQuotationMarks() throws IOException {
Expand Down Expand Up @@ -496,15 +510,15 @@ public void parseRecognizesDateFieldWithConcatenation() throws IOException {
@Test
public void parseReturnsEmptyListIfNoEntryRecognized() throws IOException {
ParserResult result = BibtexParser.parse(new StringReader(
" author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},"
+ "\n"
+ " title = {Effective work practices for floss development: A model and propositions},"
+ "\n"
+ " booktitle = {Hawaii International Conference On System Sciences (HICSS)},"
+ "\n" + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n"
+ " timestamp = {2006.05.29}," + "\n"
+ " url = {http://james.howison.name/publications.html}" + "\n" + "}))"
));
" author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},"
+ "\n"
+ " title = {Effective work practices for floss development: A model and propositions},"
+ "\n"
+ " booktitle = {Hawaii International Conference On System Sciences (HICSS)},"
+ "\n" + " year = {2005}," + "\n" + " owner = {oezbek}," + "\n"
+ " timestamp = {2006.05.29}," + "\n"
+ " url = {http://james.howison.name/publications.html}" + "\n" + "}))"
));
Collection<BibEntry> c = result.getDatabase().getEntries();
Assert.assertEquals(0, c.size());
}
Expand Down Expand Up @@ -1046,4 +1060,37 @@ public void parseHandlesAccentsCorrectly() throws IOException {
Assert.assertEquals("H\'{e}lne Fiaux", e.getField("author"));
}

/**
* Test for #669
*/
@Test
public void parsePreambleAndEntryWithoutNewLine() throws IOException {

ParserResult result = BibtexParser.parse(
new StringReader("@preamble{some text and \\latex}@article{test,author = {H\'{e}lne Fiaux}}"));
Assert.assertFalse(result.hasWarnings());

Assert.assertEquals("some text and \\latex", result.getDatabase().getPreamble());

Collection<BibEntry> c = result.getDatabase().getEntries();
Assert.assertEquals(1, c.size());

BibEntry e = c.iterator().next();
Assert.assertEquals(BibtexEntryTypes.ARTICLE, e.getType());
Assert.assertEquals("test", e.getCiteKey());
Assert.assertEquals("H\'{e}lne Fiaux", e.getField("author"));
}

/**
* Test for #669
*/
@Test
public void parseFileHeaderAndPreambleWithoutNewLine() throws IOException {

ParserResult result = BibtexParser.parse(
new StringReader("% Encoding: US-ASCII@preamble{some text and \\latex}"));
Assert.assertFalse(result.hasWarnings());

Assert.assertEquals("some text and \\latex", result.getDatabase().getPreamble());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
% Encoding: US-ASCII@PREAMBLE{testPreamble}@article{testArticle}