<commit_before>#include "rubymotion.h"

/// @class Scene < Node
/// This class represents a scene, an independent screen or stage of the
/// application workflow. A scene is responsible for handling events from the
/// device, providing a physics world for the sprites, and also starting the
/// game loop.
/// An application must have at least one scene, and the +Scene+ class is
/// designed to be subclassed.

VALUE rb_cScene = Qnil;

class mc_Scene : public cocos2d::LayerColor {
    public:
	cocos2d::Scene *scene;
	VALUE obj;
	SEL update_sel;

    mc_Scene() {
	obj = Qnil;
#if CC_TARGET_OS_IPHONE
	update_sel = rb_selector("update:");
#else
	update_sel = rb_selector("update");
#endif
    }

    static mc_Scene *create(void) {
	auto scene = new mc_Scene();
	scene->initWithColor(cocos2d::Color4B::BLACK);
	return scene;
    }

    virtual void update(float delta) {
	LayerColor::update(delta);
	VALUE arg = DBL2NUM(delta);
	rb_send(obj, update_sel, 1, &arg);
    }

    void setBackgroundColor(cocos2d::Color3B color) {
	setColor(color);
	updateColor();
    }
};

#define SCENE(obj) _COCOS_WRAP_GET(obj, mc_Scene)

extern "C"
cocos2d::Scene *
rb_any_to_scene(VALUE obj)
{
    if (rb_obj_is_kind_of(obj, rb_cScene)) {
	return SCENE(obj)->scene;
    }
    rb_raise(rb_eArgError, "expected Scene object");
}

static VALUE
scene_alloc(VALUE rcv, SEL sel)
{
    auto layer = mc_Scene::create();

    auto scene = cocos2d::Scene::createWithPhysics();
    scene->addChild(layer);
    layer->scene = scene;

    VALUE obj = rb_class_wrap_new((void *)layer, rcv);
    layer->obj = rb_retain(obj);
    return obj;
}

/// @group Constructors

/// @method #initialize
/// The default initializer. Subclasses can construct the scene interface in
/// this method, as well as providing an implementation for {#update}, then
/// run the update loop by calling {#start_update}.
/// @return [Scene] the receiver.

static VALUE
scene_initialize(VALUE rcv, SEL sel)
{
    return rcv;
}

/// @group Update Loop

/// @method #start_update
/// Starts the update loop. The +#update+ method will be called on this object
/// for every frame.
/// @return [Scene] the receiver.

static VALUE
scene_start_update(VALUE rcv, SEL sel)
{
    SCENE(rcv)->scheduleUpdate();
    return rcv;
}

/// @method #stop_update
/// Stops the update loop. The +#update+ method will no longer be called on
/// this object.
/// @return [Scene] the receiver.

static VALUE
scene_stop_update(VALUE rcv, SEL sel)
{
    SCENE(rcv)->unscheduleUpdate();
    return rcv;
}

/// @method #update(delta)
/// The update loop method. Subclasses can provide a custom implementation of
/// this method. The default implementation is empty.
/// @param delta [Float] a value representing the amount of time, in seconds,
///   since the last time this method was called.
/// @return [Scene] the receiver.

static VALUE
scene_update(VALUE rcv, SEL sel, VALUE delta)
{
    // Do nothing.
    return rcv;
}

/// @group Events

static VALUE
scene_add_listener(VALUE rcv, cocos2d::EventListener *listener)
{
    auto scene = SCENE(rcv);
    scene->getEventDispatcher()->addEventListenerWithSceneGraphPriority(
	    listener, scene);
    return rcv;
}

/// @method #on_touch_begin
/// Starts listening for touch begin events on the receiver.
/// @yield [Events::Touch] the given block will be yield when a touch begin
///   event is received.
/// @return [Scene] the receiver.

static VALUE
scene_on_touch_begin(VALUE rcv, SEL sel)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    auto listener = cocos2d::EventListenerTouchOneByOne::create();
    listener->onTouchBegan = [block](cocos2d::Touch *touch,
		cocos2d::Event *event) -> bool {
	VALUE touch_obj = rb_class_wrap_new((void *)touch,
		rb_cTouch);
	return RTEST(rb_block_call(block, 1, &touch_obj));
    };

    return scene_add_listener(rcv, listener);
}

/// @method #on_accelerate
/// Starts listening for accelerometer events on the receiver.
/// @yield [Events::Acceleration] the given block will be yield when an
///   accelerometer event is received from the device.
/// @return [Scene] the receiver.

static VALUE
scene_on_accelerate(VALUE rcv, SEL sel)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    cocos2d::Device::setAccelerometerEnabled(true);
    auto listener = cocos2d::EventListenerAcceleration::create(
	    [block](cocos2d::Acceleration *acc, cocos2d::Event *event) {
	    VALUE acc_obj = rb_class_wrap_new((void *)acc,
		    rb_cAcceleration);
	    rb_block_call(block, 1, &acc_obj);
	});

    return scene_add_listener(rcv, listener);
}

/// @method #on_contact_begin
/// Starts listening for contact begin events from the physics engine.
/// @yield [Events::PhysicsContact] the given block will be yield when a
///   contact event is received from the physics engine.
/// @return [Scene] the receiver.

static VALUE
scene_on_contact_begin(VALUE rcv, SEL sel)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    auto listener = cocos2d::EventListenerPhysicsContact::create();
    listener->onContactBegin = [block](cocos2d::PhysicsContact &contact)
	    -> bool {
//	VALUE touch_obj = rb_class_wrap_new((void *)touch,
//		rb_cTouch);
	return RTEST(rb_block_call(block, 0, NULL));
    };

    return scene_add_listener(rcv, listener);
}

/// @group Properties

/// @property #gravity
/// @return [Point] the gravity of the scene's physics world.

static VALUE
scene_gravity(VALUE rcv, SEL sel)
{
    return rb_ccvec2_to_obj(SCENE(rcv)->scene->getPhysicsWorld()->getGravity());
}

static VALUE
scene_gravity_set(VALUE rcv, SEL sel, VALUE arg)
{
    SCENE(rcv)->scene->getPhysicsWorld()->setGravity(rb_any_to_ccvec2(arg));
    return rcv;
}

/// @property #debug_physics?
/// @return [Boolean] whether the physics engine should draw debug lines.

static VALUE
scene_debug_physics(VALUE rcv, SEL sel)
{
    return SCENE(rcv)->scene->getPhysicsWorld()->getDebugDrawMask()
	== cocos2d::PhysicsWorld::DEBUGDRAW_NONE ? Qfalse : Qtrue;
}

static VALUE
scene_debug_physics_set(VALUE rcv, SEL sel, VALUE arg)
{
    SCENE(rcv)->scene->getPhysicsWorld()->setDebugDrawMask(RTEST(arg)
	    ? cocos2d::PhysicsWorld::DEBUGDRAW_ALL
	    : cocos2d::PhysicsWorld::DEBUGDRAW_NONE);
    return arg;
}

static VALUE
scene_color_set(VALUE rcv, SEL sel, VALUE val)
{
    SCENE(rcv)->setBackgroundColor(rb_any_to_cccolor3(val));
    return val;
}

extern "C"
void
Init_Layer(void)
{
    rb_cScene = rb_define_class_under(rb_mMC, "Scene", rb_cNode);

    rb_define_singleton_method(rb_cScene, "alloc", scene_alloc, 0);
    rb_define_method(rb_cScene, "initialize", scene_initialize, 0);
    rb_define_method(rb_cScene, "start_update", scene_start_update, 0);
    rb_define_method(rb_cScene, "stop_update", scene_stop_update, 0);
    rb_define_method(rb_cScene, "update", scene_update, 1);
    rb_define_method(rb_cScene, "on_touch_begin", scene_on_touch_begin, 0);
    rb_define_method(rb_cScene, "on_accelerate", scene_on_accelerate, 0);
    rb_define_method(rb_cScene, "on_contact_begin", scene_on_contact_begin, 0);
    rb_define_method(rb_cScene, "gravity", scene_gravity, 0);
    rb_define_method(rb_cScene, "gravity=", scene_gravity_set, 1);
    rb_define_method(rb_cScene, "debug_physics?", scene_debug_physics, 0);
    rb_define_method(rb_cScene, "debug_physics=", scene_debug_physics_set, 1);
    rb_define_method(rb_cScene, "color=", scene_color_set, 1);
}
<commit_msg>add Scene#schedule<commit_after>#include "rubymotion.h"

/// @class Scene < Node
/// This class represents a scene, an independent screen or stage of the
/// application workflow. A scene is responsible for handling events from the
/// device, providing a physics world for the sprites, and also starting the
/// game loop.
/// An application must have at least one scene, and the +Scene+ class is
/// designed to be subclassed.

VALUE rb_cScene = Qnil;

class mc_Scene : public cocos2d::LayerColor {
    public:
	cocos2d::Scene *scene;
	VALUE obj;
	SEL update_sel;

    mc_Scene() {
	obj = Qnil;
#if CC_TARGET_OS_IPHONE
	update_sel = rb_selector("update:");
#else
	update_sel = rb_selector("update");
#endif
    }

    static mc_Scene *create(void) {
	auto scene = new mc_Scene();
	scene->initWithColor(cocos2d::Color4B::BLACK);
	return scene;
    }

    virtual void update(float delta) {
	LayerColor::update(delta);
	VALUE arg = DBL2NUM(delta);
	rb_send(obj, update_sel, 1, &arg);
    }

    void setBackgroundColor(cocos2d::Color3B color) {
	setColor(color);
	updateColor();
    }
};

#define SCENE(obj) _COCOS_WRAP_GET(obj, mc_Scene)

extern "C"
cocos2d::Scene *
rb_any_to_scene(VALUE obj)
{
    if (rb_obj_is_kind_of(obj, rb_cScene)) {
	return SCENE(obj)->scene;
    }
    rb_raise(rb_eArgError, "expected Scene object");
}

static VALUE
scene_alloc(VALUE rcv, SEL sel)
{
    auto layer = mc_Scene::create();

    auto scene = cocos2d::Scene::createWithPhysics();
    scene->addChild(layer);
    layer->scene = scene;

    VALUE obj = rb_class_wrap_new((void *)layer, rcv);
    layer->obj = rb_retain(obj);
    return obj;
}

/// @group Constructors

/// @method #initialize
/// The default initializer. Subclasses can construct the scene interface in
/// this method, as well as providing an implementation for {#update}, then
/// run the update loop by calling {#start_update}.
/// @return [Scene] the receiver.

static VALUE
scene_initialize(VALUE rcv, SEL sel)
{
    return rcv;
}

/// @group Update Loop

/// @method #start_update
/// Starts the update loop. The +#update+ method will be called on this object
/// for every frame.
/// @return [Scene] the receiver.

static VALUE
scene_start_update(VALUE rcv, SEL sel)
{
    SCENE(rcv)->scheduleUpdate();
    return rcv;
}

/// @method #stop_update
/// Stops the update loop. The +#update+ method will no longer be called on
/// this object.
/// @return [Scene] the receiver.

static VALUE
scene_stop_update(VALUE rcv, SEL sel)
{
    SCENE(rcv)->unscheduleUpdate();
    return rcv;
}

/// @method #update(delta)
/// The update loop method. Subclasses can provide a custom implementation of
/// this method. The default implementation is empty.
/// @param delta [Float] a value representing the amount of time, in seconds,
///   since the last time this method was called.
/// @return [Scene] the receiver.

static VALUE
scene_update(VALUE rcv, SEL sel, VALUE delta)
{
    // Do nothing.
    return rcv;
}

/// @method #schedule(delay, repeat=0, interval=0)
/// Schedules a given block for execution.
/// @param delay [Float] the duration of the block, in seconds.
/// @param repeat [Integer] the number of times the block should be repeated.
/// @param interval [Float] the interval between repetitions, in seconds.
/// @yield [Float] the given block will be yield with the delta value,
///   in seconds.
/// @return [Scene] the receiver.

static VALUE
scene_schedule(VALUE rcv, SEL sel, int argc, VALUE *argv)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    VALUE interval = Qnil, repeat = Qnil, delay = Qnil;
    rb_scan_args(argc, argv, "12", &delay, &repeat, &interval);

    float interval_c  = RTEST(interval) ? NUM2DBL(interval) : 0;
    unsigned int repeat_c = RTEST(repeat) ? NUM2LONG(repeat) : 0;
    float delay_c = NUM2DBL(delay);

    SCENE(rcv)->schedule(
	    [block](float delta) {
		VALUE delta_obj = DBL2NUM(delta);
		rb_block_call(block, 1, &delta_obj);
	    },
	    interval_c, repeat_c, delay_c, "my_schedule_lambda");

    return rcv;
}

/// @group Events

static VALUE
scene_add_listener(VALUE rcv, cocos2d::EventListener *listener)
{
    auto scene = SCENE(rcv);
    scene->getEventDispatcher()->addEventListenerWithSceneGraphPriority(
	    listener, scene);
    return rcv;
}

/// @method #on_touch_begin
/// Starts listening for touch begin events on the receiver.
/// @yield [Events::Touch] the given block will be yield when a touch begin
///   event is received.
/// @return [Scene] the receiver.

static VALUE
scene_on_touch_begin(VALUE rcv, SEL sel)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    auto listener = cocos2d::EventListenerTouchOneByOne::create();
    listener->onTouchBegan = [block](cocos2d::Touch *touch,
		cocos2d::Event *event) -> bool {
	VALUE touch_obj = rb_class_wrap_new((void *)touch,
		rb_cTouch);
	return RTEST(rb_block_call(block, 1, &touch_obj));
    };

    return scene_add_listener(rcv, listener);
}

/// @method #on_accelerate
/// Starts listening for accelerometer events on the receiver.
/// @yield [Events::Acceleration] the given block will be yield when an
///   accelerometer event is received from the device.
/// @return [Scene] the receiver.

static VALUE
scene_on_accelerate(VALUE rcv, SEL sel)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    cocos2d::Device::setAccelerometerEnabled(true);
    auto listener = cocos2d::EventListenerAcceleration::create(
	    [block](cocos2d::Acceleration *acc, cocos2d::Event *event) {
	    VALUE acc_obj = rb_class_wrap_new((void *)acc,
		    rb_cAcceleration);
	    rb_block_call(block, 1, &acc_obj);
	});

    return scene_add_listener(rcv, listener);
}

/// @method #on_contact_begin
/// Starts listening for contact begin events from the physics engine.
/// @yield [Events::PhysicsContact] the given block will be yield when a
///   contact event is received from the physics engine.
/// @return [Scene] the receiver.

static VALUE
scene_on_contact_begin(VALUE rcv, SEL sel)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    auto listener = cocos2d::EventListenerPhysicsContact::create();
    listener->onContactBegin = [block](cocos2d::PhysicsContact &contact)
	    -> bool {
//	VALUE touch_obj = rb_class_wrap_new((void *)touch,
//		rb_cTouch);
	return RTEST(rb_block_call(block, 0, NULL));
    };

    return scene_add_listener(rcv, listener);
}

/// @group Properties

/// @property #gravity
/// @return [Point] the gravity of the scene's physics world.

static VALUE
scene_gravity(VALUE rcv, SEL sel)
{
    return rb_ccvec2_to_obj(SCENE(rcv)->scene->getPhysicsWorld()->getGravity());
}

static VALUE
scene_gravity_set(VALUE rcv, SEL sel, VALUE arg)
{
    SCENE(rcv)->scene->getPhysicsWorld()->setGravity(rb_any_to_ccvec2(arg));
    return rcv;
}

/// @property #debug_physics?
/// @return [Boolean] whether the physics engine should draw debug lines.

static VALUE
scene_debug_physics(VALUE rcv, SEL sel)
{
    return SCENE(rcv)->scene->getPhysicsWorld()->getDebugDrawMask()
	== cocos2d::PhysicsWorld::DEBUGDRAW_NONE ? Qfalse : Qtrue;
}

static VALUE
scene_debug_physics_set(VALUE rcv, SEL sel, VALUE arg)
{
    SCENE(rcv)->scene->getPhysicsWorld()->setDebugDrawMask(RTEST(arg)
	    ? cocos2d::PhysicsWorld::DEBUGDRAW_ALL
	    : cocos2d::PhysicsWorld::DEBUGDRAW_NONE);
    return arg;
}

static VALUE
scene_color_set(VALUE rcv, SEL sel, VALUE val)
{
    SCENE(rcv)->setBackgroundColor(rb_any_to_cccolor3(val));
    return val;
}

extern "C"
void
Init_Layer(void)
{
    rb_cScene = rb_define_class_under(rb_mMC, "Scene", rb_cNode);

    rb_define_singleton_method(rb_cScene, "alloc", scene_alloc, 0);
    rb_define_method(rb_cScene, "initialize", scene_initialize, 0);
    rb_define_method(rb_cScene, "start_update", scene_start_update, 0);
    rb_define_method(rb_cScene, "stop_update", scene_stop_update, 0);
    rb_define_method(rb_cScene, "update", scene_update, 1);
    rb_define_method(rb_cScene, "schedule", scene_schedule, -1);
    rb_define_method(rb_cScene, "on_touch_begin", scene_on_touch_begin, 0);
    rb_define_method(rb_cScene, "on_accelerate", scene_on_accelerate, 0);
    rb_define_method(rb_cScene, "on_contact_begin", scene_on_contact_begin, 0);
    rb_define_method(rb_cScene, "gravity", scene_gravity, 0);
    rb_define_method(rb_cScene, "gravity=", scene_gravity_set, 1);
    rb_define_method(rb_cScene, "debug_physics?", scene_debug_physics, 0);
    rb_define_method(rb_cScene, "debug_physics=", scene_debug_physics_set, 1);
    rb_define_method(rb_cScene, "color=", scene_color_set, 1);
}
<|endoftext|>


<commit_before>#include <physfs.h>
#include <libxml/parser.h>
#include "photon_level.h"
#include "photon_blocks.h"
#include "photon_core.h"

namespace photon{

namespace level{

void Draw(photon_level &level){
    for(auto &block : level.grid){
        blocks::Draw(block.second, glm::uvec2(block.first.first, block.first.second));
    }
}

void DrawBeams(photon_level &level){
    for(photon_laserbeam &beam : level.beams){
        opengl::DrawLaser(beam);
    }
}

void DrawBeamsLight(photon_level &level){
    for(photon_laserbeam &beam : level.beams){
        opengl::DrawLaserLight(beam);
    }
}

void DrawFX(photon_level &level){
    for(auto &block : level.grid){
        blocks::DrawFX(block.second, glm::uvec2(block.first.first, block.first.second));
    }
}

photon_level LoadLevelXML(const std::string &filename, photon_player &player){
    photon_level level;

    if(PHYSFS_exists(filename.c_str())){
        PHYSFS_File *file;
        long length;
        char *xml_buffer;

        file = PHYSFS_openRead(filename.c_str());
        if(!file){
            PrintToLog("ERROR: unable to open XML Level \"%s\"", filename.c_str());
            return level;
        }

        length = PHYSFS_fileLength(file);
        xml_buffer = (char*)malloc(length);

        PHYSFS_read(file, xml_buffer, 1, length);
        PHYSFS_close(file);

        xmlDocPtr doc = xmlParseMemory(xml_buffer, length);

        if(doc == nullptr) {
            PrintToLog("ERROR: Unable to load XML Level: Document not parsed successfully!");
            return level;
        }

        xmlNodePtr root = xmlDocGetRootElement(doc);
        if(root == nullptr) {
            PrintToLog("ERROR: Unable to load XML Level: empty document!");
            xmlFreeDoc(doc);
            return level;
        }
        if(xmlStrcmp(root->name, (const xmlChar *) "photon_level")) {
            PrintToLog("ERROR: Unable to load XML Level: root node not photon_level!");
            xmlFreeDoc(doc);
            return level;
        }

        xmlChar *width_str = xmlGetProp(root, (const xmlChar *)"width");
        xmlChar *height_str = xmlGetProp(root, (const xmlChar *)"height");

        level.width = atoi((char*)width_str);
        level.height = atoi((char*)height_str);

        xmlFree(width_str);
        xmlFree(height_str);

        PrintToLog("INFO: Level size %i x %i", level.width, level.height);

        //because we fill the edges with indestructible blocks.
        level.width += 2;
        level.height += 2;

        // fill the borders with indestructible blocks.
        for(int x = 0; x < level.width; x++){
            level.grid[photon_level_coord(x, 0               )].type = indestructible;
            level.grid[photon_level_coord(x, level.height - 1)].type = indestructible;
        }
        for(int y = 0; y < level.height; y++){
            level.grid[photon_level_coord(0,               y)].type = indestructible;
            level.grid[photon_level_coord(level.width - 1, y)].type = indestructible;
        }

        xmlNode *node = root->xmlChildrenNode;

        while(node != nullptr) {
            if((xmlStrEqual(node->name, (const xmlChar *)"data"))){
                xmlNode *row = node->xmlChildrenNode;
                while(row != nullptr) {
                    if((xmlStrEqual(row->name, (const xmlChar *)"row"))){
                        xmlChar *y_str = xmlGetProp(row, (const xmlChar *)"y");
                        uint8_t y = atoi((char*)y_str);
                        xmlFree(y_str);

                        xmlNode *block_xml = row->xmlChildrenNode;
                        while(block_xml != nullptr) {
                            if((xmlStrEqual(block_xml->name, (const xmlChar *)"block"))){
                                xmlChar *x_str = xmlGetProp(block_xml, (const xmlChar *)"x");
                                uint8_t x = atoi((char*)x_str);
                                xmlFree(x_str);

                                xmlChar *type_str = xmlGetProp(block_xml, (const xmlChar *)"type");

                                photon_block &block = level.grid[photon_level_coord(x,y)];

                                if((xmlStrEqual(type_str, (const xmlChar *)"plain"))){
                                    block.type = plain;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"mirror"))){
                                    block.type = mirror;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"mirror_locked"))){
                                    block.type = mirror_locked;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"tnt"))){
                                    block.type = tnt;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_red"))){
                                    block.type = filter_red;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_green"))){
                                    block.type = filter_green;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_blue"))){
                                    block.type = filter_blue;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_yellow"))){
                                    block.type = filter_yellow;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_cyan"))){
                                    block.type = filter_cyan;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_magenta"))){
                                    block.type = filter_magenta;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"emitter_white"))){
                                    block.type = emitter_white;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"emitter_red"))){
                                    block.type = emitter_red;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"emitter_green"))){
                                    block.type = emitter_green;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"emitter_blue"))){
                                    block.type = emitter_blue;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }
                                // TODO - load other block types.
                                xmlFree(type_str);
                            }
                            block_xml = block_xml->next;
                        }
                    }

                    row = row->next;
                }
            }else if((xmlStrEqual(node->name, (const xmlChar *)"inventory"))){
                xmlNode *item = node->xmlChildrenNode;
                while(item != nullptr) {
                    if((xmlStrEqual(item->name, (const xmlChar *)"item"))){
                        xmlChar *type_str = xmlGetProp(item, (const xmlChar *)"type");

                        if((xmlStrEqual(type_str, (const xmlChar *)"mirror"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, mirror);
                            }else{
                                player::AddItem(player, mirror, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"tnt"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, tnt);
                            }else{
                                player::AddItem(player, tnt, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_red"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_red);
                            }else{
                                player::AddItem(player, filter_red, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_green"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_green);
                            }else{
                                player::AddItem(player, filter_green, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_blue"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_blue);
                            }else{
                                player::AddItem(player, filter_blue, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_yellow"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_yellow);
                            }else{
                                player::AddItem(player, filter_yellow, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_cyan"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_cyan);
                            }else{
                                player::AddItem(player, filter_cyan, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_magenta"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_magenta);
                            }else{
                                player::AddItem(player, filter_magenta, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }
                        // TODO - load other block types.
                        xmlFree(type_str);
                    }
                    item = item->next;
                }
            }
            // TODO - load game mode & victory condition.
            node = node->next;
        }

        free(xml_buffer);
        xmlFreeDoc(doc);
    }else{
        PrintToLog("ERROR: Unable to load XML Level: \"%s\" does not exist!", filename.c_str());
    }

    return level;
}

void AdvanceFrame(photon_level &level, float time){
    level.beams.clear();
    for(auto &block : level.grid){
        blocks::OnFrame(glm::uvec2(block.first.first, block.first.second), level, time);
    }
    for(photon_laserbeam &beam : level.beams){
        tracer::TraceBeam(beam, level, time);
    }
}

}

}
<commit_msg>cap XML level dimensions to 250x250, print warning if it exceeds cap.<commit_after>#include <physfs.h>
#include <libxml/parser.h>
#include "photon_level.h"
#include "photon_blocks.h"
#include "photon_core.h"

namespace photon{

namespace level{

void Draw(photon_level &level){
    for(auto &block : level.grid){
        blocks::Draw(block.second, glm::uvec2(block.first.first, block.first.second));
    }
}

void DrawBeams(photon_level &level){
    for(photon_laserbeam &beam : level.beams){
        opengl::DrawLaser(beam);
    }
}

void DrawBeamsLight(photon_level &level){
    for(photon_laserbeam &beam : level.beams){
        opengl::DrawLaserLight(beam);
    }
}

void DrawFX(photon_level &level){
    for(auto &block : level.grid){
        blocks::DrawFX(block.second, glm::uvec2(block.first.first, block.first.second));
    }
}

photon_level LoadLevelXML(const std::string &filename, photon_player &player){
    photon_level level;

    if(PHYSFS_exists(filename.c_str())){
        PHYSFS_File *file;
        long length;
        char *xml_buffer;

        file = PHYSFS_openRead(filename.c_str());
        if(!file){
            PrintToLog("ERROR: unable to open XML Level \"%s\"", filename.c_str());
            return level;
        }

        length = PHYSFS_fileLength(file);
        xml_buffer = (char*)malloc(length);

        PHYSFS_read(file, xml_buffer, 1, length);
        PHYSFS_close(file);

        xmlDocPtr doc = xmlParseMemory(xml_buffer, length);

        if(doc == nullptr) {
            PrintToLog("ERROR: Unable to load XML Level: Document not parsed successfully!");
            return level;
        }

        xmlNodePtr root = xmlDocGetRootElement(doc);
        if(root == nullptr) {
            PrintToLog("ERROR: Unable to load XML Level: empty document!");
            xmlFreeDoc(doc);
            return level;
        }
        if(xmlStrcmp(root->name, (const xmlChar *) "photon_level")) {
            PrintToLog("ERROR: Unable to load XML Level: root node not photon_level!");
            xmlFreeDoc(doc);
            return level;
        }

        xmlChar *width_str = xmlGetProp(root, (const xmlChar *)"width");
        xmlChar *height_str = xmlGetProp(root, (const xmlChar *)"height");

        int w = atoi((char*)width_str);
        int h = atoi((char*)height_str);

        if(w < 250 && h < 250){
            level.width = w;
            level.height = h;
        }else{
            PrintToLog("WARNING: level \"%s\" dimensions exceed 250x250! capping...", filename.c_str());
            level.width = 250;
            level.height = 250;
        }

        xmlFree(width_str);
        xmlFree(height_str);

        PrintToLog("INFO: Level size %i x %i", level.width, level.height);

        //because we fill the edges with indestructible blocks.
        level.width += 2;
        level.height += 2;

        // fill the borders with indestructible blocks.
        for(int x = 0; x < level.width; x++){
            level.grid[photon_level_coord(x, 0               )].type = indestructible;
            level.grid[photon_level_coord(x, level.height - 1)].type = indestructible;
        }
        for(int y = 0; y < level.height; y++){
            level.grid[photon_level_coord(0,               y)].type = indestructible;
            level.grid[photon_level_coord(level.width - 1, y)].type = indestructible;
        }

        xmlNode *node = root->xmlChildrenNode;

        while(node != nullptr) {
            if((xmlStrEqual(node->name, (const xmlChar *)"data"))){
                xmlNode *row = node->xmlChildrenNode;
                while(row != nullptr) {
                    if((xmlStrEqual(row->name, (const xmlChar *)"row"))){
                        xmlChar *y_str = xmlGetProp(row, (const xmlChar *)"y");
                        uint8_t y = atoi((char*)y_str);
                        xmlFree(y_str);

                        xmlNode *block_xml = row->xmlChildrenNode;
                        while(block_xml != nullptr) {
                            if((xmlStrEqual(block_xml->name, (const xmlChar *)"block"))){
                                xmlChar *x_str = xmlGetProp(block_xml, (const xmlChar *)"x");
                                uint8_t x = atoi((char*)x_str);
                                xmlFree(x_str);

                                xmlChar *type_str = xmlGetProp(block_xml, (const xmlChar *)"type");

                                photon_block &block = level.grid[photon_level_coord(x,y)];

                                if((xmlStrEqual(type_str, (const xmlChar *)"plain"))){
                                    block.type = plain;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"mirror"))){
                                    block.type = mirror;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"mirror_locked"))){
                                    block.type = mirror_locked;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"tnt"))){
                                    block.type = tnt;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_red"))){
                                    block.type = filter_red;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_green"))){
                                    block.type = filter_green;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_blue"))){
                                    block.type = filter_blue;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_yellow"))){
                                    block.type = filter_yellow;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_cyan"))){
                                    block.type = filter_cyan;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_magenta"))){
                                    block.type = filter_magenta;
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"emitter_white"))){
                                    block.type = emitter_white;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"emitter_red"))){
                                    block.type = emitter_red;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"emitter_green"))){
                                    block.type = emitter_green;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }else if((xmlStrEqual(type_str, (const xmlChar *)"emitter_blue"))){
                                    block.type = emitter_blue;

                                    xmlChar *angle_str = xmlGetProp(block_xml, (const xmlChar *)"angle");

                                    block.data = atof((char*)angle_str);

                                    xmlFree(angle_str);
                                }
                                // TODO - load other block types.
                                xmlFree(type_str);
                            }
                            block_xml = block_xml->next;
                        }
                    }

                    row = row->next;
                }
            }else if((xmlStrEqual(node->name, (const xmlChar *)"inventory"))){
                xmlNode *item = node->xmlChildrenNode;
                while(item != nullptr) {
                    if((xmlStrEqual(item->name, (const xmlChar *)"item"))){
                        xmlChar *type_str = xmlGetProp(item, (const xmlChar *)"type");

                        if((xmlStrEqual(type_str, (const xmlChar *)"mirror"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, mirror);
                            }else{
                                player::AddItem(player, mirror, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"tnt"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, tnt);
                            }else{
                                player::AddItem(player, tnt, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_red"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_red);
                            }else{
                                player::AddItem(player, filter_red, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_green"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_green);
                            }else{
                                player::AddItem(player, filter_green, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_blue"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_blue);
                            }else{
                                player::AddItem(player, filter_blue, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_yellow"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_yellow);
                            }else{
                                player::AddItem(player, filter_yellow, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_cyan"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_cyan);
                            }else{
                                player::AddItem(player, filter_cyan, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }else if((xmlStrEqual(type_str, (const xmlChar *)"filter_magenta"))){
                            xmlChar *amount_str = xmlGetProp(item, (const xmlChar *)"amount");

                            if((xmlStrEqual(amount_str, (const xmlChar *)"infinite"))){
                                player::GiveInfiniteItems(player, filter_magenta);
                            }else{
                                player::AddItem(player, filter_magenta, atoi((char*)amount_str));
                            }

                            xmlFree(amount_str);
                        }
                        // TODO - load other block types.
                        xmlFree(type_str);
                    }
                    item = item->next;
                }
            }
            // TODO - load game mode & victory condition.
            node = node->next;
        }

        free(xml_buffer);
        xmlFreeDoc(doc);
    }else{
        PrintToLog("ERROR: Unable to load XML Level: \"%s\" does not exist!", filename.c_str());
    }

    return level;
}

void AdvanceFrame(photon_level &level, float time){
    level.beams.clear();
    for(auto &block : level.grid){
        blocks::OnFrame(glm::uvec2(block.first.first, block.first.second), level, time);
    }
    for(photon_laserbeam &beam : level.beams){
        tracer::TraceBeam(beam, level, time);
    }
}

}

}
<|endoftext|>


<commit_before>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ===========================================================================
// File: perfmap.cpp
//

#include "common.h"

#if defined(FEATURE_PERFMAP) && !defined(DACCESS_COMPILE)
#include "perfmap.h"
#include "perfinfo.h"
#include "pal.h"

PerfMap * PerfMap::s_Current = nullptr;

// Initialize the map for the process - called from EEStartupHelper.
void PerfMap::Initialize()
{
    LIMITED_METHOD_CONTRACT;

    // Only enable the map if requested.
    if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled))
    {
        // Get the current process id.
        int currentPid = GetCurrentProcessId();

        // Create the map.
        s_Current = new PerfMap(currentPid);

        int signalNum = (int) CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapIgnoreSignal);

        if (signalNum > 0)
        {
            PAL_IgnoreProfileSignal(signalNum);
        }
    }
}

// Destroy the map for the process - called from EEShutdownHelper.
void PerfMap::Destroy()
{
    LIMITED_METHOD_CONTRACT;

    if (s_Current != nullptr)
    {
        delete s_Current;
        s_Current = nullptr;
    }
}

// Construct a new map for the process.
PerfMap::PerfMap(int pid)
{
    LIMITED_METHOD_CONTRACT;

    // Initialize with no failures.
    m_ErrorEncountered = false;

    m_StubsMapped = 0;

    // Build the path to the map file on disk.
    WCHAR tempPath[MAX_LONGPATH+1];
    if(!GetTempPathW(MAX_LONGPATH, tempPath))
    {
        return;
    }

    SString path;
    path.Printf("%Sperf-%d.map", &tempPath, pid);

    // Open the map file for writing.
    OpenFile(path);

    m_PerfInfo = new PerfInfo(pid);
}

// Construct a new map without a specified file name.
// Used for offline creation of NGEN map files.
PerfMap::PerfMap()
  : m_FileStream(nullptr)
  , m_PerfInfo(nullptr)
{
    LIMITED_METHOD_CONTRACT;

    // Initialize with no failures.
    m_ErrorEncountered = false;

    m_StubsMapped = 0;
}

// Clean-up resources.
PerfMap::~PerfMap()
{
    LIMITED_METHOD_CONTRACT;

    delete m_FileStream;
    m_FileStream = nullptr;

    delete m_PerfInfo;
    m_PerfInfo = nullptr;
}

// Open the specified destination map file.
void PerfMap::OpenFile(SString& path)
{
    STANDARD_VM_CONTRACT;

    // Open the file stream.
    m_FileStream = new (nothrow) CFileStream();
    if(m_FileStream != nullptr)
    {
        HRESULT hr = m_FileStream->OpenForWrite(path.GetUnicode());
        if(FAILED(hr))
        {
            delete m_FileStream;
            m_FileStream = nullptr;
        }
    }
}

// Write a line to the map file.
void PerfMap::WriteLine(SString& line)
{
    STANDARD_VM_CONTRACT;

    EX_TRY
    {
        // Write the line.
        // The PAL already takes a lock when writing, so we don't need to do so here.
        StackScratchBuffer scratch;
        const char * strLine = line.GetANSI(scratch);
        ULONG inCount = line.GetCount();
        ULONG outCount;
        m_FileStream->Write(strLine, inCount, &outCount);

        if (inCount != outCount)
        {
            // This will cause us to stop writing to the file.
            // The file will still remain open until shutdown so that we don't have to take a lock at this level when we touch the file stream.
            m_ErrorEncountered = true;
        }

    }
    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

// Log a method to the map.
void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
{
    CONTRACTL{
        THROWS;
        GC_NOTRIGGER;
        MODE_PREEMPTIVE;
        PRECONDITION(pMethod != nullptr);
        PRECONDITION(pCode != nullptr);
        PRECONDITION(codeSize > 0);
    } CONTRACTL_END;

    if (m_FileStream == nullptr || m_ErrorEncountered)
    {
        // A failure occurred, do not log.
        return;
    }

    // Logging failures should not cause any exceptions to flow upstream.
    EX_TRY
    {
        // Get the full method signature.
        SString fullMethodSignature;
        pMethod->GetFullMethodInfo(fullMethodSignature);

        // Build the map file line.
        StackScratchBuffer scratch;
        SString line;
        line.Printf("%p %x %s\n", pCode, codeSize, fullMethodSignature.GetANSI(scratch));

        // Write the line.
        WriteLine(line);
    }
    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

void PerfMap::LogImageLoad(PEFile * pFile)
{
    if (s_Current != nullptr)
    {
        s_Current->LogImage(pFile);
    }
}

// Log an image load to the map.
void PerfMap::LogImage(PEFile * pFile)
{
    CONTRACTL{
        THROWS;
        GC_NOTRIGGER;
        MODE_PREEMPTIVE;
        PRECONDITION(pFile != nullptr);
    } CONTRACTL_END;

    if (m_FileStream == nullptr || m_ErrorEncountered)
    {
        // A failure occurred, do not log.
        return;
    }

    EX_TRY
    {
        WCHAR wszSignature[39];
        GetNativeImageSignature(pFile, wszSignature, lengthof(wszSignature));

        m_PerfInfo->LogImage(pFile, wszSignature);
    }
    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

// Log a method to the map.
void PerfMap::LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
{
    LIMITED_METHOD_CONTRACT;

    if (s_Current != nullptr)
    {
        s_Current->LogMethod(pMethod, pCode, codeSize);
    }
}

// Log a set of stub to the map.
void PerfMap::LogStubs(const char* stubType, const char* stubOwner, PCODE pCode, size_t codeSize)
{
    LIMITED_METHOD_CONTRACT;

    if (s_Current == nullptr || s_Current->m_FileStream == nullptr)
    {
        return;
    }

    // Logging failures should not cause any exceptions to flow upstream.
    EX_TRY
    {
        if(!stubOwner)
        {
            stubOwner = "?";
        }
        if(!stubType)
        {
            stubOwner = "?";
        }

        // Build the map file line.
        SString line;
        line.Printf("%p %x stub<%d> %s<%s>\n", pCode, codeSize, ++(s_Current->m_StubsMapped), stubType, stubOwner);

        // Write the line.
        s_Current->WriteLine(line);
    }
    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

void PerfMap::GetNativeImageSignature(PEFile * pFile, WCHAR * pwszSig, unsigned int nSigSize)
{
    CONTRACTL{
        PRECONDITION(pFile != nullptr);
        PRECONDITION(pwszSig != nullptr);
        PRECONDITION(nSigSize >= 39);
    } CONTRACTL_END;

    // We use the MVID as the signature, since ready to run images
    // don't have a native image signature.
    GUID mvid;
    pFile->GetMVID(&mvid);
    if(!StringFromGUID2(mvid, pwszSig, nSigSize))
    {
        pwszSig[0] = '\0';
    }
}

// Create a new native image perf map.
NativeImagePerfMap::NativeImagePerfMap(Assembly * pAssembly, BSTR pDestPath)
  : PerfMap()
{
    STANDARD_VM_CONTRACT;

    // Generate perfmap path.

    // Get the assembly simple name.
    LPCUTF8 lpcSimpleName = pAssembly->GetSimpleName();

    // Get the native image signature (GUID).
    // Used to ensure that we match symbols to the correct NGEN image.
    WCHAR wszSignature[39];
    GetNativeImageSignature(pAssembly->GetManifestFile(), wszSignature, lengthof(wszSignature));

    // Build the path to the perfmap file, which consists of <inputpath><imagesimplename>.ni.<signature>.map.
    // Example: /tmp/mscorlib.ni.{GUID}.map
    SString sDestPerfMapPath;
    sDestPerfMapPath.Printf("%S%s.ni.%S.map", pDestPath, lpcSimpleName, wszSignature);

    // Open the perf map file.
    OpenFile(sDestPerfMapPath);
}

// Log data to the perfmap for the specified module.
void NativeImagePerfMap::LogDataForModule(Module * pModule)
{
    STANDARD_VM_CONTRACT;

    PEImageLayout * pLoadedLayout = pModule->GetFile()->GetLoaded();
    _ASSERTE(pLoadedLayout != nullptr);

    SIZE_T baseAddr = (SIZE_T)pLoadedLayout->GetBase();

#ifdef FEATURE_READYTORUN_COMPILER
    if (pLoadedLayout->HasReadyToRunHeader())
    {
        ReadyToRunInfo::MethodIterator mi(pModule->GetReadyToRunInfo());
        while (mi.Next())
        {
            MethodDesc *hotDesc = mi.GetMethodDesc();

            LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), baseAddr);
        }
    }
    else
#endif // FEATURE_READYTORUN_COMPILER
    {
        MethodIterator mi((PTR_Module)pModule);
        while (mi.Next())
        {
            MethodDesc *hotDesc = mi.GetMethodDesc();
            hotDesc->CheckRestore();

            LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), baseAddr);
        }
    }
}

// Log a pre-compiled method to the perfmap.
void NativeImagePerfMap::LogPreCompiledMethod(MethodDesc * pMethod, PCODE pCode, SIZE_T baseAddr)
{
    STANDARD_VM_CONTRACT;

    // Get information about the NGEN'd method code.
    EECodeInfo codeInfo(pCode);
    _ASSERTE(codeInfo.IsValid());

    IJitManager::MethodRegionInfo methodRegionInfo;
    codeInfo.GetMethodRegionInfo(&methodRegionInfo);

    // NGEN can split code between hot and cold sections which are separate in memory.
    // Emit an entry for each section if it is used.
    if (methodRegionInfo.hotSize > 0)
    {
        LogMethod(pMethod, (PCODE)methodRegionInfo.hotStartAddress - baseAddr, methodRegionInfo.hotSize);
    }

    if (methodRegionInfo.coldSize > 0)
    {
        LogMethod(pMethod, (PCODE)methodRegionInfo.coldStartAddress - baseAddr, methodRegionInfo.coldSize);
    }
}

#endif // FEATURE_PERFMAP && !DACCESS_COMPILE
<commit_msg>Use 32-bit address format string during crossgen in src/vm/perfmap.cpp<commit_after>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ===========================================================================
// File: perfmap.cpp
//

#include "common.h"

#if defined(FEATURE_PERFMAP) && !defined(DACCESS_COMPILE)
#include "perfmap.h"
#include "perfinfo.h"
#include "pal.h"

// The code addresses are actually native image offsets during crossgen. Print
// them as 32-bit numbers for consistent output when cross-targeting and to
// make the output more compact.

#ifdef CROSSGEN_COMPILE
#define FMT_CODE_ADDR "%08x"
#else
#define FMT_CODE_ADDR "%p"
#endif

PerfMap * PerfMap::s_Current = nullptr;

// Initialize the map for the process - called from EEStartupHelper.
void PerfMap::Initialize()
{
    LIMITED_METHOD_CONTRACT;

    // Only enable the map if requested.
    if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapEnabled))
    {
        // Get the current process id.
        int currentPid = GetCurrentProcessId();

        // Create the map.
        s_Current = new PerfMap(currentPid);

        int signalNum = (int) CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapIgnoreSignal);

        if (signalNum > 0)
        {
            PAL_IgnoreProfileSignal(signalNum);
        }
    }
}

// Destroy the map for the process - called from EEShutdownHelper.
void PerfMap::Destroy()
{
    LIMITED_METHOD_CONTRACT;

    if (s_Current != nullptr)
    {
        delete s_Current;
        s_Current = nullptr;
    }
}

// Construct a new map for the process.
PerfMap::PerfMap(int pid)
{
    LIMITED_METHOD_CONTRACT;

    // Initialize with no failures.
    m_ErrorEncountered = false;

    m_StubsMapped = 0;

    // Build the path to the map file on disk.
    WCHAR tempPath[MAX_LONGPATH+1];
    if(!GetTempPathW(MAX_LONGPATH, tempPath))
    {
        return;
    }

    SString path;
    path.Printf("%Sperf-%d.map", &tempPath, pid);

    // Open the map file for writing.
    OpenFile(path);

    m_PerfInfo = new PerfInfo(pid);
}

// Construct a new map without a specified file name.
// Used for offline creation of NGEN map files.
PerfMap::PerfMap()
  : m_FileStream(nullptr)
  , m_PerfInfo(nullptr)
{
    LIMITED_METHOD_CONTRACT;

    // Initialize with no failures.
    m_ErrorEncountered = false;

    m_StubsMapped = 0;
}

// Clean-up resources.
PerfMap::~PerfMap()
{
    LIMITED_METHOD_CONTRACT;

    delete m_FileStream;
    m_FileStream = nullptr;

    delete m_PerfInfo;
    m_PerfInfo = nullptr;
}

// Open the specified destination map file.
void PerfMap::OpenFile(SString& path)
{
    STANDARD_VM_CONTRACT;

    // Open the file stream.
    m_FileStream = new (nothrow) CFileStream();
    if(m_FileStream != nullptr)
    {
        HRESULT hr = m_FileStream->OpenForWrite(path.GetUnicode());
        if(FAILED(hr))
        {
            delete m_FileStream;
            m_FileStream = nullptr;
        }
    }
}

// Write a line to the map file.
void PerfMap::WriteLine(SString& line)
{
    STANDARD_VM_CONTRACT;

    EX_TRY
    {
        // Write the line.
        // The PAL already takes a lock when writing, so we don't need to do so here.
        StackScratchBuffer scratch;
        const char * strLine = line.GetANSI(scratch);
        ULONG inCount = line.GetCount();
        ULONG outCount;
        m_FileStream->Write(strLine, inCount, &outCount);

        if (inCount != outCount)
        {
            // This will cause us to stop writing to the file.
            // The file will still remain open until shutdown so that we don't have to take a lock at this level when we touch the file stream.
            m_ErrorEncountered = true;
        }

    }
    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

// Log a method to the map.
void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
{
    CONTRACTL{
        THROWS;
        GC_NOTRIGGER;
        MODE_PREEMPTIVE;
        PRECONDITION(pMethod != nullptr);
        PRECONDITION(pCode != nullptr);
        PRECONDITION(codeSize > 0);
    } CONTRACTL_END;

    if (m_FileStream == nullptr || m_ErrorEncountered)
    {
        // A failure occurred, do not log.
        return;
    }

    // Logging failures should not cause any exceptions to flow upstream.
    EX_TRY
    {
        // Get the full method signature.
        SString fullMethodSignature;
        pMethod->GetFullMethodInfo(fullMethodSignature);

        // Build the map file line.
        StackScratchBuffer scratch;
        SString line;
        line.Printf(FMT_CODE_ADDR " %x %s\n", pCode, codeSize, fullMethodSignature.GetANSI(scratch));

        // Write the line.
        WriteLine(line);
    }
    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

void PerfMap::LogImageLoad(PEFile * pFile)
{
    if (s_Current != nullptr)
    {
        s_Current->LogImage(pFile);
    }
}

// Log an image load to the map.
void PerfMap::LogImage(PEFile * pFile)
{
    CONTRACTL{
        THROWS;
        GC_NOTRIGGER;
        MODE_PREEMPTIVE;
        PRECONDITION(pFile != nullptr);
    } CONTRACTL_END;

    if (m_FileStream == nullptr || m_ErrorEncountered)
    {
        // A failure occurred, do not log.
        return;
    }

    EX_TRY
    {
        WCHAR wszSignature[39];
        GetNativeImageSignature(pFile, wszSignature, lengthof(wszSignature));

        m_PerfInfo->LogImage(pFile, wszSignature);
    }
    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

// Log a method to the map.
void PerfMap::LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
{
    LIMITED_METHOD_CONTRACT;

    if (s_Current != nullptr)
    {
        s_Current->LogMethod(pMethod, pCode, codeSize);
    }
}

// Log a set of stub to the map.
void PerfMap::LogStubs(const char* stubType, const char* stubOwner, PCODE pCode, size_t codeSize)
{
    LIMITED_METHOD_CONTRACT;

    if (s_Current == nullptr || s_Current->m_FileStream == nullptr)
    {
        return;
    }

    // Logging failures should not cause any exceptions to flow upstream.
    EX_TRY
    {
        if(!stubOwner)
        {
            stubOwner = "?";
        }
        if(!stubType)
        {
            stubOwner = "?";
        }

        // Build the map file line.
        SString line;
        line.Printf(FMT_CODE_ADDR " %x stub<%d> %s<%s>\n", pCode, codeSize, ++(s_Current->m_StubsMapped), stubType, stubOwner);

        // Write the line.
        s_Current->WriteLine(line);
    }
    EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
}

void PerfMap::GetNativeImageSignature(PEFile * pFile, WCHAR * pwszSig, unsigned int nSigSize)
{
    CONTRACTL{
        PRECONDITION(pFile != nullptr);
        PRECONDITION(pwszSig != nullptr);
        PRECONDITION(nSigSize >= 39);
    } CONTRACTL_END;

    // We use the MVID as the signature, since ready to run images
    // don't have a native image signature.
    GUID mvid;
    pFile->GetMVID(&mvid);
    if(!StringFromGUID2(mvid, pwszSig, nSigSize))
    {
        pwszSig[0] = '\0';
    }
}

// Create a new native image perf map.
NativeImagePerfMap::NativeImagePerfMap(Assembly * pAssembly, BSTR pDestPath)
  : PerfMap()
{
    STANDARD_VM_CONTRACT;

    // Generate perfmap path.

    // Get the assembly simple name.
    LPCUTF8 lpcSimpleName = pAssembly->GetSimpleName();

    // Get the native image signature (GUID).
    // Used to ensure that we match symbols to the correct NGEN image.
    WCHAR wszSignature[39];
    GetNativeImageSignature(pAssembly->GetManifestFile(), wszSignature, lengthof(wszSignature));

    // Build the path to the perfmap file, which consists of <inputpath><imagesimplename>.ni.<signature>.map.
    // Example: /tmp/mscorlib.ni.{GUID}.map
    SString sDestPerfMapPath;
    sDestPerfMapPath.Printf("%S%s.ni.%S.map", pDestPath, lpcSimpleName, wszSignature);

    // Open the perf map file.
    OpenFile(sDestPerfMapPath);
}

// Log data to the perfmap for the specified module.
void NativeImagePerfMap::LogDataForModule(Module * pModule)
{
    STANDARD_VM_CONTRACT;

    PEImageLayout * pLoadedLayout = pModule->GetFile()->GetLoaded();
    _ASSERTE(pLoadedLayout != nullptr);

    SIZE_T baseAddr = (SIZE_T)pLoadedLayout->GetBase();

#ifdef FEATURE_READYTORUN_COMPILER
    if (pLoadedLayout->HasReadyToRunHeader())
    {
        ReadyToRunInfo::MethodIterator mi(pModule->GetReadyToRunInfo());
        while (mi.Next())
        {
            MethodDesc *hotDesc = mi.GetMethodDesc();

            LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), baseAddr);
        }
    }
    else
#endif // FEATURE_READYTORUN_COMPILER
    {
        MethodIterator mi((PTR_Module)pModule);
        while (mi.Next())
        {
            MethodDesc *hotDesc = mi.GetMethodDesc();
            hotDesc->CheckRestore();

            LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), baseAddr);
        }
    }
}

// Log a pre-compiled method to the perfmap.
void NativeImagePerfMap::LogPreCompiledMethod(MethodDesc * pMethod, PCODE pCode, SIZE_T baseAddr)
{
    STANDARD_VM_CONTRACT;

    // Get information about the NGEN'd method code.
    EECodeInfo codeInfo(pCode);
    _ASSERTE(codeInfo.IsValid());

    IJitManager::MethodRegionInfo methodRegionInfo;
    codeInfo.GetMethodRegionInfo(&methodRegionInfo);

    // NGEN can split code between hot and cold sections which are separate in memory.
    // Emit an entry for each section if it is used.
    if (methodRegionInfo.hotSize > 0)
    {
        LogMethod(pMethod, (PCODE)methodRegionInfo.hotStartAddress - baseAddr, methodRegionInfo.hotSize);
    }

    if (methodRegionInfo.coldSize > 0)
    {
        LogMethod(pMethod, (PCODE)methodRegionInfo.coldStartAddress - baseAddr, methodRegionInfo.coldSize);
    }
}

#endif // FEATURE_PERFMAP && !DACCESS_COMPILE
<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include "Support/CmdLine.h"

#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <set>
#include <unordered_map>
#include <climits>
#include <type_traits>

#include "PrettyPrint.h"

namespace cl = support::cl;

using support::StringRef;
using support::pretty;

namespace support {
namespace cl {

    template<class T, class P>
    void prettyPrint(std::ostream& stream, Option<T, P> const& option)
    {
        stream << option.getName() << ":\n";
        stream << "  count = " << option.getCount() << "\n";
        stream << "  value = " << pretty(option.get());
    }

}}

int main(int argc, char* argv[])
{
    //----------------------------------------------------------------------------------------------

    cl::CmdLine cmd(argv[0], "A short description.\n\nA long description.");

                    //------------------------------------------------------------------------------

    double y = -1.0;

    auto y_ref = cl::makeOption<double&>(
        cmd, "y",
        cl::ArgName("float"),
        cl::Desc("Enter a floating-point number"),
        cl::ArgRequired,
        cl::init(y)
        );

                    //------------------------------------------------------------------------------

    auto g = cl::makeOption<bool>(cmd, "g", cl::Grouping, cl::ZeroOrMore);
    auto h = cl::makeOption<bool>(cmd, "h", cl::Grouping, cl::ZeroOrMore);

    //auto gh = cl::makeOption<bool>(cmd, "gh", cl::Prefix);

                    //------------------------------------------------------------------------------

    auto z = cl::makeOption<std::set<int>>(
        cmd, "z",
        cl::ArgName("int"),
        cl::Desc("A list of integers"),
        cl::ZeroOrMore,
        cl::ArgRequired,
        cl::CommaSeparated
        );

                    //------------------------------------------------------------------------------

    std::initializer_list<std::string> Iinit = {
        "eins", "zwei", "drei", "vier", "funf"
    };

    auto I = cl::makeOption<std::vector<std::string>>(
        cmd, "I",
        cl::ArgName("dir"),
        cl::Desc("Add the directory dir to the list of directories to be searched for header files."),
        cl::Prefix,
        cl::ZeroOrMore,
        cl::init(Iinit)
        );

                    //------------------------------------------------------------------------------

////    auto regexParser = [](StringRef value, size_t, std::regex& result) -> bool
////    {
////        result = value.str();
////        return true;
////    };
//
//    std::regex regex_;
//
//    auto regex = cl::makeOption<std::regex&>(
//        cmd,
//        cl::init(regex_), "regex", cl::Positional, cl::Required
//        );

                    //------------------------------------------------------------------------------

    auto files = cl::makeOption<std::vector<std::string>>(cmd, "files", cl::Positional, cl::ZeroOrMore);

                    //------------------------------------------------------------------------------

    enum OptLevel : unsigned {
        None, Trivial, Default, Expensive
    };

    auto optParser = cl::MapParser<OptLevel>({
        { "O0", None        },
        { "O1", Trivial     },
        { "O2", Default     },
        { "O3", Expensive   }
    });

    auto opt = cl::makeOptionPiecewise<OptLevel>(
        optParser,
        cmd,
        cl::ArgDisallowed,
        cl::Desc("Choose an optimization level"),
        cl::init(None)
        );

                    //------------------------------------------------------------------------------

    enum Simpson {
        Homer, Marge, Bart, Lisa, Maggie, SideshowBob
    };

    auto simpsonParser = cl::MapParser<Simpson>({
        { "homer",       Homer  },
        { "marge",       Marge  },
        { "bart",        Bart   },
        { "el barto",    Bart   },
        { "lisa",        Lisa   },
        { "maggie",      Maggie }
    });

    auto simpson = cl::makeOptionPiecewise<Simpson>(
        simpsonParser,
        cmd, "simpson",
        cl::Desc("Choose a Simpson"),
        cl::ArgRequired,
        cl::init(SideshowBob)
        );

                    //------------------------------------------------------------------------------

    auto bf = cl::makeOptionPiecewise<unsigned>(
        cl::BinaryOpParser<std::bit_or<unsigned>>(),
        cmd, "bf",
        cl::CommaSeparated,
        cl::ArgRequired,
        cl::ZeroOrMore
        );

                    //------------------------------------------------------------------------------

    auto helpParser = [&](StringRef /*value*/, size_t /*i*/, bool& /*result*/) -> bool
    {
        cmd.help();
        exit(0);
    };

    auto help = cl::makeOptionPiecewise<bool>(helpParser, cmd, "help", cl::Optional);

    //----------------------------------------------------------------------------------------------

    if (!cmd.parse({argv + 1, argv + argc}, /*ignoreUnknowns*/false))
        return -1;

    //----------------------------------------------------------------------------------------------

    std::cout << pretty(y_ref) << std::endl;
    std::cout << pretty(g) << std::endl;
    std::cout << pretty(h) << std::endl;
    std::cout << pretty(z) << std::endl;
    std::cout << pretty(I) << std::endl;
    std::cout << pretty(opt) << std::endl;
    std::cout << pretty(simpson) << std::endl;
    std::cout << pretty(help) << std::endl;
//    std::cout << pretty(regex) << std::endl;
    std::cout << "bf = 0x" << std::hex << bf.get() << std::endl;

    std::cout << "files:\n";
    for (auto& s : files)
        std::cout << "  \"" << s << "\"" << std::endl;

    //----------------------------------------------------------------------------------------------

    return 0;
}
<commit_msg>Update the test app<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include "Support/CmdLine.h"
#include "Support/PrettyPrint.h"

#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <set>
#include <unordered_map>
#include <climits>
#include <type_traits>

namespace cl = support::cl;

using support::StringRef;
using support::pretty;

namespace support {
namespace cl {

    template<class T, class U>
    struct Parser<std::pair<T, U>>
    {
        bool operator ()(StringRef value, size_t i, std::pair<T, U>& result) const
        {
            auto p = value.split(':');

            return Parser<T>()(p.first.trim(), i, result.first)
                && Parser<U>()(p.second.trim(), i, result.second);
        }
    };

    template<class T, class P>
    void prettyPrint(std::ostream& stream, Option<T, P> const& option)
    {
        stream << option.getName() << ":\n";
        stream << "  count = " << option.getCount() << "\n";
        stream << "  value = " << pretty(option.get());
    }

}}

int main(int argc, char* argv[])
{
    //----------------------------------------------------------------------------------------------

    cl::CmdLine cmd(argv[0], "A short description.\n\nA long description.");

                    //------------------------------------------------------------------------------

    double y = -1.0;

    auto y_ref = cl::makeOption<double&>(
        cmd, "y",
        cl::ArgName("float"),
        cl::Desc("Enter a floating-point number"),
        cl::ArgRequired,
        cl::init(y)
        );

                    //------------------------------------------------------------------------------

    auto g = cl::makeOption<bool>(cmd, "g", cl::Grouping, cl::ZeroOrMore);
    auto h = cl::makeOption<bool>(cmd, "h", cl::Grouping, cl::ZeroOrMore);

    //auto gh = cl::makeOption<bool>(cmd, "gh", cl::Prefix);

                    //------------------------------------------------------------------------------

    auto z = cl::makeOption<std::set<int>>(
        cmd, "z",
        cl::ArgName("int"),
        cl::Desc("A list of integers"),
        cl::ZeroOrMore,
        cl::ArgRequired,
        cl::CommaSeparated
        );

                    //------------------------------------------------------------------------------

    std::initializer_list<std::string> Iinit = {
        "eins", "zwei", "drei", "vier", "funf"
    };

    auto I = cl::makeOption<std::vector<std::string>>(
        cmd, "I",
        cl::ArgName("dir"),
        cl::Desc("Add the directory dir to the list of directories to be searched for header files."),
        cl::Prefix,
        cl::ZeroOrMore,
        cl::init(Iinit)
        );

                    //------------------------------------------------------------------------------

////    auto regexParser = [](StringRef value, size_t, std::regex& result) -> bool
////    {
////        result = value.str();
////        return true;
////    };
//
//    std::regex regex_;
//
//    auto regex = cl::makeOption<std::regex&>(
//        cmd,
//        cl::init(regex_), "regex", cl::Positional, cl::Required
//        );

                    //------------------------------------------------------------------------------

    auto files = cl::makeOption<std::vector<std::string>>(cmd, "files", cl::Positional, cl::ZeroOrMore);

                    //------------------------------------------------------------------------------

    enum OptLevel : unsigned {
        None, Trivial, Default, Expensive
    };

    auto optParser = cl::MapParser<OptLevel>({
        { "O0", None        },
        { "O1", Trivial     },
        { "O2", Default     },
        { "O3", Expensive   }
    });

    auto opt = cl::makeOptionPiecewise<OptLevel>(
        optParser,
        cmd,
        cl::ArgDisallowed,
        cl::Desc("Choose an optimization level"),
        cl::init(None)
        );

                    //------------------------------------------------------------------------------

    enum Simpson {
        Homer, Marge, Bart, Lisa, Maggie, SideshowBob
    };

    auto simpsonParser = cl::MapParser<Simpson>({
        { "homer",       Homer  },
        { "marge",       Marge  },
        { "bart",        Bart   },
        { "el barto",    Bart   },
        { "lisa",        Lisa   },
        { "maggie",      Maggie }
    });

    auto simpson = cl::makeOptionPiecewise<Simpson>(
        simpsonParser,
        cmd, "simpson",
        cl::Desc("Choose a Simpson"),
        cl::ArgRequired,
        cl::init(SideshowBob)
        );

                    //------------------------------------------------------------------------------

    auto bf = cl::makeOptionPiecewise<unsigned>(
        cl::BinaryOpParser<std::bit_or<unsigned>>(),
        cmd, "bf",
        cl::CommaSeparated,
        cl::ArgRequired,
        cl::ZeroOrMore
        );

                    //------------------------------------------------------------------------------

    auto f = cl::makeOption<std::map<std::string, int>>(
        cmd, "f", cl::CommaSeparated, cl::ArgRequired
        );

                    //------------------------------------------------------------------------------

    auto helpParser = [&](StringRef /*value*/, size_t /*i*/, bool& /*result*/) -> bool
    {
        cmd.help();
        exit(0);
    };

    auto help = cl::makeOptionPiecewise<bool>(helpParser, cmd, "help", cl::Optional);

    //----------------------------------------------------------------------------------------------

    if (!cmd.parse({argv + 1, argv + argc}, /*ignoreUnknowns*/false))
        return -1;

    //----------------------------------------------------------------------------------------------

    std::cout << pretty(y_ref) << std::endl;
    std::cout << pretty(g) << std::endl;
    std::cout << pretty(h) << std::endl;
    std::cout << pretty(z) << std::endl;
    std::cout << pretty(I) << std::endl;
    std::cout << pretty(opt) << std::endl;
    std::cout << pretty(simpson) << std::endl;
    std::cout << pretty(help) << std::endl;
//    std::cout << pretty(regex) << std::endl;
    std::cout << "bf = 0x" << std::hex << bf.get() << std::endl;
    std::cout << pretty(f) << std::endl;

    std::cout << "files:\n";
    for (auto& s : files)
        std::cout << "  \"" << s << "\"" << std::endl;

    //----------------------------------------------------------------------------------------------

    return 0;
}
<|endoftext|>


<commit_before>//
//  GroovinatorRhythmHandler.cpp
//  Groovinator
//
//  Created by David Su on 6/1/17.
//
//

#include <sstream>

#include "bjorklund.h"

#include "GroovinatorRhythmHandler.h"

GroovinatorRhythmHandler::GroovinatorRhythmHandler() : _originalRhythm(8, 0), _targetRhythm(8, 0)
{
    //_originalRhythm[0] = 1; // Testing
}

GroovinatorRhythmHandler::GroovinatorRhythmHandler(int originalNumSteps, int targetNumSteps) : _originalRhythm(originalNumSteps, 0), _targetRhythm(targetNumSteps, 0)
{
}

GroovinatorRhythmHandler::GroovinatorRhythmHandler(RhythmSequence originalRhythm, RhythmSequence targetRhythm) : _originalRhythm(originalRhythm), _targetRhythm(targetRhythm)
{

}

GroovinatorRhythmHandler::~GroovinatorRhythmHandler()
{

}

// Getters
int GroovinatorRhythmHandler::getOriginalNumSteps()
{
    return _originalRhythm.size();
}
int GroovinatorRhythmHandler::getTargetNumSteps()
{
    return _targetRhythm.size();
}

GroovinatorRhythmHandler::RhythmSequence GroovinatorRhythmHandler::getOriginalRhythm()
{
    return _originalRhythm;
}

GroovinatorRhythmHandler::RhythmSequence GroovinatorRhythmHandler::getTargetRhythm()
{
    return _targetRhythm;
}

std::string GroovinatorRhythmHandler::getOriginalRhythmStr()
{
    return GroovinatorRhythmHandler::rhythmToString(_originalRhythm);
}

std::string GroovinatorRhythmHandler::getTargetRhythmStr()
{
    return GroovinatorRhythmHandler::rhythmToString(_targetRhythm);
}

double GroovinatorRhythmHandler::getProportionOfRhythmElapsed()
{
    return _proportionOfRhythmElapsed;
}

// Setters
void GroovinatorRhythmHandler::setOriginalNumSteps(int v)
{
    _originalRhythm.resize(v);

    // TODO: Generate Euclidean rhythm using old _originalRhythm's numPulses, and set _originalRhythm
    //_originalRhythm = GroovinatorRhythmHandler::generateEuclideanRhythm(3, v);
}
void GroovinatorRhythmHandler::setTargetNumSteps(int v)
{
    _targetRhythm.resize(v);

    // TODO: Generate Euclidean rhythm using old _targetRhythm's numPulses, and set _targetRhythm
    //_targetRhythm = GroovinatorRhythmHandler::generateEuclideanRhythm(3, v);
}

void GroovinatorRhythmHandler::setOriginalRhythm(RhythmSequence r)
{
    _originalRhythm = r;
}

void GroovinatorRhythmHandler::setTargetRhythm(RhythmSequence r)
{
    _targetRhythm = r;
}

void GroovinatorRhythmHandler::setProportionOfRhythmElapsed(double v)
{
    _proportionOfRhythmElapsed = v;
}

// Utility methods
void GroovinatorRhythmHandler::toggleOriginalRhythmStepAt(int i)
{
    if (i < 0 || i >= _originalRhythm.size())
        return;
    _originalRhythm[i] = _originalRhythm[i] == 1 ? 0 : 1;
}

void GroovinatorRhythmHandler::toggleTargetRhythmStepAt(int i)
{
    if (i < 0 || i >= _targetRhythm.size())
        return;
    _targetRhythm[i] = _targetRhythm[i] == 1 ? 0 : 1;
}

std::vector<double> GroovinatorRhythmHandler::calculateStepStretchRatios()
{
    return GroovinatorRhythmHandler::calculateStepStretchRatios(_originalRhythm, _targetRhythm);
}

std::string GroovinatorRhythmHandler::calculateStepStretchRatiosStr()
{
    std::stringstream ss;
    std::vector<double> ratios = calculateStepStretchRatios();
    for (size_t i=0; i<ratios.size(); i++)
    {
        if (i != 0)
            ss << ",";
        ss << ratios[i];
    }
    return ss.str();
}

// Fibonacci stretch methods (static)
std::vector<int> GroovinatorRhythmHandler::calculatePulseLengths(GroovinatorRhythmHandler::RhythmSequence rhythm)
{
    std::vector<int> pulseIndices;
    for (size_t i=0; i<rhythm.size(); i++)
    {
        if (rhythm[i] > 0)
            pulseIndices.push_back((int) i);
    }
    pulseIndices.push_back(rhythm.size());

    std::vector<int> pulseLengths;
    for (size_t i=0; i<pulseIndices.size()-1; i++)
    {
        pulseLengths.push_back(pulseIndices[i+1] - pulseIndices[i]);
    }

    return pulseLengths;
}

std::vector<double> GroovinatorRhythmHandler::calculatePulseRatios(GroovinatorRhythmHandler::RhythmSequence originalRhythm, GroovinatorRhythmHandler::RhythmSequence targetRhythm)
{
    std::vector<double> pulseRatios;

    std::vector<int> originalPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(originalRhythm);
    std::vector<int> targetPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(targetRhythm);

    int numPulses = std::min(originalPulseLengths.size(), targetPulseLengths.size());

    for (size_t i=0; i<numPulses; i++)
    {
        pulseRatios.push_back(originalPulseLengths[i] / (double) targetPulseLengths[i]);
    }

    return pulseRatios;
}

std::vector<double> GroovinatorRhythmHandler::calculateStepStretchRatios(GroovinatorRhythmHandler::RhythmSequence originalRhythm, GroovinatorRhythmHandler::RhythmSequence targetRhythm)
{
    // Original and target pulse lengths
    std::vector<int> originalPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(originalRhythm);
    std::vector<int> targetPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(targetRhythm);

    // Pulse ratios
    std::vector<double> pulseRatios = GroovinatorRhythmHandler::calculatePulseRatios(originalRhythm, targetRhythm);
    if (pulseRatios.size() < originalPulseLengths.size()) // Add 0s to pulse ratios if there aren't enough
    {
        for (size_t i=0; i < originalPulseLengths.size() - pulseRatios.size(); i++)
        {
            pulseRatios.push_back(0.0);
        }
    }

    // Format pulse ratios so there's one for each step
    std::vector<double> pulseRatiosByStep;
    for (size_t i=0; i<originalPulseLengths.size(); i++)
    {
        int pulseLength = originalPulseLengths[i];
        for (size_t j=0; j<pulseLength; j++)
        {
            pulseRatiosByStep.push_back(pulseRatios[i]);
        }
    }

    // Calculate stretch ratios for each original step
    // Adapted from Euclidean stretch
    std::vector<double> stepStretchRatios;
    for (size_t i=0; i<std::min(originalPulseLengths.size(), targetPulseLengths.size()); i++)
    {
        // Pulse lengths
        int opl = originalPulseLengths[i];
        int tpl = targetPulseLengths[i];

        // Adjust target pulse length if it's too small
        while (opl > tpl)
            tpl *= 2;

        // Use steps as original pulse rhythm ("opr")
        RhythmSequence opr;
        for (size_t j=0; j<originalRhythm.size(); j++)
        {
            opr.push_back(1);
        }

        // Generate target pulse rhythm ("tpr") using Bjorklund's algorithm
        RhythmSequence tpr = GroovinatorRhythmHandler::generateEuclideanRhythm(opl, tpl);
        std::vector<int> tprPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(tpr);
        std::vector<double> tprPulseRatios = GroovinatorRhythmHandler::calculatePulseRatios(opr, tpr);

        // Scale the tpr pulse ratios by the corresponding ratio from pulseRatiosByStep
        for (size_t j=0; j<tprPulseRatios.size(); j++)
        {
            tprPulseRatios[j] *= pulseRatiosByStep[i];
        }

        // Append the ratios to step stretch ratios
        stepStretchRatios.insert(stepStretchRatios.end(), tprPulseRatios.begin(), tprPulseRatios.end());
    }

    // Multiply by stretch multiplier to make sure the length is same as original
    // TODO
    double stepStretchRatiosSum;
    for (size_t i=0; i<stepStretchRatios.size(); i++)
    {
        stepStretchRatiosSum += stepStretchRatios[i];
    }
    double stretchMultiplier = 1.0 / (stepStretchRatiosSum / (double) originalRhythm.size());
    for (size_t i=0; i<stepStretchRatios.size(); i++)
    {
        stepStretchRatios[i] *= stretchMultiplier;
    }

    return stepStretchRatios;
}

// Other static methods
GroovinatorRhythmHandler::RhythmSequence GroovinatorRhythmHandler::generateEuclideanRhythm(int numPulses, int numSteps)
{
    RhythmSequence rhythm;
    std::string rhythmStr = BjorklundsAlgorithm::bjorklund(numPulses, numSteps);
    for (size_t i=0; i<rhythmStr.size(); i++)
    {
        if (rhythmStr[i] == '0')
            rhythm.push_back(0);
        else
            rhythm.push_back(1);
    }
    return rhythm;
}

std::string GroovinatorRhythmHandler::rhythmToString(RhythmSequence rhythm)
{
    std::stringstream ss;
    for (size_t i=0; i<rhythm.size(); i++)
    {
        ss << rhythm[i];
    }
    return ss.str();
}

int GroovinatorRhythmHandler::proportionToStepIndex(double proportion, int numSteps)
{
    return (int) (proportion * numSteps);
}

<commit_msg>instantiate rhythms with first step = 1<commit_after>//
//  GroovinatorRhythmHandler.cpp
//  Groovinator
//
//  Created by David Su on 6/1/17.
//
//

#include <sstream>

#include "bjorklund.h"

#include "GroovinatorRhythmHandler.h"

GroovinatorRhythmHandler::GroovinatorRhythmHandler() : _originalRhythm(8, 0), _targetRhythm(8, 0)
{
    _originalRhythm[0] = 1;
    _targetRhythm[0] = 1;
}

GroovinatorRhythmHandler::GroovinatorRhythmHandler(int originalNumSteps, int targetNumSteps) : _originalRhythm(originalNumSteps, 0), _targetRhythm(targetNumSteps, 0)
{
    _originalRhythm[0] = 1;
    _targetRhythm[0] = 1;
}

GroovinatorRhythmHandler::GroovinatorRhythmHandler(RhythmSequence originalRhythm, RhythmSequence targetRhythm) : _originalRhythm(originalRhythm), _targetRhythm(targetRhythm)
{

}

GroovinatorRhythmHandler::~GroovinatorRhythmHandler()
{

}

// Getters
int GroovinatorRhythmHandler::getOriginalNumSteps()
{
    return _originalRhythm.size();
}
int GroovinatorRhythmHandler::getTargetNumSteps()
{
    return _targetRhythm.size();
}

GroovinatorRhythmHandler::RhythmSequence GroovinatorRhythmHandler::getOriginalRhythm()
{
    return _originalRhythm;
}

GroovinatorRhythmHandler::RhythmSequence GroovinatorRhythmHandler::getTargetRhythm()
{
    return _targetRhythm;
}

std::string GroovinatorRhythmHandler::getOriginalRhythmStr()
{
    return GroovinatorRhythmHandler::rhythmToString(_originalRhythm);
}

std::string GroovinatorRhythmHandler::getTargetRhythmStr()
{
    return GroovinatorRhythmHandler::rhythmToString(_targetRhythm);
}

double GroovinatorRhythmHandler::getProportionOfRhythmElapsed()
{
    return _proportionOfRhythmElapsed;
}

// Setters
void GroovinatorRhythmHandler::setOriginalNumSteps(int v)
{
    _originalRhythm.resize(v);

    // TODO: Generate Euclidean rhythm using old _originalRhythm's numPulses, and set _originalRhythm
    //_originalRhythm = GroovinatorRhythmHandler::generateEuclideanRhythm(3, v);
}
void GroovinatorRhythmHandler::setTargetNumSteps(int v)
{
    _targetRhythm.resize(v);

    // TODO: Generate Euclidean rhythm using old _targetRhythm's numPulses, and set _targetRhythm
    //_targetRhythm = GroovinatorRhythmHandler::generateEuclideanRhythm(3, v);
}

void GroovinatorRhythmHandler::setOriginalRhythm(RhythmSequence r)
{
    _originalRhythm = r;
}

void GroovinatorRhythmHandler::setTargetRhythm(RhythmSequence r)
{
    _targetRhythm = r;
}

void GroovinatorRhythmHandler::setProportionOfRhythmElapsed(double v)
{
    _proportionOfRhythmElapsed = v;
}

// Utility methods
void GroovinatorRhythmHandler::toggleOriginalRhythmStepAt(int i)
{
    if (i < 0 || i >= _originalRhythm.size())
        return;
    _originalRhythm[i] = _originalRhythm[i] == 1 ? 0 : 1;
}

void GroovinatorRhythmHandler::toggleTargetRhythmStepAt(int i)
{
    if (i < 0 || i >= _targetRhythm.size())
        return;
    _targetRhythm[i] = _targetRhythm[i] == 1 ? 0 : 1;
}

std::vector<double> GroovinatorRhythmHandler::calculateStepStretchRatios()
{
    return GroovinatorRhythmHandler::calculateStepStretchRatios(_originalRhythm, _targetRhythm);
}

std::string GroovinatorRhythmHandler::calculateStepStretchRatiosStr()
{
    std::stringstream ss;
    std::vector<double> ratios = calculateStepStretchRatios();
    for (size_t i=0; i<ratios.size(); i++)
    {
        if (i != 0)
            ss << ",";
        ss << ratios[i];
    }
    return ss.str();
}

// Fibonacci stretch methods (static)
std::vector<int> GroovinatorRhythmHandler::calculatePulseLengths(GroovinatorRhythmHandler::RhythmSequence rhythm)
{
    std::vector<int> pulseIndices;
    for (size_t i=0; i<rhythm.size(); i++)
    {
        if (rhythm[i] > 0)
            pulseIndices.push_back((int) i);
    }
    pulseIndices.push_back(rhythm.size());

    std::vector<int> pulseLengths;
    for (size_t i=0; i<pulseIndices.size()-1; i++)
    {
        pulseLengths.push_back(pulseIndices[i+1] - pulseIndices[i]);
    }

    return pulseLengths;
}

std::vector<double> GroovinatorRhythmHandler::calculatePulseRatios(GroovinatorRhythmHandler::RhythmSequence originalRhythm, GroovinatorRhythmHandler::RhythmSequence targetRhythm)
{
    std::vector<double> pulseRatios;

    std::vector<int> originalPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(originalRhythm);
    std::vector<int> targetPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(targetRhythm);

    int numPulses = std::min(originalPulseLengths.size(), targetPulseLengths.size());

    for (size_t i=0; i<numPulses; i++)
    {
        pulseRatios.push_back(originalPulseLengths[i] / (double) targetPulseLengths[i]);
    }

    return pulseRatios;
}

std::vector<double> GroovinatorRhythmHandler::calculateStepStretchRatios(GroovinatorRhythmHandler::RhythmSequence originalRhythm, GroovinatorRhythmHandler::RhythmSequence targetRhythm)
{
    // Original and target pulse lengths
    std::vector<int> originalPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(originalRhythm);
    std::vector<int> targetPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(targetRhythm);

    // Pulse ratios
    std::vector<double> pulseRatios = GroovinatorRhythmHandler::calculatePulseRatios(originalRhythm, targetRhythm);
    if (pulseRatios.size() < originalPulseLengths.size()) // Add 0s to pulse ratios if there aren't enough
    {
        for (size_t i=0; i < originalPulseLengths.size() - pulseRatios.size(); i++)
        {
            pulseRatios.push_back(0.0);
        }
    }

    // Format pulse ratios so there's one for each step
    std::vector<double> pulseRatiosByStep;
    for (size_t i=0; i<originalPulseLengths.size(); i++)
    {
        int pulseLength = originalPulseLengths[i];
        for (size_t j=0; j<pulseLength; j++)
        {
            pulseRatiosByStep.push_back(pulseRatios[i]);
        }
    }

    // Calculate stretch ratios for each original step
    // Adapted from Euclidean stretch
    std::vector<double> stepStretchRatios;
    for (size_t i=0; i<std::min(originalPulseLengths.size(), targetPulseLengths.size()); i++)
    {
        // Pulse lengths
        int opl = originalPulseLengths[i];
        int tpl = targetPulseLengths[i];

        // Adjust target pulse length if it's too small
        while (opl > tpl)
            tpl *= 2;

        // Use steps as original pulse rhythm ("opr")
        RhythmSequence opr;
        for (size_t j=0; j<originalRhythm.size(); j++)
        {
            opr.push_back(1);
        }

        // Generate target pulse rhythm ("tpr") using Bjorklund's algorithm
        RhythmSequence tpr = GroovinatorRhythmHandler::generateEuclideanRhythm(opl, tpl);
        std::vector<int> tprPulseLengths = GroovinatorRhythmHandler::calculatePulseLengths(tpr);
        std::vector<double> tprPulseRatios = GroovinatorRhythmHandler::calculatePulseRatios(opr, tpr);

        // Scale the tpr pulse ratios by the corresponding ratio from pulseRatiosByStep
        for (size_t j=0; j<tprPulseRatios.size(); j++)
        {
            tprPulseRatios[j] *= pulseRatiosByStep[i];
        }

        // Append the ratios to step stretch ratios
        stepStretchRatios.insert(stepStretchRatios.end(), tprPulseRatios.begin(), tprPulseRatios.end());
    }

    // Multiply by stretch multiplier to make sure the length is same as original
    // TODO
    double stepStretchRatiosSum;
    for (size_t i=0; i<stepStretchRatios.size(); i++)
    {
        stepStretchRatiosSum += stepStretchRatios[i];
    }
    double stretchMultiplier = 1.0 / (stepStretchRatiosSum / (double) originalRhythm.size());
    for (size_t i=0; i<stepStretchRatios.size(); i++)
    {
        stepStretchRatios[i] *= stretchMultiplier;
    }

    return stepStretchRatios;
}

// Other static methods
GroovinatorRhythmHandler::RhythmSequence GroovinatorRhythmHandler::generateEuclideanRhythm(int numPulses, int numSteps)
{
    RhythmSequence rhythm;
    std::string rhythmStr = BjorklundsAlgorithm::bjorklund(numPulses, numSteps);
    for (size_t i=0; i<rhythmStr.size(); i++)
    {
        if (rhythmStr[i] == '0')
            rhythm.push_back(0);
        else
            rhythm.push_back(1);
    }
    return rhythm;
}

std::string GroovinatorRhythmHandler::rhythmToString(RhythmSequence rhythm)
{
    std::stringstream ss;
    for (size_t i=0; i<rhythm.size(); i++)
    {
        ss << rhythm[i];
    }
    return ss.str();
}

int GroovinatorRhythmHandler::proportionToStepIndex(double proportion, int numSteps)
{
    return (int) (proportion * numSteps);
}

<|endoftext|>


<commit_before>/*-----------------------------------------------------------------------------------------------
The MIT License (MIT)

Copyright (c) 2014-2020 Kim Kulling

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

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

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

#include "UnitTestCommon.h"

char *data = "�$$indexarray";

BEGIN_ODDLPARSER_NS

class OssFuzzTest : public testing::Test {
public:
    static void readFile(const char *name, std::vector<char> &buffer) {
        std::string fn = std::string(OPENDDL_TEST_DATA "/") + std::string(name);
        FILE *fileStream = ::fopen(fn.c_str(), "rb");
        fseek(fileStream, 0, SEEK_END);
        const size_t size = ftell(fileStream);
        buffer.resize(size);
        ::fread(&buffer[0], size, sizeof(char), fileStream);
        ::fclose(fileStream);
    }
};

TEST_F(OssFuzzTest, fuzz24806_undefinedBahavior) {
    bool success(true);
    try {
        OpenDDLParser myParser;
        myParser.setBuffer(data, 14);
        myParser.parse();
    } catch (...) {
        success = false;
    }
    EXPECT_TRUE(success);
}

TEST_F(OssFuzzTest, fuzz24587_undefinedBahavior) {
    bool success(true);
    try {
        std::vector<char> buffer;
        OssFuzzTest::readFile("clusterfuzz-testcase-minimized-assimp_fuzzer-5699047558742016", buffer);
        OpenDDLParser myParser;
        myParser.setBuffer(&buffer[0], buffer.size());
        bool ok = myParser.parse();
        EXPECT_FALSE(ok);
    } catch (...) {
        success = false;
    }
    EXPECT_TRUE(success);
}

TEST_F(OssFuzzTest, fuzz24463_undefinedBahavior) {
    bool success(true);
    try {
        std::vector<char> buffer;
        OssFuzzTest::readFile("clusterfuzz-testcase-minimized-assimp_fuzzer-5161012492500992", buffer);
        OpenDDLParser myParser;
        myParser.setBuffer(&buffer[0], buffer.size());
        bool ok = myParser.parse();
        EXPECT_FALSE(ok);
    } catch (...) {
        success = false;
    }
    EXPECT_TRUE(success);
}

END_ODDLPARSER_NS
<commit_msg>increase tst coverage.<commit_after>/*-----------------------------------------------------------------------------------------------
The MIT License (MIT)

Copyright (c) 2014-2020 Kim Kulling

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

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

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

#include "UnitTestCommon.h"

char *data = "�$$indexarray";

BEGIN_ODDLPARSER_NS

class OssFuzzTest : public testing::Test {
public:
    static void readFile(const char *name, std::vector<char> &buffer) {
        std::string fn = std::string(OPENDDL_TEST_DATA "/") + std::string(name);
        FILE *fileStream = ::fopen(fn.c_str(), "rb");
        fseek(fileStream, 0, SEEK_END);
        const size_t size = ftell(fileStream);
        buffer.resize(size);
        ::fread(&buffer[0], size, sizeof(char), fileStream);
        ::fclose(fileStream);
    }
};

TEST_F(OssFuzzTest, fuzz24806_undefinedBahavior) {
    OpenDDLParser myParser;
    myParser.setBuffer(data, 14);
    EXPECT_TRUE(myParser.parse());
}

TEST_F(OssFuzzTest, fuzz24587_undefinedBahavior) {
    std::vector<char> buffer;
    OssFuzzTest::readFile("clusterfuzz-testcase-minimized-assimp_fuzzer-5699047558742016", buffer);
    OpenDDLParser myParser;
    myParser.setBuffer(&buffer[0], buffer.size());
    bool ok = myParser.parse();
    EXPECT_FALSE(ok);
}

TEST_F(OssFuzzTest, fuzz24463_undefinedBahavior) {
    std::vector<char> buffer;
    OssFuzzTest::readFile("clusterfuzz-testcase-minimized-assimp_fuzzer-5161012492500992", buffer);
    OpenDDLParser myParser;
    myParser.setBuffer(&buffer[0], buffer.size());
    bool ok = myParser.parse();
    EXPECT_FALSE(ok);
}

END_ODDLPARSER_NS
<|endoftext|>