3

How do I convert a fixed byte array to a String in managed c++/cli ?
For example I have the following Byte array.

Byte byte_data[5];
byte_data[0]='a';
byte_data[1]='b';
byte_data[2]='c';
byte_data[3]='d';
byte_data[4]='e';

I have tried the following code
String ^mytext=System::Text::UTF8Encoding::UTF8->GetString(byte_data);

I get the following error:
error C2664: 'System::String ^System::Text::Encoding::GetString(cli::array<Type,dimension> ^)' : cannot convert parameter 1 from 'unsigned char [5]' to 'cli::array<Type,dimension> ^'

JKor
  • 3,822
  • 3
  • 28
  • 36
Peter H
  • 871
  • 1
  • 10
  • 33
  • Doesn't http://msdn.microsoft.com/en-us/library/ezh7k8d5.aspx do this for you? Give or take `signed` vs `unsigned`. – ta.speot.is Jan 28 '13 at 02:24
  • @ta.speot.is Good catch! If you use the constructor that takes an encoding parameter (and set it to `System.Text::UTF8Encoding`). – rasmus Jan 28 '13 at 02:32

3 Answers3

2

Here is one option:

array<Byte>^ array_data = gcnew array<Byte>(5);
for(int i = 0; i < 5; i++)
    array_data[i] = byte_data[i];
System::Text::UTF8Encoding::UTF8->GetString(array_data);

Not compiled but I think you get the idea.

Or use the String constructor, as indicated by @ta.speot.is, with encoding set to System.Text::UTF8Encoding.

rasmus
  • 3,136
  • 17
  • 22
  • Unfortunately I have already declared the byte array as Byte byte_data[5] and all my functions need to work on the assumption that data is in byte_data[X]. I need a method to convert this byte array and not a new one as you have declared. – Peter H Jan 28 '13 at 02:11
  • You need to create a managed copy of the array right before calling `GetString`. The rest of your code can stay the same. – rasmus Jan 28 '13 at 02:12
  • 1
    This seems tedious, But will work...Is there another efficient solution than by copying each byte manually? – Peter H Jan 28 '13 at 02:14
  • The call expects a managed array so no. Create a helper function if you want. For one, how would `GetString` know the size of `byte_data`? It is not null-terminated. – rasmus Jan 28 '13 at 02:15
  • @PeterH: `Marshal::Copy`. You have to copy the data. It's not slow, but as always, run your own tests before assuming it will or will not work for you. – Ed S. Jan 28 '13 at 02:38
  • @rasmus If it were null terminated..Can you advise what your code may will look like? – Peter H Jan 28 '13 at 03:30
  • You could get the length using strlen... I suggest going with @ta.speot.is's answer in combination with strlen and UTF8Encoding. – rasmus Jan 28 '13 at 03:43
  • @rasmus It's an array of five characters, the last character is not followed by a zero terminator. `strlen` is a bad idea. – ta.speot.is Jan 28 '13 at 07:26
  • @ta.speot.is OPs last comment was "what if it was null-terminated". Read first please. – rasmus Jan 28 '13 at 11:41
2

Arm yourself with some knowledge about casting between pointers to signed and unsigned types and then you should be set to use String::String(SByte*, Int32, Int32). It might also pay to read the Remarks on the page, specifically around encoding.

I've reproduced the sample from the page here:

// Null terminated ASCII characters in a simple char array 
char charArray3[4] = {0x41,0x42,0x43,0x00};
char * pstr3 =  &charArray3[ 0 ];
String^ szAsciiUpper = gcnew String( pstr3 );
char charArray4[4] = {0x61,0x62,0x63,0x00};
char * pstr4 =  &charArray4[ 0 ];
String^ szAsciiLower = gcnew String( pstr4,0,sizeof(charArray4) );

// Prints "ABC abc"
Console::WriteLine( String::Concat( szAsciiUpper,  " ", szAsciiLower ) );

// Compare Strings - the result is true
Console::WriteLine( String::Concat(  "The Strings are equal when capitalized ? ", (0 == String::Compare( szAsciiUpper->ToUpper(), szAsciiLower->ToUpper() ) ? (String^)"TRUE" :  "FALSE") ) );

// This is the effective equivalent of another Compare method, which ignores case
Console::WriteLine( String::Concat(  "The Strings are equal when capitalized ? ", (0 == String::Compare( szAsciiUpper, szAsciiLower, true ) ? (String^)"TRUE" :  "FALSE") ) );
Community
  • 1
  • 1
ta.speot.is
  • 26,914
  • 8
  • 68
  • 96
  • How do I do the encoding to ascii. At the moment it's doesn't appear to be accepting line breaks? I'm assuming its an encoding issue. See post below. Doesn't seem to like String ^mytextutf8=System::Text::ASCIIEncoding::ASCII->GetChars(pstr3); – Peter H Jan 28 '13 at 07:13
  • @PeterH There is another overload of `String::String` that takes an encoding. – ta.speot.is Jan 28 '13 at 07:20
0

For those interested in another working solution. I used the notes of ta.speot.is and developed a working solution,You should be able to use this solution or that provided by Rasmus.

Byte byte_data[5];
byte_data[0]='a';
byte_data[1]='b';
byte_data[2]='c';
byte_data[3]='d';
byte_data[4]='e';

char *pstr3 =  reinterpret_cast<char*>(byte_data);
String^ example1 = gcnew String( pstr3 );//Note: This method FAILS if the string is not null terminated
                                        //After executing this line the string contains garbage on the end example1="abcde<IqMŸÖð"

String^ example2 = gcnew String( pstr3,0,sizeof(byte_data));    //String Example 2 correctly contains the expected string even if it isn't null terminated
Peter H
  • 871
  • 1
  • 10
  • 33
  • 1
    `sizeof(pstr3)+1` is not correct, it will only be 5 by coincidence (only when `sizeof(char *) == 4`, which depends on your architecture). I think you wanted `sizeof(byte_data)`. – ta.speot.is Jan 28 '13 at 07:19
  • @ta.speot.is Thanks Nice Spot.. This fixed the display bug/carriage return problem. Not exactly sure why but looks good. I have edited the post above. – Peter H Jan 28 '13 at 07:23