summaryrefslogtreecommitdiff
path: root/matlab/src/IceMatlab/Util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'matlab/src/IceMatlab/Util.cpp')
-rw-r--r--matlab/src/IceMatlab/Util.cpp648
1 files changed, 648 insertions, 0 deletions
diff --git a/matlab/src/IceMatlab/Util.cpp b/matlab/src/IceMatlab/Util.cpp
new file mode 100644
index 00000000000..d4c15b7255e
--- /dev/null
+++ b/matlab/src/IceMatlab/Util.cpp
@@ -0,0 +1,648 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <Ice/LocalException.h>
+#include <iostream>
+#include <string>
+#include <locale>
+#include <codecvt>
+#include "icematlab.h"
+#include "Util.h"
+
+using namespace std;
+
+namespace
+{
+
+string
+replace(string s, string patt, string val)
+{
+ string r = s;
+ string::size_type pos = r.find(patt);
+ while(pos != string::npos)
+ {
+ r.replace(pos, patt.size(), val);
+ pos += val.size();
+ pos = r.find(patt, pos);
+ }
+ return r;
+}
+
+void
+getMajorMinor(mxArray* p, Ice::Byte& major, Ice::Byte& minor)
+{
+ mxArray* maj = mxGetProperty(p, 0, "major");
+ assert(maj);
+ if(!mxIsScalar(maj))
+ {
+ throw std::invalid_argument("major is not a scalar");
+ }
+ major = static_cast<Ice::Byte>(mxGetScalar(maj));
+ mxArray* min = mxGetProperty(p, 0, "minor");
+ assert(min);
+ if(!mxIsScalar(min))
+ {
+ throw std::invalid_argument("minor is not a scalar");
+ }
+ minor = static_cast<Ice::Byte>(mxGetScalar(min));
+}
+
+}
+
+mxArray*
+IceMatlab::createStringFromUTF8(const string& s)
+{
+#ifdef _MSC_VER
+ //
+ // Workaround for Visual Studio bug that causes a link error when using char16_t.
+ //
+ wstring utf16 = wstring_convert<codecvt_utf8_utf16<wchar_t>, wchar_t>{}.from_bytes(s.data());
+#else
+ u16string utf16 = wstring_convert<codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(s.data());
+#endif
+ mwSize dims[2] = { 1, utf16.size() };
+ mxArray* r = mxCreateCharArray(2, dims);
+ mxChar* buf = mxGetChars(r);
+ int i = 0;
+#ifdef _MSC_VER
+ for(wchar_t c : utf16)
+#else
+ for(char16_t c : utf16)
+#endif
+ {
+ buf[i++] = static_cast<mxChar>(c);
+ }
+ return r;
+}
+
+string
+IceMatlab::getStringFromUTF16(mxArray* p)
+{
+ char* s = mxArrayToUTF8String(p);
+ if(!s)
+ {
+ throw std::invalid_argument("value is not a char array");
+ }
+ string str(s);
+ mxFree(s);
+ return str;
+}
+
+mxArray*
+IceMatlab::createEmpty()
+{
+ return mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
+}
+
+mxArray*
+IceMatlab::createBool(bool v)
+{
+ mxArray* r = mxCreateNumericMatrix(1, 1, mxLOGICAL_CLASS, mxREAL);
+ bool* p = reinterpret_cast<bool*>(mxGetPr(r));
+ *p = v;
+ return r;
+}
+
+mxArray*
+IceMatlab::createByte(Ice::Byte v)
+{
+ mxArray* r = mxCreateNumericMatrix(1, 1, mxUINT8_CLASS, mxREAL);
+ Ice::Byte* p = reinterpret_cast<Ice::Byte*>(mxGetPr(r));
+ *p = v;
+ return r;
+}
+
+mxArray*
+IceMatlab::createShort(short v)
+{
+ mxArray* r = mxCreateNumericMatrix(1, 1, mxINT16_CLASS, mxREAL);
+ short* p = reinterpret_cast<short*>(mxGetPr(r));
+ *p = v;
+ return r;
+}
+
+mxArray*
+IceMatlab::createInt(int v)
+{
+ mxArray* r = mxCreateNumericMatrix(1, 1, mxINT32_CLASS, mxREAL);
+ int* p = reinterpret_cast<int*>(mxGetPr(r));
+ *p = v;
+ return r;
+}
+
+mxArray*
+IceMatlab::createLong(long long v)
+{
+ mxArray* r = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
+ long long* p = reinterpret_cast<long long*>(mxGetPr(r));
+ *p = v;
+ return r;
+}
+
+mxArray*
+IceMatlab::createFloat(float v)
+{
+ mxArray* r = mxCreateNumericMatrix(1, 1, mxSINGLE_CLASS, mxREAL);
+ float* p = reinterpret_cast<float*>(mxGetPr(r));
+ *p = v;
+ return r;
+}
+
+mxArray*
+IceMatlab::createDouble(double v)
+{
+ mxArray* r = mxCreateNumericMatrix(1, 1, mxDOUBLE_CLASS, mxREAL);
+ double* p = reinterpret_cast<double*>(mxGetPr(r));
+ *p = v;
+ return r;
+}
+
+mxArray*
+IceMatlab::createEnumerator(const string& type, int v)
+{
+ string func = type + ".ice_getValue";
+ mxArray* param = createInt(v);
+ mxArray* r;
+ mexCallMATLAB(1, &r, 1, &param, func.c_str());
+ mxFree(param);
+ return r;
+}
+
+int
+IceMatlab::getEnumerator(mxArray* p, const string& type)
+{
+ if(!mxIsClass(p, type.c_str()))
+ {
+ throw invalid_argument("expected enumerator of type " + type);
+ }
+ return static_cast<int>(mxGetScalar(p));
+}
+
+mxArray*
+IceMatlab::createIdentity(const Ice::Identity& id)
+{
+ mxArray* params[2];
+ params[0] = createStringFromUTF8(id.name);
+ params[1] = createStringFromUTF8(id.category);
+ mxArray* r;
+ mexCallMATLAB(1, &r, 2, params, "Ice.Identity");
+ return r;
+}
+
+void
+IceMatlab::getIdentity(mxArray* p, Ice::Identity& id)
+{
+ if(!mxIsClass(p, "Ice.Identity"))
+ {
+ throw std::invalid_argument("argument is not Ice.Identity");
+ }
+ mxArray* name = mxGetProperty(p, 0, "name");
+ assert(name);
+ id.name = getStringFromUTF16(name);
+ mxArray* category = mxGetProperty(p, 0, "category");
+ assert(category);
+ id.category = getStringFromUTF16(category);
+}
+
+mxArray*
+IceMatlab::createStringMap(const map<string, string>& m)
+{
+ mxArray* r;
+ if(m.empty())
+ {
+ mexCallMATLAB(1, &r, 0, 0, "containers.Map");
+ }
+ else
+ {
+ mwSize dims[2] = {1, 0};
+ dims[1] = m.size();
+ mxArray* keys = mxCreateCellArray(2, dims);
+ mxArray* values = mxCreateCellArray(2, dims);
+ int idx = 0;
+ for(map<string, string>::const_iterator p = m.begin(); p != m.end(); ++p)
+ {
+ mxSetCell(keys, idx, createStringFromUTF8(p->first));
+ mxSetCell(values, idx, createStringFromUTF8(p->second));
+ idx++;
+ }
+ mxArray* params[2];
+ params[0] = keys;
+ params[1] = values;
+ mexCallMATLAB(1, &r, 2, params, "containers.Map");
+ }
+ return r;
+}
+
+void
+IceMatlab::getStringMap(mxArray* p, map<string, string>& m)
+{
+ if(mxIsEmpty(p))
+ {
+ m.clear();
+ }
+ else if(!mxIsClass(p, "containers.Map"))
+ {
+ throw std::invalid_argument("argument is not a containers.Map");
+ }
+ else
+ {
+ mxArray* params[1];
+ params[0] = p;
+ mxArray* keys;
+ mexCallMATLAB(1, &keys, 1, params, "keys");
+ mxArray* values;
+ mexCallMATLAB(1, &values, 1, params, "values");
+ assert(mxGetM(keys) == 1 && mxGetM(values) == 1);
+ assert(mxGetN(keys) == mxGetN(values));
+ const size_t n = mxGetN(keys);
+ try
+ {
+ for(size_t i = 0; i < n; ++i)
+ {
+ string k = getStringFromUTF16(mxGetCell(keys, i));
+ string v = getStringFromUTF16(mxGetCell(values, i));
+ m[k] = v;
+ }
+ mxDestroyArray(keys);
+ mxDestroyArray(values);
+ }
+ catch(...)
+ {
+ mxDestroyArray(keys);
+ mxDestroyArray(values);
+ throw;
+ }
+ }
+}
+
+mxArray*
+IceMatlab::createEncodingVersion(const Ice::EncodingVersion& v)
+{
+ mxArray* params[2];
+ params[0] = mxCreateDoubleScalar(v.major);
+ params[1] = mxCreateDoubleScalar(v.minor);
+ mxArray* r;
+ mexCallMATLAB(1, &r, 2, params, "Ice.EncodingVersion");
+ return r;
+}
+
+void
+IceMatlab::getEncodingVersion(mxArray* p, Ice::EncodingVersion& v)
+{
+ if(!mxIsClass(p, "Ice.EncodingVersion"))
+ {
+ throw std::invalid_argument("argument is not Ice.EncodingVersion");
+ }
+ getMajorMinor(p, v.major, v.minor);
+}
+
+mxArray*
+IceMatlab::createProtocolVersion(const Ice::ProtocolVersion& v)
+{
+ mxArray* params[2];
+ params[0] = mxCreateDoubleScalar(v.major);
+ params[1] = mxCreateDoubleScalar(v.minor);
+ mxArray* r;
+ mexCallMATLAB(1, &r, 2, params, "Ice.ProtocolVersion");
+ return r;
+}
+
+void
+IceMatlab::getProtocolVersion(mxArray* p, Ice::ProtocolVersion& v)
+{
+ if(!mxIsClass(p, "Ice.ProtocolVersion"))
+ {
+ throw std::invalid_argument("argument is not Ice.ProtocolVersion");
+ }
+ getMajorMinor(p, v.major, v.minor);
+}
+
+mxArray*
+IceMatlab::convertException(const std::exception& exc)
+{
+ mxArray* ex;
+ if(dynamic_cast<const Ice::LocalException*>(&exc))
+ {
+ const Ice::LocalException* iceEx = dynamic_cast<const Ice::LocalException*>(&exc);
+ const string typeId = iceEx->ice_id();
+ //
+ // The exception ID uses single colon separators.
+ //
+ string id = typeId.substr(2); // Remove leading "::" from type ID
+ id = replace(id, "::", ":");
+
+ string cls = typeId.substr(2); // Remove leading "::" from type ID
+ cls = replace(cls, "::", ".");
+
+ mxArray* params[10];
+ params[0] = createStringFromUTF8(id);
+ int idx = 2;
+ string msg = typeId; // Use the type ID as the default exception message
+
+ try
+ {
+ iceEx->ice_throw();
+ }
+ catch(const Ice::InitializationException& e)
+ {
+ msg = e.reason;
+ params[idx++] = createStringFromUTF8(e.reason);
+ }
+ catch(const Ice::PluginInitializationException& e)
+ {
+ msg = e.reason;
+ params[idx++] = createStringFromUTF8(e.reason);
+ }
+ catch(const Ice::AlreadyRegisteredException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.kindOfObject);
+ params[idx++] = createStringFromUTF8(e.id);
+ }
+ catch(const Ice::NotRegisteredException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.kindOfObject);
+ params[idx++] = createStringFromUTF8(e.id);
+ }
+ catch(const Ice::TwowayOnlyException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.operation);
+ }
+ catch(const Ice::UnknownException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.unknown);
+ }
+ catch(const Ice::ObjectAdapterDeactivatedException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.name);
+ }
+ catch(const Ice::ObjectAdapterIdInUseException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.id);
+ }
+ catch(const Ice::NoEndpointException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.proxy);
+ }
+ catch(const Ice::EndpointParseException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.str);
+ }
+ catch(const Ice::EndpointSelectionTypeParseException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.str);
+ }
+ catch(const Ice::VersionParseException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.str);
+ }
+ catch(const Ice::IdentityParseException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.str);
+ }
+ catch(const Ice::ProxyParseException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.str);
+ }
+ catch(const Ice::IllegalIdentityException& e)
+ {
+ params[idx++] = createIdentity(e.id);
+ }
+ catch(const Ice::RequestFailedException& e)
+ {
+ params[idx++] = createIdentity(e.id);
+ params[idx++] = createStringFromUTF8(e.facet);
+ params[idx++] = createStringFromUTF8(e.operation);
+ }
+ catch(const Ice::FileException& e)
+ {
+ params[idx++] = mxCreateDoubleScalar(e.error);
+ params[idx++] = createStringFromUTF8(e.path);
+ }
+ catch(const Ice::SyscallException& e) // This must appear after all subclasses of SyscallException.
+ {
+ params[idx++] = mxCreateDoubleScalar(e.error);
+ }
+ catch(const Ice::DNSException& e)
+ {
+ params[idx++] = mxCreateDoubleScalar(e.error);
+ params[idx++] = createStringFromUTF8(e.host);
+ }
+ catch(const Ice::UnsupportedProtocolException& e)
+ {
+ params[idx++] = createProtocolVersion(e.bad);
+ params[idx++] = createProtocolVersion(e.supported);
+ }
+ catch(const Ice::UnsupportedEncodingException& e)
+ {
+ params[idx++] = createEncodingVersion(e.bad);
+ params[idx++] = createEncodingVersion(e.supported);
+ }
+ catch(const Ice::ConnectionManuallyClosedException& e)
+ {
+ params[idx++] = mxCreateLogicalScalar(e.graceful ? 1 : 0);
+ }
+ catch(const Ice::NoValueFactoryException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.reason);
+ params[idx++] = createStringFromUTF8(e.type);
+ }
+ catch(const Ice::UnexpectedObjectException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.reason);
+ params[idx++] = createStringFromUTF8(e.type);
+ params[idx++] = createStringFromUTF8(e.expectedType);
+ }
+ catch(const Ice::ProtocolException& e) // This must appear after all subclasses of ProtocolException.
+ {
+ params[idx++] = createStringFromUTF8(e.reason);
+ }
+ catch(const Ice::FeatureNotSupportedException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.unsupportedFeature);
+ }
+ catch(const Ice::SecurityException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.reason);
+ }
+ catch(const Ice::IllegalServantException& e)
+ {
+ params[idx++] = createStringFromUTF8(e.reason);
+ }
+ catch(const Ice::LocalException&)
+ {
+ //
+ // Nothing to do.
+ //
+ }
+
+ //
+ // NOTE: Matlab interprets the msg argument as an sprintf format string. It will complain if it
+ // finds invalid syntax.
+ //
+ params[1] = createStringFromUTF8(msg);
+ mexCallMATLAB(1, &ex, idx, params, cls.c_str());
+ }
+ else
+ {
+ mxArray* params[2];
+ params[0] = createStringFromUTF8("Ice:CppException");
+ params[1] = createStringFromUTF8(exc.what());
+ mexCallMATLAB(1, &ex, 2, params, "MException");
+ }
+ return ex;
+}
+
+static const char* resultFields[] = {"exception", "result"};
+
+mxArray*
+IceMatlab::createResultValue(mxArray* result)
+{
+ mwSize dims[2] = {1, 1};
+ mxArray* r = mxCreateStructArray(2, dims, 2, resultFields);
+ mxSetFieldByNumber(r, 0, 1, result);
+ return r;
+}
+
+mxArray*
+IceMatlab::createResultException(mxArray* ex)
+{
+ mwSize dims[2] = {1, 1};
+ mxArray* r = mxCreateStructArray(2, dims, 2, resultFields);
+ mxSetFieldByNumber(r, 0, 0, ex);
+ return r;
+}
+
+mxArray*
+IceMatlab::createStringList(const vector<string>& v)
+{
+ mxArray* r = mxCreateCellMatrix(1, v.size());
+ mwIndex i = 0;
+ for(vector<string>::const_iterator p = v.begin(); p != v.end(); ++p, ++i)
+ {
+ mxSetCell(r, i, createStringFromUTF8(*p));
+ }
+ return r;
+}
+
+void
+IceMatlab::getStringList(mxArray* m, vector<string>& v)
+{
+ if(!mxIsCell(m))
+ {
+ throw std::invalid_argument("argument is not a cell array");
+ }
+ if(mxGetM(m) > 1)
+ {
+ throw std::invalid_argument("invalid dimension in cell array");
+ }
+ size_t n = mxGetN(m);
+ v.clear();
+ for(size_t i = 0; i < n; ++i)
+ {
+ mxArray* c = mxGetCell(m, i);
+ v.push_back(getStringFromUTF16(c));
+ }
+}
+
+#if 0
+void*
+IceMatlab::getImpl(mxArray* obj, const std::string& className)
+{
+ void* p = 0;
+ if(!mxIsEmpty(obj))
+ {
+ if(!mxIsClass(obj, className.c_str()))
+ {
+ throw std::invalid_argument("expecting object of type " + className);
+ }
+ mxArray* implProp = mxGetProperty(obj, 0, "impl");
+ assert(implProp);
+ mxArray* value = mxGetProperty(implProp, 0, "value");
+ assert(value);
+ p = mxGetData(value);
+ }
+ return p;
+}
+#endif
+
+namespace
+{
+
+string
+lookupKwd(const string& name)
+{
+ //
+ // Keyword list. *Must* be kept in alphabetical order.
+ //
+ // This list must match the one in slice2matlab.
+ //
+ static const string keywordList[] =
+ {
+ "break", "case", "catch", "classdef", "continue", "else", "elseif", "end", "for", "function", "global",
+ "if", "otherwise", "parfor", "persistent", "return", "spmd", "switch", "try", "while"
+ };
+ bool found = binary_search(&keywordList[0],
+ &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
+ name);
+ return found ? "slice_" + name : name;
+}
+
+//
+// Split a scoped name into its components and return the components as a list of (unscoped) identifiers.
+//
+vector<string>
+splitScopedName(const string& scoped)
+{
+ assert(scoped[0] == ':');
+ vector<string> ids;
+ string::size_type next = 0;
+ string::size_type pos;
+ while((pos = scoped.find("::", next)) != string::npos)
+ {
+ pos += 2;
+ if(pos != scoped.size())
+ {
+ string::size_type endpos = scoped.find("::", pos);
+ if(endpos != string::npos)
+ {
+ ids.push_back(scoped.substr(pos, endpos - pos));
+ }
+ }
+ next = pos;
+ }
+ if(next != scoped.size())
+ {
+ ids.push_back(scoped.substr(next));
+ }
+ else
+ {
+ ids.push_back("");
+ }
+
+ return ids;
+}
+
+}
+
+string
+IceMatlab::idToClass(const string& id)
+{
+ vector<string> ids = splitScopedName(id);
+ transform(ids.begin(), ids.end(), ids.begin(), ptr_fun(lookupKwd));
+ stringstream result;
+ for(vector<string>::const_iterator i = ids.begin(); i != ids.end(); ++i)
+ {
+ if(i != ids.begin())
+ {
+ result << ".";
+ }
+ result << *i;
+ }
+ return result.str();
+}