xref: /reactos/sdk/lib/atl/atlconv.h (revision d955b932)
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