1 #include "bibtexparser.h"
2 
loadIfModified(const QFileInfo & fi)3 bool	BibTeXFileInfo::loadIfModified(const QFileInfo &fi)
4 {
5 	QDateTime fileLastModified = fi.lastModified();
6 	if (lastModified != fileLastModified) { //load BibTeX iff modified
7 		lastModified = fileLastModified;
8 		load(fi);
9 		return true;
10 	}
11 	return false;
12 }
13 
load(const QFileInfo & fi)14 void BibTeXFileInfo::load(const QFileInfo &fi)
15 {
16 	//lastModified=lastModified; see above
17 	QFile f(fi.absoluteFilePath());
18 	if (!f.open(QFile::ReadOnly)) return; //ups...
19 	QByteArray data = f.readAll().trimmed();
20 	parse(data);
21 }
22 
parse(QByteArray & data)23 void BibTeXFileInfo::parse(QByteArray &data)
24 {
25 	ids.clear();
26 	linksTo.clear();
27 	if (data.startsWith("link ")) {
28 		//handle obscure bib tex feature, a just line containing "link fileName"
29 		linksTo  = QString::fromLatin1(data.constData(), data.count()).mid(5).trimmed();
30 	} else {
31 		enum BibTeXState {BTS_IN_SPACE,  //searches the first @, ignore everything before it
32 		                  BTS_IN_TYPE,   //read until bracket ( or { e.g in @article{, reset if @comment
33 		                  BTS_IN_ID,     //read everything until bracket close or , and ignore whitespace, reset when = or "
34 		                  BTS_IN_DATA_KEY
35 		                 }; //read balanced bracket until all are closed, then reset
36 		enum BibTeXState state = BTS_IN_SPACE;
37 		const char *comment = "comment\0";
38 		const char *COMMENT = "COMMENT\0";
39 		int typeLen = 0;
40 		bool commentPossible = false;
41 		int bracketBalance = 0;
42 		char bracketOpen = 0;
43 		char bracketClose = 0;
44 		QByteArray curID;
45 		for (int j = 0; j < data.count(); j++) {
46 			char c = data.at(j);
47 			switch (state) {
48 			case BTS_IN_SPACE:
49 				if (c == '@') {
50 					state = BTS_IN_TYPE;
51 					commentPossible = true;
52 					typeLen = 0;
53 				}
54 				break;
55 			case BTS_IN_TYPE:
56 				if (c == '(' || c == '{') {
57 					bracketOpen = c;
58 					if (c == '(') bracketClose = ')';
59 					if (c == '{') bracketClose = '}';
60 					bracketBalance = 1;
61 					curID = "";
62 					state = BTS_IN_ID;
63 				} else if (commentPossible && (comment[typeLen] == c || COMMENT[typeLen] == c)) {
64 					if (comment[typeLen + 1] == '\0') state = BTS_IN_SPACE; //comment found
65 				} else commentPossible = false;
66 				typeLen++;
67 				break;
68 			case BTS_IN_ID:
69 				if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
70 					if (c == ',' || c == bracketClose) {
71 						if (!curID.isEmpty()) {
72 							if (codec)
73 								ids.insert(codec->toUnicode(curID)); //**found id**
74 							else
75 								ids.insert(curID);
76 						}
77 						state = BTS_IN_DATA_KEY;
78 					} else if (c == '=' || c == '"')
79 						state = BTS_IN_DATA_KEY; //@string or @preamble (don't cite that)
80 					else curID += c;
81 				}
82 				break;
83 			case BTS_IN_DATA_KEY:
84 				if (c == bracketOpen) bracketBalance++;
85 				else if (c == bracketClose) {
86 					bracketBalance--;
87 					if (bracketBalance <= 0) state = BTS_IN_SPACE;
88 				}
89 				break;
90 			}
91 		}
92 	}
93 }
94