<commit_before>#ifdef USE_ALLEGRO
#include <allegro.h>
#endif
#include "music-player.h"
#include "globals.h"
#include <iostream>
#include "configuration.h"
#include "sound.h"

#include "dumb/include/dumb.h"
#include "gme/Music_Emu.h"

#ifdef USE_ALLEGRO
#include "dumb/include/aldumb.h"
#include "ogg/logg.h"

#ifdef _WIN32
/* what do we need winalleg for?
 * reason: ...
 */
#include <winalleg.h>
#endif

#endif

#ifdef USE_SDL
#include "sdl/mixer/SDL_mixer.h"
#endif

#include "exceptions/exception.h"
#include <sstream>

namespace Util{

class MusicException: public Exception::Base {
public:
    MusicException(const std::string & file, int line, const std::string & reason):
        Exception::Base(file, line),
        reason(reason){
        }

    MusicException(const MusicException & copy):
    Exception::Base(copy),
    reason(copy.reason){
    }

    virtual ~MusicException() throw(){
    }

protected:
    virtual const std::string getReason() const {
        return reason;
    }

    virtual Exception::Base * copy() const {
        return new MusicException(*this);
    }

    std::string reason;
};

static double scaleVolume(double start){
    return start;
}

MusicPlayer::MusicPlayer():
volume(1.0){
}

MusicPlayer::~MusicPlayer(){
}

static const char * typeToExtension( int i ){
    switch (i){
        case 0 : return ".xm";
        case 1 : return ".s3m";
        case 2 : return ".it";
        case 3 : return ".mod";
        default : return "";
    }
}

DUH * DumbPlayer::loadDumbFile(const char * path){
    DUH * what;
    for (int i = 0; i < 4; i++){
        /* the order of trying xm/s3m/it/mod matters because mod could be
         * confused with one of the other formats, so load it last.
         */
        switch (i){
            case 0 : {
                 what =  dumb_load_xm_quick(path);
                 break;
            }
            case 1 : {
                what = dumb_load_s3m_quick(path);
                break;
            }
            case 2 : {
                what = dumb_load_it_quick(path);
                break;
            }
            case 3 : {
                what = dumb_load_mod_quick(path);
                break;
            }
        }

        if (what != NULL){
            Global::debug(0) << "Loaded " << path << " type " << typeToExtension(i) << "(" << i << ")" << std::endl;
            return what;
        }
    }
    return NULL;
}

#ifdef USE_ALLEGRO

DumbPlayer::DumbPlayer(const char * path){
    music_file = loadDumbFile(path);
    if (music_file != NULL){
        int buf = 1 << 11;
        player = al_start_duh(music_file, 2, 0, scaleVolume(volume), buf, Sound::FREQUENCY);
    } else {
        std::ostringstream error;
        error << "Could not DUMB file load " << path;
        throw MusicException(__FILE__, __LINE__, error.str());
    }
}

void DumbPlayer::play(){
    al_resume_duh(this->player);
}

void DumbPlayer::poll(){
    if (al_poll_duh(this->player) != 0){
    }
}

void DumbPlayer::pause(){
    al_pause_duh(this->player);
}

void DumbPlayer::setVolume(double volume){
    this->volume = volume;
    al_duh_set_volume(player, scaleVolume(volume));
}

DumbPlayer::~DumbPlayer(){
    al_stop_duh(player);
    unload_duh(music_file);
}

static const int GME_BUFFER_SIZE = 1 << 11;
GMEPlayer::GMEPlayer(const char * path){
    gme_err_t fail = gme_open_file(path, &emulator, Sound::FREQUENCY);
    if (fail != NULL){
        Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
        throw MusicException(__FILE__, __LINE__, "Could not load GME file");
    }
    emulator->start_track(0);
    Global::debug(0) << "Loaded GME file " << path << std::endl;

    stream = play_audio_stream(GME_BUFFER_SIZE, 16, 1, Sound::FREQUENCY, 255, 128);
    voice_set_priority(stream->voice, 255);
}

void GMEPlayer::play(){
    voice_start(stream->voice);
}

void GMEPlayer::poll(){
    short * buffer = (short*) get_audio_stream_buffer(stream);
    if (buffer){
        /* size in 16-bit samples is buffer size * channels */
        emulator->play(GME_BUFFER_SIZE * 2, buffer);
        if (emulator->track_ended()){
            gme_info_t * info;
            gme_track_info(emulator, &info, 0);
            int intro = info->intro_length;
            emulator->start_track(0);
            // Global::debug(0) << "Seeking " << intro << "ms. Track length " << info->length << "ms" << std::endl;
            /* skip past the intro if there is a loop */
            if (info->loop_length != 0){
                emulator->seek(intro);
            }
        }

        /* allegro wants unsigned data but gme produces signed so to convert
         * signed samples to unsigned samples we have to raise each value
         * by half the maximum value of a short (0xffff+1)/2 = 0x8000
         */
        for (int i = 0; i < GME_BUFFER_SIZE * 2; i++){
            buffer[i] += 0x8000;
        }

        free_audio_stream_buffer(stream);
    }
}

void GMEPlayer::pause(){
    voice_stop(stream->voice);
}

void GMEPlayer::setVolume(double volume){
    /* FIXME */
}

GMEPlayer::~GMEPlayer(){
    delete emulator;
    stop_audio_stream(stream);
}

#ifdef HAVE_OGG
OggPlayer::OggPlayer(const char * path){
    stream = logg_get_stream(path, scaleVolume(volume) * 255, 128, 1);
    if (stream == NULL){
        throw MusicException(__FILE__, __LINE__, "Could not load ogg file");
    }
}

void OggPlayer::play(){
}

void OggPlayer::poll(){
    logg_update_stream(stream);
}

void OggPlayer::pause(){
}

void OggPlayer::setVolume(double volume){
}

OggPlayer::~OggPlayer(){
    logg_destroy_stream(stream);
}
#endif /* OGG */

#endif /* ALlEGRO */

#ifdef USE_SDL
DumbPlayer::DumbPlayer(const char * path){
    music_file = loadDumbFile(path);
    if (music_file == NULL){
        std::ostringstream error;
        error << "Could not load DUMB file " << path;
        throw MusicException(__FILE__, __LINE__, error.str());
    }

    int n_channels = 2;
    int position = 0;
    renderer = duh_start_sigrenderer(music_file, 0, n_channels, position);
    if (!renderer){
        Global::debug(0) << "Could not create renderer" << std::endl;
        throw Exception::Base(__FILE__, __LINE__);
    }
}

void DumbPlayer::render(Uint8 * stream, int length){
    double delta = 65536.0 / Sound::FREQUENCY;

    /* a frame is 32 bits, 16 bit samples with 2 channels = 2 * 16,
     * so we have to divide the number of 'dumb samples' by the
     * size of each frame, 32 bits = 4 bytes
     */
    /* FIXME: use global music volume to scale the output here */
    int n = duh_render(renderer, 16, 0, volume, delta, length / 4, stream);

    if (n == 0){
        Global::debug(0) << "Sound finished?" << std::endl;
    }

    /*
    short large = 0;
    for (int i = 0; i < length / 2; i++){
        short z = ((short *) stream)[i];
        if (z < 0){
            z = -z;
        }
        if (z > large){
            large = z;
        }
    }
    Global::debug(0) << "Largest amplitude " << large << std::endl;
    */
}

struct DumbPlayerInfo{
    MusicPlayer * who;
};

void DumbPlayer::mixer(void * player_, Uint8 * stream, int length){
    DumbPlayerInfo * info = (DumbPlayerInfo *) player_;
    DumbPlayer * player = (DumbPlayer *) info->who;
    player->render(stream, length);
}

void DumbPlayer::pause(){
    Mix_HookMusic(NULL, NULL);
}

void DumbPlayer::play(){
    DumbPlayerInfo * me = new DumbPlayerInfo;
    me->who = this;
    Mix_HookMusic(mixer, me);
}

void DumbPlayer::poll(){
}

/* volume should be in the range 0.0 to 1.0 */
void DumbPlayer::setVolume(double volume){
    this->volume = volume;
    /* Mix_VolumeMusic only handles volume for formats it handles natively.
     * for custom formats (like all these players) we have to handle volume
     * ourselves.
     */
    // Mix_VolumeMusic(MIX_MAX_VOLUME * volume);
}

DumbPlayer::~DumbPlayer(){
    DumbPlayerInfo * info = (DumbPlayerInfo*) Mix_GetMusicHookData();
    Mix_HookMusic(NULL, NULL);
    if (info != NULL){
        delete info;
    }
    /* I'm pretty sure if we get this far then there is no chance
     * that our mixer function will still be active.
     */
    duh_end_sigrenderer(renderer);
    unload_duh(music_file);
}

struct GMEInfo{
    GMEPlayer * player;
};

GMEPlayer::GMEPlayer(const char * path){
    gme_err_t fail = gme_open_file(path, &emulator, Sound::FREQUENCY);
    if (fail != NULL){
        Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
        throw MusicException(__FILE__, __LINE__, "Could not load GME file");
    }
    emulator->start_track(0);
    Global::debug(0) << "Loaded GME file " << path << std::endl;
}

void GMEPlayer::mixer(void * arg, Uint8 * stream, int length){
    GMEInfo * info = (GMEInfo*) arg;
    info->player->render(stream, length);
}

void GMEPlayer::render(Uint8 * stream, int length){
    /* length/2 to convert bytes to short */
    emulator->play(length / 2, (short*) stream);

    /* scale for volume */
    for (int i = 0; i < length / 2; i++){
        short & sample = ((short *) stream)[i];
        sample *= volume;
    }

    /*
    short large = 0;
    short small = 0;
    for (int i = 0; i < length / 2; i++){
        // ((short *) stream)[i] *= 2;
        short z = ((short *) stream)[i];
        if (z < small){
            small = z;
        }
        if (z > large){
            large = z;
        }
    }
    Global::debug(0) << "Largest " << large << " Smallest " << small << std::endl;
    */
}

void GMEPlayer::play(){
    GMEInfo * me = new GMEInfo;
    me->player = this;
    Mix_HookMusic(mixer, me);
}

void GMEPlayer::poll(){
}

void GMEPlayer::pause(){
}

void GMEPlayer::setVolume(double volume){
    this->volume = volume;
    // Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
}

GMEPlayer::~GMEPlayer(){
    GMEInfo * info = (GMEInfo*) Mix_GetMusicHookData();
    Mix_HookMusic(NULL, NULL);
    if (info != NULL){
        delete info;
    }
    delete emulator;
}

#ifdef HAVE_OGG

OggPlayer::OggPlayer(const char * path){
    music = Mix_LoadMUS(path);
    if (music == NULL){
        throw MusicException(__FILE__, __LINE__, "Could not load OGG file");
    }
}

void OggPlayer::play(){
    Mix_PlayMusic(music, -1);
}

void OggPlayer::poll(){
}

void OggPlayer::pause(){
    Mix_PauseMusic();
}

void OggPlayer::setVolume(double volume){
    this->volume = volume;
    Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
}

OggPlayer::~OggPlayer(){
    Mix_FreeMusic(music);
}

#endif /* OGG */

#endif /* SDL */

}
<commit_msg>set volume for allegro gme player<commit_after>#ifdef USE_ALLEGRO
#include <allegro.h>
#endif
#include "music-player.h"
#include "globals.h"
#include <iostream>
#include "configuration.h"
#include "sound.h"

#include "dumb/include/dumb.h"
#include "gme/Music_Emu.h"

#ifdef USE_ALLEGRO
#include "dumb/include/aldumb.h"
#include "ogg/logg.h"

#ifdef _WIN32
/* what do we need winalleg for?
 * reason: ...
 */
#include <winalleg.h>
#endif

#endif

#ifdef USE_SDL
#include "sdl/mixer/SDL_mixer.h"
#endif

#include "exceptions/exception.h"
#include <sstream>

namespace Util{

class MusicException: public Exception::Base {
public:
    MusicException(const std::string & file, int line, const std::string & reason):
        Exception::Base(file, line),
        reason(reason){
        }

    MusicException(const MusicException & copy):
    Exception::Base(copy),
    reason(copy.reason){
    }

    virtual ~MusicException() throw(){
    }

protected:
    virtual const std::string getReason() const {
        return reason;
    }

    virtual Exception::Base * copy() const {
        return new MusicException(*this);
    }

    std::string reason;
};

static double scaleVolume(double start){
    return start;
}

MusicPlayer::MusicPlayer():
volume(1.0){
}

MusicPlayer::~MusicPlayer(){
}

static const char * typeToExtension( int i ){
    switch (i){
        case 0 : return ".xm";
        case 1 : return ".s3m";
        case 2 : return ".it";
        case 3 : return ".mod";
        default : return "";
    }
}

DUH * DumbPlayer::loadDumbFile(const char * path){
    DUH * what;
    for (int i = 0; i < 4; i++){
        /* the order of trying xm/s3m/it/mod matters because mod could be
         * confused with one of the other formats, so load it last.
         */
        switch (i){
            case 0 : {
                 what =  dumb_load_xm_quick(path);
                 break;
            }
            case 1 : {
                what = dumb_load_s3m_quick(path);
                break;
            }
            case 2 : {
                what = dumb_load_it_quick(path);
                break;
            }
            case 3 : {
                what = dumb_load_mod_quick(path);
                break;
            }
        }

        if (what != NULL){
            Global::debug(0) << "Loaded " << path << " type " << typeToExtension(i) << "(" << i << ")" << std::endl;
            return what;
        }
    }
    return NULL;
}

#ifdef USE_ALLEGRO

DumbPlayer::DumbPlayer(const char * path){
    music_file = loadDumbFile(path);
    if (music_file != NULL){
        int buf = 1 << 11;
        player = al_start_duh(music_file, 2, 0, scaleVolume(volume), buf, Sound::FREQUENCY);
    } else {
        std::ostringstream error;
        error << "Could not DUMB file load " << path;
        throw MusicException(__FILE__, __LINE__, error.str());
    }
}

void DumbPlayer::play(){
    al_resume_duh(this->player);
}

void DumbPlayer::poll(){
    if (al_poll_duh(this->player) != 0){
    }
}

void DumbPlayer::pause(){
    al_pause_duh(this->player);
}

void DumbPlayer::setVolume(double volume){
    this->volume = volume;
    al_duh_set_volume(player, scaleVolume(volume));
}

DumbPlayer::~DumbPlayer(){
    al_stop_duh(player);
    unload_duh(music_file);
}

static const int GME_BUFFER_SIZE = 1 << 11;
GMEPlayer::GMEPlayer(const char * path){
    gme_err_t fail = gme_open_file(path, &emulator, Sound::FREQUENCY);
    if (fail != NULL){
        Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
        throw MusicException(__FILE__, __LINE__, "Could not load GME file");
    }
    emulator->start_track(0);
    Global::debug(0) << "Loaded GME file " << path << std::endl;

    stream = play_audio_stream(GME_BUFFER_SIZE, 16, 1, Sound::FREQUENCY, 255, 128);
    voice_set_priority(stream->voice, 255);
}

void GMEPlayer::play(){
    voice_start(stream->voice);
}

void GMEPlayer::poll(){
    short * buffer = (short*) get_audio_stream_buffer(stream);
    if (buffer){
        /* size in 16-bit samples is buffer size * channels */
        emulator->play(GME_BUFFER_SIZE * 2, buffer);
        if (emulator->track_ended()){
            gme_info_t * info;
            gme_track_info(emulator, &info, 0);
            int intro = info->intro_length;
            emulator->start_track(0);
            // Global::debug(0) << "Seeking " << intro << "ms. Track length " << info->length << "ms" << std::endl;
            /* skip past the intro if there is a loop */
            if (info->loop_length != 0){
                emulator->seek(intro);
            }
        }

        /* allegro wants unsigned data but gme produces signed so to convert
         * signed samples to unsigned samples we have to raise each value
         * by half the maximum value of a short (0xffff+1)/2 = 0x8000
         */
        for (int i = 0; i < GME_BUFFER_SIZE * 2; i++){
            buffer[i] *= volume;
            buffer[i] += 0x8000;
        }

        free_audio_stream_buffer(stream);
    }
}

void GMEPlayer::pause(){
    voice_stop(stream->voice);
}

void GMEPlayer::setVolume(double volume){
    this->volume = volume;
}

GMEPlayer::~GMEPlayer(){
    delete emulator;
    stop_audio_stream(stream);
}

#ifdef HAVE_OGG
OggPlayer::OggPlayer(const char * path){
    stream = logg_get_stream(path, scaleVolume(volume) * 255, 128, 1);
    if (stream == NULL){
        throw MusicException(__FILE__, __LINE__, "Could not load ogg file");
    }
}

void OggPlayer::play(){
}

void OggPlayer::poll(){
    logg_update_stream(stream);
}

void OggPlayer::pause(){
}

void OggPlayer::setVolume(double volume){
}

OggPlayer::~OggPlayer(){
    logg_destroy_stream(stream);
}
#endif /* OGG */

#endif /* ALlEGRO */

#ifdef USE_SDL
DumbPlayer::DumbPlayer(const char * path){
    music_file = loadDumbFile(path);
    if (music_file == NULL){
        std::ostringstream error;
        error << "Could not load DUMB file " << path;
        throw MusicException(__FILE__, __LINE__, error.str());
    }

    int n_channels = 2;
    int position = 0;
    renderer = duh_start_sigrenderer(music_file, 0, n_channels, position);
    if (!renderer){
        Global::debug(0) << "Could not create renderer" << std::endl;
        throw Exception::Base(__FILE__, __LINE__);
    }
}

void DumbPlayer::render(Uint8 * stream, int length){
    double delta = 65536.0 / Sound::FREQUENCY;

    /* a frame is 32 bits, 16 bit samples with 2 channels = 2 * 16,
     * so we have to divide the number of 'dumb samples' by the
     * size of each frame, 32 bits = 4 bytes
     */
    /* FIXME: use global music volume to scale the output here */
    int n = duh_render(renderer, 16, 0, volume, delta, length / 4, stream);

    if (n == 0){
        Global::debug(0) << "Sound finished?" << std::endl;
    }

    /*
    short large = 0;
    for (int i = 0; i < length / 2; i++){
        short z = ((short *) stream)[i];
        if (z < 0){
            z = -z;
        }
        if (z > large){
            large = z;
        }
    }
    Global::debug(0) << "Largest amplitude " << large << std::endl;
    */
}

struct DumbPlayerInfo{
    MusicPlayer * who;
};

void DumbPlayer::mixer(void * player_, Uint8 * stream, int length){
    DumbPlayerInfo * info = (DumbPlayerInfo *) player_;
    DumbPlayer * player = (DumbPlayer *) info->who;
    player->render(stream, length);
}

void DumbPlayer::pause(){
    Mix_HookMusic(NULL, NULL);
}

void DumbPlayer::play(){
    DumbPlayerInfo * me = new DumbPlayerInfo;
    me->who = this;
    Mix_HookMusic(mixer, me);
}

void DumbPlayer::poll(){
}

/* volume should be in the range 0.0 to 1.0 */
void DumbPlayer::setVolume(double volume){
    this->volume = volume;
    /* Mix_VolumeMusic only handles volume for formats it handles natively.
     * for custom formats (like all these players) we have to handle volume
     * ourselves.
     */
    // Mix_VolumeMusic(MIX_MAX_VOLUME * volume);
}

DumbPlayer::~DumbPlayer(){
    DumbPlayerInfo * info = (DumbPlayerInfo*) Mix_GetMusicHookData();
    Mix_HookMusic(NULL, NULL);
    if (info != NULL){
        delete info;
    }
    /* I'm pretty sure if we get this far then there is no chance
     * that our mixer function will still be active.
     */
    duh_end_sigrenderer(renderer);
    unload_duh(music_file);
}

struct GMEInfo{
    GMEPlayer * player;
};

GMEPlayer::GMEPlayer(const char * path){
    gme_err_t fail = gme_open_file(path, &emulator, Sound::FREQUENCY);
    if (fail != NULL){
        Global::debug(0) << "GME load error for " << path << ": " << fail << std::endl;
        throw MusicException(__FILE__, __LINE__, "Could not load GME file");
    }
    emulator->start_track(0);
    Global::debug(0) << "Loaded GME file " << path << std::endl;
}

void GMEPlayer::mixer(void * arg, Uint8 * stream, int length){
    GMEInfo * info = (GMEInfo*) arg;
    info->player->render(stream, length);
}

void GMEPlayer::render(Uint8 * stream, int length){
    /* length/2 to convert bytes to short */
    emulator->play(length / 2, (short*) stream);

    /* scale for volume */
    for (int i = 0; i < length / 2; i++){
        short & sample = ((short *) stream)[i];
        sample *= volume;
    }

    /*
    short large = 0;
    short small = 0;
    for (int i = 0; i < length / 2; i++){
        // ((short *) stream)[i] *= 2;
        short z = ((short *) stream)[i];
        if (z < small){
            small = z;
        }
        if (z > large){
            large = z;
        }
    }
    Global::debug(0) << "Largest " << large << " Smallest " << small << std::endl;
    */
}

void GMEPlayer::play(){
    GMEInfo * me = new GMEInfo;
    me->player = this;
    Mix_HookMusic(mixer, me);
}

void GMEPlayer::poll(){
}

void GMEPlayer::pause(){
}

void GMEPlayer::setVolume(double volume){
    this->volume = volume;
    // Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
}

GMEPlayer::~GMEPlayer(){
    GMEInfo * info = (GMEInfo*) Mix_GetMusicHookData();
    Mix_HookMusic(NULL, NULL);
    if (info != NULL){
        delete info;
    }
    delete emulator;
}

#ifdef HAVE_OGG

OggPlayer::OggPlayer(const char * path){
    music = Mix_LoadMUS(path);
    if (music == NULL){
        throw MusicException(__FILE__, __LINE__, "Could not load OGG file");
    }
}

void OggPlayer::play(){
    Mix_PlayMusic(music, -1);
}

void OggPlayer::poll(){
}

void OggPlayer::pause(){
    Mix_PauseMusic();
}

void OggPlayer::setVolume(double volume){
    this->volume = volume;
    Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
}

OggPlayer::~OggPlayer(){
    Mix_FreeMusic(music);
}

#endif /* OGG */

#endif /* SDL */

}
<|endoftext|>


<commit_before>//
// Created by manuel on 08.06.15.
//

#include "AssemblyParser.h"
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
#include <bitset>
#include <cstdint>

const std::string AssemblyParser::ROUTINE_DIRECTIVE = ".FUNCT";
const std::string AssemblyParser::GVAR_DIRECTIVE = ".GVAR";

const std::string AssemblyParser::NEW_LINE_COMMAND = "new_line";
const std::string AssemblyParser::PRINT_COMMAND = "print";
const std::string AssemblyParser::JE_COMMAND = "je";
const std::string AssemblyParser::QUIT_COMMAND = "quit";
const std::string AssemblyParser::READ_CHAR_COMMAND = "read_char";
const std::string AssemblyParser::CALL_COMMAND = "call";
const std::string AssemblyParser::JUMP_COMMAND = "jump";

const char AssemblyParser::SPLITTER_BETWEEN_LEXEMES_IN_AN_COMMAND = ' '; // 9 is ascii for tab
const char AssemblyParser::STRING_IDENTIFIER = '\"'; // 9 is ascii for tab
const std::string AssemblyParser::ASSIGNMENT_OPERATOR = "->";

std::string trim(const std::string& str,
                 const std::string& whitespace = " \t")
{
    const auto strBegin = str.find_first_not_of(whitespace);
    if (strBegin == std::string::npos)
        return ""; // no content

    const auto strEnd = str.find_last_not_of(whitespace);
    const auto strRange = strEnd - strBegin + 1;

    return str.substr(strBegin, strRange);
}

void AssemblyParser::readAssembly(std::istream& input, std::vector <std::bitset<8>> &highMemoryZcode,
                                  size_t offset) {

    std::cout << "Compiler: Parse Assembly File\n";

    for(std::string line; getline(input, line);) {
        std::vector<std::string> lineComps;
        this->split(line, SPLITTER_BETWEEN_LEXEMES_IN_AN_COMMAND, lineComps);
        if(lineComps.size()) {
            std::string firstComp = lineComps.at(0);

            if(line.at(0) == '.') { // directive
                if(firstComp.compare(ROUTINE_DIRECTIVE) == 0) {
                    std::cout << "found routine" << std::endl;

                    if(lineComps.size() < 2) {
                        std::cerr << "invalid routine declaration" << std::endl;
                        throw;
                    }

                    // currentGenerator exists, so we can get its code
                    if(currentGenerator) {
                        finishRoutine(highMemoryZcode);
                    }

                    std::string routineName = lineComps.at(1);

                    currentGenerator.reset(new RoutineGenerator(routineName, 0, highMemoryZcode, offset));
                } else if(firstComp.compare(GVAR_DIRECTIVE) == 0) {
                    std::cout << "found gvar" << std::endl;

                    this->split(line, SPLITTER_BETWEEN_LEXEMES_IN_AN_COMMAND, lineComps);
                    if(lineComps.size() < 2) {
                        std::cerr << "empty gvar declaration" << std::endl;
                    }

                    std::string gvar = lineComps.at(1);

                    addGlobal(gvar);
                }
            } else { // normal instruction
                // check for label
                auto pos = line.find(":");
                if(pos != std::string::npos) {
                    std::cout << ":::::: new label: ";
                    std::string labelName = line.substr(0, pos);
                    currentGenerator->newLabel(labelName);
                    std::cout << labelName << std::endl;

                    std::string afterLabel = line.substr(pos + 1, line.length() - 1);
                    executeCommand(afterLabel, *currentGenerator);
                } else {
                    executeCommand(line, *currentGenerator);
                }
            }
        }
    }

    if(currentGenerator) {
        finishRoutine(highMemoryZcode);
    }
}

void AssemblyParser::finishRoutine(std::vector <std::bitset<8>> &highMemoryZcode) {
    std::cout << "adding routine to zcode" << std::endl;
    auto routineCode = currentGenerator->getRoutine();
    Utils::append(highMemoryZcode, routineCode);
}

void AssemblyParser::addGlobal(std::string globalName) {
    // TODO: check if maximum gvar limit is reached
    unsigned index = (unsigned) globalVariableStack.size();
    std::cout << "adding gvar " << globalName << " at index " << std::to_string(index) << std::endl;
    this->globalVariableStack[globalName] = index;
}

RoutineGenerator& AssemblyParser::executePRINTCommand(const std::string &printCommand, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(printCommand, AssemblyParser::STRING_IDENTIFIER);
    routineGenerator.printString(commandParts.at(1));
    std::cout << commandParts.at(1) << std::endl;
    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeREADCommand(const std::string &readCommand, RoutineGenerator &routineGenerator) {
    //this->globalVariableStack.insert(std::pair<std::string, int>("sp", variableUsed));
    std::vector <std::string> commandParts = this->split(readCommand, AssemblyParser::ASSIGNMENT_OPERATOR);
    if(commandParts.size() < 2) {
        // TODO: decide on whether to allow no args for read_char
        return routineGenerator;
    }
    auto last = trim(commandParts.back());
    routineGenerator.readChar(getAddressForId(last)); //TODO: get available address
    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeJECommand(const std::string &jeCommand, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(jeCommand, '?');
    std::string label = commandParts.at(1);
    std::cout << label << std::endl;
    routineGenerator.jumpEquals(label, true, 0x10, 49, true, false);

    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeJUMPCommand(const std::string &jumpCommand, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(jumpCommand, '?');
    std::string label = commandParts.at(1);
    std::cout << label << std::endl;
    routineGenerator.jump(label);

    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeCALLCommand(const std::string &callCommand, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(callCommand, ' ');
    std::string callRoutineName = commandParts.at(1);
    std::cout << callRoutineName << std::endl;

    routineGenerator.callRoutine(callRoutineName);
    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeCommand(const std::string& command, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(command,
                                                         AssemblyParser::SPLITTER_BETWEEN_LEXEMES_IN_AN_COMMAND);

    if(!commandParts.size()) return routineGenerator;

    std::string commandPart = commandParts.at(0);

    if (commandPart.compare(AssemblyParser::NEW_LINE_COMMAND) == 0) {
        routineGenerator.newLine();
        std::cout << ":::::: new line" << std::endl;
    } else if (commandPart.compare(AssemblyParser::PRINT_COMMAND) == 0) {
        std::cout << ":::::: new print ";
        routineGenerator = executePRINTCommand(command, routineGenerator);
    } else if (commandPart.compare(AssemblyParser::JE_COMMAND) == 0) {
        std::cout << ":::::: new je ";
        routineGenerator = executeJECommand(command, routineGenerator);
    } else if (commandPart.compare(AssemblyParser::QUIT_COMMAND) == 0) {
        routineGenerator.quitRoutine();
        std::cout << ":::::: new quit" << std::endl;
    } else if (commandPart.compare(AssemblyParser::READ_CHAR_COMMAND) == 0) {
        routineGenerator = executeREADCommand(command, routineGenerator);
        std::cout << ":::::: new read" << std::endl;
    } else if (commandPart.compare(AssemblyParser::CALL_COMMAND) == 0) {
        std::cout << ":::::: new call ";
        routineGenerator = executeCALLCommand(command, routineGenerator);
    } else if(command.compare(AssemblyParser::JUMP_COMMAND) == 0) {
        std::cout << ":::::: new jump ";
        routineGenerator = executeJUMPCommand(command, routineGenerator);
    } else {
        // TODO: handle this error more appropriately
        std::cout << "unknown command: " << command << std::endl;
        throw;
    }

    return routineGenerator;
}

bool AssemblyParser::checkIfCommandRoutineStart(const std::string &command) {
    std::vector <std::string> commandParts = this->split(command, ' ');
    for (unsigned int i = 0; i < commandParts.size(); i++) {
        if (commandParts.at(i).compare(ROUTINE_DIRECTIVE) == 0) {
            return true;
        }

    }
    return false;
}

uint8_t AssemblyParser::getAddressForId(const std::string& id) {
    // TODO: check local variables
    if(id.compare("sp") == 0) {
        return 0x0;
    }
    // check global variables
    try {
        return globalVariableStack.at(id);
    } catch(std::out_of_range) {
        std::cout << "Could not find global " << id << std::endl;
        throw;
    }
}

std::vector <std::string> &AssemblyParser::split(const std::string &s, char delim, std::vector <std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

std::vector <std::string> AssemblyParser::split(const std::string &s, char delim) {
    std::vector <std::string> elems;
    split(s, delim, elems);
    return elems;
}

std::vector <std::string> AssemblyParser::split(const std::string &s, const std::string &delim) {
    std::string s_copy = s;
    size_t pos = 0;
    std::string token;
    std::vector<std::string> tokens;
    while ((pos = s_copy.find(delim)) != std::string::npos) {
        token = s_copy.substr(0, pos);
        std::cout << "found token " << token << std::endl;
        tokens.push_back(token);
        s_copy.erase(0, pos + delim.length());
    }
    tokens.push_back(s_copy);

    return tokens;
}

<commit_msg>trims extraneous spaces<commit_after>//
// Created by manuel on 08.06.15.
//

#include "AssemblyParser.h"
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
#include <bitset>
#include <cstdint>

const std::string AssemblyParser::ROUTINE_DIRECTIVE = ".FUNCT";
const std::string AssemblyParser::GVAR_DIRECTIVE = ".GVAR";

const std::string AssemblyParser::NEW_LINE_COMMAND = "new_line";
const std::string AssemblyParser::PRINT_COMMAND = "print";
const std::string AssemblyParser::JE_COMMAND = "je";
const std::string AssemblyParser::QUIT_COMMAND = "quit";
const std::string AssemblyParser::READ_CHAR_COMMAND = "read_char";
const std::string AssemblyParser::CALL_COMMAND = "call";
const std::string AssemblyParser::JUMP_COMMAND = "jump";

const char AssemblyParser::SPLITTER_BETWEEN_LEXEMES_IN_AN_COMMAND = ' '; // 9 is ascii for tab
const char AssemblyParser::STRING_IDENTIFIER = '\"'; // 9 is ascii for tab
const std::string AssemblyParser::ASSIGNMENT_OPERATOR = "->";

std::string trim(const std::string& str,
                 const std::string& whitespace = " \t")
{
    const auto strBegin = str.find_first_not_of(whitespace);
    if (strBegin == std::string::npos)
        return ""; // no content

    const auto strEnd = str.find_last_not_of(whitespace);
    const auto strRange = strEnd - strBegin + 1;

    return str.substr(strBegin, strRange);
}

void AssemblyParser::readAssembly(std::istream& input, std::vector <std::bitset<8>> &highMemoryZcode,
                                  size_t offset) {

    std::cout << "Compiler: Parse Assembly File\n";

    for(std::string line; getline(input, line);) {
        line = trim(line);
        std::vector<std::string> lineComps;
        this->split(line, SPLITTER_BETWEEN_LEXEMES_IN_AN_COMMAND, lineComps);
        if(lineComps.size()) {
            std::string firstComp = lineComps.at(0);

            if(line.at(0) == '.') { // directive
                if(firstComp.compare(ROUTINE_DIRECTIVE) == 0) {
                    std::cout << "found routine" << std::endl;

                    if(lineComps.size() < 2) {
                        std::cerr << "invalid routine declaration" << std::endl;
                        throw;
                    }

                    // currentGenerator exists, so we can get its code
                    if(currentGenerator) {
                        finishRoutine(highMemoryZcode);
                    }

                    std::string routineName = lineComps.at(1);

                    currentGenerator.reset(new RoutineGenerator(routineName, 0, highMemoryZcode, offset));
                } else if(firstComp.compare(GVAR_DIRECTIVE) == 0) {
                    std::cout << "found gvar" << std::endl;

                    this->split(line, SPLITTER_BETWEEN_LEXEMES_IN_AN_COMMAND, lineComps);
                    if(lineComps.size() < 2) {
                        std::cerr << "empty gvar declaration" << std::endl;
                    }

                    std::string gvar = lineComps.at(1);

                    addGlobal(gvar);
                }
            } else { // normal instruction
                // check for label
                auto pos = line.find(":");
                if(pos != std::string::npos) {
                    std::cout << ":::::: new label: ";
                    std::string labelName = line.substr(0, pos);
                    currentGenerator->newLabel(labelName);
                    std::cout << labelName << std::endl;

                    std::string afterLabel = line.substr(pos + 1, line.length() - 1);
                    executeCommand(trim(afterLabel), *currentGenerator);
                } else {
                    executeCommand(line, *currentGenerator);
                }
            }
        }
    }

    if(currentGenerator) {
        finishRoutine(highMemoryZcode);
    }
}

void AssemblyParser::finishRoutine(std::vector <std::bitset<8>> &highMemoryZcode) {
    std::cout << "adding routine to zcode" << std::endl;
    auto routineCode = currentGenerator->getRoutine();
    Utils::append(highMemoryZcode, routineCode);
}

void AssemblyParser::addGlobal(std::string globalName) {
    // TODO: check if maximum gvar limit is reached
    unsigned index = (unsigned) globalVariableStack.size();
    std::cout << "adding gvar " << globalName << " at index " << std::to_string(index) << std::endl;
    this->globalVariableStack[globalName] = index;
}

RoutineGenerator& AssemblyParser::executePRINTCommand(const std::string &printCommand, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(printCommand, AssemblyParser::STRING_IDENTIFIER);
    routineGenerator.printString(commandParts.at(1));
    std::cout << commandParts.at(1) << std::endl;
    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeREADCommand(const std::string &readCommand, RoutineGenerator &routineGenerator) {
    //this->globalVariableStack.insert(std::pair<std::string, int>("sp", variableUsed));
    std::vector <std::string> commandParts = this->split(readCommand, AssemblyParser::ASSIGNMENT_OPERATOR);
    if(commandParts.size() < 2) {
        // TODO: decide on whether to allow no args for read_char
        return routineGenerator;
    }
    auto last = trim(commandParts.back());
    routineGenerator.readChar(getAddressForId(last)); //TODO: get available address
    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeJECommand(const std::string &jeCommand, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(jeCommand, '?');
    std::string label = commandParts.at(1);
    std::cout << label << std::endl;
    routineGenerator.jumpEquals(label, true, 0x10, 49, true, false);

    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeJUMPCommand(const std::string &jumpCommand, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(jumpCommand, '?');
    std::string label = commandParts.at(1);
    std::cout << label << std::endl;
    routineGenerator.jump(label);

    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeCALLCommand(const std::string &callCommand, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(callCommand, ' ');
    std::string callRoutineName = commandParts.at(1);
    std::cout << callRoutineName << std::endl;

    routineGenerator.callRoutine(callRoutineName);
    return routineGenerator;
}

RoutineGenerator& AssemblyParser::executeCommand(const std::string& command, RoutineGenerator &routineGenerator) {

    std::vector <std::string> commandParts = this->split(command,
                                                         AssemblyParser::SPLITTER_BETWEEN_LEXEMES_IN_AN_COMMAND);

    if(!commandParts.size()) return routineGenerator;

    std::string commandPart = commandParts.at(0);

    if (commandPart.compare(AssemblyParser::NEW_LINE_COMMAND) == 0) {
        routineGenerator.newLine();
        std::cout << ":::::: new line" << std::endl;
    } else if (commandPart.compare(AssemblyParser::PRINT_COMMAND) == 0) {
        std::cout << ":::::: new print ";
        routineGenerator = executePRINTCommand(command, routineGenerator);
    } else if (commandPart.compare(AssemblyParser::JE_COMMAND) == 0) {
        std::cout << ":::::: new je ";
        routineGenerator = executeJECommand(command, routineGenerator);
    } else if (commandPart.compare(AssemblyParser::QUIT_COMMAND) == 0) {
        routineGenerator.quitRoutine();
        std::cout << ":::::: new quit" << std::endl;
    } else if (commandPart.compare(AssemblyParser::READ_CHAR_COMMAND) == 0) {
        routineGenerator = executeREADCommand(command, routineGenerator);
        std::cout << ":::::: new read" << std::endl;
    } else if (commandPart.compare(AssemblyParser::CALL_COMMAND) == 0) {
        std::cout << ":::::: new call ";
        routineGenerator = executeCALLCommand(command, routineGenerator);
    } else if(command.compare(AssemblyParser::JUMP_COMMAND) == 0) {
        std::cout << ":::::: new jump ";
        routineGenerator = executeJUMPCommand(command, routineGenerator);
    } else {
        // TODO: handle this error more appropriately
        std::cout << "unknown command: " << command << std::endl;
        throw;
    }

    return routineGenerator;
}

bool AssemblyParser::checkIfCommandRoutineStart(const std::string &command) {
    std::vector <std::string> commandParts = this->split(command, ' ');
    for (unsigned int i = 0; i < commandParts.size(); i++) {
        if (commandParts.at(i).compare(ROUTINE_DIRECTIVE) == 0) {
            return true;
        }

    }
    return false;
}

uint8_t AssemblyParser::getAddressForId(const std::string& id) {
    // TODO: check local variables
    if(id.compare("sp") == 0) {
        return 0x0;
    }
    // check global variables
    try {
        return globalVariableStack.at(id);
    } catch(std::out_of_range) {
        std::cout << "Could not find global " << id << std::endl;
        throw;
    }
}

std::vector <std::string> &AssemblyParser::split(const std::string &s, char delim, std::vector <std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

std::vector <std::string> AssemblyParser::split(const std::string &s, char delim) {
    std::vector <std::string> elems;
    split(s, delim, elems);
    return elems;
}

std::vector <std::string> AssemblyParser::split(const std::string &s, const std::string &delim) {
    std::string s_copy = s;
    size_t pos = 0;
    std::string token;
    std::vector<std::string> tokens;
    while ((pos = s_copy.find(delim)) != std::string::npos) {
        token = s_copy.substr(0, pos);
        std::cout << "found token " << token << std::endl;
        tokens.push_back(token);
        s_copy.erase(0, pos + delim.length());
    }
    tokens.push_back(s_copy);

    return tokens;
}

<|endoftext|>


<commit_before>// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.

// [Export]
#define ASMJIT_EXPORTS

// [Dependencies - AsmJit]
#include "../base/cputicks.h"

// [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <time.h>
# include <unistd.h>
#endif // ASMJIT_OS_POSIX

// [Dependencies - Mac]
#if defined(ASMJIT_OS_MAC)
# include <mach/mach_time.h>
#endif // ASMJIT_OS_MAC

// [Api-Begin]
#include "../apibegin.h"

namespace asmjit {

// ============================================================================
// [asmjit::CpuTicks - Windows]
// ============================================================================

#if defined(ASMJIT_OS_WINDOWS)
static volatile uint32_t CpuTicks_hiResOk;
static volatile double CpuTicks_hiResFreq;

uint32_t CpuTicks::now() {
  do {
    uint32_t hiResOk = CpuTicks_hiResOk;

    if (hiResOk == 1) {
      LARGE_INTEGER now;
      if (!::QueryPerformanceCounter(&now))
        break;
      return (int64_t)(double(now.QuadPart) / CpuTicks_hiResFreq);
    }

    if (hiResOk == 0) {
      LARGE_INTEGER qpf;
      if (!::QueryPerformanceFrequency(&qpf)) {
        _InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 0xFFFFFFFF, 0);
        break;
      }

      LARGE_INTEGER now;
      if (!::QueryPerformanceCounter(&now)) {
        _InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 0xFFFFFFFF, 0);
        break;
      }

      double freqDouble = double(qpf.QuadPart) / 1000.0;

      CpuTicks_hiResFreq = freqDouble;
      _InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 1, 0);

      return static_cast<uint32_t>(
        static_cast<int64_t>(double(now.QuadPart) / freqDouble) & 0xFFFFFFFF);
    }
  } while (0);

  // Bail to mmsystem.
  return ::GetTickCount();
}

// ============================================================================
// [asmjit::CpuTicks - Mac]
// ============================================================================

#elif defined(ASMJIT_OS_MAC)
static mach_timebase_info_data_t CpuTicks_machTime;

uint32_t CpuTicks::now() {
  // Initialize the first time CpuTicks::now() is called (See Apple's QA1398).
  if (CpuTicks_machTime.denom == 0) {
    if (mach_timebase_info(&CpuTicks_machTime) != KERN_SUCCESS);
      return 0;
  }

  // mach_absolute_time() returns nanoseconds, we need just milliseconds.
  uint64_t t = mach_absolute_time() / 1000000;

  t = t * CpuTicks_machTime.numer / CpuTicks_machTime.denom;
  return static_cast<uint32_t>(t & 0xFFFFFFFFU);
}

// ============================================================================
// [asmjit::CpuTicks - Posix]
// ============================================================================

#else
uint32_t CpuTicks::now() {
#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
  struct timespec ts;

  if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
    return 0;

  uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000);
  return static_cast<uint32_t>(t & 0xFFFFFFFFU);
#else  // _POSIX_MONOTONIC_CLOCK
#error "AsmJit - Unsupported OS."
  return 0;
#endif  // _POSIX_MONOTONIC_CLOCK
}
#endif // ASMJIT_OS

} // asmjit namespace

// [Api-End]
#include "../apiend.h"
<commit_msg>Minor.<commit_after>// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.

// [Export]
#define ASMJIT_EXPORTS

// [Dependencies - AsmJit]
#include "../base/cputicks.h"

// [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <time.h>
# include <unistd.h>
#endif // ASMJIT_OS_POSIX

// [Dependencies - Mac]
#if defined(ASMJIT_OS_MAC)
# include <mach/mach_time.h>
#endif // ASMJIT_OS_MAC

// [Api-Begin]
#include "../apibegin.h"

namespace asmjit {

// ============================================================================
// [asmjit::CpuTicks - Windows]
// ============================================================================

#if defined(ASMJIT_OS_WINDOWS)
static volatile uint32_t CpuTicks_hiResOk;
static volatile double CpuTicks_hiResFreq;

uint32_t CpuTicks::now() {
  do {
    uint32_t hiResOk = CpuTicks_hiResOk;

    if (hiResOk == 1) {
      LARGE_INTEGER now;
      if (!::QueryPerformanceCounter(&now))
        break;
      return (int64_t)(double(now.QuadPart) / CpuTicks_hiResFreq);
    }

    if (hiResOk == 0) {
      LARGE_INTEGER qpf;
      if (!::QueryPerformanceFrequency(&qpf)) {
        _InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 0xFFFFFFFF, 0);
        break;
      }

      LARGE_INTEGER now;
      if (!::QueryPerformanceCounter(&now)) {
        _InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 0xFFFFFFFF, 0);
        break;
      }

      double freqDouble = double(qpf.QuadPart) / 1000.0;

      CpuTicks_hiResFreq = freqDouble;
      _InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 1, 0);

      return static_cast<uint32_t>(
        static_cast<int64_t>(double(now.QuadPart) / freqDouble) & 0xFFFFFFFF);
    }
  } while (0);

  // Bail to a less precise GetTickCount().
  return ::GetTickCount();
}

// ============================================================================
// [asmjit::CpuTicks - Mac]
// ============================================================================

#elif defined(ASMJIT_OS_MAC)
static mach_timebase_info_data_t CpuTicks_machTime;

uint32_t CpuTicks::now() {
  // Initialize the first time CpuTicks::now() is called (See Apple's QA1398).
  if (CpuTicks_machTime.denom == 0) {
    if (mach_timebase_info(&CpuTicks_machTime) != KERN_SUCCESS);
      return 0;
  }

  // mach_absolute_time() returns nanoseconds, we need just milliseconds.
  uint64_t t = mach_absolute_time() / 1000000;

  t = t * CpuTicks_machTime.numer / CpuTicks_machTime.denom;
  return static_cast<uint32_t>(t & 0xFFFFFFFFU);
}

// ============================================================================
// [asmjit::CpuTicks - Posix]
// ============================================================================

#else
uint32_t CpuTicks::now() {
#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
  struct timespec ts;

  if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
    return 0;

  uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000);
  return static_cast<uint32_t>(t & 0xFFFFFFFFU);
#else  // _POSIX_MONOTONIC_CLOCK
#error "AsmJit - Unsupported OS."
  return 0;
#endif  // _POSIX_MONOTONIC_CLOCK
}
#endif // ASMJIT_OS

} // asmjit namespace

// [Api-End]
#include "../apiend.h"
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------*\
 *                                OpenSG                                     *
 *                                                                           *
 *                                                                           *
 *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
 *                                                                           *
 *                            www.opensg.org                                 *
 *                                                                           *
 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                License                                    *
 *                                                                           *
 * This library is free software; you can redistribute it and/or modify it   *
 * under the terms of the GNU Library General Public License as published    *
 * by the Free Software Foundation, version 2.                               *
 *                                                                           *
 * This library is distributed in the hope that it will be useful, but       *
 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
 * Library General Public License for more details.                          *
 *                                                                           *
 * You should have received a copy of the GNU Library General Public         *
 * License along with this library; ifnot, write to the Free Software       *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                Changes                                    *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
\*---------------------------------------------------------------------------*/

//---------------------------------------------------------------------------
//  Includes
//---------------------------------------------------------------------------

#include <cstdlib>
#include <cstdio>

#include "OSGConfig.h"

#include "OSGGL.h"

#include "OSGFieldContainer.h"
#include "OSGNode.h"
#include "OSGAction.h"
#include "OSGViewport.h"
#include "OSGCamera.h"
#include "OSGWindow.h"
#include "OSGBackground.h"
#include "OSGGradientBackground.h"
#include "OSGTileCameraDecorator.h"
#include "OSGDrawEnv.h"

OSG_USING_NAMESPACE

// Documentation for this class is emited in the
// OSGGradientBackgroundBase.cpp file.
// To modify it, please change the .fcd file (OSGGradientBackground.fcd) and
// regenerate the base file.

/***************************************************************************\
 *                           Class variables                               *
\***************************************************************************/

const OSG::BitVector  GradientBackground::LineFieldMask =
                     (GradientBackground::PositionFieldMask |
                      GradientBackground::ColorFieldMask   );

/***************************************************************************\
 *                           Class methods                                 *
\***************************************************************************/

void GradientBackground::initMethod(InitPhase ePhase)
{
    Inherited::initMethod(ePhase);
}

/***************************************************************************\
 *                           Instance methods                              *
\***************************************************************************/

/*------------- constructors & destructors --------------------------------*/

GradientBackground::GradientBackground(void) :
    Inherited()
{
}

GradientBackground::GradientBackground(const GradientBackground &source) :
    Inherited(source)
{
}

GradientBackground::~GradientBackground(void)
{
}

void GradientBackground::changed(ConstFieldMaskArg whichField,
                                 UInt32            origin,
                                 BitVector         details)
{
    Inherited::changed(whichField, origin, details);
}

/*-------------------------- your_category---------------------------------*/

void GradientBackground::clear(DrawEnv *pEnv)
{
    Int32 bit = getClearStencilBit();

	glClearDepth(1.f);

    if(_mfPosition.size() < 2)
    {
        Real32 r = 0.f, g = 0.f, b = 0.f;

        if(_mfPosition.size() == 1)
        {
            Color3f col = _mfColor[0];
            col.getValuesRGB(r, g, b);
        }

        glClearColor(r, g, b, 1);

        if (bit >= 0)
        {
            glClearStencil(bit);
            glClear((GL_COLOR_BUFFER_BIT   |
                     GL_DEPTH_BUFFER_BIT   |
                     GL_STENCIL_BUFFER_BIT ));
        }
        else
        {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        }
    }
    else
    {
        glPushAttrib(GL_POLYGON_BIT | GL_DEPTH_BUFFER_BIT |
                     GL_LIGHTING_BIT);

        glDisable(GL_LIGHTING);
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        glDisable(GL_DEPTH_TEST);
        glDisable(GL_COLOR_MATERIAL);

        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadIdentity();

        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();

#if 0
        UInt32 width  = pEnv->getPixelWidth(),
               height = pEnv->getPixelHeight();

        Camera              *cP  = getCPtr(pPort->getCamera());
        TileCameraDecorator *cdP = dynamic_cast<TileCameraDecorator*>(cP);

        while(cdP != NULL)
        {
            width  = cdP->getFullWidth()  ? cdP->getFullWidth()  : width;
            height = cdP->getFullHeight() ? cdP->getFullHeight() : height;

            cP  = getCPtr(cdP->getDecoratee());
            cdP = dynamic_cast<TileCameraDecorator*>(cP);
        }

        cP  = getCPtr(pEnv->getCamera());
        cdP = dynamic_cast<TileCameraDecorator*>(cP);

        if(cdP != NULL)
        {
            Real32 left   = cdP->getLeft(),
                   right  = cdP->getRight(),
                   top    = cdP->getTop(),
                   bottom = cdP->getBottom();

            glOrtho(left , right, bottom, top, 0, 1);
        }
        else
        {
            glOrtho(0, 1, 0, 1, 0, 1);
        }
#endif

        glOrtho(pEnv->getPixelLeft  (),
                pEnv->getPixelRight (),
                pEnv->getPixelBottom(),
                pEnv->getPixelTop   (),
                0.f,
                1.f);

        Real32 r1, g1, b1;
        UInt32 size = _mfPosition.size();

        glBegin(GL_QUAD_STRIP);

        Real32 pos = _mfPosition[0];

        if(pos > 0)
        {
            glColor3f(0.0, 0.0, 0.0);
            glVertex3f(0, 0, 0);
            glVertex3f(1, 0, 0);
        }

        for(UInt32 i = 0; i < size; i++)
        {
            pos = _mfPosition[i];

            Color3f col1 = _mfColor[i];
            col1.getValuesRGB(r1, g1, b1);

            glColor3f(r1, g1, b1);
            glVertex3f(0, pos, 0);
            glVertex3f(1, pos, 0);
        }

        if(pos < 1)
        {
            glColor3f(0.0, 0.0, 0.0);
            glVertex3f(0, 1, 0);
            glVertex3f(1, 1, 0);
        }

        glEnd();

        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();

        glPopAttrib();

        if(bit >= 0)
        {
            glClearStencil(bit);

            glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
        }
        else
        {
            glClear(GL_DEPTH_BUFFER_BIT);
        }
     }
}

/*------------------------------- dump ----------------------------------*/

void GradientBackground::dump(     UInt32    OSG_CHECK_ARG(uiIndent),
                              const BitVector OSG_CHECK_ARG(bvFlags)) const
{
    SLOG << "Dump GradientBackground NI" << std::endl;
}

<commit_msg>fixed: make GradientBackground respect Backgound field values        don't use viewport pixel size for glOrtho<commit_after>/*---------------------------------------------------------------------------*\
 *                                OpenSG                                     *
 *                                                                           *
 *                                                                           *
 *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
 *                                                                           *
 *                            www.opensg.org                                 *
 *                                                                           *
 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                License                                    *
 *                                                                           *
 * This library is free software; you can redistribute it and/or modify it   *
 * under the terms of the GNU Library General Public License as published    *
 * by the Free Software Foundation, version 2.                               *
 *                                                                           *
 * This library is distributed in the hope that it will be useful, but       *
 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
 * Library General Public License for more details.                          *
 *                                                                           *
 * You should have received a copy of the GNU Library General Public         *
 * License along with this library; ifnot, write to the Free Software       *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                Changes                                    *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
\*---------------------------------------------------------------------------*/

//---------------------------------------------------------------------------
//  Includes
//---------------------------------------------------------------------------

#include <cstdlib>
#include <cstdio>

#include "OSGConfig.h"

#include "OSGGL.h"

#include "OSGFieldContainer.h"
#include "OSGNode.h"
#include "OSGAction.h"
#include "OSGViewport.h"
#include "OSGCamera.h"
#include "OSGWindow.h"
#include "OSGBackground.h"
#include "OSGGradientBackground.h"
#include "OSGTileCameraDecorator.h"
#include "OSGDrawEnv.h"

OSG_USING_NAMESPACE

// Documentation for this class is emited in the
// OSGGradientBackgroundBase.cpp file.
// To modify it, please change the .fcd file (OSGGradientBackground.fcd) and
// regenerate the base file.

/***************************************************************************\
 *                           Class variables                               *
\***************************************************************************/

const OSG::BitVector  GradientBackground::LineFieldMask =
                     (GradientBackground::PositionFieldMask |
                      GradientBackground::ColorFieldMask   );

/***************************************************************************\
 *                           Class methods                                 *
\***************************************************************************/

void GradientBackground::initMethod(InitPhase ePhase)
{
    Inherited::initMethod(ePhase);
}

/***************************************************************************\
 *                           Instance methods                              *
\***************************************************************************/

/*------------- constructors & destructors --------------------------------*/

GradientBackground::GradientBackground(void) :
    Inherited()
{
}

GradientBackground::GradientBackground(const GradientBackground &source) :
    Inherited(source)
{
}

GradientBackground::~GradientBackground(void)
{
}

void GradientBackground::changed(ConstFieldMaskArg whichField,
                                 UInt32            origin,
                                 BitVector         details)
{
    Inherited::changed(whichField, origin, details);
}

/*-------------------------- your_category---------------------------------*/

void GradientBackground::clear(DrawEnv *pEnv)
{
    Int32      stencilBit = getClearStencilBit();   // 0x0
    GLbitfield clearMask  = 0;

    if(getClearColor() == true)
    {
        if(_mfPosition.size() < 2)
        {
            // too few positions for a real gradient - just clear the buffer

            clearMask |= GL_COLOR_BUFFER_BIT;

            if(_mfPosition.size() == 1)
            {
                const Color3f &col = _mfColor[0];

                GLP::glClearColor(col[0], col[1], col[2], 1.0);
            }
        }
        else
        {
            // draw gradient - don't need to clear the color buffer

            glPushAttrib(GL_POLYGON_BIT | GL_DEPTH_BUFFER_BIT |
                         GL_LIGHTING_BIT                       );

            glDisable(GL_LIGHTING);
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
            glDisable(GL_DEPTH_TEST);
            glDisable(GL_COLOR_MATERIAL);

            glMatrixMode(GL_MODELVIEW);
            glPushMatrix();
            glLoadIdentity();

            glMatrixMode(GL_PROJECTION);
            glPushMatrix();
            glLoadIdentity();

            // FIXME This does not work with TileCameraDecorator
            glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);

            UInt32 size = _mfPosition.size();

            glBegin(GL_QUAD_STRIP);

            Real32 pos = _mfPosition[0];

            if(pos > 0.0f)
            {
                glColor3f(0.0, 0.0, 0.0);
                glVertex3f(0, 0, 0);
                glVertex3f(1, 0, 0);
            }

            for(UInt32 i = 0; i < size; i++)
            {
                pos = _mfPosition[i];

                const Color3f &col = _mfColor[i];

                glColor3f(col[0], col[1], col[2]);
                glVertex3f(0, pos, 0);
                glVertex3f(1, pos, 0);
            }

            if(pos < 1.0f)
            {
                glColor3f(0.0, 0.0, 0.0);
                glVertex3f(0, 1, 0);
                glVertex3f(1, 1, 0);
            }

            glEnd();

            glPopMatrix();
            glMatrixMode(GL_MODELVIEW);
            glPopMatrix();

            glPopAttrib();
        }
    }

    if(getClearDepth() == true)
    {
        clearMask |= GL_DEPTH_BUFFER_BIT;

        GLP::glClearDepth(getDepth());
    }

    if(stencilBit >= 0)
    {
        clearMask |= GL_STENCIL_BUFFER_BIT;

        glClearStencil(stencilBit);
    }

    if(clearMask != 0)
    {
        glClear(clearMask);
    }
}

/*------------------------------- dump ----------------------------------*/

void GradientBackground::dump(     UInt32    OSG_CHECK_ARG(uiIndent),
                              const BitVector OSG_CHECK_ARG(bvFlags)) const
{
    SLOG << "Dump GradientBackground NI" << std::endl;
}

<|endoftext|>


<commit_before>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * RDMCommandTest.cpp
 * Test fixture for the RDMCommand classes
 * Copyright (C) 2010 Simon Newton
 */

#include <cppunit/extensions/HelperMacros.h>
#include <string>
#include <iomanip>

#include "ola/Logging.h"
#include "ola/rdm/RDMCommand.h"
#include "ola/rdm/UID.h"

using std::string;
using ola::rdm::RDMCommand;
using ola::rdm::RDMRequest;
using ola::rdm::RDMGetRequest;
using ola::rdm::RDMSetRequest;
using ola::rdm::RDMResponse;
using ola::rdm::UID;

class RDMCommandTest: public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(RDMCommandTest);
  CPPUNIT_TEST(testRDMCommand);
  CPPUNIT_TEST(testRequestInflation);
  CPPUNIT_TEST(testResponseInflation);
  CPPUNIT_TEST_SUITE_END();

  public:
    void setUp();

    void testRDMCommand();
    void testRequestInflation();
    void testResponseInflation();

  private:
    void PackAndVerify(const RDMCommand &command,
                       const uint8_t *expected,
                       unsigned int expected_length);
    void UpdateChecksum(uint8_t *expected,
                        unsigned int expected_length);

    static uint8_t EXPECTED_GET_BUFFER[];
    static uint8_t EXPECTED_SET_BUFFER[];
    static uint8_t EXPECTED_GET_RESPONSE_BUFFER[];
};

CPPUNIT_TEST_SUITE_REGISTRATION(RDMCommandTest);

uint8_t RDMCommandTest::EXPECTED_GET_BUFFER[] = {
  1, 24,  // sub code & length
  0, 3, 0, 0, 0, 4,   // dst uid
  0, 1, 0, 0, 0, 2,   // src uid
  0, 1, 0, 0, 10,  // transaction, port id, msg count & sub device
  32, 1, 40, 0,  // command, param id, param data length
  0, 0  // checksum, filled in below
};

uint8_t RDMCommandTest::EXPECTED_SET_BUFFER[] = {
    1, 28,  // sub code & length
    0, 3, 0, 0, 0, 4,   // dst uid
    0, 1, 0, 0, 0, 2,   // src uid
    0, 1, 0, 0, 10,  // transaction, port id, msg count & sub device
    48, 1, 40, 4,  // command, param id, param data length
    0xa5, 0xa5, 0xa5, 0xa5,  // param data
    0, 0  // checksum, filled in below
};

uint8_t RDMCommandTest::EXPECTED_GET_RESPONSE_BUFFER[] = {
    1, 28,  // sub code & length
    0, 3, 0, 0, 0, 4,   // dst uid
    0, 1, 0, 0, 0, 2,   // src uid
    0, 1, 0, 0, 10,  // transaction, port id, msg count & sub device
    33, 1, 40, 4,  // command, param id, param data length
    0x5a, 0x5a, 0x5a, 0x5a,  // param data
    0, 0  // checksum, filled in below
};

/*
 * Fill in the checksums
 */
void RDMCommandTest::setUp() {
  ola::InitLogging(ola::OLA_LOG_INFO, ola::OLA_LOG_STDERR);
  UpdateChecksum(EXPECTED_GET_BUFFER, sizeof(EXPECTED_GET_BUFFER));
  UpdateChecksum(EXPECTED_SET_BUFFER, sizeof(EXPECTED_SET_BUFFER));
  UpdateChecksum(EXPECTED_GET_RESPONSE_BUFFER,
                 sizeof(EXPECTED_GET_RESPONSE_BUFFER));
}

/*
 * Test the RDMCommands work.
 */
void RDMCommandTest::testRDMCommand() {
  UID source(1, 2);
  UID destination(3, 4);

  RDMGetRequest command(source,
                        destination,
                        0,  // transaction #
                        1,  // port id
                        0,  // message count
                        10,  // sub device
                        296,  // param id
                        NULL,  // data
                        0);  // data length

  CPPUNIT_ASSERT_EQUAL(source, command.SourceUID());
  CPPUNIT_ASSERT_EQUAL(destination, command.DestinationUID());
  CPPUNIT_ASSERT_EQUAL((uint8_t) 0, command.TransactionNumber());
  CPPUNIT_ASSERT_EQUAL((uint8_t) 1, command.PortId());
  CPPUNIT_ASSERT_EQUAL((uint8_t) 0, command.MessageCount());
  CPPUNIT_ASSERT_EQUAL((uint16_t) 10, command.SubDevice());
  CPPUNIT_ASSERT_EQUAL(RDMCommand::GET_COMMAND, command.CommandClass());
  CPPUNIT_ASSERT_EQUAL((uint16_t) 296, command.ParamId());
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<uint8_t*>(NULL), command.ParamData());
  CPPUNIT_ASSERT_EQUAL((unsigned int) 0, command.ParamDataSize());
  CPPUNIT_ASSERT_EQUAL((unsigned int) 25, command.Size());

  // try one with extra long data
  uint8_t *data = new uint8_t[232];
  RDMGetRequest long_command(source,
                             destination,
                             0,  // transaction #
                             1,  // port id
                             0,  // message count
                             10,  // sub device
                             123,  // param id
                             data,  // data
                             232);  // data length

  CPPUNIT_ASSERT_EQUAL((unsigned int) 231, long_command.ParamDataSize());
  CPPUNIT_ASSERT_EQUAL((unsigned int) 256, long_command.Size());
  PackAndVerify(command, EXPECTED_GET_BUFFER, sizeof(EXPECTED_GET_BUFFER));

  uint32_t data_value = 0xa5a5a5a5;
  RDMSetRequest command3(source,
                         destination,
                         0,  // transaction #
                         1,  // port id
                         0,  // message count
                         10,  // sub device
                         296,  // param id
                         reinterpret_cast<uint8_t*>(&data_value),  // data
                         sizeof(data_value));  // data length

  CPPUNIT_ASSERT_EQUAL((unsigned int) 29, command3.Size());
  PackAndVerify(command3, EXPECTED_SET_BUFFER, sizeof(EXPECTED_SET_BUFFER));

  delete[] data;
}

/*
 * Test that we can inflate RDM request messages correctly
 */
void RDMCommandTest::testRequestInflation() {
  RDMRequest *command = RDMRequest::InflateFromData(NULL, 10);
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMRequest*>(NULL), command);

  command = RDMRequest::InflateFromData(EXPECTED_GET_BUFFER, 0);
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMRequest*>(NULL), command);

  command = RDMRequest::InflateFromData(
      EXPECTED_GET_BUFFER,
      sizeof(EXPECTED_GET_BUFFER));
  CPPUNIT_ASSERT(NULL != command);
  delete command;

  command = RDMRequest::InflateFromData(
      EXPECTED_SET_BUFFER,
      sizeof(EXPECTED_SET_BUFFER));
  CPPUNIT_ASSERT(NULL != command);
  uint8_t expected_data[] = {0xa5, 0xa5, 0xa5, 0xa5};
  CPPUNIT_ASSERT_EQUAL((unsigned int) 4, command->ParamDataSize());
  CPPUNIT_ASSERT(0 == memcmp(expected_data, command->ParamData(),
                             command->ParamDataSize()));
  delete command;

  // change the param length and make sure the checksum fails
  uint8_t *bad_packet = new uint8_t[sizeof(EXPECTED_GET_BUFFER)];
  memcpy(bad_packet, EXPECTED_GET_BUFFER, sizeof(EXPECTED_GET_BUFFER));
  bad_packet[22] = 255;

  command = RDMRequest::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_GET_BUFFER));
  CPPUNIT_ASSERT(NULL == command);

  // now make sure we can't pass a bad param length larger than the buffer
  UpdateChecksum(bad_packet, sizeof(EXPECTED_GET_BUFFER));
  command = RDMRequest::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_GET_BUFFER));
  CPPUNIT_ASSERT(NULL == command);
  delete[] bad_packet;

  // change the param length of another packet and make sure the checksum fails
  bad_packet = new uint8_t[sizeof(EXPECTED_SET_BUFFER)];
  memcpy(bad_packet, EXPECTED_SET_BUFFER, sizeof(EXPECTED_SET_BUFFER));
  bad_packet[22] = 5;
  UpdateChecksum(bad_packet, sizeof(EXPECTED_SET_BUFFER));
  command = RDMRequest::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_SET_BUFFER));
  CPPUNIT_ASSERT(NULL == command);
  delete[] bad_packet;

  // now try to inflate a response
  command = RDMRequest::InflateFromData(
      EXPECTED_GET_RESPONSE_BUFFER,
      sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMRequest*>(NULL), command);
}

/*
 * Calculate the checksum for a packet, and verify
 */
void RDMCommandTest::PackAndVerify(const RDMCommand &command,
                                   const uint8_t *expected,
                                   unsigned int expected_length) {
  // now check packing
  unsigned int buffer_size = command.Size();
  uint8_t *buffer = new uint8_t[buffer_size];
  CPPUNIT_ASSERT(command.Pack(buffer, &buffer_size));

  for (unsigned int i = 0 ; i < expected_length; i++) {
    std::stringstream str;
    str << "Offset " << i << ", expected " << static_cast<int>(expected[i]) <<
      ", got " << static_cast<int>(buffer[i]);
    CPPUNIT_ASSERT_MESSAGE(str.str(), buffer[i] == expected[i]);
  }
  delete[] buffer;
}

/*
 * Test that we can inflate RDM response correctly
 */
void RDMCommandTest::testResponseInflation() {
  RDMResponse *command = RDMResponse::InflateFromData(NULL, 10);
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMResponse*>(NULL), command);

  command = RDMResponse::InflateFromData(EXPECTED_GET_RESPONSE_BUFFER, 0);
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMResponse*>(NULL), command);

  command = RDMResponse::InflateFromData(
      EXPECTED_GET_RESPONSE_BUFFER,
      sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  CPPUNIT_ASSERT(NULL != command);
  uint8_t expected_data[] = {0x5a, 0x5a, 0x5a, 0x5a};
  CPPUNIT_ASSERT_EQUAL((unsigned int) 4, command->ParamDataSize());
  CPPUNIT_ASSERT(0 == memcmp(expected_data, command->ParamData(),
                             command->ParamDataSize()));
  delete command;

  // change the param length and make sure the checksum fails
  uint8_t *bad_packet = new uint8_t[sizeof(EXPECTED_GET_RESPONSE_BUFFER)];
  memcpy(bad_packet, EXPECTED_GET_RESPONSE_BUFFER,
         sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  bad_packet[22] = 255;

  command = RDMResponse::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  CPPUNIT_ASSERT(NULL == command);

  // now make sure we can't pass a bad param length larger than the buffer
  UpdateChecksum(bad_packet, sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  command = RDMResponse::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  CPPUNIT_ASSERT(NULL == command);
  delete[] bad_packet;

  // change the param length of another packet and make sure the checksum fails
  bad_packet = new uint8_t[sizeof(EXPECTED_SET_BUFFER)];
  memcpy(bad_packet, EXPECTED_SET_BUFFER, sizeof(EXPECTED_SET_BUFFER));
  bad_packet[22] = 5;
  UpdateChecksum(bad_packet, sizeof(EXPECTED_SET_BUFFER));
  command = RDMResponse::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_SET_BUFFER));
  CPPUNIT_ASSERT(NULL == command);
  delete[] bad_packet;

  // now try to inflate a response
  command = RDMResponse::InflateFromData(
      EXPECTED_GET_BUFFER,
      sizeof(EXPECTED_GET_BUFFER));
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMResponse*>(NULL), command);
}

/*
 * Calculate a checksum for a packet and update it
 */
void RDMCommandTest::UpdateChecksum(uint8_t *expected,
                                    unsigned int expected_length) {
  unsigned int checksum = RDMCommand::START_CODE;
  for (unsigned int i = 0 ; i < expected_length - 2; i++)
    checksum += expected[i];

  expected[expected_length - 2] = checksum >> 8;
  expected[expected_length - 1] = checksum & 0xff;
}
<commit_msg> * fix a test<commit_after>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * RDMCommandTest.cpp
 * Test fixture for the RDMCommand classes
 * Copyright (C) 2010 Simon Newton
 */

#include <cppunit/extensions/HelperMacros.h>
#include <string.h>
#include <string>
#include <iomanip>

#include "ola/Logging.h"
#include "ola/rdm/RDMCommand.h"
#include "ola/rdm/UID.h"

using std::string;
using ola::rdm::RDMCommand;
using ola::rdm::RDMRequest;
using ola::rdm::RDMGetRequest;
using ola::rdm::RDMSetRequest;
using ola::rdm::RDMResponse;
using ola::rdm::UID;

class RDMCommandTest: public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(RDMCommandTest);
  CPPUNIT_TEST(testRDMCommand);
  CPPUNIT_TEST(testRequestInflation);
  CPPUNIT_TEST(testResponseInflation);
  CPPUNIT_TEST_SUITE_END();

  public:
    void setUp();

    void testRDMCommand();
    void testRequestInflation();
    void testResponseInflation();

  private:
    void PackAndVerify(const RDMCommand &command,
                       const uint8_t *expected,
                       unsigned int expected_length);
    void UpdateChecksum(uint8_t *expected,
                        unsigned int expected_length);

    static uint8_t EXPECTED_GET_BUFFER[];
    static uint8_t EXPECTED_SET_BUFFER[];
    static uint8_t EXPECTED_GET_RESPONSE_BUFFER[];
};

CPPUNIT_TEST_SUITE_REGISTRATION(RDMCommandTest);

uint8_t RDMCommandTest::EXPECTED_GET_BUFFER[] = {
  1, 24,  // sub code & length
  0, 3, 0, 0, 0, 4,   // dst uid
  0, 1, 0, 0, 0, 2,   // src uid
  0, 1, 0, 0, 10,  // transaction, port id, msg count & sub device
  32, 1, 40, 0,  // command, param id, param data length
  0, 0  // checksum, filled in below
};

uint8_t RDMCommandTest::EXPECTED_SET_BUFFER[] = {
    1, 28,  // sub code & length
    0, 3, 0, 0, 0, 4,   // dst uid
    0, 1, 0, 0, 0, 2,   // src uid
    0, 1, 0, 0, 10,  // transaction, port id, msg count & sub device
    48, 1, 40, 4,  // command, param id, param data length
    0xa5, 0xa5, 0xa5, 0xa5,  // param data
    0, 0  // checksum, filled in below
};

uint8_t RDMCommandTest::EXPECTED_GET_RESPONSE_BUFFER[] = {
    1, 28,  // sub code & length
    0, 3, 0, 0, 0, 4,   // dst uid
    0, 1, 0, 0, 0, 2,   // src uid
    0, 1, 0, 0, 10,  // transaction, port id, msg count & sub device
    33, 1, 40, 4,  // command, param id, param data length
    0x5a, 0x5a, 0x5a, 0x5a,  // param data
    0, 0  // checksum, filled in below
};

/*
 * Fill in the checksums
 */
void RDMCommandTest::setUp() {
  ola::InitLogging(ola::OLA_LOG_INFO, ola::OLA_LOG_STDERR);
  UpdateChecksum(EXPECTED_GET_BUFFER, sizeof(EXPECTED_GET_BUFFER));
  UpdateChecksum(EXPECTED_SET_BUFFER, sizeof(EXPECTED_SET_BUFFER));
  UpdateChecksum(EXPECTED_GET_RESPONSE_BUFFER,
                 sizeof(EXPECTED_GET_RESPONSE_BUFFER));
}

/*
 * Test the RDMCommands work.
 */
void RDMCommandTest::testRDMCommand() {
  UID source(1, 2);
  UID destination(3, 4);

  RDMGetRequest command(source,
                        destination,
                        0,  // transaction #
                        1,  // port id
                        0,  // message count
                        10,  // sub device
                        296,  // param id
                        NULL,  // data
                        0);  // data length

  CPPUNIT_ASSERT_EQUAL(source, command.SourceUID());
  CPPUNIT_ASSERT_EQUAL(destination, command.DestinationUID());
  CPPUNIT_ASSERT_EQUAL((uint8_t) 0, command.TransactionNumber());
  CPPUNIT_ASSERT_EQUAL((uint8_t) 1, command.PortId());
  CPPUNIT_ASSERT_EQUAL((uint8_t) 0, command.MessageCount());
  CPPUNIT_ASSERT_EQUAL((uint16_t) 10, command.SubDevice());
  CPPUNIT_ASSERT_EQUAL(RDMCommand::GET_COMMAND, command.CommandClass());
  CPPUNIT_ASSERT_EQUAL((uint16_t) 296, command.ParamId());
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<uint8_t*>(NULL), command.ParamData());
  CPPUNIT_ASSERT_EQUAL((unsigned int) 0, command.ParamDataSize());
  CPPUNIT_ASSERT_EQUAL((unsigned int) 25, command.Size());

  // try one with extra long data
  uint8_t *data = new uint8_t[232];
  RDMGetRequest long_command(source,
                             destination,
                             0,  // transaction #
                             1,  // port id
                             0,  // message count
                             10,  // sub device
                             123,  // param id
                             data,  // data
                             232);  // data length

  CPPUNIT_ASSERT_EQUAL((unsigned int) 231, long_command.ParamDataSize());
  CPPUNIT_ASSERT_EQUAL((unsigned int) 256, long_command.Size());
  PackAndVerify(command, EXPECTED_GET_BUFFER, sizeof(EXPECTED_GET_BUFFER));

  uint32_t data_value = 0xa5a5a5a5;
  RDMSetRequest command3(source,
                         destination,
                         0,  // transaction #
                         1,  // port id
                         0,  // message count
                         10,  // sub device
                         296,  // param id
                         reinterpret_cast<uint8_t*>(&data_value),  // data
                         sizeof(data_value));  // data length

  CPPUNIT_ASSERT_EQUAL((unsigned int) 29, command3.Size());
  PackAndVerify(command3, EXPECTED_SET_BUFFER, sizeof(EXPECTED_SET_BUFFER));

  delete[] data;
}

/*
 * Test that we can inflate RDM request messages correctly
 */
void RDMCommandTest::testRequestInflation() {
  RDMRequest *command = RDMRequest::InflateFromData(NULL, 10);
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMRequest*>(NULL), command);

  command = RDMRequest::InflateFromData(EXPECTED_GET_BUFFER, 0);
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMRequest*>(NULL), command);

  command = RDMRequest::InflateFromData(
      EXPECTED_GET_BUFFER,
      sizeof(EXPECTED_GET_BUFFER));
  CPPUNIT_ASSERT(NULL != command);
  delete command;

  command = RDMRequest::InflateFromData(
      EXPECTED_SET_BUFFER,
      sizeof(EXPECTED_SET_BUFFER));
  CPPUNIT_ASSERT(NULL != command);
  uint8_t expected_data[] = {0xa5, 0xa5, 0xa5, 0xa5};
  CPPUNIT_ASSERT_EQUAL((unsigned int) 4, command->ParamDataSize());
  CPPUNIT_ASSERT(0 == memcmp(expected_data, command->ParamData(),
                             command->ParamDataSize()));
  delete command;

  // change the param length and make sure the checksum fails
  uint8_t *bad_packet = new uint8_t[sizeof(EXPECTED_GET_BUFFER)];
  memcpy(bad_packet, EXPECTED_GET_BUFFER, sizeof(EXPECTED_GET_BUFFER));
  bad_packet[22] = 255;

  command = RDMRequest::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_GET_BUFFER));
  CPPUNIT_ASSERT(NULL == command);

  // now make sure we can't pass a bad param length larger than the buffer
  UpdateChecksum(bad_packet, sizeof(EXPECTED_GET_BUFFER));
  command = RDMRequest::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_GET_BUFFER));
  CPPUNIT_ASSERT(NULL == command);
  delete[] bad_packet;

  // change the param length of another packet and make sure the checksum fails
  bad_packet = new uint8_t[sizeof(EXPECTED_SET_BUFFER)];
  memcpy(bad_packet, EXPECTED_SET_BUFFER, sizeof(EXPECTED_SET_BUFFER));
  bad_packet[22] = 5;
  UpdateChecksum(bad_packet, sizeof(EXPECTED_SET_BUFFER));
  command = RDMRequest::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_SET_BUFFER));
  CPPUNIT_ASSERT(NULL == command);
  delete[] bad_packet;

  // now try to inflate a response
  command = RDMRequest::InflateFromData(
      EXPECTED_GET_RESPONSE_BUFFER,
      sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMRequest*>(NULL), command);
}

/*
 * Calculate the checksum for a packet, and verify
 */
void RDMCommandTest::PackAndVerify(const RDMCommand &command,
                                   const uint8_t *expected,
                                   unsigned int expected_length) {
  // now check packing
  unsigned int buffer_size = command.Size();
  uint8_t *buffer = new uint8_t[buffer_size];
  CPPUNIT_ASSERT(command.Pack(buffer, &buffer_size));

  for (unsigned int i = 0 ; i < expected_length; i++) {
    std::stringstream str;
    str << "Offset " << i << ", expected " << static_cast<int>(expected[i]) <<
      ", got " << static_cast<int>(buffer[i]);
    CPPUNIT_ASSERT_MESSAGE(str.str(), buffer[i] == expected[i]);
  }
  delete[] buffer;
}

/*
 * Test that we can inflate RDM response correctly
 */
void RDMCommandTest::testResponseInflation() {
  RDMResponse *command = RDMResponse::InflateFromData(NULL, 10);
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMResponse*>(NULL), command);

  command = RDMResponse::InflateFromData(EXPECTED_GET_RESPONSE_BUFFER, 0);
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMResponse*>(NULL), command);

  command = RDMResponse::InflateFromData(
      EXPECTED_GET_RESPONSE_BUFFER,
      sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  CPPUNIT_ASSERT(NULL != command);
  uint8_t expected_data[] = {0x5a, 0x5a, 0x5a, 0x5a};
  CPPUNIT_ASSERT_EQUAL((unsigned int) 4, command->ParamDataSize());
  CPPUNIT_ASSERT(0 == memcmp(expected_data, command->ParamData(),
                             command->ParamDataSize()));
  delete command;

  // change the param length and make sure the checksum fails
  uint8_t *bad_packet = new uint8_t[sizeof(EXPECTED_GET_RESPONSE_BUFFER)];
  memcpy(bad_packet, EXPECTED_GET_RESPONSE_BUFFER,
         sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  bad_packet[22] = 255;

  command = RDMResponse::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  CPPUNIT_ASSERT(NULL == command);

  // now make sure we can't pass a bad param length larger than the buffer
  UpdateChecksum(bad_packet, sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  command = RDMResponse::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_GET_RESPONSE_BUFFER));
  CPPUNIT_ASSERT(NULL == command);
  delete[] bad_packet;

  // change the param length of another packet and make sure the checksum fails
  bad_packet = new uint8_t[sizeof(EXPECTED_SET_BUFFER)];
  memcpy(bad_packet, EXPECTED_SET_BUFFER, sizeof(EXPECTED_SET_BUFFER));
  bad_packet[22] = 5;
  UpdateChecksum(bad_packet, sizeof(EXPECTED_SET_BUFFER));
  command = RDMResponse::InflateFromData(
      bad_packet,
      sizeof(EXPECTED_SET_BUFFER));
  CPPUNIT_ASSERT(NULL == command);
  delete[] bad_packet;

  // now try to inflate a response
  command = RDMResponse::InflateFromData(
      EXPECTED_GET_BUFFER,
      sizeof(EXPECTED_GET_BUFFER));
  CPPUNIT_ASSERT_EQUAL(reinterpret_cast<RDMResponse*>(NULL), command);
}

/*
 * Calculate a checksum for a packet and update it
 */
void RDMCommandTest::UpdateChecksum(uint8_t *expected,
                                    unsigned int expected_length) {
  unsigned int checksum = RDMCommand::START_CODE;
  for (unsigned int i = 0 ; i < expected_length - 2; i++)
    checksum += expected[i];

  expected[expected_length - 2] = checksum >> 8;
  expected[expected_length - 1] = checksum & 0xff;
}
<|endoftext|>