-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEBookEntry.cpp
More file actions
277 lines (239 loc) · 7.4 KB
/
EBookEntry.cpp
File metadata and controls
277 lines (239 loc) · 7.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
// File EBookEntry.cpp
// Implementation for classes
// EBookEntry
// EBookEntryReader
// Author: Michael Loceff c 2009
// reads a file containing lines in the format desribed in
// EBookEntry_FormatKey, and provides a vector-like structure
// (a EBookEntryReader object) filled with EBookEntry objects
// for use by the client
#include "EBookEntry.h"
// EBookEntryReader methods ---------------------------------------------
// reads one string in the above record (all lines of the record
// are assumed to be concatenated into a single line prior to
// this call surrounded by <pgterms:etext> ... </pgterms:etext> )
// and leaves data in an EBookEntry object for return to client
EBookEntry EBookEntryReader::readOneBook(string entryString)
{
EBookEntry book;
book.SetNEtextNum(readIDFromLine(entryString));
book.setCreator(readStringFromEntry(entryString, "<dc:creator"));
book.setTitle(readStringFromEntry(entryString, "<dc:title"));
book.setSubject(readStringFromEntry(entryString, "<dc:subject"));
return book;
}
int EBookEntryReader::readIDFromLine(string line)
{
unsigned int startNumPos;
int numLength;
startNumPos = line.find("ID=\"etext") + 9;
numLength = line.substr(startNumPos).find( "\"");
if (startNumPos < 0 || startNumPos > EBookEntry::MAX_STRING
|| numLength < 0 || numLength > 20 )
return 0;
else
return convertToInt(line.substr(startNumPos, numLength));
}
// looks for a line of the form "<pgterms:etext --- " signifying a
// new record to be read and returns true if found
bool EBookEntryReader::isDataLine(string line)
{
string s;
if (line.length() < 15)
return false;
// check for a line of the form "<pgterms:etext --- "
if (line.substr(0,14) == "<pgterms:etext")
return true;
return false;
}
string EBookEntryReader::readStringFromEntry
(string entryString, string delimiter)
{
unsigned int start, stop, k;
string stringAfterDelimiter;
if (delimiter.length() < 1 || entryString.length() < delimiter.length())
return "(no data found)";
// first find "<dc:title", e.g.
start = entryString.find(delimiter);
if (start > EBookEntry::MAX_ENTRY_LENGTH)
return "(no data found)";
stringAfterDelimiter = entryString.substr(start+delimiter.length());
// we're looking for something line ">A ..." rather than ">< ... "
for (k = 0; k < stringAfterDelimiter.length() - 1; k++)
{
// rather than using isalpha() we check manually to avoid foreign
if (stringAfterDelimiter[k] == '>'
&&
// home made isalpha()
(
(stringAfterDelimiter[k+1]>='a' && stringAfterDelimiter[k+1] <= 'z')
||
(stringAfterDelimiter[k+1]>='A' && stringAfterDelimiter[k+1] <= 'Z')
)
)
break;
}
if (k == stringAfterDelimiter.length() - 1)
return "(no data found)";
// we've got the starging position for the raw data
start = k + 1;
stringAfterDelimiter = stringAfterDelimiter.substr(start); // cut off tags
stop = stringAfterDelimiter.find("<"); // by above condition, cannot be 0
return stringAfterDelimiter.substr(0, stop);
}
EBookEntry &EBookEntryReader::operator[](int k)
{
static EBookEntry dummyReturn;
if (k < 0 || k >= numBooks)
return dummyReturn;
return books[k];
}
// reads lines from the input stream, concatenating until it finds
// the terminating tag, "</pgterms:etext>". Result is a single long
// line containing entire record wrapped in
// "<pgterms:etext> ... </pgterms:etext>" which it returns to client.
// assumes first line containing <pgterms:etext> is already in
// line parameter - required for call
string EBookEntryReader::readOneEntry(ifstream &infile, string line)
{
string fullEntry = line;
string nextLine;
while ( !infile.eof() && fullEntry.length() < EBookEntry::MAX_ENTRY_LENGTH - 20 )
{
getline (infile, nextLine);
fullEntry += nextLine;
if (nextLine == "</pgterms:etext>")
break;
}
// if we have an unterminated entry, force it to be terminated.
if (nextLine != "</pgterms:etext>")
fullEntry += "</pgterms:etext>";
return fullEntry;
}
// constructor which does entire read operation
EBookEntryReader::EBookEntryReader(string fileName)
{
string name;
string line, entryString;
EBookEntry book;
numBooks = 0;
fileOpenError = false;
bookFile = "NO FILE NAME PROVIDED";
if (fileName.length() == 0)
{
fileOpenError = true;
return;
}
bookFile = fileName;
// open file for reading
ifstream infile(fileName.c_str());
if (!infile)
{
fileOpenError = true;
return;
}
// for each line that starts #. read and add to vector
numBooks = 0;
while ( !infile.eof() )
{
getline (infile, line);
if (isDataLine(line))
{
entryString = readOneEntry(infile, line); // expands line to an entry
// if it is not an English entry, we'll have problems with chars
if ( entryString.find( ">en<" ) > EBookEntry::MAX_ENTRY_LENGTH )
continue;
book = readOneBook(entryString);
books.push_back(book);
numBooks++;
}
}
infile.close();
}
int EBookEntryReader::convertToInt(string strToCnvrt)
{
int retInt;
istringstream(strToCnvrt) >> retInt;
return retInt;
}
// EBookEntry methods ---------------------------------------------------
// static int initialization
int EBookEntry::sortKey = EBookEntry::SORT_BY_CREATOR;
// default constructor
EBookEntry::EBookEntry()
: title(""), creator(""), subject(""), eTextNum(0)
{
}
// mutators
bool EBookEntry::setTitle(string strArg)
{
if (strArg.length() < MIN_STRING || strArg.length() > MAX_STRING)
return false;
title = strArg;
return true;
}
bool EBookEntry::setCreator(string strArg)
{
if (strArg.length() < MIN_STRING || strArg.length() > MAX_STRING)
return false;
creator = strArg;
return true;
}
bool EBookEntry::setSubject(string strArg)
{
if (strArg.length() < MIN_STRING || strArg.length() > MAX_STRING)
return false;
subject = strArg;
return true;
}
bool EBookEntry::SetNEtextNum(int intArg)
{
if (intArg < 1 || intArg > MAX_ID)
return false;
eTextNum = intArg;
return true;
}
bool EBookEntry::setSortType( int whichType )
{
switch (whichType)
{
case SORT_BY_TITLE:
case SORT_BY_CREATOR:
case SORT_BY_SUBJECT:
case SORT_BY_ID:
sortKey = whichType;
return true;
default:
return false;
}
return true;
}
bool EBookEntry::operator<(const EBookEntry &other) const
{
switch (sortKey)
{
case SORT_BY_TITLE:
return (title < other.title);
case SORT_BY_CREATOR:
return (creator < other.creator);
case SORT_BY_SUBJECT:
return (subject < other.subject);
case SORT_BY_ID:
return (eTextNum < other.eTextNum);
default:
return false;
}
return true;
}
bool EBookEntry::operator>(const EBookEntry &other) const
{
return (other < *this);
}
bool EBookEntry::operator==(const EBookEntry &other) const
{
return !(other < *this) && !(*this < other);
}
bool EBookEntry::operator!=(const EBookEntry &other) const
{
return !(other == *this);
}