kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[wine] / dlls / crypt32 / str.c
1 /*
2  * Copyright 2006 Juan Lang for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wincrypt.h"
22 #include "wine/debug.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
25
26 DWORD WINAPI CertRDNValueToStrA(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
27  LPSTR psz, DWORD csz)
28 {
29     DWORD ret = 0;
30
31     TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
32
33     switch (dwValueType)
34     {
35     case CERT_RDN_ANY_TYPE:
36         break;
37     case CERT_RDN_PRINTABLE_STRING:
38     case CERT_RDN_IA5_STRING:
39         if (!psz || !csz)
40             ret = pValue->cbData;
41         else
42         {
43             DWORD chars = min(pValue->cbData, csz - 1);
44
45             if (chars)
46             {
47                 memcpy(psz, pValue->pbData, chars);
48                 ret += chars;
49                 csz -= chars;
50             }
51         }
52         break;
53     default:
54         FIXME("string type %ld unimplemented\n", dwValueType);
55     }
56     if (psz && csz)
57     {
58         *(psz + ret) = '\0';
59         csz--;
60         ret++;
61     }
62     else
63         ret++;
64     return ret;
65 }
66
67 DWORD WINAPI CertRDNValueToStrW(DWORD dwValueType, PCERT_RDN_VALUE_BLOB pValue,
68  LPWSTR psz, DWORD csz)
69 {
70     DWORD ret = 0;
71
72     TRACE("(%ld, %p, %p, %ld)\n", dwValueType, pValue, psz, csz);
73
74     switch (dwValueType)
75     {
76     case CERT_RDN_ANY_TYPE:
77         break;
78     case CERT_RDN_PRINTABLE_STRING:
79     case CERT_RDN_IA5_STRING:
80         if (!psz || !csz)
81             ret = pValue->cbData;
82         else
83         {
84             DWORD chars = min(pValue->cbData, csz - 1);
85
86             if (chars)
87             {
88                 DWORD i;
89
90                 for (i = 0; i < chars; i++)
91                     psz[i] = pValue->pbData[i];
92                 ret += chars;
93                 csz -= chars;
94             }
95         }
96         break;
97     default:
98         FIXME("string type %ld unimplemented\n", dwValueType);
99     }
100     if (psz && csz)
101     {
102         *(psz + ret) = '\0';
103         csz--;
104         ret++;
105     }
106     else
107         ret++;
108     return ret;
109 }
110
111
112 DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
113  DWORD dwStrType, LPSTR psz, DWORD csz)
114 {
115     static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
116      CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
117     static const char commaSep[] = ", ";
118     static const char semiSep[] = "; ";
119     static const char crlfSep[] = "\r\n";
120     static const char plusSep[] = " + ";
121     static const char spaceSep[] = " ";
122     DWORD ret = 0, bytes = 0;
123     BOOL bRet;
124     CERT_NAME_INFO *info;
125
126     TRACE("(%ld, %p, %p, %ld)\n", dwCertEncodingType, pName, psz, csz);
127     if (dwStrType & unsupportedFlags)
128         FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);
129
130     bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
131      pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
132     if (bRet)
133     {
134         DWORD i, j, sepLen, rdnSepLen;
135         LPCSTR sep, rdnSep;
136
137         if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
138             sep = semiSep;
139         else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
140             sep = crlfSep;
141         else
142             sep = commaSep;
143         sepLen = strlen(sep);
144         if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
145             rdnSep = spaceSep;
146         else
147             rdnSep = plusSep;
148         rdnSepLen = strlen(rdnSep);
149         for (i = 0; ret < csz && i < info->cRDN; i++)
150         {
151             for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++)
152             {
153                 DWORD chars;
154
155                 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
156                 {
157                     /* - 1 is needed to account for the NULL terminator. */
158                     chars = min(
159                      lstrlenA(info->rgRDN[i].rgRDNAttr[j].pszObjId),
160                      csz - ret - 1);
161                     if (psz && chars)
162                         memcpy(psz + ret, info->rgRDN[i].rgRDNAttr[j].pszObjId,
163                          chars);
164                     ret += chars;
165                     csz -= chars;
166                     if (csz > 1)
167                     {
168                         if (psz)
169                             *(psz + ret) = '=';
170                         ret++;
171                         csz--;
172                     }
173                 }
174                 /* FIXME: handle quoting */
175                 chars = CertRDNValueToStrA(
176                  info->rgRDN[i].rgRDNAttr[j].dwValueType, 
177                  &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
178                  csz - ret - 1);
179                 if (chars)
180                     ret += chars - 1;
181                 if (j < info->rgRDN[i].cRDNAttr - 1)
182                 {
183                     if (psz && ret < csz - rdnSepLen - 1)
184                         memcpy(psz + ret, rdnSep, rdnSepLen);
185                     ret += rdnSepLen;
186                 }
187             }
188             if (i < info->cRDN - 1)
189             {
190                 if (psz && ret < csz - sepLen - 1)
191                     memcpy(psz + ret, sep, sepLen);
192                 ret += sepLen;
193             }
194         }
195         LocalFree(info);
196     }
197     if (psz && csz)
198     {
199         *(psz + ret) = '\0';
200         csz--;
201         ret++;
202     }
203     else
204         ret++;
205     return ret;
206 }
207
208 DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
209  DWORD dwStrType, LPWSTR psz, DWORD csz)
210 {
211     static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
212      CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
213     static const WCHAR commaSep[] = { ',',' ',0 };
214     static const WCHAR semiSep[] = { ';',' ',0 };
215     static const WCHAR crlfSep[] = { '\r','\n',0 };
216     static const WCHAR plusSep[] = { ' ','+',' ',0 };
217     static const WCHAR spaceSep[] = { ' ',0 };
218     DWORD ret = 0, bytes = 0;
219     BOOL bRet;
220     CERT_NAME_INFO *info;
221
222     TRACE("(%ld, %p, %p, %ld)\n", dwCertEncodingType, pName, psz, csz);
223     if (dwStrType & unsupportedFlags)
224         FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);
225
226     bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
227      pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
228     if (bRet)
229     {
230         DWORD i, j, sepLen, rdnSepLen;
231         LPCWSTR sep, rdnSep;
232
233         if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
234             sep = semiSep;
235         else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
236             sep = crlfSep;
237         else
238             sep = commaSep;
239         sepLen = lstrlenW(sep);
240         if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
241             rdnSep = spaceSep;
242         else
243             rdnSep = plusSep;
244         rdnSepLen = lstrlenW(rdnSep);
245         for (i = 0; ret < csz && i < info->cRDN; i++)
246         {
247             for (j = 0; ret < csz && j < info->rgRDN[i].cRDNAttr; j++)
248             {
249                 DWORD chars;
250
251                 if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
252                 {
253                     /* - 1 is needed to account for the NULL terminator. */
254                     chars = min(
255                      lstrlenA(info->rgRDN[i].rgRDNAttr[j].pszObjId),
256                      csz - ret - 1);
257                     if (psz && chars)
258                     {
259                         DWORD k;
260
261                         for (k = 0; k < chars; k++)
262                             *(psz + ret + k) =
263                              info->rgRDN[i].rgRDNAttr[j].pszObjId[k];
264                     }
265                     ret += chars;
266                     csz -= chars;
267                     if (csz > 1)
268                     {
269                         if (psz)
270                             *(psz + ret) = '=';
271                         ret++;
272                         csz--;
273                     }
274                 }
275                 /* FIXME: handle quoting */
276                 chars = CertRDNValueToStrW(
277                  info->rgRDN[i].rgRDNAttr[j].dwValueType, 
278                  &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
279                  csz - ret - 1);
280                 if (chars)
281                     ret += chars - 1;
282                 if (j < info->rgRDN[i].cRDNAttr - 1)
283                 {
284                     if (psz && ret < csz - rdnSepLen - 1)
285                         memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR));
286                     ret += rdnSepLen;
287                 }
288             }
289             if (i < info->cRDN - 1)
290             {
291                 if (psz && ret < csz - sepLen - 1)
292                     memcpy(psz + ret, sep, sepLen * sizeof(WCHAR));
293                 ret += sepLen;
294             }
295         }
296         LocalFree(info);
297     }
298     if (psz && csz)
299     {
300         *(psz + ret) = '\0';
301         csz--;
302         ret++;
303     }
304     else
305         ret++;
306     return ret;
307 }