Removed W->A from DEFWND_ImmIsUIMessageW.
[wine] / dlls / mapi32 / prop.c
1 /*
2  * Property functions
3  *
4  * Copyright 2004 Jon Griffiths
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winreg.h"
27 #include "winerror.h"
28 #include "winternl.h"
29 #include "objbase.h"
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33 #include "mapival.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(mapi);
36
37 BOOL WINAPI FBadRglpszA(LPSTR*,ULONG);
38 BOOL WINAPI FBadRglpszW(LPWSTR*,ULONG);
39
40 /* Internal: Check if a property value array is invalid */
41 static inline ULONG PROP_BadArray(LPSPropValue lpProp, size_t elemSize)
42 {
43     return IsBadReadPtr(lpProp->Value.MVi.lpi, lpProp->Value.MVi.cValues * elemSize);
44 }
45
46 /*************************************************************************
47  * PropCopyMore@16 (MAPI32.76)
48  *
49  * Copy a property value.
50  *
51  * PARAMS
52  *  lpDest [O] Destination for the copied value
53  *  lpSrc  [I] Property value to copy to lpDest
54  *  lpMore [I] Linked memory allocation function (pass MAPIAllocateMore())
55  *  lpOrig [I] Original allocation to which memory will be linked
56  *
57  * RETURNS
58  *  Success: S_OK. lpDest contains a deep copy of lpSrc.
59  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
60  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
61  *
62  * NOTES
63  *  Any elements within the property returned should not be individually
64  *  freed, as they will be freed when lpOrig is.
65  */
66 SCODE WINAPI PropCopyMore(LPSPropValue lpDest, LPSPropValue lpSrc, 
67                           ALLOCATEMORE *lpMore, LPVOID lpOrig)
68 {
69     ULONG ulLen, i;
70     SCODE scode = S_OK;
71     
72     TRACE("(%p,%p,%p,%p)\n", lpDest, lpSrc, lpMore, lpOrig);
73     
74     if (!lpDest || IsBadWritePtr(lpDest, sizeof(SPropValue)) ||
75         FBadProp(lpSrc) || !lpMore)
76         return MAPI_E_INVALID_PARAMETER;
77
78     /* Shallow copy first, this is sufficient for properties without pointers */
79     *lpDest = *lpSrc;
80         
81    switch (PROP_TYPE(lpSrc->ulPropTag))
82     {
83     case PT_CLSID:
84         scode = lpMore(sizeof(GUID), lpOrig, (LPVOID*)&lpDest->Value.lpguid);
85         if (SUCCEEDED(scode))
86             memcpy(lpDest->Value.lpguid, lpSrc->Value.lpguid, sizeof(GUID));
87         break;
88     case PT_STRING8:
89         ulLen = lstrlenA(lpSrc->Value.lpszA) + 1u;
90         scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszA);
91         if (SUCCEEDED(scode))
92             memcpy(lpDest->Value.lpszA, lpSrc->Value.lpszA, ulLen);
93         break;
94     case PT_UNICODE:
95         ulLen = (strlenW(lpSrc->Value.lpszW) + 1u) * sizeof(WCHAR);
96         scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszW);
97         if (SUCCEEDED(scode))
98             memcpy(lpDest->Value.lpszW, lpSrc->Value.lpszW, ulLen);
99         break;
100     case PT_BINARY:
101         scode = lpMore(lpSrc->Value.bin.cb, lpOrig, (LPVOID*)&lpDest->Value.bin.lpb);
102         if (SUCCEEDED(scode))
103             memcpy(lpDest->Value.bin.lpb, lpSrc->Value.bin.lpb, lpSrc->Value.bin.cb);
104         break;
105     default:
106         if (lpSrc->ulPropTag & MV_FLAG)
107         {
108             ulLen = UlPropSize(lpSrc);
109
110             if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_STRING8 ||
111                 PROP_TYPE(lpSrc->ulPropTag) == PT_MV_UNICODE)
112             {
113                 /* UlPropSize doesn't account for the string pointers */
114                 ulLen += lpSrc->Value.MVszA.cValues * sizeof(char*);
115             }
116             else if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_BINARY)
117             {
118                /* UlPropSize doesn't account for the SBinary structs */
119                ulLen += lpSrc->Value.MVbin.cValues * sizeof(SBinary);
120             }
121
122             lpDest->Value.MVi.cValues = lpSrc->Value.MVi.cValues;
123             scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.MVi.lpi);
124             if (FAILED(scode))
125                 break;
126
127             /* Note that we could allocate the memory for each value in a 
128              * multi-value property seperately, however if an allocation failed
129              * we would be left with a bunch of allocated memory, which (while
130              * not really leaked) is unusable until lpOrig is freed. So for 
131              * strings and binary arrays we make a single allocation for all 
132              * of the data. This is consistent since individual elements can't
133              * be freed anyway.
134              */
135                                 
136             switch (PROP_TYPE(lpSrc->ulPropTag))
137             {
138             case PT_MV_STRING8:
139             {
140                 char *lpNextStr = (char*)(lpDest->Value.MVszA.lppszA + 
141                                           lpDest->Value.MVszA.cValues);
142                 
143                 for (i = 0; i < lpSrc->Value.MVszA.cValues; i++)
144                 {
145                     ULONG ulStrLen = lstrlenA(lpSrc->Value.MVszA.lppszA[i]) + 1u;
146                     
147                     lpDest->Value.MVszA.lppszA[i] = lpNextStr;
148                     memcpy(lpNextStr, lpSrc->Value.MVszA.lppszA[i], ulStrLen);
149                     lpNextStr += ulStrLen;
150                 }                    
151                 break;
152             }
153             case PT_MV_UNICODE:
154             {
155                 WCHAR *lpNextStr = (WCHAR*)(lpDest->Value.MVszW.lppszW + 
156                                             lpDest->Value.MVszW.cValues);
157
158                 for (i = 0; i < lpSrc->Value.MVszW.cValues; i++)
159                 {
160                     ULONG ulStrLen = strlenW(lpSrc->Value.MVszW.lppszW[i]) + 1u;
161                     
162                     lpDest->Value.MVszW.lppszW[i] = lpNextStr;
163                     memcpy(lpNextStr, lpSrc->Value.MVszW.lppszW[i], ulStrLen * sizeof(WCHAR));
164                     lpNextStr += ulStrLen;
165                 }                    
166                 break;
167             }
168             case PT_MV_BINARY:
169             {
170                 LPBYTE lpNext = (LPBYTE)(lpDest->Value.MVbin.lpbin + 
171                                          lpDest->Value.MVbin.cValues);
172                 
173                 for (i = 0; i < lpSrc->Value.MVszW.cValues; i++)
174                 {
175                     lpDest->Value.MVbin.lpbin[i].cb = lpSrc->Value.MVbin.lpbin[i].cb;
176                     lpDest->Value.MVbin.lpbin[i].lpb = lpNext;
177                     memcpy(lpNext, lpSrc->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb);
178                     lpNext += lpDest->Value.MVbin.lpbin[i].cb;
179                 }                    
180                 break;
181             }
182             default:
183                 /* No embedded pointers, just copy the data over */
184                 memcpy(lpDest->Value.MVi.lpi, lpSrc->Value.MVi.lpi, ulLen);
185                 break;
186             }
187             break;
188         }
189     }
190     return scode;
191 }
192  
193 /*************************************************************************
194  * UlPropSize@4 (MAPI32.77)
195  *
196  * Determine the size of a property in bytes.
197  *
198  * PARAMS
199  *  lpProp [I] Property to determine the size of
200  *
201  * RETURNS
202  *  Success: The size of the value in lpProp.
203  *  Failure: 0, if a multi-value (array) property is invalid or the type of lpProp
204  *           is unknown.
205  *
206  * NOTES
207  *  - The size returned does not include the size of the SPropValue struct
208  *    or the size of the array of pointers for multi-valued properties that
209  *    contain pointers (such as PT_MV_STRING8 or PT-MV_UNICODE).
210  *  - MSDN incorrectly states that this function returns MAPI_E_CALL_FAILED if
211  *    lpProp is invalid. In reality no checking is performed and this function
212  *    will crash if passed an invalid property, or return 0 if the property
213  *    type is PT_OBJECT or is unknown.
214  */
215 ULONG WINAPI UlPropSize(LPSPropValue lpProp)
216 {
217     ULONG ulRet = 1u, i;
218
219     TRACE("(%p)\n", lpProp);
220
221     switch (PROP_TYPE(lpProp->ulPropTag))
222     {
223     case PT_MV_I2:       ulRet = lpProp->Value.MVi.cValues;
224     case PT_BOOLEAN:
225     case PT_I2:          ulRet *= sizeof(USHORT);
226                          break;
227     case PT_MV_I4:       ulRet = lpProp->Value.MVl.cValues;
228     case PT_ERROR:
229     case PT_I4:          ulRet *= sizeof(LONG);
230                          break;
231     case PT_MV_I8:       ulRet = lpProp->Value.MVli.cValues;
232     case PT_I8:          ulRet *= sizeof(LONG64);
233                          break;
234     case PT_MV_R4:       ulRet = lpProp->Value.MVflt.cValues;
235     case PT_R4:          ulRet *= sizeof(float);
236                          break;
237     case PT_MV_APPTIME:
238     case PT_MV_R8:       ulRet = lpProp->Value.MVdbl.cValues;
239     case PT_APPTIME:
240     case PT_R8:          ulRet *= sizeof(double);
241                          break;
242     case PT_MV_CURRENCY: ulRet = lpProp->Value.MVcur.cValues;
243     case PT_CURRENCY:    ulRet *= sizeof(CY);
244                          break;
245     case PT_MV_SYSTIME:  ulRet = lpProp->Value.MVft.cValues;
246     case PT_SYSTIME:     ulRet *= sizeof(FILETIME);
247                          break;
248     case PT_MV_CLSID:    ulRet = lpProp->Value.MVguid.cValues;
249     case PT_CLSID:       ulRet *= sizeof(GUID);
250                          break;
251     case PT_MV_STRING8:  ulRet = 0u;
252                          for (i = 0; i < lpProp->Value.MVszA.cValues; i++)
253                              ulRet += (lstrlenA(lpProp->Value.MVszA.lppszA[i]) + 1u);
254                          break;
255     case PT_STRING8:     ulRet = lstrlenA(lpProp->Value.lpszA) + 1u;
256                          break;
257     case PT_MV_UNICODE:  ulRet = 0u;
258                          for (i = 0; i < lpProp->Value.MVszW.cValues; i++)
259                              ulRet += (strlenW(lpProp->Value.MVszW.lppszW[i]) + 1u);
260                          ulRet *= sizeof(WCHAR);
261                          break;
262     case PT_UNICODE:     ulRet = (lstrlenW(lpProp->Value.lpszW) + 1u) * sizeof(WCHAR);
263                          break;
264     case PT_MV_BINARY:   ulRet = 0u;
265                          for (i = 0; i < lpProp->Value.MVbin.cValues; i++)
266                              ulRet += lpProp->Value.MVbin.lpbin[i].cb;
267                          break;
268     case PT_BINARY:      ulRet = lpProp->Value.bin.cb;
269                          break;
270         break;
271     case PT_OBJECT:
272     default:             ulRet = 0u;
273                          break;
274     }
275
276     return ulRet;
277 }
278
279 /*************************************************************************
280  * FPropContainsProp@12 (MAPI32.78)
281  *
282  * Find a property with a given property tag in a property array.
283  *
284  * PARAMS
285  *  lpHaystack [I] Property to match to
286  *  lpNeedle   [I] Property to find in lpHaystack
287  *  ulFuzzy    [I] Flags controlling match type and strictness (FL_* flags from "mapidefs.h")
288  *
289  * RETURNS
290  *  TRUE, if lpNeedle matches lpHaystack according to the criteria of ulFuzzy.
291  *
292  * NOTES
293  *  Only property types of PT_STRING8 and PT_BINARY are handled by this function.
294  */
295 BOOL WINAPI FPropContainsProp(LPSPropValue lpHaystack, LPSPropValue lpNeedle, ULONG ulFuzzy)
296 {
297     TRACE("(%p,%p,0x%08lx)\n", lpHaystack, lpNeedle, ulFuzzy);
298
299     if (FBadProp(lpHaystack) || FBadProp(lpNeedle) ||
300         PROP_TYPE(lpHaystack->ulPropTag) != PROP_TYPE(lpNeedle->ulPropTag))
301         return FALSE;
302
303     /* FIXME: Do later versions support Unicode as well? */
304
305     if (PROP_TYPE(lpHaystack->ulPropTag) == PT_STRING8)
306     {
307         DWORD dwFlags = 0, dwNeedleLen, dwHaystackLen;
308
309         if (ulFuzzy & FL_IGNORECASE)
310             dwFlags |= NORM_IGNORECASE;
311         if (ulFuzzy & FL_IGNORENONSPACE)
312             dwFlags |= NORM_IGNORENONSPACE;
313         if (ulFuzzy & FL_LOOSE)
314             dwFlags |= (NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS);
315
316         dwNeedleLen = lstrlenA(lpNeedle->Value.lpszA);
317         dwHaystackLen = lstrlenA(lpHaystack->Value.lpszA);
318
319         if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX)
320         {
321             if (dwNeedleLen <= dwHaystackLen &&
322                 CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
323                                lpHaystack->Value.lpszA, dwNeedleLen,
324                                lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
325                 return TRUE; /* needle is a prefix of haystack */
326         }
327         else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING)
328         {
329             LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD) = StrChrA;
330             LPSTR lpStr = lpHaystack->Value.lpszA;
331
332             if (dwFlags & NORM_IGNORECASE)
333                 pStrChrFn = StrChrIA;
334
335             while ((lpStr = pStrChrFn(lpStr, *lpNeedle->Value.lpszA)) != NULL)
336             {
337                 dwHaystackLen -= (lpStr - lpHaystack->Value.lpszA);
338                 if (dwNeedleLen <= dwHaystackLen &&
339                     CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
340                                lpStr, dwNeedleLen,
341                                lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
342                     return TRUE; /* needle is a substring of haystack */
343                 lpStr++;
344             }
345         }
346         else if (CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
347                                 lpHaystack->Value.lpszA, dwHaystackLen,
348                                 lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
349             return TRUE; /* full string match */
350     }
351     else if (PROP_TYPE(lpHaystack->ulPropTag) == PT_BINARY)
352     {
353         if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX)
354         {
355             if (lpNeedle->Value.bin.cb <= lpHaystack->Value.bin.cb &&
356                 !memcmp(lpNeedle->Value.bin.lpb, lpHaystack->Value.bin.lpb,
357                         lpNeedle->Value.bin.cb))
358                 return TRUE; /* needle is a prefix of haystack */
359         }
360         else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING)
361         {
362             ULONG ulLen = lpHaystack->Value.bin.cb;
363             LPBYTE lpb = lpHaystack->Value.bin.lpb;
364
365             while ((lpb = memchr(lpb, *lpNeedle->Value.bin.lpb, ulLen)) != NULL)
366             {
367                 ulLen = lpHaystack->Value.bin.cb - (lpb - lpHaystack->Value.bin.lpb);
368                 if (lpNeedle->Value.bin.cb <= ulLen &&
369                     !memcmp(lpNeedle->Value.bin.lpb, lpb, lpNeedle->Value.bin.cb))
370                     return TRUE; /* needle is a substring of haystack */
371                 lpb++;
372             }
373         }
374         else if (!LPropCompareProp(lpHaystack, lpNeedle))
375             return TRUE; /* needle is an exact match with haystack */
376
377     }
378     return FALSE;
379 }
380
381 /*************************************************************************
382  * FPropCompareProp@12 (MAPI32.79)
383  *
384  * Compare two properties.
385  *
386  * PARAMS
387  *  lpPropLeft  [I] Left hand property to compare to lpPropRight
388  *  ulOp        [I] Comparison operator (RELOP_* enum from "mapidefs.h")
389  *  lpPropRight [I] Right hand property to compare to lpPropLeft
390  *
391  * RETURNS
392  *  TRUE, if the comparison is true, FALSE otherwise.
393  */
394 BOOL WINAPI FPropCompareProp(LPSPropValue lpPropLeft, ULONG ulOp, LPSPropValue lpPropRight)
395 {
396     LONG iCmp;
397
398     TRACE("(%p,%ld,%p)\n", lpPropLeft, ulOp, lpPropRight);
399
400     if (ulOp > RELOP_RE || FBadProp(lpPropLeft) || FBadProp(lpPropRight))
401         return FALSE;
402
403     if (ulOp == RELOP_RE)
404     {
405         FIXME("Comparison operator RELOP_RE not yet implemented!\n");
406         return FALSE;
407     }
408
409     iCmp = LPropCompareProp(lpPropLeft, lpPropRight);
410
411     switch (ulOp)
412     {
413     case RELOP_LT: return iCmp <  0 ? TRUE : FALSE;
414     case RELOP_LE: return iCmp <= 0 ? TRUE : FALSE;
415     case RELOP_GT: return iCmp >  0 ? TRUE : FALSE;
416     case RELOP_GE: return iCmp >= 0 ? TRUE : FALSE;
417     case RELOP_EQ: return iCmp == 0 ? TRUE : FALSE;
418     case RELOP_NE: return iCmp != 0 ? TRUE : FALSE;
419     }
420     return FALSE;
421 }
422
423 /*************************************************************************
424  * LPropCompareProp@8 (MAPI32.80)
425  *
426  * Compare two properties.
427  *
428  * PARAMS
429  *  lpPropLeft  [I] Left hand property to compare to lpPropRight
430  *  lpPropRight [I] Right hand property to compare to lpPropLeft
431  *
432  * RETURNS
433  *  An integer less than, equal to or greater than 0, indicating that
434  *  lpszStr is less than, the same, or greater than lpszComp.
435  */
436 LONG WINAPI LPropCompareProp(LPSPropValue lpPropLeft, LPSPropValue lpPropRight)
437 {
438     LONG iRet;
439
440     TRACE("(%p->0x%08lx,%p->0x%08lx)\n", lpPropLeft, lpPropLeft->ulPropTag,
441           lpPropRight, lpPropRight->ulPropTag);
442
443     /* If the properties are not the same, sort by property type */
444     if (PROP_TYPE(lpPropLeft->ulPropTag) != PROP_TYPE(lpPropRight->ulPropTag))
445         return (LONG)PROP_TYPE(lpPropLeft->ulPropTag) - (LONG)PROP_TYPE(lpPropRight->ulPropTag);
446
447     switch (PROP_TYPE(lpPropLeft->ulPropTag))
448     {
449     case PT_UNSPECIFIED:
450     case PT_NULL:
451         return 0; /* NULLs are equal */
452     case PT_I2:
453         return lpPropLeft->Value.i - lpPropRight->Value.i;
454     case PT_I4:
455         return lpPropLeft->Value.l - lpPropRight->Value.l;
456     case PT_I8:
457         if (lpPropLeft->Value.li.QuadPart > lpPropRight->Value.li.QuadPart)
458             return 1;
459         if (lpPropLeft->Value.li.QuadPart == lpPropRight->Value.li.QuadPart)
460             return 0;
461         return -1;
462     case PT_R4:
463         if (lpPropLeft->Value.flt > lpPropRight->Value.flt)
464             return 1;
465         if (lpPropLeft->Value.flt == lpPropRight->Value.flt)
466             return 0;
467         return -1;
468     case PT_APPTIME:
469     case PT_R8:
470         if (lpPropLeft->Value.dbl > lpPropRight->Value.dbl)
471             return 1;
472         if (lpPropLeft->Value.dbl == lpPropRight->Value.dbl)
473             return 0;
474         return -1;
475     case PT_CURRENCY:
476         if (lpPropLeft->Value.cur.int64 > lpPropRight->Value.cur.int64)
477             return 1;
478         if (lpPropLeft->Value.cur.int64 == lpPropRight->Value.cur.int64)
479             return 0;
480         return -1;
481     case PT_SYSTIME:
482         return CompareFileTime(&lpPropLeft->Value.ft, &lpPropRight->Value.ft);
483     case PT_BOOLEAN:
484         return (lpPropLeft->Value.b ? 1 : 0) - (lpPropRight->Value.b ? 1 : 0);
485     case PT_BINARY:
486         if (lpPropLeft->Value.bin.cb == lpPropRight->Value.bin.cb)
487             iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb,
488                           lpPropLeft->Value.bin.cb);
489         else
490         {
491             iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb,
492                           min(lpPropLeft->Value.bin.cb, lpPropRight->Value.bin.cb));
493
494             if (!iRet)
495                 iRet = lpPropLeft->Value.bin.cb - lpPropRight->Value.bin.cb;
496         }
497         return iRet;
498     case PT_STRING8:
499         return lstrcmpA(lpPropLeft->Value.lpszA, lpPropRight->Value.lpszA);
500     case PT_UNICODE:
501         return strcmpW(lpPropLeft->Value.lpszW, lpPropRight->Value.lpszW);
502     case PT_ERROR:
503         if (lpPropLeft->Value.err > lpPropRight->Value.err)
504             return 1;
505         if (lpPropLeft->Value.err == lpPropRight->Value.err)
506             return 0;
507         return -1;
508     case PT_CLSID:
509         return memcmp(lpPropLeft->Value.lpguid, lpPropRight->Value.lpguid,
510                       sizeof(GUID));
511     }
512     FIXME("Unhandled property type %ld", PROP_TYPE(lpPropLeft->ulPropTag));
513     return 0;
514 }
515
516 /*************************************************************************
517  * HrGetOneProp@8 (MAPI32.135)
518  *
519  * Get a property value from an IMAPIProp object.
520  *
521  * PARAMS
522  *  lpIProp   [I] IMAPIProp object to get the property value in
523  *  ulPropTag [I] Property tag of the property to get
524  *  lppProp   [O] Destination for the returned property
525  *
526  * RETURNS
527  *  Success: S_OK. *lppProp contains the property value requested.
528  *  Failure: MAPI_E_NOT_FOUND, if no property value has the tag given by ulPropTag.
529  */
530 HRESULT WINAPI HrGetOneProp(LPMAPIPROP lpIProp, ULONG ulPropTag, LPSPropValue *lppProp)
531 {
532     SPropTagArray pta;
533     ULONG ulCount;
534     HRESULT hRet;
535
536     TRACE("(%p,%ld,%p)\n", lpIProp, ulPropTag, lppProp);
537
538     pta.cValues = 1u;
539     pta.aulPropTag[0] = ulPropTag;
540     hRet = IMAPIProp_GetProps(lpIProp, &pta, 0u, &ulCount, lppProp);
541     if (hRet == MAPI_W_ERRORS_RETURNED)
542     {
543         MAPIFreeBuffer(*lppProp);
544         *lppProp = NULL;
545         hRet = MAPI_E_NOT_FOUND;
546     }
547     return hRet;
548 }
549
550 /*************************************************************************
551  * HrSetOneProp@8 (MAPI32.136)
552  *
553  * Set a property value in an IMAPIProp object.
554  *
555  * PARAMS
556  *  lpIProp [I] IMAPIProp object to set the property value in
557  *  lpProp  [I] Property value to set
558  *
559  * RETURNS
560  *  Success: S_OK. The value in lpProp is set in lpIProp.
561  *  Failure: An error result from IMAPIProp_SetProps().
562  */
563 HRESULT WINAPI HrSetOneProp(LPMAPIPROP lpIProp, LPSPropValue lpProp)
564 {
565     TRACE("(%p,%p)\n", lpIProp, lpProp);
566
567     return IMAPIProp_SetProps(lpIProp, 1u, lpProp, NULL);
568 }
569
570 /*************************************************************************
571  * FPropExists@8 (MAPI32.137)
572  *
573  * Find a property with a given property tag in an IMAPIProp object.
574  *
575  * PARAMS
576  *  lpIProp   [I] IMAPIProp object to find the property tag in
577  *  ulPropTag [I] Property tag to find
578  *
579  * RETURNS
580  *  TRUE, if ulPropTag matches a property held in lpIProp,
581  *  FALSE, otherwise.
582  *
583  * NOTES
584  *  if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
585  *  Ids need to match for a successful match to occur.
586  */
587  BOOL WINAPI FPropExists(LPMAPIPROP lpIProp, ULONG ulPropTag)
588  {
589     BOOL bRet = FALSE;
590
591     TRACE("(%p,%ld)\n", lpIProp, ulPropTag);
592
593     if (lpIProp)
594     {
595         LPSPropTagArray lpTags;
596         ULONG i;
597
598         if (FAILED(IMAPIProp_GetPropList(lpIProp, 0u, &lpTags)))
599             return FALSE;
600
601         for (i = 0; i < lpTags->cValues; i++)
602         {
603             if (!FBadPropTag(lpTags->aulPropTag[i]) &&
604                 (lpTags->aulPropTag[i] == ulPropTag ||
605                  (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED &&
606                   PROP_ID(lpTags->aulPropTag[i]) == lpTags->aulPropTag[i])))
607             {
608                 bRet = TRUE;
609                 break;
610             }
611         }
612         MAPIFreeBuffer(lpTags);
613     }
614     return bRet;
615 }
616
617 /*************************************************************************
618  * PpropFindProp@12 (MAPI32.138)
619  *
620  * Find a property with a given property tag in a property array.
621  *
622  * PARAMS
623  *  lpProps   [I] Property array to search
624  *  cValues   [I] Number of properties in lpProps
625  *  ulPropTag [I] Property tag to find
626  *
627  * RETURNS
628  *  A pointer to the matching property, or NULL if none was found.
629  *
630  * NOTES
631  *  if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
632  *  Ids need to match for a successful match to occur.
633  */
634 LPSPropValue WINAPI PpropFindProp(LPSPropValue lpProps, ULONG cValues, ULONG ulPropTag)
635 {
636     TRACE("(%p,%ld,%ld)\n", lpProps, cValues, ulPropTag);
637
638     if (lpProps && cValues)
639     {
640         ULONG i;
641         for (i = 0; i < cValues; i++)
642         {
643             if (!FBadPropTag(lpProps[i].ulPropTag) &&
644                 (lpProps[i].ulPropTag == ulPropTag ||
645                  (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED &&
646                   PROP_ID(lpProps[i].ulPropTag) == PROP_ID(ulPropTag))))
647                 return &lpProps[i];
648         }
649     }
650     return NULL;
651 }
652
653 /*************************************************************************
654  * FreePadrlist@4 (MAPI32.139)
655  *
656  * Free the memory used by an address book list.
657  *
658  * PARAMS
659  *  lpAddrs [I] Address book list to free
660  *
661  * RETURNS
662  *  Nothing.
663  */
664 VOID WINAPI FreePadrlist(LPADRLIST lpAddrs)
665 {
666     TRACE("(%p)\n", lpAddrs);
667
668     /* Structures are binary compatible; use the same implementation */
669     return FreeProws((LPSRowSet)lpAddrs);
670 }
671
672 /*************************************************************************
673  * FreeProws@4 (MAPI32.140)
674  *
675  * Free the memory used by a row set.
676  *
677  * PARAMS
678  *  lpRowSet [I] Row set to free
679  *
680  * RETURNS
681  *  Nothing.
682  */
683 VOID WINAPI FreeProws(LPSRowSet lpRowSet)
684 {
685     TRACE("(%p)\n", lpRowSet);
686
687     if (lpRowSet)
688     {
689         ULONG i;
690
691         for (i = 0; i < lpRowSet->cRows; i++)
692             MAPIFreeBuffer(lpRowSet->aRow[i].lpProps);
693
694         MAPIFreeBuffer(lpRowSet);
695     }
696 }
697
698 /*************************************************************************
699  * ScCountProps@12 (MAPI32.170)
700  *
701  * Validate and determine the length of an array of properties.
702  *
703  * PARAMS
704  *  iCount  [I] Length of the lpProps array
705  *  lpProps [I] Array of properties to validate/size
706  *  pcBytes [O] If non-NULL, destination for the size of the property array
707  *
708  * RETURNS
709  *  Success: S_OK. If pcBytes is non-NULL, it contains the size of the propery array.
710  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid or validation
711  *           of the property array fails.
712  */
713 SCODE WINAPI ScCountProps(INT iCount, LPSPropValue lpProps, ULONG *pcBytes)
714 {
715     ULONG i, ulCount = iCount, ulBytes = 0;
716
717     TRACE("(%d,%p,%p)\n", iCount, lpProps, pcBytes);
718
719     if (iCount <= 0 || !lpProps ||
720         IsBadReadPtr(lpProps, iCount * sizeof(SPropValue)))
721         return MAPI_E_INVALID_PARAMETER;
722
723     for (i = 0; i < ulCount; i++)
724     {
725         ULONG ulPropSize = 0;
726         
727         if (FBadProp(&lpProps[i]) || lpProps[i].ulPropTag == PROP_ID_NULL ||
728             lpProps[i].ulPropTag == PROP_ID_INVALID)
729             return MAPI_E_INVALID_PARAMETER;
730
731             if (PROP_TYPE(lpProps[i].ulPropTag) != PT_OBJECT)
732             {
733                 ulPropSize = UlPropSize(&lpProps[i]);
734                 if (!ulPropSize)
735                     return MAPI_E_INVALID_PARAMETER;
736             }
737             
738             switch (PROP_TYPE(lpProps[i].ulPropTag))
739             {
740             case PT_STRING8:
741             case PT_UNICODE:
742             case PT_CLSID:
743             case PT_BINARY:
744             case PT_MV_I2:       
745             case PT_MV_I4:       
746             case PT_MV_I8:       
747             case PT_MV_R4:       
748             case PT_MV_R8:       
749             case PT_MV_CURRENCY: 
750             case PT_MV_SYSTIME:  
751             case PT_MV_APPTIME:
752                 ulPropSize += sizeof(SPropValue);
753                 break;
754             case PT_MV_CLSID:
755                 ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue);
756                 break;
757             case PT_MV_STRING8:
758             case PT_MV_UNICODE:
759                 ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue);
760                 break;
761             case PT_MV_BINARY:
762                 ulPropSize += lpProps[i].Value.MVbin.cValues * sizeof(SBinary) + sizeof(SPropValue);
763                 break;
764             default:
765                 ulPropSize = sizeof(SPropValue);
766                 break;
767             }
768             ulBytes += ulPropSize;
769     }
770     if (pcBytes)
771         *pcBytes = ulBytes;
772
773     return S_OK;
774 }
775
776 /*************************************************************************
777  * ScCopyProps@16 (MAPI32.171)
778  *
779  * Copy an array of property values into a buffer suited for serialisation.
780  *
781  * PARAMS
782  *  cValues   [I] Number of properties in lpProps
783  *  lpProps   [I] Property array to copy
784  *  lpDst     [O] Destination for the serialised data
785  *  lpCount   [O] If non-NULL, destination for the number of bytes of data written to lpDst
786  *
787  * RETURNS
788  *  Success: S_OK. lpDst contains the serialised data from lpProps.
789  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
790  *
791  * NOTES
792  *  The resulting property value array is stored in a contigous block starting at lpDst.
793  */
794 SCODE WINAPI ScCopyProps(int cValues, LPSPropValue lpProps, LPVOID lpDst, ULONG *lpCount)
795 {
796     LPSPropValue lpDest = (LPSPropValue)lpDst;
797     char *lpDataDest = (char *)(lpDest + cValues);
798     ULONG ulLen, i, iter;
799
800     TRACE("(%d,%p,%p,%p)\n", cValues, lpProps, lpDst, lpCount);
801
802     if (!lpProps || cValues < 0 || !lpDest)
803         return MAPI_E_INVALID_PARAMETER;
804
805     memcpy(lpDst, lpProps, cValues * sizeof(SPropValue));
806
807     for (iter = 0; iter < cValues; iter++)
808     {
809         switch (PROP_TYPE(lpProps->ulPropTag))
810         {
811         case PT_CLSID:
812             lpDest->Value.lpguid = (LPGUID)lpDataDest;
813             memcpy(lpDest->Value.lpguid, lpProps->Value.lpguid, sizeof(GUID));
814             lpDataDest += sizeof(GUID);
815             break;
816         case PT_STRING8:
817             ulLen = lstrlenA(lpProps->Value.lpszA) + 1u;
818             lpDest->Value.lpszA = lpDataDest;
819             memcpy(lpDest->Value.lpszA, lpProps->Value.lpszA, ulLen);
820             lpDataDest += ulLen;
821             break;
822         case PT_UNICODE:
823             ulLen = (strlenW(lpProps->Value.lpszW) + 1u) * sizeof(WCHAR);
824             lpDest->Value.lpszW = (LPWSTR)lpDataDest;
825             memcpy(lpDest->Value.lpszW, lpProps->Value.lpszW, ulLen);
826             lpDataDest += ulLen;
827             break;
828         case PT_BINARY:
829             lpDest->Value.bin.lpb = (LPBYTE)lpDataDest;
830             memcpy(lpDest->Value.bin.lpb, lpProps->Value.bin.lpb, lpProps->Value.bin.cb);
831             lpDataDest += lpProps->Value.bin.cb;
832             break;
833         default:
834             if (lpProps->ulPropTag & MV_FLAG)
835             {
836                 lpDest->Value.MVi.cValues = lpProps->Value.MVi.cValues;
837                 /* Note: Assignment uses lppszA but covers all cases by union aliasing */
838                 lpDest->Value.MVszA.lppszA = (char**)lpDataDest;
839
840                 switch (PROP_TYPE(lpProps->ulPropTag))
841                 {
842                 case PT_MV_STRING8:
843                 {
844                     lpDataDest += lpProps->Value.MVszA.cValues * sizeof(char *);
845
846                     for (i = 0; i < lpProps->Value.MVszA.cValues; i++)
847                     {
848                         ULONG ulStrLen = lstrlenA(lpProps->Value.MVszA.lppszA[i]) + 1u;
849
850                         lpDest->Value.MVszA.lppszA[i] = lpDataDest;
851                         memcpy(lpDataDest, lpProps->Value.MVszA.lppszA[i], ulStrLen);
852                         lpDataDest += ulStrLen;
853                     }
854                     break;
855                 }
856                 case PT_MV_UNICODE:
857                 {
858                     lpDataDest += lpProps->Value.MVszW.cValues * sizeof(WCHAR *);
859
860                     for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
861                     {
862                         ULONG ulStrLen = (strlenW(lpProps->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
863
864                         lpDest->Value.MVszW.lppszW[i] = (LPWSTR)lpDataDest;
865                         memcpy(lpDataDest, lpProps->Value.MVszW.lppszW[i], ulStrLen);
866                         lpDataDest += ulStrLen;
867                     }
868                     break;
869                 }
870                 case PT_MV_BINARY:
871                 {
872                     lpDataDest += lpProps->Value.MVszW.cValues * sizeof(SBinary);
873
874                     for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
875                     {
876                         lpDest->Value.MVbin.lpbin[i].cb = lpProps->Value.MVbin.lpbin[i].cb;
877                         lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)lpDataDest;
878                         memcpy(lpDataDest, lpProps->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb);
879                         lpDataDest += lpDest->Value.MVbin.lpbin[i].cb;
880                     }
881                     break;
882                 }
883                 default:
884                     /* No embedded pointers, just copy the data over */
885                     ulLen = UlPropSize(lpProps);
886                     memcpy(lpDest->Value.MVi.lpi, lpProps->Value.MVi.lpi, ulLen);
887                     lpDataDest += ulLen;
888                     break;
889                 }
890                 break;
891             }
892         }
893         lpDest++;
894         lpProps++;
895     }
896     if (lpCount)
897         *lpCount = lpDataDest - (char *)lpDst;
898
899     return S_OK;
900 }
901
902 /*************************************************************************
903  * ScRelocProps@20 (MAPI32.172)
904  *
905  * Relocate the pointers in an array of property values after it has been copied.
906  *
907  * PARAMS
908  *  cValues   [I] Number of properties in lpProps
909  *  lpProps   [O] Property array to relocate the pointers in.
910  *  lpOld     [I] Position where the data was copied from
911  *  lpNew     [I] Position where the data was copied to
912  *  lpCount   [O] If non-NULL, destination for the number of bytes of data at lpDst
913  *
914  * RETURNS
915  *  Success: S_OK. Any pointers in lpProps are relocated.
916  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
917  *
918  * NOTES
919  *  MSDN states that this function can be used for serialisation by passing
920  *  NULL as either lpOld or lpNew, thus converting any pointers in lpProps
921  *  between offsets and pointers. This does not work in native (it crashes),
922  *  and cannot be made to work in Wine because the original interface design 
923  *  is deficient. The only use left for this function is to remap pointers
924  *  in a contigous property array that has been copied with memcpy() to another
925  *  memory location.
926  */
927 SCODE WINAPI ScRelocProps(int cValues, LPSPropValue lpProps, LPVOID lpOld, 
928                           LPVOID lpNew, ULONG *lpCount)
929 {
930     static const BOOL bBadPtr = TRUE; /* Windows bug - Assumes source is bad */
931     LPSPropValue lpDest = (LPSPropValue)lpProps;
932     ULONG ulCount = cValues * sizeof(SPropValue);    
933     ULONG ulLen, i, iter;
934
935     TRACE("(%d,%p,%p,%p,%p)\n", cValues, lpProps, lpOld, lpNew, lpCount);
936
937     if (!lpProps || cValues < 0 || !lpOld || !lpNew)
938         return MAPI_E_INVALID_PARAMETER;
939
940     /* The reason native doesn't work as MSDN states is that it assumes that
941      * the lpProps pointer contains valid pointers. This is obviously not
942      * true if the array is being read back from serialisation (the pointers
943      * are just offsets). Native can't actually work converting the pointers to
944      * offsets either, because it converts any array pointers to offsets then
945      * _dereferences the offset_ in order to convert the array elements!
946      *
947      * The code below would handle both cases except that the design of this
948      * function makes it impossible to know when the pointers in lpProps are
949      * valid. If both lpOld and lpNew are non-NULL, native reads the pointers
950      * after converting them, so we must do the same. Its seems this
951      * functionality was never tested by MS.
952      */
953
954 #define RELOC_PTR(p) (((char*)(p)) - (char*)lpOld + (char*)lpNew)
955
956     for (iter = 0; iter < cValues; iter++)
957     {
958         switch (PROP_TYPE(lpDest->ulPropTag))
959         {
960         case PT_CLSID:
961             lpDest->Value.lpguid = (LPGUID)RELOC_PTR(lpDest->Value.lpguid);
962             ulCount += sizeof(GUID);
963             break;
964         case PT_STRING8:
965             ulLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.lpszA) + 1u;
966             lpDest->Value.lpszA = (LPSTR)RELOC_PTR(lpDest->Value.lpszA);
967             if (bBadPtr)
968                 ulLen = lstrlenA(lpDest->Value.lpszA) + 1u;
969             ulCount += ulLen;
970             break;
971         case PT_UNICODE:
972             ulLen = bBadPtr ? 0 : (lstrlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
973             lpDest->Value.lpszW = (LPWSTR)RELOC_PTR(lpDest->Value.lpszW);
974             if (bBadPtr)
975                 ulLen = (strlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
976             ulCount += ulLen;
977             break;
978         case PT_BINARY:
979             lpDest->Value.bin.lpb = (LPBYTE)RELOC_PTR(lpDest->Value.bin.lpb);
980             ulCount += lpDest->Value.bin.cb;
981             break;
982         default:
983             if (lpDest->ulPropTag & MV_FLAG)
984             {
985                 /* Since we have to access the array elements, don't map the
986                  * array unless it is invalid (otherwise, map it at the end)
987                  */
988                 if (bBadPtr)
989                     lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
990
991                 switch (PROP_TYPE(lpProps->ulPropTag))
992                 {
993                 case PT_MV_STRING8:
994                 {
995                     ulCount += lpDest->Value.MVszA.cValues * sizeof(char *);
996
997                     for (i = 0; i < lpDest->Value.MVszA.cValues; i++)
998                     {
999                         ULONG ulStrLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
1000
1001                         lpDest->Value.MVszA.lppszA[i] = (LPSTR)RELOC_PTR(lpDest->Value.MVszA.lppszA[i]);
1002                         if (bBadPtr)
1003                             ulStrLen = lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
1004                         ulCount += ulStrLen;
1005                     }
1006                     break;
1007                 }
1008                 case PT_MV_UNICODE:
1009                 {
1010                     ulCount += lpDest->Value.MVszW.cValues * sizeof(WCHAR *);
1011
1012                     for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
1013                     {
1014                         ULONG ulStrLen = bBadPtr ? 0 : (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
1015
1016                         lpDest->Value.MVszW.lppszW[i] = (LPWSTR)RELOC_PTR(lpDest->Value.MVszW.lppszW[i]);
1017                         if (bBadPtr)
1018                             ulStrLen = (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
1019                         ulCount += ulStrLen;
1020                     }
1021                     break;
1022                 }
1023                 case PT_MV_BINARY:
1024                 {
1025                     ulCount += lpDest->Value.MVszW.cValues * sizeof(SBinary);
1026
1027                     for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
1028                     {
1029                         lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)RELOC_PTR(lpDest->Value.MVbin.lpbin[i].lpb);
1030                         ulCount += lpDest->Value.MVbin.lpbin[i].cb;
1031                     }
1032                     break;
1033                 }
1034                 default:
1035                     ulCount += UlPropSize(lpDest);
1036                     break;
1037                 }
1038                 if (!bBadPtr)
1039                     lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
1040                 break;
1041             }
1042         }
1043         lpDest++;
1044     }
1045     if (lpCount)
1046         *lpCount = ulCount;
1047
1048     return S_OK;
1049 }
1050
1051 /*************************************************************************
1052  * LpValFindProp@12 (MAPI32.173)
1053  *
1054  * Find a property with a given property id in a property array.
1055  *
1056  * PARAMS
1057  *  ulPropTag [I] Property tag containing property id to find
1058  *  cValues   [I] Number of properties in lpProps
1059  *  lpProps   [I] Property array to search
1060  *
1061  * RETURNS
1062  *  A pointer to the matching property, or NULL if none was found.
1063  *
1064  * NOTES
1065  *  This function matches only on the property id and does not care if the
1066  *  property types differ.
1067  */
1068 LPSPropValue WINAPI LpValFindProp(ULONG ulPropTag, ULONG cValues, LPSPropValue lpProps)
1069 {
1070     TRACE("(%ld,%ld,%p)\n", ulPropTag, cValues, lpProps);
1071
1072     if (lpProps && cValues)
1073     {
1074         ULONG i;
1075         for (i = 0; i < cValues; i++)
1076         {
1077             if (PROP_ID(ulPropTag) == PROP_ID(lpProps[i].ulPropTag))
1078                 return &lpProps[i];
1079         }
1080     }
1081     return NULL;
1082 }
1083
1084 /*************************************************************************
1085  * ScDupPropset@16 (MAPI32.174)
1086  *
1087  * Duplicate a property value array into a contigous block of memory.
1088  *
1089  * PARAMS
1090  *  cValues   [I] Number of properties in lpProps
1091  *  lpProps   [I] Property array to duplicate
1092  *  lpAlloc   [I] Memory allocation function, use MAPIAllocateBuffer()
1093  *  lpNewProp [O] Destination for the newly duplicated property value array
1094  *
1095  * RETURNS
1096  *  Success: S_OK. *lpNewProp contains the duplicated array.
1097  *  Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
1098  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
1099  */
1100 SCODE WINAPI ScDupPropset(int cValues, LPSPropValue lpProps,
1101                           LPALLOCATEBUFFER lpAlloc, LPSPropValue *lpNewProp)
1102 {
1103     ULONG ulCount;
1104     SCODE sc;
1105
1106     TRACE("(%d,%p,%p,%p)\n", cValues, lpProps, lpAlloc, lpNewProp);
1107
1108     sc = ScCountProps(cValues, lpProps, &ulCount);
1109     if (SUCCEEDED(sc))
1110     {
1111         sc = lpAlloc(ulCount, (LPVOID*)lpNewProp);
1112         if (SUCCEEDED(sc))
1113             sc = ScCopyProps(cValues, lpProps, *lpNewProp, &ulCount);
1114     }
1115     return sc;
1116 }
1117
1118 /*************************************************************************
1119  * FBadRglpszA@8 (MAPI32.175)
1120  *
1121  * Determine if an array of strings is invalid
1122  *
1123  * PARAMS
1124  *  lppszStrs [I] Array of strings to check
1125  *  ulCount   [I] Number of strings in lppszStrs
1126  *
1127  * RETURNS
1128  *  TRUE, if lppszStrs is invalid, FALSE otherwise.
1129  */
1130 BOOL WINAPI FBadRglpszA(LPSTR *lppszStrs, ULONG ulCount)
1131 {
1132     ULONG i;
1133
1134     TRACE("(%p,%ld)\n", lppszStrs, ulCount);
1135
1136     if (!ulCount)
1137         return FALSE;
1138
1139     if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR)))
1140         return TRUE;
1141
1142     for (i = 0; i < ulCount; i++)
1143     {
1144         if (!lppszStrs[i] || IsBadStringPtrA(lppszStrs[i], -1))
1145             return TRUE;
1146     }
1147     return FALSE;
1148 }
1149
1150 /*************************************************************************
1151  * FBadRglpszW@8 (MAPI32.176)
1152  *
1153  * See FBadRglpszA.
1154  */
1155 BOOL WINAPI FBadRglpszW(LPWSTR *lppszStrs, ULONG ulCount)
1156 {
1157     ULONG i;
1158
1159     TRACE("(%p,%ld)\n", lppszStrs, ulCount);
1160
1161     if (!ulCount)
1162         return FALSE;
1163
1164     if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR)))
1165         return TRUE;
1166
1167     for (i = 0; i < ulCount; i++)
1168     {
1169         if (!lppszStrs[i] || IsBadStringPtrW(lppszStrs[i], -1))
1170             return TRUE;
1171     }
1172     return FALSE;
1173 }
1174
1175 /*************************************************************************
1176  * FBadRowSet@4 (MAPI32.177)
1177  *
1178  * Determine if a row is invalid
1179  *
1180  * PARAMS
1181  *  lpRow [I] Row to check
1182  *
1183  * RETURNS
1184  *  TRUE, if lpRow is invalid, FALSE otherwise.
1185  */
1186 BOOL WINAPI FBadRowSet(LPSRowSet lpRowSet)
1187 {
1188     ULONG i;
1189     TRACE("(%p)\n", lpRowSet);
1190
1191     if (!lpRowSet || IsBadReadPtr(lpRowSet, CbSRowSet(lpRowSet)))
1192         return TRUE;
1193
1194     for (i = 0; i < lpRowSet->cRows; i++)
1195     {
1196         if (FBadRow(&lpRowSet->aRow[i]))
1197             return TRUE;
1198     }
1199     return FALSE;
1200 }
1201
1202 /*************************************************************************
1203  * FBadPropTag@4 (MAPI32.179)
1204  *
1205  * Determine if a property tag is invalid
1206  *
1207  * PARAMS
1208  *  ulPropTag [I] Property tag to check
1209  *
1210  * RETURNS
1211  *  TRUE, if ulPropTag is invalid, FALSE otherwise.
1212  */
1213 ULONG WINAPI FBadPropTag(ULONG ulPropTag)
1214 {
1215     TRACE("(0x%08lx)\n", ulPropTag);
1216
1217     switch (ulPropTag & (~MV_FLAG & PROP_TYPE_MASK))
1218     {
1219     case PT_UNSPECIFIED:
1220     case PT_NULL:
1221     case PT_I2:
1222     case PT_LONG:
1223     case PT_R4:
1224     case PT_DOUBLE:
1225     case PT_CURRENCY:
1226     case PT_APPTIME:
1227     case PT_ERROR:
1228     case PT_BOOLEAN:
1229     case PT_OBJECT:
1230     case PT_I8:
1231     case PT_STRING8:
1232     case PT_UNICODE:
1233     case PT_SYSTIME:
1234     case PT_CLSID:
1235     case PT_BINARY:
1236         return FALSE;
1237     }
1238     return TRUE;
1239 }
1240
1241 /*************************************************************************
1242  * FBadRow@4 (MAPI32.180)
1243  *
1244  * Determine if a row is invalid
1245  *
1246  * PARAMS
1247  *  lpRow [I] Row to check
1248  *
1249  * RETURNS
1250  *  TRUE, if lpRow is invalid, FALSE otherwise.
1251  */
1252 ULONG WINAPI FBadRow(LPSRow lpRow)
1253 {
1254     ULONG i;
1255     TRACE("(%p)\n", lpRow);
1256
1257     if (!lpRow || IsBadReadPtr(lpRow, sizeof(SRow)) || !lpRow->lpProps ||
1258         IsBadReadPtr(lpRow->lpProps, lpRow->cValues * sizeof(SPropValue)))
1259         return TRUE;
1260
1261     for (i = 0; i < lpRow->cValues; i++)
1262     {
1263         if (FBadProp(&lpRow->lpProps[i]))
1264             return TRUE;
1265     }
1266     return FALSE;
1267 }
1268
1269 /*************************************************************************
1270  * FBadProp@4 (MAPI32.181)
1271  *
1272  * Determine if a property is invalid
1273  *
1274  * PARAMS
1275  *  lpProp [I] Property to check
1276  *
1277  * RETURNS
1278  *  TRUE, if lpProp is invalid, FALSE otherwise.
1279  */
1280 ULONG WINAPI FBadProp(LPSPropValue lpProp)
1281 {
1282     ULONG i;
1283
1284     if (!lpProp || IsBadReadPtr(lpProp, sizeof(SPropValue)) ||
1285         FBadPropTag(lpProp->ulPropTag))
1286         return TRUE;
1287
1288     switch (PROP_TYPE(lpProp->ulPropTag))
1289     {
1290     /* Single value properties containing pointers */
1291     case PT_STRING8:
1292         if (!lpProp->Value.lpszA || IsBadStringPtrA(lpProp->Value.lpszA, -1))
1293             return TRUE;
1294         break;
1295     case PT_UNICODE:
1296         if (!lpProp->Value.lpszW || IsBadStringPtrW(lpProp->Value.lpszW, -1))
1297             return TRUE;
1298         break;
1299     case PT_BINARY:
1300         if (IsBadReadPtr(lpProp->Value.bin.lpb, lpProp->Value.bin.cb))
1301             return TRUE;
1302         break;
1303     case PT_CLSID:
1304         if (IsBadReadPtr(lpProp->Value.lpguid, sizeof(GUID)))
1305             return TRUE;
1306         break;
1307
1308     /* Multiple value properties (arrays) containing no pointers */
1309     case PT_MV_I2:
1310         return PROP_BadArray(lpProp, sizeof(SHORT));
1311     case PT_MV_LONG:
1312         return PROP_BadArray(lpProp, sizeof(LONG));
1313     case PT_MV_LONGLONG:
1314         return PROP_BadArray(lpProp, sizeof(LONG64));
1315     case PT_MV_FLOAT:
1316         return PROP_BadArray(lpProp, sizeof(float));
1317     case PT_MV_SYSTIME:
1318         return PROP_BadArray(lpProp, sizeof(FILETIME));
1319     case PT_MV_APPTIME:
1320     case PT_MV_DOUBLE:
1321         return PROP_BadArray(lpProp, sizeof(double));
1322     case PT_MV_CURRENCY:
1323         return PROP_BadArray(lpProp, sizeof(CY));
1324     case PT_MV_CLSID:
1325         return PROP_BadArray(lpProp, sizeof(GUID));
1326
1327     /* Multiple value properties containing pointers */
1328     case PT_MV_STRING8:
1329         return FBadRglpszA(lpProp->Value.MVszA.lppszA,
1330                            lpProp->Value.MVszA.cValues);
1331     case PT_MV_UNICODE:
1332         return FBadRglpszW(lpProp->Value.MVszW.lppszW,
1333                            lpProp->Value.MVszW.cValues);
1334     case PT_MV_BINARY:
1335         if (PROP_BadArray(lpProp, sizeof(SBinary)))
1336             return TRUE;
1337
1338         for (i = 0; i < lpProp->Value.MVszW.cValues; i++)
1339         {
1340             if (IsBadReadPtr(lpProp->Value.MVbin.lpbin[i].lpb,
1341                              lpProp->Value.MVbin.lpbin[i].cb))
1342                 return TRUE;
1343         }
1344         break;
1345     }
1346     return FALSE;
1347 }
1348
1349 /*************************************************************************
1350  * FBadColumnSet@4 (MAPI32.182)
1351  *
1352  * Determine if an array of property tags is invalid
1353  *
1354  * PARAMS
1355  *  lpCols [I] Property tag array to check
1356  *
1357  * RETURNS
1358  *  TRUE, if lpCols is invalid, FALSE otherwise.
1359  */
1360 ULONG WINAPI FBadColumnSet(LPSPropTagArray lpCols)
1361 {
1362     ULONG ulRet = FALSE, i;
1363
1364     TRACE("(%p)\n", lpCols);
1365
1366     if (!lpCols || IsBadReadPtr(lpCols, CbSPropTagArray(lpCols)))
1367         ulRet = TRUE;
1368     else
1369     {
1370         for (i = 0; i < lpCols->cValues; i++)
1371         {
1372             if ((lpCols->aulPropTag[i] & PROP_TYPE_MASK) == PT_ERROR ||
1373                 FBadPropTag(lpCols->aulPropTag[i]))
1374             {
1375                 ulRet = TRUE;
1376                 break;
1377             }
1378         }
1379     }
1380     TRACE("Returning %s\n", ulRet ? "TRUE" : "FALSE");
1381     return ulRet;
1382 }