<commit_before>
#include <girepository.h>
#include <glib.h>

#include "boxed.h"
#include "debug.h"
#include "error.h"
#include "function.h"
#include "gi.h"
#include "gobject.h"
#include "macros.h"
#include "type.h"
#include "util.h"
#include "value.h"

using v8::Array;
using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Persistent;
using Nan::New;
using Nan::WeakCallbackType;

namespace GNodeJS {

size_t Boxed::GetSize (GIBaseInfo *boxed_info) {
    GIInfoType type = g_base_info_get_type(boxed_info);
    if (type == GI_INFO_TYPE_STRUCT) {
        return g_struct_info_get_size((GIStructInfo*)boxed_info);
    } else if (type == GI_INFO_TYPE_UNION) {
        return g_union_info_get_size((GIUnionInfo*)boxed_info);
    } else {
        warn("received bad type: %s", g_info_type_to_string (type));
        g_assert_not_reached();
    }
}

static bool IsNoArgsConstructor (GIFunctionInfo *info) {
    auto flags = g_function_info_get_flags (info);
    return ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0
        && g_callable_info_get_n_args (info) == 0);
}

static bool IsConstructor (GIFunctionInfo *info) {
    auto flags = g_function_info_get_flags (info);
    return (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
}

static GIFunctionInfo* FindBoxedConstructorCached (GType gtype) {
    if (gtype == G_TYPE_NONE)
        return NULL;

    GIFunctionInfo* fn_info = (GIFunctionInfo*) g_type_get_qdata(gtype, GNodeJS::constructor_quark());

    if (fn_info != NULL)
        return fn_info;

    return NULL;
}

static GIFunctionInfo* FindBoxedConstructor (GIBaseInfo* info, GType gtype) {
    GIFunctionInfo* fn_info = NULL;

    if ((fn_info = FindBoxedConstructorCached(gtype)) != NULL)
        return g_base_info_ref (fn_info);

    if (GI_IS_STRUCT_INFO (info)) {
        int n_methods = g_struct_info_get_n_methods (info);
        for (int i = 0; i < n_methods; i++) {
            fn_info = g_struct_info_get_method (info, i);

            if (IsNoArgsConstructor (fn_info))
                break;

            g_base_info_unref(fn_info);
            fn_info = NULL;
        }

        if (fn_info == NULL)
            fn_info = g_struct_info_find_method(info, "new");

        if (fn_info == NULL) {
            for (int i = 0; i < n_methods; i++) {
                fn_info = g_struct_info_get_method (info, i);

                if (IsConstructor (fn_info))
                    break;

                g_base_info_unref(fn_info);
                fn_info = NULL;
            }
        }
    }
    else {
        int n_methods = g_union_info_get_n_methods (info);
        for (int i = 0; i < n_methods; i++) {
            fn_info = g_union_info_get_method (info, i);

            if (IsNoArgsConstructor (fn_info))
                break;

            g_base_info_unref(fn_info);
            fn_info = NULL;
        }

        if (fn_info == NULL)
            fn_info = g_union_info_find_method(info, "new");

        if (fn_info == NULL) {
            for (int i = 0; i < n_methods; i++) {
                fn_info = g_union_info_get_method (info, i);

                if (IsConstructor (fn_info))
                    break;

                g_base_info_unref(fn_info);
                fn_info = NULL;
            }
        }
    }

    if (fn_info != NULL && gtype != G_TYPE_NONE) {
        g_type_set_qdata(gtype, GNodeJS::constructor_quark(),
                g_base_info_ref (fn_info));
    }

    return fn_info;
}

static void BoxedDestroyed(const Nan::WeakCallbackInfo<Boxed> &info);

static void BoxedConstructor(const Nan::FunctionCallbackInfo<Value> &info) {
    /* See gobject.cc for how this works */
    if (!info.IsConstructCall ()) {
        Nan::ThrowTypeError("Not a construct call");
        return;
    }

    void *boxed = NULL;
    unsigned long size = 0;

    Local<Object> self = info.This ();
    GIBaseInfo *gi_info = (GIBaseInfo *) External::Cast (*info.Data ())->Value ();
    GType gtype = g_registered_type_info_get_g_type (gi_info);

    if (info[0]->IsExternal ()) {
        /* The External case. This is how WrapperFromBoxed is called. */

        boxed = External::Cast(*info[0])->Value();

    } else {
        /* User code calling `new Pango.AttrList()` */

        GIFunctionInfo* fn_info = FindBoxedConstructor(gi_info, gtype);

        if (fn_info != NULL) {

            FunctionInfo func(fn_info);
            GIArgument return_value;
            GError *error = NULL;

            auto jsResult = FunctionCall (&func, info, &return_value, &error);

            g_base_info_unref (fn_info);

            if (jsResult.IsEmpty()) {
                // func->Init() or func->TypeCheck() have thrown
                return;
            }

            if (error) {
                Throw::GError ("Boxed constructor failed", error);
                g_error_free (error);
                return;
            }

            boxed = return_value.v_pointer;

        } else if ((size = Boxed::GetSize(gi_info)) != 0) {
            boxed = g_slice_alloc0(size);

        } else {
            Nan::ThrowError("Boxed allocation failed: no constructor found");
            return;
        }

        if (!boxed) {
            Nan::ThrowError("Boxed allocation failed");
            return;
        }
    }

    self->SetAlignedPointerInInternalField (0, boxed);

    Nan::DefineOwnProperty(self,
            UTF8("__gtype__"),
            Nan::New<Number>(gtype),
            (v8::PropertyAttribute)(v8::PropertyAttribute::ReadOnly | v8::PropertyAttribute::DontEnum)
    );

    auto* box = new Boxed();
    box->data = boxed;
    box->size = size;
    box->g_type = gtype;
    box->info = g_base_info_ref (gi_info);
    box->persistent = new Nan::Persistent<Object>(self);
    box->persistent->SetWeak(box, BoxedDestroyed, Nan::WeakCallbackType::kParameter);
}

static void BoxedDestroyed(const Nan::WeakCallbackInfo<Boxed> &info) {
    Boxed *box = info.GetParameter();

    if (G_TYPE_IS_BOXED(box->g_type)) {
        g_boxed_free(box->g_type, box->data);
    }
    else if (box->size != 0) {
        // Allocated in ./function.cc @ AllocateArgument
        g_slice_free1(box->size, box->data);
    }
    else if (box->data != NULL) {
        /*
         * TODO(find informations on what to do here. Only seems to be reached for GI.Typelib)
         */
        warn("boxed possibly not freed (%s.%s : %s)",
                g_base_info_get_namespace (box->info),
                g_base_info_get_name (box->info),
                g_type_name (box->g_type));
    }

    g_base_info_unref (box->info);
    delete box->persistent;
    delete box;
}

static void BoxedClassDestroyed(const v8::WeakCallbackInfo<GIBaseInfo> &info) {
    GIBaseInfo *gi_info = info.GetParameter ();
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) gi_info);

    auto *persistent_template = (Persistent<FunctionTemplate> *) g_type_get_qdata (gtype, GNodeJS::template_quark());
    auto *persistent_function = (Persistent<FunctionTemplate> *) g_type_get_qdata (gtype, GNodeJS::function_quark());
    delete persistent_template;
    delete persistent_function;

    auto fn_info = (GIFunctionInfo *) g_type_get_qdata (gtype, GNodeJS::constructor_quark());
    if (fn_info != NULL)
        g_base_info_unref (fn_info);

    g_type_set_qdata (gtype, GNodeJS::template_quark(), NULL);
    g_type_set_qdata (gtype, GNodeJS::function_quark(), NULL);
    g_type_set_qdata (gtype, GNodeJS::constructor_quark(), NULL);

    g_base_info_unref (gi_info);
}

/**
 * Get the constructor FunctionTemplate for the given type, cached.
 * @param info GIBaseInfo of the type
 * @param gtype GType of the type
 * @retuns the constructor FunctionTemplate
 */
Local<FunctionTemplate> GetBoxedTemplate(GIBaseInfo *info, GType gtype) {
    void *data = NULL;

    if (gtype != G_TYPE_NONE) {
        data = g_type_get_qdata(gtype, GNodeJS::template_quark());
    }

    /*
     * Template already created
     */

    if (data) {
        auto *persistent = (Persistent<FunctionTemplate> *) data;
        auto tpl = Nan::New<FunctionTemplate> (*persistent);
        return tpl;
    }

    /*
     * Template not created yet
     */

    auto tpl = New<FunctionTemplate>(BoxedConstructor, New<External>(info));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    if (gtype != G_TYPE_NONE) {
        const char *class_name = g_type_name(gtype);
        tpl->SetClassName (UTF8(class_name));
    } else {
        const char *class_name = g_base_info_get_name (info);
        tpl->SetClassName (UTF8(class_name));
    }

    if (gtype == G_TYPE_NONE)
        return tpl;

    auto *persistent = new Persistent<FunctionTemplate>(Isolate::GetCurrent(), tpl);
    persistent->SetWeak(
            g_base_info_ref(info),
            BoxedClassDestroyed,
            WeakCallbackType::kParameter);

    g_type_set_qdata(gtype, GNodeJS::template_quark(), persistent);

    return tpl;
}

/**
 * Get the constructor function for the given type, cached.
 * Added because FunctionTemplate->GetFunction() seems to return a
 * different instance on each call.
 * @param info GIBaseInfo of the type
 * @param gtype GType of the type
 * @retuns the constructor function
 */
Local<Function> GetBoxedFunction(GIBaseInfo *info, GType gtype) {
    void *data = NULL;

    if (gtype != G_TYPE_NONE) {
        data = g_type_get_qdata(gtype, GNodeJS::function_quark());
    }

    if (data) {
        auto *persistent = (Persistent<Function> *) data;
        auto tpl = Nan::New<Function> (*persistent);
        return tpl;
    }

    Local<FunctionTemplate> tpl = GetBoxedTemplate (info, gtype);
    Local<Function> fn = Nan::GetFunction (tpl).ToLocalChecked();

    if (gtype == G_TYPE_NONE)
        return fn;

    auto *persistent = new Persistent<Function>(Isolate::GetCurrent(), fn);

    g_type_set_qdata(gtype, GNodeJS::function_quark(), persistent);

    return fn;
}

Local<Function> MakeBoxedClass(GIBaseInfo *info) {
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);

    if (gtype == G_TYPE_NONE) {
        auto moduleCache = GNodeJS::GetModuleCache();
        auto ns   = UTF8 (g_base_info_get_namespace (info));
        auto name = UTF8 (g_base_info_get_name (info));

        if (Nan::HasOwnProperty(moduleCache, ns).FromMaybe(false)) {
            auto module = TO_OBJECT (Nan::Get(moduleCache, ns).ToLocalChecked());

            if (Nan::HasOwnProperty(module, name).FromMaybe(false)) {
                auto constructor = TO_OBJECT (Nan::Get(module, name).ToLocalChecked());
                return Local<Function>::Cast (constructor);
            }
        }
    }

    return GetBoxedFunction (info, gtype);
}

Local<Value> WrapperFromBoxed(GIBaseInfo *info, void *data) {
    if (data == NULL)
        return Nan::Null();

    Local<Function> constructor = MakeBoxedClass (info);

    Local<Value> boxed_external = Nan::New<External> (data);
    Local<Value> args[] = { boxed_external };

    MaybeLocal<Object> instance = Nan::NewInstance(constructor, 1, args);

    // FIXME(we should propage failure here)
    if (instance.IsEmpty())
        return Nan::Null();

    return instance.ToLocalChecked();
}

void* BoxedFromWrapper(Local<Value> value) {
    Local<Object> object = Nan::To<Object> (value).ToLocalChecked();
    g_assert(object->InternalFieldCount() > 0);
    void *boxed = object->GetAlignedPointerFromInternalField(0);
    return boxed;
}

};
<commit_msg>migration: fix missing object conversion<commit_after>
#include <girepository.h>
#include <glib.h>

#include "boxed.h"
#include "debug.h"
#include "error.h"
#include "function.h"
#include "gi.h"
#include "gobject.h"
#include "macros.h"
#include "type.h"
#include "util.h"
#include "value.h"

using v8::Array;
using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Persistent;
using Nan::New;
using Nan::WeakCallbackType;

namespace GNodeJS {

size_t Boxed::GetSize (GIBaseInfo *boxed_info) {
    GIInfoType type = g_base_info_get_type(boxed_info);
    if (type == GI_INFO_TYPE_STRUCT) {
        return g_struct_info_get_size((GIStructInfo*)boxed_info);
    } else if (type == GI_INFO_TYPE_UNION) {
        return g_union_info_get_size((GIUnionInfo*)boxed_info);
    } else {
        warn("received bad type: %s", g_info_type_to_string (type));
        g_assert_not_reached();
    }
}

static bool IsNoArgsConstructor (GIFunctionInfo *info) {
    auto flags = g_function_info_get_flags (info);
    return ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0
        && g_callable_info_get_n_args (info) == 0);
}

static bool IsConstructor (GIFunctionInfo *info) {
    auto flags = g_function_info_get_flags (info);
    return (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
}

static GIFunctionInfo* FindBoxedConstructorCached (GType gtype) {
    if (gtype == G_TYPE_NONE)
        return NULL;

    GIFunctionInfo* fn_info = (GIFunctionInfo*) g_type_get_qdata(gtype, GNodeJS::constructor_quark());

    if (fn_info != NULL)
        return fn_info;

    return NULL;
}

static GIFunctionInfo* FindBoxedConstructor (GIBaseInfo* info, GType gtype) {
    GIFunctionInfo* fn_info = NULL;

    if ((fn_info = FindBoxedConstructorCached(gtype)) != NULL)
        return g_base_info_ref (fn_info);

    if (GI_IS_STRUCT_INFO (info)) {
        int n_methods = g_struct_info_get_n_methods (info);
        for (int i = 0; i < n_methods; i++) {
            fn_info = g_struct_info_get_method (info, i);

            if (IsNoArgsConstructor (fn_info))
                break;

            g_base_info_unref(fn_info);
            fn_info = NULL;
        }

        if (fn_info == NULL)
            fn_info = g_struct_info_find_method(info, "new");

        if (fn_info == NULL) {
            for (int i = 0; i < n_methods; i++) {
                fn_info = g_struct_info_get_method (info, i);

                if (IsConstructor (fn_info))
                    break;

                g_base_info_unref(fn_info);
                fn_info = NULL;
            }
        }
    }
    else {
        int n_methods = g_union_info_get_n_methods (info);
        for (int i = 0; i < n_methods; i++) {
            fn_info = g_union_info_get_method (info, i);

            if (IsNoArgsConstructor (fn_info))
                break;

            g_base_info_unref(fn_info);
            fn_info = NULL;
        }

        if (fn_info == NULL)
            fn_info = g_union_info_find_method(info, "new");

        if (fn_info == NULL) {
            for (int i = 0; i < n_methods; i++) {
                fn_info = g_union_info_get_method (info, i);

                if (IsConstructor (fn_info))
                    break;

                g_base_info_unref(fn_info);
                fn_info = NULL;
            }
        }
    }

    if (fn_info != NULL && gtype != G_TYPE_NONE) {
        g_type_set_qdata(gtype, GNodeJS::constructor_quark(),
                g_base_info_ref (fn_info));
    }

    return fn_info;
}

static void BoxedDestroyed(const Nan::WeakCallbackInfo<Boxed> &info);

static void BoxedConstructor(const Nan::FunctionCallbackInfo<Value> &info) {
    /* See gobject.cc for how this works */
    if (!info.IsConstructCall ()) {
        Nan::ThrowTypeError("Not a construct call");
        return;
    }

    void *boxed = NULL;
    unsigned long size = 0;

    Local<Object> self = info.This ();
    GIBaseInfo *gi_info = (GIBaseInfo *) External::Cast (*info.Data ())->Value ();
    GType gtype = g_registered_type_info_get_g_type (gi_info);

    if (info[0]->IsExternal ()) {
        /* The External case. This is how WrapperFromBoxed is called. */

        boxed = External::Cast(*info[0])->Value();

    } else {
        /* User code calling `new Pango.AttrList()` */

        GIFunctionInfo* fn_info = FindBoxedConstructor(gi_info, gtype);

        if (fn_info != NULL) {

            FunctionInfo func(fn_info);
            GIArgument return_value;
            GError *error = NULL;

            auto jsResult = FunctionCall (&func, info, &return_value, &error);

            g_base_info_unref (fn_info);

            if (jsResult.IsEmpty()) {
                // func->Init() or func->TypeCheck() have thrown
                return;
            }

            if (error) {
                Throw::GError ("Boxed constructor failed", error);
                g_error_free (error);
                return;
            }

            boxed = return_value.v_pointer;

        } else if ((size = Boxed::GetSize(gi_info)) != 0) {
            boxed = g_slice_alloc0(size);

        } else {
            Nan::ThrowError("Boxed allocation failed: no constructor found");
            return;
        }

        if (!boxed) {
            Nan::ThrowError("Boxed allocation failed");
            return;
        }
    }

    self->SetAlignedPointerInInternalField (0, boxed);

    Nan::DefineOwnProperty(self,
            UTF8("__gtype__"),
            Nan::New<Number>(gtype),
            (v8::PropertyAttribute)(v8::PropertyAttribute::ReadOnly | v8::PropertyAttribute::DontEnum)
    );

    auto* box = new Boxed();
    box->data = boxed;
    box->size = size;
    box->g_type = gtype;
    box->info = g_base_info_ref (gi_info);
    box->persistent = new Nan::Persistent<Object>(self);
    box->persistent->SetWeak(box, BoxedDestroyed, Nan::WeakCallbackType::kParameter);
}

static void BoxedDestroyed(const Nan::WeakCallbackInfo<Boxed> &info) {
    Boxed *box = info.GetParameter();

    if (G_TYPE_IS_BOXED(box->g_type)) {
        g_boxed_free(box->g_type, box->data);
    }
    else if (box->size != 0) {
        // Allocated in ./function.cc @ AllocateArgument
        g_slice_free1(box->size, box->data);
    }
    else if (box->data != NULL) {
        /*
         * TODO(find informations on what to do here. Only seems to be reached for GI.Typelib)
         */
        warn("boxed possibly not freed (%s.%s : %s)",
                g_base_info_get_namespace (box->info),
                g_base_info_get_name (box->info),
                g_type_name (box->g_type));
    }

    g_base_info_unref (box->info);
    delete box->persistent;
    delete box;
}

static void BoxedClassDestroyed(const v8::WeakCallbackInfo<GIBaseInfo> &info) {
    GIBaseInfo *gi_info = info.GetParameter ();
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) gi_info);

    auto *persistent_template = (Persistent<FunctionTemplate> *) g_type_get_qdata (gtype, GNodeJS::template_quark());
    auto *persistent_function = (Persistent<FunctionTemplate> *) g_type_get_qdata (gtype, GNodeJS::function_quark());
    delete persistent_template;
    delete persistent_function;

    auto fn_info = (GIFunctionInfo *) g_type_get_qdata (gtype, GNodeJS::constructor_quark());
    if (fn_info != NULL)
        g_base_info_unref (fn_info);

    g_type_set_qdata (gtype, GNodeJS::template_quark(), NULL);
    g_type_set_qdata (gtype, GNodeJS::function_quark(), NULL);
    g_type_set_qdata (gtype, GNodeJS::constructor_quark(), NULL);

    g_base_info_unref (gi_info);
}

/**
 * Get the constructor FunctionTemplate for the given type, cached.
 * @param info GIBaseInfo of the type
 * @param gtype GType of the type
 * @retuns the constructor FunctionTemplate
 */
Local<FunctionTemplate> GetBoxedTemplate(GIBaseInfo *info, GType gtype) {
    void *data = NULL;

    if (gtype != G_TYPE_NONE) {
        data = g_type_get_qdata(gtype, GNodeJS::template_quark());
    }

    /*
     * Template already created
     */

    if (data) {
        auto *persistent = (Persistent<FunctionTemplate> *) data;
        auto tpl = Nan::New<FunctionTemplate> (*persistent);
        return tpl;
    }

    /*
     * Template not created yet
     */

    auto tpl = New<FunctionTemplate>(BoxedConstructor, New<External>(info));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    if (gtype != G_TYPE_NONE) {
        const char *class_name = g_type_name(gtype);
        tpl->SetClassName (UTF8(class_name));
    } else {
        const char *class_name = g_base_info_get_name (info);
        tpl->SetClassName (UTF8(class_name));
    }

    if (gtype == G_TYPE_NONE)
        return tpl;

    auto *persistent = new Persistent<FunctionTemplate>(Isolate::GetCurrent(), tpl);
    persistent->SetWeak(
            g_base_info_ref(info),
            BoxedClassDestroyed,
            WeakCallbackType::kParameter);

    g_type_set_qdata(gtype, GNodeJS::template_quark(), persistent);

    return tpl;
}

/**
 * Get the constructor function for the given type, cached.
 * Added because FunctionTemplate->GetFunction() seems to return a
 * different instance on each call.
 * @param info GIBaseInfo of the type
 * @param gtype GType of the type
 * @retuns the constructor function
 */
Local<Function> GetBoxedFunction(GIBaseInfo *info, GType gtype) {
    void *data = NULL;

    if (gtype != G_TYPE_NONE) {
        data = g_type_get_qdata(gtype, GNodeJS::function_quark());
    }

    if (data) {
        auto *persistent = (Persistent<Function> *) data;
        auto tpl = Nan::New<Function> (*persistent);
        return tpl;
    }

    Local<FunctionTemplate> tpl = GetBoxedTemplate (info, gtype);
    Local<Function> fn = Nan::GetFunction (tpl).ToLocalChecked();

    if (gtype == G_TYPE_NONE)
        return fn;

    auto *persistent = new Persistent<Function>(Isolate::GetCurrent(), fn);

    g_type_set_qdata(gtype, GNodeJS::function_quark(), persistent);

    return fn;
}

Local<Function> MakeBoxedClass(GIBaseInfo *info) {
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);

    if (gtype == G_TYPE_NONE) {
        auto moduleCache = GNodeJS::GetModuleCache();
        auto ns   = UTF8 (g_base_info_get_namespace (info));
        auto name = UTF8 (g_base_info_get_name (info));

        if (Nan::HasOwnProperty(moduleCache, ns).FromMaybe(false)) {
            auto module = TO_OBJECT (Nan::Get(moduleCache, ns).ToLocalChecked());

            if (Nan::HasOwnProperty(module, name).FromMaybe(false)) {
                auto constructor = TO_OBJECT (Nan::Get(module, name).ToLocalChecked());
                return Local<Function>::Cast (constructor);
            }
        }
    }

    return GetBoxedFunction (info, gtype);
}

Local<Value> WrapperFromBoxed(GIBaseInfo *info, void *data) {
    if (data == NULL)
        return Nan::Null();

    Local<Function> constructor = MakeBoxedClass (info);

    Local<Value> boxed_external = Nan::New<External> (data);
    Local<Value> args[] = { boxed_external };

    MaybeLocal<Object> instance = Nan::NewInstance(constructor, 1, args);

    // FIXME(we should propage failure here)
    if (instance.IsEmpty())
        return Nan::Null();

    return instance.ToLocalChecked();
}

void* BoxedFromWrapper(Local<Value> value) {
    Local<Object> object = TO_OBJECT (value);
    g_assert(object->InternalFieldCount() > 0);
    void *boxed = object->GetAlignedPointerFromInternalField(0);
    return boxed;
}

};
<|endoftext|>


<commit_before>/*
Copyright (c) 2014 Pauli Nieminen <suokkos@gmail.com>

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

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

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

#include "languagemodel.h"

#include <QDir>
#include <QRegExp>

#include <QSettings>
#include <QLocale>
#include <QCoreApplication>

#include <QVariant>

LanguageModel::LanguageModel()
{

    QDir localepath(QCoreApplication::applicationDirPath() + "/locale");
    QStringList filter("*.qm");
    QStringList files = localepath.entryList(filter);

    QString lang = "en";

    QSettings settings;

    QRegExp rx("BridgeClock_([^.]*).qm");
    for (const QString &f : files) {
        if (rx.exactMatch(f)) {
            QString l = rx.cap(1);
            translations_.append(l);
            QLocale loc(l);
            if (loc.language() == QLocale::system().language())
                lang = l;
        }
    }

    if (settings.contains("locale"))
        lang = settings.value("locale").toString();

    std::sort(translations_.begin(), translations_.end(),
            [](const QString &a, const QString &b) {
                QLocale al(a);
                QLocale bl(b);
                return al.nativeLanguageName() < bl.nativeLanguageName();
            });
    selected_ = 0;

    for (const QString &t : translations_) {
        if (t == lang)
            break;
        selected_++;
    }

    trans_.load("locale/BridgeClock_" + lang);
    qApp->installTranslator(&trans_);
}

#include <QDebug>

QHash<int, QByteArray> LanguageModel::roleNames() const
{
    static QHash<int, QByteArray> names;
    if (names.empty()) {
        names[NameRole] = "name";
    }
    return names;
}

int LanguageModel::rowCount(const QModelIndex &) const
{
    return translations_.size();
}

QVariant LanguageModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= (int)translations_.size())
        return QVariant();

    switch (role) {
    default:
        break;
    case NameRole:
    {
        QLocale loc(translations_.at(index.row()));
        return loc.nativeLanguageName();
    }
    }
    return QVariant();
}

void LanguageModel::setSelectedId(int id)
{
    if (id == selected_ || id < 0 || id >= (int)translations_.size())
        return;

    selected_ = id;
    trans_.load("locale/BridgeClock_" + translations_.at(id));
    QSettings settings;
    settings.setValue("locale", translations_.at(id));
    emit selectedChanged();
}

QString LanguageModel::emptyLang() const
{
    return "";
}

QString LanguageModel::selectedNative() const
{
    QLocale loc(translations_.at(selected_));
    return loc.nativeLanguageName();
}

int LanguageModel::selectedId() const
{
    return selected_;
}
<commit_msg>Use case insensitive compare for languages<commit_after>/*
Copyright (c) 2014 Pauli Nieminen <suokkos@gmail.com>

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

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

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

#include "languagemodel.h"

#include <QDir>
#include <QRegExp>

#include <QSettings>
#include <QLocale>
#include <QCoreApplication>

#include <QVariant>

LanguageModel::LanguageModel()
{

    QDir localepath(QCoreApplication::applicationDirPath() + "/locale");
    QStringList filter("*.qm");
    QStringList files = localepath.entryList(filter);

    QString lang = "en";

    QSettings settings;

    QRegExp rx("BridgeClock_([^.]*).qm");
    for (const QString &f : files) {
        if (rx.exactMatch(f)) {
            QString l = rx.cap(1);
            translations_.append(l);
            QLocale loc(l);
            if (loc.language() == QLocale::system().language())
                lang = l;
        }
    }

    if (settings.contains("locale"))
        lang = settings.value("locale").toString();

    std::sort(translations_.begin(), translations_.end(),
            [](const QString &a, const QString &b) {
                QLocale al(a);
                QLocale bl(b);
                return QString::compare(al.nativeLanguageName(), bl.nativeLanguageName(), Qt::CaseInsensitive) < 0;
            });
    selected_ = 0;

    for (const QString &t : translations_) {
        if (t == lang)
            break;
        selected_++;
    }

    trans_.load("locale/BridgeClock_" + lang);
    qApp->installTranslator(&trans_);
}

#include <QDebug>

QHash<int, QByteArray> LanguageModel::roleNames() const
{
    static QHash<int, QByteArray> names;
    if (names.empty()) {
        names[NameRole] = "name";
    }
    return names;
}

int LanguageModel::rowCount(const QModelIndex &) const
{
    return translations_.size();
}

QVariant LanguageModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= (int)translations_.size())
        return QVariant();

    switch (role) {
    default:
        break;
    case NameRole:
    {
        QLocale loc(translations_.at(index.row()));
        return loc.nativeLanguageName();
    }
    }
    return QVariant();
}

void LanguageModel::setSelectedId(int id)
{
    if (id == selected_ || id < 0 || id >= (int)translations_.size())
        return;

    selected_ = id;
    trans_.load("locale/BridgeClock_" + translations_.at(id));
    QSettings settings;
    settings.setValue("locale", translations_.at(id));
    emit selectedChanged();
}

QString LanguageModel::emptyLang() const
{
    return "";
}

QString LanguageModel::selectedNative() const
{
    QLocale loc(translations_.at(selected_));
    return loc.nativeLanguageName();
}

int LanguageModel::selectedId() const
{
    return selected_;
}
<|endoftext|>


<commit_before>/*
* Copyright (c), Microsoft Open Technologies, Inc.
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  - Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*  - Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Win32_Common.h"

namespace Globals
{
    size_t pageSize = 0;
}

/* This function is used to force the VEH on the entire size of the buffer length,
 * in the event that the buffer crosses the memory page boundaries */
void EnsureMemoryIsMapped(const void *buffer, size_t size) {
    // Use 'volatile' to make sure the compiler doesn't remove "c = *((char*) (p + offset));"
    volatile char c;
    char* p = (char*) buffer;
    char* pStart = p - ((size_t) p % Globals::pageSize);
    char* pEnd = p + size;
    if ((size_t) (pEnd - pStart) > Globals::pageSize) {
        size_t offset = 0;
        while (offset < size) {
            if (size < offset) {
                offset = size;
            } else {
                offset += Globals::pageSize;
            }
            c = *((char*) (p + offset));
        }
    }
}

bool IsWindowsVersionAtLeast(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) {
    OSVERSIONINFOEXW osvi = {sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0};
    DWORDLONG const dwlConditionMask = VerSetConditionMask(
        VerSetConditionMask(
        VerSetConditionMask(
        0, VER_MAJORVERSION, VER_GREATER_EQUAL),
        VER_MINORVERSION, VER_GREATER_EQUAL),
        VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);

    osvi.dwMajorVersion = wMajorVersion;
    osvi.dwMinorVersion = wMinorVersion;
    osvi.wServicePackMajor = wServicePackMajor;

    return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
<commit_msg>[PR] Fixed pointer overflow crash when using bgsave under rare circumstances.<commit_after>/*
* Copyright (c), Microsoft Open Technologies, Inc.
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  - Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*  - Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Win32_Common.h"

namespace Globals
{
    size_t pageSize = 0;
}

/* This function is used to force the VEH on the entire size of the buffer length,
 * in the event that the buffer crosses the memory page boundaries */
void EnsureMemoryIsMapped(const void *buffer, size_t size) {
    // Use 'volatile' to make sure the compiler doesn't remove "c = *((char*) (p + offset));"
    volatile char c;
    char* p = (char*) buffer;
    char* pStart = p - ((size_t) p % Globals::pageSize);
    char* pEnd = p + size;
    if ((size_t) (pEnd - pStart) > Globals::pageSize) {
        size_t offset = 0;
        while (offset < size) {
            offset += Globals::pageSize;
            if (offset > size) {
                offset = size;
            }
            c = *((char*) (p + offset));
        }
    }
}

bool IsWindowsVersionAtLeast(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) {
    OSVERSIONINFOEXW osvi = {sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0};
    DWORDLONG const dwlConditionMask = VerSetConditionMask(
        VerSetConditionMask(
        VerSetConditionMask(
        0, VER_MAJORVERSION, VER_GREATER_EQUAL),
        VER_MINORVERSION, VER_GREATER_EQUAL),
        VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);

    osvi.dwMajorVersion = wMajorVersion;
    osvi.dwMinorVersion = wMinorVersion;
    osvi.wServicePackMajor = wServicePackMajor;

    return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2013 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * SEDMLUtils.cpp
 *
 *  Created on: 15 Jul 2013
 *      Author: dada
 */

//#include <zip.h>
#include <sstream>
#include <iostream>
#include <vector>
#include "SEDMLUtils.h"

#include <sedml/SedTypes.h>
#include <sbml/SBMLTypes.h>

#include <copasi/model/CModel.h>
#include <copasi/report/CCopasiObject.h>
#include <copasi/CopasiDataModel/CCopasiDataModel.h>

std::string SEDMLUtils::findIdByNameAndType(
  const std::map<const CCopasiObject*, SBase*>& map,
  int typeCode,
  const std::string& name)
{
  std::map<const CCopasiObject*, SBase*>::const_iterator it = map.begin();

  std::string::size_type compartmentStart = name.find("{");

  std::string compId = "";

  if (compartmentStart != std::string::npos)
    {
      std::string compName = name.substr(compartmentStart + 1, name.size() - compartmentStart - 2);
      SEDMLUtils::removeCharactersFromString(compName, "\"");

      compId = findIdByNameAndType(map, SBML_COMPARTMENT, compName);
    }

  while (it != map.end())
    {
      SBase* current = it->second;
      const CCopasiObject* object = it->first;
      std::string displayName = object->getObjectDisplayName();

      if (((current->getTypeCode() & typeCode) != typeCode))
        {
          ++it;
          continue;
        }

      if (current->getName() == name)
        return current->getId();

      if (typeCode == SBML_SPECIES  && compartmentStart != std::string::npos)
        {
          if (displayName == name)
            {
              Species* species = (Species*)current;

              if (species->getCompartment() == compId)
                return species->getId();
            }
        }

      ++it;
    }

  return "";
}

std::string
SEDMLUtils::getXPathAndName(std::string& sbmlId,
                            const std::string &type,
                            const CModel *pModel,
                            const CCopasiDataModel& dataModel)
{
  std::vector<std::string> stringsContainer;
  std::string targetXPathString;
  const std::map<const CCopasiObject*, SBase*>& copasi2sbmlmap =
    const_cast<CCopasiDataModel&>(dataModel).getCopasi2SBMLMap();
  std::string displayName = sbmlId;

  if (copasi2sbmlmap.size() == 0)
    {
      // this should not be happening, as this is used to verify the element.
      return "";
    }

  std::map<CCopasiObject*, SBase*>::const_iterator pos;

  if (type == "Concentration" || type == "InitialConcentration")
    {
      targetXPathString = "/sbml:sbml/sbml:model/sbml:listOfSpecies/sbml:species[@id=\'";
      //remove unwanted characters from the plot item object name
      removeCharactersFromString(displayName, "[]");

      if (type == "InitialConcentration")
        {
          displayName = displayName.substr(0, displayName.length() - 2);
        }

      sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_SPECIES, displayName);

      if (!sbmlId.empty())
        {
          return targetXPathString + sbmlId + "\']";
        }
      else
        return "";
    }

  else if (type == "Flux")
    {
      targetXPathString = "/sbml:sbml/sbml:model/sbml:listOfReactions/sbml:reaction[@id=\'";

      std::string::size_type pos = displayName.rfind(".Flux");
      displayName = displayName.substr(1, pos - 2);

      sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_REACTION, displayName);

      if (!sbmlId.empty())
        {
          return targetXPathString + sbmlId + "\']";
        }
      else
        return "";
    }
  else if (type == "Value" || type == "InitialValue")
    {
      if (type == "InitialValue")
        {
          displayName = displayName.substr(0, displayName.find(".InitialValue"));
        }

      targetXPathString = "/sbml:sbml/sbml:model/sbml:listOfParameters/sbml:parameter[@id=\'";
      splitStrings(displayName, '[', stringsContainer);

      if (stringsContainer.size() == 1)
        {
          // not found ... might be a local parameter
          removeCharactersFromString(displayName, "()");
          splitStrings(displayName, '.', stringsContainer);

          if (stringsContainer.size() == 2)
            {
              sbmlId = stringsContainer[0] + "_" + stringsContainer[1];
              std::stringstream xpath;
              xpath << "/sbml:sbml/sbml:model/sbml:listOfReactions/sbml:reaction[@id=\'";
              xpath << stringsContainer[0];
              xpath << "\']/sbml:kineticLaw/sbml:listOfParameters/sbml:parameter[@id=\'";
              xpath << stringsContainer[1];
              xpath << "\']";
              return xpath.str();
            }
        }

      displayName = stringsContainer[1];

      removeCharactersFromString(displayName, "]");

      sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_PARAMETER , displayName);

      if (sbmlId.empty())
        sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_LOCAL_PARAMETER , displayName);

      if (!sbmlId.empty())
        {
          return targetXPathString + sbmlId + "\']";
        }
      else
        return "";
    }
  else if (type == "Volume" || type == "InitialVolume")
    {
      targetXPathString = "/sbml:sbml/sbml:model/sbml:listOfCompartments/sbml:compartment[@id=\'";
      splitStrings(displayName, '[', stringsContainer);
      displayName = stringsContainer[1];

      if (type == "InitialVolume")
        {
          displayName = displayName.substr(0, displayName.find(".InitialVolume"));
        }

      if (type == "Volume")
        {
          displayName = displayName.substr(0, displayName.find(".Volume"));
        }

      removeCharactersFromString(displayName, "]");

      sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_COMPARTMENT, displayName);

      if (!sbmlId.empty())
        {
          return targetXPathString + sbmlId + "\']";
        }
      else
        return "";
    }
  else if (type == "Time" || type == "Initial Time")
    return SEDML_TIME_URN;

  sbmlId = "";
  return targetXPathString;
}

const CCopasiObject*
SEDMLUtils::resolveDatagenerator(const CModel *model, const SedDataGenerator* dataReference)
{
  // for now one variable only
  if (dataReference == NULL || dataReference->getNumVariables() < 1) return NULL;

  const SedVariable* var = dataReference->getVariable(0);

  if (var->isSetSymbol() && var->getSymbol() == SEDML_TIME_URN)
    {
      return static_cast<const CCopasiObject *>(model->getObject(CCopasiObjectName("Reference=Time")));
    }

  return resolveXPath(model, var->getTarget());
}

std::string
SEDMLUtils::translateTargetXpathInSBMLId(const std::string &xpath, std::string& SBMLType)
{
  std::vector<std::string> xpathStrings;
  std::string id, nextString;

  splitStrings(xpath, ':', xpathStrings);
  nextString = xpathStrings[xpathStrings.size() - 1];

  splitStrings(nextString, '[', xpathStrings);
  SBMLType = xpathStrings[0];
  nextString = xpathStrings[xpathStrings.size() - 1];

  splitStrings(nextString, '=', xpathStrings);
  nextString = xpathStrings[xpathStrings.size() - 1];
  splitStrings(nextString, ']', xpathStrings);
  id = xpathStrings[0];

  //remove the remaining unwanted characters
  removeCharactersFromString(id, "\"']");
  return id;
}

const CCopasiObject*
SEDMLUtils::resolveXPath(const CModel *model,  const std::string& xpath,
                         bool initial /* = false*/)
{
  std::string SBMLType;
  std::string id = translateTargetXpathInSBMLId(xpath, SBMLType);
  const CCopasiObject* result = getObjectForSbmlId(model, id, SBMLType, initial);

  if (result == NULL)
    {
      // old method fails here, possibly a local parameter
      size_t pos = xpath.find("/sbml:kineticLaw/sbml:listOfParameters/");

      if (pos != std::string::npos)
        {
          std::string reactionType;
          std::string reactionId = translateTargetXpathInSBMLId(xpath.substr(0, pos), reactionType);
          const CCopasiObject* flux = getObjectForSbmlId(model, reactionId, reactionType);

          if (flux != NULL)
            {
              const CCopasiObject* reactionObj = flux->getObjectParent();
              std::string cn = "ParameterGroup=Parameters,Parameter=" + id + ",Reference=Value";
              return dynamic_cast<const CCopasiObject*>(reactionObj->getObject(cn));
            }
        }
    }

  return result;
}

std::string&
SEDMLUtils::removeCharactersFromString(std::string& str, const std::string& characters)
{
  for (unsigned int ii = 0; ii < characters.length(); ++ii)
    {
      str.erase(std::remove(str.begin(), str.end(), characters[ii]), str.end());
    }

  return str;
}

std::string
SEDMLUtils::getXPathForObject(const CCopasiObject& object)
{
  const std::string& type = object.getObjectName();
  const CCopasiDataModel* dm = object.getObjectDataModel();
  std::string yAxis = object.getObjectDisplayName();
  std::string targetXPathString = getXPathAndName(yAxis, type,
                                  dm->getModel(), *dm);
  return targetXPathString;
}

std::string SEDMLUtils::getNextId(const std::string& base, int count)
{
  std::stringstream str; str << base << count;
  return str.str();
}

int SEDMLUtils::processArchive(const std::string & archiveFile,
                               std::string &fileName, std::string &fileContent)
{

  int err = 0;
  /*
  const char * cArchive = archiveFile.c_str();

    //Open the ZIP archive
    zip *zip = zip_open(cArchive, 0, &err);

    //Search for file using its given name
    const char *nameOfFile = fileName.c_str();
    struct zip_stat st;
    zip_stat_init(&st);
    zip_stat(zip, nameOfFile, 0, &st);

    //Alloc memory for its uncompressed contents
    char *fileCont = new char[st.size];

    //Read the compressed file
  zip_file *file = zip_fopen(zip, nameOfFile, 0);
  zip_fread(file, fileCont, st.size);

  std::ostringstream fileContentStream;
  size_t i, iMax = st.size;
  for(i = 0; i<iMax; ++i){
    fileContentStream << fileCont[i];
  }
  fileContent = fileContentStream.str();

  //close the file and archive
  zip_fclose(file);
  zip_close(zip);
  */

  return err;
}

//split: receives a char delimiter and string and a vector of strings that will contain the splited strings
//this is presently a hack to parse the XPath based target attribute in SEDML. A better solution may be
//necessary in the future.

void
SEDMLUtils::splitStrings(const std::string &xpath, char delim,
                         std::vector<std::string> &xpathStrings)
{
  std::string myPath = xpath;
  xpathStrings.clear();
  std::string next;

  // For each character in the string
  for (std::string::const_iterator it = xpath.begin(); it != xpath.end(); it++)
    {
      // check delimeter character
      if (*it == delim)
        {
          if (!next.empty())
            {
              // Add them to the xpathStrings vector
              xpathStrings.push_back(next);
              next.clear();
            }
        }
      else
        {
          next += *it;
        }
    }

  if (!next.empty())
    xpathStrings.push_back(next);
}

const CCopasiObject *
SEDMLUtils::getObjectForSbmlId(const CModel* pModel, const std::string& id, const std::string& SBMLType, bool initial/* = false*/)
{
  if (SBMLType == "Time")
    return static_cast<const CCopasiObject *>(pModel->getObject(CCopasiObjectName("Reference=Time")));

  if (SBMLType == "species")
    {
      size_t iMet, imax = pModel->getMetabolites().size();

      for (iMet = 0; iMet < imax; ++iMet)
        {
          // the importer should not need to change the initial concentration
          // pModel->getMetabolites()[iMet].setInitialConcentration(0.896901);

          if (pModel->getMetabolites()[iMet].getSBMLId() == id)
            {
              if (initial)
                return pModel->getMetabolites()[iMet].getInitialConcentrationReference();

              return pModel->getMetabolites()[iMet].getConcentrationReference();
            }
        }
    }
  else if (SBMLType == "reaction")
    {
      size_t iMet, imax = pModel->getReactions().size();

      for (iMet = 0; iMet < imax; ++iMet)
        {
          if (pModel->getReactions()[iMet].getSBMLId() == id)
            {
              if (initial)
                return NULL;

              return pModel->getReactions()[iMet].getFluxReference();
            }
        }
    }
  else if (SBMLType == "parameter")
    {
      size_t iMet, imax = pModel->getModelValues().size();

      for (iMet = 0; iMet < imax; ++iMet)
        {
          if (pModel->getModelValues()[iMet].getSBMLId() == id)
            {
              if (initial)
                return pModel->getModelValues()[iMet].getInitialValueReference();

              return pModel->getModelValues()[iMet].getValueReference();
            }
        }
    }

  else if (SBMLType == "compartment")
    {
      size_t iComp, imax = pModel->getCompartments().size();

      for (iComp = 0; iComp < imax; ++iComp)
        {
          if (pModel->getCompartments()[iComp].getSBMLId() == id)
            {
              if (initial)
                return pModel->getCompartments()[iComp].getInitialValueReference();

              return pModel->getCompartments()[iComp].getValueReference();
            }
        }
    }

  return NULL;
}

/*void SEDMLUtils::resmoveUnwantedChars(std::string & str, char chars[]) {
  for (unsigned int i = 0; i < strlen(chars); ++i) {

    str.erase(std::remove(str.begin(), str.end(), chars[i]), str.end());
  }
}
 */
SEDMLUtils::SEDMLUtils()
{
  // TODO Auto-generated constructor stub
}

SEDMLUtils::~SEDMLUtils()
{
  // TODO Auto-generated destructor stub
}
<commit_msg>- issue 2360: improve xpath generation for local parameters<commit_after>// Copyright (C) 2017 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2013 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * SEDMLUtils.cpp
 *
 *  Created on: 15 Jul 2013
 *      Author: dada
 */

//#include <zip.h>
#include <sstream>
#include <iostream>
#include <vector>
#include "SEDMLUtils.h"

#include <sedml/SedTypes.h>
#include <sbml/SBMLTypes.h>

#include <copasi/model/CModel.h>
#include <copasi/report/CCopasiObject.h>
#include <copasi/CopasiDataModel/CCopasiDataModel.h>

std::string SEDMLUtils::findIdByNameAndType(
  const std::map<const CCopasiObject*, SBase*>& map,
  int typeCode,
  const std::string& name)
{
  std::map<const CCopasiObject*, SBase*>::const_iterator it = map.begin();

  std::string::size_type compartmentStart = name.find("{");

  std::string compId = "";

  if (compartmentStart != std::string::npos)
    {
      std::string compName = name.substr(compartmentStart + 1, name.size() - compartmentStart - 2);
      SEDMLUtils::removeCharactersFromString(compName, "\"");

      compId = findIdByNameAndType(map, SBML_COMPARTMENT, compName);
    }

  while (it != map.end())
    {
      SBase* current = it->second;
      const CCopasiObject* object = it->first;
      std::string displayName = object->getObjectDisplayName();

      if (((current->getTypeCode() & typeCode) != typeCode))
        {
          ++it;
          continue;
        }

      if (current->getName() == name)
        return current->getId();

      if (typeCode == SBML_SPECIES  && compartmentStart != std::string::npos)
        {
          if (displayName == name)
            {
              Species* species = (Species*)current;

              if (species->getCompartment() == compId)
                return species->getId();
            }
        }

      ++it;
    }

  return "";
}

std::string
SEDMLUtils::getXPathAndName(std::string& sbmlId,
                            const std::string &type,
                            const CModel *pModel,
                            const CCopasiDataModel& dataModel)
{
  std::vector<std::string> stringsContainer;
  std::string targetXPathString;
  const std::map<const CCopasiObject*, SBase*>& copasi2sbmlmap =
    const_cast<CCopasiDataModel&>(dataModel).getCopasi2SBMLMap();
  std::string displayName = sbmlId;

  if (copasi2sbmlmap.size() == 0)
    {
      // this should not be happening, as this is used to verify the element.
      return "";
    }

  std::map<CCopasiObject*, SBase*>::const_iterator pos;

  if (type == "Concentration" || type == "InitialConcentration")
    {
      targetXPathString = "/sbml:sbml/sbml:model/sbml:listOfSpecies/sbml:species[@id=\'";
      //remove unwanted characters from the plot item object name
      removeCharactersFromString(displayName, "[]");

      if (type == "InitialConcentration")
        {
          displayName = displayName.substr(0, displayName.length() - 2);
        }

      sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_SPECIES, displayName);

      if (!sbmlId.empty())
        {
          return targetXPathString + sbmlId + "\']";
        }
      else
        return "";
    }

  else if (type == "Flux")
    {
      targetXPathString = "/sbml:sbml/sbml:model/sbml:listOfReactions/sbml:reaction[@id=\'";

      std::string::size_type pos = displayName.rfind(".Flux");
      displayName = displayName.substr(1, pos - 2);

      sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_REACTION, displayName);

      if (!sbmlId.empty())
        {
          return targetXPathString + sbmlId + "\']";
        }
      else
        return "";
    }
  else if (type == "Value" || type == "InitialValue")
    {
      if (type == "InitialValue")
        {
          displayName = displayName.substr(0, displayName.find(".InitialValue"));
        }

      targetXPathString = "/sbml:sbml/sbml:model/sbml:listOfParameters/sbml:parameter[@id=\'";
      splitStrings(displayName, '[', stringsContainer);

      if (stringsContainer.size() == 1)
        {
          // not found ... might be a local parameter
          size_t parameterPos = displayName.rfind(".");

          if (parameterPos != std::string::npos)
            {
              std::string parameterId = displayName.substr(parameterPos + 1);
              std::string reactionName = displayName.substr(1, parameterPos - 2);
              sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_REACTION, reactionName);

              std::stringstream xpath;
              xpath << "/sbml:sbml/sbml:model/sbml:listOfReactions/sbml:reaction[@id=\'";
              xpath << sbmlId;
              xpath << "\']/sbml:kineticLaw/sbml:listOfParameters/sbml:parameter[@id=\'";
              xpath << parameterId;
              xpath << "\']";

              sbmlId += "_" + parameterId;

              return xpath.str();

            }

          removeCharactersFromString(displayName, "()");
          splitStrings(displayName, '.', stringsContainer);

          if (stringsContainer.size() == 2)
            {
              sbmlId = stringsContainer[0] + "_" + stringsContainer[1];
              std::stringstream xpath;
              xpath << "/sbml:sbml/sbml:model/sbml:listOfReactions/sbml:reaction[@id=\'";
              xpath << stringsContainer[0];
              xpath << "\']/sbml:kineticLaw/sbml:listOfParameters/sbml:parameter[@id=\'";
              xpath << stringsContainer[1];
              xpath << "\']";
              return xpath.str();
            }
        }

      displayName = stringsContainer[1];

      removeCharactersFromString(displayName, "]");

      sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_PARAMETER , displayName);

      if (sbmlId.empty())
        sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_LOCAL_PARAMETER , displayName);

      if (!sbmlId.empty())
        {
          return targetXPathString + sbmlId + "\']";
        }
      else
        return "";
    }
  else if (type == "Volume" || type == "InitialVolume")
    {
      targetXPathString = "/sbml:sbml/sbml:model/sbml:listOfCompartments/sbml:compartment[@id=\'";
      splitStrings(displayName, '[', stringsContainer);
      displayName = stringsContainer[1];

      if (type == "InitialVolume")
        {
          displayName = displayName.substr(0, displayName.find(".InitialVolume"));
        }

      if (type == "Volume")
        {
          displayName = displayName.substr(0, displayName.find(".Volume"));
        }

      removeCharactersFromString(displayName, "]");

      sbmlId = findIdByNameAndType(copasi2sbmlmap, SBML_COMPARTMENT, displayName);

      if (!sbmlId.empty())
        {
          return targetXPathString + sbmlId + "\']";
        }
      else
        return "";
    }
  else if (type == "Time" || type == "Initial Time")
    return SEDML_TIME_URN;

  sbmlId = "";
  return targetXPathString;
}

const CCopasiObject*
SEDMLUtils::resolveDatagenerator(const CModel *model, const SedDataGenerator* dataReference)
{
  // for now one variable only
  if (dataReference == NULL || dataReference->getNumVariables() < 1) return NULL;

  const SedVariable* var = dataReference->getVariable(0);

  if (var->isSetSymbol() && var->getSymbol() == SEDML_TIME_URN)
    {
      return static_cast<const CCopasiObject *>(model->getObject(CCopasiObjectName("Reference=Time")));
    }

  return resolveXPath(model, var->getTarget());
}

std::string
SEDMLUtils::translateTargetXpathInSBMLId(const std::string &xpath, std::string& SBMLType)
{
  std::vector<std::string> xpathStrings;
  std::string id, nextString;

  splitStrings(xpath, ':', xpathStrings);
  nextString = xpathStrings[xpathStrings.size() - 1];

  splitStrings(nextString, '[', xpathStrings);
  SBMLType = xpathStrings[0];
  nextString = xpathStrings[xpathStrings.size() - 1];

  splitStrings(nextString, '=', xpathStrings);
  nextString = xpathStrings[xpathStrings.size() - 1];
  splitStrings(nextString, ']', xpathStrings);
  id = xpathStrings[0];

  //remove the remaining unwanted characters
  removeCharactersFromString(id, "\"']");
  return id;
}

const CCopasiObject*
SEDMLUtils::resolveXPath(const CModel *model,  const std::string& xpath,
                         bool initial /* = false*/)
{
  std::string SBMLType;
  std::string id = translateTargetXpathInSBMLId(xpath, SBMLType);
  const CCopasiObject* result = getObjectForSbmlId(model, id, SBMLType, initial);

  if (result == NULL)
    {
      // old method fails here, possibly a local parameter
      size_t pos = xpath.find("/sbml:kineticLaw/sbml:listOfParameters/");

      if (pos != std::string::npos)
        {
          std::string reactionType;
          std::string reactionId = translateTargetXpathInSBMLId(xpath.substr(0, pos), reactionType);
          const CCopasiObject* flux = getObjectForSbmlId(model, reactionId, reactionType);

          if (flux != NULL)
            {
              const CCopasiObject* reactionObj = flux->getObjectParent();
              std::string cn = "ParameterGroup=Parameters,Parameter=" + id + ",Reference=Value";
              return dynamic_cast<const CCopasiObject*>(reactionObj->getObject(cn));
            }
        }
    }

  return result;
}

std::string&
SEDMLUtils::removeCharactersFromString(std::string& str, const std::string& characters)
{
  for (unsigned int ii = 0; ii < characters.length(); ++ii)
    {
      str.erase(std::remove(str.begin(), str.end(), characters[ii]), str.end());
    }

  return str;
}

std::string
SEDMLUtils::getXPathForObject(const CCopasiObject& object)
{
  const std::string& type = object.getObjectName();
  const CCopasiDataModel* dm = object.getObjectDataModel();
  std::string yAxis = object.getObjectDisplayName();
  std::string targetXPathString = getXPathAndName(yAxis, type,
                                  dm->getModel(), *dm);
  return targetXPathString;
}

std::string SEDMLUtils::getNextId(const std::string& base, int count)
{
  std::stringstream str; str << base << count;
  return str.str();
}

int SEDMLUtils::processArchive(const std::string & archiveFile,
                               std::string &fileName, std::string &fileContent)
{

  int err = 0;
  /*
  const char * cArchive = archiveFile.c_str();

    //Open the ZIP archive
    zip *zip = zip_open(cArchive, 0, &err);

    //Search for file using its given name
    const char *nameOfFile = fileName.c_str();
    struct zip_stat st;
    zip_stat_init(&st);
    zip_stat(zip, nameOfFile, 0, &st);

    //Alloc memory for its uncompressed contents
    char *fileCont = new char[st.size];

    //Read the compressed file
  zip_file *file = zip_fopen(zip, nameOfFile, 0);
  zip_fread(file, fileCont, st.size);

  std::ostringstream fileContentStream;
  size_t i, iMax = st.size;
  for(i = 0; i<iMax; ++i){
    fileContentStream << fileCont[i];
  }
  fileContent = fileContentStream.str();

  //close the file and archive
  zip_fclose(file);
  zip_close(zip);
  */

  return err;
}

//split: receives a char delimiter and string and a vector of strings that will contain the splited strings
//this is presently a hack to parse the XPath based target attribute in SEDML. A better solution may be
//necessary in the future.

void
SEDMLUtils::splitStrings(const std::string &xpath, char delim,
                         std::vector<std::string> &xpathStrings)
{
  std::string myPath = xpath;
  xpathStrings.clear();
  std::string next;

  // For each character in the string
  for (std::string::const_iterator it = xpath.begin(); it != xpath.end(); it++)
    {
      // check delimeter character
      if (*it == delim)
        {
          if (!next.empty())
            {
              // Add them to the xpathStrings vector
              xpathStrings.push_back(next);
              next.clear();
            }
        }
      else
        {
          next += *it;
        }
    }

  if (!next.empty())
    xpathStrings.push_back(next);
}

const CCopasiObject *
SEDMLUtils::getObjectForSbmlId(const CModel* pModel, const std::string& id, const std::string& SBMLType, bool initial/* = false*/)
{
  if (SBMLType == "Time")
    return static_cast<const CCopasiObject *>(pModel->getObject(CCopasiObjectName("Reference=Time")));

  if (SBMLType == "species")
    {
      size_t iMet, imax = pModel->getMetabolites().size();

      for (iMet = 0; iMet < imax; ++iMet)
        {
          // the importer should not need to change the initial concentration
          // pModel->getMetabolites()[iMet].setInitialConcentration(0.896901);

          if (pModel->getMetabolites()[iMet].getSBMLId() == id)
            {
              if (initial)
                return pModel->getMetabolites()[iMet].getInitialConcentrationReference();

              return pModel->getMetabolites()[iMet].getConcentrationReference();
            }
        }
    }
  else if (SBMLType == "reaction")
    {
      size_t iMet, imax = pModel->getReactions().size();

      for (iMet = 0; iMet < imax; ++iMet)
        {
          if (pModel->getReactions()[iMet].getSBMLId() == id)
            {
              if (initial)
                return NULL;

              return pModel->getReactions()[iMet].getFluxReference();
            }
        }
    }
  else if (SBMLType == "parameter")
    {
      size_t iMet, imax = pModel->getModelValues().size();

      for (iMet = 0; iMet < imax; ++iMet)
        {
          if (pModel->getModelValues()[iMet].getSBMLId() == id)
            {
              if (initial)
                return pModel->getModelValues()[iMet].getInitialValueReference();

              return pModel->getModelValues()[iMet].getValueReference();
            }
        }
    }

  else if (SBMLType == "compartment")
    {
      size_t iComp, imax = pModel->getCompartments().size();

      for (iComp = 0; iComp < imax; ++iComp)
        {
          if (pModel->getCompartments()[iComp].getSBMLId() == id)
            {
              if (initial)
                return pModel->getCompartments()[iComp].getInitialValueReference();

              return pModel->getCompartments()[iComp].getValueReference();
            }
        }
    }

  return NULL;
}

/*void SEDMLUtils::resmoveUnwantedChars(std::string & str, char chars[]) {
  for (unsigned int i = 0; i < strlen(chars); ++i) {

    str.erase(std::remove(str.begin(), str.end(), chars[i]), str.end());
  }
}
 */
SEDMLUtils::SEDMLUtils()
{
  // TODO Auto-generated constructor stub
}

SEDMLUtils::~SEDMLUtils()
{
  // TODO Auto-generated destructor stub
}
<|endoftext|>


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

#include <gtest/gtest.h>
#include "capu/os/TcpServerSocket.h"
#include "capu/os/Thread.h"
#include "capu/os/TcpSocket.h"
#include "gmock/gmock-matchers.h"
#include "gmock/gmock-generated-matchers.h"
#include "capu/container/HashTable.h"
#include "capu/os/NonBlockSocketChecker.h"

class RandomPort
{
public:
    /**
    * Gets a Random Port between 1024 and 10024
    */
    static capu::uint16_t get()
    {
        return (rand() % 10000) + 40000; // 0-1023 = Well Known, 1024-49151 = User, 49152 - 65535 = Dynamic
    }
};

class AsyncSocketHandler
{
public:

    AsyncSocketHandler(const capu::uint32_t numberOfClients, capu::uint16_t port)
        : m_socketInfos(numberOfClients*2)
        , m_receiveCount(0)
    {
        m_serverSocket.bind(port, "0.0.0.0");
        m_serverSocket.listen(10);

        m_socketInfos.push_back(capu::os::SocketInfoPair(m_serverSocket.getSocketDescription(), capu::os::SocketDelegate::Create<AsyncSocketHandler, &AsyncSocketHandler::acceptConnectionCallback>(*this)));
    }

    ~AsyncSocketHandler()
    {
        capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator current = m_clientSockets.begin();
        const capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator end = m_clientSockets.end();

        for (; current != end; ++current)
        {
            current->value->close();
            delete current->value;
        }
    }

    void acceptConnectionCallback(const capu::os::SocketDescription& socketDescription)
    {
        UNUSED(socketDescription);
        capu::TcpSocket* clientSocket = m_serverSocket.accept();
        EXPECT_TRUE(0 != clientSocket);
        m_clientSockets.put(clientSocket->getSocketDescription(), clientSocket);
        m_socketInfos.push_back(capu::os::SocketInfoPair(clientSocket->getSocketDescription(), capu::os::SocketDelegate::Create<AsyncSocketHandler, &AsyncSocketHandler::receiveDataCallback>(*this)));
    }

    void sendSomeData()
    {
        capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator current = m_clientSockets.begin();
        capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator end = m_clientSockets.end();

        for (; current != end; ++current)
        {
            capu::uint32_t sendValue = 42;
            capu::int32_t sendBytes;
            current->value->send(reinterpret_cast<capu::char_t*>(&sendValue), sizeof(sendValue), sendBytes);
        }
    }

    void receiveDataCallback(const capu::os::SocketDescription& socketDescription)
    {
        capu::int32_t data;
        capu::int32_t numbytes = 0;

        capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator entry = m_clientSockets.find(socketDescription);
        if (entry != m_clientSockets.end())
        {
            EXPECT_EQ(capu::CAPU_OK, entry->value->receive(reinterpret_cast<capu::char_t*>(&data), sizeof(data), numbytes));
            if (numbytes != 0)
            {
                EXPECT_EQ(42, data);
                ++m_receiveCount;
            }
        }
    }

    capu::Vector<capu::os::SocketInfoPair> m_socketInfos;
    capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*> m_clientSockets;
    capu::TcpServerSocket m_serverSocket;
    capu::uint32_t m_receiveCount;
};

class AsyncClient : public capu::Runnable
{
public:
    AsyncClient()
        : m_port(0)
        , m_send(false)
        , m_receiveCount(0)
    {

    }
    void receiveSomeData(const capu::os::SocketDescription&)
    {
        capu::int32_t data;
        capu::int32_t numbytes = 0;

        EXPECT_EQ(capu::CAPU_OK, m_clientSocket.receive(reinterpret_cast<capu::char_t*>(&data), sizeof(data), numbytes));
        if (numbytes!=0)
        {
            EXPECT_EQ(42, data);
            ++m_receiveCount;
        }
    }

    void run()
    {
        m_clientSocket.setTimeout(1000);

        while (m_clientSocket.connect("localhost", m_port) != capu::CAPU_OK){
        }

        m_socketInfos.push_back(capu::os::SocketInfoPair(m_clientSocket.getSocketDescription(), capu::os::SocketDelegate::Create<AsyncClient, &AsyncClient::receiveSomeData>(*this)));

        if (m_send)
        {
            capu::uint32_t sendValue = 42;
            capu::int32_t sendBytes;
            m_clientSocket.send(reinterpret_cast<capu::char_t*>(&sendValue), sizeof(sendValue), sendBytes);
            EXPECT_EQ(static_cast<capu::int32_t>(sizeof(sendValue)), sendBytes);
        }
    }

    void start(capu::uint16_t port, capu::bool_t send)
    {
        m_port = port;
        m_send = send;
        m_thread.start(*this);
    }

    void stop()
    {
        m_thread.cancel();
        m_thread.join();
        m_clientSocket.close();
    }

    capu::TcpSocket* getSocket()
    {
        return &m_clientSocket;
    }

    capu::uint16_t m_port;
    capu::bool_t m_send;
    capu::TcpSocket m_clientSocket;
    capu::Thread m_thread;
    capu::Vector<capu::os::SocketInfoPair> m_socketInfos;
    capu::uint32_t m_receiveCount;
};

TEST(NonBlockSocketCheckerTest, AcceptALotOfClients)
{
    static const capu::uint32_t clientcount = 50;

    capu::uint16_t port = RandomPort::get();

    AsyncSocketHandler asyncSocketHandler(clientcount, port);

    AsyncClient asyncClient[clientcount];

    for (capu::uint32_t i = 0; i < clientcount; ++i)
    {
        asyncClient[i].start(port, false);
    }

    while (asyncSocketHandler.m_clientSockets.count() < clientcount)
    {
        capu::NonBlockSocketChecker::CheckSocketsForIncomingData(asyncSocketHandler.m_socketInfos, 10);
    }

    for (capu::uint32_t i = 0; i < clientcount; ++i)
    {
        asyncClient[i].stop();
    }
}

TEST(NonBlockSocketCheckerTest, DISABLED_ReceiveDataFromALotOfClients)
{
    static const capu::uint32_t clientcount = 50;

    capu::uint16_t port = RandomPort::get();

    AsyncSocketHandler asyncSocketHandler(clientcount, port);

    AsyncClient asyncClient[clientcount];

    for (capu::uint32_t i = 0; i < clientcount; ++i)
    {
        asyncClient[i].start(port, true);
    }

    while (asyncSocketHandler.m_receiveCount < clientcount)
    {
        capu::NonBlockSocketChecker::CheckSocketsForIncomingData(asyncSocketHandler.m_socketInfos, 10);
    }

    for (capu::uint32_t i = 0; i < clientcount; ++i)
    {
        asyncClient[i].stop();
    }
}

TEST(NonBlockSocketCheckerTest, DISABLED_ReceiveDataOnClientSide)
{
    capu::uint16_t port = RandomPort::get();

    AsyncSocketHandler asyncSocketHandler(1, port);

    AsyncClient asyncClient;
    asyncClient.start(port, false);

    while (asyncSocketHandler.m_clientSockets.count() < 1)
    {
        capu::NonBlockSocketChecker::CheckSocketsForIncomingData(asyncSocketHandler.m_socketInfos, 0);
    }

    asyncSocketHandler.sendSomeData();

    while (asyncClient.m_receiveCount < 1)
    {
        capu::NonBlockSocketChecker::CheckSocketsForIncomingData(asyncClient.m_socketInfos, 1000);
    }

    asyncClient.stop();
}
<commit_msg>Fix uninitialized warning in NonBlockSocketCheckerTest<commit_after>/*
 * Copyright (C) 2012 BMW Car IT GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>
#include "capu/os/TcpServerSocket.h"
#include "capu/os/Thread.h"
#include "capu/os/TcpSocket.h"
#include "gmock/gmock-matchers.h"
#include "gmock/gmock-generated-matchers.h"
#include "capu/container/HashTable.h"
#include "capu/os/NonBlockSocketChecker.h"

class RandomPort
{
public:
    /**
    * Gets a Random Port between 1024 and 10024
    */
    static capu::uint16_t get()
    {
        return (rand() % 10000) + 40000; // 0-1023 = Well Known, 1024-49151 = User, 49152 - 65535 = Dynamic
    }
};

class AsyncSocketHandler
{
public:

    AsyncSocketHandler(const capu::uint32_t numberOfClients, capu::uint16_t port)
        : m_socketInfos(numberOfClients*2)
        , m_receiveCount(0)
    {
        m_serverSocket.bind(port, "0.0.0.0");
        m_serverSocket.listen(10);

        m_socketInfos.push_back(capu::os::SocketInfoPair(m_serverSocket.getSocketDescription(), capu::os::SocketDelegate::Create<AsyncSocketHandler, &AsyncSocketHandler::acceptConnectionCallback>(*this)));
    }

    ~AsyncSocketHandler()
    {
        capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator current = m_clientSockets.begin();
        const capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator end = m_clientSockets.end();

        for (; current != end; ++current)
        {
            current->value->close();
            delete current->value;
        }
    }

    void acceptConnectionCallback(const capu::os::SocketDescription& socketDescription)
    {
        UNUSED(socketDescription);
        capu::TcpSocket* clientSocket = m_serverSocket.accept();
        EXPECT_TRUE(0 != clientSocket);
        m_clientSockets.put(clientSocket->getSocketDescription(), clientSocket);
        m_socketInfos.push_back(capu::os::SocketInfoPair(clientSocket->getSocketDescription(), capu::os::SocketDelegate::Create<AsyncSocketHandler, &AsyncSocketHandler::receiveDataCallback>(*this)));
    }

    void sendSomeData()
    {
        capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator current = m_clientSockets.begin();
        capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator end = m_clientSockets.end();

        for (; current != end; ++current)
        {
            capu::uint32_t sendValue = 42;
            capu::int32_t sendBytes;
            current->value->send(reinterpret_cast<capu::char_t*>(&sendValue), sizeof(sendValue), sendBytes);
        }
    }

    void receiveDataCallback(const capu::os::SocketDescription& socketDescription)
    {
        capu::int32_t data;
        capu::int32_t numbytes = 0;

        capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*>::Iterator entry = m_clientSockets.find(socketDescription);
        if (entry != m_clientSockets.end())
        {
            EXPECT_EQ(capu::CAPU_OK, entry->value->receive(reinterpret_cast<capu::char_t*>(&data), sizeof(data), numbytes));
            if (numbytes != 0)
            {
                EXPECT_EQ(42, data);
                ++m_receiveCount;
            }
        }
    }

    capu::Vector<capu::os::SocketInfoPair> m_socketInfos;
    capu::HashTable<capu::os::SocketDescription, capu::TcpSocket*> m_clientSockets;
    capu::TcpServerSocket m_serverSocket;
    capu::uint32_t m_receiveCount;
};

class AsyncClient : public capu::Runnable
{
public:
    AsyncClient()
        : m_port(0)
        , m_send(false)
        , m_receiveCount(0)
    {

    }
    void receiveSomeData(const capu::os::SocketDescription&)
    {
        capu::int32_t data;
        capu::int32_t numbytes = 0;

        EXPECT_EQ(capu::CAPU_OK, m_clientSocket.receive(reinterpret_cast<capu::char_t*>(&data), sizeof(data), numbytes));
        if (numbytes!=0)
        {
            EXPECT_EQ(42, data);
            ++m_receiveCount;
        }
    }

    void run()
    {
        m_clientSocket.setTimeout(1000);

        while (m_clientSocket.connect("localhost", m_port) != capu::CAPU_OK){
        }

        m_socketInfos.push_back(capu::os::SocketInfoPair(m_clientSocket.getSocketDescription(), capu::os::SocketDelegate::Create<AsyncClient, &AsyncClient::receiveSomeData>(*this)));

        if (m_send)
        {
            capu::uint32_t sendValue = 42;
            capu::int32_t sendBytes = -1;
            m_clientSocket.send(reinterpret_cast<capu::char_t*>(&sendValue), sizeof(sendValue), sendBytes);
            EXPECT_EQ(static_cast<capu::int32_t>(sizeof(sendValue)), sendBytes);
        }
    }

    void start(capu::uint16_t port, capu::bool_t send)
    {
        m_port = port;
        m_send = send;
        m_thread.start(*this);
    }

    void stop()
    {
        m_thread.cancel();
        m_thread.join();
        m_clientSocket.close();
    }

    capu::TcpSocket* getSocket()
    {
        return &m_clientSocket;
    }

    capu::uint16_t m_port;
    capu::bool_t m_send;
    capu::TcpSocket m_clientSocket;
    capu::Thread m_thread;
    capu::Vector<capu::os::SocketInfoPair> m_socketInfos;
    capu::uint32_t m_receiveCount;
};

TEST(NonBlockSocketCheckerTest, AcceptALotOfClients)
{
    static const capu::uint32_t clientcount = 50;

    capu::uint16_t port = RandomPort::get();

    AsyncSocketHandler asyncSocketHandler(clientcount, port);

    AsyncClient asyncClient[clientcount];

    for (capu::uint32_t i = 0; i < clientcount; ++i)
    {
        asyncClient[i].start(port, false);
    }

    while (asyncSocketHandler.m_clientSockets.count() < clientcount)
    {
        capu::NonBlockSocketChecker::CheckSocketsForIncomingData(asyncSocketHandler.m_socketInfos, 10);
    }

    for (capu::uint32_t i = 0; i < clientcount; ++i)
    {
        asyncClient[i].stop();
    }
}

TEST(NonBlockSocketCheckerTest, DISABLED_ReceiveDataFromALotOfClients)
{
    static const capu::uint32_t clientcount = 50;

    capu::uint16_t port = RandomPort::get();

    AsyncSocketHandler asyncSocketHandler(clientcount, port);

    AsyncClient asyncClient[clientcount];

    for (capu::uint32_t i = 0; i < clientcount; ++i)
    {
        asyncClient[i].start(port, true);
    }

    while (asyncSocketHandler.m_receiveCount < clientcount)
    {
        capu::NonBlockSocketChecker::CheckSocketsForIncomingData(asyncSocketHandler.m_socketInfos, 10);
    }

    for (capu::uint32_t i = 0; i < clientcount; ++i)
    {
        asyncClient[i].stop();
    }
}

TEST(NonBlockSocketCheckerTest, DISABLED_ReceiveDataOnClientSide)
{
    capu::uint16_t port = RandomPort::get();

    AsyncSocketHandler asyncSocketHandler(1, port);

    AsyncClient asyncClient;
    asyncClient.start(port, false);

    while (asyncSocketHandler.m_clientSockets.count() < 1)
    {
        capu::NonBlockSocketChecker::CheckSocketsForIncomingData(asyncSocketHandler.m_socketInfos, 0);
    }

    asyncSocketHandler.sendSomeData();

    while (asyncClient.m_receiveCount < 1)
    {
        capu::NonBlockSocketChecker::CheckSocketsForIncomingData(asyncClient.m_socketInfos, 1000);
    }

    asyncClient.stop();
}
<|endoftext|>


<commit_before>// An implementation of Fujimoto's airport model
// Ported from the ROSS airport model (https://github.com/carothersc/ROSS/blob/master/ross/models/airport)
// Author: Eric Carver (carverer@mail.uc.edu)

#include <vector>
#include <memory>
#include <random>

#include "warped.hpp"
#include "airport.hpp"

#include "MLCG.h"
#include "NegExp.h"

#include "tclap/ValueArg.h"

WARPED_REGISTER_POLYMORPHIC_SERIALIZABLE_CLASS(AirportEvent)

std::vector<std::shared_ptr<warped::Event> > Airport::createInitialEvents()
{
  std::vector<std::shared_ptr<warped::Event> > events;

  NegativeExpntl depart_expo((double)this->depart_mean_, this->rng_.get());

  for (unsigned int i = 0; i < this->num_planes_; i++) {
    events.emplace_back(new AirportEvent {this->name_, DEPARTURE,
                                            (unsigned int)depart_expo()});
  }

  return events;
}

inline std::string Airport::object_name(const unsigned int object_index)
{
  return std::string("Object ") + std::to_string(object_index);
}

std::vector<std::shared_ptr<warped::Event> > Airport::receiveEvent(const warped::Event& event)
{
  std::vector<std::shared_ptr<warped::Event> > response_events;
  auto received_event = static_cast<const AirportEvent&>(event);

  NegativeExpntl depart_expo((double)this->depart_mean_, this->rng_.get());
  NegativeExpntl land_expo((double)this->land_mean_, this->rng_.get());

  // std::uniform_int_distribution<unsigned int> rand_direction(0,3);
  std::uniform_int_distribution<unsigned int> rand_airport(0,this->num_airports_-1);

  switch ( received_event.type_ ) {
  case DEPARTURE:
    {
      this->state_.planes_grounded_--;
      this->state_.planes_flying_++;
      this->state_.departures_++;
      // Schedule an arrival at a random airport
      unsigned int landing_time = received_event.ts_ + (unsigned int)land_expo();
      // direction_t direction = (direction_t) rand_direction(this->rng_engine_);
      unsigned int destination_index = rand_airport(this->rng_engine_);
      response_events.emplace_back(new AirportEvent {Airport::object_name(destination_index),
                                                            ARRIVAL, landing_time });
      break;
    }
  case ARRIVAL:
    {
      // Schedule a landing
      response_events.emplace_back(new AirportEvent { this->name_, LANDING, received_event.ts_ });
      break;
    }
  case LANDING:
    {
      this->state_.landings_++;
      this->state_.planes_flying_--;
      this->state_.planes_grounded_++;
      // Schedule a departure
      response_events.emplace_back(new AirportEvent { this->name_, DEPARTURE,
                                            received_event.ts_ + (unsigned int)depart_expo() });
      break;
    }
  }
  return response_events;
}

int main(int argc, const char** argv)
{
  unsigned int num_airports = 1024;
  unsigned int mean_ground_time = 10;
  unsigned int mean_flight_time = 30;
  unsigned int num_planes = 1;

  TCLAP::ValueArg<unsigned int> num_airports_arg("n", "num-airports", "Number of airports",
                                                 false, num_airports, "unsigned int");
  TCLAP::ValueArg<unsigned int> mean_ground_time_arg("g", "ground-time", "Mean time of planes waiting to depart",
                                                     false, mean_ground_time, "unsigned int");
  TCLAP::ValueArg<unsigned int> mean_flight_time_arg("f", "flight-time", "Mean flight time",
                                                     false, mean_flight_time, "unsigned int");
  TCLAP::ValueArg<unsigned int> num_planes_arg("p", "num-planes", "Number of planes per airport",
                                               false, num_planes, "unsigned int");

  std::vector<TCLAP::Arg*> args = {&num_airports_arg, &mean_ground_time_arg, &mean_flight_time_arg,
                                   &num_planes_arg};

  warped::Simulation airport_sim {"Airport Simulation", argc, argv, args};

  num_airports = num_airports_arg.getValue();
  mean_ground_time = mean_ground_time_arg.getValue();
  mean_flight_time = mean_flight_time_arg.getValue();
  num_planes = num_planes_arg.getValue();

  std::vector<Airport> objects;

  for (unsigned int i = 0; i < num_airports; i++) {
    std::string name = Airport::object_name(i);
    objects.emplace_back(name, num_airports, num_planes, mean_flight_time, mean_ground_time, i);
  }

  std::vector<warped::SimulationObject*> object_pointers;
  for (auto& o : objects) {
    object_pointers.push_back(&o);
  }

  airport_sim.simulate(object_pointers);

  unsigned int landings = 0;
  unsigned int departures = 0;

  for (auto& o : objects) {
    landings += o.state_.landings_;
    departures += o.state_.departures_;
  }

  std::cout << departures << " total departures" << std::endl;
  std::cout << landings << " total landings" << std::endl;

  return 0;
}
<commit_msg>corrected the arrival event where new events were being generated without any increment in time<commit_after>// An implementation of Fujimoto's airport model
// Ported from the ROSS airport model (https://github.com/carothersc/ROSS/blob/master/ross/models/airport)
// Author: Eric Carver (carverer@mail.uc.edu)

#include <vector>
#include <memory>
#include <random>

#include "warped.hpp"
#include "airport.hpp"

#include "MLCG.h"
#include "NegExp.h"

#include "tclap/ValueArg.h"

WARPED_REGISTER_POLYMORPHIC_SERIALIZABLE_CLASS(AirportEvent)

std::vector<std::shared_ptr<warped::Event> > Airport::createInitialEvents()
{
  std::vector<std::shared_ptr<warped::Event> > events;

  NegativeExpntl depart_expo((double)this->depart_mean_, this->rng_.get());

  for (unsigned int i = 0; i < this->num_planes_; i++) {
    events.emplace_back(new AirportEvent {this->name_, DEPARTURE,
                                            (unsigned int)depart_expo()});
  }

  return events;
}

inline std::string Airport::object_name(const unsigned int object_index)
{
  return std::string("Object ") + std::to_string(object_index);
}

std::vector<std::shared_ptr<warped::Event> > Airport::receiveEvent(const warped::Event& event)
{
  std::vector<std::shared_ptr<warped::Event> > response_events;
  auto received_event = static_cast<const AirportEvent&>(event);

  NegativeExpntl depart_expo((double)this->depart_mean_, this->rng_.get());
  NegativeExpntl land_expo((double)this->land_mean_, this->rng_.get());

  // std::uniform_int_distribution<unsigned int> rand_direction(0,3);
  std::uniform_int_distribution<unsigned int> rand_airport(0,this->num_airports_-1);

  switch ( received_event.type_ ) {
  case DEPARTURE:
    {
      this->state_.planes_grounded_--;
      this->state_.planes_flying_++;
      this->state_.departures_++;
      // Schedule an arrival at a random airport
      unsigned int landing_time = received_event.ts_ + (unsigned int)land_expo();
      // direction_t direction = (direction_t) rand_direction(this->rng_engine_);
      unsigned int destination_index = rand_airport(this->rng_engine_);
      response_events.emplace_back(new AirportEvent {Airport::object_name(destination_index),
                                                            ARRIVAL, landing_time });
      break;
    }
  case ARRIVAL:
    {
      // Schedule a landing
      response_events.emplace_back(new AirportEvent { this->name_, LANDING, received_event.ts_+1 });
      break;
    }
  case LANDING:
    {
      this->state_.landings_++;
      this->state_.planes_flying_--;
      this->state_.planes_grounded_++;
      // Schedule a departure
      response_events.emplace_back(new AirportEvent { this->name_, DEPARTURE,
                                            received_event.ts_ + (unsigned int)depart_expo() });
      break;
    }
  }
  return response_events;
}

int main(int argc, const char** argv)
{
  unsigned int num_airports = 1024;
  unsigned int mean_ground_time = 10;
  unsigned int mean_flight_time = 30;
  unsigned int num_planes = 1;

  TCLAP::ValueArg<unsigned int> num_airports_arg("n", "num-airports", "Number of airports",
                                                 false, num_airports, "unsigned int");
  TCLAP::ValueArg<unsigned int> mean_ground_time_arg("g", "ground-time", "Mean time of planes waiting to depart",
                                                     false, mean_ground_time, "unsigned int");
  TCLAP::ValueArg<unsigned int> mean_flight_time_arg("f", "flight-time", "Mean flight time",
                                                     false, mean_flight_time, "unsigned int");
  TCLAP::ValueArg<unsigned int> num_planes_arg("p", "num-planes", "Number of planes per airport",
                                               false, num_planes, "unsigned int");

  std::vector<TCLAP::Arg*> args = {&num_airports_arg, &mean_ground_time_arg, &mean_flight_time_arg,
                                   &num_planes_arg};

  warped::Simulation airport_sim {"Airport Simulation", argc, argv, args};

  num_airports = num_airports_arg.getValue();
  mean_ground_time = mean_ground_time_arg.getValue();
  mean_flight_time = mean_flight_time_arg.getValue();
  num_planes = num_planes_arg.getValue();

  std::vector<Airport> objects;

  for (unsigned int i = 0; i < num_airports; i++) {
    std::string name = Airport::object_name(i);
    objects.emplace_back(name, num_airports, num_planes, mean_flight_time, mean_ground_time, i);
  }

  std::vector<warped::SimulationObject*> object_pointers;
  for (auto& o : objects) {
    object_pointers.push_back(&o);
  }

  airport_sim.simulate(object_pointers);

  unsigned int landings = 0;
  unsigned int departures = 0;

  for (auto& o : objects) {
    landings += o.state_.landings_;
    departures += o.state_.departures_;
  }

  std::cout << departures << " total departures" << std::endl;
  std::cout << landings << " total landings" << std::endl;

  return 0;
}
<|endoftext|>