kodi
clix.hpp
1 // ------------------------------------------------------------------------------------------- //
2 // clix.h
3 //
4 // Marshals strings between .NET and C++ using C++/CLI (Visual C++ 2005 and later only).
5 // Faster and cleaner than the System::Interop method because it uses garbage collected memory.
6 // Use at your own leisure. No warranties whatsoever provided.
7 //
8 // Original code by Markus Ewald (http://www.nuclex.org/articles/marshaling-strings-in-cxx-cli)
9 // Updated version including several improvements suggested by Neil Hunt
10 //
11 // Licensed under the IBM CPL (free of charge, closed source commercial use is okay)
12 // ------------------------------------------------------------------------------------------- //
13 #pragma once
14 
15 #include <string>
16 #include <vcclr.h>
17 
18 // CLI extensions namespace
19 namespace clix {
20 
22  enum Encoding {
23 
29  E_ANSI,
30 
38  E_UTF8,
39 
48  E_UTF16, E_UNICODE = E_UTF16
49 
50  };
51 
52  // Ignore this if you're just scanning the headers for informations!
53  /* All this template stuff might seem like overkill, but it is well thought out and enables
54  you to use a readable and convenient call while still keeping the highest possible code
55  efficiency due to compile-time evaluation of the required conversion path.
56  */
57  namespace detail {
58 
59  // Get C++ string type for specified encoding
60  template<Encoding encoding> struct StringTypeSelector;
61  template<> struct StringTypeSelector<E_ANSI> { typedef std::string Type; };
62  template<> struct StringTypeSelector<E_UTF8> { typedef std::string Type; };
63  template<> struct StringTypeSelector<E_UTF16> { typedef std::wstring Type; };
64 
65  // Compile-time selection depending on whether a string is managed
66  template<typename StringType> struct IfManaged {
67  struct Select {
68  template<typename TrueType, typename FalseType>
69  struct Either { typedef FalseType Type; };
70  };
71  enum { Result = false };
72  };
73  template<> struct IfManaged<System::String ^> {
74  struct Select {
75  template<typename TrueType, typename FalseType>
76  struct Either { typedef TrueType Type; };
77  };
78  enum { Result = true };
79  };
80 
81  // Direction of the marshaling process
82  enum MarshalingDirection {
83  CxxFromNet,
84  NetFromCxx
85  };
86 
87  // The actual marshaling code
88  template<MarshalingDirection direction> struct StringMarshaler;
89 
90  // Marshals to .NET from C++ strings
91  template<> struct StringMarshaler<NetFromCxx> {
92 
93  template<Encoding encoding, typename SourceType>
94  static System::String ^marshal(const SourceType &string) {
95  // Constructs a std::[w]string in case someone gave us a char * to choke on
96  return marshalCxxString<encoding, SourceType>(string);
97  }
98 
99  template<Encoding encoding, typename SourceType>
100  static System::String ^marshalCxxString(
101  const typename StringTypeSelector<encoding>::Type &cxxString
102  ) {
103  typedef typename StringTypeSelector<encoding>::Type SourceStringType;
104  size_t byteCount = cxxString.length() * sizeof(SourceStringType::value_type);
105 
106  // Empty strings would cause trouble accessing the array below
107  if(byteCount == 0) {
108  return System::String::Empty;
109  }
110 
111  // Copy the C++ string contents into a managed array of bytes
112  array<unsigned char> ^bytes = gcnew array<unsigned char>(byteCount);
113  { pin_ptr<unsigned char> pinnedBytes = &bytes[0];
114  memcpy(pinnedBytes, cxxString.c_str(), byteCount);
115  }
116 
117  // Now let one of .NET's encoding classes do the rest
118  return decode<encoding>(bytes);
119  }
120 
121  private:
122  // Converts a byte array based on the selected encoding
123  template<Encoding encoding> static System::String ^decode(array<unsigned char> ^bytes);
124  template<> static System::String ^decode<E_ANSI>(array<unsigned char> ^bytes) {
125  return System::Text::Encoding::Default->GetString(bytes);
126  }
127  template<> static System::String ^decode<E_UTF8>(array<unsigned char> ^bytes) {
128  return System::Text::Encoding::UTF8->GetString(bytes);
129  }
130  template<> static System::String ^decode<E_UTF16>(array<unsigned char> ^bytes) {
131  return System::Text::Encoding::Unicode->GetString(bytes);
132  }
133  };
134 
135  // Marshals to C++ strings from .NET
136  template<> struct StringMarshaler<CxxFromNet> {
137 
138  template<Encoding encoding, typename SourceType>
139  static typename detail::StringTypeSelector<encoding>::Type marshal(
140  System::String ^string
141  ) {
142  typedef typename StringTypeSelector<encoding>::Type StringType;
143 
144  // Empty strings would cause a problem when accessing the empty managed array
145  if(string->Length == 0) {
146  return StringType();
147  }
148 
149  // First, we use .NET's encoding classes to convert the string into a byte array
150  array<unsigned char> ^bytes = encode<encoding>(string);
151 
152  // Then we construct our native string from that byte array
153  pin_ptr<unsigned char> pinnedBytes(&bytes[0]);
154  return StringType(
155  reinterpret_cast<StringType::value_type *>(static_cast<unsigned char *>(pinnedBytes)),
156  bytes->Length / sizeof(StringType::value_type)
157  );
158  }
159 
160  template<> static std::wstring marshal<E_UTF16, System::String ^>(
161  System::String ^string
162  ) {
163  // We can directly accesss the characters in the managed string
164  pin_ptr<const wchar_t> pinnedChars(::PtrToStringChars(string));
165  return std::wstring(pinnedChars, string->Length);
166  }
167 
168  private:
169  // Converts a string based on the selected encoding
170  template<Encoding encoding> static array<unsigned char> ^encode(System::String ^string);
171  template<> static array<unsigned char> ^encode<E_ANSI>(System::String ^string) {
172  return System::Text::Encoding::Default->GetBytes(string);
173  }
174  template<> static array<unsigned char> ^encode<E_UTF8>(System::String ^string) {
175  return System::Text::Encoding::UTF8->GetBytes(string);
176  }
177  template<> static array<unsigned char> ^encode<E_UTF16>(System::String ^string) {
178  return System::Text::Encoding::Unicode->GetBytes(string);
179  }
180 
181  };
182 
183  } // namespace detail
184 
185  // ----------------------------------------------------------------------------------------- //
186  // clix::marshalString()
187  // ----------------------------------------------------------------------------------------- //
196  template<Encoding encoding, typename SourceType>
199  System::String ^
200  >::Type marshalString(SourceType string) {
201 
202  // Pass on the call to our nifty template routines
204  detail::IfManaged<SourceType>::Result ? detail::CxxFromNet : detail::NetFromCxx
205  >::marshal<encoding, SourceType>(string);
206 
207  }
208 
209 } // namespace clix
Definition: Clix.h:70
Definition: Clix.h:85
Definition: EventStreamDetail.h:15
Definition: clix.hpp:60
Definition: Clix.h:19
Definition: clix.hpp:66
Definition: clix.hpp:67