c++stringprotocol-buffersactivemq-cpp

Convert 'const char*' to 'const unsigned char*' (Protobuf & ActiveMQ-cpp)


Context

I know this question has been asked a lot, I just cannot find a solution that works for me in the given answers.

I have generated classes by protobuf, I wanted to test out the use of these classes with ActiveMQ-cpp.

Problem

I want to use ByteMessage, but CreateByteMessage() only takes unsigned char* as parameter.

My question is simple : How do I convert an std::string (or const char*) to const unsigned char* ?

Here is the code for sending :

for (int ix = 0; ix < m_numMessages; ++ix)
{
   // Create a CsgNode object from the protobuf class 
   csgBox csgNode;
   csgNode.set_n("box");
   csgNode.set_h(1600.0f);
   csgNode.set_l(1600.0f);
   csgNode.set_w(1600.0f);

   // /!\ PROBLEM OCCURS HERE /!\ 
   // Tries to convert the csgNode to unsigned char array
   std::string csgNodeStr = csgNode.SerializeAsString();
   auto msg = (const unsigned char *)csgNodeStr.c_str();

   // Create a BytesMessage
   constexpr int msgSize = sizeof(msg);
   std::unique_ptr<cms::BytesMessage> message(m_session->createBytesMessage(msg, msgSize));
   // No compile errors, but the message will be wrongly parsed when received (see following code)

   LOG_INFO("Sent message: " << ix << " csgNode: " << csgNode.DebugString());
   m_producer->send(message.get());
}

And here's the code for receiving :

const cms::BytesMessage* msg = dynamic_cast<const cms::BytesMessage*> (message);
const unsigned char* bytes = nullptr;

if (msg != nullptr) {
   bytes = msg->getBodyBytes();
}

CsgNode csgNode;
csgNode.ParseFromArray(bytes, msg->getBodyLength());

LOG_INFO("Received message: " << count << " csgNode: " << csgNode.DebugString());

These codes give the following output :

[INFO] Sent message: 0 csgNode: n: "box"
l: 1600
w: 1600
h: 1600

[INFO] Sent message: 1 csgNode: n: "box"
l: 1600
w: 1600
h: 1600

[INFO] Received message: 1 csgNode: type: "box"
3: 0x00000000

[INFO] Received message: 2 csgNode: type: "box"
3: 0x00000000

The protobuf .proto file which was generated from an architecture of node classe. CsgBox herited from CsgNode. Protobuf handled the inheritance by creating the byte value property that contains the element specific to the child class

message CsgNode {
  string type = 1;
  // decoded as message with one of these types:
  //   message csgDifference, serial name 'csgDifference'
  //   message csgIntersection, serial name 'csgIntersection'
  //   message csgUnion, serial name 'csgUnion'
  //   message csgCut, serial name 'csgCut'
  //   message csgMesh, serial name 'csgMesh'
  //   message csgBox, serial name 'csgBox'
  //   message csgCone, serial name 'csgCone'
  //   message csgCylinder, serial name 'csgCylinder'
  //   message csgEmpty, serial name 'csgEmpty'
  //   message csgSphere, serial name 'csgSphere'
  //   message csgTorus, serial name 'csgTorus'
  bytes value = 2;
}

message csgBox {
  string n = 1;
  repeated float t = 2;
  float l = 3;
  float w = 4;
  float h = 5;
  Color4d cl = 6;
}

Edit

Thanks to comments and answers, I tried multiple things such as

// Tries to convert the csgNode to unsigned char array
std::string csgNodeStr = csgNode.SerializeAsString();
auto msg = (const unsigned char *)csgNodeStr.c_str();

std::unique_ptr<cms::BytesMessage> message(m_session->createBytesMessage(msg, csgNodeStr.size()));

or

std::string csgNodeStr = csgNode.SerializeAsString();
const char* signedArr = csgNodeStr.c_str();
const int msgSize = (int)csgNodeStr.size();
            
unsigned char* msg = new unsigned char[msgSize + 1];
for (int i = 0; i < msgSize; ++i)
{
    msg[i] = static_cast<unsigned char>(signedArr[i]);
}
            
msg[msgSize + 1] = 0;
std::unique_ptr<cms::BytesMessage> message(m_session->createBytesMessage(msg, csgNodeStr.size()));

Both solutions gave me this output

[INFO] Sent message: 0 csgNode: n: "box"
l: 1600
w: 1600
h: 1600

[INFO] Sent message: 1 csgNode: n: "box"
l: 1600
w: 1600
h: 1600

[INFO] Received message: 1 csgNode: type: "box"
3: 0x44c80000
4: 0x44c80000
5: 0x44c80000

[INFO] Received message: 2 csgNode: type: "box"
3: 0x44c80000
4: 0x44c80000
5: 0x44c80000

Which is closer to what I want (don't bother with the 'type' value). I feel like I'm missing something but I can't put my hands on it.


Solution

  • To anyone having same problems with char* to unsigned char* casting here is the final solution :

    std::string csgNodeStr = csgNode.SerializeAsString();
    const auto msg = reinterpret_cast<const unsigned char*>(csgNodeStr.c_str());
    
    // Create a BytesMessage
    const int msgSize = static_cast<int>(csgNodeStr.size());
    std::unique_ptr<cms::BytesMessage> message(m_session->createBytesMessage(msg, msgSize));
    

    My problem was coming from the parsing itself, it was a protobuf problem. I'm still trying to figure out how to use inheritence with protocol buffers.