Convert Multidimensional List to Blob - list

I have a list that I'd like to convert to a Blob. I first tried converting the list to a long string, like so:
List<Contact_Deals__c> result = ...SOQL Query...
String strSobjects = null;
for(integer i=0;i<result.size();i++){
If(strSobjects == null){
strSobjects = String.valueOf(result2[i]);
}
Else{
strSobjects = strSobjects + ','+String.valueOf(result[i]);
}
}
and then converted the string into a blob, like so:
Document resultD = new Document();
resultD.Name = 'ResultCSV';
Blob myBlob = Blob.valueof(strSobjects);
resultD.body = myBlob;
This worked fine for a 2 dimensional List, but now my list has gotten deep. Real deep. Should I try writing a recursive call to convert it all into one large string (it's JSON format, so it can be parsed later) or is there a better way to convert this list to a blob?
EDIT: This will have to work in SF apex, which is a bit more limited. It seems that the only way to write to a blob is via a string (is this obvious? Blobs are new to me): https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_blob.htm
Thanks all!
Zac

Related

How to convert fetched string data to character array?

I am doing this IoT based project on displaying data to connected display( I've used the MAX7219 module, in this case) with the help of nodeMCU. The idea here is that the string which is stored in my firebase database is to be display on the led display.
I've had no trouble in getting the value from the database to my nodeMCU but there is this little problem with converting that string to char array since the code i am using( Max72xx_Message_serial, which was available as an example with the max72xx library) has used char array but i can only fetch the stored data in string format. I've modified that code so as to connect with firebase but the main issue is to convert the string fetched from the database to char array.
I tried toCharArray() but it still shows conversion error.
void readfromfirebase(void)
{
static uint8_t putIndex = 0;
int n=1;
while (Firebase.available())
{
newMessage[putIndex] = (char)Firebase.getString("Submit Message"); // this line produces the error
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
{
// put in a message separator and end the string
newMessage[putIndex++] = ' ';
newMessage[putIndex] = '\0';
// restart the index for next filling spree and flag we have a message waiting
putIndex = 0;
newMessageAvailable = true;
}
else if (newMessage[putIndex] != '\r')
// Just save the next char in next location
{putIndex++;}
n++;
}
}
I think you are confusing the types
getString returns a String object wich can be converted to a char[] using the methods of the String class.
I assume your newMessage is of type char[] or char*.
Then I would advise you to go for the String.c_str() method, because it returns a C style null-terminated string, meaning a char*.
See https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/c_str/ for reference.
It also sets the last character of the string to 0. So methods like strlen, strcmp etc will work.
! be carefull not to modify the array returned by c_str(), if you want to modify it you chould copy the char[] or use string.toCharArray(buf, len).
Your Code might then look like the following.
String msg = Firebase.getString("Submit Message");
newMessage = msg.c_str();
// rest of your code
If newMessage is a buffer storing multiple messages, meaning char* newMessage[3].
String msg = Firebase.getString("Submit Message");
newMessage[putIndex] = msg.c_str();
// rest of your code
Be careful, because you are storing multiple characters in an array, so use strcmp to compare these arrays!
If you are new to C I would recommend reading.
https://www.cprogramming.com/tutorial/c/lesson9.html
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/ (as pointed out by #gre_gor)

Qt with GDIplus can't read the exif value of a jpeg image (id, type, length working)

i want to read the exif data of jpeg images with a windows application in qt.
I uses this function: Image.GetAllPropertyItems class
i could load all property items and display it in a textBrowser for testing:
PropertyItem* pAllItems = (PropertyItem*)malloc(totalBufferSize);
image->GetAllPropertyItems(totalBufferSize, numProperties, pAllItems);
... loop ...
ui->textBrowser->append(QString::number(pAllItems[xxx].id));
ui->textBrowser->append(QString::number(pAllItems[xxx].type));
ui->textBrowser->append(QString::number(pAllItems[xxx].length));
So i could see the id, type and length of my exif data and thats working great.
But i can't read the value of PropertyItem. The datatype is different and could be checked with the type.
I want to read the time of the exif data (id == 0x9003), the type is 2 (have a look) and the length is 20.
Microsoft writes:
Specifies that Value is a null-terminated ASCII string. If you set the type data member to ASCII type, you should set the Len property to the length of the string including the null terminator. For example, the string "Hello" would have a length of 6.
I tried so many ways like this:
QByteArray propItem = pAllItems[xxx].value;
but i dont know what i do wrong. Qt didnt compile it:
C2240: "Initalisation": 'void *' cannot convert to 'QByteArray'
I think i know what the compiler means, but i didnt have any idea to solve it. I would be happy if somebody could help me. Thanks.
When the type is a string, you should reinterpret the value to mean a pointer to a null-terminated ASCII string, precisely as the documentation you cited states:
for (auto i = 0; i < numProperties; ++i) {
auto const & property = pAllItems[i];
ui->textBrowser->append(QString::number(property.id));
ui->textBrowser->append(QString::number(property.type));
ui->textBrowser->append(QString::number(property.length));
auto valueStr{QStringLiteral("value of an unhandled type")};
switch (property.type) {
case PropertyTagTypeASCII:
valueStr = QString::fromLatin1(reinterpret_cast<const char*>(property.value),
property.length);
break;
case PropertyTagTypeByte:
valueStr = QString::number(*reinterpret_cast<qint8*>(property.value));
break;
// etc.
default:
break;
}
ui->textBrowser->append(valueStr);
}

using SerializeJSON from cfm how do I just output the Data portion?

SerializeJSON(cfquery)
creates a JSON that looks like this:
"COLUMNS":["POINT","LOCATION"],"DATA":[["41.322365,-71.679251","Ashaway...
How do I output the JSON Data only?
ie...
[["41.322365,-71.679251","Ashaway...
I don't think there is a convenient way to do this unless you can modify the code that is serializing the query; otherwise you are going to need to use some string manipulation. However, assuming you have access to the CF code that is serializing the query, this is a little unorthodox but does work:
<!---Serialize and Deserialize the cfquery to shortcut obtaining a Structure--->
<cfset queryAsStruct = DeSerializeJSON(SerializeJSON(cfquery))>
<!---Now serialize the data key of the struct--->
<cfset dataJSON = SerializeJSON(queryAsStruct.data)>
As I said, not the the prettiest maybe...but seems to get it done. There may be a more convenient/better practice way to convert cfquery to a struct, but this one resulted in fewest lines of code for me.
edit: Just thought to explain why this works. The JSON string when being deserialized by ColdFusion is not detected as a query object anymore, just a plain struct so the "DATA" key is created and populated. THis way you can access it as a key of the structure. When cfquery is a query object, while still a "struct" type of object it has special considerations that prevent you from accessing the data key directly (to my knowledge).
Sample Query
q = QueryNew( '' );
point = [ "41.322365,-71.679251" ];
location = [ "Ashaway" ];
QueryAddColumn( q,"point",point );
QueryAddColumn( q,"location",location );
CF10+ (Using "for row in query" syntax)
data = [];
for( row in q ) {
// append array of two values
ArrayAppend( data, [ row.point, row.location ] );
}
data = SerializeJSON( data );
CF9.01
data = [];
for( row=1; row <= q.recordcount; row++ ) {
rowdata = [];
ArrayAppend( rowdata,q.point[ row ] );
ArrayAppend( rowdata,q.location[ row ] );
ArrayAppend( data,rowdata );
}
data = SerializeJSON( data );
Result:
[["41.322365,-71.679251","Ashaway"]]
I came across this same problem, I think. I'm sending a query to a browser through an ajax call and need to loop through the JSON string in order to display the info. ColdFusion's serializeJSON method outputs a 1-D array called COLUMNS and a 2-D array called DATA.
Let's assume your JSON string has come back through and ajax call into the "response" variable. So we have response.COLUMNS and response.DATA.
By using the column name and finding its index, you can pinpoint its data for a given row. From there you do whatever you need.
var point;
var location;
for(i=0; i<response.COLUMNS.length; i++){
point=response.DATA[i][response.COLUMNS.indexOf('POINT')];
location=response.DATA[i][response.COLUMNS.indexOf('LOCATION')];
}

insert utf-8 data in openldap with c api

What is the correct method to insert utf-8 data in an openldap database? I have data in a std::wstring which utf-8 encoded with:
std::wstring converted = boost::locale::conv::to_utf<wchar_t>(line, "Latin1");
When the string needs to added tot an ldapMod structure, i use this fuction:
std::string str8(const std::wstring& s) {
return boost::locale::conv::utf_to_utf<char>(s);
}
to convert from wstring to string. This is used in my function to create an LDAPMod:
LDAPMod ** y::ldap::server::createMods(dataset& values) {
LDAPMod ** mods = new LDAPMod*[values.elms() + 1];
mods[values.elms()] = NULL;
for(int i = 0; i < values.elms(); i++) {
mods[i] = new LDAPMod;
data & d = values.get(i);
switch (d.getType()) {
case NEW: mods[i]->mod_op = 0; break;
case ADD: mods[i]->mod_op = LDAP_MOD_ADD; break;
case MODIFY: mods[i]->mod_op = LDAP_MOD_REPLACE; break;
case DELETE: mods[i]->mod_op = LDAP_MOD_DELETE; break;
default: assert(false);
}
std::string type = str8(d.getValue(L"type"));
mods[i]->mod_type = new char[type.size() + 1];
std::copy(type.begin(), type.end(), mods[i]->mod_type);
mods[i]->mod_type[type.size()] = '\0';
mods[i]->mod_vals.modv_strvals = new char*[d.elms(L"values") + 1];
for(int j = 0; j < d.elms(L"values"); j++) {
std::string value = str8(d.getValue(L"values", j));
mods[i]->mod_vals.modv_strvals[j] = new char[value.size() + 1];
std::copy(value.begin(), value.end(), mods[i]->mod_vals.modv_strvals[j]);
mods[i]->mod_vals.modv_strvals[j][value.size()] = '\0';
}
mods[i]->mod_vals.modv_strvals[d.elms(L"values")] = NULL;
}
return mods;
}
The resulting LDAPMod is passed on to ldap_modify_ext_s and works as long as i only use ASCII characters. But if other characters are present in the string I get an ldap operations error.
I've also tried this with the function provided by the ldap library (ldap_x_wcs_to_utf8s) but the result is the same as with the boost conversion.
It's not the conversion itself that is wrong, because if I convert the modifications back to a std::wstring and show it in my program output, the encoding is still correct.
AFAIK openldap supports utf-8 since long, so I wonder if there's something else that must be done before this works?
I've looked into the openldap client/tools examples, but the utf-8 functions provided by the library are never used in there.
Update:
I noticed I can insert utf-8 characters like é into ldap with Apache Directory Studio. I can retrieve these values from ldap in my c++ program. But if I insert the same character again, without changing anything to that string, I get the ldap operations error again.
It turns out that my code was not wrong at all. My modifications tried to store the full name in the 'displayName' field as well as in 'gecos'. But apparently 'gecos' cannot handle utf8 data.
We don't actually use gecos anymore. The value was only present because of some software we used years ago, so I removed it from the directory.
What made it hard to find was that even though the loglevel was set to 'parse', this error was still not in the logs.
Because libldap can be such a hard nut to crack, I'll include a link to the complete code of the project i'm working on. It might serve as a starting point for other programmers. (Most of the code in tutorials I have found is outdated.)
https://github.com/yvanvds/yATools/tree/master/libadmintools/ldap

CFile writes some garbage value

Im wriitng some data in File.But it doesnot write this properly.
Code:
CString sFileName = "C:\\Test.txt";
CFile gpFile;
CString testarr[10] = {"Tom","Ger","FER","DER","SIL","REM","FWE","DWR","SFE","RPOP"};
if (!gpFile.Open( sFileName,CFile::modeCreate|CFile::modeWrite))
{
AfxMessageBox( sFileName + (CString)" - File Write Error");
return;
}
else
{
gpFile.Write(testarr,10);
}
AfxMessageBox("Completed");
gpFile.Close();
It shows the file as
That's probably because you're using CFile incorrectly. The first parameter to CFile::Write should be a buffer whose bytes you'd like to write to the file. However, testarr is more like a "buffer of buffers", since each element of testarr is a string, and a string is itself a sequence of bytes.
What you would need to do instead is either concatenate the elements of testarr, and then call CFile::Write. Or (probably more practical), iterate over testarr printing each string one at a time, e.g. for your particular example, the following should do what you're looking for:
for(int i = 0; i < 10; ++i)
{
gpFile.Write(testarr[i], strlen(testarr[i]));
}
There may be some built-in way to accomplish this, but I'm not really familiar with MFC, so I won't be much help there.