Thanks a ton Alok !
On 5 February 2014 14:35, Alok Gandhi <[email protected]> wrote: > 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 <[email protected]>wrote: > >> Could definitely use an example, >> thanks Alok. >> >> ;-) >> >> >> On 4 February 2014 13:52, Alok Gandhi <[email protected]> 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 <[email protected]> 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 <[email protected]>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:* [email protected] [mailto: >>>> [email protected]] *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 <[email protected]> >>>> 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 <[email protected]> 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. >>>> >>>> >>>> >>>> >>>> >>>> -- >>>> >>>> >>>> >>> >>> >> > > > -- >

