You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by jb...@apache.org on 2018/03/13 04:04:43 UTC

[geode-native] branch develop updated: GEODE-4381: Refactoring readCacheableString() decoding (#234)

This is an automated email from the ASF dual-hosted git repository.

jbarrett pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode-native.git


The following commit(s) were added to refs/heads/develop by this push:
     new e1c75de  GEODE-4381: Refactoring readCacheableString() decoding (#234)
e1c75de is described below

commit e1c75ded5c07e3039bff5b41501d4d30aa6c4076
Author: Ryan McMahon <rm...@pivotal.io>
AuthorDate: Mon Mar 12 21:04:41 2018 -0700

    GEODE-4381: Refactoring readCacheableString() decoding (#234)
    
    
    
    Signed-off-by: Blake Bender <bb...@pivotal.io>
---
 cppcache/include/geode/DataInput.hpp         | 125 ++---------------
 cppcache/src/DataInput.cpp                   |  12 ++
 cppcache/src/TcrMessage.cpp                  | 195 ++++++++++++---------------
 cppcache/src/TcrMessage.hpp                  |   4 +-
 cppcache/src/util/JavaModifiedUtf8.hpp       |  59 ++++++++
 cppcache/test/util/JavaModifiedUtf8Tests.cpp |  20 +++
 6 files changed, 188 insertions(+), 227 deletions(-)

diff --git a/cppcache/include/geode/DataInput.hpp b/cppcache/include/geode/DataInput.hpp
index a77d46d..088d168 100644
--- a/cppcache/include/geode/DataInput.hpp
+++ b/cppcache/include/geode/DataInput.hpp
@@ -379,37 +379,21 @@ class _GEODE_EXPORT DataInput {
 
   inline void readObject(double* value) { *value = readDouble(); }
 
-  inline std::vector<char16_t> readCharArray() {
-    return readArray<char16_t>();
-  }
+  inline std::vector<char16_t> readCharArray() { return readArray<char16_t>(); }
 
-  inline std::vector<bool> readBooleanArray() {
-    return readArray<bool>();
-  }
+  inline std::vector<bool> readBooleanArray() { return readArray<bool>(); }
 
-  inline std::vector<int8_t> readByteArray() {
-    return readArray<int8_t>();
-  }
+  inline std::vector<int8_t> readByteArray() { return readArray<int8_t>(); }
 
-  inline std::vector<int16_t> readShortArray() {
-    return readArray<int16_t>();
-  }
+  inline std::vector<int16_t> readShortArray() { return readArray<int16_t>(); }
 
-  inline std::vector<int32_t> readIntArray() {
-    return readArray<int32_t>();
-  }
+  inline std::vector<int32_t> readIntArray() { return readArray<int32_t>(); }
 
-  inline std::vector<int64_t> readLongArray() {
-    return readArray<int64_t>();
-  }
+  inline std::vector<int64_t> readLongArray() { return readArray<int64_t>(); }
 
-  inline std::vector<float> readFloatArray() {
-    return readArray<float>();
-  }
+  inline std::vector<float> readFloatArray() { return readArray<float>(); }
 
-  inline std::vector<double> readDoubleArray() {
-    return readArray<double>();
-  }
+  inline std::vector<double> readDoubleArray() { return readArray<double>(); }
 
   inline std::vector<std::string> readStringArray() {
     std::vector<std::string> value;
@@ -447,42 +431,6 @@ class _GEODE_EXPORT DataInput {
     }
   }
 
-  /**
-   * Get the length required to represent a given UTF-8 encoded string
-   * (created using {@link DataOutput::writeUTF} or
-   * <code>java.io.DataOutput.writeUTF</code>) in wide-character format.
-   *
-   * @param value The UTF-8 encoded stream.
-   * @param length The length of the stream to be read.
-   * @return The length of the decoded string.
-   * @see DataOutput::getEncodedLength
-   */
-  static int32_t getDecodedLength(const uint8_t* value, int32_t length) {
-    const uint8_t* end = value + length;
-    int32_t decodedLen = 0;
-    while (value < end) {
-      // get next byte unsigned
-      int32_t b = *value++ & 0xff;
-      int32_t k = b >> 5;
-      // classify based on the high order 3 bits
-      switch (k) {
-        case 6: {
-          value++;
-          break;
-        }
-        case 7: {
-          value += 2;
-          break;
-        }
-        default:
-          break;
-      }
-      decodedLen += 1;
-    }
-    if (value > end) decodedLen--;
-    return decodedLen;
-  }
-
   /** destructor */
   ~DataInput() {}
 
@@ -604,51 +552,6 @@ class _GEODE_EXPORT DataInput {
     }
   }
 
-  inline char16_t decodeJavaModifiedUtf8Char() {
-    char16_t c;
-    // get next byte unsigned
-    int32_t b = *m_buf++ & 0xff;
-    int32_t k = b >> 5;
-    // classify based on the high order 3 bits
-    switch (k) {
-      case 6: {
-        // two byte encoding
-        // 110yyyyy 10xxxxxx
-        // use low order 6 bits
-        int32_t y = b & 0x1f;
-        // use low order 6 bits of the next byte
-        // It should have high order bits 10, which we don't check.
-        int32_t x = *m_buf++ & 0x3f;
-        // 00000yyy yyxxxxxx
-        c = (y << 6 | x);
-        break;
-      }
-      case 7: {
-        // three byte encoding
-        // 1110zzzz 10yyyyyy 10xxxxxx
-        // use low order 4 bits
-        int32_t z = b & 0x0f;
-        // use low order 6 bits of the next byte
-        // It should have high order bits 10, which we don't check.
-        int32_t y = *m_buf++ & 0x3f;
-        // use low order 6 bits of the next byte
-        // It should have high order bits 10, which we don't check.
-        int32_t x = *m_buf++ & 0x3f;
-        // zzzzyyyy yyxxxxxx
-        c = (z << 12 | y << 6 | x);
-        break;
-      }
-      default:
-        // one byte encoding
-        // 0xxxxxxx
-        // use just low order 7 bits
-        // 00000000 0xxxxxxx
-        c = (b & 0x7f);
-        break;
-    }
-    return c;
-  }
-
   inline int8_t readNoCheck() { return *(m_buf++); }
 
   inline int16_t readInt16NoCheck() {
@@ -683,16 +586,8 @@ class _GEODE_EXPORT DataInput {
       std::basic_string<_CharT, _Traits, _Allocator>& value);
 
   template <class _Traits, class _Allocator>
-  inline void readJavaModifiedUtf8(
-      std::basic_string<char16_t, _Traits, _Allocator>& value) {
-    uint16_t length = readInt16();
-    _GEODE_CHECK_BUFFER_SIZE(length);
-    value.reserve(length);
-    const auto end = m_buf + length;
-    while (m_buf < end) {
-      value += decodeJavaModifiedUtf8Char();
-    }
-  }
+  void readJavaModifiedUtf8(
+      std::basic_string<char16_t, _Traits, _Allocator>& value);
 
   template <class _Traits, class _Allocator>
   void readJavaModifiedUtf8(
diff --git a/cppcache/src/DataInput.cpp b/cppcache/src/DataInput.cpp
index e6ee8f4..ee1bda9 100644
--- a/cppcache/src/DataInput.cpp
+++ b/cppcache/src/DataInput.cpp
@@ -21,6 +21,7 @@
 #include "SerializationRegistry.hpp"
 #include "CacheImpl.hpp"
 #include "util/string.hpp"
+#include "util/JavaModifiedUtf8.hpp"
 
 namespace apache {
 namespace geode {
@@ -48,6 +49,17 @@ template _GEODE_EXPORT void DataInput::readJavaModifiedUtf8(std::string&);
 
 template <class _Traits, class _Allocator>
 void DataInput::readJavaModifiedUtf8(
+    std::basic_string<char16_t, _Traits, _Allocator>& value) {
+  uint16_t length = readInt16();
+  _GEODE_CHECK_BUFFER_SIZE(length);
+  value =
+      JavaModifiedUtf8::decode(reinterpret_cast<const char*>(m_buf), length);
+  advanceCursor(length);
+}
+template _GEODE_EXPORT void DataInput::readJavaModifiedUtf8(std::u16string&);
+
+template <class _Traits, class _Allocator>
+void DataInput::readJavaModifiedUtf8(
     std::basic_string<char32_t, _Traits, _Allocator>& value) {
   // TODO string OPTIMIZE convert from UTF-16 to UCS-4 directly
   std::u16string utf16;
diff --git a/cppcache/src/TcrMessage.cpp b/cppcache/src/TcrMessage.cpp
index b119884..598352c 100644
--- a/cppcache/src/TcrMessage.cpp
+++ b/cppcache/src/TcrMessage.cpp
@@ -302,7 +302,7 @@ void TcrMessage::readSecureObjectPart(DataInput& input, bool defaultString,
         // m_connectionIDBytes = readCacheableBytes(input, lenObj);
         m_connectionIDBytes = CacheableBytes::create(
             std::vector<int8_t>(input.currentBufferPosition(),
-              input.currentBufferPosition() + lenObj));
+                                input.currentBufferPosition() + lenObj));
         input.advanceCursor(lenObj);
       }
     }
@@ -322,19 +322,18 @@ void TcrMessage::readUniqueIDObjectPart(DataInput& input) {
   LOGDEBUG("TcrMessage::readUniqueIDObjectPart lenObj = %d isObj = %d", lenObj,
            isObj);
   if (lenObj > 0) {
-    m_value = CacheableBytes::create(
-        std::vector<int8_t>(input.currentBufferPosition(),
-                            input.currentBufferPosition() + lenObj));
+    m_value = CacheableBytes::create(std::vector<int8_t>(
+        input.currentBufferPosition(), input.currentBufferPosition() + lenObj));
     input.advanceCursor(lenObj);
   }
 }
 
 int64_t TcrMessage::getConnectionId(TcrConnection* conn) {
   if (m_connectionIDBytes != nullptr) {
-   auto tmp = conn->decryptBytes(m_connectionIDBytes);
-   auto di = m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
-       reinterpret_cast<const uint8_t*>(tmp->value().data()), tmp->length());
-   return di->readInt64();
+    auto tmp = conn->decryptBytes(m_connectionIDBytes);
+    auto di = m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
+        reinterpret_cast<const uint8_t*>(tmp->value().data()), tmp->length());
+    return di->readInt64();
   } else {
     LOGWARN("Returning 0 as internal connection ID msgtype = %d ", m_msgType);
     return 0;
@@ -391,43 +390,13 @@ inline void TcrMessage::writeInt(uint8_t* buffer, uint32_t value) {
 }
 std::shared_ptr<Serializable> TcrMessage::readCacheableString(DataInput& input,
                                                               int lenObj) {
-  std::shared_ptr<Serializable> sPtr;
-  // check whether unicode or ASCII string (bug #356)
-  unsigned int decodedLen =
-      DataInput::getDecodedLength(input.currentBufferPosition(), lenObj);
-
-  if (decodedLen == static_cast<unsigned int>(lenObj)) {
-    if (decodedLen <= 0xffff) {
-      input.rewindCursor(2);
-      writeInt(const_cast<uint8_t*>(input.currentBufferPosition()),
-               static_cast<uint16_t>(lenObj));
-      sPtr = input.readDirectObject(static_cast<int8_t>(
-          apache::geode::client::GeodeTypeIds::CacheableASCIIString));
-    } else {
-      input.rewindCursor(4);
-      writeInt(const_cast<uint8_t*>(input.currentBufferPosition()),
-               static_cast<uint32_t>(lenObj));
-      sPtr = input.readDirectObject(static_cast<int8_t>(
-          apache::geode::client::GeodeTypeIds::CacheableASCIIStringHuge));
-    }
-  } else {
-    if (decodedLen <= 0xffff) {
-      input.rewindCursor(2);
-      writeInt(const_cast<uint8_t*>(input.currentBufferPosition()),
-               static_cast<uint16_t>(lenObj));
-      sPtr = input.readDirectObject(static_cast<int8_t>(
-          apache::geode::client::GeodeTypeIds::CacheableString));
-    } else {
-      input.rewindCursor(4);
-      writeInt(const_cast<uint8_t*>(input.currentBufferPosition()),
-               static_cast<uint32_t>(lenObj));
-      sPtr = input.readDirectObject(static_cast<int8_t>(
-          apache::geode::client::GeodeTypeIds::CacheableStringHuge));
-    }
-  }
+  auto decoded = JavaModifiedUtf8::decode(
+      reinterpret_cast<const char*>(input.currentBufferPosition()), lenObj);
+  input.advanceCursor(lenObj);
 
-  return sPtr;
+  return CacheableString::create(decoded);
 }
+
 std::shared_ptr<Serializable> TcrMessage::readCacheableBytes(DataInput& input,
                                                              int lenObj) {
   if (lenObj <= 252) {  // 252 is java's ((byte)-4 && 0xFF)
@@ -802,9 +771,9 @@ void TcrMessage::processChunk(const uint8_t* bytes, int32_t len,
         if (bytes == nullptr) {
           // last chunk -- wait for processing of all the chunks to complete
           m_chunkedResult->waitFinalize();
-         auto ex = m_chunkedResult->getException();
-         if (ex != nullptr) {
-           throw *ex;
+          auto ex = m_chunkedResult->getException();
+          if (ex != nullptr) {
+            throw *ex;
           }
         }
         break;
@@ -868,8 +837,9 @@ void TcrMessage::processChunk(const uint8_t* bytes, int32_t len,
     case TcrMessage::EXCEPTION: {
       if (bytes != nullptr) {
         DeleteArray<const uint8_t> delChunk(bytes);
-        auto input = m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
-                  bytes, len);
+        auto input =
+            m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
+                bytes, len);
         readExceptionPart(*input, isLastChunkAndisSecurityHeader);
         readSecureObjectPart(*input, false, true,
                              isLastChunkAndisSecurityHeader);
@@ -926,7 +896,7 @@ void TcrMessage::chunkSecurityHeader(int skipPart, const uint8_t* bytes,
   LOGDEBUG("TcrMessage::chunkSecurityHeader:: skipParts = %d", skipPart);
   if ((isLastChunkAndSecurityHeader & 0x3) == 0x3) {
     auto di = m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
-              bytes, len);
+        bytes, len);
     skipParts(*di, skipPart);
     readSecureObjectPart(*di, false, true, isLastChunkAndSecurityHeader);
   }
@@ -937,7 +907,7 @@ void TcrMessage::handleByteArrayResponse(
     const SerializationRegistry& serializationRegistry,
     MemberListForVersionStamp& memberListForVersionStamp) {
   auto input = m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
-                  (uint8_t*)bytearray, len);
+      (uint8_t*)bytearray, len);
   // TODO:: this need to make sure that pool is there
   //  if(m_tcdm == nullptr)
   //  throw IllegalArgumentException("Pool is nullptr in TcrMessage");
@@ -1251,7 +1221,8 @@ void TcrMessage::handleByteArrayResponse(
         LOGDEBUG("RESPONSE_CLIENT_PR_METADATA len is 17");
         return;
       }
-      m_metadata = new std::vector<std::vector<std::shared_ptr<BucketServerLocation>> >();
+      m_metadata =
+          new std::vector<std::vector<std::shared_ptr<BucketServerLocation>>>();
       for (int32_t i = 0; i < numparts; i++) {
         int32_t bits32 = input->readInt32();  // partlen;
         input->read();                        // isObj;
@@ -1262,7 +1233,8 @@ void TcrMessage::handleByteArrayResponse(
         bits32 = input->readArrayLen();  // array length
         LOGDEBUG("Array length = %d ", bits32);
         if (bits32 > 0) {
-          std::vector<std::shared_ptr<BucketServerLocation>> bucketServerLocations;
+          std::vector<std::shared_ptr<BucketServerLocation>>
+              bucketServerLocations;
           for (int32_t index = 0; index < bits32; index++) {
             // ignore DS typeid, CLASS typeid, and string typeid
             input->advanceCursor(3);
@@ -1316,7 +1288,8 @@ void TcrMessage::handleByteArrayResponse(
 
         bits32 = input->readArrayLen();  // array length
         if (bits32 > 0) {
-          m_fpaSet = new std::vector<std::shared_ptr<FixedPartitionAttributesImpl>>();
+          m_fpaSet =
+              new std::vector<std::shared_ptr<FixedPartitionAttributesImpl>>();
           for (int32_t index = 0; index < bits32; index++) {
             input->advanceCursor(
                 3);  // ignore DS typeid, CLASS typeid, string typeid
@@ -1588,8 +1561,8 @@ TcrMessageQueryWithParameters::TcrMessageQueryWithParameters(
   // Part-5: Parameters
   if (paramList != nullptr) {
     for (int32_t i = 0; i < paramList->size(); i++) {
-     auto value = (*paramList)[i];
-     writeObjectPart(value);
+      auto value = (*paramList)[i];
+      writeObjectPart(value);
     }
   }
   writeMessageLength();
@@ -1754,11 +1727,11 @@ TcrMessageDestroy::TcrMessageDestroy(
     writeObjectPart(key);
     writeObjectPart(value);  // expectedOldValue part
     uint8_t removeByte = 8;  // OP_TYPE_DESTROY value from Operation.java
-   auto removeBytePart = CacheableByte::create(removeByte);
-   writeObjectPart(removeBytePart);  // operation part
-   writeEventIdPart();
-   if (aCallbackArgument != nullptr) {
-     writeObjectPart(aCallbackArgument);
+    auto removeBytePart = CacheableByte::create(removeByte);
+    writeObjectPart(removeBytePart);  // operation part
+    writeEventIdPart();
+    if (aCallbackArgument != nullptr) {
+      writeObjectPart(aCallbackArgument);
     }
     writeMessageLength();
   } else {
@@ -2130,11 +2103,11 @@ TcrMessagePeriodicAck::TcrMessagePeriodicAck(
   writeHeader(m_msgType, numParts);
   for (EventIdMapEntryList::const_iterator entry = entries.begin();
        entry != entries.end(); ++entry) {
-   auto src = entry->first;
-   auto seq = entry->second;
-   auto eid = EventId::create(src->getMemId(), src->getMemIdLen(),
-                              src->getThrId(), seq->getSeqNum());
-   writeObjectPart(eid);
+    auto src = entry->first;
+    auto seq = entry->second;
+    auto eid = EventId::create(src->getMemId(), src->getMemIdLen(),
+                               src->getThrId(), seq->getSeqNum());
+    writeObjectPart(eid);
   }
   writeMessageLength();
 }
@@ -2143,7 +2116,8 @@ TcrMessagePutAll::TcrMessagePutAll(
     std::unique_ptr<DataOutput> dataOutput, const Region* region,
     const HashMapOfCacheable& map,
     std::chrono::milliseconds messageResponsetimeout,
-    ThinClientBaseDM* connectionDM, const std::shared_ptr<Serializable>& aCallbackArgument) {
+    ThinClientBaseDM* connectionDM,
+    const std::shared_ptr<Serializable>& aCallbackArgument) {
   m_tcdm = connectionDM;
   m_regionName = region->getFullPath();
   m_region = region;
@@ -2297,7 +2271,8 @@ TcrMessageGetAll::TcrMessageGetAll(
   writeMessageLength();*/
 }
 
-void TcrMessage::InitializeGetallMsg(const std::shared_ptr<Serializable>& aCallbackArgument) {
+void TcrMessage::InitializeGetallMsg(
+    const std::shared_ptr<Serializable>& aCallbackArgument) {
   /*CacheableObjectArrayPtr keyArr = nullptr;
   if (m_keyList != nullptr) {
     keyArr = CacheableObjectArray::create();
@@ -2584,10 +2559,8 @@ void TcrMessage::createUserCredentialMessage(TcrConnection* conn) {
 
   if (m_creds != nullptr) m_creds->toData(*dOut);
 
-  auto credBytes =
-      CacheableBytes::create(
-        std::vector<int8_t>(dOut->getBuffer(),
-                            dOut->getBuffer() + dOut->getBufferLength()));
+  auto credBytes = CacheableBytes::create(std::vector<int8_t>(
+      dOut->getBuffer(), dOut->getBuffer() + dOut->getBufferLength()));
   auto encryptBytes = conn->encryptBytes(credBytes);
   writeObjectPart(encryptBytes);
 
@@ -2616,9 +2589,8 @@ void TcrMessage::addSecurityPart(int64_t connectionId, int64_t unique_id,
   dOutput->writeInt(connectionId);
   dOutput->writeInt(unique_id);
 
-  auto bytes = CacheableBytes::create(
-      std::vector<int8_t>(dOutput->getBuffer(), dOutput->getBuffer() +
-      dOutput->getBufferLength()));
+  auto bytes = CacheableBytes::create(std::vector<int8_t>(
+      dOutput->getBuffer(), dOutput->getBuffer() + dOutput->getBufferLength()));
 
   auto encryptBytes = conn->encryptBytes(bytes);
 
@@ -2642,13 +2614,13 @@ void TcrMessage::addSecurityPart(int64_t connectionId, TcrConnection* conn) {
   }
   m_isSecurityHeaderAdded = true;
   LOGDEBUG("TcrMessage::addSecurityPart only connid");
-  auto dOutput = m_tcdm->getConnectionManager().getCacheImpl()->createDataOutput();
+  auto dOutput =
+      m_tcdm->getConnectionManager().getCacheImpl()->createDataOutput();
 
   dOutput->writeInt(connectionId);
 
-  auto bytes = CacheableBytes::create(
-      std::vector<int8_t>(dOutput->getBuffer(), dOutput->getBuffer() +
-      dOutput->getBufferLength()));
+  auto bytes = CacheableBytes::create(std::vector<int8_t>(
+      dOutput->getBuffer(), dOutput->getBuffer() + dOutput->getBufferLength()));
 
   auto encryptBytes = conn->encryptBytes(bytes);
 
@@ -2814,7 +2786,8 @@ void TcrMessage::setData(const char* bytearray, int32_t len, uint16_t memId,
                          const SerializationRegistry& serializationRegistry,
                          MemberListForVersionStamp& memberListForVersionStamp) {
   if (m_request == nullptr) {
-    m_request = m_tcdm->getConnectionManager().getCacheImpl()->createDataOutput();
+    m_request =
+        m_tcdm->getConnectionManager().getCacheImpl()->createDataOutput();
   }
   if (bytearray) {
     DeleteArray<const char> delByteArr(bytearray);
@@ -2847,9 +2820,11 @@ void TcrMessage::setMessageTypeRequest(int32_t msgType) {
 int32_t TcrMessage::getMessageTypeRequest() const { return m_msgTypeRequest; }
 
 const std::map<std::string, int>* TcrMessage::getCqs() const { return m_cqs; }
- std::shared_ptr<CacheableKey> TcrMessage::getKey() const { return m_key; }
+std::shared_ptr<CacheableKey> TcrMessage::getKey() const { return m_key; }
 
-const std::shared_ptr<CacheableKey>& TcrMessage::getKeyRef() const { return m_key; }
+const std::shared_ptr<CacheableKey>& TcrMessage::getKeyRef() const {
+  return m_key;
+}
 std::shared_ptr<Cacheable> TcrMessage::getValue() const { return m_value; }
 
 const std::shared_ptr<Cacheable>& TcrMessage::getValueRef() const {
@@ -2882,16 +2857,16 @@ uint32_t TcrMessage::getMsgLength() const {
 uint32_t TcrMessage::getMsgBodyLength() const {
   return m_request->getBufferLength() - g_headerLen;
 }
- std::shared_ptr<EventId> TcrMessage::getEventId() const { return m_eventid; }
+std::shared_ptr<EventId> TcrMessage::getEventId() const { return m_eventid; }
 
- int32_t TcrMessage::getTransId() const { return m_txId; }
+int32_t TcrMessage::getTransId() const { return m_txId; }
 
- void TcrMessage::setTransId(int32_t txId) { m_txId = txId; }
+void TcrMessage::setTransId(int32_t txId) { m_txId = txId; }
 
- std::chrono::milliseconds TcrMessage::getTimeout() const { return m_timeout; }
+std::chrono::milliseconds TcrMessage::getTimeout() const { return m_timeout; }
 
- void TcrMessage::setTimeout(std::chrono::milliseconds timeout) {
-   m_timeout = timeout;
+void TcrMessage::setTimeout(std::chrono::milliseconds timeout) {
+  m_timeout = timeout;
 }
 
 void TcrMessage::skipParts(DataInput& input, int32_t numParts) {
@@ -2918,30 +2893,30 @@ void TcrMessage::readEventIdPart(DataInput& input, bool skip, int32_t parts) {
 
   m_eventid = std::static_pointer_cast<EventId>(input.readObject());
 }
- std::shared_ptr<DSMemberForVersionStamp> TcrMessage::readDSMember(
+std::shared_ptr<DSMemberForVersionStamp> TcrMessage::readDSMember(
     apache::geode::client::DataInput& input) {
-   uint8_t typeidLen = input.read();
-   if (typeidLen == 1) {
-     uint8_t typeidofMember = input.read();
-     if (typeidofMember != GeodeTypeIdsImpl::InternalDistributedMember) {
-       throw Exception(
-           "Reading DSMember. Expecting type id 92 for "
-           "InternalDistributedMember. ");
-     }
-
-     auto memId = std::shared_ptr<ClientProxyMembershipID>(
-         new ClientProxyMembershipID());
-     memId->fromData(input);
-     return (std::shared_ptr<DSMemberForVersionStamp>)memId;
-   } else if (typeidLen == 2) {
-     uint16_t typeidofMember = input.readInt16();
-     if (typeidofMember != GeodeTypeIdsImpl::DiskStoreId) {
-       throw Exception(
-           "Reading DSMember. Expecting type id 2133 for DiskStoreId. ");
-     }
-     DiskStoreId* diskStore = new DiskStoreId();
-     diskStore->fromData(input);
-     return std::shared_ptr<DSMemberForVersionStamp>(diskStore);
+  uint8_t typeidLen = input.read();
+  if (typeidLen == 1) {
+    uint8_t typeidofMember = input.read();
+    if (typeidofMember != GeodeTypeIdsImpl::InternalDistributedMember) {
+      throw Exception(
+          "Reading DSMember. Expecting type id 92 for "
+          "InternalDistributedMember. ");
+    }
+
+    auto memId =
+        std::shared_ptr<ClientProxyMembershipID>(new ClientProxyMembershipID());
+    memId->fromData(input);
+    return (std::shared_ptr<DSMemberForVersionStamp>)memId;
+  } else if (typeidLen == 2) {
+    uint16_t typeidofMember = input.readInt16();
+    if (typeidofMember != GeodeTypeIdsImpl::DiskStoreId) {
+      throw Exception(
+          "Reading DSMember. Expecting type id 2133 for DiskStoreId. ");
+    }
+    DiskStoreId* diskStore = new DiskStoreId();
+    diskStore->fromData(input);
+    return std::shared_ptr<DSMemberForVersionStamp>(diskStore);
   } else {
     throw Exception(
         "Reading DSMember. Expecting type id length as either one or two "
diff --git a/cppcache/src/TcrMessage.hpp b/cppcache/src/TcrMessage.hpp
index 7e883fd..8012a29 100644
--- a/cppcache/src/TcrMessage.hpp
+++ b/cppcache/src/TcrMessage.hpp
@@ -392,8 +392,8 @@ class _GEODE_EXPORT TcrMessage {
     if (m_deltaBytes == nullptr) {
       return nullptr;
     }
-    auto retVal =
-        CacheableBytes::create(std::vector<int8_t>(m_deltaBytes, m_deltaBytes + m_deltaBytesLen));
+    auto retVal = CacheableBytes::create(
+        std::vector<int8_t>(m_deltaBytes, m_deltaBytes + m_deltaBytesLen));
     m_deltaBytes = nullptr;
     return retVal;
   }
diff --git a/cppcache/src/util/JavaModifiedUtf8.hpp b/cppcache/src/util/JavaModifiedUtf8.hpp
index 71c2634..314ed1c 100644
--- a/cppcache/src/util/JavaModifiedUtf8.hpp
+++ b/cppcache/src/util/JavaModifiedUtf8.hpp
@@ -115,6 +115,65 @@ struct JavaModifiedUtf8 {
       jmutf8 += static_cast<uint8_t>(0x80 | (c & 0x3F));
     }
   }
+
+  inline static std::u16string decode(const char* buf, uint16_t len) {
+    std::u16string value;
+    const auto end = buf + len;
+    while (buf < end) {
+      value += decodeJavaModifiedUtf8Char(&buf);
+    }
+    return value;
+  }
+
+  inline static char16_t decodeJavaModifiedUtf8Char(const char** pbuf) {
+    char16_t c;
+
+    // get next byte unsigned
+    int32_t b = **pbuf & 0xff;
+    (*pbuf)++;
+    int32_t k = b >> 5;
+    // classify based on the high order 3 bits
+    switch (k) {
+      case 6: {
+        // two byte encoding
+        // 110yyyyy 10xxxxxx
+        // use low order 6 bits
+        int32_t y = b & 0x1f;
+        // use low order 6 bits of the next byte
+        // It should have high order bits 10, which we don't check.
+        int32_t x = **pbuf & 0x3f;
+        (*pbuf)++;
+        // 00000yyy yyxxxxxx
+        c = (y << 6 | x);
+        break;
+      }
+      case 7: {
+        // three byte encoding
+        // 1110zzzz 10yyyyyy 10xxxxxx
+        // use low order 4 bits
+        int32_t z = b & 0x0f;
+        // use low order 6 bits of the next byte
+        // It should have high order bits 10, which we don't check.
+        int32_t y = **pbuf & 0x3f;
+        (*pbuf)++;
+        // use low order 6 bits of the next byte
+        // It should have high order bits 10, which we don't check.
+        int32_t x = **pbuf & 0x3f;
+        (*pbuf)++;
+        // zzzzyyyy yyxxxxxx
+        c = static_cast<char16_t>(z << 12 | y << 6 | x);
+        break;
+      }
+      default:
+        // one byte encoding
+        // 0xxxxxxx
+        // use just low order 7 bits
+        // 00000000 0xxxxxxx
+        c = static_cast<char16_t>(b & 0x7f);
+        break;
+    }
+    return c;
+  }
 };
 
 }  // namespace internal
diff --git a/cppcache/test/util/JavaModifiedUtf8Tests.cpp b/cppcache/test/util/JavaModifiedUtf8Tests.cpp
index 5e1c975..9f37ccc 100644
--- a/cppcache/test/util/JavaModifiedUtf8Tests.cpp
+++ b/cppcache/test/util/JavaModifiedUtf8Tests.cpp
@@ -21,6 +21,8 @@
 
 #include <util/JavaModifiedUtf8.hpp>
 
+#include "../ByteArray.hpp"
+
 using namespace apache::geode::client::internal;
 
 TEST(JavaModifiedUtf8Tests, EncodedLengthFromUtf8) {
@@ -31,3 +33,21 @@ TEST(JavaModifiedUtf8Tests, EncodedLengthUtf16) {
   EXPECT_EQ(27,
             JavaModifiedUtf8::encodedLength(u"You had me at meat tornado."));
 }
+
+TEST(JavaModifiedUtf8Tests, DecodeToString) {
+  const char* buf = "You had me at meat tornado!";
+  EXPECT_EQ(JavaModifiedUtf8::decode(buf, 27),
+            std::u16string(u"You had me at meat tornado!"));
+}
+
+TEST(JavaModifiedUtf8Tests, DecodeStringWithInlineNullChar) {
+  auto expected = std::u16string(u"You had me at");
+  expected.push_back(0);
+  expected.append(u"meat tornad\u00F6!\U000F0000");
+
+  auto buf = ByteArray::fromString(
+      "596F7520686164206D65206174C0806D65617420746F726E6164C3B621EDAE80EDB080");
+  std::u16string actual =
+      JavaModifiedUtf8::decode(reinterpret_cast<const char*>(buf.get()), 35);
+  EXPECT_EQ(expected, actual);
+}

-- 
To stop receiving notification emails like this one, please contact
jbarrett@apache.org.