No problem, you are welcome. Just let me know if this works for you.
On Fri, Feb 7, 2014 at 11:40 AM, Jeremie Passerin <[email protected]>wrote: > 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. >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> >>>>> >>>>> >>>> >>>> >>> >> >> >> -- >> > > --

