1 /* 2 * PROJECT: ReactOS ATL 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: String conversion 5 * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 8 #ifndef __ATLCONV_H__ 9 #define __ATLCONV_H__ 10 11 #pragma once 12 13 #include "atlbase.h" 14 15 namespace ATL 16 { 17 18 // This class does not own the string 19 template <int t_nBufferLength = 128> 20 class CA2CAEX 21 { 22 public: 23 LPCSTR m_psz; 24 CA2CAEX(_In_z_ LPCSTR psz)25 CA2CAEX(_In_z_ LPCSTR psz) : m_psz(psz) { } 26 CA2CAEX(_In_z_ LPCSTR psz,_In_ UINT nCodePage)27 CA2CAEX(_In_z_ LPCSTR psz, _In_ UINT nCodePage) : m_psz(psz) 28 { 29 UNREFERENCED_PARAMETER(nCodePage); 30 } 31 ~CA2CAEX()32 ~CA2CAEX() noexcept { } // There is nothing to free here 33 LPCSTR()34 _Ret_z_ operator LPCSTR() const noexcept { return m_psz; } 35 36 private: 37 // CA2CAEX is not copyable 38 CA2CAEX(_In_ const CA2CAEX&) noexcept = delete; 39 CA2CAEX& operator=(_In_ const CA2CAEX&) noexcept = delete; 40 }; 41 42 // This class does not own the string 43 template <int t_nBufferLength = 128> 44 class CW2CWEX 45 { 46 public: 47 LPCWSTR m_psz; 48 CW2CWEX(_In_z_ LPCWSTR psz)49 CW2CWEX(_In_z_ LPCWSTR psz) : m_psz(psz) { } 50 CW2CWEX(_In_z_ LPCWSTR psz,_In_ UINT nCodePage)51 CW2CWEX(_In_z_ LPCWSTR psz, _In_ UINT nCodePage) : m_psz(psz) 52 { 53 UNREFERENCED_PARAMETER(nCodePage); 54 } 55 ~CW2CWEX()56 ~CW2CWEX() noexcept { } // There is nothing to free here 57 LPCWSTR()58 _Ret_z_ operator LPCWSTR() const noexcept { return m_psz; } 59 60 private: 61 // CW2CWEX is not copyable 62 CW2CWEX(_In_ const CW2CWEX&) noexcept = delete; 63 CW2CWEX& operator=(_In_ const CW2CWEX&) noexcept = delete; 64 }; 65 66 template <int t_nBufferLength = 128> 67 class CA2AEX 68 { 69 public: 70 LPSTR m_psz; 71 char m_szBuffer[t_nBufferLength]; 72 CA2AEX(_In_z_ LPCSTR psz)73 CA2AEX(_In_z_ LPCSTR psz) 74 { 75 Init(psz); 76 } 77 CA2AEX(_In_z_ LPCSTR psz,_In_ UINT nCodePage)78 CA2AEX(_In_z_ LPCSTR psz, _In_ UINT nCodePage) 79 { 80 UNREFERENCED_PARAMETER(nCodePage); 81 Init(psz); 82 } 83 ~CA2AEX()84 ~CA2AEX() noexcept 85 { 86 if (m_psz != m_szBuffer) 87 free(m_psz); 88 } 89 LPSTR()90 _Ret_z_ operator LPSTR() const noexcept 91 { 92 return m_psz; 93 } 94 95 private: 96 // CA2AEX is not copyable 97 CA2AEX(_In_ const CA2AEX &) noexcept = delete; 98 CA2AEX& operator=(_In_ const CA2AEX &) noexcept = delete; 99 Init(_In_z_ LPCSTR psz)100 void Init(_In_z_ LPCSTR psz) 101 { 102 if (!psz) 103 { 104 m_psz = NULL; 105 m_szBuffer[0] = 0; 106 return; 107 } 108 int cchMax = lstrlenA(psz) + 1; 109 if (cchMax <= t_nBufferLength) 110 { 111 #ifdef _STRSAFE_H_INCLUDED_ 112 StringCchCopyA(m_szBuffer, _countof(m_szBuffer), psz); 113 #else 114 lstrcpynA(m_szBuffer, psz, _countof(m_szBuffer)); 115 #endif 116 m_psz = m_szBuffer; 117 return; 118 } 119 120 m_szBuffer[0] = 0; 121 m_psz = _strdup(psz); 122 if (!m_psz) 123 AtlThrow(E_OUTOFMEMORY); 124 } 125 }; 126 127 template <int t_nBufferLength = 128> 128 class CW2WEX 129 { 130 public: 131 LPWSTR m_psz; 132 wchar_t m_szBuffer[t_nBufferLength]; 133 CW2WEX(_In_z_ LPCWSTR psz)134 CW2WEX(_In_z_ LPCWSTR psz) 135 { 136 Init(psz); 137 } 138 CW2WEX(_In_z_ LPCWSTR psz,_In_ UINT nCodePage)139 CW2WEX(_In_z_ LPCWSTR psz, _In_ UINT nCodePage) 140 { 141 UNREFERENCED_PARAMETER(nCodePage); 142 Init(psz); 143 } 144 ~CW2WEX()145 ~CW2WEX() noexcept 146 { 147 if (m_psz != m_szBuffer) 148 free(m_psz); 149 } 150 LPWSTR()151 _Ret_z_ operator LPWSTR() const noexcept 152 { 153 return m_psz; 154 } 155 156 private: 157 // CW2WEX is not copyable 158 CW2WEX(_In_ const CW2WEX&) noexcept = delete; 159 CW2WEX& operator=(_In_ const CW2WEX&) noexcept = delete; 160 Init(_In_z_ LPCWSTR psz)161 void Init(_In_z_ LPCWSTR psz) 162 { 163 if (!psz) 164 { 165 m_psz = NULL; 166 m_szBuffer[0] = 0; 167 return; 168 } 169 int cchMax = lstrlenW(psz); 170 if (cchMax <= t_nBufferLength) 171 { 172 #ifdef _STRSAFE_H_INCLUDED_ 173 StringCchCopyW(m_szBuffer, _countof(m_szBuffer), psz); 174 #else 175 lstrcpynW(m_szBuffer, psz, _countof(m_szBuffer)); 176 #endif 177 m_psz = m_szBuffer; 178 return; 179 } 180 181 m_szBuffer[0] = 0; 182 m_psz = _wcsdup(psz); 183 if (!m_psz) 184 AtlThrow(E_OUTOFMEMORY); 185 } 186 }; 187 188 template <int t_nBufferLength = 128> 189 class CA2WEX 190 { 191 public: 192 LPWSTR m_psz; 193 wchar_t m_szBuffer[t_nBufferLength]; 194 CA2WEX(_In_z_ LPCSTR psz)195 CA2WEX(_In_z_ LPCSTR psz) 196 { 197 Init(psz, CP_ACP); 198 } 199 CA2WEX(_In_z_ LPCSTR psz,_In_ UINT nCodePage)200 CA2WEX(_In_z_ LPCSTR psz, _In_ UINT nCodePage) 201 { 202 Init(psz, nCodePage); 203 } 204 ~CA2WEX()205 ~CA2WEX() noexcept 206 { 207 if (m_psz != m_szBuffer) 208 free(m_psz); 209 } 210 LPWSTR()211 _Ret_z_ operator LPWSTR() const noexcept 212 { 213 return m_psz; 214 } 215 216 private: 217 // CA2WEX is not copyable 218 CA2WEX(_In_ const CA2WEX&) noexcept = delete; 219 CA2WEX& operator=(_In_ const CA2WEX&) noexcept = delete; 220 Init(_In_z_ LPCSTR psz,_In_ UINT nCodePage)221 void Init(_In_z_ LPCSTR psz, _In_ UINT nCodePage) 222 { 223 if (!psz) 224 { 225 m_psz = NULL; 226 m_szBuffer[0] = 0; 227 return; 228 } 229 230 #if 1 231 int cchMax = lstrlenA(psz) + 1; // This is 3 times faster 232 #else 233 int cchMax = MultiByteToWideChar(nCodePage, 0, psz, -1, NULL, 0); // It's slow 234 #endif 235 if (cchMax <= (int)_countof(m_szBuffer)) 236 { 237 // Use the static buffer 238 m_psz = m_szBuffer; 239 cchMax = _countof(m_szBuffer); 240 } 241 else 242 { 243 // Allocate a new buffer 244 m_szBuffer[0] = 0; 245 m_psz = (LPWSTR)malloc(cchMax * sizeof(WCHAR)); 246 if (!m_psz) 247 AtlThrow(E_OUTOFMEMORY); 248 } 249 250 MultiByteToWideChar(nCodePage, 0, psz, -1, m_psz, cchMax); 251 m_psz[cchMax - 1] = 0; 252 } 253 }; 254 255 template <int t_nBufferLength = 128> 256 class CW2AEX 257 { 258 public: 259 LPSTR m_psz; 260 char m_szBuffer[t_nBufferLength]; 261 CW2AEX(_In_z_ LPCWSTR psz)262 CW2AEX(_In_z_ LPCWSTR psz) 263 { 264 Init(psz, CP_ACP); 265 } 266 CW2AEX(_In_z_ LPCWSTR psz,_In_ UINT nCodePage)267 CW2AEX(_In_z_ LPCWSTR psz, _In_ UINT nCodePage) 268 { 269 Init(psz, nCodePage); 270 } 271 ~CW2AEX()272 ~CW2AEX() noexcept 273 { 274 if (m_psz != m_szBuffer) 275 free(m_psz); 276 } 277 LPSTR()278 _Ret_z_ operator LPSTR() const noexcept 279 { 280 return m_psz; 281 } 282 283 private: 284 // CW2AEX is not copyable 285 CW2AEX(_In_ const CW2AEX&) noexcept = delete; 286 CW2AEX& operator=(_In_ const CW2AEX&) noexcept = delete; 287 Init(_In_z_ LPCWSTR psz,_In_ UINT nConvertCodePage)288 void Init(_In_z_ LPCWSTR psz, _In_ UINT nConvertCodePage) 289 { 290 if (!psz) 291 { 292 m_psz = NULL; 293 m_szBuffer[0] = 0; 294 return; 295 } 296 297 // NOTE: This has a failure. 298 int cchMax = WideCharToMultiByte(nConvertCodePage, 0, psz, -1, NULL, 0, NULL, NULL); 299 if (cchMax <= (int)_countof(m_szBuffer)) 300 { 301 // Use the static buffer 302 m_psz = m_szBuffer; 303 cchMax = _countof(m_szBuffer); 304 } 305 else 306 { 307 // Allocate a new buffer 308 m_szBuffer[0] = 0; 309 m_psz = (LPSTR)malloc(cchMax * sizeof(CHAR)); 310 if (!m_psz) 311 AtlThrow(E_OUTOFMEMORY); 312 } 313 314 WideCharToMultiByte(nConvertCodePage, 0, psz, -1, m_psz, cchMax, NULL, NULL); 315 m_psz[cchMax - 1] = 0; 316 } 317 }; 318 319 typedef CA2AEX<> CA2A; 320 typedef CW2AEX<> CW2A; 321 typedef CA2WEX<> CA2W; 322 typedef CW2WEX<> CW2W; 323 typedef CA2CAEX<> CA2CA; 324 typedef CW2CWEX<> CW2CW; 325 326 #ifdef UNICODE 327 #define CA2CTEX CA2WEX 328 #define CA2TEX CA2WEX 329 #define CT2AEX CW2AEX 330 #define CT2CAEX CW2AEX 331 #define CT2CWEX CW2CWEX 332 #define CT2WEX CW2WEX 333 #define CW2CTEX CW2CWEX 334 #define CW2CTEX CW2CWEX 335 #else 336 #define CA2CTEX CA2CAEX 337 #define CA2TEX CA2AEX 338 #define CT2AEX CA2AEX 339 #define CT2CAEX CA2CAEX 340 #define CT2CWEX CA2WEX 341 #define CT2WEX CA2WEX 342 #define CW2CTEX CW2AEX 343 #define CW2TEX CW2AEX 344 #endif 345 346 } // namespace ATL 347 348 #endif // ndef __ATLCONV_H__ 349