Ok I was able to finally lay my hands on this one.

Follwing is a complete solution for : Write from Python (string or a json
dump string), read from C++ (on a UserDataBlob)

First of all, when writing with python you cannot simply use blob.value =
"my string" as this is not written as 32 Byte Array which C++ can
recognise. So you have to convert your data into a 32 Byte Array and then
write it. Here's how to do it

-----------------------------------------------------
----- Python Code for writing the data to blob-------
-----------------------------------------------------
# python standard array module so that we can store C/ C ++ types
import array

*stringToStore  = "Hello World!, 1234 !@#$"*

# We need to convert this string to unsigned byte array
byteArray = array.array('B', stringToStore)

# As we have to convert this from unsigned byte (8 bit) to unsigned integer
(32 bit),
# we need to add some null (0) bytes at the end so the total elements in
this array
# are a multiple of 4. We will also have to know how many null bytes we are
adding

nbNullBytes = 0
# Padding the end of byteArray with null bytes
while len(byteArray) % 4 != 0:
    byteArray.append(0)
    nbNullBytes += 1

# Now we convert the array to unsigned integer array (32 bit)
intArray = array.array('I', byteArray.tostring())

# And we also add the number of null bytes added at end as the first element
# of this array, why ?? becuase a C++ reader function blob.GetValue()
# expects that
intArray.insert(0, nbNullBytes)


# Ok we are done, now we can conviniently set this data on the blob

# Create a blob
blob = Application.ActiveSceneRoot.AddProperty('UserDataBlob', False,
'data')

# And add the data as 32 bit array
blob.Array32 = intArray

# That's it we are done
# Note - If you want to read this from python, then do not use data =
blob.Value
# as it will not work, you will have to do exactly the inverse of what we
did
# above and read it into python.

-------------------------- end of python
code------------------------------------


Now for C++ code,

What you were doing initially was fine, the only trick is to
cast in the proper way.

Here is the relevant part for your C++ code

-------------------------------------------------------
----------- C++ code to read the data------------------
-------------------------------------------------------

// I am copying the same code as was posted in the
// first message on this thread with some modifications

CStatus simplexCPP_Update( CRef& in_ctxt ){

OperatorContext ctxt(in_ctxt);
Application app;
Operator op(ctxt.GetSource());
 UserDataBlob b = ctxt.GetInputValue(0,2,0);

const unsigned char *x = NULL;
unsigned int size = 0;
b.GetValue(x, size);

// Here is the proper and safe casting from const unsigned char* to const
char* (as is needed by CString)
const char* s_ = reinterpret_cast<char*>(const_cast<unsigned char*>(x));

// Now we can easily construct a CString from this const char*
CString data(s_);

// and log it
app.LogMessage(L"Data Read from Blob: " +  data, siVerboseMsg);
 return CStatus::OK;
}

------------ end of C++
code-----------------------------------------------------

That's it! It should work fine. I have already tested it on my side.

Here is a the expalanation of the casting

We have to cast from const unsigned char* to const char*. For this we need
the 'reinterpret_cast' operator.
This operator than cast a pointer from derived type (usigned char*)to
another unrelated derived type  (char*) .
But this operator cannot work with const attribute, so first we have to
remove the constness. To do
this we have to use the 'const_cast'. I did all of this in one line of code
as shown above.

I hope this examples works for other people on the list as well.


PS: There are some things to consider, in your use case scenario:
1. If possible do write the data from C++ (as suggested already in this
post). This
way you don't have to go through the python array module conversion.

2. In your case, since you are converting everything (int, float, string)
to an ASCII string,
what you will get in C++ is the same, a SI CString. You will then have to
deserialize it
into respective data types to use them in your operator. If you use a C++
writer, then
you can simply use a schema as a struct and not to worry about this
conversions.
An excellent example to reading and writing these is available in the docs:
http://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=si_cpp/classXSI_1_1UserDataBlob.html,topicNumber=si_cpp_classXSI_1_1UserDataBlob_html

3. Also I don't see an output port in your operator's update() code.
Something like,
OutputPort outPort = ctxt.GetOutputPort();
outPort.PutValue(0); // just putting a zero value on out port

This might also crash soft, but I guess you removed it while posting.


Cheers !





On Tue, Feb 4, 2014 at 5:17 PM, Jeremie Passerin <gerem....@gmail.com>wrote:

> Could definitely use an example,
> thanks Alok.
>
> ;-)
>
>
> On 4 February 2014 13:52, Alok Gandhi <alok.gandhi2...@gmail.com> wrote:
>
>> You could definitely write through python and read through CPP. You can
>> also read binary / ascii file on disk from CPP using streams if you want.
>>
>> I think your problem lies in reading the value in context of a CPP
>> operator. The way to access data from the input port is where you are
>> having a glitch, at least that's what I think.
>>
>> I am not near a machine right now so I cannot provide you with a specific
>> code. But I will do so later today or tomorrow in case somebody does not
>> answer before that.
>>
>> Sent from my iPhone
>>
>> On Feb 4, 2014, at 14:29, Tyler Fox <tbtt...@gmail.com> wrote:
>>
>> HI there,
>> I'm the Tyler that Jeremie was talking about in the original post.
>>
>> Writing the data generation in c++ is gonna be a really tough sell due to
>> time/knowledge/expertise constraints on this end. It's been a LONG time
>> since I've written any c++, and I'm doing some not easily portable stuff in
>> the python code.
>>
>> Would a possible workaround be to write a custom command that reads a
>> file on disk, builds my class structure using that data, and send that over
>> to my custom operator?
>>
>> Which leads to the question, is an operator's userData saved with the
>> file?
>>
>> ~T.Fox
>>
>>
>>
>>
>>
>> On Tue, Feb 4, 2014 at 10:31 AM, Matt Lind <ml...@carbinestudios.com>wrote:
>>
>>> Write it in CPP.
>>>
>>>
>>>
>>> If your data requirements are small, you can use a userdatablob template
>>> to store basic values to make them language agnostic (mostly).  A template
>>> is essentially a customparamset applied to the object and flagged to be
>>> read by a userdatablob.  Templates also exist for userdatamaps.
>>>
>>>
>>>
>>>
>>>
>>> Matt
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> *From:* softimage-boun...@listproc.autodesk.com [mailto:
>>> softimage-boun...@listproc.autodesk.com] *On Behalf Of *Jeremie Passerin
>>> *Sent:* Tuesday, February 04, 2014 10:28 AM
>>> *To:* softimage
>>> *Subject:* Re: [C++] Reading UserDataBlob as JSON String
>>>
>>>
>>>
>>> Thanks for the inputs guys. This is where I am wrong assuming that
>>> assuming I can write Cpp just like I write Python.
>>>
>>>
>>>
>>> So let me explain you the root of the problem so maybe someone has an
>>> idea how to solve it with another way.
>>>
>>>
>>>
>>> We have a solver in Cpp (for optimization purpose). This solver needs to
>>> be initialized with some values that only need to be computed once. We did
>>> a prototype in Python and it works just fine. The init values is just a
>>> bunch of list of strings, integers and floats. Nothing weird.
>>>
>>> Rather than rewriting this whole initial computation in Cpp, which would
>>> take us a lot of time (and is using some external python libraries), we
>>> though we could just do the init in Python store the result in a datablob
>>> and read this from the Cpp solver.
>>>
>>>
>>>
>>> What would be the best way to ready array of strings, integers and
>>> floats stored somewhere in the scene from a Cpp solver ?
>>>
>>>
>>>
>>> thanks for your help !
>>>
>>>
>>>
>>> Jeremie
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> On 3 February 2014 18:25, Alok Gandhi <alok.gandhi2...@gmail.com> wrote:
>>>
>>> I'd side with exactly what Matt and Oleg are saying, the data stored in
>>> a user data blob through C++ is essentially binary. That might be the cause
>>> of the issue. I wrote some plugin for userdatablob using c++ but I was
>>> writing the data instead of reading it. You can probably do the inverse of
>>> what I did.
>>>
>>>
>>>
>>> Here is the code from my plugin:
>>>
>>>
>>> ----------------------------------------------------------------------------------------------------------
>>>
>>> struct DataForBlob
>>>
>>> {
>>>
>>> const char* blobVal;
>>>
>>> } ;
>>>
>>>
>>>
>>>  DataForBlob blobData; blobData.blobVal =
>>> CString(L"MSVDATA").GetAsciiString(); UserDataBlob blob ;
>>> agentModel.AddProperty( L"UserDataBlob", false, L"msvResource", blob);
>>> blob.PutValue((unsigned char*)&blobData, sizeof(blobData)) ;
>>> blob.SetLock(siLockLevelAll);
>>>
>>>
>>>
>>>
>>> --------------------------------------------------------------------------------------------------------
>>>
>>>
>>>
>>> On Mon, Feb 3, 2014 at 9:15 PM, Oleg Bliznuk <gbo...@gmail.com> wrote:
>>>
>>> casting from char* to CString* is unsafe as you dont know how CString is
>>> implemented. It can be even not null-terminated ( and most likely this is
>>> true as its responsible to hold both wide and non-wide characters ) inside
>>> and in such case the "LogMEssage" internally may call something like
>>> "GetLength() {return m_Length;}" but physically there is only
>>> null-terminated char buffer or whatever JSON stuff can holds. First check
>>> if the "x" is not NULL after GetVall call and then try to create CString
>>> stringObj ( x ) and log it.
>>>
>>>
>>>
>>>
>>>
>>> --
>>>
>>>
>>>
>>
>>
>


--

Reply via email to