Problem reading strings [SOLVED]

mbustos
edited June 2010 in Native
Hi, I have a problem reading a string of HashTable. Look at this ("data" is a HashTable):
PhotonEvent &PhotonEvent::operator >>(std::string &value)
{
  value = (char*)data.getValue(KeyObject<char>(dataObjectPointer++))->getData();

  return *this;
}

Use something similar to read char, short, int, ... but this does not work for strings

data.toString :
{(b)6 = (k)0, (b)5 = (k)0, (b)4 = (k)0, (b)3 = (k)0, (b)2 = (b)1, (b)1 = (s)nick, (b)0 = (i)72}

The only I do not read properly is the key 1... any clue?

Thanks!

- m

Comments

  • Fixed using JString :D
    PhotonEvent &PhotonEvent::operator >>(std::string &value)
    {
      JString tmp;
    
      tmp = *(JString*)data.getValue(KeyObject<char>(dataObjectPointer++))->getData();
      value = tmp;
    
      return *this;
    }
    
  • Kaiserludi
    Kaiserludi admin
    edited July 2010
    mbustos wrote:
    Fixed using JString :D
    PhotonEvent &PhotonEvent::operator >>(std::string &value)
    {
      JString tmp;
    
      tmp = *(JString*)data.getValue(KeyObject<char>(dataObjectPointer++))->getData();
      value = tmp;
    
      return *this;
    }
    
    Hi mbustos.
    Yes, we use instances of class JString for strings. As we do not want to break compatibility to platforms using a C++ implementation without the standard library, we can not use std::string and we wanted to avoid the disadvantages of oldstyle c-strings.
    You could do the code above a bit shorter by using trhe implicit conversion from JString to char*:
    PhotonEvent &PhotonEvent::operator >>(std::string &value)
    {
      value = *(JString*)data.getValue(KeyObject<nByte>(dataObjectPointer++))->getData();
      return *this;
    }
    
    I replaced "char" by "nByte", as the API uses nByte and although this is defined as char at the moment it is not unlikely, that this will change into unsigned char in the future.

    My usage recommendation would by the way more be like this:
    PhotonEvent &PhotonEvent::operator >>(std::string &value)
    {
      value = (ValueObject<JString>(data.getValue(KeyObject<nByte>(dataObjectPointer++)))).getDataCopy();
      return *this;
    }
    
    It is a bit longer and looks a bit more complicated for the first moment, yes, but it comes with an integrated type-check instead of the dangerous cast.
    By using getDataCopy() of ValueObject<JString> instead of getData(), you do not get a void*, which you would have to cast into a JString* and then would have to dereference, but you already get back a JString. The big adavantage of this is, that in case by accident the object stored as value under that key is no JString, but for example an int, the approach of casting the returnvalue of getData() into a JString* and then dereference it, would most likely end in a crash, but getDataCopy() will alway return a valid JString to you, either the one, you wanted, or, in the case, the first code would crash, it would simply return an empty string, so your programm would stay stable and you could check for an epty string, if you want to make sure, nothing went wrong.
    This event gets more important for more primitive types. In Jstring-case if the situation will ever appear while debugging, you will have a crash and can easily track down the problem, but if you expect a short and get a part of an int or you expect an int and get a float, the cast will not result in a crash, but just in strange values and such bugs are more difficult to find then crashs, but the getDataCopy()-code will always return 0, if the type is not the expected one, so if you change types at the sending side at some time in the development process and forget to change them at the receiving side, getting 0 everytime will easily come to your attention.
    Also for futre we plan to call DebugReturn with an errormessage, if you try to read out the value as a different type than it actually has.
  • Also for futre we plan to call DebugReturn with an errormessage, if you try to read out the value as a different type than it actually has.

    That would be great, Kaiserludi. As client's programmer, I never trust the information I receive so all events received (and send) are created by a factory which uses a template defined in an xml as:
      &lt;event name="EV_LOGIN" id="100"&gt;
        &lt;value name="EV_USERNAME" type="string"/&gt;
        &lt;value name="EV_SHA1PASS" type="string"/&gt;
        &lt;value name="EV_BUILDVERSION" type="short"/&gt;
      &lt;/event&gt;
    

    And I read with:
    ...
    typedef ExitGames::KeyObject&lt;nByte&gt; EventKey
    ...
    
    PhotonEvent &PhotonEvent::operator &gt;&gt;(std::string &value)
    {
      if (dataObjectPointer &lt; (nByte)data.keys().size())
      {
        if (data.getValue(EventKey(dataObjectPointer))-&gt;getType() != EG_STRING)
          Error::FatalError("&#91;net&#93; Wrong key type at event %d (expected STRING)", eventID);
      }
      else
        Error::FatalError("&#91;net&#93; Event %d pointer outofrange", eventID);
    
      value = *(JString*)data.getValue(EventKey(dataObjectPointer++))-&gt;getData();
    
      return *this;
    }
    

    So the event received must have the same structure as the template xml. A native support to check types would be great!

    - m