-
Notifications
You must be signed in to change notification settings - Fork 516
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
Added SQLite header parsing functionality and associated tests #249
Changes from 3 commits
8723d0e
0e88d62
251388c
afe10c3
1acb606
fe14559
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -300,6 +300,138 @@ bool Database::isUnencrypted(const std::string& aFilename) | |
throw exception; | ||
} | ||
|
||
// Parse header data from a database. | ||
Header Database::getHeaderInfo(const std::string& aFilename) | ||
{ | ||
Header h; | ||
unsigned char buf[100]; | ||
|
||
if (aFilename.length() > 0 ) | ||
{ | ||
|
||
std::ifstream fileBuffer(aFilename.c_str(), std::ios::in | std::ios::binary); | ||
|
||
if (fileBuffer.is_open()) | ||
{ | ||
fileBuffer.seekg(0, std::ios::beg); | ||
fileBuffer.read(reinterpret_cast<char*>(&buf[0]), 100); | ||
fileBuffer.close(); | ||
strncpy(reinterpret_cast<char*>(&h.headerStr[0]), reinterpret_cast<char*>(buf), 16); | ||
} | ||
|
||
else | ||
{ | ||
const SQLite::Exception exception("Error opening file: " + aFilename); | ||
throw exception; | ||
} | ||
|
||
// If the "magic string" can't be found then header is invalid, corrupt or unreadable | ||
if (!strncmp(reinterpret_cast<const char*>(h.headerStr), "SQLite format 3", 15) == 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly here, headerStr could simply be a char[] variable directly on the header structure |
||
{ | ||
const SQLite::Exception exception("Invalid SQLite header"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or encrypted database |
||
throw exception; | ||
} | ||
|
||
h.pageSizeBytes = (buf[16] << 8) | buf[17]; | ||
h.fileFormatWriteVersion = buf[18]; | ||
h.fileFormatReadVersion = buf[19]; | ||
h.reservedSpaceBytes = buf[20]; | ||
h.maxEmbeddedPayloadFrac = buf[21]; | ||
h.minEmbeddedPayloadFrac = buf[22]; | ||
h.leafPayloadFrac = buf[23]; | ||
|
||
h.fileChangeCounter = | ||
(buf[24] << 24) | | ||
(buf[25] << 16) | | ||
(buf[26] << 8) | | ||
(buf[27] << 0); | ||
|
||
h.databaseSizePages = | ||
(buf[28] << 24) | | ||
(buf[29] << 16) | | ||
(buf[30] << 8) | | ||
(buf[31] << 0); | ||
|
||
h.firstFreelistTrunkPage = | ||
(buf[32] << 24) | | ||
(buf[33] << 16) | | ||
(buf[34] << 8) | | ||
(buf[35] << 0); | ||
|
||
h.totalFreelistPages = | ||
(buf[36] << 24) | | ||
(buf[37] << 16) | | ||
(buf[38] << 8) | | ||
(buf[39] << 0); | ||
|
||
h.schemaCookie = | ||
(buf[40] << 24) | | ||
(buf[41] << 16) | | ||
(buf[42] << 8) | | ||
(buf[43] << 0); | ||
|
||
h.schemaFormatNumber = | ||
(buf[44] << 24) | | ||
(buf[45] << 16) | | ||
(buf[46] << 8) | | ||
(buf[47] << 0); | ||
|
||
h.defaultPageCacheSizeBytes = | ||
(buf[48] << 24) | | ||
(buf[49] << 16) | | ||
(buf[50] << 8) | | ||
(buf[51] << 0); | ||
|
||
h.largestBTreePageNumber = | ||
(buf[52] << 24) | | ||
(buf[53] << 16) | | ||
(buf[54] << 8) | | ||
(buf[55] << 0); | ||
|
||
h.databaseTextEncoding = | ||
(buf[56] << 24) | | ||
(buf[57] << 16) | | ||
(buf[58] << 8) | | ||
(buf[59] << 0); | ||
|
||
h.userVersion = | ||
(buf[60] << 24) | | ||
(buf[61] << 16) | | ||
(buf[62] << 8) | | ||
(buf[63] << 0); | ||
|
||
h.incrementalVaccumMode = | ||
(buf[64] << 24) | | ||
(buf[65] << 16) | | ||
(buf[66] << 8) | | ||
(buf[67] << 0); | ||
|
||
h.applicationId = | ||
(buf[68] << 24) | | ||
(buf[69] << 16) | | ||
(buf[70] << 8) | | ||
(buf[71] << 0); | ||
|
||
h.versionValidFor = | ||
(buf[92] << 24) | | ||
(buf[93] << 16) | | ||
(buf[94] << 8) | | ||
(buf[95] << 0); | ||
|
||
h.sqliteVersion = | ||
(buf[96] << 24) | | ||
(buf[97] << 16) | | ||
(buf[98] << 8) | | ||
(buf[99] << 0); | ||
|
||
return h; | ||
} | ||
|
||
const SQLite::Exception exception("Could not open database, the aFilename parameter was empty."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you perhaps put this exception at the start of the function like I did yesterday on a cleanup commit? It would avoid the return being inside the scope. |
||
throw exception; | ||
} | ||
|
||
|
||
// This is a reference implementation of live backup taken from the official sit: | ||
// https://www.sqlite.org/backup.html | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to avoid these cast; perhaps have one additional "pointer of char" variable pointing to the buf.
unsigned char buf[100];
char* pBuf = reinterpret_cast<char*>(&buf[0]);