<commit_before>#include "gl/texture.h"

#include "gl/glError.h"
#include "gl/renderState.h"
#include "gl/hardware.h"
#include "log.h"
#include "map.h"
#include "platform.h"
#include "util/geom.h"

#include "stb_image.h"

#include <cassert>
#include <cstring> // for memset

namespace Tangram {

Texture::Texture(TextureOptions _options) : m_options(_options) {}

Texture::Texture(const uint8_t* data, size_t length, TextureOptions options)
    : Texture(options) {
    loadImageFromMemory(data, length);
}

Texture::~Texture() {
    freeBufferData();

    if (m_rs) {
        m_rs->queueTextureDeletion(m_glHandle);
    }
}

bool Texture::loadImageFromMemory(const uint8_t* data, size_t length) {
    freeBufferData();

    // stbi_load_from_memory loads the image as a series of scanlines starting
    // from the top-left corner of the image. This flips the output such that
    // the data begins at the bottom-left corner, as required for our OpenGL
    // texture coordinates.
    stbi_set_flip_vertically_on_load(true);

    int width = 0, height = 0;
    int channelsInFile = 0;
    int channelsRequested = bpp();

    m_buffer = stbi_load_from_memory(data, static_cast<int>(length),
                                     &width, &height, &channelsInFile,
                                     channelsRequested);

    if (!m_buffer) {
        LOGE("Could not load image data: %dx%d bpp:%d/%d",
             m_width, m_height, channelsInFile, channelsRequested);

        // Default inconsistent texture data is set to a 1*1 pixel texture
        // This reduces inconsistent behavior when texture failed loading
        // texture data but a Tangram style shader requires a shader sampler
        GLubyte pixel[4] = { 0, 0, 0, 255 };
        setPixelData(1, 1, bpp(), pixel, bpp());
        return false;
    }
    resize(width, height);
    return true;
}

bool Texture::setPixelData(int _width, int _height, int _bytesPerPixel,
                           const GLubyte* _data, size_t _length) {

    if (!sanityCheck(_width, _height, _bytesPerPixel, _length)) {
        return false;
    }

    if (m_bufferSize != _length) {
        freeBufferData();
    }

    if (!m_buffer) {
        m_buffer = reinterpret_cast<GLubyte*>(std::malloc(_length));
    }

    if (!m_buffer) {
        LOGE("Could not allocate texture: Out of memory!");
        return false;
    }

    std::memcpy(m_buffer, _data, _length);

    m_bufferSize = _length;

    resize(_width, _height);

    return true;
}

void Texture::setSpriteAtlas(std::unique_ptr<Tangram::SpriteAtlas> sprites) {
    m_spriteAtlas = std::move(sprites);
}

void Texture::generate(RenderState& _rs, GLuint _textureUnit) {
    GL::genTextures(1, &m_glHandle);

    _rs.texture(m_glHandle, _textureUnit, GL_TEXTURE_2D);

    GL::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                      static_cast<GLint>(m_options.minFilter));
    GL::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                      static_cast<GLint>(m_options.magFilter));

    GL::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
                      static_cast<GLint>(m_options.wrapS));
    GL::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
                      static_cast<GLint>(m_options.wrapT));

    m_rs = &_rs;
}

bool Texture::isValid() const {
    return (m_glHandle != 0) || bool(m_buffer);
}

bool Texture::upload(RenderState& _rs, GLuint _textureUnit) {
    m_shouldResize = false;

    if (Hardware::maxTextureSize < m_width ||
        Hardware::maxTextureSize < m_height) {
        LOGW("Texture larger than Hardware maximum texture size");
        if (m_disposeBuffer) { freeBufferData(); }
        return false;
    }
    if (m_glHandle == 0) {
        generate(_rs, _textureUnit);
    } else {
        _rs.texture(m_glHandle, _textureUnit, GL_TEXTURE_2D);
    }

    auto format = static_cast<GLenum>(m_options.pixelFormat);
    GL::texImage2D(GL_TEXTURE_2D, 0, format, m_width, m_height, 0, format,
                   GL_UNSIGNED_BYTE, m_buffer);

    if (m_buffer && m_options.generateMipmaps) {
        GL::generateMipmap(GL_TEXTURE_2D);
    }
    return true;
}

bool Texture::bind(RenderState& _rs, GLuint _textureUnit) {

    if (!m_shouldResize) {
        if (m_glHandle == 0) { return false; }

        _rs.texture(m_glHandle, _textureUnit, GL_TEXTURE_2D);
        return true;
    }

    bool ok = upload(_rs, _textureUnit);

    if (m_disposeBuffer) { freeBufferData(); }

    return ok;
}

void Texture::resize(int width, int height) {
    assert(width >= 0);
    assert(height >= 0);
    m_width = width;
    m_height = height;

    if (!(Hardware::supportsTextureNPOT) &&
        !(isPowerOfTwo(m_width) && isPowerOfTwo(m_height)) &&
        (m_options.generateMipmaps || (m_options.wrapS == TextureWrap::REPEAT ||
                                       m_options.wrapT == TextureWrap::REPEAT))) {
        LOGW("OpenGL ES doesn't support texture repeat" \
             " wrapping for NPOT textures nor mipmap textures");
        LOGW("Falling back to LINEAR Filtering");
        m_options.minFilter =TextureMinFilter::LINEAR;
        m_options.magFilter = TextureMagFilter::LINEAR;
        m_options.generateMipmaps = false;
    }

    m_shouldResize = true;
}

size_t Texture::bpp() const {
    switch (m_options.pixelFormat) {
    case PixelFormat::ALPHA:
    case PixelFormat::LUMINANCE:
        return 1;
    case PixelFormat::LUMINANCE_ALPHA:
        return 2;
    case PixelFormat::RGB:
        return 3;
    default:
        return 4;
    }
}

bool Texture::sanityCheck(size_t _width, size_t _height, size_t _bytesPerPixel,
                          size_t _length) const {
    size_t dim = _width * _height;
    if (_length != dim * bpp()) {
        LOGW("Invalid data size for Texture dimension! %dx%d bpp:%d bytes:%d",
             _width, _height, _bytesPerPixel, _length);
        return false;
    }
    if (bpp() != _bytesPerPixel) {
        LOGW("PixelFormat and bytesPerPixel do not match! %d:%d",
             bpp(), _bytesPerPixel);
        return false;
    }
    return true;
}

}
<commit_msg>fixup stb_image m_buffersize<commit_after>#include "gl/texture.h"

#include "gl/glError.h"
#include "gl/renderState.h"
#include "gl/hardware.h"
#include "log.h"
#include "map.h"
#include "platform.h"
#include "util/geom.h"

#include "stb_image.h"

#include <cassert>
#include <cstring> // for memset

namespace Tangram {

Texture::Texture(TextureOptions _options) : m_options(_options) {}

Texture::Texture(const uint8_t* data, size_t length, TextureOptions options)
    : Texture(options) {
    loadImageFromMemory(data, length);
}

Texture::~Texture() {
    freeBufferData();

    if (m_rs) {
        m_rs->queueTextureDeletion(m_glHandle);
    }
}

bool Texture::loadImageFromMemory(const uint8_t* data, size_t length) {
    freeBufferData();

    // stbi_load_from_memory loads the image as a series of scanlines starting
    // from the top-left corner of the image. This flips the output such that
    // the data begins at the bottom-left corner, as required for our OpenGL
    // texture coordinates.
    stbi_set_flip_vertically_on_load(true);

    int width = 0, height = 0;
    int channelsInFile = 0;
    int channelsRequested = bpp();

    m_buffer = stbi_load_from_memory(data, static_cast<int>(length),
                                     &width, &height, &channelsInFile,
                                     channelsRequested);

    if (!m_buffer) {
        LOGE("Could not load image data: %dx%d bpp:%d/%d",
             m_width, m_height, channelsInFile, channelsRequested);

        // Default inconsistent texture data is set to a 1*1 pixel texture
        // This reduces inconsistent behavior when texture failed loading
        // texture data but a Tangram style shader requires a shader sampler
        GLubyte pixel[4] = { 0, 0, 0, 255 };
        setPixelData(1, 1, bpp(), pixel, bpp());
        return false;
    }
    m_bufferSize = width * height * bpp();

    resize(width, height);
    return true;
}

bool Texture::setPixelData(int _width, int _height, int _bytesPerPixel,
                           const GLubyte* _data, size_t _length) {

    if (!sanityCheck(_width, _height, _bytesPerPixel, _length)) {
        return false;
    }

    if (m_bufferSize != _length) {
        freeBufferData();
    }

    if (!m_buffer) {
        m_buffer = reinterpret_cast<GLubyte*>(std::malloc(_length));
    }

    if (!m_buffer) {
        LOGE("Could not allocate texture: Out of memory!");
        return false;
    }

    std::memcpy(m_buffer, _data, _length);

    m_bufferSize = _length;

    resize(_width, _height);

    return true;
}

void Texture::setSpriteAtlas(std::unique_ptr<Tangram::SpriteAtlas> sprites) {
    m_spriteAtlas = std::move(sprites);
}

void Texture::generate(RenderState& _rs, GLuint _textureUnit) {
    GL::genTextures(1, &m_glHandle);

    _rs.texture(m_glHandle, _textureUnit, GL_TEXTURE_2D);

    GL::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                      static_cast<GLint>(m_options.minFilter));
    GL::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                      static_cast<GLint>(m_options.magFilter));

    GL::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
                      static_cast<GLint>(m_options.wrapS));
    GL::texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
                      static_cast<GLint>(m_options.wrapT));

    m_rs = &_rs;
}

bool Texture::isValid() const {
    return (m_glHandle != 0) || bool(m_buffer);
}

bool Texture::upload(RenderState& _rs, GLuint _textureUnit) {
    m_shouldResize = false;

    if (Hardware::maxTextureSize < m_width ||
        Hardware::maxTextureSize < m_height) {
        LOGW("Texture larger than Hardware maximum texture size");
        if (m_disposeBuffer) { freeBufferData(); }
        return false;
    }
    if (m_glHandle == 0) {
        generate(_rs, _textureUnit);
    } else {
        _rs.texture(m_glHandle, _textureUnit, GL_TEXTURE_2D);
    }

    auto format = static_cast<GLenum>(m_options.pixelFormat);
    GL::texImage2D(GL_TEXTURE_2D, 0, format, m_width, m_height, 0, format,
                   GL_UNSIGNED_BYTE, m_buffer);

    if (m_buffer && m_options.generateMipmaps) {
        GL::generateMipmap(GL_TEXTURE_2D);
    }
    return true;
}

bool Texture::bind(RenderState& _rs, GLuint _textureUnit) {

    if (!m_shouldResize) {
        if (m_glHandle == 0) { return false; }

        _rs.texture(m_glHandle, _textureUnit, GL_TEXTURE_2D);
        return true;
    }

    bool ok = upload(_rs, _textureUnit);

    if (m_disposeBuffer) { freeBufferData(); }

    return ok;
}

void Texture::resize(int width, int height) {
    assert(width >= 0);
    assert(height >= 0);
    m_width = width;
    m_height = height;

    if (!(Hardware::supportsTextureNPOT) &&
        !(isPowerOfTwo(m_width) && isPowerOfTwo(m_height)) &&
        (m_options.generateMipmaps || (m_options.wrapS == TextureWrap::REPEAT ||
                                       m_options.wrapT == TextureWrap::REPEAT))) {
        LOGW("OpenGL ES doesn't support texture repeat" \
             " wrapping for NPOT textures nor mipmap textures");
        LOGW("Falling back to LINEAR Filtering");
        m_options.minFilter =TextureMinFilter::LINEAR;
        m_options.magFilter = TextureMagFilter::LINEAR;
        m_options.generateMipmaps = false;
    }

    m_shouldResize = true;
}

size_t Texture::bpp() const {
    switch (m_options.pixelFormat) {
    case PixelFormat::ALPHA:
    case PixelFormat::LUMINANCE:
        return 1;
    case PixelFormat::LUMINANCE_ALPHA:
        return 2;
    case PixelFormat::RGB:
        return 3;
    default:
        return 4;
    }
}

bool Texture::sanityCheck(size_t _width, size_t _height, size_t _bytesPerPixel,
                          size_t _length) const {
    size_t dim = _width * _height;
    if (_length != dim * bpp()) {
        LOGW("Invalid data size for Texture dimension! %dx%d bpp:%d bytes:%d",
             _width, _height, _bytesPerPixel, _length);
        return false;
    }
    if (bpp() != _bytesPerPixel) {
        LOGW("PixelFormat and bytesPerPixel do not match! %d:%d",
             bpp(), _bytesPerPixel);
        return false;
    }
    return true;
}

}
<|endoftext|>


<commit_before>/**
 *  TEM.cpp
 *  main program for running DVM-DOS-TEM
 *
 *  It runs at 3 run-mods:
 *      (1) site-specific
 *      (2) regional - time series
 * 		(3) regional - spatially (not yet available)
 *
 * Authors: Shuhua Yi - the original codes
 * 		    Fengming Yuan - re-designing and re-coding for (1) easily code managing;
 *                                        (2) java interface developing for calibration;
 *                                        (3) stand-alone application of TEM (java-c++)
 *                                        (4) inputs/outputs using netcdf format, have to be modified
 *                                        to fix memory-leaks
 *                                        (5) fix the snow/soil thermal/hydraulic algorithms
 *                                        (6) DVM coupled
 * 			Tobey Carman - modifications and maintenance
 *            1) update application entry point with boost command line arg. handling.
 *
 * Affilation: Spatial Ecology Lab, University of Alaska Fairbanks
 *
 * started: 11/01/2010
 * last modified: 09/18/2012
*/

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <ctime>
#include <cstdlib>
#include <exception>
#include <map>
#include <set>

#include <boost/filesystem.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>

#include "ArgHandler.h"
#include "TEMLogger.h"
#include "assembler/Runner.h"

ArgHandler* args = new ArgHandler();

int main(int argc, char* argv[]){
extern src::severity_logger< severity_level > glg;

  args->parse(argc, argv);
	if (args->getHelp()){
		args->showHelp();
		return 0;
	}
  args->verify();

  std::cout << "Setting up logging...\n";

  setup_logging(args->getLogLevel());

  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);

  if (args->getMode() == "siterun") {
    time_t stime;
    time_t etime;
    stime=time(0);
    BOOST_LOG_SEV(glg, note) << "Running dvm-dos-tem in siterun mode. Start @ "
                             << ctime(&stime);

    string controlfile = args->getCtrlfile();
    string chtid = args->getChtid();

    Runner siter;

    // Not working yet. Need to figure out if it is even possible to
    // control modules from the command line? and if so how this should working
    // in all the different run stages.
    //siter.modeldata_module_settings_from_args(*args);

    if (args->getCalibrationMode() == "on") {
      BOOST_LOG_SEV(glg, note) << "Turning CalibrationMode on in Runner (siter).";
      siter.set_calibrationMode(true);

      boost::filesystem::path tmp_json_folder("/tmp/cal-dvmdostem/");
      if( !(boost::filesystem::exists(tmp_json_folder)) ) {
        BOOST_LOG_SEV(glg, info) << "Creating folder: " << tmp_json_folder;
        boost::filesystem::create_directory(tmp_json_folder);
      } else {
        BOOST_LOG_SEV(glg, info) << "Calibraiton json folder already exists. ("
                                 << tmp_json_folder << ")";
        BOOST_LOG_SEV(glg, info) << "Deleting any exisiting calibration json data.";
        boost::filesystem::remove_all(tmp_json_folder);
        boost::filesystem::create_directory(tmp_json_folder);
      }

    } else {
      BOOST_LOG_SEV(glg, note) << "Running in extrapolation mode.";
    }

    siter.chtid = atoi(chtid.c_str());

    siter.initInput(controlfile, "siter");

    siter.initOutput();

    siter.setupData();

    siter.setupIDs();

    siter.runmode1();

    etime=time(0);

  } else if (args->getMode() == "regnrun") {

    time_t stime;
    time_t etime;
    stime=time(0);
    BOOST_LOG_SEV(glg, note) << "Running dvm-dos-tem in regional mode. Start @ "
                              << ctime(&stime);

    string controlfile = args->getCtrlfile();
    string runmode = args->getRegrunmode();

    Runner regner;

    regner.initInput(controlfile, runmode);

    regner.initOutput();

    regner.setupData();

    regner.setupIDs();

    if (runmode.compare("regner1")==0) {
      BOOST_LOG_SEV(glg, note) << "Running in regner1...(runmode2)";
      regner.runmode2();
    } else if (runmode.compare("regner2")==0){
      BOOST_LOG_SEV(glg, note) << "Running in regner2...(runmode3)";
      regner.runmode3();
    } else {
      BOOST_LOG_SEV(glg, fatal) << "Invalid runmode...quitting.";
      exit(-1);
    }

    etime = time(0);
    BOOST_LOG_SEV(glg, note) << "Done running dvm-dos-tem regionally "
                              << "(" << ctime(&etime) << ").";
    BOOST_LOG_SEV(glg, note) << "total seconds: " << difftime(etime, stime);
  }
  return 0;
};
<commit_msg>Add directroy-exist check for new temporary yearly cal json data folder.<commit_after>/**
 *  TEM.cpp
 *  main program for running DVM-DOS-TEM
 *
 *  It runs at 3 run-mods:
 *      (1) site-specific
 *      (2) regional - time series
 * 		(3) regional - spatially (not yet available)
 *
 * Authors: Shuhua Yi - the original codes
 * 		    Fengming Yuan - re-designing and re-coding for (1) easily code managing;
 *                                        (2) java interface developing for calibration;
 *                                        (3) stand-alone application of TEM (java-c++)
 *                                        (4) inputs/outputs using netcdf format, have to be modified
 *                                        to fix memory-leaks
 *                                        (5) fix the snow/soil thermal/hydraulic algorithms
 *                                        (6) DVM coupled
 * 			Tobey Carman - modifications and maintenance
 *            1) update application entry point with boost command line arg. handling.
 *
 * Affilation: Spatial Ecology Lab, University of Alaska Fairbanks
 *
 * started: 11/01/2010
 * last modified: 09/18/2012
*/

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <ctime>
#include <cstdlib>
#include <exception>
#include <map>
#include <set>

#include <boost/filesystem.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>

#include "ArgHandler.h"
#include "TEMLogger.h"
#include "assembler/Runner.h"

ArgHandler* args = new ArgHandler();

int main(int argc, char* argv[]){
extern src::severity_logger< severity_level > glg;

  args->parse(argc, argv);
	if (args->getHelp()){
		args->showHelp();
		return 0;
	}
  args->verify();

  std::cout << "Setting up logging...\n";

  setup_logging(args->getLogLevel());

  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);

  if (args->getMode() == "siterun") {
    time_t stime;
    time_t etime;
    stime=time(0);
    BOOST_LOG_SEV(glg, note) << "Running dvm-dos-tem in siterun mode. Start @ "
                             << ctime(&stime);

    string controlfile = args->getCtrlfile();
    string chtid = args->getChtid();

    Runner siter;

    // Not working yet. Need to figure out if it is even possible to
    // control modules from the command line? and if so how this should working
    // in all the different run stages.
    //siter.modeldata_module_settings_from_args(*args);

    if (args->getCalibrationMode() == "on") {
      BOOST_LOG_SEV(glg, note) << "Turning CalibrationMode on in Runner (siter).";
      siter.set_calibrationMode(true);

      boost::filesystem::path tmp_json_folder("/tmp/cal-dvmdostem/");
      boost::filesystem::path tmp_json_folder_yly("/tmp/year-cal-dvmdostem");

      if( !(boost::filesystem::exists(tmp_json_folder_yly)) ) {
        BOOST_LOG_SEV(glg, info) << "Creating folder: " << tmp_json_folder_yly;
        boost::filesystem::create_directory(tmp_json_folder_yly);
      } else {
        BOOST_LOG_SEV(glg, info) << "Calibraiton json yearly folder already exists. ("
                                 << tmp_json_folder << ")";
        BOOST_LOG_SEV(glg, info) << "Deleting any exisiting calibration yearly json data.";
        boost::filesystem::remove_all(tmp_json_folder_yly);
        boost::filesystem::create_directory(tmp_json_folder_yly);
      }

      if( !(boost::filesystem::exists(tmp_json_folder)) ) {
        BOOST_LOG_SEV(glg, info) << "Creating folder: " << tmp_json_folder;
        boost::filesystem::create_directory(tmp_json_folder);
      } else {
        BOOST_LOG_SEV(glg, info) << "Calibraiton json folder already exists. ("
                                 << tmp_json_folder << ")";
        BOOST_LOG_SEV(glg, info) << "Deleting any exisiting calibration json data.";
        boost::filesystem::remove_all(tmp_json_folder);
        boost::filesystem::create_directory(tmp_json_folder);
      }

    } else {
      BOOST_LOG_SEV(glg, note) << "Running in extrapolation mode.";
    }

    siter.chtid = atoi(chtid.c_str());

    siter.initInput(controlfile, "siter");

    siter.initOutput();

    siter.setupData();

    siter.setupIDs();

    siter.runmode1();

    etime=time(0);

  } else if (args->getMode() == "regnrun") {

    time_t stime;
    time_t etime;
    stime=time(0);
    BOOST_LOG_SEV(glg, note) << "Running dvm-dos-tem in regional mode. Start @ "
                              << ctime(&stime);

    string controlfile = args->getCtrlfile();
    string runmode = args->getRegrunmode();

    Runner regner;

    regner.initInput(controlfile, runmode);

    regner.initOutput();

    regner.setupData();

    regner.setupIDs();

    if (runmode.compare("regner1")==0) {
      BOOST_LOG_SEV(glg, note) << "Running in regner1...(runmode2)";
      regner.runmode2();
    } else if (runmode.compare("regner2")==0){
      BOOST_LOG_SEV(glg, note) << "Running in regner2...(runmode3)";
      regner.runmode3();
    } else {
      BOOST_LOG_SEV(glg, fatal) << "Invalid runmode...quitting.";
      exit(-1);
    }

    etime = time(0);
    BOOST_LOG_SEV(glg, note) << "Done running dvm-dos-tem regionally "
                              << "(" << ctime(&etime) << ").";
    BOOST_LOG_SEV(glg, note) << "total seconds: " << difftime(etime, stime);
  }
  return 0;
};
<|endoftext|>


<commit_before>#include "SteamAppDataTransferer.h"
#include "SteamAppListItem.h"
#include "SteamAppManifestParser.h"
#include <QDirIterator>
#include <QSharedPointer>

SteamAppDataTransferer::SteamAppDataTransferer(QObject *parent)
    : QObject(parent),
      LeftDir(),
      RightDir()
{
}

SteamAppDataTransferer::~SteamAppDataTransferer()
{
}

void SteamAppDataTransferer::SetLeftDir(const QString& dirName)
{
    LeftDir = dirName;
}

QString SteamAppDataTransferer::GetLeftDir() const
{
    return LeftDir;
}

void SteamAppDataTransferer::SetRightDir(const QString& dirName)
{
    RightDir = dirName;
}

QString SteamAppDataTransferer::GetRightDir() const
{
    return RightDir;
}

void SteamAppDataTransferer::MoveAppsLeftToRight(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    MoveApps(apps, LeftDir, RightDir);
    emit CopyFinished();
}

void SteamAppDataTransferer::MoveAppsRightToLeft(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    MoveApps(apps, RightDir, LeftDir);
    emit CopyFinished();
}

#include <QDebug>
void SteamAppDataTransferer::MoveApps(const QList<QSharedPointer<SteamAppListItem> >& apps, const QString& source, const QString &destination) const
{
    foreach (const QSharedPointer<SteamAppListItem>& app, apps)
    {
        // Check size

        // check that install path exists
        QString installPath = app->GetInstallDir();
        QDir installDir(installPath);
        if (!installDir.exists())
        {
            // sometimes on Linux, Steam puts "steamapps" as the appinstalldir even though it should be "SteamApps"
            installPath.replace("steamapps", "SteamApps");
            installDir.setPath(installPath);
        }

        // copy files
        if (!installDir.exists())
        {
            qDebug() << "Could not find install dir";
            continue;
        }

        if (!CopyFilesRecursively(installDir, source, destination))
        {
            qDebug() << "Copy failed";
            continue;
        }

        QString newAppFilePath = app->GetManifestFilePath().replace(source, destination);
        if (!QFile::copy(app->GetManifestFilePath(), newAppFilePath))
        {
            qDebug() << "Could not copy manifest.";
            continue;
        }

        SteamAppManifestParser parser(newAppFilePath);
        if (!parser.SetInstallDir(installPath.replace(source, destination)))
        {
            qDebug() << "Failed to edit manifest";
        }

        // remove files
    }
}

bool SteamAppDataTransferer::CopyFilesRecursively(const QDir& sourceDir, const QString& sourceBasePath, const QString& destBasePath) const
{
    bool success = true;

    QDirIterator iterator(sourceDir.absolutePath(), QDirIterator::Subdirectories);
    while (iterator.hasNext())
    {
        iterator.next();
        if (!iterator.fileInfo().isDir())
        {
            QFileInfo fileInfo = iterator.fileInfo();
            QString relevantPath = fileInfo.absolutePath().replace(sourceBasePath, destBasePath);
            QString destFile = fileInfo.absoluteFilePath().replace(sourceBasePath, destBasePath);

            if (!sourceDir.mkpath(relevantPath) || !QFile::copy(fileInfo.absoluteFilePath(), destFile))
            {
                success = false;
                break;
            }
        }
    }

    return success;
}
<commit_msg>File removal! TODO: Progress Dialog, Error Dialog, Help Dialog.<commit_after>#include "SteamAppDataTransferer.h"
#include "SteamAppListItem.h"
#include "SteamAppManifestParser.h"
#include <QDirIterator>
#include <QSharedPointer>

SteamAppDataTransferer::SteamAppDataTransferer(QObject *parent)
    : QObject(parent),
      LeftDir(),
      RightDir()
{
}

SteamAppDataTransferer::~SteamAppDataTransferer()
{
}

void SteamAppDataTransferer::SetLeftDir(const QString& dirName)
{
    LeftDir = dirName;
}

QString SteamAppDataTransferer::GetLeftDir() const
{
    return LeftDir;
}

void SteamAppDataTransferer::SetRightDir(const QString& dirName)
{
    RightDir = dirName;
}

QString SteamAppDataTransferer::GetRightDir() const
{
    return RightDir;
}

void SteamAppDataTransferer::MoveAppsLeftToRight(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    MoveApps(apps, LeftDir, RightDir);
    emit CopyFinished();
}

void SteamAppDataTransferer::MoveAppsRightToLeft(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    MoveApps(apps, RightDir, LeftDir);
    emit CopyFinished();
}

#include <QDebug>
void SteamAppDataTransferer::MoveApps(const QList<QSharedPointer<SteamAppListItem> >& apps, const QString& source, const QString &destination) const
{
    foreach (const QSharedPointer<SteamAppListItem>& app, apps)
    {
        QString installPath = app->GetInstallDir();
        QDir installDir(installPath);
        if (!installDir.exists())
        {
            // sometimes on Linux, Steam puts "steamapps" as the appinstalldir even though it should be "SteamApps"
            installPath.replace("steamapps", "SteamApps");
            installDir.setPath(installPath);

            if (!installDir.exists())
            {
                qDebug() << "Could not find install dir";
                continue;
            }
        }

        if (!CopyFilesRecursively(installDir, source, destination))
        {
            qDebug() << "Copy failed";
            continue;
        }

        QString newAppFilePath = app->GetManifestFilePath().replace(source, destination);
        if (!QFile::copy(app->GetManifestFilePath(), newAppFilePath))
        {
            qDebug() << "Failed to copy manifest.";
            continue;
        }

        SteamAppManifestParser parser(newAppFilePath);
        if (!parser.SetInstallDir(installPath.replace(source, destination)))
        {
            qDebug() << "Failed to edit manifest";
            continue;
        }

        if (!installDir.removeRecursively())
        {
            qDebug() << "Failed to delete original files";
            continue;
        }

        QFile appManifest(app->GetManifestFilePath());
        if (!appManifest.remove())
        {
            qDebug() << "Failed to delete original manifest";
            continue;
        }
    }
}

bool SteamAppDataTransferer::CopyFilesRecursively(const QDir& sourceDir, const QString& sourceBasePath, const QString& destBasePath) const
{
    bool success = true;

    QDirIterator iterator(sourceDir.absolutePath(), QDirIterator::Subdirectories);
    while (iterator.hasNext())
    {
        iterator.next();
        if (!iterator.fileInfo().isDir())
        {
            QFileInfo fileInfo = iterator.fileInfo();
            QString relevantPath = fileInfo.absolutePath().replace(sourceBasePath, destBasePath);
            QString destFile = fileInfo.absoluteFilePath().replace(sourceBasePath, destBasePath);

            if (!sourceDir.mkpath(relevantPath) || !QFile::copy(fileInfo.absoluteFilePath(), destFile))
            {
                success = false;
                break;
            }
        }
    }

    return success;
}
<|endoftext|>


<commit_before>#include "SteamAppDataTransferer.h"
#include "SteamAppListItem.h"
#include "SteamAppManifestParser.h"
#include "AppTransferError.h"

#include <QDirIterator>
#include <QScopedPointer>
#include <QSharedPointer>

SteamAppDataTransferer::SteamAppDataTransferer(QObject *parent)
    : QObject(parent),
      LeftDir(),
      RightDir(),
      PreviousTransfer(None)
{
}

SteamAppDataTransferer::SteamAppDataTransferer(const SteamAppDataTransferer& rhs)
    : QObject(rhs.parent()),
      LeftDir(rhs.LeftDir),
      RightDir(rhs.RightDir),
      PreviousTransfer(rhs.PreviousTransfer)
{
}

SteamAppDataTransferer::~SteamAppDataTransferer()
{
}

void SteamAppDataTransferer::SetLeftDir(const QString& dirName)
{
    LeftDir = dirName;
}

QString SteamAppDataTransferer::GetLeftDir() const
{
    return LeftDir;
}

void SteamAppDataTransferer::SetRightDir(const QString& dirName)
{
    RightDir = dirName;
}

QString SteamAppDataTransferer::GetRightDir() const
{
    return RightDir;
}

void SteamAppDataTransferer::MoveAppsLeftToRight(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    PreviousTransfer = LeftToRight;
    MoveApps(apps, LeftDir, RightDir);
}

void SteamAppDataTransferer::MoveAppsRightToLeft(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    PreviousTransfer = RightToLeft;
    MoveApps(apps, RightDir, LeftDir);
}

void SteamAppDataTransferer::RetryPreviousTransfer(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    if (LeftToRight == PreviousTransfer)
    {
        MoveAppsLeftToRight(apps);
    }
    else if (RightToLeft == PreviousTransfer)
    {
        MoveAppsRightToLeft(apps);
    }
}
#include <QThread>
void SteamAppDataTransferer::MoveApps(const QList<QSharedPointer<SteamAppListItem> >& apps, const QString& source, const QString &destination)
{
    emit TransferBeginning(apps.count());

    int percentComplete = 0;
    QList<AppTransferError> errors;
    foreach (const QSharedPointer<SteamAppListItem>& app, apps)
    {
        emit SingleTransferStarting();
        emit TransferProgress(QString("%1: %2 of %3 bytes copied").arg(app->GetName()).arg(0).arg(app->GetSize()), percentComplete);

        QThread::msleep(1000);
        QString installPath = app->GetInstallDir();
        QDir installDir(installPath);
        if (!installDir.exists())
        {
            // sometimes on Linux, Steam puts "steamapps" as the appinstalldir even though it should be "SteamApps"
            installPath.replace("steamapps", "SteamApps");
            installDir.setPath(installPath);

            if (!installDir.exists())
            {
                errors << AppTransferError(app, "Could not find install directory");
                continue;
            }
        }

        if (!CopyFilesRecursively(installDir, source, destination))
        {
            errors << AppTransferError(app, "Copy failed");
            continue;
        }

        QString newAppFilePath = app->GetManifestFilePath().replace(source, destination);
        if (!QFile::copy(app->GetManifestFilePath(), newAppFilePath))
        {
            errors << AppTransferError(app, "Copy of manifest failed");
            continue;
        }

        SteamAppManifestParser parser(newAppFilePath);
        if (!parser.SetInstallDir(installPath.replace(source, destination)))
        {
            errors << AppTransferError(app, "Edit of manifest failed");
            continue;
        }

        if (!installDir.removeRecursively())
        {
            errors << AppTransferError(app, "Removal of old files failed");
            continue;
        }

        QFile appManifest(app->GetManifestFilePath());
        if (!appManifest.remove())
        {
            errors << AppTransferError(app, "Removal of old manifest failed");
            continue;
        }

        percentComplete += 100 / apps.count();
    }

    if (!errors.empty())
    {
        emit ErrorsDuringTransfer(errors);
    }

    emit TransferComplete();
}

bool SteamAppDataTransferer::CopyFilesRecursively(const QDir& sourceDir, const QString& sourceBasePath, const QString& destBasePath) const
{
    bool success = true;

    QDirIterator iterator(sourceDir.absolutePath(), QDirIterator::Subdirectories);
    while (iterator.hasNext())
    {
        iterator.next();
        if (!iterator.fileInfo().isDir())
        {
//            fileInfo.size()
            QFileInfo fileInfo = iterator.fileInfo();
            QString relevantPath = fileInfo.absolutePath().replace(sourceBasePath, destBasePath);
            QString destFile = fileInfo.absoluteFilePath().replace(sourceBasePath, destBasePath);

            if (!sourceDir.mkpath(relevantPath) || !QFile::copy(fileInfo.absoluteFilePath(), destFile))
            {
                success = false;
                break;
            }
        }
    }

    return success;
}
<commit_msg>Fixing transfer details messages to include percent signs.<commit_after>#include "SteamAppDataTransferer.h"
#include "SteamAppListItem.h"
#include "SteamAppManifestParser.h"
#include "AppTransferError.h"

#include <QDirIterator>
#include <QScopedPointer>
#include <QSharedPointer>

SteamAppDataTransferer::SteamAppDataTransferer(QObject *parent)
    : QObject(parent),
      LeftDir(),
      RightDir(),
      PreviousTransfer(None)
{
}

SteamAppDataTransferer::SteamAppDataTransferer(const SteamAppDataTransferer& rhs)
    : QObject(rhs.parent()),
      LeftDir(rhs.LeftDir),
      RightDir(rhs.RightDir),
      PreviousTransfer(rhs.PreviousTransfer)
{
}

SteamAppDataTransferer::~SteamAppDataTransferer()
{
}

void SteamAppDataTransferer::SetLeftDir(const QString& dirName)
{
    LeftDir = dirName;
}

QString SteamAppDataTransferer::GetLeftDir() const
{
    return LeftDir;
}

void SteamAppDataTransferer::SetRightDir(const QString& dirName)
{
    RightDir = dirName;
}

QString SteamAppDataTransferer::GetRightDir() const
{
    return RightDir;
}

void SteamAppDataTransferer::MoveAppsLeftToRight(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    PreviousTransfer = LeftToRight;
    MoveApps(apps, LeftDir, RightDir);
}

void SteamAppDataTransferer::MoveAppsRightToLeft(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    PreviousTransfer = RightToLeft;
    MoveApps(apps, RightDir, LeftDir);
}

void SteamAppDataTransferer::RetryPreviousTransfer(const QList<QSharedPointer<SteamAppListItem> >& apps)
{
    if (LeftToRight == PreviousTransfer)
    {
        MoveAppsLeftToRight(apps);
    }
    else if (RightToLeft == PreviousTransfer)
    {
        MoveAppsRightToLeft(apps);
    }
}
#include <QThread>
void SteamAppDataTransferer::MoveApps(const QList<QSharedPointer<SteamAppListItem> >& apps, const QString& source, const QString &destination)
{
    emit TransferBeginning(apps.count());

    int percentComplete = 0;
    quint16 appNum = 1;
    QList<AppTransferError> errors;
    foreach (const QSharedPointer<SteamAppListItem>& app, apps)
    {
        emit SingleTransferStarting();
        emit TransferProgress(QString("%1\%... %2: %3 of %4 bytes copied").arg(percentComplete).arg(app->GetName()).arg(0).arg(app->GetSize()), percentComplete);

        QThread::msleep(1000);
        QString installPath = app->GetInstallDir();
        QDir installDir(installPath);
        if (!installDir.exists())
        {
            // sometimes on Linux, Steam puts "steamapps" as the appinstalldir even though it should be "SteamApps"
            installPath.replace("steamapps", "SteamApps");
            installDir.setPath(installPath);

            if (!installDir.exists())
            {
                errors << AppTransferError(app, "Could not find install directory");
                continue;
            }
        }

        if (!CopyFilesRecursively(installDir, source, destination))
        {
            errors << AppTransferError(app, "Copy failed");
            continue;
        }

        emit TransferProgress(QString("%1\%... %2: Copying manifest file").arg(percentComplete).arg(app->GetName()), percentComplete);
        QString newAppFilePath = app->GetManifestFilePath().replace(source, destination);
        if (!QFile::copy(app->GetManifestFilePath(), newAppFilePath))
        {
            errors << AppTransferError(app, "Copy of manifest failed");
            continue;
        }

        emit TransferProgress(QString("%1\%... %2: Editing manifest file").arg(percentComplete).arg(app->GetName()), percentComplete);
        SteamAppManifestParser parser(newAppFilePath);
        if (!parser.SetInstallDir(installPath.replace(source, destination)))
        {
            errors << AppTransferError(app, "Edit of manifest failed");
            continue;
        }

        emit TransferProgress(QString("%1\%... %2: Deleting old install files").arg(percentComplete).arg(app->GetName()), percentComplete);
        if (!installDir.removeRecursively())
        {
            errors << AppTransferError(app, "Removal of old files failed");
            continue;
        }

        emit TransferProgress(QString("%1\%... %2: Deleting old manifest file").arg(percentComplete).arg(app->GetName()), percentComplete);
        QFile appManifest(app->GetManifestFilePath());
        if (!appManifest.remove())
        {
            errors << AppTransferError(app, "Removal of old manifest failed");
            continue;
        }

        percentComplete = (appNum++ * 100) / apps.count();
    }

    if (!errors.empty())
    {
        emit ErrorsDuringTransfer(errors);
    }

    emit TransferComplete();
}

bool SteamAppDataTransferer::CopyFilesRecursively(const QDir& sourceDir, const QString& sourceBasePath, const QString& destBasePath) const
{
    bool success = true;

    QDirIterator iterator(sourceDir.absolutePath(), QDirIterator::Subdirectories);
    while (iterator.hasNext())
    {
        iterator.next();
        if (!iterator.fileInfo().isDir())
        {
//            fileInfo.size()
            QFileInfo fileInfo = iterator.fileInfo();
            QString relevantPath = fileInfo.absolutePath().replace(sourceBasePath, destBasePath);
            QString destFile = fileInfo.absoluteFilePath().replace(sourceBasePath, destBasePath);

            if (!sourceDir.mkpath(relevantPath) || !QFile::copy(fileInfo.absoluteFilePath(), destFile))
            {
                success = false;
                break;
            }
        }
    }

    return success;
}
<|endoftext|>


<commit_before>
#include "Tcl.h"
#include "ScriptingLib.tcl.h"
#include "Editor.h"
#include "Log.h"

#include "bx/bx.h"

#include <iostream>
#include <fstream>
#include <algorithm>
#include <functional>
#include <cstring>
#include <cassert>
#include <string.h>
#include <map>

#include "bx/os.h"

extern "C" {
  int Jim_clockInit(Jim_Interp * interp);
  int Jim_regexpInit(Jim_Interp * interp);
}

namespace tcl {

  // -- Globals --

  static Jim_Interp * interpreter_ = nullptr;

  // -- Variable --

  static std::vector<Variable *> & builtInVariables()
  {
    static std::vector<Variable *> vars;
    return vars;
  }

  Variable::Variable(const char * name, const char * defaultValue)
    : name_(name),
      type_(ValueType::STRING),
      defaultStrValue_(defaultValue)
  {
    builtInVariables().push_back(this);
  }

  Variable::Variable(const char * name, int defaultValue)
    : name_(name),
      type_(ValueType::INT),
      defaultIntValue_(defaultValue)
  {
    builtInVariables().push_back(this);
  }

  Variable::Variable(const char * name, bool defaultValue)
    : name_(name),
      type_(ValueType::BOOL),
      defaultBoolValue_(defaultValue)
  {
    builtInVariables().push_back(this);
  }

  Jim_Obj * Variable::value() const
  {
    assert(interpreter_);
    return Jim_GetGlobalVariableStr(interpreter_, name_, 0);
  }

  Jim_Obj * Variable::defaultValue() const
  {
    assert(interpreter_);

    switch (type_)
    {
      case ValueType::STRING:
        return Jim_NewStringObj(interpreter_, defaultStrValue_, std::strlen(defaultStrValue_));

      case ValueType::INT:
        return Jim_NewIntObj(interpreter_, defaultIntValue_);

      case ValueType::BOOL:
        return Jim_NewIntObj(interpreter_, defaultBoolValue_ ? 1 : 0);
    }

    return nullptr;
  }

  std::string Variable::toStr() const
  {
    return std::string(Jim_String(value()));
  }

  bool Variable::toBool() const
  {
    return toInt() > 0;
  }

  int Variable::toInt() const
  {
    long val;
    if (Jim_GetLong(interpreter_, value(), &val) != JIM_OK)
      return 0;

    return val;
  }

  // -- BuiltInProc --

  static std::vector<BuiltInProc *> & builtInProcs()
  {
    static std::vector<BuiltInProc *> procs;
    return procs;
  }

  BuiltInProc::BuiltInProc(const char * name, Jim_CmdProc * proc)
    : name_(name),
      proc_(proc)
  {
    builtInProcs().push_back(this);
  }

  BuiltInProc::BuiltInProc(const char * name, const char * args, Jim_CmdProc * proc)
    : name_(name),
      args_(args),
      proc_(proc)
  {
    builtInProcs().push_back(this);
  }

  BuiltInProc::BuiltInProc(const char * name, const char * args, const char * desc, Jim_CmdProc * proc)
    : name_(name),
      args_(args),
      desc_(desc),
      proc_(proc)
  {
    builtInProcs().push_back(this);
  }

  int BuiltInProc::call(struct Jim_Interp * interp, int argc, Jim_Obj * const * argv)
  {
    // Check for the help command
    if (argc == 2 && Jim_CompareStringImmediate(interp, argv[1], "-help"))
    {
      Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
      Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]), NULL);

      if (strlen(args_) > 0)
        Jim_AppendStrings(interp, Jim_GetResult(interp), " ", args_, NULL);

      Jim_AppendStrings(interp, Jim_GetResult(interp), "\"");

      if (strlen(desc_) > 0)
        Jim_AppendStrings(interp, Jim_GetResult(interp), " ", desc_, NULL);

      return JIM_OK;
    }

    return proc_(interp, argc, argv);
  }

  static int cmdProc(Jim_Interp * interp, int argc, Jim_Obj * const * argv)
  {
    BuiltInProc * cmd = static_cast<BuiltInProc *>(Jim_CmdPrivData(interp));
    return cmd->call(interp, argc, argv);
  }

  // -- BuiltInSubProc

  static void addSubCommands(struct Jim_Interp * interp, std::vector<const char *> const& subCommands, const char * sep)
  {
    const char * s = "";

    for (int i = 0; i < subCommands.size() / 3; ++i)
    {
      logInfo(subCommands[i * 3]);
      Jim_AppendStrings(interp, Jim_GetResult(interp), s, subCommands[i * 3], NULL);
      s = sep;
    }
  }

  static void showCommandUsage(struct Jim_Interp * interp, int argc, Jim_Obj * const * argv, std::vector<const char *> const& subCommands)
  {
    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
    Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]), " command ... \", where command is one of: ", NULL);
    addSubCommands(interp, subCommands, ", ");
  }

  static std::vector<BuiltInSubProc *> & builtInSubCmdProcs()
  {
    static std::vector<BuiltInSubProc *> procs;
    return procs;
  }

  BuiltInSubProc::BuiltInSubProc(const char * name, std::vector<const char *> subCommands, SubCmdProc * proc)
    : name_(name),
      subCommands_(subCommands),
      proc_(proc)
  {
    assert(subCommands.size() % 3 == 0);
    builtInSubCmdProcs().push_back(this);
  }

  int BuiltInSubProc::call(struct Jim_Interp * interp, int argc, Jim_Obj * const * argv)
  {
    bool help = false;
    const char * cmdName = Jim_String(argv[0]);

    if (argc < 2)
    {
      Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
      Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdName, " command ...\"\n", NULL);
      Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdName, " -help ?command?\" for help about the command", NULL);
      return JIM_ERR;
    }

    Jim_Obj * cmd = argv[1];

    // Check for the help command
    if (Jim_CompareStringImmediate(interp, cmd, "-help"))
    {
      if (argc == 2)
      {
        showCommandUsage(interp, argc, argv, subCommands_);
        return JIM_OK;
      }

      help = true;
      cmd = argv[2];
    }

    // Check for special builtin '-commands' command first
    if (Jim_CompareStringImmediate(interp, cmd, "-commands"))
    {
        /* Build the result here */
        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
        addSubCommands(interp, subCommands_, " ");
        return JIM_OK;
    }

    for (int i = 0; i < subCommands_.size() / 3; ++i)
    {
      if (Jim_CompareStringImmediate(interp, cmd, subCommands_[i * 3]))
      {
        if (help)
        {
          Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
          Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", cmdName, " ", subCommands_[i * 3], NULL);

          if (strlen(subCommands_[i * 3 + 1]) > 0)
            Jim_AppendStrings(interp, Jim_GetResult(interp), " ", subCommands_[i * 3 + 1], NULL);

          Jim_AppendStrings(interp, Jim_GetResult(interp), "\"");

          if (strlen(subCommands_[i * 3 + 2]) > 0)
            Jim_AppendStrings(interp, Jim_GetResult(interp), " ", subCommands_[i * 3 + 2], NULL);

          return JIM_OK;
        }
        else
        {
          return proc_(interp, i, argc - 2, argv + 2);
        }
      }
    }

    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
    Jim_AppendStrings(interp, Jim_GetResult(interp), cmdName, ", unknown command \"", Jim_String(cmd), "\" should be one of: ", NULL);
    addSubCommands(interp, subCommands_, ", ");

    return JIM_ERR;
  }

  static int subCmdProc(Jim_Interp * interp, int argc, Jim_Obj * const * argv)
  {
    BuiltInSubProc * subCmd = static_cast<BuiltInSubProc *>(Jim_CmdPrivData(interp));
    return subCmd->call(interp, argc, argv);
  }

  // -- Exposed procs --

  class ExposedProc
  {
    public:
      ExposedProc(std::string const& name)
        : name_(name)
      { }

      std::string name() const { return name_; }

    private:
      std::string name_;
  };

  static std::vector<ExposedProc> exposedProcs_;

  // -- Interface --

  static const std::string CONFIG_FILE = "zum.conf";

  void initialize()
  {
    interpreter_ = Jim_CreateInterp();
    Jim_RegisterCoreCommands(interpreter_);

    // Register extensions
    ::Jim_clockInit(interpreter_);
    ::Jim_regexpInit(interpreter_);

    // Register built in commands
    for (auto * cmd : builtInProcs())
      Jim_CreateCommand(interpreter_, cmd->name(), cmdProc, cmd, nullptr);

    for (auto * cmd : builtInSubCmdProcs())
      Jim_CreateCommand(interpreter_, cmd->name(), subCmdProc, cmd, nullptr);

    // Register built in variables
    for (auto * var : builtInVariables())
      Jim_SetGlobalVariableStr(interpreter_, var->name(), var->defaultValue());

#if DEBUG
    // Use the file from the source directory
    Jim_EvalFileGlobal(interpreter_, "../src/ScriptingLib.tcl");
#else
    Jim_EvalSource(interpreter_, __FILE__, __LINE__, std::string((char *)&ScriptingLib[0], BX_COUNTOF(ScriptingLib)).c_str());
#endif

    std::string configFile = "";
#if BX_PLATFORM_LINUX || BX_PLATFORM_OSX
    // Try to load the config file
    char * home = getenv("HOME");
    if (home)
      configFile = std::string(home) + "/." + CONFIG_FILE;
    else
      configFile = "~/." + CONFIG_FILE;
#else
    char pwd[1024];
    configFile = std::string(bx::pwd(pwd, 1024)) + "/" + CONFIG_FILE;
#endif

    logInfo("Loading config file: ", configFile);
    Jim_EvalFileGlobal(interpreter_, configFile.c_str());
  }

  void shutdown()
  {
    Jim_FreeInterp(interpreter_);
    interpreter_ = nullptr;
  }

  bool evaluate(std::string const& code)
  {
    const bool ok = Jim_EvalGlobal(interpreter_, code.c_str()) == JIM_OK;
    if (!ok)
      logError(result());

    return ok;
  }

  std::string result()
  {
    return std::string(Jim_String(Jim_GetResult(interpreter_)));
  }

  std::vector<std::string> findMatches(std::string const& name)
  {
    std::vector<std::string> result;

    // Search for matching procs
    for (auto * cmd : builtInProcs())
    {
      const std::string cmdName(cmd->name());
      if (cmdName.find(name) == 0)
        result.push_back(cmdName);
    }

    // Search for matching global variables
    for (auto * cmd : builtInSubCmdProcs())
    {
      const std::string cmdName(cmd->name());
      if (cmdName.find(name) == 0)
        result.push_back(cmdName);
    }

    for (auto const& it : exposedProcs_)
    {
      if (it.name().find(name) == 0)
        result.push_back(it.name());
    }

    // Search for matching global variables
    for (auto * var : builtInVariables())
    {
      const std::string varName(var->name());
      if (varName.find(name) == 0)
        result.push_back(varName);
    }

/*
    Jim_HashTableIterator * it = Jim_GetHashTableIterator(&interpreter_->commands);
    Jim_HashEntry * entry = nullptr;

    while ((entry = Jim_NextHashEntry(it)) != nullptr)
    {
      const std::string cmdName((const char *)Jim_GetHashEntryKey(entry));
      Jim_Cmd * cmd = (Jim_Cmd *)Jim_GetHashEntryVal(entry);

      if (cmdName.find(name) == 0)
        result.push_back(cmdName);
    }

    Jim_Free(it);

    it = Jim_GetHashTableIterator(&interpreter_->topFramePtr->vars);

    while ((entry = Jim_NextHashEntry(it)) != nullptr)
    {
      const std::string varName((const char *)Jim_GetHashEntryKey(entry));
      //Jim_Cmd * cmd = (Jim_Cmd *)Jim_GetHashEntryVal(entry);

      if (varName.find(name) == 0)
        result.push_back(varName);
    }

    Jim_Free(it);
*/

    return result;
  }

  TCL_FUNC(puts, "string ?string ...?")
  {
    TCL_CHECK_ARGS(2, 1000);

    std::string log;
    for (uint32_t i = 1; i < argc; ++i)
      log += Jim_String(argv[i]) + std::string((i + 1) == argc ? "" : " ");

    logInfo(log);
    flashMessage(log);

    return JIM_OK;
  }

  TCL_FUNC(expose, "string", "Expose a tcl function to command auto-completion")
  {
    TCL_CHECK_ARG(2);
    TCL_STRING_ARG(1, procName);

    exposedProcs_.push_back(ExposedProc(procName));
  }
}
<commit_msg>Removed some old code<commit_after>
#include "Tcl.h"
#include "ScriptingLib.tcl.h"
#include "Editor.h"
#include "Log.h"

#include "bx/bx.h"

#include <iostream>
#include <fstream>
#include <algorithm>
#include <functional>
#include <cstring>
#include <cassert>
#include <string.h>
#include <map>

#include "bx/os.h"

extern "C" {
  int Jim_clockInit(Jim_Interp * interp);
  int Jim_regexpInit(Jim_Interp * interp);
}

namespace tcl {

  // -- Globals --

  static Jim_Interp * interpreter_ = nullptr;

  // -- Variable --

  static std::vector<Variable *> & builtInVariables()
  {
    static std::vector<Variable *> vars;
    return vars;
  }

  Variable::Variable(const char * name, const char * defaultValue)
    : name_(name),
      type_(ValueType::STRING),
      defaultStrValue_(defaultValue)
  {
    builtInVariables().push_back(this);
  }

  Variable::Variable(const char * name, int defaultValue)
    : name_(name),
      type_(ValueType::INT),
      defaultIntValue_(defaultValue)
  {
    builtInVariables().push_back(this);
  }

  Variable::Variable(const char * name, bool defaultValue)
    : name_(name),
      type_(ValueType::BOOL),
      defaultBoolValue_(defaultValue)
  {
    builtInVariables().push_back(this);
  }

  Jim_Obj * Variable::value() const
  {
    assert(interpreter_);
    return Jim_GetGlobalVariableStr(interpreter_, name_, 0);
  }

  Jim_Obj * Variable::defaultValue() const
  {
    assert(interpreter_);

    switch (type_)
    {
      case ValueType::STRING:
        return Jim_NewStringObj(interpreter_, defaultStrValue_, std::strlen(defaultStrValue_));

      case ValueType::INT:
        return Jim_NewIntObj(interpreter_, defaultIntValue_);

      case ValueType::BOOL:
        return Jim_NewIntObj(interpreter_, defaultBoolValue_ ? 1 : 0);
    }

    return nullptr;
  }

  std::string Variable::toStr() const
  {
    return std::string(Jim_String(value()));
  }

  bool Variable::toBool() const
  {
    return toInt() > 0;
  }

  int Variable::toInt() const
  {
    long val;
    if (Jim_GetLong(interpreter_, value(), &val) != JIM_OK)
      return 0;

    return val;
  }

  // -- BuiltInProc --

  static std::vector<BuiltInProc *> & builtInProcs()
  {
    static std::vector<BuiltInProc *> procs;
    return procs;
  }

  BuiltInProc::BuiltInProc(const char * name, Jim_CmdProc * proc)
    : name_(name),
      proc_(proc)
  {
    builtInProcs().push_back(this);
  }

  BuiltInProc::BuiltInProc(const char * name, const char * args, Jim_CmdProc * proc)
    : name_(name),
      args_(args),
      proc_(proc)
  {
    builtInProcs().push_back(this);
  }

  BuiltInProc::BuiltInProc(const char * name, const char * args, const char * desc, Jim_CmdProc * proc)
    : name_(name),
      args_(args),
      desc_(desc),
      proc_(proc)
  {
    builtInProcs().push_back(this);
  }

  int BuiltInProc::call(struct Jim_Interp * interp, int argc, Jim_Obj * const * argv)
  {
    // Check for the help command
    if (argc == 2 && Jim_CompareStringImmediate(interp, argv[1], "-help"))
    {
      Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
      Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]), NULL);

      if (strlen(args_) > 0)
        Jim_AppendStrings(interp, Jim_GetResult(interp), " ", args_, NULL);

      Jim_AppendStrings(interp, Jim_GetResult(interp), "\"");

      if (strlen(desc_) > 0)
        Jim_AppendStrings(interp, Jim_GetResult(interp), " ", desc_, NULL);

      return JIM_OK;
    }

    return proc_(interp, argc, argv);
  }

  static int cmdProc(Jim_Interp * interp, int argc, Jim_Obj * const * argv)
  {
    BuiltInProc * cmd = static_cast<BuiltInProc *>(Jim_CmdPrivData(interp));
    return cmd->call(interp, argc, argv);
  }

  // -- BuiltInSubProc

  static void addSubCommands(struct Jim_Interp * interp, std::vector<const char *> const& subCommands, const char * sep)
  {
    const char * s = "";

    for (int i = 0; i < subCommands.size() / 3; ++i)
    {
      logInfo(subCommands[i * 3]);
      Jim_AppendStrings(interp, Jim_GetResult(interp), s, subCommands[i * 3], NULL);
      s = sep;
    }
  }

  static void showCommandUsage(struct Jim_Interp * interp, int argc, Jim_Obj * const * argv, std::vector<const char *> const& subCommands)
  {
    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
    Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]), " command ... \", where command is one of: ", NULL);
    addSubCommands(interp, subCommands, ", ");
  }

  static std::vector<BuiltInSubProc *> & builtInSubCmdProcs()
  {
    static std::vector<BuiltInSubProc *> procs;
    return procs;
  }

  BuiltInSubProc::BuiltInSubProc(const char * name, std::vector<const char *> subCommands, SubCmdProc * proc)
    : name_(name),
      subCommands_(subCommands),
      proc_(proc)
  {
    assert(subCommands.size() % 3 == 0);
    builtInSubCmdProcs().push_back(this);
  }

  int BuiltInSubProc::call(struct Jim_Interp * interp, int argc, Jim_Obj * const * argv)
  {
    bool help = false;
    const char * cmdName = Jim_String(argv[0]);

    if (argc < 2)
    {
      Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
      Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdName, " command ...\"\n", NULL);
      Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdName, " -help ?command?\" for help about the command", NULL);
      return JIM_ERR;
    }

    Jim_Obj * cmd = argv[1];

    // Check for the help command
    if (Jim_CompareStringImmediate(interp, cmd, "-help"))
    {
      if (argc == 2)
      {
        showCommandUsage(interp, argc, argv, subCommands_);
        return JIM_OK;
      }

      help = true;
      cmd = argv[2];
    }

    // Check for special builtin '-commands' command first
    if (Jim_CompareStringImmediate(interp, cmd, "-commands"))
    {
        /* Build the result here */
        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
        addSubCommands(interp, subCommands_, " ");
        return JIM_OK;
    }

    for (int i = 0; i < subCommands_.size() / 3; ++i)
    {
      if (Jim_CompareStringImmediate(interp, cmd, subCommands_[i * 3]))
      {
        if (help)
        {
          Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
          Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", cmdName, " ", subCommands_[i * 3], NULL);

          if (strlen(subCommands_[i * 3 + 1]) > 0)
            Jim_AppendStrings(interp, Jim_GetResult(interp), " ", subCommands_[i * 3 + 1], NULL);

          Jim_AppendStrings(interp, Jim_GetResult(interp), "\"");

          if (strlen(subCommands_[i * 3 + 2]) > 0)
            Jim_AppendStrings(interp, Jim_GetResult(interp), " ", subCommands_[i * 3 + 2], NULL);

          return JIM_OK;
        }
        else
        {
          return proc_(interp, i, argc - 2, argv + 2);
        }
      }
    }

    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
    Jim_AppendStrings(interp, Jim_GetResult(interp), cmdName, ", unknown command \"", Jim_String(cmd), "\" should be one of: ", NULL);
    addSubCommands(interp, subCommands_, ", ");

    return JIM_ERR;
  }

  static int subCmdProc(Jim_Interp * interp, int argc, Jim_Obj * const * argv)
  {
    BuiltInSubProc * subCmd = static_cast<BuiltInSubProc *>(Jim_CmdPrivData(interp));
    return subCmd->call(interp, argc, argv);
  }

  // -- Exposed procs --

  class ExposedProc
  {
    public:
      ExposedProc(std::string const& name)
        : name_(name)
      { }

      std::string name() const { return name_; }

    private:
      std::string name_;
  };

  static std::vector<ExposedProc> exposedProcs_;

  // -- Interface --

  static const std::string CONFIG_FILE = "zum.conf";

  void initialize()
  {
    interpreter_ = Jim_CreateInterp();
    Jim_RegisterCoreCommands(interpreter_);

    // Register extensions
    ::Jim_clockInit(interpreter_);
    ::Jim_regexpInit(interpreter_);

    // Register built in commands
    for (auto * cmd : builtInProcs())
      Jim_CreateCommand(interpreter_, cmd->name(), cmdProc, cmd, nullptr);

    for (auto * cmd : builtInSubCmdProcs())
      Jim_CreateCommand(interpreter_, cmd->name(), subCmdProc, cmd, nullptr);

    // Register built in variables
    for (auto * var : builtInVariables())
      Jim_SetGlobalVariableStr(interpreter_, var->name(), var->defaultValue());

#if DEBUG
    // Use the file from the source directory
    Jim_EvalFileGlobal(interpreter_, "../src/ScriptingLib.tcl");
#else
    Jim_EvalSource(interpreter_, __FILE__, __LINE__, std::string((char *)&ScriptingLib[0], BX_COUNTOF(ScriptingLib)).c_str());
#endif

    std::string configFile = "";
#if BX_PLATFORM_LINUX || BX_PLATFORM_OSX
    // Try to load the config file
    char * home = getenv("HOME");
    if (home)
      configFile = std::string(home) + "/." + CONFIG_FILE;
    else
      configFile = "~/." + CONFIG_FILE;
#else
    char pwd[1024];
    configFile = std::string(bx::pwd(pwd, 1024)) + "/" + CONFIG_FILE;
#endif

    logInfo("Loading config file: ", configFile);
    Jim_EvalFileGlobal(interpreter_, configFile.c_str());
  }

  void shutdown()
  {
    Jim_FreeInterp(interpreter_);
    interpreter_ = nullptr;
  }

  bool evaluate(std::string const& code)
  {
    const bool ok = Jim_EvalGlobal(interpreter_, code.c_str()) == JIM_OK;
    if (!ok)
      logError(result());

    return ok;
  }

  std::string result()
  {
    return std::string(Jim_String(Jim_GetResult(interpreter_)));
  }

  std::vector<std::string> findMatches(std::string const& name)
  {
    std::vector<std::string> result;

    // Search for matching procs
    for (auto * cmd : builtInProcs())
    {
      const std::string cmdName(cmd->name());
      if (cmdName.find(name) == 0)
        result.push_back(cmdName);
    }

    // Search for matching global variables
    for (auto * cmd : builtInSubCmdProcs())
    {
      const std::string cmdName(cmd->name());
      if (cmdName.find(name) == 0)
        result.push_back(cmdName);
    }

    for (auto const& it : exposedProcs_)
    {
      if (it.name().find(name) == 0)
        result.push_back(it.name());
    }

    // Search for matching global variables
    for (auto * var : builtInVariables())
    {
      const std::string varName(var->name());
      if (varName.find(name) == 0)
        result.push_back(varName);
    }

    return result;
  }

  TCL_FUNC(puts, "string ?string ...?")
  {
    TCL_CHECK_ARGS(2, 1000);

    std::string log;
    for (uint32_t i = 1; i < argc; ++i)
      log += Jim_String(argv[i]) + std::string((i + 1) == argc ? "" : " ");

    logInfo(log);
    flashMessage(log);

    return JIM_OK;
  }

  TCL_FUNC(expose, "string", "Expose a tcl function to command auto-completion")
  {
    TCL_CHECK_ARG(2);
    TCL_STRING_ARG(1, procName);

    exposedProcs_.push_back(ExposedProc(procName));
  }
}
<|endoftext|>


<commit_before>/*
<License>
Copyright 2016 Virtium Technology

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http ://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
</License>
*/
#include <memory>

#include "Device.h"
#include "StorageUtility.h"

namespace vtStor
{

eErrorCode GetStorageDevices(std::vector<std::shared_ptr<IDevice>>& Devices, eOnErrorBehavior OnErrorBehavior)
{
    eErrorCode error = eErrorCode::None;

    sEnumerateDevicesCallback callBack;
    callBack.Data = (void*)&Devices;
    callBack.Function = [](void* Data, const HDEVINFO& DevInfoHandle, SP_DEVINFO_DATA& DevInfoData, SP_DEVICE_INTERFACE_DATA& DevInterfaceData, const PSP_INTERFACE_DEVICE_DETAIL_DATA& DevDetailData, U32 SizeOfDevDetailData, eErrorCode& ErrorCode)
    {
        std::vector<std::shared_ptr<vtStor::IDevice>>* devices = (std::vector<std::shared_ptr<vtStor::IDevice>>*)Data;
        devices->push_back(std::make_shared<cDevice>((SP_DEVINFO_DATA*)&DevInfoData, (SP_DEVICE_INTERFACE_DATA*)&DevInterfaceData, DevDetailData, SizeOfDevDetailData));
    };

    error = EnumerateDevices(callBack, &GUID_DEVINTERFACE_DISK, OnErrorBehavior);
    return(error);
}

eErrorCode GetStorageDevicePaths( std::vector<String>& Paths, eOnErrorBehavior OnErrorBehavior )
{
    return( GetDevicePaths( Paths, &GUID_DEVINTERFACE_DISK, OnErrorBehavior ) );
}

eErrorCode GetDevicePaths( std::vector<String>& Paths, const GUID* InterfaceClassGUID, eOnErrorBehavior OnErrorBehavior )
{
    eErrorCode error = eErrorCode::None;

    sEnumerateDevicesCallback callBack;
    callBack.Data = (void*)&Paths;
    callBack.Function = [](void* Data, const HDEVINFO& DevInfoHandle, SP_DEVINFO_DATA& DevInfoData, SP_DEVICE_INTERFACE_DATA& DevInterfaceData, const PSP_INTERFACE_DEVICE_DETAIL_DATA& DevDetailData, U32 SizeOfDevDetailData, eErrorCode& ErrorCode)
    {
        std::vector<String>* paths = ( std::vector<String>* )Data;
        paths->push_back( DevDetailData->DevicePath );
    };

    error = EnumerateDevices( callBack, InterfaceClassGUID, OnErrorBehavior );
    return( error );
}

eErrorCode EnumerateDevices( sEnumerateDevicesCallback& Callback, const GUID* InterfaceClassGUID, eOnErrorBehavior OnErrorBehavior )
{
    HDEVINFO devInfoHandle =
        SetupDiGetClassDevs
        (
        InterfaceClassGUID,
        NULL,
        NULL,
        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
        );
    if ( INVALID_HANDLE_VALUE == devInfoHandle )
    {
        return( eErrorCode::Unknown );
    }

    DWORD error = 0;
    DWORD memberIndex = 0;
    while ( true == true )
    {
        SP_DEVICE_INTERFACE_DATA devInterfaceData;
        devInterfaceData.cbSize = sizeof( devInterfaceData );
        if ( SetupDiEnumDeviceInterfaces( devInfoHandle, NULL, InterfaceClassGUID, memberIndex++, &devInterfaceData ) == FALSE )
        {
            error = GetLastError();
            if ( ERROR_NO_MORE_ITEMS == error )
            {
                break;
            }
            else
            {
                SetupDiDestroyDeviceInfoList( devInfoHandle );
                return( eErrorCode::Unknown );
            }
        }

        DWORD bufferSize = 0;
        SP_DEVINFO_DATA devInfoData;
        devInfoData.cbSize = sizeof( devInfoData );

        // Get buffer size
        if ( SetupDiGetDeviceInterfaceDetail( devInfoHandle, &devInterfaceData, NULL, 0, &bufferSize, &devInfoData ) == FALSE )
        {
            error = GetLastError();
            if ( ERROR_INSUFFICIENT_BUFFER != error )
            {
                if ( eOnErrorBehavior::Continue == OnErrorBehavior ) { continue; }
                SetupDiDestroyDeviceInfoList( devInfoHandle );
                return( eErrorCode::Unknown );
            }
        }

        PSP_INTERFACE_DEVICE_DETAIL_DATA pDevDetailData = (PSP_INTERFACE_DEVICE_DETAIL_DATA)HeapAlloc( GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, bufferSize );
        if ( NULL == pDevDetailData )
        {
            if ( eOnErrorBehavior::Continue == OnErrorBehavior ) { continue; }
            SetupDiDestroyDeviceInfoList( devInfoHandle );
            return( eErrorCode::Memory );
        }
        pDevDetailData->cbSize = sizeof( SP_INTERFACE_DEVICE_DETAIL_DATA );

        if ( SetupDiGetDeviceInterfaceDetail( devInfoHandle, &devInterfaceData, pDevDetailData, bufferSize, NULL, NULL ) == FALSE )
        {
            error = GetLastError();
            if ( ERROR_INSUFFICIENT_BUFFER != error )
            {
                HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pDevDetailData);
                if ( eOnErrorBehavior::Continue == OnErrorBehavior ) { continue; }
                SetupDiDestroyDeviceInfoList( devInfoHandle );
                return( eErrorCode::Unknown );
            }
        }

        eErrorCode errorCode;
        errorCode = eErrorCode::Unknown;
        Callback.Function(Callback.Data, devInfoHandle, devInfoData, devInterfaceData, pDevDetailData, bufferSize, errorCode);

        HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pDevDetailData);
    }

    SetupDiDestroyDeviceInfoList( devInfoHandle );

    return( eErrorCode::None );
}

eErrorCode GetStorageAdapterProperty( HANDLE Handle, sStorageAdapterProperty& AdapterProperty )
{
    STORAGE_DESCRIPTOR_HEADER storageDescHeader;

    STORAGE_PROPERTY_QUERY StorageProperty;
    StorageProperty.PropertyId = StorageAdapterProperty;
    StorageProperty.QueryType = PropertyStandardQuery;

    DWORD bytesReturned;
    DWORD ret =
        DeviceIoControl(
                        Handle,
                        IOCTL_STORAGE_QUERY_PROPERTY,
                        &StorageProperty,
                        sizeof(STORAGE_PROPERTY_QUERY),
                        &storageDescHeader,
                        sizeof(STORAGE_DESCRIPTOR_HEADER),
                        &bytesReturned,
                        NULL
                        );
    if ( 0 == ret )
    {
        return( eErrorCode::Io );
    }

    if ( 0 == storageDescHeader.Size )
    {
        return( eErrorCode::Io );   //TODO: replace with more descriptive error
    }

    PSTORAGE_ADAPTER_DESCRIPTOR pstorageAdapterDesc = NULL;
    pstorageAdapterDesc = (PSTORAGE_ADAPTER_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, storageDescHeader.Size);

    ret =
        DeviceIoControl(
                        Handle,
                        IOCTL_STORAGE_QUERY_PROPERTY,
                        &StorageProperty,
                        sizeof(STORAGE_PROPERTY_QUERY),
                        pstorageAdapterDesc,
                        storageDescHeader.Size,
                        &bytesReturned,
                        NULL
                        );
    if (0 == ret)
    {
        HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pstorageAdapterDesc);
        return( eErrorCode::Io );
    }

    AdapterProperty.BusType = pstorageAdapterDesc->BusType;
    //iAdapterProperty.SrbType = pstorageAdapterDesc->SrbType;  TODO check this
    AdapterProperty.AlignmentMask = pstorageAdapterDesc->AlignmentMask;

    HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pstorageAdapterDesc);

    return( eErrorCode::None );
}

eErrorCode GetPhysicalDiskNumber(HANDLE Handle, U32& PhysicalDiskNumber)
{
    STORAGE_DEVICE_NUMBER storageDevice = { 0 };
    DWORD bytesReturned;
    DWORD ret =
        DeviceIoControl(
                        Handle,
                        IOCTL_STORAGE_GET_DEVICE_NUMBER,
                        NULL,
                        0,
                        &storageDevice,
                        sizeof(storageDevice),
                        &bytesReturned,
                        NULL
                        );
    if (0 == ret)
    {
        return(eErrorCode::Io);
    }

    PhysicalDiskNumber = storageDevice.DeviceNumber;
    return(eErrorCode::None);
}

void CloseDeviceHandle(HANDLE& Handle)
{
    if (FALSE == CloseHandle(Handle))
    {
        //! TODO
        //fprintf(stderr, "\nCloseDeviceHandle was not successful. Error Code: %d", GetLastError());
    }
    Handle = INVALID_HANDLE_VALUE;
}

bool IsAtaDeviceBus( sStorageAdapterProperty StorageDeviceProperty )
{
    switch ( StorageDeviceProperty.BusType )
    {
        case BusTypeAta:
        case BusTypeSata:
        {
            return( true );
        } break;
        default:
        {
            return( false );
        } break;
    }
}

bool IsScsiDeviceBus(sStorageAdapterProperty StorageDeviceProperty)
{
    switch (StorageDeviceProperty.BusType)
    {
        case BusTypeScsi:
        case BusTypeUsb:
        case BusTypeiScsi:
        {
            return( true );
        } break;
        default:
        {
            return( false );
        } break;
    }
}

}<commit_msg>Edit checking bus (for ata) to catch BusTypeRaid of devices when OS was set up to RAID mode<commit_after>/*
<License>
Copyright 2016 Virtium Technology

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http ://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
</License>
*/
#include <memory>

#include "Device.h"
#include "StorageUtility.h"

namespace vtStor
{

eErrorCode GetStorageDevices(std::vector<std::shared_ptr<IDevice>>& Devices, eOnErrorBehavior OnErrorBehavior)
{
    eErrorCode error = eErrorCode::None;

    sEnumerateDevicesCallback callBack;
    callBack.Data = (void*)&Devices;
    callBack.Function = [](void* Data, const HDEVINFO& DevInfoHandle, SP_DEVINFO_DATA& DevInfoData, SP_DEVICE_INTERFACE_DATA& DevInterfaceData, const PSP_INTERFACE_DEVICE_DETAIL_DATA& DevDetailData, U32 SizeOfDevDetailData, eErrorCode& ErrorCode)
    {
        std::vector<std::shared_ptr<vtStor::IDevice>>* devices = (std::vector<std::shared_ptr<vtStor::IDevice>>*)Data;
        devices->push_back(std::make_shared<cDevice>((SP_DEVINFO_DATA*)&DevInfoData, (SP_DEVICE_INTERFACE_DATA*)&DevInterfaceData, DevDetailData, SizeOfDevDetailData));
    };

    error = EnumerateDevices(callBack, &GUID_DEVINTERFACE_DISK, OnErrorBehavior);
    return(error);
}

eErrorCode GetStorageDevicePaths( std::vector<String>& Paths, eOnErrorBehavior OnErrorBehavior )
{
    return( GetDevicePaths( Paths, &GUID_DEVINTERFACE_DISK, OnErrorBehavior ) );
}

eErrorCode GetDevicePaths( std::vector<String>& Paths, const GUID* InterfaceClassGUID, eOnErrorBehavior OnErrorBehavior )
{
    eErrorCode error = eErrorCode::None;

    sEnumerateDevicesCallback callBack;
    callBack.Data = (void*)&Paths;
    callBack.Function = [](void* Data, const HDEVINFO& DevInfoHandle, SP_DEVINFO_DATA& DevInfoData, SP_DEVICE_INTERFACE_DATA& DevInterfaceData, const PSP_INTERFACE_DEVICE_DETAIL_DATA& DevDetailData, U32 SizeOfDevDetailData, eErrorCode& ErrorCode)
    {
        std::vector<String>* paths = ( std::vector<String>* )Data;
        paths->push_back( DevDetailData->DevicePath );
    };

    error = EnumerateDevices( callBack, InterfaceClassGUID, OnErrorBehavior );
    return( error );
}

eErrorCode EnumerateDevices( sEnumerateDevicesCallback& Callback, const GUID* InterfaceClassGUID, eOnErrorBehavior OnErrorBehavior )
{
    HDEVINFO devInfoHandle =
        SetupDiGetClassDevs
        (
        InterfaceClassGUID,
        NULL,
        NULL,
        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
        );
    if ( INVALID_HANDLE_VALUE == devInfoHandle )
    {
        return( eErrorCode::Unknown );
    }

    DWORD error = 0;
    DWORD memberIndex = 0;
    while ( true == true )
    {
        SP_DEVICE_INTERFACE_DATA devInterfaceData;
        devInterfaceData.cbSize = sizeof( devInterfaceData );
        if ( SetupDiEnumDeviceInterfaces( devInfoHandle, NULL, InterfaceClassGUID, memberIndex++, &devInterfaceData ) == FALSE )
        {
            error = GetLastError();
            if ( ERROR_NO_MORE_ITEMS == error )
            {
                break;
            }
            else
            {
                SetupDiDestroyDeviceInfoList( devInfoHandle );
                return( eErrorCode::Unknown );
            }
        }

        DWORD bufferSize = 0;
        SP_DEVINFO_DATA devInfoData;
        devInfoData.cbSize = sizeof( devInfoData );

        // Get buffer size
        if ( SetupDiGetDeviceInterfaceDetail( devInfoHandle, &devInterfaceData, NULL, 0, &bufferSize, &devInfoData ) == FALSE )
        {
            error = GetLastError();
            if ( ERROR_INSUFFICIENT_BUFFER != error )
            {
                if ( eOnErrorBehavior::Continue == OnErrorBehavior ) { continue; }
                SetupDiDestroyDeviceInfoList( devInfoHandle );
                return( eErrorCode::Unknown );
            }
        }

        PSP_INTERFACE_DEVICE_DETAIL_DATA pDevDetailData = (PSP_INTERFACE_DEVICE_DETAIL_DATA)HeapAlloc( GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, bufferSize );
        if ( NULL == pDevDetailData )
        {
            if ( eOnErrorBehavior::Continue == OnErrorBehavior ) { continue; }
            SetupDiDestroyDeviceInfoList( devInfoHandle );
            return( eErrorCode::Memory );
        }
        pDevDetailData->cbSize = sizeof( SP_INTERFACE_DEVICE_DETAIL_DATA );

        if ( SetupDiGetDeviceInterfaceDetail( devInfoHandle, &devInterfaceData, pDevDetailData, bufferSize, NULL, NULL ) == FALSE )
        {
            error = GetLastError();
            if ( ERROR_INSUFFICIENT_BUFFER != error )
            {
                HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pDevDetailData);
                if ( eOnErrorBehavior::Continue == OnErrorBehavior ) { continue; }
                SetupDiDestroyDeviceInfoList( devInfoHandle );
                return( eErrorCode::Unknown );
            }
        }

        eErrorCode errorCode;
        errorCode = eErrorCode::Unknown;
        Callback.Function(Callback.Data, devInfoHandle, devInfoData, devInterfaceData, pDevDetailData, bufferSize, errorCode);

        HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pDevDetailData);
    }

    SetupDiDestroyDeviceInfoList( devInfoHandle );

    return( eErrorCode::None );
}

eErrorCode GetStorageAdapterProperty( HANDLE Handle, sStorageAdapterProperty& AdapterProperty )
{
    STORAGE_DESCRIPTOR_HEADER storageDescHeader;

    STORAGE_PROPERTY_QUERY StorageProperty;
    StorageProperty.PropertyId = StorageAdapterProperty;
    StorageProperty.QueryType = PropertyStandardQuery;

    DWORD bytesReturned;
    DWORD ret =
        DeviceIoControl(
                        Handle,
                        IOCTL_STORAGE_QUERY_PROPERTY,
                        &StorageProperty,
                        sizeof(STORAGE_PROPERTY_QUERY),
                        &storageDescHeader,
                        sizeof(STORAGE_DESCRIPTOR_HEADER),
                        &bytesReturned,
                        NULL
                        );
    if ( 0 == ret )
    {
        return( eErrorCode::Io );
    }

    if ( 0 == storageDescHeader.Size )
    {
        return( eErrorCode::Io );   //TODO: replace with more descriptive error
    }

    PSTORAGE_ADAPTER_DESCRIPTOR pstorageAdapterDesc = NULL;
    pstorageAdapterDesc = (PSTORAGE_ADAPTER_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, storageDescHeader.Size);

    ret =
        DeviceIoControl(
                        Handle,
                        IOCTL_STORAGE_QUERY_PROPERTY,
                        &StorageProperty,
                        sizeof(STORAGE_PROPERTY_QUERY),
                        pstorageAdapterDesc,
                        storageDescHeader.Size,
                        &bytesReturned,
                        NULL
                        );
    if (0 == ret)
    {
        HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pstorageAdapterDesc);
        return( eErrorCode::Io );
    }

    AdapterProperty.BusType = pstorageAdapterDesc->BusType;
    //iAdapterProperty.SrbType = pstorageAdapterDesc->SrbType;  TODO check this
    AdapterProperty.AlignmentMask = pstorageAdapterDesc->AlignmentMask;

    HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pstorageAdapterDesc);

    return( eErrorCode::None );
}

eErrorCode GetPhysicalDiskNumber(HANDLE Handle, U32& PhysicalDiskNumber)
{
    STORAGE_DEVICE_NUMBER storageDevice = { 0 };
    DWORD bytesReturned;
    DWORD ret =
        DeviceIoControl(
                        Handle,
                        IOCTL_STORAGE_GET_DEVICE_NUMBER,
                        NULL,
                        0,
                        &storageDevice,
                        sizeof(storageDevice),
                        &bytesReturned,
                        NULL
                        );
    if (0 == ret)
    {
        return(eErrorCode::Io);
    }

    PhysicalDiskNumber = storageDevice.DeviceNumber;
    return(eErrorCode::None);
}

void CloseDeviceHandle(HANDLE& Handle)
{
    if (FALSE == CloseHandle(Handle))
    {
        //! TODO
        //fprintf(stderr, "\nCloseDeviceHandle was not successful. Error Code: %d", GetLastError());
    }
    Handle = INVALID_HANDLE_VALUE;
}

bool IsAtaDeviceBus( sStorageAdapterProperty StorageDeviceProperty )
{
    switch ( StorageDeviceProperty.BusType )
    {
        case BusTypeRAID:
        case BusTypeAta:
        case BusTypeSata:
        {
            return( true );
        } break;
        default:
        {
            return( false );
        } break;
    }
}

bool IsScsiDeviceBus(sStorageAdapterProperty StorageDeviceProperty)
{
    switch (StorageDeviceProperty.BusType)
    {
        case BusTypeScsi:
        case BusTypeUsb:
        case BusTypeiScsi:
        {
            return( true );
        } break;
        default:
        {
            return( false );
        } break;
    }
}

}<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Devices/OpenNI/OpenNIScaffold.h"

#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <OpenNI.h>

#include "SurgSim/DataStructures/DataGroup.h"
#include "SurgSim/DataStructures/DataGroupBuilder.h"
#include "SurgSim/Devices/OpenNI/OpenNIDevice.h"
#include "SurgSim/Framework/Barrier.h"
#include "SurgSim/Framework/Log.h"
#include "SurgSim/Framework/SharedInstance.h"

namespace SurgSim
{
namespace Device
{

struct OpenNIScaffold::DeviceData
{
	explicit DeviceData(OpenNIDevice* device) :
		deviceObject(device)
	{
	}

	/// OpenNI device
	openni::Device camera;
	/// OpenNI Depth Video Stream
	openni::VideoStream depthStream;
	/// OpenNI RGB Image Video Stream
	openni::VideoStream colorStream;
	/// The corresponding device object.
	OpenNIDevice* const deviceObject;
};

struct OpenNIScaffold::StateData
{
	/// The list of known devices.
	std::list<std::unique_ptr<DeviceData>> activeDevices;

	/// The mutex that protects the list of known devices.
	boost::mutex mutex;
};

OpenNIScaffold::OpenNIScaffold() :
	SurgSim::Framework::BasicThread("OpenNI Scaffold"),
	m_state(new StateData),
	m_logger(SurgSim::Framework::Logger::getLogger("OpenNI"))
{
	setRate(100);
}

OpenNIScaffold::~OpenNIScaffold()
{
	openni::OpenNI::shutdown();
}

bool OpenNIScaffold::registerDevice(OpenNIDevice* device)
{
	bool success = true;
	if (!isRunning())
	{
		std::shared_ptr<SurgSim::Framework::Barrier> barrier = std::make_shared<SurgSim::Framework::Barrier>(2);
		start(barrier);
		barrier->wait(true); // Wait for initialize
		barrier->wait(true); // Wait for startup
		success = isInitialized();
	}

	if (success)
	{
		boost::lock_guard<boost::mutex> lock(m_state->mutex);
		const std::string deviceName = device->getName();
		auto sameName = [&deviceName](const std::unique_ptr<DeviceData>& info)
		{
			return info->deviceObject->getName() == deviceName;
		};
		auto found = std::find_if(m_state->activeDevices.cbegin(), m_state->activeDevices.cend(), sameName);

		if (found == m_state->activeDevices.end())
		{
			std::unique_ptr<DeviceData> info(new DeviceData(device));
			success = doRegisterDevice(info.get());
			if (success)
			{
				SURGSIM_LOG_INFO(m_logger) << "Device " << device->getName() << ": Registered";
				m_state->activeDevices.emplace_back(std::move(info));
			}
		}
		else
		{
			SURGSIM_LOG_SEVERE(m_logger) << "Tried to register a device when the same name, '" <<
				device->getName() << "', is already present!";
			success = false;
		}
	}

	return success;
}

bool OpenNIScaffold::doRegisterDevice(DeviceData* info)
{
	openni::Status status;

	status = info->camera.open(openni::ANY_DEVICE);
	if (status != openni::STATUS_OK)
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Could not connect to a camera: " << openni::OpenNI::getExtendedError();
		return false;
	}

	status = info->depthStream.create(info->camera, openni::SENSOR_DEPTH);
	if (status != openni::STATUS_OK)
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Could not find depth stream: " << openni::OpenNI::getExtendedError();
		return false;
	}

	status = info->colorStream.create(info->camera, openni::SENSOR_COLOR);
	if (status != openni::STATUS_OK)
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Could find color image stream: " << openni::OpenNI::getExtendedError();
		return false;
	}

	status = info->depthStream.start();
	if (status != openni::STATUS_OK || !info->depthStream.isValid())
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Unable to start depth stream: " << openni::OpenNI::getExtendedError();
		return false;
	}

	status = info->colorStream.start();
	if (status != openni::STATUS_OK || !info->colorStream.isValid())
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Unable to start color image stream: " << openni::OpenNI::getExtendedError();
		return false;
	}
	return true;
}

bool OpenNIScaffold::unregisterDevice(const OpenNIDevice* device)
{
	bool success = true;
	{
		boost::lock_guard<boost::mutex> lock(m_state->mutex);

		auto sameDevice = [device](const std::unique_ptr<DeviceData>& info)
		{
			return info->deviceObject == device;
		};
		auto info = std::find_if(m_state->activeDevices.begin(), m_state->activeDevices.end(), sameDevice);
		if (info != m_state->activeDevices.end())
		{
			success = doUnregisterDevice((*info).get());
			if (success)
			{
				SURGSIM_LOG_INFO(m_logger) << "Device " << device->getName() << ": Unregistered";
				m_state->activeDevices.erase(info);
			}
		}
		else
		{
			SURGSIM_LOG_SEVERE(m_logger) << "Attempted to release a non-registered device named '" <<
				device->getName() << ".";
			success = false;
		}
	}

	if (success && isRunning() && m_state->activeDevices.size() == 0)
	{
		stop();
	}

	return success;
}

bool OpenNIScaffold::doUnregisterDevice(DeviceData* info)
{
	info->depthStream.destroy();
	info->colorStream.destroy();
	info->camera.close();
	return true;
}

bool OpenNIScaffold::doInitialize()
{
	openni::Status status = openni::OpenNI::initialize();
	bool success = (status == openni::STATUS_OK);
	SURGSIM_LOG_IF(!success, m_logger, SEVERE) << "Initialize failed: " << openni::OpenNI::getExtendedError();
	return success;
}

bool OpenNIScaffold::doStartUp()
{
	return true;
}

bool OpenNIScaffold::doUpdate(double dt)
{
	boost::lock_guard<boost::mutex> lock(m_state->mutex);

	openni::VideoFrameRef depthFrame;
	openni::VideoFrameRef colorFrame;
	typedef SurgSim::DataStructures::DataGroup::ImageType ImageType;

	for (auto info = m_state->activeDevices.begin();  info != m_state->activeDevices.end();  ++info)
	{
		bool newImages = false;
		SurgSim::DataStructures::DataGroup& inputData = (*info)->deviceObject->getInputData();

		if ((*info)->depthStream.readFrame(&depthFrame) == openni::STATUS_OK)
		{
			newImages = true;
			ImageType image(depthFrame.getWidth(), depthFrame.getHeight(), 1,
					reinterpret_cast<const unsigned short*>(depthFrame.getData()));
			image.getAsVector() *= (1.0f / 1000.0f); // OpenNI2 returns mm, convert to meters
			inputData.images().set("depth", std::move(image));
		}

		if ((*info)->colorStream.readFrame(&colorFrame) == openni::STATUS_OK)
		{
			newImages = true;
			ImageType image(colorFrame.getWidth(), colorFrame.getHeight(), 3,
					reinterpret_cast<const unsigned char*>(colorFrame.getData()));
			image.getAsVector() *= (1.0 / 256.0); // OpenNI returns colors between 0 and 255, scale values to 0..1
			inputData.images().set("color", std::move(image));
		}

		if (newImages)
		{
			(*info)->deviceObject->pushInput();
		}
	}
	return true;
}

std::shared_ptr<OpenNIScaffold> OpenNIScaffold::getOrCreateSharedInstance()
{
	static auto creator = []()
	{
		return std::shared_ptr<OpenNIScaffold>(new OpenNIScaffold);
	};
	static SurgSim::Framework::SharedInstance<OpenNIScaffold> sharedInstance(creator);
	return sharedInstance.get();
}

SurgSim::DataStructures::DataGroup OpenNIScaffold::buildDeviceInputData()
{
	SurgSim::DataStructures::DataGroupBuilder builder;
	builder.addImage("color");
	builder.addImage("depth");
	return builder.createData();
}

};  // namespace Device
};  // namespace SurgSim
<commit_msg>reset datagroup entry in OpenNI if no data<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Devices/OpenNI/OpenNIScaffold.h"

#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <OpenNI.h>

#include "SurgSim/DataStructures/DataGroup.h"
#include "SurgSim/DataStructures/DataGroupBuilder.h"
#include "SurgSim/Devices/OpenNI/OpenNIDevice.h"
#include "SurgSim/Framework/Barrier.h"
#include "SurgSim/Framework/Log.h"
#include "SurgSim/Framework/SharedInstance.h"

namespace SurgSim
{
namespace Device
{

struct OpenNIScaffold::DeviceData
{
	explicit DeviceData(OpenNIDevice* device) :
		deviceObject(device)
	{
	}

	/// OpenNI device
	openni::Device camera;
	/// OpenNI Depth Video Stream
	openni::VideoStream depthStream;
	/// OpenNI RGB Image Video Stream
	openni::VideoStream colorStream;
	/// The corresponding device object.
	OpenNIDevice* const deviceObject;
};

struct OpenNIScaffold::StateData
{
	/// The list of known devices.
	std::list<std::unique_ptr<DeviceData>> activeDevices;

	/// The mutex that protects the list of known devices.
	boost::mutex mutex;
};

OpenNIScaffold::OpenNIScaffold() :
	SurgSim::Framework::BasicThread("OpenNI Scaffold"),
	m_state(new StateData),
	m_logger(SurgSim::Framework::Logger::getLogger("OpenNI"))
{
	setRate(100);
}

OpenNIScaffold::~OpenNIScaffold()
{
	openni::OpenNI::shutdown();
}

bool OpenNIScaffold::registerDevice(OpenNIDevice* device)
{
	bool success = true;
	if (!isRunning())
	{
		std::shared_ptr<SurgSim::Framework::Barrier> barrier = std::make_shared<SurgSim::Framework::Barrier>(2);
		start(barrier);
		barrier->wait(true); // Wait for initialize
		barrier->wait(true); // Wait for startup
		success = isInitialized();
	}

	if (success)
	{
		boost::lock_guard<boost::mutex> lock(m_state->mutex);
		const std::string deviceName = device->getName();
		auto sameName = [&deviceName](const std::unique_ptr<DeviceData>& info)
		{
			return info->deviceObject->getName() == deviceName;
		};
		auto found = std::find_if(m_state->activeDevices.cbegin(), m_state->activeDevices.cend(), sameName);

		if (found == m_state->activeDevices.end())
		{
			std::unique_ptr<DeviceData> info(new DeviceData(device));
			success = doRegisterDevice(info.get());
			if (success)
			{
				SURGSIM_LOG_INFO(m_logger) << "Device " << device->getName() << ": Registered";
				m_state->activeDevices.emplace_back(std::move(info));
			}
		}
		else
		{
			SURGSIM_LOG_SEVERE(m_logger) << "Tried to register a device when the same name, '" <<
				device->getName() << "', is already present!";
			success = false;
		}
	}

	return success;
}

bool OpenNIScaffold::doRegisterDevice(DeviceData* info)
{
	openni::Status status;

	status = info->camera.open(openni::ANY_DEVICE);
	if (status != openni::STATUS_OK)
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Could not connect to a camera: " << openni::OpenNI::getExtendedError();
		return false;
	}

	status = info->depthStream.create(info->camera, openni::SENSOR_DEPTH);
	if (status != openni::STATUS_OK)
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Could not find depth stream: " << openni::OpenNI::getExtendedError();
		return false;
	}

	status = info->colorStream.create(info->camera, openni::SENSOR_COLOR);
	if (status != openni::STATUS_OK)
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Could find color image stream: " << openni::OpenNI::getExtendedError();
		return false;
	}

	status = info->depthStream.start();
	if (status != openni::STATUS_OK || !info->depthStream.isValid())
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Unable to start depth stream: " << openni::OpenNI::getExtendedError();
		return false;
	}

	status = info->colorStream.start();
	if (status != openni::STATUS_OK || !info->colorStream.isValid())
	{
		SURGSIM_LOG_SEVERE(m_logger) << "Unable to start color image stream: " << openni::OpenNI::getExtendedError();
		return false;
	}
	return true;
}

bool OpenNIScaffold::unregisterDevice(const OpenNIDevice* device)
{
	bool success = true;
	{
		boost::lock_guard<boost::mutex> lock(m_state->mutex);

		auto sameDevice = [device](const std::unique_ptr<DeviceData>& info)
		{
			return info->deviceObject == device;
		};
		auto info = std::find_if(m_state->activeDevices.begin(), m_state->activeDevices.end(), sameDevice);
		if (info != m_state->activeDevices.end())
		{
			success = doUnregisterDevice((*info).get());
			if (success)
			{
				SURGSIM_LOG_INFO(m_logger) << "Device " << device->getName() << ": Unregistered";
				m_state->activeDevices.erase(info);
			}
		}
		else
		{
			SURGSIM_LOG_SEVERE(m_logger) << "Attempted to release a non-registered device named '" <<
				device->getName() << ".";
			success = false;
		}
	}

	if (success && isRunning() && m_state->activeDevices.size() == 0)
	{
		stop();
	}

	return success;
}

bool OpenNIScaffold::doUnregisterDevice(DeviceData* info)
{
	info->depthStream.destroy();
	info->colorStream.destroy();
	info->camera.close();
	return true;
}

bool OpenNIScaffold::doInitialize()
{
	openni::Status status = openni::OpenNI::initialize();
	bool success = (status == openni::STATUS_OK);
	SURGSIM_LOG_IF(!success, m_logger, SEVERE) << "Initialize failed: " << openni::OpenNI::getExtendedError();
	return success;
}

bool OpenNIScaffold::doStartUp()
{
	return true;
}

bool OpenNIScaffold::doUpdate(double dt)
{
	boost::lock_guard<boost::mutex> lock(m_state->mutex);

	openni::VideoFrameRef depthFrame;
	openni::VideoFrameRef colorFrame;
	typedef SurgSim::DataStructures::DataGroup::ImageType ImageType;

	for (auto info = m_state->activeDevices.begin();  info != m_state->activeDevices.end();  ++info)
	{
		SurgSim::DataStructures::DataGroup& inputData = (*info)->deviceObject->getInputData();

		if ((*info)->depthStream.readFrame(&depthFrame) == openni::STATUS_OK)
		{
			ImageType image(depthFrame.getWidth(), depthFrame.getHeight(), 1,
					reinterpret_cast<const unsigned short*>(depthFrame.getData()));
			image.getAsVector() *= (1.0f / 1000.0f); // OpenNI2 returns mm, convert to meters
			inputData.images().set("depth", std::move(image));
		}
		else
		{
			inputData.images().reset("depth");
		}

		if ((*info)->colorStream.readFrame(&colorFrame) == openni::STATUS_OK)
		{
			ImageType image(colorFrame.getWidth(), colorFrame.getHeight(), 3,
					reinterpret_cast<const unsigned char*>(colorFrame.getData()));
			image.getAsVector() *= (1.0f / 255.0f); // OpenNI returns colors between 0 and 255, scale values to 0..1
			inputData.images().set("color", std::move(image));
		}
		else
		{
			inputData.images().reset("color");
		}

		(*info)->deviceObject->pushInput();
	}
	return true;
}

std::shared_ptr<OpenNIScaffold> OpenNIScaffold::getOrCreateSharedInstance()
{
	static auto creator = []()
	{
		return std::shared_ptr<OpenNIScaffold>(new OpenNIScaffold);
	};
	static SurgSim::Framework::SharedInstance<OpenNIScaffold> sharedInstance(creator);
	return sharedInstance.get();
}

SurgSim::DataStructures::DataGroup OpenNIScaffold::buildDeviceInputData()
{
	SurgSim::DataStructures::DataGroupBuilder builder;
	builder.addImage("color");
	builder.addImage("depth");
	return builder.createData();
}

};  // namespace Device
};  // namespace SurgSim
<|endoftext|>