3 Replies Latest reply on Sep 6, 2007 11:13 PM by 843829

    Truncated jstring under JRE 1.6 with NewStringUTF

    843829
      Hi,

      I have a JNI app that runs perfectly up to JRE 1.5_07, but crashes on JRE 1.6. After some debugging, I found out the reason for the crash was that the Java UI was received truncated strings from the C++ DLL.

      Again, when I run the app with JRE 1.5_07 or earlier, the strings are passed in full. But under JRE 1.6, I can see they are truncated. Did anyone face a similar problem?

      I am testing it under Wndows XP. The instruction I use for converting my strings to Unicode is:

      jstring jstrTunes = env->NewStringUTF((const char*)GetCompositionsMgr().GetTunes(intPartIndex, ptrRagaString));

      Thanks for any help you can provide.

      Mariano
        • 1. Re: Truncated jstring under JRE 1.6 with NewStringUTF
          843829
          After further debugging, I have noticed that the resulting jstring was truncated by one character for each "special" character found in the original string (I use "�" as a separator). Surprisingly this was never a problem before JRE 1.6.

          The solution seems to be to use the MultiByteToWideChar() function in the C++ part. I did that through this function found on these forums:
          jstring WindowsTojstring(JNIEnv* pEnv, CONST char* str)
          {
               jstring rtn = 0;
               int slen = strlen(str);
               wchar_t* buffer = 0;
               if( slen == 0 )
                    rtn = pEnv->NewStringUTF( str ); //UTF ok since empty string
               else
               {
                    int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
                    buffer = (unsigned short *)malloc( length*2 + 1 );
                    if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
                         rtn = pEnv->NewString( (jchar*)buffer, length );
               }
               if( buffer )
                    free( buffer );
          
               return rtn;
          }
          You would then replace:
          jstring jstrTunes = env->NewStringUTF((const char*)GetCompositionsMgr().GetTunes(intPartIndex, ptrRagaString));
          by:
          jstring jstrTunes = WindowsTojstring(env, (const char*)GetCompositionsMgr().GetTunes(intPartIndex, ptrRagaString));
          Hope this helps anyone facing the same problem.

          Cheers!

          Mariano
          • 2. Re: Truncated jstring under JRE 1.6 with NewStringUTF
            843829
            We've been having the same issue except we are using C on Unix / Linux.
            • 3. Re: Truncated jstring under JRE 1.6 with NewStringUTF
              843829
              I too experienced this bug. In our code we have strings that contain the cross of Lorraine character (ascii code 135). For each occurrence of the cross of Lorraine character, one character would get truncated from the end of the string. The truncation of the string occurred in the following function:

              jstring convertToJstring (JNIEnv * env, const char * str)
              {
              jstring jstr = NULL;
              jstr = (*env)->NewStringUTF(env, str);
              }

              I tried fixing the problem with the following code that uses MultiByteToWideChar:

              jstring convertToJstring(JNIEnv* pEnv, const char* str)
              {
                   jstring rtn = 0;
                   int slen = strlen(str);
                   wchar_t* buffer = 0;
                   if( slen == 0 )
                        rtn = (*pEnv)->NewStringUTF(pEnv, str ); //UTF ok since empty string
                   else
                   {
                        int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
                        buffer = (unsigned short *)malloc( length*2 + 1 );
                        if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
                             rtn = (*pEnv)->NewString(pEnv, (jchar*)buffer, length );
                   }
                   if( buffer )
                        free( buffer );

                   return rtn;
              }

              The above fixes the truncation problem, however, it ended up not working for us because apparently the cross of Lorraine (ascii 135) character got converted to the unicode cross of Lorraine (\u2628) character. Our code needs it to be ascii 135 so our code still failed.

              So I used the following solution. It merely checks to see if the length changed and if it did, then it pads the end with one extra character for each special character found.

              jstring convertToJstring (JNIEnv * env, const char * str)
              {
              jstring jstr = NULL;

              int index = 0;
              int specialCharCount = 0;
              int slen = strlen(str);
              char * buffer;
              jsize jLen;

              if ( env != NULL )
              {
              jstr = (*env)->NewStringUTF(env, str);
              jLen = (*env)->GetStringLength(env, jstr);
              if (jLen == slen)
              {
              //Beep(5000, 200);
              //If the length is equal then we do not have the JRE 1.6 bug
              }
              else
              {
              //Beep(500, 200);
              //If the length is not equal then we have the JRE 1.6 bug
              for (index = 0; index < slen; index++)
              {
              if (str[index] < 0)
              {
              specialCharCount++;
              }
              }

              buffer = malloc( slen + specialCharCount + 1 );
              for (index = 0; index < slen; index++)
              {
              buffer[index] = str[index];
              }

              //Append an extra char for each special char
              for (index = 0; index < specialCharCount; index++)
              {
              buffer[slen + index] = 'Z';
              }

              buffer[slen + index] = '\0';

              jstr = (*env)->NewStringUTF(env, buffer);

              if (buffer)
              {
              free(buffer);
              }
              }
              }

              return jstr;
              }

              The above code is tested and works. It could be streamlined further. By using the difference between the lengths you would not need to count the number of special characters.

              Message was edited by: Brian Bruderer
              Brian-Bruderer