<commit_before>#include "engine.h"
#include <QDateTime>
#include <QTextStream>
#include <QSettings>
#include <QStandardPaths>
#include "globals.h"
#include "fileworker.h"
#include "statfileinfo.h"

Engine::Engine(QObject *parent) :
    QObject(parent),
    m_clipboardContainsCopy(false),
    m_progress(0)
{
    m_fileWorker = new FileWorker;

    // update progress property when worker progresses
    connect(m_fileWorker, SIGNAL(progressChanged(int, QString)),
            this, SLOT(setProgress(int, QString)));

    // pass worker end signals to QML
    connect(m_fileWorker, SIGNAL(done()), this, SIGNAL(workerDone()));
    connect(m_fileWorker, SIGNAL(errorOccurred(QString, QString)),
            this, SIGNAL(workerErrorOccurred(QString, QString)));
    connect(m_fileWorker, SIGNAL(fileDeleted(QString)), this, SIGNAL(fileDeleted(QString)));
}

Engine::~Engine()
{
    // is this the way to force stop the worker thread?
    m_fileWorker->cancel(); // stop possibly running background thread
    m_fileWorker->wait();   // wait until thread stops
    delete m_fileWorker;    // delete it
}

void Engine::deleteFiles(QStringList filenames)
{
    setProgress(0, "");
    m_fileWorker->startDeleteFiles(filenames);
}

void Engine::cutFiles(QStringList filenames)
{
    m_clipboardFiles = filenames;
    m_clipboardContainsCopy = false;
    emit clipboardCountChanged();
    emit clipboardContainsCopyChanged();
}

void Engine::copyFiles(QStringList filenames)
{
    // don't copy special files (chr/blk/fifo/sock)
    QMutableStringListIterator i(filenames);
    while (i.hasNext()) {
        QString filename = i.next();
        StatFileInfo info(filename);
        if (info.isSystem())
            i.remove();
    }

    m_clipboardFiles = filenames;
    m_clipboardContainsCopy = true;
    emit clipboardCountChanged();
    emit clipboardContainsCopyChanged();
}

void Engine::pasteFiles(QString destDirectory)
{
    if (m_clipboardFiles.isEmpty()) {
        emit workerErrorOccurred("No files to paste", "");
        return;
    }

    QStringList files = m_clipboardFiles;
    setProgress(0, "");

    QDir dest(destDirectory);
    if (!dest.exists()) {
        emit workerErrorOccurred(tr("Destination does not exist"), destDirectory);
        return;
    }

    foreach (QString filename, files) {
        QFileInfo fileInfo(filename);
        QString newname = dest.absoluteFilePath(fileInfo.fileName());

        // source and dest filenames are the same?
        if (filename == newname) {
            emit workerErrorOccurred(tr("Can't overwrite itself"), newname);
            return;
        }

        // dest is under source? (directory)
        if (newname.startsWith(filename)) {
            emit workerErrorOccurred(tr("Can't move/copy to itself"), filename);
            return;
        }
    }

    m_clipboardFiles.clear();
    emit clipboardCountChanged();

    if (m_clipboardContainsCopy) {
        m_fileWorker->startCopyFiles(files, destDirectory);
        return;
    }

    m_fileWorker->startMoveFiles(files, destDirectory);
}

void Engine::cancel()
{
    m_fileWorker->cancel();
}

QString Engine::homeFolder() const
{
    return QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
}

QString Engine::sdcardPath() const
{
    // get sdcard dir candidates
    QDir dir("/media/sdcard");
    if (!dir.exists())
        return QString();
    dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
    QStringList sdcards = dir.entryList();
    if (sdcards.isEmpty())
        return QString();

    // remove all directories which are not mount points
    QStringList mps = mountPoints();
    QMutableStringListIterator i(sdcards);
    while (i.hasNext()) {
        QString dirname = i.next();
        QString abspath = dir.absoluteFilePath(dirname);
        if (!mps.contains(abspath))
            i.remove();
    }

    // none found, return empty string
    if (sdcards.isEmpty())
        return QString();

    // if only one directory, then return it
    if (sdcards.count() == 1)
        return dir.absoluteFilePath(sdcards.first());

    // if multiple directories, then return "/media/sdcard", which is the parent for them
    return "/media/sdcard";
}

QString Engine::androidSdcardPath() const
{
    return QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/android_storage";
}

bool Engine::exists(QString filename)
{
    if (filename.isEmpty())
        return false;

    return QFile::exists(filename);
}

QStringList Engine::diskSpace(QString path)
{
    if (path.isEmpty())
        return QStringList();

    // return no disk space for sdcard parent directory
    if (path == "/media/sdcard")
        return QStringList();

    // run df for the given path to get disk space
    QString blockSize = "--block-size=1024";
    QString result = execute("/bin/df", QStringList() << blockSize << path, false);
    if (result.isEmpty())
        return QStringList();

    // split result to lines
    QStringList lines = result.split(QRegExp("[\n\r]"));
    if (lines.count() < 2)
        return QStringList();

    // get first line and its columns
    QString line = lines.at(1);
    QStringList columns = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
    if (columns.count() < 5)
        return QStringList();

    QString totalString = columns.at(1);
    QString usedString = columns.at(2);
    QString percentageString = columns.at(4);
    qint64 total = totalString.toLongLong() * 1024LL;
    qint64 used = usedString.toLongLong() * 1024LL;

    return QStringList() << percentageString << filesizeToString(used)+"/"+filesizeToString(total);
}

QStringList Engine::readFile(QString filename)
{
    int maxLines = 1000;
    int maxSize = 10000;
    int maxBinSize = 2048;

    // check existence
    StatFileInfo fileInfo(filename);
    if (!fileInfo.exists()) {
        if (!fileInfo.isSymLink())
            return makeStringList(tr("File does not exist\n%1").arg(filename));
        else
            return makeStringList(tr("Broken symbolic link\n%1").arg(filename));
    }

    // don't read unsafe system files
    if (!fileInfo.isSafeToRead()) {
        return makeStringList(tr("Can't read this type of file\n%1").arg(filename));
    }

    // check permissions
    if (access(filename, R_OK) == -1)
        return makeStringList(tr("No permission to read the file\n%1").arg(filename));

    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly))
        return makeStringList(tr("Error reading file\n%1").arg(filename));

    // read start of file
    char buffer[maxSize+1];
    qint64 readSize = file.read(buffer, maxSize);
    if (readSize < 0)
        return makeStringList(tr("Error reading file\n%1").arg(filename));

    if (readSize == 0)
        return makeStringList(tr("Empty file"));

    bool atEnd = file.atEnd();
    file.close();

    // detect binary or text file, it is binary if it contains zeros
    bool isText = true;
    for (int i = 0; i < readSize; ++i) {
        if (buffer[i] == 0) {
            isText = false;
            break;
        }
    }

    // binary output
    if (!isText) {
        // two different line widths
        if (readSize > maxBinSize) {
            readSize = maxBinSize;
            atEnd = false;
        }
        QString out8 = createHexDump(buffer, readSize, 8);
        QString out16 = createHexDump(buffer, readSize, 16);
        QString msg = "";

        if (!atEnd) {
            msg = tr("--- Binary file preview clipped at %1 kB ---").arg(maxBinSize/1000);
            msg = tr("--- Binary file preview clipped at %1 kB ---").arg(maxBinSize/1000);
        }

        return QStringList() << msg << out8 << out16;
    }

    // read lines to a string list and join
    QByteArray ba(buffer, readSize);
    QTextStream in(&ba);
    QStringList lines;
    int lineCount = 0;
    while (!in.atEnd() && lineCount < maxLines) {
        QString line = in.readLine();
        lines.append(line);
        lineCount++;
    }

    QString msg = "";
    if (lineCount == maxLines)
        msg = tr("--- Text file preview clipped at %1 lines ---").arg(maxLines);
    else if (!atEnd)
        msg = tr("--- Text file preview clipped at %1 kB ---").arg(maxSize/1000);

    return makeStringList(msg, lines.join("\n"));
}

QString Engine::mkdir(QString path, QString name)
{
    QDir dir(path);

    if (!dir.mkdir(name)) {
        if (access(dir.absolutePath(), W_OK) == -1)
            return tr("Cannot create folder %1\nPermission denied").arg(name);

        return tr("Cannot create folder %1").arg(name);
    }

    return QString();
}

QStringList Engine::rename(QString fullOldFilename, QString newName)
{
    QFile file(fullOldFilename);
    QFileInfo fileInfo(fullOldFilename);
    QDir dir = fileInfo.absoluteDir();
    QString fullNewFilename = dir.absoluteFilePath(newName);

    QString errorMessage;
    if (!file.rename(fullNewFilename)) {
        QString oldName = fileInfo.fileName();
        errorMessage = tr("Cannot rename %1\n%2").arg(oldName).arg(file.errorString());
    }

    return QStringList() << fullNewFilename << errorMessage;
}

QString Engine::chmod(QString path,
                      bool ownerRead, bool ownerWrite, bool ownerExecute,
                      bool groupRead, bool groupWrite, bool groupExecute,
                      bool othersRead, bool othersWrite, bool othersExecute)
{
    QFile file(path);
    QFileDevice::Permissions p;
    if (ownerRead) p |= QFileDevice::ReadOwner;
    if (ownerWrite) p |= QFileDevice::WriteOwner;
    if (ownerExecute) p |= QFileDevice::ExeOwner;
    if (groupRead) p |= QFileDevice::ReadGroup;
    if (groupWrite) p |= QFileDevice::WriteGroup;
    if (groupExecute) p |= QFileDevice::ExeGroup;
    if (othersRead) p |= QFileDevice::ReadOther;
    if (othersWrite) p |= QFileDevice::WriteOther;
    if (othersExecute) p |= QFileDevice::ExeOther;
    if (!file.setPermissions(p))
        return tr("Cannot change permissions\n%1").arg(file.errorString());

    return QString();
}

QString Engine::readSetting(QString key, QString defaultValue)
{
    QSettings settings;
    return settings.value(key, defaultValue).toString();
}

void Engine::writeSetting(QString key, QString value)
{
    QSettings settings;

    // do nothing if value didn't change
    if (settings.value(key) == value)
        return;

    settings.setValue(key, value);

    emit settingsChanged();
}

void Engine::setProgress(int progress, QString filename)
{
    m_progress = progress;
    m_progressFilename = filename;
    emit progressChanged();
    emit progressFilenameChanged();
}

QStringList Engine::mountPoints() const
{
    // read /proc/mounts and return all mount points for the filesystem
    QFile file("/proc/mounts");
    if (!file.open(QFile::ReadOnly | QFile::Text))
        return QStringList();

    QTextStream in(&file);
    QString result = in.readAll();

    // split result to lines
    QStringList lines = result.split(QRegExp("[\n\r]"));

    // get columns
    QStringList dirs;
    foreach (QString line, lines) {
        QStringList columns = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
        if (columns.count() < 6) // sanity check
            continue;

        QString dir = columns.at(1);
        dirs.append(dir);
    }

    return dirs;
}

QString Engine::createHexDump(char *buffer, int size, int bytesPerLine)
{
    QString out;
    QString ascDump;
    int i;
    for (i = 0; i < size; ++i) {
        if ((i % bytesPerLine) == 0) { // line change
            out += " "+ascDump+"\n"+
                    QString("%1").arg(QString::number(i, 16), 4, QLatin1Char('0'))+": ";
            ascDump.clear();
        }

        out += QString("%1").arg(QString::number((unsigned char)buffer[i], 16),
                                       2, QLatin1Char('0'))+" ";
        if (buffer[i] >= 32 && buffer[i] <= 126)
            ascDump += buffer[i];
        else
            ascDump += ".";
    }
    // write out remaining asc dump
    if ((i % bytesPerLine) > 0) {
        int emptyBytes = bytesPerLine - (i % bytesPerLine);
        for (int j = 0; j < emptyBytes; ++j) {
            out += "   ";
        }
    }
    out += " "+ascDump;

    return out;
}

QStringList Engine::makeStringList(QString msg, QString str)
{
    QStringList list;
    list << msg << str << str;
    return list;
}
<commit_msg>Fix view page to display actual kilobytes (1024s)<commit_after>#include "engine.h"
#include <QDateTime>
#include <QTextStream>
#include <QSettings>
#include <QStandardPaths>
#include "globals.h"
#include "fileworker.h"
#include "statfileinfo.h"

Engine::Engine(QObject *parent) :
    QObject(parent),
    m_clipboardContainsCopy(false),
    m_progress(0)
{
    m_fileWorker = new FileWorker;

    // update progress property when worker progresses
    connect(m_fileWorker, SIGNAL(progressChanged(int, QString)),
            this, SLOT(setProgress(int, QString)));

    // pass worker end signals to QML
    connect(m_fileWorker, SIGNAL(done()), this, SIGNAL(workerDone()));
    connect(m_fileWorker, SIGNAL(errorOccurred(QString, QString)),
            this, SIGNAL(workerErrorOccurred(QString, QString)));
    connect(m_fileWorker, SIGNAL(fileDeleted(QString)), this, SIGNAL(fileDeleted(QString)));
}

Engine::~Engine()
{
    // is this the way to force stop the worker thread?
    m_fileWorker->cancel(); // stop possibly running background thread
    m_fileWorker->wait();   // wait until thread stops
    delete m_fileWorker;    // delete it
}

void Engine::deleteFiles(QStringList filenames)
{
    setProgress(0, "");
    m_fileWorker->startDeleteFiles(filenames);
}

void Engine::cutFiles(QStringList filenames)
{
    m_clipboardFiles = filenames;
    m_clipboardContainsCopy = false;
    emit clipboardCountChanged();
    emit clipboardContainsCopyChanged();
}

void Engine::copyFiles(QStringList filenames)
{
    // don't copy special files (chr/blk/fifo/sock)
    QMutableStringListIterator i(filenames);
    while (i.hasNext()) {
        QString filename = i.next();
        StatFileInfo info(filename);
        if (info.isSystem())
            i.remove();
    }

    m_clipboardFiles = filenames;
    m_clipboardContainsCopy = true;
    emit clipboardCountChanged();
    emit clipboardContainsCopyChanged();
}

void Engine::pasteFiles(QString destDirectory)
{
    if (m_clipboardFiles.isEmpty()) {
        emit workerErrorOccurred("No files to paste", "");
        return;
    }

    QStringList files = m_clipboardFiles;
    setProgress(0, "");

    QDir dest(destDirectory);
    if (!dest.exists()) {
        emit workerErrorOccurred(tr("Destination does not exist"), destDirectory);
        return;
    }

    foreach (QString filename, files) {
        QFileInfo fileInfo(filename);
        QString newname = dest.absoluteFilePath(fileInfo.fileName());

        // source and dest filenames are the same?
        if (filename == newname) {
            emit workerErrorOccurred(tr("Can't overwrite itself"), newname);
            return;
        }

        // dest is under source? (directory)
        if (newname.startsWith(filename)) {
            emit workerErrorOccurred(tr("Can't move/copy to itself"), filename);
            return;
        }
    }

    m_clipboardFiles.clear();
    emit clipboardCountChanged();

    if (m_clipboardContainsCopy) {
        m_fileWorker->startCopyFiles(files, destDirectory);
        return;
    }

    m_fileWorker->startMoveFiles(files, destDirectory);
}

void Engine::cancel()
{
    m_fileWorker->cancel();
}

QString Engine::homeFolder() const
{
    return QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
}

QString Engine::sdcardPath() const
{
    // get sdcard dir candidates
    QDir dir("/media/sdcard");
    if (!dir.exists())
        return QString();
    dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
    QStringList sdcards = dir.entryList();
    if (sdcards.isEmpty())
        return QString();

    // remove all directories which are not mount points
    QStringList mps = mountPoints();
    QMutableStringListIterator i(sdcards);
    while (i.hasNext()) {
        QString dirname = i.next();
        QString abspath = dir.absoluteFilePath(dirname);
        if (!mps.contains(abspath))
            i.remove();
    }

    // none found, return empty string
    if (sdcards.isEmpty())
        return QString();

    // if only one directory, then return it
    if (sdcards.count() == 1)
        return dir.absoluteFilePath(sdcards.first());

    // if multiple directories, then return "/media/sdcard", which is the parent for them
    return "/media/sdcard";
}

QString Engine::androidSdcardPath() const
{
    return QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/android_storage";
}

bool Engine::exists(QString filename)
{
    if (filename.isEmpty())
        return false;

    return QFile::exists(filename);
}

QStringList Engine::diskSpace(QString path)
{
    if (path.isEmpty())
        return QStringList();

    // return no disk space for sdcard parent directory
    if (path == "/media/sdcard")
        return QStringList();

    // run df for the given path to get disk space
    QString blockSize = "--block-size=1024";
    QString result = execute("/bin/df", QStringList() << blockSize << path, false);
    if (result.isEmpty())
        return QStringList();

    // split result to lines
    QStringList lines = result.split(QRegExp("[\n\r]"));
    if (lines.count() < 2)
        return QStringList();

    // get first line and its columns
    QString line = lines.at(1);
    QStringList columns = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
    if (columns.count() < 5)
        return QStringList();

    QString totalString = columns.at(1);
    QString usedString = columns.at(2);
    QString percentageString = columns.at(4);
    qint64 total = totalString.toLongLong() * 1024LL;
    qint64 used = usedString.toLongLong() * 1024LL;

    return QStringList() << percentageString << filesizeToString(used)+"/"+filesizeToString(total);
}

QStringList Engine::readFile(QString filename)
{
    int maxLines = 1000;
    int maxSize = 10240;
    int maxBinSize = 2048;

    // check existence
    StatFileInfo fileInfo(filename);
    if (!fileInfo.exists()) {
        if (!fileInfo.isSymLink())
            return makeStringList(tr("File does not exist\n%1").arg(filename));
        else
            return makeStringList(tr("Broken symbolic link\n%1").arg(filename));
    }

    // don't read unsafe system files
    if (!fileInfo.isSafeToRead()) {
        return makeStringList(tr("Can't read this type of file\n%1").arg(filename));
    }

    // check permissions
    if (access(filename, R_OK) == -1)
        return makeStringList(tr("No permission to read the file\n%1").arg(filename));

    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly))
        return makeStringList(tr("Error reading file\n%1").arg(filename));

    // read start of file
    char buffer[maxSize+1];
    qint64 readSize = file.read(buffer, maxSize);
    if (readSize < 0)
        return makeStringList(tr("Error reading file\n%1").arg(filename));

    if (readSize == 0)
        return makeStringList(tr("Empty file"));

    bool atEnd = file.atEnd();
    file.close();

    // detect binary or text file, it is binary if it contains zeros
    bool isText = true;
    for (int i = 0; i < readSize; ++i) {
        if (buffer[i] == 0) {
            isText = false;
            break;
        }
    }

    // binary output
    if (!isText) {
        // two different line widths
        if (readSize > maxBinSize) {
            readSize = maxBinSize;
            atEnd = false;
        }
        QString out8 = createHexDump(buffer, readSize, 8);
        QString out16 = createHexDump(buffer, readSize, 16);
        QString msg = "";

        if (!atEnd) {
            msg = tr("--- Binary file preview clipped at %1 kB ---").arg(maxBinSize/1024);
            msg = tr("--- Binary file preview clipped at %1 kB ---").arg(maxBinSize/1024);
        }

        return QStringList() << msg << out8 << out16;
    }

    // read lines to a string list and join
    QByteArray ba(buffer, readSize);
    QTextStream in(&ba);
    QStringList lines;
    int lineCount = 0;
    while (!in.atEnd() && lineCount < maxLines) {
        QString line = in.readLine();
        lines.append(line);
        lineCount++;
    }

    QString msg = "";
    if (lineCount == maxLines)
        msg = tr("--- Text file preview clipped at %1 lines ---").arg(maxLines);
    else if (!atEnd)
        msg = tr("--- Text file preview clipped at %1 kB ---").arg(maxSize/1024);

    return makeStringList(msg, lines.join("\n"));
}

QString Engine::mkdir(QString path, QString name)
{
    QDir dir(path);

    if (!dir.mkdir(name)) {
        if (access(dir.absolutePath(), W_OK) == -1)
            return tr("Cannot create folder %1\nPermission denied").arg(name);

        return tr("Cannot create folder %1").arg(name);
    }

    return QString();
}

QStringList Engine::rename(QString fullOldFilename, QString newName)
{
    QFile file(fullOldFilename);
    QFileInfo fileInfo(fullOldFilename);
    QDir dir = fileInfo.absoluteDir();
    QString fullNewFilename = dir.absoluteFilePath(newName);

    QString errorMessage;
    if (!file.rename(fullNewFilename)) {
        QString oldName = fileInfo.fileName();
        errorMessage = tr("Cannot rename %1\n%2").arg(oldName).arg(file.errorString());
    }

    return QStringList() << fullNewFilename << errorMessage;
}

QString Engine::chmod(QString path,
                      bool ownerRead, bool ownerWrite, bool ownerExecute,
                      bool groupRead, bool groupWrite, bool groupExecute,
                      bool othersRead, bool othersWrite, bool othersExecute)
{
    QFile file(path);
    QFileDevice::Permissions p;
    if (ownerRead) p |= QFileDevice::ReadOwner;
    if (ownerWrite) p |= QFileDevice::WriteOwner;
    if (ownerExecute) p |= QFileDevice::ExeOwner;
    if (groupRead) p |= QFileDevice::ReadGroup;
    if (groupWrite) p |= QFileDevice::WriteGroup;
    if (groupExecute) p |= QFileDevice::ExeGroup;
    if (othersRead) p |= QFileDevice::ReadOther;
    if (othersWrite) p |= QFileDevice::WriteOther;
    if (othersExecute) p |= QFileDevice::ExeOther;
    if (!file.setPermissions(p))
        return tr("Cannot change permissions\n%1").arg(file.errorString());

    return QString();
}

QString Engine::readSetting(QString key, QString defaultValue)
{
    QSettings settings;
    return settings.value(key, defaultValue).toString();
}

void Engine::writeSetting(QString key, QString value)
{
    QSettings settings;

    // do nothing if value didn't change
    if (settings.value(key) == value)
        return;

    settings.setValue(key, value);

    emit settingsChanged();
}

void Engine::setProgress(int progress, QString filename)
{
    m_progress = progress;
    m_progressFilename = filename;
    emit progressChanged();
    emit progressFilenameChanged();
}

QStringList Engine::mountPoints() const
{
    // read /proc/mounts and return all mount points for the filesystem
    QFile file("/proc/mounts");
    if (!file.open(QFile::ReadOnly | QFile::Text))
        return QStringList();

    QTextStream in(&file);
    QString result = in.readAll();

    // split result to lines
    QStringList lines = result.split(QRegExp("[\n\r]"));

    // get columns
    QStringList dirs;
    foreach (QString line, lines) {
        QStringList columns = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
        if (columns.count() < 6) // sanity check
            continue;

        QString dir = columns.at(1);
        dirs.append(dir);
    }

    return dirs;
}

QString Engine::createHexDump(char *buffer, int size, int bytesPerLine)
{
    QString out;
    QString ascDump;
    int i;
    for (i = 0; i < size; ++i) {
        if ((i % bytesPerLine) == 0) { // line change
            out += " "+ascDump+"\n"+
                    QString("%1").arg(QString::number(i, 16), 4, QLatin1Char('0'))+": ";
            ascDump.clear();
        }

        out += QString("%1").arg(QString::number((unsigned char)buffer[i], 16),
                                       2, QLatin1Char('0'))+" ";
        if (buffer[i] >= 32 && buffer[i] <= 126)
            ascDump += buffer[i];
        else
            ascDump += ".";
    }
    // write out remaining asc dump
    if ((i % bytesPerLine) > 0) {
        int emptyBytes = bytesPerLine - (i % bytesPerLine);
        for (int j = 0; j < emptyBytes; ++j) {
            out += "   ";
        }
    }
    out += " "+ascDump;

    return out;
}

QStringList Engine::makeStringList(QString msg, QString str)
{
    QStringList list;
    list << msg << str << str;
    return list;
}
<|endoftext|>


<commit_before>#include "engine.h"
#include "random.h"
#include "gameEntity.h"
#include "Updatable.h"
#include "collisionable.h"
#include "audio/source.h"

#include <SDL.h>

#ifdef DEBUG
#include <typeinfo>
int DEBUG_PobjCount;
PObject* DEBUG_PobjListStart;
#endif

#ifdef WIN32
#include <windows.h>

namespace
{
    HINSTANCE exchndl = nullptr;
}
#endif

Engine* engine;

Engine::Engine()
{
    engine = this;

#ifdef WIN32
    // Setup crash reporter (Dr. MinGW) if available.
    exchndl = LoadLibrary(TEXT("exchndl.dll"));

    if (exchndl)
    {
        auto pfnExcHndlInit = GetProcAddress(exchndl, "ExcHndlInit");

        if (pfnExcHndlInit)
        {
            pfnExcHndlInit();
            LOG(INFO) << "Crash Reporter ON";
        }
        else
        {
            LOG(WARNING) << "Failed to initialize Crash Reporter";
            FreeLibrary(exchndl);
            exchndl = nullptr;
        }
    }
#endif // WIN32

    SDL_Init(SDL_INIT_EVERYTHING);
    atexit(SDL_Quit);

    initRandom();
    window = nullptr;
    CollisionManager::initialize();
    InputHandler::initialize();
    gameSpeed = 1.0;
    running = true;
    elapsedTime = 0.0;
    soundManager = new SoundManager();
}

Engine::~Engine()
{
    delete soundManager;
    soundManager = nullptr;

#ifdef WIN32
    if (exchndl)
    {
        FreeLibrary(exchndl);
        exchndl = nullptr;
    }
#endif // WIN32
}

void Engine::registerObject(string name, P<PObject> obj)
{
    objectMap[name] = obj;
}

P<PObject> Engine::getObject(string name)
{
    if (!objectMap[name])
        return NULL;
    return objectMap[name];
}

void Engine::runMainLoop()
{
    window = dynamic_cast<Window*>(*getObject("window"));
    if (!window)
    {
        sp::SystemStopwatch frame_timer;
        while(running)
        {
            float delta = frame_timer.restart();
            if (delta > 0.5f)
                delta = 0.5f;
            if (delta < 0.001f)
                delta = 0.001f;
            delta *= gameSpeed;

            foreach(Updatable, u, updatableList)
                u->update(delta);
            elapsedTime += delta;
            CollisionManager::handleCollisions(delta);
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            std::this_thread::sleep_for(std::chrono::duration<float>(1.f/60.f - delta));
        }
    }else{
        sp::audio::Source::startAudioSystem();
        sp::SystemStopwatch frame_timer;
#ifdef DEBUG
        sp::SystemTimer debug_output_timer;
        debug_output_timer.repeat(5);
#endif
        while(running)
        {
            InputHandler::preEventsUpdate();
            // Handle events
            SDL_Event event;
            while (SDL_PollEvent(&event))
            {
                handleEvent(event);
            }
            InputHandler::postEventsUpdate();

#ifdef DEBUG
            if (debug_output_timer.isExpired())
                printf("Object count: %4d %4zd\n", DEBUG_PobjCount, updatableList.size());
#endif

            float delta = frame_timer.restart();
            if (delta > 0.5f)
                delta = 0.5f;
            if (delta < 0.001f)
                delta = 0.001f;
            delta *= gameSpeed;
#ifdef DEBUG
#warning TODO SDL2
/*
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tab))
                delta /= 5.f;
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tilde))
                delta *= 5.f;
*/
#endif
            EngineTiming engine_timing;

            sp::SystemStopwatch engine_timing_stopwatch;
            foreach(Updatable, u, updatableList) {
                u->update(delta);
            }
            elapsedTime += delta;
            engine_timing.update = engine_timing_stopwatch.restart();
            CollisionManager::handleCollisions(delta);
            engine_timing.collision = engine_timing_stopwatch.restart();
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            // Clear the window
            window->render();
            engine_timing.render = engine_timing_stopwatch.restart();
            engine_timing.server_update = 0.0f;
            if (game_server)
                engine_timing.server_update = game_server->getUpdateTime();

            last_engine_timing = engine_timing;
        }
        soundManager->stopMusic();
    }
}

void Engine::handleEvent(SDL_Event& event)
{
    // Window closed: exit
    if (event.type == SDL_QUIT)
        running = false;
#ifdef DEBUG
    if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)
        running = false;
    if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_l)
    {
        int n = 0;
        printf("------------------------\n");
        std::unordered_map<string,int> totals;
        for(PObject* obj = DEBUG_PobjListStart; obj; obj = obj->DEBUG_PobjListNext)
        {
            printf("%c%4d: %4d: %s\n", obj->isDestroyed() ? '>' : ' ', n++, obj->getRefCount(), typeid(*obj).name());
            if (!obj->isDestroyed())
            {
                totals[typeid(*obj).name()]=totals[typeid(*obj).name()]+1;
            }
        }
        printf("--non-destroyed totals--\n");
        int grand_total=0;
        for (auto entry : totals)
        {
            printf("%4d %s\n", entry.second, entry.first.c_str());
            grand_total+=entry.second;
        }
        printf("%4d %s\n",grand_total,"All PObjects");
        printf("------------------------\n");
    }
#endif
    InputHandler::handleEvent(event);
    if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED)
        window->setupView();
}

void Engine::setGameSpeed(float speed)
{
    gameSpeed = speed;
}

float Engine::getGameSpeed()
{
    return gameSpeed;
}

float Engine::getElapsedTime()
{
    return elapsedTime;
}

Engine::EngineTiming Engine::getEngineTiming()
{
    return last_engine_timing;
}

void Engine::shutdown()
{
    running = false;
}
<commit_msg>Update engine.cpp<commit_after>#include "engine.h"
#include "random.h"
#include "gameEntity.h"
#include "Updatable.h"
#include "collisionable.h"
#include "audio/source.h"

#include <SDL.h>

#ifdef DEBUG
#include <typeinfo>
int DEBUG_PobjCount;
PObject* DEBUG_PobjListStart;
#endif

#ifdef WIN32
#include <windows.h>

namespace
{
    HINSTANCE exchndl = nullptr;
}
#endif

Engine* engine;

Engine::Engine()
{
    engine = this;

#ifdef WIN32
    // Setup crash reporter (Dr. MinGW) if available.
    exchndl = LoadLibrary(TEXT("exchndl.dll"));

    if (exchndl)
    {
        auto pfnExcHndlInit = GetProcAddress(exchndl, "ExcHndlInit");

        if (pfnExcHndlInit)
        {
            pfnExcHndlInit();
            LOG(INFO) << "Crash Reporter ON";
        }
        else
        {
            LOG(WARNING) << "Failed to initialize Crash Reporter";
            FreeLibrary(exchndl);
            exchndl = nullptr;
        }
    }
#endif // WIN32

    SDL_Init(SDL_INIT_EVERYTHING);
    atexit(SDL_Quit);

    initRandom();
    window = nullptr;
    CollisionManager::initialize();
    InputHandler::initialize();
    gameSpeed = 1.0;
    running = true;
    elapsedTime = 0.0;
    soundManager = new SoundManager();
}

Engine::~Engine()
{
    delete soundManager;
    soundManager = nullptr;

#ifdef WIN32
    if (exchndl)
    {
        FreeLibrary(exchndl);
        exchndl = nullptr;
    }
#endif // WIN32
}

void Engine::registerObject(string name, P<PObject> obj)
{
    objectMap[name] = obj;
}

P<PObject> Engine::getObject(string name)
{
    if (!objectMap[name])
        return NULL;
    return objectMap[name];
}

void Engine::runMainLoop()
{
    window = dynamic_cast<Window*>(*getObject("window"));
    if (!window)
    {
        sp::SystemStopwatch frame_timer;
        while(running)
        {
            float delta = frame_timer.restart();
            if (delta > 0.5f)
                delta = 0.5f;
            if (delta < 0.001f)
                delta = 0.001f;
            delta *= gameSpeed;

            foreach(Updatable, u, updatableList)
                u->update(delta);
            elapsedTime += delta;
            CollisionManager::handleCollisions(delta);
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            std::this_thread::sleep_for(std::chrono::duration<float>(1.f/60.f - delta));
        }
    }else{
        sp::audio::Source::startAudioSystem();
        sp::SystemStopwatch frame_timer;
#ifdef DEBUG
        sp::SystemTimer debug_output_timer;
        debug_output_timer.repeat(5);
#endif
        while(running)
        {
            InputHandler::preEventsUpdate();
            // Handle events
            SDL_Event event;
            while (SDL_PollEvent(&event))
            {
                handleEvent(event);
            }
            InputHandler::postEventsUpdate();

#ifdef DEBUG
            if (debug_output_timer.isExpired())
                printf("Object count: %4d %4zd\n", DEBUG_PobjCount, updatableList.size());
#endif

            float delta = frame_timer.restart();
            if (delta > 0.5f)
                delta = 0.5f;
            if (delta < 0.001f)
                delta = 0.001f;
            delta *= gameSpeed;
#ifdef DEBUG
/*
#warning TODO SDL2
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tab))
                delta /= 5.f;
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tilde))
                delta *= 5.f;
*/
#endif
            EngineTiming engine_timing;

            sp::SystemStopwatch engine_timing_stopwatch;
            foreach(Updatable, u, updatableList) {
                u->update(delta);
            }
            elapsedTime += delta;
            engine_timing.update = engine_timing_stopwatch.restart();
            CollisionManager::handleCollisions(delta);
            engine_timing.collision = engine_timing_stopwatch.restart();
            ScriptObject::clearDestroyedObjects();
            soundManager->updateTick();

            // Clear the window
            window->render();
            engine_timing.render = engine_timing_stopwatch.restart();
            engine_timing.server_update = 0.0f;
            if (game_server)
                engine_timing.server_update = game_server->getUpdateTime();

            last_engine_timing = engine_timing;
        }
        soundManager->stopMusic();
    }
}

void Engine::handleEvent(SDL_Event& event)
{
    // Window closed: exit
    if (event.type == SDL_QUIT)
        running = false;
#ifdef DEBUG
    if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)
        running = false;
    if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_l)
    {
        int n = 0;
        printf("------------------------\n");
        std::unordered_map<string,int> totals;
        for(PObject* obj = DEBUG_PobjListStart; obj; obj = obj->DEBUG_PobjListNext)
        {
            printf("%c%4d: %4d: %s\n", obj->isDestroyed() ? '>' : ' ', n++, obj->getRefCount(), typeid(*obj).name());
            if (!obj->isDestroyed())
            {
                totals[typeid(*obj).name()]=totals[typeid(*obj).name()]+1;
            }
        }
        printf("--non-destroyed totals--\n");
        int grand_total=0;
        for (auto entry : totals)
        {
            printf("%4d %s\n", entry.second, entry.first.c_str());
            grand_total+=entry.second;
        }
        printf("%4d %s\n",grand_total,"All PObjects");
        printf("------------------------\n");
    }
#endif
    InputHandler::handleEvent(event);
    if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED)
        window->setupView();
}

void Engine::setGameSpeed(float speed)
{
    gameSpeed = speed;
}

float Engine::getGameSpeed()
{
    return gameSpeed;
}

float Engine::getElapsedTime()
{
    return elapsedTime;
}

Engine::EngineTiming Engine::getEngineTiming()
{
    return last_engine_timing;
}

void Engine::shutdown()
{
    running = false;
}
<|endoftext|>


<commit_before>// fluxbox.hh for Fluxbox Window Manager
// Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
//
// blackbox.hh for Blackbox - an X11 Window manager
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
//
// 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.

// $Id: fluxbox.hh,v 1.82 2004/01/11 16:10:23 fluxgen Exp $

#ifndef	 FLUXBOX_HH
#define	 FLUXBOX_HH

#include "FbTk/App.hh"
#include "FbTk/Resource.hh"
#include "FbTk/Timer.hh"
#include "FbTk/Observer.hh"
#include "FbTk/SignalHandler.hh"

#include <X11/Xlib.h>
#include <X11/Xresource.h>

#include <cstdio>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H

#ifdef TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else // !TIME_WITH_SYS_TIME
#ifdef	HAVE_SYS_TIME_H
#include <sys/time.h>
#else // !HAVE_SYS_TIME_H
#include <time.h>
#endif // HAVE_SYS_TIME_H
#endif // TIME_WITH_SYS_TIME

#include <list>
#include <map>
#include <memory>
#include <string>
#include <vector>

class AtomHandler;
class FluxboxWindow;
class WinClient;
class Keys;
class BScreen;
class FbAtoms;
class Toolbar;

///	main class for the window manager.
/**
	singleton type
*/
class Fluxbox : public FbTk::App,
                public FbTk::SignalEventHandler,
                public FbTk::Observer {
public:
    Fluxbox(int argc, char **argv, const char * dpy_name= 0,
            const char *rcfilename = 0);
    virtual ~Fluxbox();

    static Fluxbox *instance() { return s_singleton; }
    /// main event loop
    void eventLoop();
    bool validateWindow(Window win) const;
    void grab();
    void ungrab();
    Keys *keys() { return m_key.get(); }
    inline Atom getFluxboxPidAtom() const { return m_fluxbox_pid; }

    // Not currently implemented until we decide how it'll be used
    //WinClient *searchGroup(Window);
    WinClient *searchWindow(Window);
    inline WinClient *getFocusedWindow() { return m_focused_window; }

    BScreen *searchScreen(Window w);

    inline unsigned int getDoubleClickInterval() const { return *m_rc_double_click_interval; }
    inline unsigned int getUpdateDelayTime() const { return *m_rc_update_delay_time; }
    inline Time getLastTime() const { return m_last_time; }

    void addAtomHandler(AtomHandler *atomh);
    void removeAtomHandler(AtomHandler *atomh);

    /// obsolete
    enum Titlebar{SHADE=0, MINIMIZE, MAXIMIZE, CLOSE, STICK, MENU, EMPTY};

    inline const Bool getIgnoreBorder() const { return *m_rc_ignoreborder; }

    inline const std::vector<Fluxbox::Titlebar>& getTitlebarRight() const { return *m_rc_titlebar_right; }
    inline const std::vector<Fluxbox::Titlebar>& getTitlebarLeft() const { return *m_rc_titlebar_left; }
    inline const std::string &getStyleFilename() const { return *m_rc_stylefile; }

    inline const std::string &getMenuFilename() const { return *m_rc_menufile; }
    inline const std::string &getSlitlistFilename() const { return *m_rc_slitlistfile; }
    inline int colorsPerChannel() const { return *m_rc_colors_per_channel; }
    inline int getNumberOfLayers() const { return *m_rc_numlayers; }

    // class to store layer numbers (special Resource type)
    // we have a special resource type because we need to be able to name certain layers
    // a Resource<int> wouldn't allow this
    class Layer {
    public:
        explicit Layer(int i) : m_num(i) {};
        inline int getNum() const { return m_num; }

        Layer &operator=(int num) { m_num = num; return *this; }

    private:
        int m_num;
    };

    // TODO these probably should be configurable
    inline int getMenuLayer()      const { return 0; }
    inline int getAboveDockLayer() const { return 2; }
    inline int getDockLayer()      const { return 4; }
    inline int getTopLayer()       const { return 6; }
    inline int getNormalLayer()    const { return 8; }
    inline int getBottomLayer()    const { return 10; }
    inline int getDesktopLayer()   const { return 12; }

    inline time_t getAutoRaiseDelay() const { return *m_rc_auto_raise_delay; }

    inline unsigned int getCacheLife() const { return *m_rc_cache_life * 60000; }
    inline unsigned int getCacheMax() const { return *m_rc_cache_max; }
    inline bool useMod1() const { return *m_rc_use_mod1; }

    inline void maskWindowEvents(Window w, FluxboxWindow *bw)
        { m_masked = w; m_masked_window = bw; }

    void watchKeyRelease(BScreen &screen, unsigned int mods);

    void setFocusedWindow(WinClient *w);
    void revertFocus(BScreen &screen);
    void shutdown();
    void load_rc(BScreen &scr);
    void loadRootCommand(BScreen &scr);
    void loadTitlebar();
    void saveStyleFilename(const char *val) { m_rc_stylefile = (val == 0 ? "" : val); }
    void saveMenuFilename(const char *);
    void clearMenuFilenames();
    void saveTitlebarFilename(const char *);
    void saveSlitlistFilename(const char *val) { m_rc_slitlistfile = (val == 0 ? "" : val); }
    void saveWindowSearch(Window win, WinClient *winclient);
    // some windows relate to the group, not the client, so we record separately
    // searchWindow on these windows will give the active client in the group
    void saveWindowSearchGroup(Window win, FluxboxWindow *fbwin);
    void saveGroupSearch(Window win, WinClient *winclient);
    void save_rc();
    void removeWindowSearch(Window win);
    void removeWindowSearchGroup(Window win);
    void removeGroupSearch(Window win);
    void restart(const char *command = 0);
    void reconfigure();
    void rereadMenu();
    /// reloads the menus if the timestamps changed
    void checkMenu();

    void hideExtraMenus(BScreen &screen);

    /// handle any system signal sent to the application
    void handleSignal(int signum);
    void update(FbTk::Subject *changed);

    void attachSignals(FluxboxWindow &win);
    void attachSignals(WinClient &winclient);

    void timed_reconfigure();

    bool isStartup() const { return m_starting; }

    typedef std::vector<Fluxbox::Titlebar> TitlebarList;
    /// @return whether the timestamps on the menu changed
    bool menuTimestampsChanged() const;
    bool haveShape() const { return m_have_shape; }
    int shapeEventbase() const { return m_shape_eventbase; }
    void getDefaultDataFilename(char *, std::string &);
    // screen mouse was in at last key event
    BScreen *mouseScreen() { return m_mousescreen; }
    // screen of window that last key event (i.e. focused window) went to
    BScreen *keyScreen() { return m_keyscreen; }
    // screen we are watching for modifier changes
    BScreen *watchingScreen() { return m_watching_screen; }
    const XEvent &lastEvent() const { return m_last_event; }
private:

    typedef struct MenuTimestamp {
        std::string filename;
        time_t timestamp;
    } MenuTimestamp;

    std::string getRcFilename();
    void load_rc();

    void reload_rc();
    void real_rereadMenu();
    void real_reconfigure();

    void handleEvent(XEvent *xe);

    void setupConfigFiles();
    void handleButtonEvent(XButtonEvent &be);
    void handleUnmapNotify(XUnmapEvent &ue);
    void handleClientMessage(XClientMessageEvent &ce);
    void handleKeyEvent(XKeyEvent &ke);
    void setTitlebar(std::vector<Fluxbox::Titlebar>& dir, const char *arg);

    std::auto_ptr<FbAtoms> m_fbatoms;

    FbTk::ResourceManager m_resourcemanager, &m_screen_rm;

    //--- Resources

    FbTk::Resource<bool> m_rc_tabs, m_rc_ignoreborder;
    FbTk::Resource<int> m_rc_colors_per_channel, m_rc_numlayers,
        m_rc_double_click_interval, m_rc_update_delay_time;
    FbTk::Resource<std::string> m_rc_stylefile,
        m_rc_menufile, m_rc_keyfile, m_rc_slitlistfile,
        m_rc_groupfile;

    FbTk::Resource<TitlebarList> m_rc_titlebar_left, m_rc_titlebar_right;
    FbTk::Resource<unsigned int> m_rc_cache_life, m_rc_cache_max;
    FbTk::Resource<time_t> m_rc_auto_raise_delay;
    FbTk::Resource<bool> m_rc_use_mod1; /// temporary!, to disable mod1 for resize/move

    std::map<Window, WinClient *> m_window_search;
    std::map<Window, FluxboxWindow *> m_window_search_group;
    // A window is the group leader, which can map to several
    // WinClients in the group, it is *not* fluxbox's concept of groups
    // See ICCCM section 4.1.11
    // The group leader (which may not be mapped, so may not have a WinClient)
    // will have it's window being the group index
    std::multimap<Window, WinClient *> m_group_search;

    std::list<MenuTimestamp *> m_menu_timestamps;
    typedef std::list<BScreen *> ScreenList;
    ScreenList m_screen_list;

    WinClient *m_focused_window;
    FluxboxWindow *m_masked_window;

    BScreen *m_mousescreen, *m_keyscreen;
    BScreen *m_watching_screen;
    unsigned int m_watch_keyrelease;

    Atom m_fluxbox_pid;

    bool m_reconfigure_wait, m_reread_menu_wait;
    Time m_last_time;
    Window m_masked;
    std::string m_rc_file; ///< resource filename
    char **m_argv;
    int m_argc;
    XEvent m_last_event;

    FbTk::Timer m_reconfig_timer; ///< when we execute reconfig command we must wait at least to next event round

    std::auto_ptr<Keys> m_key;

    //default arguments for titlebar left and right
    static Fluxbox::Titlebar s_titlebar_left[], s_titlebar_right[];
    static Fluxbox *s_singleton;
    std::vector<AtomHandler *> m_atomhandler;
    std::vector<Toolbar *> m_toolbars;

    bool m_starting;
    bool m_shutdown;
    int m_server_grabs;
    int m_randr_event_type; ///< the type number of randr event
    int m_shape_eventbase; ///< event base for shape events
    bool m_have_shape; ///< if shape is supported by server
    const char *m_RC_PATH;
    const char *m_RC_INIT_FILE;
    Atom m_kwm1_dockwindow, m_kwm2_dockwindow;
};

#endif // FLUXBOX_HH
<commit_msg>minor fix<commit_after>// fluxbox.hh for Fluxbox Window Manager
// Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
//
// blackbox.hh for Blackbox - an X11 Window manager
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
//
// 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.

// $Id: fluxbox.hh,v 1.83 2004/02/10 18:45:57 fluxgen Exp $

#ifndef	 FLUXBOX_HH
#define	 FLUXBOX_HH

#include "FbTk/App.hh"
#include "FbTk/Resource.hh"
#include "FbTk/Timer.hh"
#include "FbTk/Observer.hh"
#include "FbTk/SignalHandler.hh"

#include <X11/Xlib.h>
#include <X11/Xresource.h>

#include <cstdio>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H

#ifdef TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else // !TIME_WITH_SYS_TIME
#ifdef	HAVE_SYS_TIME_H
#include <sys/time.h>
#else // !HAVE_SYS_TIME_H
#include <time.h>
#endif // HAVE_SYS_TIME_H
#endif // TIME_WITH_SYS_TIME

#include <list>
#include <map>
#include <memory>
#include <string>
#include <vector>

class AtomHandler;
class FluxboxWindow;
class WinClient;
class Keys;
class BScreen;
class FbAtoms;
class Toolbar;

///	main class for the window manager.
/**
	singleton type
*/
class Fluxbox : public FbTk::App,
                public FbTk::SignalEventHandler,
                public FbTk::Observer {
public:
    Fluxbox(int argc, char **argv, const char * dpy_name= 0,
            const char *rcfilename = 0);
    virtual ~Fluxbox();

    static Fluxbox *instance() { return s_singleton; }
    /// main event loop
    void eventLoop();
    bool validateWindow(Window win) const;
    void grab();
    void ungrab();
    Keys *keys() { return m_key.get(); }
    inline Atom getFluxboxPidAtom() const { return m_fluxbox_pid; }

    // Not currently implemented until we decide how it'll be used
    //WinClient *searchGroup(Window);
    WinClient *searchWindow(Window);
    inline WinClient *getFocusedWindow() { return m_focused_window; }

    BScreen *searchScreen(Window w);

    inline unsigned int getDoubleClickInterval() const { return *m_rc_double_click_interval; }
    inline unsigned int getUpdateDelayTime() const { return *m_rc_update_delay_time; }
    inline Time getLastTime() const { return m_last_time; }

    void addAtomHandler(AtomHandler *atomh);
    void removeAtomHandler(AtomHandler *atomh);

    /// obsolete
    enum Titlebar{SHADE=0, MINIMIZE, MAXIMIZE, CLOSE, STICK, MENU, EMPTY};

    inline bool getIgnoreBorder() const { return *m_rc_ignoreborder; }

    inline const std::vector<Fluxbox::Titlebar>& getTitlebarRight() const { return *m_rc_titlebar_right; }
    inline const std::vector<Fluxbox::Titlebar>& getTitlebarLeft() const { return *m_rc_titlebar_left; }
    inline const std::string &getStyleFilename() const { return *m_rc_stylefile; }

    inline const std::string &getMenuFilename() const { return *m_rc_menufile; }
    inline const std::string &getSlitlistFilename() const { return *m_rc_slitlistfile; }
    inline int colorsPerChannel() const { return *m_rc_colors_per_channel; }
    inline int getNumberOfLayers() const { return *m_rc_numlayers; }

    // class to store layer numbers (special Resource type)
    // we have a special resource type because we need to be able to name certain layers
    // a Resource<int> wouldn't allow this
    class Layer {
    public:
        explicit Layer(int i) : m_num(i) {};
        inline int getNum() const { return m_num; }

        Layer &operator=(int num) { m_num = num; return *this; }

    private:
        int m_num;
    };

    // TODO these probably should be configurable
    inline int getMenuLayer()      const { return 0; }
    inline int getAboveDockLayer() const { return 2; }
    inline int getDockLayer()      const { return 4; }
    inline int getTopLayer()       const { return 6; }
    inline int getNormalLayer()    const { return 8; }
    inline int getBottomLayer()    const { return 10; }
    inline int getDesktopLayer()   const { return 12; }

    inline time_t getAutoRaiseDelay() const { return *m_rc_auto_raise_delay; }

    inline unsigned int getCacheLife() const { return *m_rc_cache_life * 60000; }
    inline unsigned int getCacheMax() const { return *m_rc_cache_max; }
    inline bool useMod1() const { return *m_rc_use_mod1; }

    inline void maskWindowEvents(Window w, FluxboxWindow *bw)
        { m_masked = w; m_masked_window = bw; }

    void watchKeyRelease(BScreen &screen, unsigned int mods);

    void setFocusedWindow(WinClient *w);
    void revertFocus(BScreen &screen);
    void shutdown();
    void load_rc(BScreen &scr);
    void loadRootCommand(BScreen &scr);
    void loadTitlebar();
    void saveStyleFilename(const char *val) { m_rc_stylefile = (val == 0 ? "" : val); }
    void saveMenuFilename(const char *);
    void clearMenuFilenames();
    void saveTitlebarFilename(const char *);
    void saveSlitlistFilename(const char *val) { m_rc_slitlistfile = (val == 0 ? "" : val); }
    void saveWindowSearch(Window win, WinClient *winclient);
    // some windows relate to the group, not the client, so we record separately
    // searchWindow on these windows will give the active client in the group
    void saveWindowSearchGroup(Window win, FluxboxWindow *fbwin);
    void saveGroupSearch(Window win, WinClient *winclient);
    void save_rc();
    void removeWindowSearch(Window win);
    void removeWindowSearchGroup(Window win);
    void removeGroupSearch(Window win);
    void restart(const char *command = 0);
    void reconfigure();
    void rereadMenu();
    /// reloads the menus if the timestamps changed
    void checkMenu();

    void hideExtraMenus(BScreen &screen);

    /// handle any system signal sent to the application
    void handleSignal(int signum);
    void update(FbTk::Subject *changed);

    void attachSignals(FluxboxWindow &win);
    void attachSignals(WinClient &winclient);

    void timed_reconfigure();

    bool isStartup() const { return m_starting; }

    typedef std::vector<Fluxbox::Titlebar> TitlebarList;
    /// @return whether the timestamps on the menu changed
    bool menuTimestampsChanged() const;
    bool haveShape() const { return m_have_shape; }
    int shapeEventbase() const { return m_shape_eventbase; }
    void getDefaultDataFilename(char *, std::string &);
    // screen mouse was in at last key event
    BScreen *mouseScreen() { return m_mousescreen; }
    // screen of window that last key event (i.e. focused window) went to
    BScreen *keyScreen() { return m_keyscreen; }
    // screen we are watching for modifier changes
    BScreen *watchingScreen() { return m_watching_screen; }
    const XEvent &lastEvent() const { return m_last_event; }
private:

    typedef struct MenuTimestamp {
        std::string filename;
        time_t timestamp;
    } MenuTimestamp;

    std::string getRcFilename();
    void load_rc();

    void reload_rc();
    void real_rereadMenu();
    void real_reconfigure();

    void handleEvent(XEvent *xe);

    void setupConfigFiles();
    void handleButtonEvent(XButtonEvent &be);
    void handleUnmapNotify(XUnmapEvent &ue);
    void handleClientMessage(XClientMessageEvent &ce);
    void handleKeyEvent(XKeyEvent &ke);
    void setTitlebar(std::vector<Fluxbox::Titlebar>& dir, const char *arg);

    std::auto_ptr<FbAtoms> m_fbatoms;

    FbTk::ResourceManager m_resourcemanager, &m_screen_rm;

    //--- Resources

    FbTk::Resource<bool> m_rc_tabs, m_rc_ignoreborder;
    FbTk::Resource<int> m_rc_colors_per_channel, m_rc_numlayers,
        m_rc_double_click_interval, m_rc_update_delay_time;
    FbTk::Resource<std::string> m_rc_stylefile,
        m_rc_menufile, m_rc_keyfile, m_rc_slitlistfile,
        m_rc_groupfile;

    FbTk::Resource<TitlebarList> m_rc_titlebar_left, m_rc_titlebar_right;
    FbTk::Resource<unsigned int> m_rc_cache_life, m_rc_cache_max;
    FbTk::Resource<time_t> m_rc_auto_raise_delay;
    FbTk::Resource<bool> m_rc_use_mod1; /// temporary!, to disable mod1 for resize/move

    std::map<Window, WinClient *> m_window_search;
    std::map<Window, FluxboxWindow *> m_window_search_group;
    // A window is the group leader, which can map to several
    // WinClients in the group, it is *not* fluxbox's concept of groups
    // See ICCCM section 4.1.11
    // The group leader (which may not be mapped, so may not have a WinClient)
    // will have it's window being the group index
    std::multimap<Window, WinClient *> m_group_search;

    std::list<MenuTimestamp *> m_menu_timestamps;
    typedef std::list<BScreen *> ScreenList;
    ScreenList m_screen_list;

    WinClient *m_focused_window;
    FluxboxWindow *m_masked_window;

    BScreen *m_mousescreen, *m_keyscreen;
    BScreen *m_watching_screen;
    unsigned int m_watch_keyrelease;

    Atom m_fluxbox_pid;

    bool m_reconfigure_wait, m_reread_menu_wait;
    Time m_last_time;
    Window m_masked;
    std::string m_rc_file; ///< resource filename
    char **m_argv;
    int m_argc;
    XEvent m_last_event;

    FbTk::Timer m_reconfig_timer; ///< when we execute reconfig command we must wait at least to next event round

    std::auto_ptr<Keys> m_key;

    //default arguments for titlebar left and right
    static Fluxbox::Titlebar s_titlebar_left[], s_titlebar_right[];
    static Fluxbox *s_singleton;
    std::vector<AtomHandler *> m_atomhandler;
    std::vector<Toolbar *> m_toolbars;

    bool m_starting;
    bool m_shutdown;
    int m_server_grabs;
    int m_randr_event_type; ///< the type number of randr event
    int m_shape_eventbase; ///< event base for shape events
    bool m_have_shape; ///< if shape is supported by server
    const char *m_RC_PATH;
    const char *m_RC_INIT_FILE;
    Atom m_kwm1_dockwindow, m_kwm2_dockwindow;
};

#endif // FLUXBOX_HH
<|endoftext|>


<commit_before>/**
 * @file fsLogic.cc
 * @author Rafal Slota
 * @author Konrad Zemek
 * @copyright (C) 2013-2015 ACK CYFRONET AGH
 * @copyright This software is released under the MIT license cited in
 * 'LICENSE.txt'
 */

#include "fsLogic.h"

#include "context.h"
#include "events/eventManager.h"
#include "logging.h"
#include "messages/fuse/getFileAttr.h"
#include "messages/fuse/fileAttr.h"
#include "messages/fuse/createDir.h"
#include "messages/fuse/deleteFile.h"
#include "messages/fuse/fileChildren.h"
#include "messages/fuse/getFileChildren.h"
#include "messages/fuse/updateTimes.h"

#include <boost/algorithm/string.hpp>

using namespace std::literals;

namespace one {
namespace client {

FsLogic::FsLogic(std::shared_ptr<Context> context)
    : m_uid{geteuid()}
    , m_gid{getegid()}
    , m_context{std::move(context)}
    , m_eventManager{std::make_unique<events::EventManager>(m_context)}
{
}

int FsLogic::access(boost::filesystem::path path, const int mask)
{
    DLOG(INFO) << "FUSE: access(path: '" << path << "', mask: " << mask << ")";
    return 0;
}

int FsLogic::getattr(boost::filesystem::path path, struct stat *const statbuf)
{
    DLOG(INFO) << "FUSE: getattr(path: '" << path << ", ...)";

    auto attr = getAttr(path);
    statbuf->st_atime = std::chrono::system_clock::to_time_t(attr.atime());
    statbuf->st_mtime = std::chrono::system_clock::to_time_t(attr.mtime());
    statbuf->st_ctime = std::chrono::system_clock::to_time_t(attr.ctime());
    statbuf->st_gid = attr.gid();
    statbuf->st_uid = attr.uid();
    statbuf->st_mode = attr.mode();
    statbuf->st_size = attr.size();
    return 0;
}

int FsLogic::readlink(
    boost::filesystem::path path, boost::asio::mutable_buffer buf)
{
    DLOG(INFO) << "FUSE: readlink(path: '" << path
               << "', bufferSize: " << boost::asio::buffer_size(buf) << ")";

    throw std::errc::operation_not_supported;
}

int FsLogic::mknod(
    boost::filesystem::path path, const mode_t mode, const dev_t dev)
{
    DLOG(INFO) << "FUSE: mknod(path: '" << path << "', mode: " << mode
               << ", dev: " << dev << ")";

    throw std::errc::operation_not_supported;
}

int FsLogic::mkdir(boost::filesystem::path path, const mode_t mode)
{
    DLOG(INFO) << "FUSE: mkdir(path: '" << path << "', mode: " << mode << ")";

    auto parentAttr = getAttr(path.parent_path());
    if (parentAttr.type() != messages::fuse::FileAttr::FileType::directory)
        throw std::errc::not_a_directory;

    messages::fuse::CreateDir msg{
        parentAttr.uuid(), path.filename().string(), mode};

    auto future =
        m_context->communicator()->communicate<messages::fuse::FuseResponse>(
            msg);

    communication::wait(future);

    return 0;
}

int FsLogic::unlink(boost::filesystem::path path)
{
    DLOG(INFO) << "FUSE: unlink(path: '" << path << "')";
    removeFile(std::move(path));
    return 0;
}

int FsLogic::rmdir(boost::filesystem::path path)
{
    DLOG(INFO) << "FUSE: rmdir(path: '" << path << "')";
    removeFile(std::move(path));
    return 0;
}

int FsLogic::symlink(
    boost::filesystem::path target, boost::filesystem::path linkPath)
{
    DLOG(INFO) << "FUSE: symlink(target: " << target
               << ", linkPath: " << linkPath << ")";

    throw std::errc::operation_not_supported;
}

int FsLogic::rename(
    boost::filesystem::path oldPath, boost::filesystem::path newPath)
{
    DLOG(INFO) << "FUSE: rename(oldPath: '" << oldPath << "', newPath: '"
               << newPath << "')";

    throw std::errc::operation_not_supported;
}

int FsLogic::chmod(boost::filesystem::path path, const mode_t mode)
{
    DLOG(INFO) << "FUSE: chmod(path: '" << path << "', mode: " << mode << ")";
    throw std::errc::operation_not_supported;
}

int FsLogic::chown(
    boost::filesystem::path path, const uid_t uid, const gid_t gid)
{
    DLOG(INFO) << "FUSE: chown(path: '" << path << "', uid: " << uid
               << ", gid: " << gid << ")";

    throw std::errc::operation_not_supported;
}

int FsLogic::truncate(boost::filesystem::path path, const off_t newSize)
{
    DLOG(INFO) << "FUSE: truncate(path: '" << path << "', newSize: " << newSize
               << ")";

    //    m_eventManager->emitTruncateEvent(path.string(), newSize);
    throw std::errc::operation_not_supported;
}

int FsLogic::utime(boost::filesystem::path path, struct utimbuf *const ubuf)
{
    DLOG(INFO) << "FUSE: utime(path: '" << path << "', ...)";

    auto attr = getAttr(path);
    messages::fuse::UpdateTimes msg{attr.uuid()};

    if (!ubuf) {
        const auto now = std::chrono::system_clock::now();
        msg.atime(now);
        msg.mtime(now);
    }
    else {
        msg.atime(std::chrono::system_clock::from_time_t(ubuf->actime));
        msg.mtime(std::chrono::system_clock::from_time_t(ubuf->modtime));
    }

    auto future =
        m_context->communicator()->communicate<messages::fuse::FuseResponse>(
            msg);

    communication::wait(future);

    return 0;
}

int FsLogic::open(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: open(path: '" << path << "', ...)";
    throw std::errc::operation_not_supported;
}

int FsLogic::read(boost::filesystem::path path, boost::asio::mutable_buffer buf,
    const off_t offset, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: read(path: '" << path
               << "', bufferSize: " << boost::asio::buffer_size(buf)
               << ", offset: " << offset << ", ...)";

    //    m_eventManager->emitReadEvent(
    //        path.string(), offset, static_cast<size_t>(res));

    throw std::errc::operation_not_supported;
}

int FsLogic::write(boost::filesystem::path path, boost::asio::const_buffer buf,
    const off_t offset, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: write(path: '" << path
               << "', bufferSize: " << boost::asio::buffer_size(buf)
               << ", offset: " << offset << ", ...)";

    //    if (m_shMock->shGetattr(path.string(), &statbuf) == 0) {
    //        m_eventManager->emitWriteEvent(path.string(), offset,
    //            static_cast<size_t>(res),
    //            std::max(offset + res, statbuf.st_size));
    //    }
    //    else {
    //        m_eventManager->emitWriteEvent(
    //            path.string(), offset, static_cast<size_t>(res), offset +
    //            res);
    //    }

    throw std::errc::operation_not_supported;
}

int FsLogic::statfs(
    boost::filesystem::path path, struct statvfs *const statInfo)
{
    DLOG(INFO) << "FUSE: statfs(path: '" << path << "', ...)";
    throw std::errc::operation_not_supported;
}

int FsLogic::flush(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: flush(path: '" << path << "', ...)";
    throw std::errc::operation_not_supported;
}

int FsLogic::release(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: release(path: '" << path << "', ...)";
    throw std::errc::operation_not_supported;
}

int FsLogic::fsync(boost::filesystem::path path, const int datasync,
    struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: fsync(path: '" << path << "', datasync: " << datasync
               << ", ...)";

    throw std::errc::operation_not_supported;
}

int FsLogic::opendir(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: opendir(path: '" << path << "', ...)";
    return 0;
}

int FsLogic::readdir(boost::filesystem::path path, void *const buf,
    const fuse_fill_dir_t filler, const off_t offset,
    struct fuse_file_info *const /*fileInfo*/)
{
    DLOG(INFO) << "FUSE: readdir(path: '" << path
               << "', ..., offset: " << offset << ", ...)";

    auto attr = getAttr(path);
    if (attr.type() != messages::fuse::FileAttr::FileType::directory)
        throw std::errc::not_a_directory;

    messages::fuse::GetFileChildren msg{attr.uuid(), offset, 1000};
    auto future =
        m_context->communicator()->communicate<messages::fuse::FileChildren>(
            msg);

    auto fileChildren = communication::wait(future);
    auto currentOffset = offset;

    for (const auto &uuidAndName : fileChildren.uuidsAndNames()) {
        auto name = std::get<1>(uuidAndName);
        auto childPath = path / name;
        m_uuidCache.insert({std::move(childPath), std::get<0>(uuidAndName)});

        if (filler(buf, name.c_str(), nullptr, ++currentOffset))
            break;
    }

    return 0;
}

int FsLogic::releasedir(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: releasedir(path: '" << path << "', ...)";
    return 0;
}

int FsLogic::fsyncdir(boost::filesystem::path path, const int datasync,
    struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: fsyncdir(path: '" << path
               << "', datasync: " << datasync << ", ...)";

    return 0;
}

void FsLogic::removeFile(boost::filesystem::path path)
{
    auto attr = getAttr(path);
    messages::fuse::DeleteFile msg{attr.uuid()};

    auto future =
        m_context->communicator()->communicate<messages::fuse::FuseResponse>(
            msg);

    communication::wait(future);

    m_uuidCache.erase(path);
    m_attrCache.erase(attr.uuid());
}

messages::fuse::FileAttr FsLogic::getAttr(const boost::filesystem::path &path)
{
    decltype(m_uuidCache)::const_accessor acc;
    if (m_uuidCache.find(acc, path)) {
        auto uuid = acc->second;
        acc.release();

        return getAttr(uuid);
    }

    return getAttr(messages::fuse::GetFileAttr{path});
}

messages::fuse::FileAttr FsLogic::getAttr(const std::string &uuid)
{
    decltype(m_attrCache)::const_accessor acc;
    if (m_attrCache.find(acc, uuid))
        return acc->second;

    return getAttr(messages::fuse::GetFileAttr{uuid});
}

messages::fuse::FileAttr FsLogic::getAttr(
    const messages::fuse::GetFileAttr &req)
{
    auto future =
        m_context->communicator()->communicate<messages::fuse::FileAttr>(req);

    auto attr = communication::wait(future);
    m_attrCache.insert({attr.uuid(), attr});

    return attr;
}

std::size_t FsLogic::PathHash::hash(const boost::filesystem::path &path)
{
    return std::hash<std::string>{}(path.string());
}

bool FsLogic::PathHash::equal(
    const boost::filesystem::path &a, const boost::filesystem::path &b)
{
    return a == b;
}

} // namespace client
} // namespace one
<commit_msg>VFS-1153 Set file type in getattr.<commit_after>/**
 * @file fsLogic.cc
 * @author Rafal Slota
 * @author Konrad Zemek
 * @copyright (C) 2013-2015 ACK CYFRONET AGH
 * @copyright This software is released under the MIT license cited in
 * 'LICENSE.txt'
 */

#include "fsLogic.h"

#include "context.h"
#include "events/eventManager.h"
#include "logging.h"
#include "messages/fuse/getFileAttr.h"
#include "messages/fuse/fileAttr.h"
#include "messages/fuse/createDir.h"
#include "messages/fuse/deleteFile.h"
#include "messages/fuse/fileChildren.h"
#include "messages/fuse/getFileChildren.h"
#include "messages/fuse/updateTimes.h"

#include <boost/algorithm/string.hpp>

using namespace std::literals;

namespace one {
namespace client {

FsLogic::FsLogic(std::shared_ptr<Context> context)
    : m_uid{geteuid()}
    , m_gid{getegid()}
    , m_context{std::move(context)}
    , m_eventManager{std::make_unique<events::EventManager>(m_context)}
{
}

int FsLogic::access(boost::filesystem::path path, const int mask)
{
    DLOG(INFO) << "FUSE: access(path: '" << path << "', mask: " << mask << ")";
    return 0;
}

int FsLogic::getattr(boost::filesystem::path path, struct stat *const statbuf)
{
    DLOG(INFO) << "FUSE: getattr(path: '" << path << ", ...)";

    auto attr = getAttr(path);
    statbuf->st_atime = std::chrono::system_clock::to_time_t(attr.atime());
    statbuf->st_mtime = std::chrono::system_clock::to_time_t(attr.mtime());
    statbuf->st_ctime = std::chrono::system_clock::to_time_t(attr.ctime());
    statbuf->st_gid = attr.gid();
    statbuf->st_uid = attr.uid();
    statbuf->st_mode = attr.mode();
    statbuf->st_size = attr.size();
    statbuf->st_nlink = 1;
    statbuf->st_blocks = 0;

    switch (attr.type()) {
        case messages::fuse::FileAttr::FileType::directory:
            statbuf->st_mode |= S_IFDIR;
            break;
        case messages::fuse::FileAttr::FileType::link:
            statbuf->st_mode |= S_IFLNK;
            break;
        case messages::fuse::FileAttr::FileType::regular:
            statbuf->st_mode |= S_IFREG;
            break;
    }

    return 0;
}

int FsLogic::readlink(
    boost::filesystem::path path, boost::asio::mutable_buffer buf)
{
    DLOG(INFO) << "FUSE: readlink(path: '" << path
               << "', bufferSize: " << boost::asio::buffer_size(buf) << ")";

    throw std::errc::operation_not_supported;
}

int FsLogic::mknod(
    boost::filesystem::path path, const mode_t mode, const dev_t dev)
{
    DLOG(INFO) << "FUSE: mknod(path: '" << path << "', mode: " << mode
               << ", dev: " << dev << ")";

    throw std::errc::operation_not_supported;
}

int FsLogic::mkdir(boost::filesystem::path path, const mode_t mode)
{
    DLOG(INFO) << "FUSE: mkdir(path: '" << path << "', mode: " << mode << ")";

    auto parentAttr = getAttr(path.parent_path());
    if (parentAttr.type() != messages::fuse::FileAttr::FileType::directory)
        throw std::errc::not_a_directory;

    messages::fuse::CreateDir msg{
        parentAttr.uuid(), path.filename().string(), mode};

    auto future =
        m_context->communicator()->communicate<messages::fuse::FuseResponse>(
            msg);

    communication::wait(future);

    return 0;
}

int FsLogic::unlink(boost::filesystem::path path)
{
    DLOG(INFO) << "FUSE: unlink(path: '" << path << "')";
    removeFile(std::move(path));
    return 0;
}

int FsLogic::rmdir(boost::filesystem::path path)
{
    DLOG(INFO) << "FUSE: rmdir(path: '" << path << "')";
    removeFile(std::move(path));
    return 0;
}

int FsLogic::symlink(
    boost::filesystem::path target, boost::filesystem::path linkPath)
{
    DLOG(INFO) << "FUSE: symlink(target: " << target
               << ", linkPath: " << linkPath << ")";

    throw std::errc::operation_not_supported;
}

int FsLogic::rename(
    boost::filesystem::path oldPath, boost::filesystem::path newPath)
{
    DLOG(INFO) << "FUSE: rename(oldPath: '" << oldPath << "', newPath: '"
               << newPath << "')";

    throw std::errc::operation_not_supported;
}

int FsLogic::chmod(boost::filesystem::path path, const mode_t mode)
{
    DLOG(INFO) << "FUSE: chmod(path: '" << path << "', mode: " << mode << ")";
    throw std::errc::operation_not_supported;
}

int FsLogic::chown(
    boost::filesystem::path path, const uid_t uid, const gid_t gid)
{
    DLOG(INFO) << "FUSE: chown(path: '" << path << "', uid: " << uid
               << ", gid: " << gid << ")";

    throw std::errc::operation_not_supported;
}

int FsLogic::truncate(boost::filesystem::path path, const off_t newSize)
{
    DLOG(INFO) << "FUSE: truncate(path: '" << path << "', newSize: " << newSize
               << ")";

    //    m_eventManager->emitTruncateEvent(path.string(), newSize);
    throw std::errc::operation_not_supported;
}

int FsLogic::utime(boost::filesystem::path path, struct utimbuf *const ubuf)
{
    DLOG(INFO) << "FUSE: utime(path: '" << path << "', ...)";

    auto attr = getAttr(path);
    messages::fuse::UpdateTimes msg{attr.uuid()};

    if (!ubuf) {
        const auto now = std::chrono::system_clock::now();
        msg.atime(now);
        msg.mtime(now);
    }
    else {
        msg.atime(std::chrono::system_clock::from_time_t(ubuf->actime));
        msg.mtime(std::chrono::system_clock::from_time_t(ubuf->modtime));
    }

    auto future =
        m_context->communicator()->communicate<messages::fuse::FuseResponse>(
            msg);

    communication::wait(future);

    return 0;
}

int FsLogic::open(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: open(path: '" << path << "', ...)";
    throw std::errc::operation_not_supported;
}

int FsLogic::read(boost::filesystem::path path, boost::asio::mutable_buffer buf,
    const off_t offset, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: read(path: '" << path
               << "', bufferSize: " << boost::asio::buffer_size(buf)
               << ", offset: " << offset << ", ...)";

    //    m_eventManager->emitReadEvent(
    //        path.string(), offset, static_cast<size_t>(res));

    throw std::errc::operation_not_supported;
}

int FsLogic::write(boost::filesystem::path path, boost::asio::const_buffer buf,
    const off_t offset, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: write(path: '" << path
               << "', bufferSize: " << boost::asio::buffer_size(buf)
               << ", offset: " << offset << ", ...)";

    //    if (m_shMock->shGetattr(path.string(), &statbuf) == 0) {
    //        m_eventManager->emitWriteEvent(path.string(), offset,
    //            static_cast<size_t>(res),
    //            std::max(offset + res, statbuf.st_size));
    //    }
    //    else {
    //        m_eventManager->emitWriteEvent(
    //            path.string(), offset, static_cast<size_t>(res), offset +
    //            res);
    //    }

    throw std::errc::operation_not_supported;
}

int FsLogic::statfs(
    boost::filesystem::path path, struct statvfs *const statInfo)
{
    DLOG(INFO) << "FUSE: statfs(path: '" << path << "', ...)";
    throw std::errc::operation_not_supported;
}

int FsLogic::flush(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: flush(path: '" << path << "', ...)";
    throw std::errc::operation_not_supported;
}

int FsLogic::release(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: release(path: '" << path << "', ...)";
    throw std::errc::operation_not_supported;
}

int FsLogic::fsync(boost::filesystem::path path, const int datasync,
    struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: fsync(path: '" << path << "', datasync: " << datasync
               << ", ...)";

    throw std::errc::operation_not_supported;
}

int FsLogic::opendir(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: opendir(path: '" << path << "', ...)";
    return 0;
}

int FsLogic::readdir(boost::filesystem::path path, void *const buf,
    const fuse_fill_dir_t filler, const off_t offset,
    struct fuse_file_info *const /*fileInfo*/)
{
    DLOG(INFO) << "FUSE: readdir(path: '" << path
               << "', ..., offset: " << offset << ", ...)";

    auto attr = getAttr(path);
    if (attr.type() != messages::fuse::FileAttr::FileType::directory)
        throw std::errc::not_a_directory;

    messages::fuse::GetFileChildren msg{attr.uuid(), offset, 1000};
    auto future =
        m_context->communicator()->communicate<messages::fuse::FileChildren>(
            msg);

    auto fileChildren = communication::wait(future);
    auto currentOffset = offset;

    for (const auto &uuidAndName : fileChildren.uuidsAndNames()) {
        auto name = std::get<1>(uuidAndName);
        auto childPath = path / name;
        m_uuidCache.insert({std::move(childPath), std::get<0>(uuidAndName)});

        if (filler(buf, name.c_str(), nullptr, ++currentOffset))
            break;
    }

    return 0;
}

int FsLogic::releasedir(
    boost::filesystem::path path, struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: releasedir(path: '" << path << "', ...)";
    return 0;
}

int FsLogic::fsyncdir(boost::filesystem::path path, const int datasync,
    struct fuse_file_info *const fileInfo)
{
    DLOG(INFO) << "FUSE: fsyncdir(path: '" << path
               << "', datasync: " << datasync << ", ...)";

    return 0;
}

void FsLogic::removeFile(boost::filesystem::path path)
{
    auto attr = getAttr(path);
    messages::fuse::DeleteFile msg{attr.uuid()};

    auto future =
        m_context->communicator()->communicate<messages::fuse::FuseResponse>(
            msg);

    communication::wait(future);

    m_uuidCache.erase(path);
    m_attrCache.erase(attr.uuid());
}

messages::fuse::FileAttr FsLogic::getAttr(const boost::filesystem::path &path)
{
    decltype(m_uuidCache)::const_accessor acc;
    if (m_uuidCache.find(acc, path)) {
        auto uuid = acc->second;
        acc.release();

        return getAttr(uuid);
    }

    return getAttr(messages::fuse::GetFileAttr{path});
}

messages::fuse::FileAttr FsLogic::getAttr(const std::string &uuid)
{
    decltype(m_attrCache)::const_accessor acc;
    if (m_attrCache.find(acc, uuid))
        return acc->second;

    return getAttr(messages::fuse::GetFileAttr{uuid});
}

messages::fuse::FileAttr FsLogic::getAttr(
    const messages::fuse::GetFileAttr &req)
{
    auto future =
        m_context->communicator()->communicate<messages::fuse::FileAttr>(req);

    auto attr = communication::wait(future);
    m_attrCache.insert({attr.uuid(), attr});

    return attr;
}

std::size_t FsLogic::PathHash::hash(const boost::filesystem::path &path)
{
    return std::hash<std::string>{}(path.string());
}

bool FsLogic::PathHash::equal(
    const boost::filesystem::path &a, const boost::filesystem::path &b)
{
    return a == b;
}

} // namespace client
} // namespace one
<|endoftext|>


<commit_before>#include <cstdlib>

#include <iostream>
#include <sstream>
#include <fstream>
#include <openssl/md5.h>

#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include <pHash.h>

#include "imagedb.h"
#include "common.h"

using namespace std;
namespace fs = boost::filesystem;

void ImageDB::addImages(const string& imagepath) const
{
    if(!fs::is_directory(imagepath))
    {
        cerr <<"Invalid imagepath '"<<imagepath<<"' specified." <<endl;
        return;
    }

    fs::recursive_directory_iterator  endIter;
    for(fs::recursive_directory_iterator itr(imagepath); itr !=endIter; ++itr)
    {
        ostringstream cmd;
        if(fs::is_regular_file(itr->path()))
        {
            cmd << "curl -XPOST --data-binary @" <<itr->path().string() <<" http://localhost:8080/ &";
            cout << cmd.str() <<endl;
            system(cmd.str().c_str());
        }
    }
}

void ImageDB::_updateIndicies(const Image& image)
{

}

Result ImageDB::getImage(const unsigned char* data, unsigned int size, bool add)
{
    Image image;
    MD5(data, size, image.md5);

    ofstream ofs;
    fs::path path = fs::unique_path("/tmp/%%%%%%-%%%%.jpg");
    ofs.open(path.string().c_str());
    /*char d[128];
    memcpy(d, data, 127);
    d[127]='\0';
    cout <<"\""<<d<<"\""<<endl;*/
    ofs.write((const char*)data, size);
    ofs.close();
    ph_dct_imagehash(path.string().c_str(), image.phash);

    cout <<"Image size "<< size <<endl;
    fs::remove(path);
    return PRESENT;
}

<commit_msg>move tmp file generation<commit_after>#include <cstdlib>

#include <iostream>
#include <sstream>
#include <fstream>
#include <openssl/md5.h>

#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include <pHash.h>

#include "imagedb.h"
#include "common.h"

using namespace std;
namespace fs = boost::filesystem;

void ImageDB::addImages(const string& imagepath) const
{
    if(!fs::is_directory(imagepath))
    {
        cerr <<"Invalid imagepath '"<<imagepath<<"' specified." <<endl;
        return;
    }

    fs::recursive_directory_iterator  endIter;
    for(fs::recursive_directory_iterator itr(imagepath); itr !=endIter; ++itr)
    {
        ostringstream cmd;
        if(fs::is_regular_file(itr->path()))
        {
            cmd << "curl -XPOST --data-binary @" <<itr->path().string() <<" http://localhost:8080/ &";
            system(cmd.str().c_str());
        }
    }
}

void ImageDB::_updateIndicies(const Image& image)
{

}

Result ImageDB::getImage(const unsigned char* data, unsigned int size, bool add)
{
    Image image;
    MD5(data, size, image.md5);

    ofstream ofs;
    fs::path path = fs::unique_path("/tmp/%%%%%%-%%%%");
    ofs.open(path.string().c_str());
    ofs.write((const char*)data, size);
    ofs.close();
    ph_dct_imagehash(path.string().c_str(), image.phash);

    cout <<"Image size:"<< size << " md5:"<< image.md5 << " phash:" << image.phash << endl;
    fs::remove(path);
    return PRESENT;
}

<|endoftext|>


<commit_before>#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "model.h"
#include "camera.h"
#include "kernel.h"
#include "string.h"

Kernel::Kernel(int argc, char** argv)
{
	/* open and read config file */
	char option[255];
	char value[255];
	FILE *config_file;
	config_file = fopen(CONFIG_PATH, "r");
	if (config_file != NULL)
	{
		while(fscanf(config_file, "%s %s", option, value) != EOF)
		{
			if (!strcmp(option, "height"))
			{
				height = atof(value);
			}
			if (!strcmp(option, "width"))
			{
				width = atof(value);
			}
		}
		fclose(config_file);
	}
	else
	{
		printf("Warning: no config file found\n");
	}
	/* parse command line arguments */
	static const char *optString = "m:h:w:";
	int opt = 0;
	opt = getopt(argc, argv, optString);
	while(opt != -1)
	{
		switch(opt) {
			case 'm':
				map_name = optarg;
				break;
			case 'h':
				height = atoi(optarg);
				break;
			case 'w':
				width = atoi(optarg);
				break;
		}
		opt = getopt(argc, argv, optString);
	}
	/* write config to config file */
//	FILE *config_file;
	config_file = fopen(CONFIG_PATH, "w");
	if (config_file != NULL)
	{
		fprintf(config_file, "%s %f\n", "width", width);
		fprintf(config_file, "%s %f\n", "height", height);
		fclose(config_file);
		printf("Config saved\n");
	}
	else
	{
		printf("Warning: can not save config\n");
	}
	printf("Resolution set to %fx%f\n", width, height);
	printf("Loading map %s\n", map_name);
};
<commit_msg>small fixes<commit_after>#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "model.h"
#include "camera.h"
#include "kernel.h"
#include "string.h"

Kernel::Kernel(int argc, char** argv)
{
	/* default config */
	height = DEF_HEIGHT;
	width = DEF_WIDTH;
	/* open and read config file */
	char option[255];
	char value[255];
	FILE *config_file;
	config_file = fopen(CONFIG_PATH, "r");
	if (config_file != NULL)
	{
		while(fscanf(config_file, "%s %s", option, value) != EOF)
		{
			if (!strcmp(option, "height"))
			{
				height = atof(value);
			}
			if (!strcmp(option, "width"))
			{
				width = atof(value);
			}
		}
		fclose(config_file);
	}
	else
	{
		printf("Warning: no config file found\n");
	}
	/* parse command line arguments */
	static const char *optString = "m:h:w:";
	int opt = 0;
	opt = getopt(argc, argv, optString);
	while(opt != -1)
	{
		switch(opt) {
			case 'm':
				map_name = optarg;
				break;
			case 'h':
				height = atof(optarg);
				break;
			case 'w':
				width = atof(optarg);
				break;
		}
		opt = getopt(argc, argv, optString);
	}
	/* write config to config file */
//	FILE *config_file;
	config_file = fopen(CONFIG_PATH, "w");
	if (config_file != NULL)
	{
		fprintf(config_file, "%s %f\n", "width", width);
		fprintf(config_file, "%s %f\n", "height", height);
		fclose(config_file);
		printf("Config saved\n");
	}
	else
	{
		printf("Warning: can not save config\n");
	}
	printf("Resolution set to %fx%f\n", width, height);
	printf("Loading map %s\n", map_name);
};
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
// HIMG, by Marcus Geelnard, 2015
//
// This is free and unencumbered software released into the public domain.
//
// See LICENSE for details.
//-----------------------------------------------------------------------------

#include "mapper.h"

#include <algorithm>

namespace himg {

namespace {

// This is a hand-tuned mapping table that seems to give good results.
const int16_t kLowResMappingTable[128] = {
  0, 1, 2, 3, 4, 5, 6, 7,
  8, 9, 10, 11, 12, 13, 14, 15,
  16, 17, 18, 19, 20, 21, 22, 23,
  24, 25, 26, 27, 28, 29, 30, 31,
  32, 33, 34, 35, 36, 37, 38, 39,
  40, 41, 42, 43, 44, 45, 46, 47,
  48, 49, 50, 51, 52, 53, 54, 55,
  56, 57, 58, 59, 60, 62, 63, 64,
  65, 67, 68, 70, 71, 73, 74, 76,
  78, 79, 81, 83, 85, 87, 89, 91,
  93, 95, 97, 99, 102, 104, 106, 109,
  111, 114, 117, 119, 122, 125, 128, 131,
  134, 137, 140, 143, 146, 150, 153, 156,
  160, 164, 167, 171, 175, 178, 182, 186,
  190, 195, 199, 203, 207, 212, 216, 221,
  226, 230, 235, 240, 245, 250, 255, 999 // FIXME!
};

}  // namespace

void LowResMapper::InitForQuality(int quality) {
  // TODO(m): Use quality to control the mapping table.
  for (int i = 0; i < 128; ++i)
    m_mapping_table[i] = kLowResMappingTable[i];
}

int Mapper::MappingFunctionSize() const {
  // The mapping table requires one byte that tells how many items can be
  // represented with a single byte, plus the actual single- and double-byte
  // items.
  int single_byte_items = NumberOfSingleByteMappingItems();
  return 1 + single_byte_items + 2 * (128 - single_byte_items);
}

void Mapper::GetMappingFunction(uint8_t *out) const {
  // Store the mapping table.
  int single_byte_items = NumberOfSingleByteMappingItems();
  *out++ = static_cast<uint8_t>(single_byte_items);
  int i;
  for (i = 0; i < single_byte_items; ++i)
    *out++ = static_cast<uint8_t>(m_mapping_table[i]);
  for (; i < 128; ++i) {
    uint16_t x = m_mapping_table[i];
    *out++ = static_cast<uint8_t>(x & 255);
    *out++ = static_cast<uint8_t>(x >> 8);
  }
}

bool Mapper::SetMappingFunction(const uint8_t *in, int map_fun_size) {
  if (map_fun_size < 1)
    return false;

  // Restore the mapping table.
  int single_byte_items = static_cast<int>(*in++);
  int actual_size = 1 + single_byte_items + 2 * (128 - single_byte_items);
  if (actual_size != map_fun_size)
    return false;
  int i;
  for (i = 0; i < single_byte_items; ++i)
    m_mapping_table[i] = static_cast<uint16_t>(*in++);
  for (; i < 128; ++i) {
    m_mapping_table[i] =
        static_cast<uint16_t>(in[0]) | (static_cast<uint16_t>(in[1]) << 8);
    in += 2;
  }

  return true;
}

uint8_t Mapper::MapTo8Bit(int16_t x) const {
  if (!x)
    return 0;

  uint16_t abs_x = static_cast<uint16_t>(std::abs(x));

  // TODO(m): Use binary search instead of O(n) search.
  uint8_t mapped;
  for (mapped = 1; mapped < 127; ++mapped) {
    if (abs_x < m_mapping_table[mapped]) {
      if ((abs_x - m_mapping_table[mapped - 1]) <
          (m_mapping_table[mapped] - abs_x)) {
        --mapped;
      }
      break;
    }
  }

  return x >= 0 ? mapped : static_cast<uint8_t>(-static_cast<int8_t>(mapped));
}

int16_t Mapper::UnmapFrom8Bit(uint8_t x) const {
  if (!x)
    return 0;

  bool negative = (x & 128) != 0;
  if (negative) {
    x = static_cast<uint8_t>(-static_cast<int8_t>(x));
  }

  int16_t value = static_cast<int16_t>(m_mapping_table[x]);
  return negative ? -value : value;
}

int Mapper::NumberOfSingleByteMappingItems() const {
  int single_byte_items;
  for (single_byte_items = 0; single_byte_items < 128; ++single_byte_items) {
    if (m_mapping_table[single_byte_items] >= 256)
      break;
  }
  return single_byte_items;
}

}  // namespace himg
<commit_msg>First version of quality based DPCM of the low res image<commit_after>//-----------------------------------------------------------------------------
// HIMG, by Marcus Geelnard, 2015
//
// This is free and unencumbered software released into the public domain.
//
// See LICENSE for details.
//-----------------------------------------------------------------------------

#include "mapper.h"

#include <algorithm>
#include <utility>

namespace himg {

namespace {

// This is a hand-tuned mapping table that seems to give good results.
const int16_t kLowResMappingTable[128] = {
  0, 1, 2, 3, 4, 5, 6, 7,
  8, 9, 10, 11, 12, 13, 14, 15,
  16, 17, 18, 19, 20, 21, 22, 23,
  24, 25, 26, 27, 28, 29, 30, 31,
  32, 33, 34, 35, 36, 37, 38, 39,
  40, 41, 42, 43, 44, 45, 46, 47,
  48, 49, 50, 51, 52, 53, 54, 55,
  56, 57, 58, 59, 60, 62, 63, 64,
  65, 67, 68, 70, 71, 73, 74, 76,
  78, 79, 81, 83, 85, 87, 89, 91,
  93, 95, 97, 99, 102, 104, 106, 109,
  111, 114, 117, 119, 122, 125, 128, 131,
  134, 137, 140, 143, 146, 150, 153, 156,
  160, 164, 167, 171, 175, 178, 182, 186,
  190, 195, 199, 203, 207, 212, 216, 221,
  226, 230, 235, 240, 245, 250, 255, 999 // FIXME!
};

const std::pair<int, int> kLowResMapScaleTable[] = {
  {   0, 120 },
  {   5,  90 },
  {  10,  70 },
  {  20,  40 },
  {  30,  32 },
  {  40,  26 },
  {  50,  20 },
  { 100,  16 }
};

// Given a quality value in the range [0, 100], return an interpolated scaling
// factor.
int QualityToScale(int quality,
                   const std::pair<int, int> *table,
                   int table_size) {
  // Look up the quality level in the quality -> scaling factor LUT.
  int idx;
  for (idx = 0; idx < table_size - 1; ++idx) {
    if (table[idx + 1].first > quality)
      break;
  }
  if (idx >= table_size - 1)
    return table[table_size - 1].second;

  // Pick out the two closest table entries.
  int q1 = table[idx].first;
  int s1 = table[idx].second;
  int q2 = table[idx + 1].first;
  int s2 = table[idx + 1].second;

  // Perform linear interpolation between the two table entries.
  int q = quality;
  int denom = q2 - q1;
  return s1 + ((s2 - s1) * (q - q1) + (denom >> 1)) / denom;
}

}  // namespace

void LowResMapper::InitForQuality(int quality) {
  // Determine ramp factor based on the quality setting. The ramp factor is in
  // 1/16ths.
  int16_t index_scale = QualityToScale(quality,
                                       kLowResMapScaleTable,
                                       sizeof(kLowResMapScaleTable) /
                                          sizeof(kLowResMapScaleTable[0]));

  // Generate the mapping table based on the index scale.
  for (int16_t i = 0; i < 128; ++i) {
    int16_t index = (i * index_scale + 8) >> 4;
    index = std::min(index, int16_t(127));
    m_mapping_table[i] = kLowResMappingTable[index];
  }
}

int Mapper::MappingFunctionSize() const {
  // The mapping table requires one byte that tells how many items can be
  // represented with a single byte, plus the actual single- and double-byte
  // items.
  int single_byte_items = NumberOfSingleByteMappingItems();
  return 1 + single_byte_items + 2 * (128 - single_byte_items);
}

void Mapper::GetMappingFunction(uint8_t *out) const {
  // Store the mapping table.
  int single_byte_items = NumberOfSingleByteMappingItems();
  *out++ = static_cast<uint8_t>(single_byte_items);
  int i;
  for (i = 0; i < single_byte_items; ++i)
    *out++ = static_cast<uint8_t>(m_mapping_table[i]);
  for (; i < 128; ++i) {
    uint16_t x = m_mapping_table[i];
    *out++ = static_cast<uint8_t>(x & 255);
    *out++ = static_cast<uint8_t>(x >> 8);
  }
}

bool Mapper::SetMappingFunction(const uint8_t *in, int map_fun_size) {
  if (map_fun_size < 1)
    return false;

  // Restore the mapping table.
  int single_byte_items = static_cast<int>(*in++);
  int actual_size = 1 + single_byte_items + 2 * (128 - single_byte_items);
  if (actual_size != map_fun_size)
    return false;
  int i;
  for (i = 0; i < single_byte_items; ++i)
    m_mapping_table[i] = static_cast<uint16_t>(*in++);
  for (; i < 128; ++i) {
    m_mapping_table[i] =
        static_cast<uint16_t>(in[0]) | (static_cast<uint16_t>(in[1]) << 8);
    in += 2;
  }

  return true;
}

uint8_t Mapper::MapTo8Bit(int16_t x) const {
  if (!x)
    return 0;

  uint16_t abs_x = static_cast<uint16_t>(std::abs(x));

  // TODO(m): Use binary search instead of O(n) search.
  uint8_t mapped;
  for (mapped = 1; mapped < 127; ++mapped) {
    if (abs_x < m_mapping_table[mapped]) {
      if ((abs_x - m_mapping_table[mapped - 1]) <
          (m_mapping_table[mapped] - abs_x)) {
        --mapped;
      }
      break;
    }
  }

  return x >= 0 ? mapped : static_cast<uint8_t>(-static_cast<int8_t>(mapped));
}

int16_t Mapper::UnmapFrom8Bit(uint8_t x) const {
  if (!x)
    return 0;

  bool negative = (x & 128) != 0;
  if (negative) {
    x = static_cast<uint8_t>(-static_cast<int8_t>(x));
  }

  int16_t value = static_cast<int16_t>(m_mapping_table[x]);
  return negative ? -value : value;
}

int Mapper::NumberOfSingleByteMappingItems() const {
  int single_byte_items;
  for (single_byte_items = 0; single_byte_items < 128; ++single_byte_items) {
    if (m_mapping_table[single_byte_items] >= 256)
      break;
  }
  return single_byte_items;
}

}  // namespace himg
<|endoftext|>