Files
sqlitebrowser/src/ExportCsvDialog.cpp
Martin Kleusberg 9ba36d02b2 Add initial SQLCipher support
Add some basic initial support for SQLCipher. Note that this is more of
a POC than a final implementation.

This commit adds an option called 'sqlcipher' to the cmake and qmake
projects which - when enabled - replaces the default SQLite3 include and
library files by their SQLCipher counter-parts. Especially on MacOS X
there might be some more work required in finding the correct include
paths. The SQLCipher library supports unencrypted databases, too, so
even if the option is enabled the program behaves like before. You can
see the difference, though, in the About Dialog where the SQLite version
string will say 'SQLCipher version xy'.

When the sqlcipher option is enabled and you try to open a file which is
neither a project file nor a normal SQLite3 database it is assumed now
that the file is an encypted database. There is no way to tell between
an invalid file and an encypted file, so in both cases a password dialog
pops up. When the correct password and page size are entered the file is
opened and can be edited like any other database before.

Creating encrypted databases isn't supported yet. So for testing you
need to fall back to the sqlcipher command line tool.

See issue #12.
2014-11-01 12:56:53 +01:00

153 lines
5.7 KiB
C++

#include "ExportCsvDialog.h"
#include "ui_ExportCsvDialog.h"
#include "sqlitedb.h"
#include "PreferencesDialog.h"
#include "sqlitetablemodel.h"
#include "sqlite.h"
#include <QFile>
#include <QTextStream>
#include <QMessageBox>
#include <QFileDialog>
ExportCsvDialog::ExportCsvDialog(DBBrowserDB* db, QWidget* parent, const QString& query, const QString& selection)
: QDialog(parent),
ui(new Ui::ExportCsvDialog),
pdb(db),
m_sQuery(query)
{
// Create UI
ui->setupUi(this);
showCustomCharEdits();
// If a SQL query was specified hide the table combo box. If not fill it with tables to export
if(query.isEmpty())
{
// Get list of tables to export
objectMap objects = pdb->getBrowsableObjects();
for(objectMap::ConstIterator i=objects.begin();i!=objects.end();++i)
ui->comboTable->addItem(QIcon(QString(":icons/%1").arg(i.value().gettype())), i.value().getname());
// Sort list of tables and select the table specified in the selection parameter or alternatively the first one
ui->comboTable->model()->sort(0);
if(selection.isEmpty())
ui->comboTable->setCurrentIndex(0);
else
ui->comboTable->setCurrentIndex(ui->comboTable->findText(selection));
} else {
// Hide table combo box
ui->labelTable->setVisible(false);
ui->comboTable->setVisible(false);
}
}
ExportCsvDialog::~ExportCsvDialog()
{
delete ui;
}
void ExportCsvDialog::accept()
{
// Get filename
QString fileName = QFileDialog::getSaveFileName(
this,
tr("Choose a filename to export data"),
PreferencesDialog::getSettingsValue("db", "defaultlocation").toString(),
tr("Text files(*.csv *.txt)"));
// Only if the user hasn't clicked the cancel button
if(fileName.size() > 0)
{
if(m_sQuery.isEmpty())
{
m_sQuery = QString("SELECT * from `%1`;").arg(ui->comboTable->currentText());
}
// Prepare the quote and separating characters
QString quoteChar = ui->comboQuoteCharacter->currentIndex() == ui->comboQuoteCharacter->count()-1
? ui->editCustomQuote->text() : ui->comboQuoteCharacter->currentText();
QString quotequoteChar = quoteChar + quoteChar;
QString sepChar;
if(ui->comboFieldSeparator->currentIndex() == ui->comboFieldSeparator->count()-1)
{
sepChar = ui->editCustomSeparator->text();
} else {
sepChar = ui->comboFieldSeparator->currentText();
if(sepChar == tr("Tab")) sepChar = "\t";
}
QString newlineChar = "\r\n";
// Open file
QFile file(fileName);
if(file.open(QIODevice::WriteOnly))
{
// Open text stream to the file
QTextStream stream(&file);
QByteArray utf8Query = m_sQuery.toUtf8();
sqlite3_stmt *stmt;
int status = sqlite3_prepare_v2(pdb->_db, utf8Query.data(), utf8Query.size(), &stmt, NULL);
if(SQLITE_OK == status)
{
if(ui->checkHeader->isChecked())
{
int columns = sqlite3_column_count(stmt);
for (int i = 0; i < columns; ++i)
{
QString content = QString::fromUtf8(sqlite3_column_name(stmt, i));
if(content.contains(quoteChar) || content.contains(newlineChar))
stream << quoteChar << content.replace(quoteChar, quotequoteChar) << quoteChar;
else
stream << content;
if(i != columns - 1)
stream << sepChar;
}
stream << newlineChar;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
int columns = sqlite3_column_count(stmt);
size_t counter = 0;
while(sqlite3_step(stmt) == SQLITE_ROW)
{
for (int i = 0; i < columns; ++i)
{
QString content = QString::fromUtf8(
(const char*)sqlite3_column_blob(stmt, i),
sqlite3_column_bytes(stmt, i));
if(content.contains(quoteChar) || content.contains("\r\n") || content.contains('\n'))
stream << quoteChar << content.replace(quoteChar, quotequoteChar) << quoteChar;
else
stream << content;
if(i != columns - 1)
stream << sepChar;
}
stream << newlineChar;
if(counter % 1000 == 0)
qApp->processEvents();
counter++;
}
}
sqlite3_finalize(stmt);
QApplication::restoreOverrideCursor();
qApp->processEvents();
// Done writing the file
file.close();
QMessageBox::information(this, QApplication::applicationName(), tr("Export completed."));
QDialog::accept();
} else {
QMessageBox::warning(this, QApplication::applicationName(), tr("Could not open output file."));
}
}
}
void ExportCsvDialog::showCustomCharEdits()
{
// Show/hide custom quote/separator input fields
ui->editCustomQuote->setVisible(ui->comboQuoteCharacter->currentIndex() == ui->comboQuoteCharacter->count()-1);
ui->editCustomSeparator->setVisible(ui->comboFieldSeparator->currentIndex() == ui->comboFieldSeparator->count()-1);
}