<commit_before>/* nobleNote, a note taking application
 * Copyright (C) 2012 Christian Metscher <hakaishi@web.de>,
                      Fabian Deuchler <Taiko000@gmail.com>

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.

 * nobleNote is licensed under the MIT, see `http://copyfree.org/licenses/mit/license.txt'.
 */

#include "backup.h"
#include "htmlnotereader.h"
#include "abstractnotereader.h"
#include <QDirIterator>
#include <QMessageBox>
#include <QSettings>
#include <QtConcurrentMap>
#include <QAbstractItemModel>

Backup::Backup(QWidget *parent): QDialog(parent){
     setupUi(this);

     splitter = new QSplitter(groupBox);
     gridLayout_2->addWidget(splitter);
     treeWidget = new QTreeWidget(splitter);
     treeWidget->setAlternatingRowColors(true);
     treeWidget->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
     treeWidget->setSortingEnabled(true);
     frame = new QFrame(splitter);
     gridLayout3 = new QGridLayout(frame);
     label = new QLabel(frame);
     label->setText(tr("Preview of the selected backup"));
     gridLayout3->addWidget(label, 0, 0, 1, 1);
     textEdit = new QTextEdit(this);
     textEdit->setDisabled(frame);
     gridLayout3->addWidget(textEdit, 1, 0, 1, 1);

     document = new QTextDocument(this);
     textEdit->setDocument(document);

     QStringList header;
     header << tr("Backups") << tr("Titels");
     treeWidget->setHeaderLabels(header);

     setupTreeData();

     deleteOldButton = new QPushButton(tr("&delete all old backups and file entries"),this);
     buttonBox->addButton(deleteOldButton ,QDialogButtonBox::ActionRole);

     //TODO: should be selectionChanged instead of activated...
     connect(treeWidget, SIGNAL(activated(QModelIndex)), this, SLOT(showPreview(QModelIndex)));
     connect(this, SIGNAL(handleBackupsSignal()), this, SLOT(handleBackups()));
     connect(this, SIGNAL(accepted()), this, SLOT(restoreBackup()));
     connect(deleteOldButton, SIGNAL(clicked(bool)), this, SLOT(deleteOldBackupsAndFileEntries()));
}

void Backup::setupTreeData()
{
     treeWidget->clear(); //if there already is any data

     //Load backup data
     QMap<QString,QList<QVariant> > backupMap;
     QDir backupDir(QSettings().value("backupDirPath").toString());
     QList<QFileInfo> backupList = backupDir.entryInfoList(QDir::Files, QDir::Name);
     foreach(QFileInfo backup, backupList)
     {
          QList<QVariant> data = getFileData(backup.absoluteFilePath());
          data.takeFirst();
          backupMap.insert(backup.absoluteFilePath(), data);
     }

     //Load note data
     QMap<QString,QList<QVariant> > noteMap;
     QDirIterator itFiles(QSettings().value("noteDirPath").toString(),
                                              QDirIterator::Subdirectories);
     QStringList noteFiles;
     while(itFiles.hasNext()){
       QString filePath = itFiles.next();
       if(itFiles.fileInfo().isFile())
         noteFiles << filePath;
     }
     QStringList notebookNameList; //Get notebook names
     foreach(QString note, noteFiles)
     {
          QList<QVariant> data = getFileData(note);
          QString uuid = data.takeFirst().toString();
          QString title = data.takeFirst().toString();
          data.clear(); //We don't need more than that
          QString notebook = note;
          notebook.remove("/" + QFileInfo(note).fileName());
          notebook.remove(QSettings().value("noteDirPath").toString() + "/");
          notebookNameList << notebook;
          QList<QVariant> list;
          list << notebook << title;
          noteMap.insert(uuid, list);
     }
     notebookNameList.removeDuplicates();

     foreach(QString notebookName, notebookNameList)
     {
          //Create tree toplevel items for notebooks
          QTreeWidgetItem *notebookItem = new QTreeWidgetItem(treeWidget);
          notebookItem->setText(0,notebookName);

          //Get note titles and create a child for the notebook
          foreach(QString noteUuid, noteMap.keys())
          {
               if(noteMap[noteUuid].first() == notebookName)
               {
                    //Create a child with the note title
                    noteMap[noteUuid].takeFirst(); //removing notebook name to get the title
                    QTreeWidgetItem *noteItem = new QTreeWidgetItem(notebookItem);
                    noteItem->setText(0,noteMap[noteUuid].first().toString());

                    foreach(QString backupFile, backupMap.keys())
                    {
                         QString backupUuid = "{" + backupFile + "}";
                         backupUuid.remove(QSettings().value("backupDirPath").toString() + "/");
                         backupUuid.remove(QRegExp("_\\d+\\-\\d+\\-\\d+T\\d+\\-\\d+\\-\\d+"));

                         //Create for each backup of the note a child with date and title
                         if(noteUuid == backupUuid)
                         {
                              QList<QVariant> list = backupMap[backupFile];
                              backupMap.remove(backupFile);
                              QString title = list.takeFirst().toString();
                              QDateTime date = list.takeFirst().toDateTime();
                              QStringList content;
                              content<< backupFile << list.takeFirst().toString();
                              QTreeWidgetItem *backupItem = new QTreeWidgetItem(noteItem);
                              backupItem->setText(0, date.toString("yyyy-MM-dd hh-mm-ss"));
                              backupItem->setData(0,Qt::UserRole,content);
                              backupItem->setText(1, title);
                         }
                    }
               }
          }
     }

     //Create toplevel item for backups of deleted notes
     QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
     item->setText(0,tr("Backups of deleted notes"));

     //Get remaining backups
     QStringList backupFiles = backupMap.keys();
     QStringList deletedTitles;
     foreach(QString path, backupFiles)
     {
          QString str = path;
          str.remove(QRegExp("_\\d+\\-\\d+\\-\\d+T\\d+\\-\\d+\\-\\d+"));
          deletedTitles << str;
     }
     deletedTitles.removeDuplicates();

     foreach(QString backupPath, deletedTitles)
     {
          QTreeWidgetItem *childItem = new QTreeWidgetItem(item);
          childItem->setText(0,backupMap[backupPath].first().toString());

          foreach(QString backupFile, backupMap.keys())
          {
               QList<QVariant> list = backupMap[backupFile];
               backupMap.remove(backupFile);
               QString title = list.takeFirst().toString();
               QDateTime date = list.takeFirst().toDateTime();
               QStringList content;
               content << backupFile << list.takeFirst().toString();
               QTreeWidgetItem *backupItem = new QTreeWidgetItem(childItem);
               backupItem->setText(0,date.toString("yyyy-MM-dd hh-mm-ss"));
               backupItem->setData(0,Qt::UserRole,content);
               backupItem->setText(1,title);
          }
     }

     treeWidget->resizeColumnToContents(0);
}

QList<QVariant> Backup::getFileData(const QString &file)
{
     AbstractNoteReader *reader = new HtmlNoteReader(file,document);
     QList<QVariant> list;
     QString uuid = reader->uuid();
     list << uuid << reader->title() << reader->lastChange() << document->toHtml();
     return list;
}

void Backup::showPreview(const QModelIndex &idx)
{
     QStringList dataList = idx.data(Qt::UserRole).toStringList();
     textEdit->setText(dataList.last());
}

void Backup::restoreBackup()
{
     QStringList dataList = treeWidget->selectionModel()->currentIndex().data(Qt::UserRole).toStringList();
     if(!QFile(dataList.first()).exists())
       return;
     else
     {
        qDebug()<<dataList.first();//TODO:Remove or Override Note
     }
}

void Backup::handleBackups()
{
//TODO: Create and handle Backups here
}

void Backup::getNoteUuidList(){
     QFutureIterator<QUuid> it(future1->future());
     while(it.hasNext())
       notesUuids << it.next();
}

void Backup::deleteOldBackupsAndFileEntries(){
     notesUuids.clear(); //make sure that it's empty

     //searching for existing Notes
     QDirIterator itFiles(QSettings().value("noteDirPath").toString(),
                                              QDirIterator::Subdirectories);
     QStringList noteFiles;
     while(itFiles.hasNext()){
       QString filePath = itFiles.next();
       if(itFiles.fileInfo().isFile())
         noteFiles << filePath;
     }

     future1 = new QFutureWatcher<QUuid>(this);

     QUuid (*uuidPtr)(QString) = & HtmlNoteReader::uuid; // function pointer, because uuid method is overloaded
     future1->setFuture(QtConcurrent::mapped(noteFiles, uuidPtr));

     indexDialog = new QProgressDialog(this);
     indexDialog->setLabelText(QString(tr("Indexing notes...")));

     QObject::connect(future1, SIGNAL(finished()), this, SLOT(getNoteUuidList()));
     QObject::connect(future1, SIGNAL(finished()), this, SLOT(progressChanges()));
     QObject::connect(future1, SIGNAL(finished()), indexDialog, SLOT(reset()));
     QObject::connect(indexDialog, SIGNAL(canceled()), future1, SLOT(cancel()));
     QObject::connect(future1, SIGNAL(progressRangeChanged(int,int)),
                indexDialog, SLOT(setRange(int,int)));
     QObject::connect(future1, SIGNAL(progressValueChanged(int)), indexDialog,
                SLOT(setValue(int)));

     indexDialog->exec();
}

void actualRemoval(const QString& backupAndUuid){
     if(!backupAndUuid.contains("Notes/"))
       QFile::remove(backupAndUuid);
     else
       QSettings().remove(backupAndUuid);
}

void Backup::progressChanges(){
     //get backup files
     QStringList backups;
     QDir backupDir(QSettings().value("backupDirPath").toString());
     QList<QFileInfo> backupList = backupDir.entryInfoList(QDir::Files, QDir::Name);
     foreach(QFileInfo backup, backupList)
          backups << backup.absoluteFilePath();

     //add QSettings Uuids to the backups
     QStringList backupsAndUuids = backups + QSettings().allKeys().filter("Notes/");

     //We only need the redundant backups and Uuids
     foreach(QString str, backupsAndUuids){
       if(!str.contains("Notes/") && notesUuids.contains(QFileInfo(str).fileName()))
         backupsAndUuids.removeOne(str);
       if(str.contains("Notes/")){
         QString settings = str;
         settings.remove("Notes/");
         settings.remove("_size");
         settings.remove("_cursor_position");
         if(notesUuids.contains(settings))
           backupsAndUuids.removeOne(str);
       }
     }

     QString redundantBackupList;
     foreach(QString str, backupsAndUuids)
       if(!str.contains("Notes/"))
         redundantBackupList += (str+"\n");

     if(backupsAndUuids.isEmpty()){
          QMessageBox::information(this, tr("No redundant data!"), tr("no redundant"
                                   " Everything is clean! No redundant data!"));
          return;
     }
     else{
       if(QMessageBox::warning(this,tr("Deleting backups and file entries"),
           tr("Do you really want to delete the backups and entries for the "
              "following files?\n\n%1\nYou won't be able to restore them!").arg(
           redundantBackupList),
           QMessageBox::Yes | QMessageBox::Abort) != QMessageBox::Yes)
         return;
     }

     progressDialog = new QProgressDialog(this);
     progressDialog->setLabelText(QString(tr("Progressing files...")));

     future2 = new QFutureWatcher<void>(this);
     future2->setFuture(QtConcurrent::map(backupsAndUuids, actualRemoval));

     QObject::connect(future2, SIGNAL(finished()), progressDialog, SLOT(reset()));
     QObject::connect(future2, SIGNAL(finished()), this, SLOT(setupTreeData()));
     QObject::connect(progressDialog, SIGNAL(canceled()), future2, SLOT(cancel()));
     QObject::connect(future2, SIGNAL(progressRangeChanged(int,int)), progressDialog,
                                                                SLOT(setRange(int,int)));
     QObject::connect(future2, SIGNAL(progressValueChanged(int)), progressDialog,
                                                                SLOT(setValue(int)));

     progressDialog->exec();
}
<commit_msg>fixed crush after clicked on empty column.<commit_after>/* nobleNote, a note taking application
 * Copyright (C) 2012 Christian Metscher <hakaishi@web.de>,
                      Fabian Deuchler <Taiko000@gmail.com>

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.

 * nobleNote is licensed under the MIT, see `http://copyfree.org/licenses/mit/license.txt'.
 */

#include "backup.h"
#include "htmlnotereader.h"
#include "abstractnotereader.h"
#include <QDirIterator>
#include <QMessageBox>
#include <QSettings>
#include <QtConcurrentMap>
#include <QAbstractItemModel>

Backup::Backup(QWidget *parent): QDialog(parent){
     setupUi(this);

     splitter = new QSplitter(groupBox);
     gridLayout_2->addWidget(splitter);
     treeWidget = new QTreeWidget(splitter);
     treeWidget->setAlternatingRowColors(true);
     treeWidget->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
     treeWidget->setSortingEnabled(true);
     frame = new QFrame(splitter);
     gridLayout3 = new QGridLayout(frame);
     label = new QLabel(frame);
     label->setText(tr("Preview of the selected backup"));
     gridLayout3->addWidget(label, 0, 0, 1, 1);
     textEdit = new QTextEdit(this);
     textEdit->setDisabled(frame);
     gridLayout3->addWidget(textEdit, 1, 0, 1, 1);

     document = new QTextDocument(this);
     textEdit->setDocument(document);

     QStringList header;
     header << tr("Backups") << tr("Titels");
     treeWidget->setHeaderLabels(header);

     setupTreeData();

     deleteOldButton = new QPushButton(tr("&delete all old backups and file entries"),this);
     buttonBox->addButton(deleteOldButton ,QDialogButtonBox::ActionRole);

     //TODO: should be selectionChanged instead of activated...
     connect(treeWidget, SIGNAL(activated(QModelIndex)), this, SLOT(showPreview(QModelIndex)));
     connect(this, SIGNAL(handleBackupsSignal()), this, SLOT(handleBackups()));
     connect(this, SIGNAL(accepted()), this, SLOT(restoreBackup()));
     connect(deleteOldButton, SIGNAL(clicked(bool)), this, SLOT(deleteOldBackupsAndFileEntries()));
}

void Backup::setupTreeData()
{
     treeWidget->clear(); //if there already is any data

     //Load backup data
     QMap<QString,QList<QVariant> > backupMap;
     QDir backupDir(QSettings().value("backupDirPath").toString());
     QList<QFileInfo> backupList = backupDir.entryInfoList(QDir::Files, QDir::Name);
     foreach(QFileInfo backup, backupList)
     {
          QList<QVariant> data = getFileData(backup.absoluteFilePath());
          data.takeFirst();
          backupMap.insert(backup.absoluteFilePath(), data);
     }

     //Load note data
     QMap<QString,QList<QVariant> > noteMap;
     QDirIterator itFiles(QSettings().value("noteDirPath").toString(),
                                              QDirIterator::Subdirectories);
     QStringList noteFiles;
     while(itFiles.hasNext()){
       QString filePath = itFiles.next();
       if(itFiles.fileInfo().isFile())
         noteFiles << filePath;
     }
     QStringList notebookNameList; //Get notebook names
     foreach(QString note, noteFiles)
     {
          QList<QVariant> data = getFileData(note);
          QString uuid = data.takeFirst().toString();
          QString title = data.takeFirst().toString();
          data.clear(); //We don't need more than that
          QString notebook = note;
          notebook.remove("/" + QFileInfo(note).fileName());
          notebook.remove(QSettings().value("noteDirPath").toString() + "/");
          notebookNameList << notebook;
          QList<QVariant> list;
          list << notebook << title;
          noteMap.insert(uuid, list);
     }
     notebookNameList.removeDuplicates();

     foreach(QString notebookName, notebookNameList)
     {
          //Create tree toplevel items for notebooks
          QTreeWidgetItem *notebookItem = new QTreeWidgetItem(treeWidget);
          notebookItem->setText(0,notebookName);

          //Get note titles and create a child for the notebook
          foreach(QString noteUuid, noteMap.keys())
          {
               if(noteMap[noteUuid].first() == notebookName)
               {
                    //Create a child with the note title
                    noteMap[noteUuid].takeFirst(); //removing notebook name to get the title
                    QTreeWidgetItem *noteItem = new QTreeWidgetItem(notebookItem);
                    noteItem->setText(0,noteMap[noteUuid].first().toString());

                    foreach(QString backupFile, backupMap.keys())
                    {
                         QString backupUuid = "{" + backupFile + "}";
                         backupUuid.remove(QSettings().value("backupDirPath").toString() + "/");
                         backupUuid.remove(QRegExp("_\\d+\\-\\d+\\-\\d+T\\d+\\-\\d+\\-\\d+"));

                         //Create for each backup of the note a child with date and title
                         if(noteUuid == backupUuid)
                         {
                              QList<QVariant> list = backupMap[backupFile];
                              backupMap.remove(backupFile);
                              QString title = list.takeFirst().toString();
                              QDateTime date = list.takeFirst().toDateTime();
                              QStringList content;
                              content<< backupFile << list.takeFirst().toString();
                              QTreeWidgetItem *backupItem = new QTreeWidgetItem(noteItem);
                              backupItem->setText(0, date.toString("yyyy-MM-dd hh-mm-ss"));
                              backupItem->setData(0,Qt::UserRole,content);
                              backupItem->setText(1, title);
                         }
                    }
               }
          }
     }

     //Create toplevel item for backups of deleted notes
     QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
     item->setText(0,tr("Backups of deleted notes"));

     //Get remaining backups
     QStringList backupFiles = backupMap.keys();
     QStringList deletedTitles;
     foreach(QString path, backupFiles)
     {
          QString str = path;
          str.remove(QRegExp("_\\d+\\-\\d+\\-\\d+T\\d+\\-\\d+\\-\\d+"));
          deletedTitles << str;
     }
     deletedTitles.removeDuplicates();

     foreach(QString backupPath, deletedTitles)
     {
          QTreeWidgetItem *childItem = new QTreeWidgetItem(item);
          childItem->setText(0,backupMap[backupPath].first().toString());

          foreach(QString backupFile, backupMap.keys())
          {
               QList<QVariant> list = backupMap[backupFile];
               backupMap.remove(backupFile);
               QString title = list.takeFirst().toString();
               QDateTime date = list.takeFirst().toDateTime();
               QStringList content;
               content << backupFile << list.takeFirst().toString();
               QTreeWidgetItem *backupItem = new QTreeWidgetItem(childItem);
               backupItem->setText(0,date.toString("yyyy-MM-dd hh-mm-ss"));
               backupItem->setData(0,Qt::UserRole,content);
               backupItem->setText(1,title);
          }
     }

     treeWidget->resizeColumnToContents(0);
}

QList<QVariant> Backup::getFileData(const QString &file)
{
     AbstractNoteReader *reader = new HtmlNoteReader(file,document);
     QList<QVariant> list;
     QString uuid = reader->uuid();
     list << uuid << reader->title() << reader->lastChange() << document->toHtml();
     return list;
}

void Backup::showPreview(const QModelIndex &idx)
{
     QStringList dataList = idx.data(Qt::UserRole).toStringList();
     if(dataList.isEmpty())
       return;
     textEdit->setText(dataList.last());
}

void Backup::restoreBackup()
{
     QStringList dataList = treeWidget->selectionModel()->currentIndex().data(Qt::UserRole).toStringList();
     if(!QFile(dataList.first()).exists())
       return;
     else
     {
        qDebug()<<dataList.first();//TODO:Remove or Override Note
     }
}

void Backup::handleBackups()
{
//TODO: Create and handle Backups here
}

void Backup::getNoteUuidList(){
     QFutureIterator<QUuid> it(future1->future());
     while(it.hasNext())
       notesUuids << it.next();
}

void Backup::deleteOldBackupsAndFileEntries(){
     notesUuids.clear(); //make sure that it's empty

     //searching for existing Notes
     QDirIterator itFiles(QSettings().value("noteDirPath").toString(),
                                              QDirIterator::Subdirectories);
     QStringList noteFiles;
     while(itFiles.hasNext()){
       QString filePath = itFiles.next();
       if(itFiles.fileInfo().isFile())
         noteFiles << filePath;
     }

     future1 = new QFutureWatcher<QUuid>(this);

     QUuid (*uuidPtr)(QString) = & HtmlNoteReader::uuid; // function pointer, because uuid method is overloaded
     future1->setFuture(QtConcurrent::mapped(noteFiles, uuidPtr));

     indexDialog = new QProgressDialog(this);
     indexDialog->setLabelText(QString(tr("Indexing notes...")));

     QObject::connect(future1, SIGNAL(finished()), this, SLOT(getNoteUuidList()));
     QObject::connect(future1, SIGNAL(finished()), this, SLOT(progressChanges()));
     QObject::connect(future1, SIGNAL(finished()), indexDialog, SLOT(reset()));
     QObject::connect(indexDialog, SIGNAL(canceled()), future1, SLOT(cancel()));
     QObject::connect(future1, SIGNAL(progressRangeChanged(int,int)),
                indexDialog, SLOT(setRange(int,int)));
     QObject::connect(future1, SIGNAL(progressValueChanged(int)), indexDialog,
                SLOT(setValue(int)));

     indexDialog->exec();
}

void actualRemoval(const QString& backupAndUuid){
     if(!backupAndUuid.contains("Notes/"))
       QFile::remove(backupAndUuid);
     else
       QSettings().remove(backupAndUuid);
}

void Backup::progressChanges(){
     //get backup files
     QStringList backups;
     QDir backupDir(QSettings().value("backupDirPath").toString());
     QList<QFileInfo> backupList = backupDir.entryInfoList(QDir::Files, QDir::Name);
     foreach(QFileInfo backup, backupList)
          backups << backup.absoluteFilePath();

     //add QSettings Uuids to the backups
     QStringList backupsAndUuids = backups + QSettings().allKeys().filter("Notes/");

     //We only need the redundant backups and Uuids
     foreach(QString str, backupsAndUuids){
       if(!str.contains("Notes/") && notesUuids.contains(QFileInfo(str).fileName()))
         backupsAndUuids.removeOne(str);
       if(str.contains("Notes/")){
         QString settings = str;
         settings.remove("Notes/");
         settings.remove("_size");
         settings.remove("_cursor_position");
         if(notesUuids.contains(settings))
           backupsAndUuids.removeOne(str);
       }
     }

     QString redundantBackupList;
     foreach(QString str, backupsAndUuids)
       if(!str.contains("Notes/"))
         redundantBackupList += (str+"\n");

     if(backupsAndUuids.isEmpty()){
          QMessageBox::information(this, tr("No redundant data!"), tr("no redundant"
                                   " Everything is clean! No redundant data!"));
          return;
     }
     else{
       if(QMessageBox::warning(this,tr("Deleting backups and file entries"),
           tr("Do you really want to delete the backups and entries for the "
              "following files?\n\n%1\nYou won't be able to restore them!").arg(
           redundantBackupList),
           QMessageBox::Yes | QMessageBox::Abort) != QMessageBox::Yes)
         return;
     }

     progressDialog = new QProgressDialog(this);
     progressDialog->setLabelText(QString(tr("Progressing files...")));

     future2 = new QFutureWatcher<void>(this);
     future2->setFuture(QtConcurrent::map(backupsAndUuids, actualRemoval));

     QObject::connect(future2, SIGNAL(finished()), progressDialog, SLOT(reset()));
     QObject::connect(future2, SIGNAL(finished()), this, SLOT(setupTreeData()));
     QObject::connect(progressDialog, SIGNAL(canceled()), future2, SLOT(cancel()));
     QObject::connect(future2, SIGNAL(progressRangeChanged(int,int)), progressDialog,
                                                                SLOT(setRange(int,int)));
     QObject::connect(future2, SIGNAL(progressValueChanged(int)), progressDialog,
                                                                SLOT(setValue(int)));

     progressDialog->exec();
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2009, John Wiegley.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of New Artisans LLC nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <system.hh>

#include "balance.h"
#include "commodity.h"
#include "pool.h"
#include "unistring.h"		// for justify()

namespace ledger {

balance_t::balance_t(const double val)
{
  TRACE_CTOR(balance_t, "const double");
  amounts.insert
    (amounts_map::value_type(amount_t::current_pool->null_commodity, val));
}

balance_t::balance_t(const unsigned long val)
{
  TRACE_CTOR(balance_t, "const unsigned long");
  amounts.insert
    (amounts_map::value_type(amount_t::current_pool->null_commodity, val));
}

balance_t::balance_t(const long val)
{
  TRACE_CTOR(balance_t, "const long");
  amounts.insert
    (amounts_map::value_type(amount_t::current_pool->null_commodity, val));
}

balance_t& balance_t::operator+=(const balance_t& bal)
{
  foreach (const amounts_map::value_type& pair, bal.amounts)
    *this += pair.second;
  return *this;
}

balance_t& balance_t::operator+=(const amount_t& amt)
{
  if (amt.is_null())
    throw_(balance_error,
	   _("Cannot add an uninitialized amount to a balance"));

  if (amt.is_realzero())
    return *this;

  amounts_map::iterator i = amounts.find(&amt.commodity());
  if (i != amounts.end())
    i->second += amt;
  else
    amounts.insert(amounts_map::value_type(&amt.commodity(), amt));

  return *this;
}

balance_t& balance_t::operator-=(const balance_t& bal)
{
  foreach (const amounts_map::value_type& pair, bal.amounts)
    *this -= pair.second;
  return *this;
}

balance_t& balance_t::operator-=(const amount_t& amt)
{
  if (amt.is_null())
    throw_(balance_error,
	   _("Cannot subtract an uninitialized amount from a balance"));

  if (amt.is_realzero())
    return *this;

  amounts_map::iterator i = amounts.find(&amt.commodity());
  if (i != amounts.end()) {
    i->second -= amt;
    if (i->second.is_realzero())
      amounts.erase(i);
  } else {
    amounts.insert(amounts_map::value_type(&amt.commodity(), amt.negated()));
  }
  return *this;
}

balance_t& balance_t::operator*=(const amount_t& amt)
{
  if (amt.is_null())
    throw_(balance_error,
	   _("Cannot multiply a balance by an uninitialized amount"));

  if (is_realzero()) {
    ;
  }
  else if (amt.is_realzero()) {
    *this = amt;
  }
  else if (! amt.commodity()) {
    // Multiplying by an amount with no commodity causes all the
    // component amounts to be increased by the same factor.
    foreach (amounts_map::value_type& pair, amounts)
      pair.second *= amt;
  }
  else if (amounts.size() == 1) {
    // Multiplying by a commoditized amount is only valid if the sole
    // commodity in the balance is of the same kind as the amount's
    // commodity.
    if (*amounts.begin()->first == amt.commodity())
      amounts.begin()->second *= amt;
    else
      throw_(balance_error,
	     _("Cannot multiply a balance with annotated commodities by a commoditized amount"));
  }
  else {
    assert(amounts.size() > 1);
    throw_(balance_error,
	   _("Cannot multiply a multi-commodity balance by a commoditized amount"));
  }
  return *this;
}

balance_t& balance_t::operator/=(const amount_t& amt)
{
  if (amt.is_null())
    throw_(balance_error,
	   _("Cannot divide a balance by an uninitialized amount"));

  if (is_realzero()) {
    ;
  }
  else if (amt.is_realzero()) {
    throw_(balance_error, _("Divide by zero"));
  }
  else if (! amt.commodity()) {
    // Dividing by an amount with no commodity causes all the
    // component amounts to be divided by the same factor.
    foreach (amounts_map::value_type& pair, amounts)
      pair.second /= amt;
  }
  else if (amounts.size() == 1) {
    // Dividing by a commoditized amount is only valid if the sole
    // commodity in the balance is of the same kind as the amount's
    // commodity.
    if (*amounts.begin()->first == amt.commodity())
      amounts.begin()->second /= amt;
    else
      throw_(balance_error,
	     _("Cannot divide a balance with annotated commodities by a commoditized amount"));
  }
  else {
    assert(amounts.size() > 1);
    throw_(balance_error,
	   _("Cannot divide a multi-commodity balance by a commoditized amount"));
  }
  return *this;
}

optional<balance_t>
balance_t::value(const bool		       primary_only,
		 const optional<datetime_t>&   moment,
		 const optional<commodity_t&>& in_terms_of) const
{
  balance_t temp;
  bool      resolved = false;

  foreach (const amounts_map::value_type& pair, amounts) {
    if (optional<amount_t> val = pair.second.value(primary_only, moment,
						   in_terms_of)) {
      temp += *val;
      resolved = true;
    } else {
      temp += pair.second;
    }
  }
  return resolved ? temp : optional<balance_t>();
}

balance_t balance_t::price() const
{
  balance_t temp;

  foreach (const amounts_map::value_type& pair, amounts)
    temp += pair.second.price();

  return temp;
}

optional<amount_t>
balance_t::commodity_amount(const optional<const commodity_t&>& commodity) const
{
  if (! commodity) {
    if (amounts.size() == 1) {
      return amounts.begin()->second;
    }
#if 0
    else if (amounts.size() > 1) {
      // Try stripping annotations before giving an error.
      balance_t temp(strip_annotations());
      if (temp.amounts.size() == 1)
	return temp.commodity_amount(commodity);

      throw_(amount_error,
	     _("Requested amount of a balance with multiple commodities: %1") << temp);
    }
#endif
  }
  else if (amounts.size() > 0) {
    amounts_map::const_iterator i = amounts.find(&*commodity);
    if (i != amounts.end())
      return i->second;
  }
  return none;
}

balance_t
balance_t::strip_annotations(const keep_details_t& what_to_keep) const
{
  balance_t temp;

  foreach (const amounts_map::value_type& pair, amounts)
    temp += pair.second.strip_annotations(what_to_keep);

  return temp;
}

void balance_t::print(std::ostream& out,
		      const int     first_width,
		      const int     latter_width,
		      const bool    right_justify,
		      const bool    colorize) const
{
  bool first  = true;
  int  lwidth = latter_width;

  if (lwidth == -1)
    lwidth = first_width;

  typedef std::vector<const amount_t *> amounts_array;
  amounts_array sorted;

  foreach (const amounts_map::value_type& pair, amounts)
    if (pair.second)
      sorted.push_back(&pair.second);

  std::stable_sort(sorted.begin(), sorted.end(), compare_amount_commodities());

  foreach (const amount_t * amount, sorted) {
    int width;
    if (! first) {
      out << std::endl;
      width = lwidth;
    } else {
      first = false;
      width = first_width;
    }

    std::ostringstream buf;
    buf << *amount;
    justify(out, buf.str(), width, right_justify,
	    colorize && amount->sign() < 0);
  }

  if (first) {
    out.width(first_width);
    if (right_justify)
      out << std::right;
    else
      out << std::left;
    out << 0;
  }
}

} // namespace ledger
<commit_msg>Whitespace fix<commit_after>/*
 * Copyright (c) 2003-2009, John Wiegley.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of New Artisans LLC nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <system.hh>

#include "balance.h"
#include "commodity.h"
#include "pool.h"
#include "unistring.h"		// for justify()

namespace ledger {

balance_t::balance_t(const double val)
{
  TRACE_CTOR(balance_t, "const double");
  amounts.insert
    (amounts_map::value_type(amount_t::current_pool->null_commodity, val));
}

balance_t::balance_t(const unsigned long val)
{
  TRACE_CTOR(balance_t, "const unsigned long");
  amounts.insert
    (amounts_map::value_type(amount_t::current_pool->null_commodity, val));
}

balance_t::balance_t(const long val)
{
  TRACE_CTOR(balance_t, "const long");
  amounts.insert
    (amounts_map::value_type(amount_t::current_pool->null_commodity, val));
}

balance_t& balance_t::operator+=(const balance_t& bal)
{
  foreach (const amounts_map::value_type& pair, bal.amounts)
    *this += pair.second;
  return *this;
}

balance_t& balance_t::operator+=(const amount_t& amt)
{
  if (amt.is_null())
    throw_(balance_error,
	   _("Cannot add an uninitialized amount to a balance"));

  if (amt.is_realzero())
    return *this;

  amounts_map::iterator i = amounts.find(&amt.commodity());
  if (i != amounts.end())
    i->second += amt;
  else
    amounts.insert(amounts_map::value_type(&amt.commodity(), amt));

  return *this;
}

balance_t& balance_t::operator-=(const balance_t& bal)
{
  foreach (const amounts_map::value_type& pair, bal.amounts)
    *this -= pair.second;
  return *this;
}

balance_t& balance_t::operator-=(const amount_t& amt)
{
  if (amt.is_null())
    throw_(balance_error,
	   _("Cannot subtract an uninitialized amount from a balance"));

  if (amt.is_realzero())
    return *this;

  amounts_map::iterator i = amounts.find(&amt.commodity());
  if (i != amounts.end()) {
    i->second -= amt;
    if (i->second.is_realzero())
      amounts.erase(i);
  } else {
    amounts.insert(amounts_map::value_type(&amt.commodity(), amt.negated()));
  }
  return *this;
}

balance_t& balance_t::operator*=(const amount_t& amt)
{
  if (amt.is_null())
    throw_(balance_error,
	   _("Cannot multiply a balance by an uninitialized amount"));

  if (is_realzero()) {
    ;
  }
  else if (amt.is_realzero()) {
    *this = amt;
  }
  else if (! amt.commodity()) {
    // Multiplying by an amount with no commodity causes all the
    // component amounts to be increased by the same factor.
    foreach (amounts_map::value_type& pair, amounts)
      pair.second *= amt;
  }
  else if (amounts.size() == 1) {
    // Multiplying by a commoditized amount is only valid if the sole
    // commodity in the balance is of the same kind as the amount's
    // commodity.
    if (*amounts.begin()->first == amt.commodity())
      amounts.begin()->second *= amt;
    else
      throw_(balance_error,
	     _("Cannot multiply a balance with annotated commodities by a commoditized amount"));
  }
  else {
    assert(amounts.size() > 1);
    throw_(balance_error,
	   _("Cannot multiply a multi-commodity balance by a commoditized amount"));
  }
  return *this;
}

balance_t& balance_t::operator/=(const amount_t& amt)
{
  if (amt.is_null())
    throw_(balance_error,
	   _("Cannot divide a balance by an uninitialized amount"));

  if (is_realzero()) {
    ;
  }
  else if (amt.is_realzero()) {
    throw_(balance_error, _("Divide by zero"));
  }
  else if (! amt.commodity()) {
    // Dividing by an amount with no commodity causes all the
    // component amounts to be divided by the same factor.
    foreach (amounts_map::value_type& pair, amounts)
      pair.second /= amt;
  }
  else if (amounts.size() == 1) {
    // Dividing by a commoditized amount is only valid if the sole
    // commodity in the balance is of the same kind as the amount's
    // commodity.
    if (*amounts.begin()->first == amt.commodity())
      amounts.begin()->second /= amt;
    else
      throw_(balance_error,
	     _("Cannot divide a balance with annotated commodities by a commoditized amount"));
  }
  else {
    assert(amounts.size() > 1);
    throw_(balance_error,
	   _("Cannot divide a multi-commodity balance by a commoditized amount"));
  }
  return *this;
}

optional<balance_t>
balance_t::value(const bool		       primary_only,
		 const optional<datetime_t>&   moment,
		 const optional<commodity_t&>& in_terms_of) const
{
  balance_t temp;
  bool      resolved = false;

  foreach (const amounts_map::value_type& pair, amounts) {
    if (optional<amount_t> val = pair.second.value(primary_only, moment,
						   in_terms_of)) {
      temp += *val;
      resolved = true;
    } else {
      temp += pair.second;
    }
  }
  return resolved ? temp : optional<balance_t>();
}

balance_t balance_t::price() const
{
  balance_t temp;

  foreach (const amounts_map::value_type& pair, amounts)
    temp += pair.second.price();

  return temp;
}

optional<amount_t>
balance_t::commodity_amount(const optional<const commodity_t&>& commodity) const
{
  if (! commodity) {
    if (amounts.size() == 1) {
      return amounts.begin()->second;
    }
#if 0
    else if (amounts.size() > 1) {
      // Try stripping annotations before giving an error.
      balance_t temp(strip_annotations());
      if (temp.amounts.size() == 1)
	return temp.commodity_amount(commodity);

      throw_(amount_error,
	     _("Requested amount of a balance with multiple commodities: %1")
	     << temp);
    }
#endif
  }
  else if (amounts.size() > 0) {
    amounts_map::const_iterator i =
      amounts.find(const_cast<commodity_t *>(&*commodity));
    if (i != amounts.end())
      return i->second;
  }
  return none;
}

balance_t
balance_t::strip_annotations(const keep_details_t& what_to_keep) const
{
  balance_t temp;

  foreach (const amounts_map::value_type& pair, amounts)
    temp += pair.second.strip_annotations(what_to_keep);

  return temp;
}

void balance_t::print(std::ostream& out,
		      const int     first_width,
		      const int     latter_width,
		      const bool    right_justify,
		      const bool    colorize) const
{
  bool first  = true;
  int  lwidth = latter_width;

  if (lwidth == -1)
    lwidth = first_width;

  typedef std::vector<const amount_t *> amounts_array;
  amounts_array sorted;

  foreach (const amounts_map::value_type& pair, amounts)
    if (pair.second)
      sorted.push_back(&pair.second);

  std::stable_sort(sorted.begin(), sorted.end(), compare_amount_commodities());

  foreach (const amount_t * amount, sorted) {
    int width;
    if (! first) {
      out << std::endl;
      width = lwidth;
    } else {
      first = false;
      width = first_width;
    }

    std::ostringstream buf;
    buf << *amount;
    justify(out, buf.str(), width, right_justify,
	    colorize && amount->sign() < 0);
  }

  if (first) {
    out.width(first_width);
    if (right_justify)
      out << std::right;
    else
      out << std::left;
    out << 0;
  }
}

} // namespace ledger
<|endoftext|>


<commit_before>// Copyright (c) 2014 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"

#include "hash.h"
#include "uint256.h"

#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <vector>
#include <string>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
// SYSCOIN use aliases as addresses
extern void GetAddressFromAlias(const std::string& strAlias, std::string& strAddress);
extern void GetAliasFromAddress(const std::string& strAddress, std::string& strAlias);
/** All alphanumeric characters except for "0", "I", "O", and "l" */
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
{
    // Skip leading spaces.
    while (*psz && isspace(*psz))
        psz++;
    // Skip and count leading '1's.
    int zeroes = 0;
    while (*psz == '1') {
        zeroes++;
        psz++;
    }
    // Allocate enough space in big-endian base256 representation.
    std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
    // Process the characters.
    while (*psz && !isspace(*psz)) {
        // Decode base58 character
        const char* ch = strchr(pszBase58, *psz);
        if (ch == NULL)
            return false;
        // Apply "b256 = b256 * 58 + ch".
        int carry = ch - pszBase58;
        for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
            carry += 58 * (*it);
            *it = carry % 256;
            carry /= 256;
        }
        assert(carry == 0);
        psz++;
    }
    // Skip trailing spaces.
    while (isspace(*psz))
        psz++;
    if (*psz != 0)
        return false;
    // Skip leading zeroes in b256.
    std::vector<unsigned char>::iterator it = b256.begin();
    while (it != b256.end() && *it == 0)
        it++;
    // Copy result into output vector.
    vch.reserve(zeroes + (b256.end() - it));
    vch.assign(zeroes, 0x00);
    while (it != b256.end())
        vch.push_back(*(it++));
    return true;
}

std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{
    // Skip & count leading zeroes.
    int zeroes = 0;
    while (pbegin != pend && *pbegin == 0) {
        pbegin++;
        zeroes++;
    }
    // Allocate enough space in big-endian base58 representation.
    std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
    // Process the bytes.
    while (pbegin != pend) {
        int carry = *pbegin;
        // Apply "b58 = b58 * 256 + ch".
        for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
            carry += 256 * (*it);
            *it = carry % 58;
            carry /= 58;
        }
        assert(carry == 0);
        pbegin++;
    }
    // Skip leading zeroes in base58 result.
    std::vector<unsigned char>::iterator it = b58.begin();
    while (it != b58.end() && *it == 0)
        it++;
    // Translate the result into a string.
    std::string str;
    str.reserve(zeroes + (b58.end() - it));
    str.assign(zeroes, '1');
    while (it != b58.end())
        str += pszBase58[*(it++)];
    return str;
}

std::string EncodeBase58(const std::vector<unsigned char>& vch)
{
    return EncodeBase58(&vch[0], &vch[0] + vch.size());
}

bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
{
    return DecodeBase58(str.c_str(), vchRet);
}

std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
{
    // add 4-byte hash check to the end
    std::vector<unsigned char> vch(vchIn);
    uint256 hash = Hash(vch.begin(), vch.end());
    vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
    return EncodeBase58(vch);
}

bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
{
    if (!DecodeBase58(psz, vchRet) ||
        (vchRet.size() < 4)) {
        vchRet.clear();
        return false;
    }
    // re-calculate the checksum, insure it matches the included 4-byte checksum
    uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
    if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) {
        vchRet.clear();
        return false;
    }
    vchRet.resize(vchRet.size() - 4);
    return true;
}

bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
{
    return DecodeBase58Check(str.c_str(), vchRet);
}

CBase58Data::CBase58Data()
{
    vchVersion.clear();
    vchData.clear();
}

void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
{
    vchVersion = vchVersionIn;
    vchData.resize(nSize);
    if (!vchData.empty())
        memcpy(&vchData[0], pdata, nSize);
}

void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
{
    SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
}

bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
{
    std::vector<unsigned char> vchTemp;
    bool rc58 = DecodeBase58Check(psz, vchTemp);
    if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
        vchData.clear();
        vchVersion.clear();
        return false;
    }
    vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
    vchData.resize(vchTemp.size() - nVersionBytes);
    if (!vchData.empty())
        memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
    memory_cleanse(&vchTemp[0], vchData.size());
    return true;
}

bool CBase58Data::SetString(const std::string& str)
{
    return SetString(str.c_str());
}

std::string CBase58Data::ToString() const
{
    std::vector<unsigned char> vch = vchVersion;
    vch.insert(vch.end(), vchData.begin(), vchData.end());
    return EncodeBase58Check(vch);
}

int CBase58Data::CompareTo(const CBase58Data& b58) const
{
    if (vchVersion < b58.vchVersion)
        return -1;
    if (vchVersion > b58.vchVersion)
        return 1;
    if (vchData < b58.vchData)
        return -1;
    if (vchData > b58.vchData)
        return 1;
    return 0;
}

namespace
{
class CSyscoinAddressVisitor : public boost::static_visitor<bool>
{
private:
    CSyscoinAddress* addr;
	// SYSCOIN support old sys
	bool bOldSys;
public:
    CSyscoinAddressVisitor(CSyscoinAddress* addrIn) : addr(addrIn) {}
	CSyscoinAddressVisitor(CSyscoinAddress* addrIn, bool oldSys) : bOldSys(oldSys), addr(addrIn) {}

    bool operator()(const CKeyID& id) const { return addr->Set(id, bOldSys); }
    bool operator()(const CScriptID& id) const { return addr->Set(id); }
    bool operator()(const CNoDestination& no) const { return false; }
};

} // anon namespace
// SYSCOIN aliases as addresses
CSyscoinAddress::CSyscoinAddress() {
	isAlias = false;
	aliasName = "";
}
// SYSCOIN support old sys
CSyscoinAddress::CSyscoinAddress(const CTxDestination &dest, bool oldSys) {
	isAlias = false;
	aliasName = "";
    Set(dest, oldSys);
}
CSyscoinAddress::CSyscoinAddress(const CTxDestination &dest) {
	isAlias = false;
	aliasName = "";
    Set(dest);
}
CSyscoinAddress::CSyscoinAddress(const std::string& strAddress) {
	isAlias = false;
	aliasName = "";
    SetString(strAddress);
	// try to resolve alias address from alias name
	if (!IsValid())
	{
		try
		{
			std::string strAliasAddress;
			GetAddressFromAlias(strAddress, strAliasAddress);
			SetString(strAliasAddress);
			aliasName = strAddress;
			isAlias = true;
		}
		catch(...)
		{
		}
	}
	// try to resolve alias name from alias address
	else
	{
		try
		{
			std::string strAlias;
			GetAliasFromAddress(strAddress, strAlias);
			aliasName = strAlias;
			isAlias = true;
		}
		catch(...)
		{
		}
	}

}
CSyscoinAddress::CSyscoinAddress(const char* pszAddress) {
	isAlias = false;
    SetString(pszAddress);
	// try to resolve alias address
	if (!IsValid())
	{
		try
		{
			std::string strAliasAddress;
			GetAddressFromAlias(std::string(pszAddress), strAliasAddress);
			SetString(strAliasAddress);
			aliasName = std::string(pszAddress);
			isAlias = true;

		}
		catch(...)
		{
		}
	}
	else
	{
		try
		{
			std::string strAlias;
			GetAliasFromAddress(std::string(pszAddress), strAlias);
			aliasName = strAlias;
			isAlias = true;
		}
		catch(...)
		{
		}
	}
}
// SYSCOIN support old sys
bool CSyscoinAddress::Set(const CKeyID& id, bool oldSys = false)
{
	SetData(Params().Base58Prefix(oldSys? CChainParams::PUBKEY_ADDRESS_SYS: CChainParams::PUBKEY_ADDRESS), &id, 20);
    return true;
}

bool CSyscoinAddress::Set(const CScriptID& id)
{
    SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
    return true;
}
// SYSCOIN support old sys
bool CSyscoinAddress::Set(const CTxDestination& dest, bool oldSys = false)
{
    return boost::apply_visitor(CSyscoinAddressVisitor(this, oldSys), dest);
}

bool CSyscoinAddress::IsValid() const
{
    return IsValid(Params());
}

bool CSyscoinAddress::IsValid(const CChainParams& params) const
{
    bool fCorrectSize = vchData.size() == 20;
	// SYSCOIN allow old SYSCOIN address scheme
    bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS)     ||
						 vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS_SYS) ||
                         vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
    return fCorrectSize && fKnownVersion;
}

CTxDestination CSyscoinAddress::Get() const
{
    if (!IsValid())
        return CNoDestination();
    uint160 id;
    memcpy(&id, &vchData[0], 20);
	// SYSCOIN allow old SYSCOIN address scheme
    if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
		vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_SYS))
        return CKeyID(id);
    else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
        return CScriptID(id);
    else
        return CNoDestination();
}

bool CSyscoinAddress::GetKeyID(CKeyID& keyID) const
{
	// SYSCOIN allow old SYSCOIN address scheme
    if (!IsValid() || (vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) && vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_SYS)))
        return false;
    uint160 id;
    memcpy(&id, &vchData[0], 20);
    keyID = CKeyID(id);
    return true;
}

bool CSyscoinAddress::IsScript() const
{
    return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
}

void CSyscoinSecret::SetKey(const CKey& vchSecret)
{
    assert(vchSecret.IsValid());
    SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
    if (vchSecret.IsCompressed())
        vchData.push_back(1);
}

CKey CSyscoinSecret::GetKey()
{
    CKey ret;
    assert(vchData.size() >= 32);
    ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1);
    return ret;
}

bool CSyscoinSecret::IsValid() const
{
    bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
	// SYSCOIN allow old SYSCOIN address scheme
    bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY) ||
                               vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY_SYS);
    return fExpectedFormat && fCorrectVersion;
}

bool CSyscoinSecret::SetString(const char* pszSecret)
{
    return CBase58Data::SetString(pszSecret) && IsValid();
}

bool CSyscoinSecret::SetString(const std::string& strSecret)
{
    return SetString(strSecret.c_str());
}
<commit_msg>compile<commit_after>// Copyright (c) 2014 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "base58.h"

#include "hash.h"
#include "uint256.h"

#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <vector>
#include <string>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
// SYSCOIN use aliases as addresses
extern void GetAddressFromAlias(const std::string& strAlias, std::string& strAddress);
extern void GetAliasFromAddress(const std::string& strAddress, std::string& strAlias);
/** All alphanumeric characters except for "0", "I", "O", and "l" */
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
{
    // Skip leading spaces.
    while (*psz && isspace(*psz))
        psz++;
    // Skip and count leading '1's.
    int zeroes = 0;
    while (*psz == '1') {
        zeroes++;
        psz++;
    }
    // Allocate enough space in big-endian base256 representation.
    std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
    // Process the characters.
    while (*psz && !isspace(*psz)) {
        // Decode base58 character
        const char* ch = strchr(pszBase58, *psz);
        if (ch == NULL)
            return false;
        // Apply "b256 = b256 * 58 + ch".
        int carry = ch - pszBase58;
        for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
            carry += 58 * (*it);
            *it = carry % 256;
            carry /= 256;
        }
        assert(carry == 0);
        psz++;
    }
    // Skip trailing spaces.
    while (isspace(*psz))
        psz++;
    if (*psz != 0)
        return false;
    // Skip leading zeroes in b256.
    std::vector<unsigned char>::iterator it = b256.begin();
    while (it != b256.end() && *it == 0)
        it++;
    // Copy result into output vector.
    vch.reserve(zeroes + (b256.end() - it));
    vch.assign(zeroes, 0x00);
    while (it != b256.end())
        vch.push_back(*(it++));
    return true;
}

std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{
    // Skip & count leading zeroes.
    int zeroes = 0;
    while (pbegin != pend && *pbegin == 0) {
        pbegin++;
        zeroes++;
    }
    // Allocate enough space in big-endian base58 representation.
    std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
    // Process the bytes.
    while (pbegin != pend) {
        int carry = *pbegin;
        // Apply "b58 = b58 * 256 + ch".
        for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
            carry += 256 * (*it);
            *it = carry % 58;
            carry /= 58;
        }
        assert(carry == 0);
        pbegin++;
    }
    // Skip leading zeroes in base58 result.
    std::vector<unsigned char>::iterator it = b58.begin();
    while (it != b58.end() && *it == 0)
        it++;
    // Translate the result into a string.
    std::string str;
    str.reserve(zeroes + (b58.end() - it));
    str.assign(zeroes, '1');
    while (it != b58.end())
        str += pszBase58[*(it++)];
    return str;
}

std::string EncodeBase58(const std::vector<unsigned char>& vch)
{
    return EncodeBase58(&vch[0], &vch[0] + vch.size());
}

bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
{
    return DecodeBase58(str.c_str(), vchRet);
}

std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
{
    // add 4-byte hash check to the end
    std::vector<unsigned char> vch(vchIn);
    uint256 hash = Hash(vch.begin(), vch.end());
    vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
    return EncodeBase58(vch);
}

bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
{
    if (!DecodeBase58(psz, vchRet) ||
        (vchRet.size() < 4)) {
        vchRet.clear();
        return false;
    }
    // re-calculate the checksum, insure it matches the included 4-byte checksum
    uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
    if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) {
        vchRet.clear();
        return false;
    }
    vchRet.resize(vchRet.size() - 4);
    return true;
}

bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
{
    return DecodeBase58Check(str.c_str(), vchRet);
}

CBase58Data::CBase58Data()
{
    vchVersion.clear();
    vchData.clear();
}

void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
{
    vchVersion = vchVersionIn;
    vchData.resize(nSize);
    if (!vchData.empty())
        memcpy(&vchData[0], pdata, nSize);
}

void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
{
    SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
}

bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
{
    std::vector<unsigned char> vchTemp;
    bool rc58 = DecodeBase58Check(psz, vchTemp);
    if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
        vchData.clear();
        vchVersion.clear();
        return false;
    }
    vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
    vchData.resize(vchTemp.size() - nVersionBytes);
    if (!vchData.empty())
        memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
    memory_cleanse(&vchTemp[0], vchData.size());
    return true;
}

bool CBase58Data::SetString(const std::string& str)
{
    return SetString(str.c_str());
}

std::string CBase58Data::ToString() const
{
    std::vector<unsigned char> vch = vchVersion;
    vch.insert(vch.end(), vchData.begin(), vchData.end());
    return EncodeBase58Check(vch);
}

int CBase58Data::CompareTo(const CBase58Data& b58) const
{
    if (vchVersion < b58.vchVersion)
        return -1;
    if (vchVersion > b58.vchVersion)
        return 1;
    if (vchData < b58.vchData)
        return -1;
    if (vchData > b58.vchData)
        return 1;
    return 0;
}

namespace
{
class CSyscoinAddressVisitor : public boost::static_visitor<bool>
{
private:
    CSyscoinAddress* addr;
	// SYSCOIN support old sys
	bool bOldSys;
public:
    CSyscoinAddressVisitor(CSyscoinAddress* addrIn) : addr(addrIn) {}
	CSyscoinAddressVisitor(CSyscoinAddress* addrIn, bool oldSys) : bOldSys(oldSys), addr(addrIn) {}

    bool operator()(const CKeyID& id) const { return addr->Set(id, bOldSys); }
    bool operator()(const CScriptID& id) const { return addr->Set(id); }
    bool operator()(const CNoDestination& no) const { return false; }
};

} // anon namespace
// SYSCOIN aliases as addresses
CSyscoinAddress::CSyscoinAddress() {
	isAlias = false;
	aliasName = "";
}
// SYSCOIN support old sys
CSyscoinAddress::CSyscoinAddress(const CTxDestination &dest, bool oldSys) {
	isAlias = false;
	aliasName = "";
    Set(dest, oldSys);
}
CSyscoinAddress::CSyscoinAddress(const CTxDestination &dest) {
	isAlias = false;
	aliasName = "";
    Set(dest, false);
}
CSyscoinAddress::CSyscoinAddress(const std::string& strAddress) {
	isAlias = false;
	aliasName = "";
    SetString(strAddress);
	// try to resolve alias address from alias name
	if (!IsValid())
	{
		try
		{
			std::string strAliasAddress;
			GetAddressFromAlias(strAddress, strAliasAddress);
			SetString(strAliasAddress);
			aliasName = strAddress;
			isAlias = true;
		}
		catch(...)
		{
		}
	}
	// try to resolve alias name from alias address
	else
	{
		try
		{
			std::string strAlias;
			GetAliasFromAddress(strAddress, strAlias);
			aliasName = strAlias;
			isAlias = true;
		}
		catch(...)
		{
		}
	}

}
CSyscoinAddress::CSyscoinAddress(const char* pszAddress) {
	isAlias = false;
    SetString(pszAddress);
	// try to resolve alias address
	if (!IsValid())
	{
		try
		{
			std::string strAliasAddress;
			GetAddressFromAlias(std::string(pszAddress), strAliasAddress);
			SetString(strAliasAddress);
			aliasName = std::string(pszAddress);
			isAlias = true;

		}
		catch(...)
		{
		}
	}
	else
	{
		try
		{
			std::string strAlias;
			GetAliasFromAddress(std::string(pszAddress), strAlias);
			aliasName = strAlias;
			isAlias = true;
		}
		catch(...)
		{
		}
	}
}
// SYSCOIN support old sys
bool CSyscoinAddress::Set(const CKeyID& id, bool oldSys = false)
{
	SetData(Params().Base58Prefix(oldSys? CChainParams::PUBKEY_ADDRESS_SYS: CChainParams::PUBKEY_ADDRESS), &id, 20);
    return true;
}

bool CSyscoinAddress::Set(const CScriptID& id)
{
    SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
    return true;
}
// SYSCOIN support old sys
bool CSyscoinAddress::Set(const CTxDestination& dest, bool oldSys = false)
{
    return boost::apply_visitor(CSyscoinAddressVisitor(this, oldSys), dest);
}

bool CSyscoinAddress::IsValid() const
{
    return IsValid(Params());
}

bool CSyscoinAddress::IsValid(const CChainParams& params) const
{
    bool fCorrectSize = vchData.size() == 20;
	// SYSCOIN allow old SYSCOIN address scheme
    bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS)     ||
						 vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS_SYS) ||
                         vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
    return fCorrectSize && fKnownVersion;
}

CTxDestination CSyscoinAddress::Get() const
{
    if (!IsValid())
        return CNoDestination();
    uint160 id;
    memcpy(&id, &vchData[0], 20);
	// SYSCOIN allow old SYSCOIN address scheme
    if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
		vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_SYS))
        return CKeyID(id);
    else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
        return CScriptID(id);
    else
        return CNoDestination();
}

bool CSyscoinAddress::GetKeyID(CKeyID& keyID) const
{
	// SYSCOIN allow old SYSCOIN address scheme
    if (!IsValid() || (vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) && vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS_SYS)))
        return false;
    uint160 id;
    memcpy(&id, &vchData[0], 20);
    keyID = CKeyID(id);
    return true;
}

bool CSyscoinAddress::IsScript() const
{
    return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
}

void CSyscoinSecret::SetKey(const CKey& vchSecret)
{
    assert(vchSecret.IsValid());
    SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
    if (vchSecret.IsCompressed())
        vchData.push_back(1);
}

CKey CSyscoinSecret::GetKey()
{
    CKey ret;
    assert(vchData.size() >= 32);
    ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1);
    return ret;
}

bool CSyscoinSecret::IsValid() const
{
    bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
	// SYSCOIN allow old SYSCOIN address scheme
    bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY) ||
                               vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY_SYS);
    return fExpectedFormat && fCorrectVersion;
}

bool CSyscoinSecret::SetString(const char* pszSecret)
{
    return CBase58Data::SetString(pszSecret) && IsValid();
}

bool CSyscoinSecret::SetString(const std::string& strSecret)
{
    return SetString(strSecret.c_str());
}
<|endoftext|>


<commit_before>//
//  ex8_05.cpp
//  Exercise 8.5
//
//  Created by pezy on 11/9/14.
//  Copyright (c) 2014 pezy. All rights reserved.
//
//  @Brief  Rewrite the previous program to store each word in a separate element
//  @See    ex8_04.cpp

#include <fstream>
#include <string>
#include <vector>
#include <iostream>

using std::vector;
using std::string;
using std::ifstream;
using std::cout;
using std::endl;

void ReadFileToVec(const string& fileName, vector<string>& vec)
{
    ifstream ifs(fileName);
    if (ifs) {
        string buf;
        while (ifs >> buf) vec.push_back(buf);
    }
}

int main()
{
    vector<string> vec;
    ReadFileToVec("../data/book.txt", vec);
    for (const auto& str : vec) cout << str << endl;
    return 0;
}
<commit_msg>Update ex8_05.cpp<commit_after>//
//  ex8_05.cpp
//  Exercise 8.5
//
//  Created by pezy on 11/9/14.
//  Copyright (c) 2014 pezy. All rights reserved.
//
//  @Brief  Rewrite the previous program to store each word in a separate element.
//  @See    ex8_04.cpp

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

using std::cout;
using std::endl;
using std::ifstream;
using std::vector;
using std::string;

void ReadFileToVec(const string &fileName, vector<string> &vec)
{
    ifstream input(fileName);
    if(input)
    {
        string s;
        while(input>>s)
            vec.push_back(s);
    }
}

int main()
{
    vector<string> vec;
    ReadFileToVec("E:\\zzz.txt", vec);
    for(const auto &str:vec)
        cout<<str<<endl;
}
<|endoftext|>


<commit_before>/*
 * This file is part of the Objavi Renderer.
 *
 * Copyright (C) 2013 Borko Jandras <borko.jandras@sourcefabric.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bookjs.hpp"

#include <QDir>
#include <QFile>
#include <QString>
#include <QVariant>
#include <QTextStream>
#include <QDebug>

#include <QWebElement>
#include <QWebFrame>
#include <QWebPage>

#include <stdexcept>

namespace Objavi { namespace BookJS {

    PaginationConfig::PaginationConfig()
    {}

    PaginationConfig::PaginationConfig(QList<QPair<QString,QVariant> > const & items)
    {
        typedef QPair<QString,QVariant> ItemType;

        Q_FOREACH (ItemType const & item, items)
        {
            m_map[item.first] = item.second;
        }
    }

    PaginationConfig PaginationConfig::parse(QString const & text)
    {
        typedef QPair<QString,QVariant> ItemType;

        QList<ItemType> items;

        Q_FOREACH (QString item, text.split(','))
        {
            QStringList pair = item.split(':');

            if (pair.length() < 2) continue;

            QString key = pair[0].trimmed();
            QString val = pair[1].trimmed();

            QVariant value;

            if (key == "lengthUnit")
            {
                if (val == "'em'" || val == "\"em\"" ||
                    val == "'cm'" || val == "\"cm\"" ||
                    val == "'mm'" || val == "\"mm\"" ||
                    val == "'in'" || val == "\"in\"" ||
                    val == "'pt'" || val == "\"pt\"" ||
                    val == "'pc'" || val == "\"pc\"" ||
                    val == "'px'" || val == "\"px\"" ||
                    val == "'ex'" || val == "\"ex\"" ||
                    val == "'%'"  || val == "\"%\"")
                {
                    value = val;
                }
            }
            else
            {
                bool ok = false;
                double d = val.toDouble(&ok);

                if (ok)
                {
                    value = d;
                }
            }

            if (value.isValid())
            {
                items.append(ItemType(key, value));
            }
            else
            {
                QString msg = QString("invalid value for option %1: %2").arg(key).arg(val);
                throw std::runtime_error(msg.toLatin1().data());
            }
        }

        return PaginationConfig(items);
    }

    namespace {

        QSizeF makeSize(QString width, QString height)
        {
            if (width.endsWith("px") && height.endsWith("px"))
            {
                width  = width.left(width.size() - 2);
                height = height.left(height.size() - 2);

                return QSizeF(width.toFloat(), height.toFloat());
            }
            else
            {
                return QSizeF();
            }
        }

    }

    QSizeF getPageSize(QWebPage const * page, QString className)
    {
        QWebElement document = page->mainFrame()->documentElement();

        QWebElement element = document.findFirst(QString(".%1").arg(className));
        if (! element.isNull())
        {
            QString width  = element.styleProperty("width",  QWebElement::ComputedStyle);
            QString height = element.styleProperty("height", QWebElement::ComputedStyle);

            return makeSize(width, height);
        }

        QString script_text =
            "(function(className) {"
            "    var style = getComputedStyle(document.getElementsByClassName(className)[0], className);"
            "    return [style.width, style.height];"
            "})('%1');";

        script_text = script_text.arg(className);

        QVariant result = document.evaluateJavaScript(script_text);

        if (result.canConvert(QVariant::StringList))
        {
            QStringList list = result.toStringList();

            return makeSize(list[0], list[1]);
        }

        return QSizeF();
    }

    namespace {

        QString loadFile(QString path)
        {
            QFile file(path);

            if (! file.open(QFile::ReadOnly))
            {
                QString message = QString("could not open file %1").arg(path);

                throw std::runtime_error(message.toStdString());
            }

            return QTextStream(&file).readAll();
        }

        void appendCSS(QString text, QWebElement & element)
        {
            QString xml = element.toInnerXml();

            xml += "";

            element.setInnerXml(xml);
        }

        void appendJavascript(QString text, QWebElement & element)
        {
            QString xml = element.toInnerXml();

            xml += "";

            element.setInnerXml(xml);
        }

        QString makeFrontMatterContents(QWebElement const & head)
        {
            QString title;
            QString subtitle;
            QString editors;
            QString license;
            QString copyright;

            for (QWebElement node = head.firstChild(); !node.isNull(); node = node.nextSibling())
            {
                QString name = node.localName();

                if (name == "title")
                {
                    title = node.toPlainText();
                }
                else if (name == "meta")
                {
                    QString name = node.attribute("name");
                    QString value = node.attribute("content");

                    if (name == "license")
                    {
                        license = value;
                    }
                    else if (name == "copyright")
                    {
                        copyright = value;
                    }
                }
            }

            return QString(
                "
%1
"
                "
%2
"
                "
%3
"
                "

"
                "
Copyright: %4
License: %5
"
                "

")
                .arg(title)
                .arg(subtitle)
                .arg(editors)
                .arg(copyright).arg(license);
        }

    }

    void install(QWebPage * page, QString bookjsPath, PaginationConfig const & paginationConfig, QString customCSS)
    {
        QWebElement document = page->mainFrame()->documentElement();
        QWebElement head = document.findFirst("head");

        if (head.isNull())
        {
            throw std::runtime_error("no document head");
        }

        QDir bookjsDir = QDir::current();
        if (! bookjsPath.isEmpty())
        {
            bookjsDir = QDir(bookjsPath);
        }

        if (bookjsDir.exists() == false)
        {
            throw std::runtime_error("invalid BookJS path");
        }

        if (! customCSS.isEmpty())
        {
            appendCSS(customCSS, head);
        }

        QString script;

        // preset pagination configuration
        script += loadFile(bookjsDir.filePath("book-config.js"));

        // user-specified pagination configuration
        //
        for (PaginationConfig::MapType::ConstIterator it = paginationConfig.items().begin();
             it != paginationConfig.items().end(); ++it)
        {
            QString optionKey   = it.key();
            QString optionValue = it.value().toString();

            script += QString("paginationConfig.%1 = %2;\n").arg(optionKey).arg(optionValue);
        }

        // front matter configuration
        script += QString("paginationConfig.frontmatterContents = '%1';\n").arg(makeFrontMatterContents(head));

        // main BookJS script text
        script += loadFile(bookjsDir.filePath("book.js"));

        // apply
        script += "Pagination.applyBookLayout();";

        page->mainFrame()->evaluateJavaScript(script);
    }

} }  // namespace Objavi::BookJS
<commit_msg>Make sure the contents of frontmatterContents is escaped.<commit_after>/*
 * This file is part of the Objavi Renderer.
 *
 * Copyright (C) 2013 Borko Jandras <borko.jandras@sourcefabric.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bookjs.hpp"

#include <QDir>
#include <QFile>
#include <QString>
#include <QVariant>
#include <QTextStream>
#include <QDebug>

#include <QWebElement>
#include <QWebFrame>
#include <QWebPage>

#include <stdexcept>

namespace Objavi { namespace BookJS {

    PaginationConfig::PaginationConfig()
    {}

    PaginationConfig::PaginationConfig(QList<QPair<QString,QVariant> > const & items)
    {
        typedef QPair<QString,QVariant> ItemType;

        Q_FOREACH (ItemType const & item, items)
        {
            m_map[item.first] = item.second;
        }
    }

    PaginationConfig PaginationConfig::parse(QString const & text)
    {
        typedef QPair<QString,QVariant> ItemType;

        QList<ItemType> items;

        Q_FOREACH (QString item, text.split(','))
        {
            QStringList pair = item.split(':');

            if (pair.length() < 2) continue;

            QString key = pair[0].trimmed();
            QString val = pair[1].trimmed();

            QVariant value;

            if (key == "lengthUnit")
            {
                if (val == "'em'" || val == "\"em\"" ||
                    val == "'cm'" || val == "\"cm\"" ||
                    val == "'mm'" || val == "\"mm\"" ||
                    val == "'in'" || val == "\"in\"" ||
                    val == "'pt'" || val == "\"pt\"" ||
                    val == "'pc'" || val == "\"pc\"" ||
                    val == "'px'" || val == "\"px\"" ||
                    val == "'ex'" || val == "\"ex\"" ||
                    val == "'%'"  || val == "\"%\"")
                {
                    value = val;
                }
            }
            else
            {
                bool ok = false;
                double d = val.toDouble(&ok);

                if (ok)
                {
                    value = d;
                }
            }

            if (value.isValid())
            {
                items.append(ItemType(key, value));
            }
            else
            {
                QString msg = QString("invalid value for option %1: %2").arg(key).arg(val);
                throw std::runtime_error(msg.toLatin1().data());
            }
        }

        return PaginationConfig(items);
    }

    namespace {

        QSizeF makeSize(QString width, QString height)
        {
            if (width.endsWith("px") && height.endsWith("px"))
            {
                width  = width.left(width.size() - 2);
                height = height.left(height.size() - 2);

                return QSizeF(width.toFloat(), height.toFloat());
            }
            else
            {
                return QSizeF();
            }
        }

    }

    QSizeF getPageSize(QWebPage const * page, QString className)
    {
        QWebElement document = page->mainFrame()->documentElement();

        QWebElement element = document.findFirst(QString(".%1").arg(className));
        if (! element.isNull())
        {
            QString width  = element.styleProperty("width",  QWebElement::ComputedStyle);
            QString height = element.styleProperty("height", QWebElement::ComputedStyle);

            return makeSize(width, height);
        }

        QString script_text =
            "(function(className) {"
            "    var style = getComputedStyle(document.getElementsByClassName(className)[0], className);"
            "    return [style.width, style.height];"
            "})('%1');";

        script_text = script_text.arg(className);

        QVariant result = document.evaluateJavaScript(script_text);

        if (result.canConvert(QVariant::StringList))
        {
            QStringList list = result.toStringList();

            return makeSize(list[0], list[1]);
        }

        return QSizeF();
    }

    namespace {

        QString loadFile(QString path)
        {
            QFile file(path);

            if (! file.open(QFile::ReadOnly))
            {
                QString message = QString("could not open file %1").arg(path);

                throw std::runtime_error(message.toStdString());
            }

            return QTextStream(&file).readAll();
        }

        void appendCSS(QString text, QWebElement & element)
        {
            QString xml = element.toInnerXml();

            xml += "";

            element.setInnerXml(xml);
        }

        void appendJavascript(QString text, QWebElement & element)
        {
            QString xml = element.toInnerXml();

            xml += "";

            element.setInnerXml(xml);
        }

        QString makeFrontMatterContents(QWebElement const & head)
        {
            QString title;
            QString subtitle;
            QString editors;
            QString license;
            QString copyright;

            for (QWebElement node = head.firstChild(); !node.isNull(); node = node.nextSibling())
            {
                QString name = node.localName();

                if (name == "title")
                {
                    title = node.toPlainText();
                }
                else if (name == "meta")
                {
                    QString name = node.attribute("name");
                    QString value = node.attribute("content");

                    if (name == "license")
                    {
                        license = value;
                    }
                    else if (name == "copyright")
                    {
                        copyright = value;
                    }
                }
            }

            return QString(
                "
%1
"
                "
%2
"
                "
%3
"
                "

"
                "
Copyright: %4
License: %5
"
                "

")
                .arg(title)
                .arg(subtitle)
                .arg(editors)
                .arg(copyright).arg(license);
        }

    }

    void install(QWebPage * page, QString bookjsPath, PaginationConfig const & paginationConfig, QString customCSS)
    {
        QWebElement document = page->mainFrame()->documentElement();
        QWebElement head = document.findFirst("head");

        if (head.isNull())
        {
            throw std::runtime_error("no document head");
        }

        QDir bookjsDir = QDir::current();
        if (! bookjsPath.isEmpty())
        {
            bookjsDir = QDir(bookjsPath);
        }

        if (bookjsDir.exists() == false)
        {
            throw std::runtime_error("invalid BookJS path");
        }

        if (! customCSS.isEmpty())
        {
            appendCSS(customCSS, head);
        }

        QString script;

        // preset pagination configuration
        script += loadFile(bookjsDir.filePath("book-config.js"));

        // user-specified pagination configuration
        //
        for (PaginationConfig::MapType::ConstIterator it = paginationConfig.items().begin();
             it != paginationConfig.items().end(); ++it)
        {
            QString optionKey   = it.key();
            QString optionValue = it.value().toString();

            script += QString("\npaginationConfig.%1 = %2;").arg(optionKey).arg(optionValue);
        }

        // front matter configuration
        //
        QString frontmatterContents = makeFrontMatterContents(head);
        frontmatterContents.replace("'", "\\'");
        script += QString("\npaginationConfig.frontmatterContents = '%1';\n").arg(frontmatterContents);

        // main BookJS script text
        script += loadFile(bookjsDir.filePath("book.js"));

        // apply
        script += "\nPagination.applyBookLayout();";

        page->mainFrame()->evaluateJavaScript(script);
    }

} }  // namespace Objavi::BookJS
<|endoftext|>