Sync with trunk revision 63128.
[reactos.git] / dll / win32 / oleaut32 / vartype.c
1 /*
2 * Low level variant functions
3 *
4 * Copyright 2003 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(variant);
24
25 extern HMODULE hProxyDll DECLSPEC_HIDDEN;
26
27 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
28 #define CY_MULTIPLIER_F 10000.0
29 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
30 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
31
32 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' };
33 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' };
34
35 /* Copy data from one variant to another. */
36 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
37 {
38 switch (vt)
39 {
40 case VT_I1:
41 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
42 case VT_BOOL:
43 case VT_I2:
44 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
45 case VT_R4:
46 case VT_INT:
47 case VT_I4:
48 case VT_UINT:
49 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
50 case VT_R8:
51 case VT_DATE:
52 case VT_CY:
53 case VT_I8:
54 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
55 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
56 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
57 case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); break;
58 default:
59 FIXME("VT_ type %d unhandled, please report!\n", vt);
60 }
61 }
62
63 /* Macro to inline conversion from a float or double to any integer type,
64 * rounding according to the 'dutch' convention.
65 */
66 #define VARIANT_DutchRound(typ, value, res) do { \
67 double whole = value < 0 ? ceil(value) : floor(value); \
68 double fract = value - whole; \
69 if (fract > 0.5) res = (typ)whole + (typ)1; \
70 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
71 else if (fract >= 0.0) res = (typ)whole; \
72 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
73 else if (fract > -0.5) res = (typ)whole; \
74 else res = (typ)whole - (typ)1; \
75 } while(0)
76
77
78 /* Coerce VT_BSTR to a numeric type */
79 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
80 void* pOut, VARTYPE vt)
81 {
82 VARIANTARG dstVar;
83 HRESULT hRet;
84 NUMPARSE np;
85 BYTE rgb[1024];
86
87 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
88 np.cDig = sizeof(rgb) / sizeof(BYTE);
89 np.dwInFlags = NUMPRS_STD;
90
91 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
92
93 if (SUCCEEDED(hRet))
94 {
95 /* 1 << vt gives us the VTBIT constant for the destination number type */
96 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
97 if (SUCCEEDED(hRet))
98 VARIANT_CopyData(&dstVar, vt, pOut);
99 }
100 return hRet;
101 }
102
103 /* Coerce VT_DISPATCH to another type */
104 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut,
105 VARTYPE vt, DWORD dwFlags)
106 {
107 static DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
108 VARIANTARG srcVar, dstVar;
109 HRESULT hRet;
110
111 if (!pdispIn)
112 return DISP_E_BADVARTYPE;
113
114 /* Get the default 'value' property from the IDispatch */
115 VariantInit(&srcVar);
116 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
117 &emptyParams, &srcVar, NULL, NULL);
118
119 if (SUCCEEDED(hRet))
120 {
121 /* Convert the property to the requested type */
122 V_VT(&dstVar) = VT_EMPTY;
123 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
124 VariantClear(&srcVar);
125
126 if (SUCCEEDED(hRet))
127 {
128 VARIANT_CopyData(&dstVar, vt, pOut);
129 VariantClear(&srcVar);
130 }
131 }
132 else
133 hRet = DISP_E_TYPEMISMATCH;
134 return hRet;
135 }
136
137 /* Inline return type */
138 #define RETTYP static inline HRESULT
139
140
141 /* Simple compiler cast from one type to another */
142 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
143 *out = in; return S_OK; }
144
145 /* Compiler cast where input cannot be negative */
146 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
147 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
148
149 /* Compiler cast where input cannot be > some number */
150 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
151 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
152
153 /* Compiler cast where input cannot be < some number or >= some other number */
154 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
155 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
156
157 /* I1 */
158 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX)
159 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX)
160 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX)
161 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool)
162 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX)
163 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX)
164 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX)
165 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX)
166
167 /* UI1 */
168 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX)
169 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool)
170 NEGTST(BYTE, signed char, VarUI1FromI1)
171 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX)
172 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX)
173 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX)
174 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX)
175 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX)
176
177 /* I2 */
178 SIMPLE(SHORT, BYTE, VarI2FromUI1)
179 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX)
180 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool)
181 SIMPLE(SHORT, signed char, VarI2FromI1)
182 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX)
183 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX)
184 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX)
185 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX)
186
187 /* UI2 */
188 SIMPLE(USHORT, BYTE, VarUI2FromUI1)
189 NEGTST(USHORT, SHORT, VarUI2FromI2)
190 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX)
191 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool)
192 NEGTST(USHORT, signed char, VarUI2FromI1)
193 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX)
194 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX)
195 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX)
196
197 /* I4 */
198 SIMPLE(LONG, BYTE, VarI4FromUI1)
199 SIMPLE(LONG, SHORT, VarI4FromI2)
200 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool)
201 SIMPLE(LONG, signed char, VarI4FromI1)
202 SIMPLE(LONG, USHORT, VarI4FromUI2)
203 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX)
204 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX)
205 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX)
206
207 /* UI4 */
208 SIMPLE(ULONG, BYTE, VarUI4FromUI1)
209 NEGTST(ULONG, SHORT, VarUI4FromI2)
210 NEGTST(ULONG, LONG, VarUI4FromI4)
211 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool)
212 NEGTST(ULONG, signed char, VarUI4FromI1)
213 SIMPLE(ULONG, USHORT, VarUI4FromUI2)
214 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX)
215 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX)
216
217 /* I8 */
218 SIMPLE(LONG64, BYTE, VarI8FromUI1)
219 SIMPLE(LONG64, SHORT, VarI8FromI2)
220 SIMPLE(LONG64, signed char, VarI8FromI1)
221 SIMPLE(LONG64, USHORT, VarI8FromUI2)
222 SIMPLE(LONG64, ULONG, VarI8FromUI4)
223 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX)
224
225 /* UI8 */
226 SIMPLE(ULONG64, BYTE, VarUI8FromUI1)
227 NEGTST(ULONG64, SHORT, VarUI8FromI2)
228 NEGTST(ULONG64, signed char, VarUI8FromI1)
229 SIMPLE(ULONG64, USHORT, VarUI8FromUI2)
230 SIMPLE(ULONG64, ULONG, VarUI8FromUI4)
231 NEGTST(ULONG64, LONG64, VarUI8FromI8)
232
233 /* R4 (float) */
234 SIMPLE(float, BYTE, VarR4FromUI1)
235 SIMPLE(float, SHORT, VarR4FromI2)
236 SIMPLE(float, signed char, VarR4FromI1)
237 SIMPLE(float, USHORT, VarR4FromUI2)
238 SIMPLE(float, LONG, VarR4FromI4)
239 SIMPLE(float, ULONG, VarR4FromUI4)
240 SIMPLE(float, LONG64, VarR4FromI8)
241 SIMPLE(float, ULONG64, VarR4FromUI8)
242
243 /* R8 (double) */
244 SIMPLE(double, BYTE, VarR8FromUI1)
245 SIMPLE(double, SHORT, VarR8FromI2)
246 SIMPLE(double, float, VarR8FromR4)
247 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
248 SIMPLE(double, DATE, VarR8FromDate)
249 SIMPLE(double, signed char, VarR8FromI1)
250 SIMPLE(double, USHORT, VarR8FromUI2)
251 SIMPLE(double, LONG, VarR8FromI4)
252 SIMPLE(double, ULONG, VarR8FromUI4)
253 SIMPLE(double, LONG64, VarR8FromI8)
254 SIMPLE(double, ULONG64, VarR8FromUI8)
255
256
257 /* I1
258 */
259
260 /************************************************************************
261 * VarI1FromUI1 (OLEAUT32.244)
262 *
263 * Convert a VT_UI1 to a VT_I1.
264 *
265 * PARAMS
266 * bIn [I] Source
267 * pcOut [O] Destination
268 *
269 * RETURNS
270 * Success: S_OK.
271 * Failure: E_INVALIDARG, if the source value is invalid
272 * DISP_E_OVERFLOW, if the value will not fit in the destination
273 */
274 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
275 {
276 return _VarI1FromUI1(bIn, pcOut);
277 }
278
279 /************************************************************************
280 * VarI1FromI2 (OLEAUT32.245)
281 *
282 * Convert a VT_I2 to a VT_I1.
283 *
284 * PARAMS
285 * sIn [I] Source
286 * pcOut [O] Destination
287 *
288 * RETURNS
289 * Success: S_OK.
290 * Failure: E_INVALIDARG, if the source value is invalid
291 * DISP_E_OVERFLOW, if the value will not fit in the destination
292 */
293 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
294 {
295 return _VarI1FromI2(sIn, pcOut);
296 }
297
298 /************************************************************************
299 * VarI1FromI4 (OLEAUT32.246)
300 *
301 * Convert a VT_I4 to a VT_I1.
302 *
303 * PARAMS
304 * iIn [I] Source
305 * pcOut [O] Destination
306 *
307 * RETURNS
308 * Success: S_OK.
309 * Failure: E_INVALIDARG, if the source value is invalid
310 * DISP_E_OVERFLOW, if the value will not fit in the destination
311 */
312 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
313 {
314 return _VarI1FromI4(iIn, pcOut);
315 }
316
317 /************************************************************************
318 * VarI1FromR4 (OLEAUT32.247)
319 *
320 * Convert a VT_R4 to a VT_I1.
321 *
322 * PARAMS
323 * fltIn [I] Source
324 * pcOut [O] Destination
325 *
326 * RETURNS
327 * Success: S_OK.
328 * Failure: E_INVALIDARG, if the source value is invalid
329 * DISP_E_OVERFLOW, if the value will not fit in the destination
330 */
331 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
332 {
333 return VarI1FromR8(fltIn, pcOut);
334 }
335
336 /************************************************************************
337 * VarI1FromR8 (OLEAUT32.248)
338 *
339 * Convert a VT_R8 to a VT_I1.
340 *
341 * PARAMS
342 * dblIn [I] Source
343 * pcOut [O] Destination
344 *
345 * RETURNS
346 * Success: S_OK.
347 * Failure: E_INVALIDARG, if the source value is invalid
348 * DISP_E_OVERFLOW, if the value will not fit in the destination
349 *
350 * NOTES
351 * See VarI8FromR8() for details concerning rounding.
352 */
353 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
354 {
355 if (dblIn < I1_MIN - 0.5 || dblIn >= I1_MAX + 0.5)
356 return DISP_E_OVERFLOW;
357 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
358 return S_OK;
359 }
360
361 /************************************************************************
362 * VarI1FromDate (OLEAUT32.249)
363 *
364 * Convert a VT_DATE to a VT_I1.
365 *
366 * PARAMS
367 * dateIn [I] Source
368 * pcOut [O] Destination
369 *
370 * RETURNS
371 * Success: S_OK.
372 * Failure: E_INVALIDARG, if the source value is invalid
373 * DISP_E_OVERFLOW, if the value will not fit in the destination
374 */
375 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
376 {
377 return VarI1FromR8(dateIn, pcOut);
378 }
379
380 /************************************************************************
381 * VarI1FromCy (OLEAUT32.250)
382 *
383 * Convert a VT_CY to a VT_I1.
384 *
385 * PARAMS
386 * cyIn [I] Source
387 * pcOut [O] Destination
388 *
389 * RETURNS
390 * Success: S_OK.
391 * Failure: E_INVALIDARG, if the source value is invalid
392 * DISP_E_OVERFLOW, if the value will not fit in the destination
393 */
394 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
395 {
396 LONG i = I1_MAX + 1;
397
398 VarI4FromCy(cyIn, &i);
399 return _VarI1FromI4(i, pcOut);
400 }
401
402 /************************************************************************
403 * VarI1FromStr (OLEAUT32.251)
404 *
405 * Convert a VT_BSTR to a VT_I1.
406 *
407 * PARAMS
408 * strIn [I] Source
409 * lcid [I] LCID for the conversion
410 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
411 * pcOut [O] Destination
412 *
413 * RETURNS
414 * Success: S_OK.
415 * Failure: E_INVALIDARG, if the source value is invalid
416 * DISP_E_OVERFLOW, if the value will not fit in the destination
417 * DISP_E_TYPEMISMATCH, if the type cannot be converted
418 */
419 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
420 {
421 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
422 }
423
424 /************************************************************************
425 * VarI1FromDisp (OLEAUT32.252)
426 *
427 * Convert a VT_DISPATCH to a VT_I1.
428 *
429 * PARAMS
430 * pdispIn [I] Source
431 * lcid [I] LCID for conversion
432 * pcOut [O] Destination
433 *
434 * RETURNS
435 * Success: S_OK.
436 * Failure: E_INVALIDARG, if the source value is invalid
437 * DISP_E_OVERFLOW, if the value will not fit in the destination
438 * DISP_E_TYPEMISMATCH, if the type cannot be converted
439 */
440 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
441 {
442 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
443 }
444
445 /************************************************************************
446 * VarI1FromBool (OLEAUT32.253)
447 *
448 * Convert a VT_BOOL to a VT_I1.
449 *
450 * PARAMS
451 * boolIn [I] Source
452 * pcOut [O] Destination
453 *
454 * RETURNS
455 * S_OK.
456 */
457 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
458 {
459 return _VarI1FromBool(boolIn, pcOut);
460 }
461
462 /************************************************************************
463 * VarI1FromUI2 (OLEAUT32.254)
464 *
465 * Convert a VT_UI2 to a VT_I1.
466 *
467 * PARAMS
468 * usIn [I] Source
469 * pcOut [O] Destination
470 *
471 * RETURNS
472 * Success: S_OK.
473 * Failure: E_INVALIDARG, if the source value is invalid
474 * DISP_E_OVERFLOW, if the value will not fit in the destination
475 */
476 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
477 {
478 return _VarI1FromUI2(usIn, pcOut);
479 }
480
481 /************************************************************************
482 * VarI1FromUI4 (OLEAUT32.255)
483 *
484 * Convert a VT_UI4 to a VT_I1.
485 *
486 * PARAMS
487 * ulIn [I] Source
488 * pcOut [O] Destination
489 *
490 * RETURNS
491 * Success: S_OK.
492 * Failure: E_INVALIDARG, if the source value is invalid
493 * DISP_E_OVERFLOW, if the value will not fit in the destination
494 * DISP_E_TYPEMISMATCH, if the type cannot be converted
495 */
496 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
497 {
498 return _VarI1FromUI4(ulIn, pcOut);
499 }
500
501 /************************************************************************
502 * VarI1FromDec (OLEAUT32.256)
503 *
504 * Convert a VT_DECIMAL to a VT_I1.
505 *
506 * PARAMS
507 * pDecIn [I] Source
508 * pcOut [O] Destination
509 *
510 * RETURNS
511 * Success: S_OK.
512 * Failure: E_INVALIDARG, if the source value is invalid
513 * DISP_E_OVERFLOW, if the value will not fit in the destination
514 */
515 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
516 {
517 LONG64 i64;
518 HRESULT hRet;
519
520 hRet = VarI8FromDec(pdecIn, &i64);
521
522 if (SUCCEEDED(hRet))
523 hRet = _VarI1FromI8(i64, pcOut);
524 return hRet;
525 }
526
527 /************************************************************************
528 * VarI1FromI8 (OLEAUT32.376)
529 *
530 * Convert a VT_I8 to a VT_I1.
531 *
532 * PARAMS
533 * llIn [I] Source
534 * pcOut [O] Destination
535 *
536 * RETURNS
537 * Success: S_OK.
538 * Failure: E_INVALIDARG, if the source value is invalid
539 * DISP_E_OVERFLOW, if the value will not fit in the destination
540 */
541 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
542 {
543 return _VarI1FromI8(llIn, pcOut);
544 }
545
546 /************************************************************************
547 * VarI1FromUI8 (OLEAUT32.377)
548 *
549 * Convert a VT_UI8 to a VT_I1.
550 *
551 * PARAMS
552 * ullIn [I] Source
553 * pcOut [O] Destination
554 *
555 * RETURNS
556 * Success: S_OK.
557 * Failure: E_INVALIDARG, if the source value is invalid
558 * DISP_E_OVERFLOW, if the value will not fit in the destination
559 */
560 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
561 {
562 return _VarI1FromUI8(ullIn, pcOut);
563 }
564
565 /* UI1
566 */
567
568 /************************************************************************
569 * VarUI1FromI2 (OLEAUT32.130)
570 *
571 * Convert a VT_I2 to a VT_UI1.
572 *
573 * PARAMS
574 * sIn [I] Source
575 * pbOut [O] Destination
576 *
577 * RETURNS
578 * Success: S_OK.
579 * Failure: E_INVALIDARG, if the source value is invalid
580 * DISP_E_OVERFLOW, if the value will not fit in the destination
581 */
582 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
583 {
584 return _VarUI1FromI2(sIn, pbOut);
585 }
586
587 /************************************************************************
588 * VarUI1FromI4 (OLEAUT32.131)
589 *
590 * Convert a VT_I4 to a VT_UI1.
591 *
592 * PARAMS
593 * iIn [I] Source
594 * pbOut [O] Destination
595 *
596 * RETURNS
597 * Success: S_OK.
598 * Failure: E_INVALIDARG, if the source value is invalid
599 * DISP_E_OVERFLOW, if the value will not fit in the destination
600 */
601 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
602 {
603 return _VarUI1FromI4(iIn, pbOut);
604 }
605
606 /************************************************************************
607 * VarUI1FromR4 (OLEAUT32.132)
608 *
609 * Convert a VT_R4 to a VT_UI1.
610 *
611 * PARAMS
612 * fltIn [I] Source
613 * pbOut [O] Destination
614 *
615 * RETURNS
616 * Success: S_OK.
617 * Failure: E_INVALIDARG, if the source value is invalid
618 * DISP_E_OVERFLOW, if the value will not fit in the destination
619 * DISP_E_TYPEMISMATCH, if the type cannot be converted
620 */
621 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
622 {
623 return VarUI1FromR8(fltIn, pbOut);
624 }
625
626 /************************************************************************
627 * VarUI1FromR8 (OLEAUT32.133)
628 *
629 * Convert a VT_R8 to a VT_UI1.
630 *
631 * PARAMS
632 * dblIn [I] Source
633 * pbOut [O] Destination
634 *
635 * RETURNS
636 * Success: S_OK.
637 * Failure: E_INVALIDARG, if the source value is invalid
638 * DISP_E_OVERFLOW, if the value will not fit in the destination
639 *
640 * NOTES
641 * See VarI8FromR8() for details concerning rounding.
642 */
643 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
644 {
645 if (dblIn < -0.5 || dblIn >= UI1_MAX + 0.5)
646 return DISP_E_OVERFLOW;
647 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
648 return S_OK;
649 }
650
651 /************************************************************************
652 * VarUI1FromCy (OLEAUT32.134)
653 *
654 * Convert a VT_CY to a VT_UI1.
655 *
656 * PARAMS
657 * cyIn [I] Source
658 * pbOut [O] Destination
659 *
660 * RETURNS
661 * Success: S_OK.
662 * Failure: E_INVALIDARG, if the source value is invalid
663 * DISP_E_OVERFLOW, if the value will not fit in the destination
664 *
665 * NOTES
666 * Negative values >= -5000 will be converted to 0.
667 */
668 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
669 {
670 ULONG i = UI1_MAX + 1;
671
672 VarUI4FromCy(cyIn, &i);
673 return _VarUI1FromUI4(i, pbOut);
674 }
675
676 /************************************************************************
677 * VarUI1FromDate (OLEAUT32.135)
678 *
679 * Convert a VT_DATE to a VT_UI1.
680 *
681 * PARAMS
682 * dateIn [I] Source
683 * pbOut [O] Destination
684 *
685 * RETURNS
686 * Success: S_OK.
687 * Failure: E_INVALIDARG, if the source value is invalid
688 * DISP_E_OVERFLOW, if the value will not fit in the destination
689 */
690 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
691 {
692 return VarUI1FromR8(dateIn, pbOut);
693 }
694
695 /************************************************************************
696 * VarUI1FromStr (OLEAUT32.136)
697 *
698 * Convert a VT_BSTR to a VT_UI1.
699 *
700 * PARAMS
701 * strIn [I] Source
702 * lcid [I] LCID for the conversion
703 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
704 * pbOut [O] Destination
705 *
706 * RETURNS
707 * Success: S_OK.
708 * Failure: E_INVALIDARG, if the source value is invalid
709 * DISP_E_OVERFLOW, if the value will not fit in the destination
710 * DISP_E_TYPEMISMATCH, if the type cannot be converted
711 */
712 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
713 {
714 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
715 }
716
717 /************************************************************************
718 * VarUI1FromDisp (OLEAUT32.137)
719 *
720 * Convert a VT_DISPATCH to a VT_UI1.
721 *
722 * PARAMS
723 * pdispIn [I] Source
724 * lcid [I] LCID for conversion
725 * pbOut [O] Destination
726 *
727 * RETURNS
728 * Success: S_OK.
729 * Failure: E_INVALIDARG, if the source value is invalid
730 * DISP_E_OVERFLOW, if the value will not fit in the destination
731 * DISP_E_TYPEMISMATCH, if the type cannot be converted
732 */
733 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
734 {
735 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
736 }
737
738 /************************************************************************
739 * VarUI1FromBool (OLEAUT32.138)
740 *
741 * Convert a VT_BOOL to a VT_UI1.
742 *
743 * PARAMS
744 * boolIn [I] Source
745 * pbOut [O] Destination
746 *
747 * RETURNS
748 * S_OK.
749 */
750 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
751 {
752 return _VarUI1FromBool(boolIn, pbOut);
753 }
754
755 /************************************************************************
756 * VarUI1FromI1 (OLEAUT32.237)
757 *
758 * Convert a VT_I1 to a VT_UI1.
759 *
760 * PARAMS
761 * cIn [I] Source
762 * pbOut [O] Destination
763 *
764 * RETURNS
765 * Success: S_OK.
766 * Failure: E_INVALIDARG, if the source value is invalid
767 * DISP_E_OVERFLOW, if the value will not fit in the destination
768 */
769 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
770 {
771 return _VarUI1FromI1(cIn, pbOut);
772 }
773
774 /************************************************************************
775 * VarUI1FromUI2 (OLEAUT32.238)
776 *
777 * Convert a VT_UI2 to a VT_UI1.
778 *
779 * PARAMS
780 * usIn [I] Source
781 * pbOut [O] Destination
782 *
783 * RETURNS
784 * Success: S_OK.
785 * Failure: E_INVALIDARG, if the source value is invalid
786 * DISP_E_OVERFLOW, if the value will not fit in the destination
787 */
788 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
789 {
790 return _VarUI1FromUI2(usIn, pbOut);
791 }
792
793 /************************************************************************
794 * VarUI1FromUI4 (OLEAUT32.239)
795 *
796 * Convert a VT_UI4 to a VT_UI1.
797 *
798 * PARAMS
799 * ulIn [I] Source
800 * pbOut [O] Destination
801 *
802 * RETURNS
803 * Success: S_OK.
804 * Failure: E_INVALIDARG, if the source value is invalid
805 * DISP_E_OVERFLOW, if the value will not fit in the destination
806 */
807 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
808 {
809 return _VarUI1FromUI4(ulIn, pbOut);
810 }
811
812 /************************************************************************
813 * VarUI1FromDec (OLEAUT32.240)
814 *
815 * Convert a VT_DECIMAL to a VT_UI1.
816 *
817 * PARAMS
818 * pDecIn [I] Source
819 * pbOut [O] Destination
820 *
821 * RETURNS
822 * Success: S_OK.
823 * Failure: E_INVALIDARG, if the source value is invalid
824 * DISP_E_OVERFLOW, if the value will not fit in the destination
825 */
826 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
827 {
828 LONG64 i64;
829 HRESULT hRet;
830
831 hRet = VarI8FromDec(pdecIn, &i64);
832
833 if (SUCCEEDED(hRet))
834 hRet = _VarUI1FromI8(i64, pbOut);
835 return hRet;
836 }
837
838 /************************************************************************
839 * VarUI1FromI8 (OLEAUT32.372)
840 *
841 * Convert a VT_I8 to a VT_UI1.
842 *
843 * PARAMS
844 * llIn [I] Source
845 * pbOut [O] Destination
846 *
847 * RETURNS
848 * Success: S_OK.
849 * Failure: E_INVALIDARG, if the source value is invalid
850 * DISP_E_OVERFLOW, if the value will not fit in the destination
851 */
852 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
853 {
854 return _VarUI1FromI8(llIn, pbOut);
855 }
856
857 /************************************************************************
858 * VarUI1FromUI8 (OLEAUT32.373)
859 *
860 * Convert a VT_UI8 to a VT_UI1.
861 *
862 * PARAMS
863 * ullIn [I] Source
864 * pbOut [O] Destination
865 *
866 * RETURNS
867 * Success: S_OK.
868 * Failure: E_INVALIDARG, if the source value is invalid
869 * DISP_E_OVERFLOW, if the value will not fit in the destination
870 */
871 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
872 {
873 return _VarUI1FromUI8(ullIn, pbOut);
874 }
875
876
877 /* I2
878 */
879
880 /************************************************************************
881 * VarI2FromUI1 (OLEAUT32.48)
882 *
883 * Convert a VT_UI2 to a VT_I2.
884 *
885 * PARAMS
886 * bIn [I] Source
887 * psOut [O] Destination
888 *
889 * RETURNS
890 * S_OK.
891 */
892 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
893 {
894 return _VarI2FromUI1(bIn, psOut);
895 }
896
897 /************************************************************************
898 * VarI2FromI4 (OLEAUT32.49)
899 *
900 * Convert a VT_I4 to a VT_I2.
901 *
902 * PARAMS
903 * iIn [I] Source
904 * psOut [O] Destination
905 *
906 * RETURNS
907 * Success: S_OK.
908 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
909 */
910 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
911 {
912 return _VarI2FromI4(iIn, psOut);
913 }
914
915 /************************************************************************
916 * VarI2FromR4 (OLEAUT32.50)
917 *
918 * Convert a VT_R4 to a VT_I2.
919 *
920 * PARAMS
921 * fltIn [I] Source
922 * psOut [O] Destination
923 *
924 * RETURNS
925 * Success: S_OK.
926 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
927 */
928 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
929 {
930 return VarI2FromR8(fltIn, psOut);
931 }
932
933 /************************************************************************
934 * VarI2FromR8 (OLEAUT32.51)
935 *
936 * Convert a VT_R8 to a VT_I2.
937 *
938 * PARAMS
939 * dblIn [I] Source
940 * psOut [O] Destination
941 *
942 * RETURNS
943 * Success: S_OK.
944 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
945 *
946 * NOTES
947 * See VarI8FromR8() for details concerning rounding.
948 */
949 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
950 {
951 if (dblIn < I2_MIN - 0.5 || dblIn >= I2_MAX + 0.5)
952 return DISP_E_OVERFLOW;
953 VARIANT_DutchRound(SHORT, dblIn, *psOut);
954 return S_OK;
955 }
956
957 /************************************************************************
958 * VarI2FromCy (OLEAUT32.52)
959 *
960 * Convert a VT_CY to a VT_I2.
961 *
962 * PARAMS
963 * cyIn [I] Source
964 * psOut [O] Destination
965 *
966 * RETURNS
967 * Success: S_OK.
968 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
969 */
970 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
971 {
972 LONG i = I2_MAX + 1;
973
974 VarI4FromCy(cyIn, &i);
975 return _VarI2FromI4(i, psOut);
976 }
977
978 /************************************************************************
979 * VarI2FromDate (OLEAUT32.53)
980 *
981 * Convert a VT_DATE to a VT_I2.
982 *
983 * PARAMS
984 * dateIn [I] Source
985 * psOut [O] Destination
986 *
987 * RETURNS
988 * Success: S_OK.
989 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
990 */
991 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
992 {
993 return VarI2FromR8(dateIn, psOut);
994 }
995
996 /************************************************************************
997 * VarI2FromStr (OLEAUT32.54)
998 *
999 * Convert a VT_BSTR to a VT_I2.
1000 *
1001 * PARAMS
1002 * strIn [I] Source
1003 * lcid [I] LCID for the conversion
1004 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1005 * psOut [O] Destination
1006 *
1007 * RETURNS
1008 * Success: S_OK.
1009 * Failure: E_INVALIDARG, if any parameter is invalid
1010 * DISP_E_OVERFLOW, if the value will not fit in the destination
1011 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1012 */
1013 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1014 {
1015 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1016 }
1017
1018 /************************************************************************
1019 * VarI2FromDisp (OLEAUT32.55)
1020 *
1021 * Convert a VT_DISPATCH to a VT_I2.
1022 *
1023 * PARAMS
1024 * pdispIn [I] Source
1025 * lcid [I] LCID for conversion
1026 * psOut [O] Destination
1027 *
1028 * RETURNS
1029 * Success: S_OK.
1030 * Failure: E_INVALIDARG, if pdispIn is invalid,
1031 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1032 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1033 */
1034 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1035 {
1036 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1037 }
1038
1039 /************************************************************************
1040 * VarI2FromBool (OLEAUT32.56)
1041 *
1042 * Convert a VT_BOOL to a VT_I2.
1043 *
1044 * PARAMS
1045 * boolIn [I] Source
1046 * psOut [O] Destination
1047 *
1048 * RETURNS
1049 * S_OK.
1050 */
1051 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1052 {
1053 return _VarI2FromBool(boolIn, psOut);
1054 }
1055
1056 /************************************************************************
1057 * VarI2FromI1 (OLEAUT32.205)
1058 *
1059 * Convert a VT_I1 to a VT_I2.
1060 *
1061 * PARAMS
1062 * cIn [I] Source
1063 * psOut [O] Destination
1064 *
1065 * RETURNS
1066 * S_OK.
1067 */
1068 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1069 {
1070 return _VarI2FromI1(cIn, psOut);
1071 }
1072
1073 /************************************************************************
1074 * VarI2FromUI2 (OLEAUT32.206)
1075 *
1076 * Convert a VT_UI2 to a VT_I2.
1077 *
1078 * PARAMS
1079 * usIn [I] Source
1080 * psOut [O] Destination
1081 *
1082 * RETURNS
1083 * Success: S_OK.
1084 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1085 */
1086 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1087 {
1088 return _VarI2FromUI2(usIn, psOut);
1089 }
1090
1091 /************************************************************************
1092 * VarI2FromUI4 (OLEAUT32.207)
1093 *
1094 * Convert a VT_UI4 to a VT_I2.
1095 *
1096 * PARAMS
1097 * ulIn [I] Source
1098 * psOut [O] Destination
1099 *
1100 * RETURNS
1101 * Success: S_OK.
1102 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1103 */
1104 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1105 {
1106 return _VarI2FromUI4(ulIn, psOut);
1107 }
1108
1109 /************************************************************************
1110 * VarI2FromDec (OLEAUT32.208)
1111 *
1112 * Convert a VT_DECIMAL to a VT_I2.
1113 *
1114 * PARAMS
1115 * pDecIn [I] Source
1116 * psOut [O] Destination
1117 *
1118 * RETURNS
1119 * Success: S_OK.
1120 * Failure: E_INVALIDARG, if the source value is invalid
1121 * DISP_E_OVERFLOW, if the value will not fit in the destination
1122 */
1123 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1124 {
1125 LONG64 i64;
1126 HRESULT hRet;
1127
1128 hRet = VarI8FromDec(pdecIn, &i64);
1129
1130 if (SUCCEEDED(hRet))
1131 hRet = _VarI2FromI8(i64, psOut);
1132 return hRet;
1133 }
1134
1135 /************************************************************************
1136 * VarI2FromI8 (OLEAUT32.346)
1137 *
1138 * Convert a VT_I8 to a VT_I2.
1139 *
1140 * PARAMS
1141 * llIn [I] Source
1142 * psOut [O] Destination
1143 *
1144 * RETURNS
1145 * Success: S_OK.
1146 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1147 */
1148 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1149 {
1150 return _VarI2FromI8(llIn, psOut);
1151 }
1152
1153 /************************************************************************
1154 * VarI2FromUI8 (OLEAUT32.347)
1155 *
1156 * Convert a VT_UI8 to a VT_I2.
1157 *
1158 * PARAMS
1159 * ullIn [I] Source
1160 * psOut [O] Destination
1161 *
1162 * RETURNS
1163 * Success: S_OK.
1164 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1165 */
1166 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1167 {
1168 return _VarI2FromUI8(ullIn, psOut);
1169 }
1170
1171 /* UI2
1172 */
1173
1174 /************************************************************************
1175 * VarUI2FromUI1 (OLEAUT32.257)
1176 *
1177 * Convert a VT_UI1 to a VT_UI2.
1178 *
1179 * PARAMS
1180 * bIn [I] Source
1181 * pusOut [O] Destination
1182 *
1183 * RETURNS
1184 * S_OK.
1185 */
1186 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1187 {
1188 return _VarUI2FromUI1(bIn, pusOut);
1189 }
1190
1191 /************************************************************************
1192 * VarUI2FromI2 (OLEAUT32.258)
1193 *
1194 * Convert a VT_I2 to a VT_UI2.
1195 *
1196 * PARAMS
1197 * sIn [I] Source
1198 * pusOut [O] Destination
1199 *
1200 * RETURNS
1201 * Success: S_OK.
1202 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1203 */
1204 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1205 {
1206 return _VarUI2FromI2(sIn, pusOut);
1207 }
1208
1209 /************************************************************************
1210 * VarUI2FromI4 (OLEAUT32.259)
1211 *
1212 * Convert a VT_I4 to a VT_UI2.
1213 *
1214 * PARAMS
1215 * iIn [I] Source
1216 * pusOut [O] Destination
1217 *
1218 * RETURNS
1219 * Success: S_OK.
1220 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1221 */
1222 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1223 {
1224 return _VarUI2FromI4(iIn, pusOut);
1225 }
1226
1227 /************************************************************************
1228 * VarUI2FromR4 (OLEAUT32.260)
1229 *
1230 * Convert a VT_R4 to a VT_UI2.
1231 *
1232 * PARAMS
1233 * fltIn [I] Source
1234 * pusOut [O] Destination
1235 *
1236 * RETURNS
1237 * Success: S_OK.
1238 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1239 */
1240 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1241 {
1242 return VarUI2FromR8(fltIn, pusOut);
1243 }
1244
1245 /************************************************************************
1246 * VarUI2FromR8 (OLEAUT32.261)
1247 *
1248 * Convert a VT_R8 to a VT_UI2.
1249 *
1250 * PARAMS
1251 * dblIn [I] Source
1252 * pusOut [O] Destination
1253 *
1254 * RETURNS
1255 * Success: S_OK.
1256 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1257 *
1258 * NOTES
1259 * See VarI8FromR8() for details concerning rounding.
1260 */
1261 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1262 {
1263 if (dblIn < -0.5 || dblIn >= UI2_MAX + 0.5)
1264 return DISP_E_OVERFLOW;
1265 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1266 return S_OK;
1267 }
1268
1269 /************************************************************************
1270 * VarUI2FromDate (OLEAUT32.262)
1271 *
1272 * Convert a VT_DATE to a VT_UI2.
1273 *
1274 * PARAMS
1275 * dateIn [I] Source
1276 * pusOut [O] Destination
1277 *
1278 * RETURNS
1279 * Success: S_OK.
1280 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1281 */
1282 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1283 {
1284 return VarUI2FromR8(dateIn, pusOut);
1285 }
1286
1287 /************************************************************************
1288 * VarUI2FromCy (OLEAUT32.263)
1289 *
1290 * Convert a VT_CY to a VT_UI2.
1291 *
1292 * PARAMS
1293 * cyIn [I] Source
1294 * pusOut [O] Destination
1295 *
1296 * RETURNS
1297 * Success: S_OK.
1298 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1299 *
1300 * NOTES
1301 * Negative values >= -5000 will be converted to 0.
1302 */
1303 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1304 {
1305 ULONG i = UI2_MAX + 1;
1306
1307 VarUI4FromCy(cyIn, &i);
1308 return _VarUI2FromUI4(i, pusOut);
1309 }
1310
1311 /************************************************************************
1312 * VarUI2FromStr (OLEAUT32.264)
1313 *
1314 * Convert a VT_BSTR to a VT_UI2.
1315 *
1316 * PARAMS
1317 * strIn [I] Source
1318 * lcid [I] LCID for the conversion
1319 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1320 * pusOut [O] Destination
1321 *
1322 * RETURNS
1323 * Success: S_OK.
1324 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1325 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1326 */
1327 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1328 {
1329 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1330 }
1331
1332 /************************************************************************
1333 * VarUI2FromDisp (OLEAUT32.265)
1334 *
1335 * Convert a VT_DISPATCH to a VT_UI2.
1336 *
1337 * PARAMS
1338 * pdispIn [I] Source
1339 * lcid [I] LCID for conversion
1340 * pusOut [O] Destination
1341 *
1342 * RETURNS
1343 * Success: S_OK.
1344 * Failure: E_INVALIDARG, if the source value is invalid
1345 * DISP_E_OVERFLOW, if the value will not fit in the destination
1346 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1347 */
1348 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1349 {
1350 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1351 }
1352
1353 /************************************************************************
1354 * VarUI2FromBool (OLEAUT32.266)
1355 *
1356 * Convert a VT_BOOL to a VT_UI2.
1357 *
1358 * PARAMS
1359 * boolIn [I] Source
1360 * pusOut [O] Destination
1361 *
1362 * RETURNS
1363 * S_OK.
1364 */
1365 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1366 {
1367 return _VarUI2FromBool(boolIn, pusOut);
1368 }
1369
1370 /************************************************************************
1371 * VarUI2FromI1 (OLEAUT32.267)
1372 *
1373 * Convert a VT_I1 to a VT_UI2.
1374 *
1375 * PARAMS
1376 * cIn [I] Source
1377 * pusOut [O] Destination
1378 *
1379 * RETURNS
1380 * Success: S_OK.
1381 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1382 */
1383 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1384 {
1385 return _VarUI2FromI1(cIn, pusOut);
1386 }
1387
1388 /************************************************************************
1389 * VarUI2FromUI4 (OLEAUT32.268)
1390 *
1391 * Convert a VT_UI4 to a VT_UI2.
1392 *
1393 * PARAMS
1394 * ulIn [I] Source
1395 * pusOut [O] Destination
1396 *
1397 * RETURNS
1398 * Success: S_OK.
1399 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1400 */
1401 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1402 {
1403 return _VarUI2FromUI4(ulIn, pusOut);
1404 }
1405
1406 /************************************************************************
1407 * VarUI2FromDec (OLEAUT32.269)
1408 *
1409 * Convert a VT_DECIMAL to a VT_UI2.
1410 *
1411 * PARAMS
1412 * pDecIn [I] Source
1413 * pusOut [O] Destination
1414 *
1415 * RETURNS
1416 * Success: S_OK.
1417 * Failure: E_INVALIDARG, if the source value is invalid
1418 * DISP_E_OVERFLOW, if the value will not fit in the destination
1419 */
1420 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1421 {
1422 LONG64 i64;
1423 HRESULT hRet;
1424
1425 hRet = VarI8FromDec(pdecIn, &i64);
1426
1427 if (SUCCEEDED(hRet))
1428 hRet = _VarUI2FromI8(i64, pusOut);
1429 return hRet;
1430 }
1431
1432 /************************************************************************
1433 * VarUI2FromI8 (OLEAUT32.378)
1434 *
1435 * Convert a VT_I8 to a VT_UI2.
1436 *
1437 * PARAMS
1438 * llIn [I] Source
1439 * pusOut [O] Destination
1440 *
1441 * RETURNS
1442 * Success: S_OK.
1443 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1444 */
1445 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1446 {
1447 return _VarUI2FromI8(llIn, pusOut);
1448 }
1449
1450 /************************************************************************
1451 * VarUI2FromUI8 (OLEAUT32.379)
1452 *
1453 * Convert a VT_UI8 to a VT_UI2.
1454 *
1455 * PARAMS
1456 * ullIn [I] Source
1457 * pusOut [O] Destination
1458 *
1459 * RETURNS
1460 * Success: S_OK.
1461 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1462 */
1463 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1464 {
1465 return _VarUI2FromUI8(ullIn, pusOut);
1466 }
1467
1468 /* I4
1469 */
1470
1471 /************************************************************************
1472 * VarI4FromUI1 (OLEAUT32.58)
1473 *
1474 * Convert a VT_UI1 to a VT_I4.
1475 *
1476 * PARAMS
1477 * bIn [I] Source
1478 * piOut [O] Destination
1479 *
1480 * RETURNS
1481 * S_OK.
1482 */
1483 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1484 {
1485 return _VarI4FromUI1(bIn, piOut);
1486 }
1487
1488 /************************************************************************
1489 * VarI4FromI2 (OLEAUT32.59)
1490 *
1491 * Convert a VT_I2 to a VT_I4.
1492 *
1493 * PARAMS
1494 * sIn [I] Source
1495 * piOut [O] Destination
1496 *
1497 * RETURNS
1498 * Success: S_OK.
1499 * Failure: E_INVALIDARG, if the source value is invalid
1500 * DISP_E_OVERFLOW, if the value will not fit in the destination
1501 */
1502 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1503 {
1504 return _VarI4FromI2(sIn, piOut);
1505 }
1506
1507 /************************************************************************
1508 * VarI4FromR4 (OLEAUT32.60)
1509 *
1510 * Convert a VT_R4 to a VT_I4.
1511 *
1512 * PARAMS
1513 * fltIn [I] Source
1514 * piOut [O] Destination
1515 *
1516 * RETURNS
1517 * Success: S_OK.
1518 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1519 */
1520 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1521 {
1522 return VarI4FromR8(fltIn, piOut);
1523 }
1524
1525 /************************************************************************
1526 * VarI4FromR8 (OLEAUT32.61)
1527 *
1528 * Convert a VT_R8 to a VT_I4.
1529 *
1530 * PARAMS
1531 * dblIn [I] Source
1532 * piOut [O] Destination
1533 *
1534 * RETURNS
1535 * Success: S_OK.
1536 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1537 *
1538 * NOTES
1539 * See VarI8FromR8() for details concerning rounding.
1540 */
1541 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1542 {
1543 if (dblIn < I4_MIN - 0.5 || dblIn >= I4_MAX + 0.5)
1544 return DISP_E_OVERFLOW;
1545 VARIANT_DutchRound(LONG, dblIn, *piOut);
1546 return S_OK;
1547 }
1548
1549 /************************************************************************
1550 * VarI4FromCy (OLEAUT32.62)
1551 *
1552 * Convert a VT_CY to a VT_I4.
1553 *
1554 * PARAMS
1555 * cyIn [I] Source
1556 * piOut [O] Destination
1557 *
1558 * RETURNS
1559 * Success: S_OK.
1560 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1561 */
1562 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1563 {
1564 double d = cyIn.int64 / CY_MULTIPLIER_F;
1565 return VarI4FromR8(d, piOut);
1566 }
1567
1568 /************************************************************************
1569 * VarI4FromDate (OLEAUT32.63)
1570 *
1571 * Convert a VT_DATE to a VT_I4.
1572 *
1573 * PARAMS
1574 * dateIn [I] Source
1575 * piOut [O] Destination
1576 *
1577 * RETURNS
1578 * Success: S_OK.
1579 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1580 */
1581 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1582 {
1583 return VarI4FromR8(dateIn, piOut);
1584 }
1585
1586 /************************************************************************
1587 * VarI4FromStr (OLEAUT32.64)
1588 *
1589 * Convert a VT_BSTR to a VT_I4.
1590 *
1591 * PARAMS
1592 * strIn [I] Source
1593 * lcid [I] LCID for the conversion
1594 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1595 * piOut [O] Destination
1596 *
1597 * RETURNS
1598 * Success: S_OK.
1599 * Failure: E_INVALIDARG, if any parameter is invalid
1600 * DISP_E_OVERFLOW, if the value will not fit in the destination
1601 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1602 */
1603 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1604 {
1605 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1606 }
1607
1608 /************************************************************************
1609 * VarI4FromDisp (OLEAUT32.65)
1610 *
1611 * Convert a VT_DISPATCH to a VT_I4.
1612 *
1613 * PARAMS
1614 * pdispIn [I] Source
1615 * lcid [I] LCID for conversion
1616 * piOut [O] Destination
1617 *
1618 * RETURNS
1619 * Success: S_OK.
1620 * Failure: E_INVALIDARG, if the source value is invalid
1621 * DISP_E_OVERFLOW, if the value will not fit in the destination
1622 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1623 */
1624 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1625 {
1626 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1627 }
1628
1629 /************************************************************************
1630 * VarI4FromBool (OLEAUT32.66)
1631 *
1632 * Convert a VT_BOOL to a VT_I4.
1633 *
1634 * PARAMS
1635 * boolIn [I] Source
1636 * piOut [O] Destination
1637 *
1638 * RETURNS
1639 * S_OK.
1640 */
1641 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1642 {
1643 return _VarI4FromBool(boolIn, piOut);
1644 }
1645
1646 /************************************************************************
1647 * VarI4FromI1 (OLEAUT32.209)
1648 *
1649 * Convert a VT_I1 to a VT_I4.
1650 *
1651 * PARAMS
1652 * cIn [I] Source
1653 * piOut [O] Destination
1654 *
1655 * RETURNS
1656 * S_OK.
1657 */
1658 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1659 {
1660 return _VarI4FromI1(cIn, piOut);
1661 }
1662
1663 /************************************************************************
1664 * VarI4FromUI2 (OLEAUT32.210)
1665 *
1666 * Convert a VT_UI2 to a VT_I4.
1667 *
1668 * PARAMS
1669 * usIn [I] Source
1670 * piOut [O] Destination
1671 *
1672 * RETURNS
1673 * S_OK.
1674 */
1675 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1676 {
1677 return _VarI4FromUI2(usIn, piOut);
1678 }
1679
1680 /************************************************************************
1681 * VarI4FromUI4 (OLEAUT32.211)
1682 *
1683 * Convert a VT_UI4 to a VT_I4.
1684 *
1685 * PARAMS
1686 * ulIn [I] Source
1687 * piOut [O] Destination
1688 *
1689 * RETURNS
1690 * Success: S_OK.
1691 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1692 */
1693 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1694 {
1695 return _VarI4FromUI4(ulIn, piOut);
1696 }
1697
1698 /************************************************************************
1699 * VarI4FromDec (OLEAUT32.212)
1700 *
1701 * Convert a VT_DECIMAL to a VT_I4.
1702 *
1703 * PARAMS
1704 * pDecIn [I] Source
1705 * piOut [O] Destination
1706 *
1707 * RETURNS
1708 * Success: S_OK.
1709 * Failure: E_INVALIDARG, if pdecIn is invalid
1710 * DISP_E_OVERFLOW, if the value will not fit in the destination
1711 */
1712 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1713 {
1714 LONG64 i64;
1715 HRESULT hRet;
1716
1717 hRet = VarI8FromDec(pdecIn, &i64);
1718
1719 if (SUCCEEDED(hRet))
1720 hRet = _VarI4FromI8(i64, piOut);
1721 return hRet;
1722 }
1723
1724 /************************************************************************
1725 * VarI4FromI8 (OLEAUT32.348)
1726 *
1727 * Convert a VT_I8 to a VT_I4.
1728 *
1729 * PARAMS
1730 * llIn [I] Source
1731 * piOut [O] Destination
1732 *
1733 * RETURNS
1734 * Success: S_OK.
1735 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1736 */
1737 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1738 {
1739 return _VarI4FromI8(llIn, piOut);
1740 }
1741
1742 /************************************************************************
1743 * VarI4FromUI8 (OLEAUT32.349)
1744 *
1745 * Convert a VT_UI8 to a VT_I4.
1746 *
1747 * PARAMS
1748 * ullIn [I] Source
1749 * piOut [O] Destination
1750 *
1751 * RETURNS
1752 * Success: S_OK.
1753 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1754 */
1755 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1756 {
1757 return _VarI4FromUI8(ullIn, piOut);
1758 }
1759
1760 /* UI4
1761 */
1762
1763 /************************************************************************
1764 * VarUI4FromUI1 (OLEAUT32.270)
1765 *
1766 * Convert a VT_UI1 to a VT_UI4.
1767 *
1768 * PARAMS
1769 * bIn [I] Source
1770 * pulOut [O] Destination
1771 *
1772 * RETURNS
1773 * S_OK.
1774 */
1775 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1776 {
1777 return _VarUI4FromUI1(bIn, pulOut);
1778 }
1779
1780 /************************************************************************
1781 * VarUI4FromI2 (OLEAUT32.271)
1782 *
1783 * Convert a VT_I2 to a VT_UI4.
1784 *
1785 * PARAMS
1786 * sIn [I] Source
1787 * pulOut [O] Destination
1788 *
1789 * RETURNS
1790 * Success: S_OK.
1791 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1792 */
1793 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1794 {
1795 return _VarUI4FromI2(sIn, pulOut);
1796 }
1797
1798 /************************************************************************
1799 * VarUI4FromI4 (OLEAUT32.272)
1800 *
1801 * Convert a VT_I4 to a VT_UI4.
1802 *
1803 * PARAMS
1804 * iIn [I] Source
1805 * pulOut [O] Destination
1806 *
1807 * RETURNS
1808 * Success: S_OK.
1809 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1810 */
1811 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1812 {
1813 return _VarUI4FromI4(iIn, pulOut);
1814 }
1815
1816 /************************************************************************
1817 * VarUI4FromR4 (OLEAUT32.273)
1818 *
1819 * Convert a VT_R4 to a VT_UI4.
1820 *
1821 * PARAMS
1822 * fltIn [I] Source
1823 * pulOut [O] Destination
1824 *
1825 * RETURNS
1826 * Success: S_OK.
1827 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1828 */
1829 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1830 {
1831 return VarUI4FromR8(fltIn, pulOut);
1832 }
1833
1834 /************************************************************************
1835 * VarUI4FromR8 (OLEAUT32.274)
1836 *
1837 * Convert a VT_R8 to a VT_UI4.
1838 *
1839 * PARAMS
1840 * dblIn [I] Source
1841 * pulOut [O] Destination
1842 *
1843 * RETURNS
1844 * Success: S_OK.
1845 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1846 *
1847 * NOTES
1848 * See VarI8FromR8() for details concerning rounding.
1849 */
1850 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1851 {
1852 if (dblIn < -0.5 || dblIn >= UI4_MAX + 0.5)
1853 return DISP_E_OVERFLOW;
1854 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1855 return S_OK;
1856 }
1857
1858 /************************************************************************
1859 * VarUI4FromDate (OLEAUT32.275)
1860 *
1861 * Convert a VT_DATE to a VT_UI4.
1862 *
1863 * PARAMS
1864 * dateIn [I] Source
1865 * pulOut [O] Destination
1866 *
1867 * RETURNS
1868 * Success: S_OK.
1869 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1870 */
1871 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1872 {
1873 return VarUI4FromR8(dateIn, pulOut);
1874 }
1875
1876 /************************************************************************
1877 * VarUI4FromCy (OLEAUT32.276)
1878 *
1879 * Convert a VT_CY to a VT_UI4.
1880 *
1881 * PARAMS
1882 * cyIn [I] Source
1883 * pulOut [O] Destination
1884 *
1885 * RETURNS
1886 * Success: S_OK.
1887 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1888 */
1889 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1890 {
1891 double d = cyIn.int64 / CY_MULTIPLIER_F;
1892 return VarUI4FromR8(d, pulOut);
1893 }
1894
1895 /************************************************************************
1896 * VarUI4FromStr (OLEAUT32.277)
1897 *
1898 * Convert a VT_BSTR to a VT_UI4.
1899 *
1900 * PARAMS
1901 * strIn [I] Source
1902 * lcid [I] LCID for the conversion
1903 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1904 * pulOut [O] Destination
1905 *
1906 * RETURNS
1907 * Success: S_OK.
1908 * Failure: E_INVALIDARG, if any parameter is invalid
1909 * DISP_E_OVERFLOW, if the value will not fit in the destination
1910 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1911 */
1912 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1913 {
1914 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1915 }
1916
1917 /************************************************************************
1918 * VarUI4FromDisp (OLEAUT32.278)
1919 *
1920 * Convert a VT_DISPATCH to a VT_UI4.
1921 *
1922 * PARAMS
1923 * pdispIn [I] Source
1924 * lcid [I] LCID for conversion
1925 * pulOut [O] Destination
1926 *
1927 * RETURNS
1928 * Success: S_OK.
1929 * Failure: E_INVALIDARG, if the source value is invalid
1930 * DISP_E_OVERFLOW, if the value will not fit in the destination
1931 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1932 */
1933 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1934 {
1935 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1936 }
1937
1938 /************************************************************************
1939 * VarUI4FromBool (OLEAUT32.279)
1940 *
1941 * Convert a VT_BOOL to a VT_UI4.
1942 *
1943 * PARAMS
1944 * boolIn [I] Source
1945 * pulOut [O] Destination
1946 *
1947 * RETURNS
1948 * S_OK.
1949 */
1950 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1951 {
1952 return _VarUI4FromBool(boolIn, pulOut);
1953 }
1954
1955 /************************************************************************
1956 * VarUI4FromI1 (OLEAUT32.280)
1957 *
1958 * Convert a VT_I1 to a VT_UI4.
1959 *
1960 * PARAMS
1961 * cIn [I] Source
1962 * pulOut [O] Destination
1963 *
1964 * RETURNS
1965 * Success: S_OK.
1966 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1967 */
1968 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1969 {
1970 return _VarUI4FromI1(cIn, pulOut);
1971 }
1972
1973 /************************************************************************
1974 * VarUI4FromUI2 (OLEAUT32.281)
1975 *
1976 * Convert a VT_UI2 to a VT_UI4.
1977 *
1978 * PARAMS
1979 * usIn [I] Source
1980 * pulOut [O] Destination
1981 *
1982 * RETURNS
1983 * S_OK.
1984 */
1985 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1986 {
1987 return _VarUI4FromUI2(usIn, pulOut);
1988 }
1989
1990 /************************************************************************
1991 * VarUI4FromDec (OLEAUT32.282)
1992 *
1993 * Convert a VT_DECIMAL to a VT_UI4.
1994 *
1995 * PARAMS
1996 * pDecIn [I] Source
1997 * pulOut [O] Destination
1998 *
1999 * RETURNS
2000 * Success: S_OK.
2001 * Failure: E_INVALIDARG, if pdecIn is invalid
2002 * DISP_E_OVERFLOW, if the value will not fit in the destination
2003 */
2004 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2005 {
2006 LONG64 i64;
2007 HRESULT hRet;
2008
2009 hRet = VarI8FromDec(pdecIn, &i64);
2010
2011 if (SUCCEEDED(hRet))
2012 hRet = _VarUI4FromI8(i64, pulOut);
2013 return hRet;
2014 }
2015
2016 /************************************************************************
2017 * VarUI4FromI8 (OLEAUT32.425)
2018 *
2019 * Convert a VT_I8 to a VT_UI4.
2020 *
2021 * PARAMS
2022 * llIn [I] Source
2023 * pulOut [O] Destination
2024 *
2025 * RETURNS
2026 * Success: S_OK.
2027 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2028 */
2029 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2030 {
2031 return _VarUI4FromI8(llIn, pulOut);
2032 }
2033
2034 /************************************************************************
2035 * VarUI4FromUI8 (OLEAUT32.426)
2036 *
2037 * Convert a VT_UI8 to a VT_UI4.
2038 *
2039 * PARAMS
2040 * ullIn [I] Source
2041 * pulOut [O] Destination
2042 *
2043 * RETURNS
2044 * Success: S_OK.
2045 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2046 */
2047 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2048 {
2049 return _VarUI4FromUI8(ullIn, pulOut);
2050 }
2051
2052 /* I8
2053 */
2054
2055 /************************************************************************
2056 * VarI8FromUI1 (OLEAUT32.333)
2057 *
2058 * Convert a VT_UI1 to a VT_I8.
2059 *
2060 * PARAMS
2061 * bIn [I] Source
2062 * pi64Out [O] Destination
2063 *
2064 * RETURNS
2065 * S_OK.
2066 */
2067 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2068 {
2069 return _VarI8FromUI1(bIn, pi64Out);
2070 }
2071
2072
2073 /************************************************************************
2074 * VarI8FromI2 (OLEAUT32.334)
2075 *
2076 * Convert a VT_I2 to a VT_I8.
2077 *
2078 * PARAMS
2079 * sIn [I] Source
2080 * pi64Out [O] Destination
2081 *
2082 * RETURNS
2083 * S_OK.
2084 */
2085 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2086 {
2087 return _VarI8FromI2(sIn, pi64Out);
2088 }
2089
2090 /************************************************************************
2091 * VarI8FromR4 (OLEAUT32.335)
2092 *
2093 * Convert a VT_R4 to a VT_I8.
2094 *
2095 * PARAMS
2096 * fltIn [I] Source
2097 * pi64Out [O] Destination
2098 *
2099 * RETURNS
2100 * Success: S_OK.
2101 * Failure: E_INVALIDARG, if the source value is invalid
2102 * DISP_E_OVERFLOW, if the value will not fit in the destination
2103 */
2104 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2105 {
2106 return VarI8FromR8(fltIn, pi64Out);
2107 }
2108
2109 /************************************************************************
2110 * VarI8FromR8 (OLEAUT32.336)
2111 *
2112 * Convert a VT_R8 to a VT_I8.
2113 *
2114 * PARAMS
2115 * dblIn [I] Source
2116 * pi64Out [O] Destination
2117 *
2118 * RETURNS
2119 * Success: S_OK.
2120 * Failure: E_INVALIDARG, if the source value is invalid
2121 * DISP_E_OVERFLOW, if the value will not fit in the destination
2122 *
2123 * NOTES
2124 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2125 * very high or low values will not be accurately converted.
2126 *
2127 * Numbers are rounded using Dutch rounding, as follows:
2128 *
2129 *| Fractional Part Sign Direction Example
2130 *| --------------- ---- --------- -------
2131 *| < 0.5 + Down 0.4 -> 0.0
2132 *| < 0.5 - Up -0.4 -> 0.0
2133 *| > 0.5 + Up 0.6 -> 1.0
2134 *| < 0.5 - Up -0.6 -> -1.0
2135 *| = 0.5 + Up/Down Down if even, Up if odd
2136 *| = 0.5 - Up/Down Up if even, Down if odd
2137 *
2138 * This system is often used in supermarkets.
2139 */
2140 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2141 {
2142 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2143 return DISP_E_OVERFLOW;
2144 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2145 return S_OK;
2146 }
2147
2148 /************************************************************************
2149 * VarI8FromCy (OLEAUT32.337)
2150 *
2151 * Convert a VT_CY to a VT_I8.
2152 *
2153 * PARAMS
2154 * cyIn [I] Source
2155 * pi64Out [O] Destination
2156 *
2157 * RETURNS
2158 * S_OK.
2159 *
2160 * NOTES
2161 * All negative numbers are rounded down by 1, including those that are
2162 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2163 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2164 * for details.
2165 */
2166 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2167 {
2168 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2169
2170 if (cyIn.int64 < 0)
2171 (*pi64Out)--; /* Mimic Win32 bug */
2172 else
2173 {
2174 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2175
2176 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2177 (*pi64Out)++;
2178 }
2179 return S_OK;
2180 }
2181
2182 /************************************************************************
2183 * VarI8FromDate (OLEAUT32.338)
2184 *
2185 * Convert a VT_DATE to a VT_I8.
2186 *
2187 * PARAMS
2188 * dateIn [I] Source
2189 * pi64Out [O] Destination
2190 *
2191 * RETURNS
2192 * Success: S_OK.
2193 * Failure: E_INVALIDARG, if the source value is invalid
2194 * DISP_E_OVERFLOW, if the value will not fit in the destination
2195 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2196 */
2197 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2198 {
2199 return VarI8FromR8(dateIn, pi64Out);
2200 }
2201
2202 /************************************************************************
2203 * VarI8FromStr (OLEAUT32.339)
2204 *
2205 * Convert a VT_BSTR to a VT_I8.
2206 *
2207 * PARAMS
2208 * strIn [I] Source
2209 * lcid [I] LCID for the conversion
2210 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2211 * pi64Out [O] Destination
2212 *
2213 * RETURNS
2214 * Success: S_OK.
2215 * Failure: E_INVALIDARG, if the source value is invalid
2216 * DISP_E_OVERFLOW, if the value will not fit in the destination
2217 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2218 */
2219 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2220 {
2221 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2222 }
2223
2224 /************************************************************************
2225 * VarI8FromDisp (OLEAUT32.340)
2226 *
2227 * Convert a VT_DISPATCH to a VT_I8.
2228 *
2229 * PARAMS
2230 * pdispIn [I] Source
2231 * lcid [I] LCID for conversion
2232 * pi64Out [O] Destination
2233 *
2234 * RETURNS
2235 * Success: S_OK.
2236 * Failure: E_INVALIDARG, if the source value is invalid
2237 * DISP_E_OVERFLOW, if the value will not fit in the destination
2238 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2239 */
2240 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2241 {
2242 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2243 }
2244
2245 /************************************************************************
2246 * VarI8FromBool (OLEAUT32.341)
2247 *
2248 * Convert a VT_BOOL to a VT_I8.
2249 *
2250 * PARAMS
2251 * boolIn [I] Source
2252 * pi64Out [O] Destination
2253 *
2254 * RETURNS
2255 * S_OK.
2256 */
2257 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2258 {
2259 return VarI8FromI2(boolIn, pi64Out);
2260 }
2261
2262 /************************************************************************
2263 * VarI8FromI1 (OLEAUT32.342)
2264 *
2265 * Convert a VT_I1 to a VT_I8.
2266 *
2267 * PARAMS
2268 * cIn [I] Source
2269 * pi64Out [O] Destination
2270 *
2271 * RETURNS
2272 * S_OK.
2273 */
2274 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2275 {
2276 return _VarI8FromI1(cIn, pi64Out);
2277 }
2278
2279 /************************************************************************
2280 * VarI8FromUI2 (OLEAUT32.343)
2281 *
2282 * Convert a VT_UI2 to a VT_I8.
2283 *
2284 * PARAMS
2285 * usIn [I] Source
2286 * pi64Out [O] Destination
2287 *
2288 * RETURNS
2289 * S_OK.
2290 */
2291 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2292 {
2293 return _VarI8FromUI2(usIn, pi64Out);
2294 }
2295
2296 /************************************************************************
2297 * VarI8FromUI4 (OLEAUT32.344)
2298 *
2299 * Convert a VT_UI4 to a VT_I8.
2300 *
2301 * PARAMS
2302 * ulIn [I] Source
2303 * pi64Out [O] Destination
2304 *
2305 * RETURNS
2306 * S_OK.
2307 */
2308 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2309 {
2310 return _VarI8FromUI4(ulIn, pi64Out);
2311 }
2312
2313 /************************************************************************
2314 * VarI8FromDec (OLEAUT32.345)
2315 *
2316 * Convert a VT_DECIMAL to a VT_I8.
2317 *
2318 * PARAMS
2319 * pDecIn [I] Source
2320 * pi64Out [O] Destination
2321 *
2322 * RETURNS
2323 * Success: S_OK.
2324 * Failure: E_INVALIDARG, if the source value is invalid
2325 * DISP_E_OVERFLOW, if the value will not fit in the destination
2326 */
2327 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2328 {
2329 if (!DEC_SCALE(pdecIn))
2330 {
2331 /* This decimal is just a 96 bit integer */
2332 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2333 return E_INVALIDARG;
2334
2335 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2336 return DISP_E_OVERFLOW;
2337
2338 if (DEC_SIGN(pdecIn))
2339 *pi64Out = -DEC_LO64(pdecIn);
2340 else
2341 *pi64Out = DEC_LO64(pdecIn);
2342 return S_OK;
2343 }
2344 else
2345 {
2346 /* Decimal contains a floating point number */
2347 HRESULT hRet;
2348 double dbl;
2349
2350 hRet = VarR8FromDec(pdecIn, &dbl);
2351 if (SUCCEEDED(hRet))
2352 hRet = VarI8FromR8(dbl, pi64Out);
2353 return hRet;
2354 }
2355 }
2356
2357 /************************************************************************
2358 * VarI8FromUI8 (OLEAUT32.427)
2359 *
2360 * Convert a VT_UI8 to a VT_I8.
2361 *
2362 * PARAMS
2363 * ullIn [I] Source
2364 * pi64Out [O] Destination
2365 *
2366 * RETURNS
2367 * Success: S_OK.
2368 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2369 */
2370 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2371 {
2372 return _VarI8FromUI8(ullIn, pi64Out);
2373 }
2374
2375 /* UI8
2376 */
2377
2378 /************************************************************************
2379 * VarUI8FromI8 (OLEAUT32.428)
2380 *
2381 * Convert a VT_I8 to a VT_UI8.
2382 *
2383 * PARAMS
2384 * ulIn [I] Source
2385 * pui64Out [O] Destination
2386 *
2387 * RETURNS
2388 * Success: S_OK.
2389 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2390 */
2391 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2392 {
2393 return _VarUI8FromI8(llIn, pui64Out);
2394 }
2395
2396 /************************************************************************
2397 * VarUI8FromUI1 (OLEAUT32.429)
2398 *
2399 * Convert a VT_UI1 to a VT_UI8.
2400 *
2401 * PARAMS
2402 * bIn [I] Source
2403 * pui64Out [O] Destination
2404 *
2405 * RETURNS
2406 * S_OK.
2407 */
2408 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2409 {
2410 return _VarUI8FromUI1(bIn, pui64Out);
2411 }
2412
2413 /************************************************************************
2414 * VarUI8FromI2 (OLEAUT32.430)
2415 *
2416 * Convert a VT_I2 to a VT_UI8.
2417 *
2418 * PARAMS
2419 * sIn [I] Source
2420 * pui64Out [O] Destination
2421 *
2422 * RETURNS
2423 * S_OK.
2424 */
2425 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2426 {
2427 return _VarUI8FromI2(sIn, pui64Out);
2428 }
2429
2430 /************************************************************************
2431 * VarUI8FromR4 (OLEAUT32.431)
2432 *
2433 * Convert a VT_R4 to a VT_UI8.
2434 *
2435 * PARAMS
2436 * fltIn [I] Source
2437 * pui64Out [O] Destination
2438 *
2439 * RETURNS
2440 * Success: S_OK.
2441 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2442 */
2443 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2444 {
2445 return VarUI8FromR8(fltIn, pui64Out);
2446 }
2447
2448 /************************************************************************
2449 * VarUI8FromR8 (OLEAUT32.432)
2450 *
2451 * Convert a VT_R8 to a VT_UI8.
2452 *
2453 * PARAMS
2454 * dblIn [I] Source
2455 * pui64Out [O] Destination
2456 *
2457 * RETURNS
2458 * Success: S_OK.
2459 * Failure: E_INVALIDARG, if the source value is invalid
2460 * DISP_E_OVERFLOW, if the value will not fit in the destination
2461 *
2462 * NOTES
2463 * See VarI8FromR8() for details concerning rounding.
2464 */
2465 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2466 {
2467 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2468 return DISP_E_OVERFLOW;
2469 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2470 return S_OK;
2471 }
2472
2473 /************************************************************************
2474 * VarUI8FromCy (OLEAUT32.433)
2475 *
2476 * Convert a VT_CY to a VT_UI8.
2477 *
2478 * PARAMS
2479 * cyIn [I] Source
2480 * pui64Out [O] Destination
2481 *
2482 * RETURNS
2483 * Success: S_OK.
2484 * Failure: E_INVALIDARG, if the source value is invalid
2485 * DISP_E_OVERFLOW, if the value will not fit in the destination
2486 *
2487 * NOTES
2488 * Negative values >= -5000 will be converted to 0.
2489 */
2490 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2491 {
2492 if (cyIn.int64 < 0)
2493 {
2494 if (cyIn.int64 < -CY_HALF)
2495 return DISP_E_OVERFLOW;
2496 *pui64Out = 0;
2497 }
2498 else
2499 {
2500 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2501
2502 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2503
2504 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2505 (*pui64Out)++;
2506 }
2507 return S_OK;
2508 }
2509
2510 /************************************************************************
2511 * VarUI8FromDate (OLEAUT32.434)
2512 *
2513 * Convert a VT_DATE to a VT_UI8.
2514 *
2515 * PARAMS
2516 * dateIn [I] Source
2517 * pui64Out [O] Destination
2518 *
2519 * RETURNS
2520 * Success: S_OK.
2521 * Failure: E_INVALIDARG, if the source value is invalid
2522 * DISP_E_OVERFLOW, if the value will not fit in the destination
2523 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2524 */
2525 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2526 {
2527 return VarUI8FromR8(dateIn, pui64Out);
2528 }
2529
2530 /************************************************************************
2531 * VarUI8FromStr (OLEAUT32.435)
2532 *
2533 * Convert a VT_BSTR to a VT_UI8.
2534 *
2535 * PARAMS
2536 * strIn [I] Source
2537 * lcid [I] LCID for the conversion
2538 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2539 * pui64Out [O] Destination
2540 *
2541 * RETURNS
2542 * Success: S_OK.
2543 * Failure: E_INVALIDARG, if the source value is invalid
2544 * DISP_E_OVERFLOW, if the value will not fit in the destination
2545 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2546 */
2547 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2548 {
2549 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2550 }
2551
2552 /************************************************************************
2553 * VarUI8FromDisp (OLEAUT32.436)
2554 *
2555 * Convert a VT_DISPATCH to a VT_UI8.
2556 *
2557 * PARAMS
2558 * pdispIn [I] Source
2559 * lcid [I] LCID for conversion
2560 * pui64Out [O] Destination
2561 *
2562 * RETURNS
2563 * Success: S_OK.
2564 * Failure: E_INVALIDARG, if the source value is invalid
2565 * DISP_E_OVERFLOW, if the value will not fit in the destination
2566 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2567 */
2568 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2569 {
2570 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2571 }
2572
2573 /************************************************************************
2574 * VarUI8FromBool (OLEAUT32.437)
2575 *
2576 * Convert a VT_BOOL to a VT_UI8.
2577 *
2578 * PARAMS
2579 * boolIn [I] Source
2580 * pui64Out [O] Destination
2581 *
2582 * RETURNS
2583 * Success: S_OK.
2584 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2585 */
2586 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2587 {
2588 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2589 }
2590 /************************************************************************
2591 * VarUI8FromI1 (OLEAUT32.438)
2592 *
2593 * Convert a VT_I1 to a VT_UI8.
2594 *
2595 * PARAMS
2596 * cIn [I] Source
2597 * pui64Out [O] Destination
2598 *
2599 * RETURNS
2600 * Success: S_OK.
2601 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2602 */
2603 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2604 {
2605 return _VarUI8FromI1(cIn, pui64Out);
2606 }
2607
2608 /************************************************************************
2609 * VarUI8FromUI2 (OLEAUT32.439)
2610 *
2611 * Convert a VT_UI2 to a VT_UI8.
2612 *
2613 * PARAMS
2614 * usIn [I] Source
2615 * pui64Out [O] Destination
2616 *
2617 * RETURNS
2618 * S_OK.
2619 */
2620 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2621 {
2622 return _VarUI8FromUI2(usIn, pui64Out);
2623 }
2624
2625 /************************************************************************
2626 * VarUI8FromUI4 (OLEAUT32.440)
2627 *
2628 * Convert a VT_UI4 to a VT_UI8.
2629 *
2630 * PARAMS
2631 * ulIn [I] Source
2632 * pui64Out [O] Destination
2633 *
2634 * RETURNS
2635 * S_OK.
2636 */
2637 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2638 {
2639 return _VarUI8FromUI4(ulIn, pui64Out);
2640 }
2641
2642 /************************************************************************
2643 * VarUI8FromDec (OLEAUT32.441)
2644 *
2645 * Convert a VT_DECIMAL to a VT_UI8.
2646 *
2647 * PARAMS
2648 * pDecIn [I] Source
2649 * pui64Out [O] Destination
2650 *
2651 * RETURNS
2652 * Success: S_OK.
2653 * Failure: E_INVALIDARG, if the source value is invalid
2654 * DISP_E_OVERFLOW, if the value will not fit in the destination
2655 *
2656 * NOTES
2657 * Under native Win32, if the source value has a scale of 0, its sign is
2658 * ignored, i.e. this function takes the absolute value rather than fail
2659 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2660 * (use VarAbs() on pDecIn first if you really want this behaviour).
2661 */
2662 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2663 {
2664 if (!DEC_SCALE(pdecIn))
2665 {
2666 /* This decimal is just a 96 bit integer */
2667 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2668 return E_INVALIDARG;
2669
2670 if (DEC_HI32(pdecIn))
2671 return DISP_E_OVERFLOW;
2672
2673 if (DEC_SIGN(pdecIn))
2674 {
2675 WARN("Sign would be ignored under Win32!\n");
2676 return DISP_E_OVERFLOW;
2677 }
2678
2679 *pui64Out = DEC_LO64(pdecIn);
2680 return S_OK;
2681 }
2682 else
2683 {
2684 /* Decimal contains a floating point number */
2685 HRESULT hRet;
2686 double dbl;
2687
2688 hRet = VarR8FromDec(pdecIn, &dbl);
2689 if (SUCCEEDED(hRet))
2690 hRet = VarUI8FromR8(dbl, pui64Out);
2691 return hRet;
2692 }
2693 }
2694
2695 /* R4
2696 */
2697
2698 /************************************************************************
2699 * VarR4FromUI1 (OLEAUT32.68)
2700 *
2701 * Convert a VT_UI1 to a VT_R4.
2702 *
2703 * PARAMS
2704 * bIn [I] Source
2705 * pFltOut [O] Destination
2706 *
2707 * RETURNS
2708 * S_OK.
2709 */
2710 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2711 {
2712 return _VarR4FromUI1(bIn, pFltOut);
2713 }
2714
2715 /************************************************************************
2716 * VarR4FromI2 (OLEAUT32.69)
2717 *
2718 * Convert a VT_I2 to a VT_R4.
2719 *
2720 * PARAMS
2721 * sIn [I] Source
2722 * pFltOut [O] Destination
2723 *
2724 * RETURNS
2725 * S_OK.
2726 */
2727 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2728 {
2729 return _VarR4FromI2(sIn, pFltOut);
2730 }
2731
2732 /************************************************************************
2733 * VarR4FromI4 (OLEAUT32.70)
2734 *
2735 * Convert a VT_I4 to a VT_R4.
2736 *
2737 * PARAMS
2738 * sIn [I] Source
2739 * pFltOut [O] Destination
2740 *
2741 * RETURNS
2742 * S_OK.
2743 */
2744 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2745 {
2746 return _VarR4FromI4(lIn, pFltOut);
2747 }
2748
2749 /************************************************************************
2750 * VarR4FromR8 (OLEAUT32.71)
2751 *
2752 * Convert a VT_R8 to a VT_R4.
2753 *
2754 * PARAMS
2755 * dblIn [I] Source
2756 * pFltOut [O] Destination
2757 *
2758 * RETURNS
2759 * Success: S_OK.
2760 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2761 */
2762 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2763 {
2764 double d = dblIn < 0.0 ? -dblIn : dblIn;
2765 if (d > R4_MAX) return DISP_E_OVERFLOW;
2766 *pFltOut = dblIn;
2767 return S_OK;
2768 }
2769
2770 /************************************************************************
2771 * VarR4FromCy (OLEAUT32.72)
2772 *
2773 * Convert a VT_CY to a VT_R4.
2774 *
2775 * PARAMS
2776 * cyIn [I] Source
2777 * pFltOut [O] Destination
2778 *
2779 * RETURNS
2780 * S_OK.
2781 */
2782 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2783 {
2784 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2785 return S_OK;
2786 }
2787
2788 /************************************************************************
2789 * VarR4FromDate (OLEAUT32.73)
2790 *
2791 * Convert a VT_DATE to a VT_R4.
2792 *
2793 * PARAMS
2794 * dateIn [I] Source
2795 * pFltOut [O] Destination
2796 *
2797 * RETURNS
2798 * Success: S_OK.
2799 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2800 */
2801 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2802 {
2803 return VarR4FromR8(dateIn, pFltOut);
2804 }
2805
2806 /************************************************************************
2807 * VarR4FromStr (OLEAUT32.74)
2808 *
2809 * Convert a VT_BSTR to a VT_R4.
2810 *
2811 * PARAMS
2812 * strIn [I] Source
2813 * lcid [I] LCID for the conversion
2814 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2815 * pFltOut [O] Destination
2816 *
2817 * RETURNS
2818 * Success: S_OK.
2819 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2820 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2821 */
2822 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2823 {
2824 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2825 }
2826
2827 /************************************************************************
2828 * VarR4FromDisp (OLEAUT32.75)
2829 *
2830 * Convert a VT_DISPATCH to a VT_R4.
2831 *
2832 * PARAMS
2833 * pdispIn [I] Source
2834 * lcid [I] LCID for conversion
2835 * pFltOut [O] Destination
2836 *
2837 * RETURNS
2838 * Success: S_OK.
2839 * Failure: E_INVALIDARG, if the source value is invalid
2840 * DISP_E_OVERFLOW, if the value will not fit in the destination
2841 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2842 */
2843 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2844 {
2845 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2846 }
2847
2848 /************************************************************************
2849 * VarR4FromBool (OLEAUT32.76)
2850 *
2851 * Convert a VT_BOOL to a VT_R4.
2852 *
2853 * PARAMS
2854 * boolIn [I] Source
2855 * pFltOut [O] Destination
2856 *
2857 * RETURNS
2858 * S_OK.
2859 */
2860 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2861 {
2862 return VarR4FromI2(boolIn, pFltOut);
2863 }
2864
2865 /************************************************************************
2866 * VarR4FromI1 (OLEAUT32.213)
2867 *
2868 * Convert a VT_I1 to a VT_R4.
2869 *
2870 * PARAMS
2871 * cIn [I] Source
2872 * pFltOut [O] Destination
2873 *
2874 * RETURNS
2875 * Success: S_OK.
2876 * Failure: E_INVALIDARG, if the source value is invalid
2877 * DISP_E_OVERFLOW, if the value will not fit in the destination
2878 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2879 */
2880 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2881 {
2882 return _VarR4FromI1(cIn, pFltOut);
2883 }
2884
2885 /************************************************************************
2886 * VarR4FromUI2 (OLEAUT32.214)
2887 *
2888 * Convert a VT_UI2 to a VT_R4.
2889 *
2890 * PARAMS
2891 * usIn [I] Source
2892 * pFltOut [O] Destination
2893 *
2894 * RETURNS
2895 * Success: S_OK.
2896 * Failure: E_INVALIDARG, if the source value is invalid
2897 * DISP_E_OVERFLOW, if the value will not fit in the destination
2898 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2899 */
2900 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2901 {
2902 return _VarR4FromUI2(usIn, pFltOut);
2903 }
2904
2905 /************************************************************************
2906 * VarR4FromUI4 (OLEAUT32.215)
2907 *
2908 * Convert a VT_UI4 to a VT_R4.
2909 *
2910 * PARAMS
2911 * ulIn [I] Source
2912 * pFltOut [O] Destination
2913 *
2914 * RETURNS
2915 * Success: S_OK.
2916 * Failure: E_INVALIDARG, if the source value is invalid
2917 * DISP_E_OVERFLOW, if the value will not fit in the destination
2918 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2919 */
2920 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2921 {
2922 return _VarR4FromUI4(ulIn, pFltOut);
2923 }
2924
2925 /************************************************************************
2926 * VarR4FromDec (OLEAUT32.216)
2927 *
2928 * Convert a VT_DECIMAL to a VT_R4.
2929 *
2930 * PARAMS
2931 * pDecIn [I] Source
2932 * pFltOut [O] Destination
2933 *
2934 * RETURNS
2935 * Success: S_OK.
2936 * Failure: E_INVALIDARG, if the source value is invalid.
2937 */
2938 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2939 {
2940 BYTE scale = DEC_SCALE(pDecIn);
2941 int divisor = 1;
2942 double highPart;
2943
2944 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2945 return E_INVALIDARG;
2946
2947 while (scale--)
2948 divisor *= 10;
2949
2950 if (DEC_SIGN(pDecIn))
2951 divisor = -divisor;
2952
2953 if (DEC_HI32(pDecIn))
2954 {
2955 highPart = (double)DEC_HI32(pDecIn) / (double)divisor;
2956 highPart *= 4294967296.0F;
2957 highPart *= 4294967296.0F;
2958 }
2959 else
2960 highPart = 0.0;
2961
2962 *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart;
2963 return S_OK;
2964 }
2965
2966 /************************************************************************
2967 * VarR4FromI8 (OLEAUT32.360)
2968 *
2969 * Convert a VT_I8 to a VT_R4.
2970 *
2971 * PARAMS
2972 * ullIn [I] Source
2973 * pFltOut [O] Destination
2974 *
2975 * RETURNS
2976 * S_OK.
2977 */
2978 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2979 {
2980 return _VarR4FromI8(llIn, pFltOut);
2981 }
2982
2983 /************************************************************************
2984 * VarR4FromUI8 (OLEAUT32.361)
2985 *
2986 * Convert a VT_UI8 to a VT_R4.
2987 *
2988 * PARAMS
2989 * ullIn [I] Source
2990 * pFltOut [O] Destination
2991 *
2992 * RETURNS
2993 * S_OK.
2994 */
2995 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
2996 {
2997 return _VarR4FromUI8(ullIn, pFltOut);
2998 }
2999
3000 /************************************************************************
3001 * VarR4CmpR8 (OLEAUT32.316)
3002 *
3003 * Compare a VT_R4 to a VT_R8.
3004 *
3005 * PARAMS
3006 * fltLeft [I] Source
3007 * dblRight [I] Value to compare
3008 *
3009 * RETURNS
3010 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3011 * equal to or greater than dblRight respectively.
3012 */
3013 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3014 {
3015 if (fltLeft < dblRight)
3016 return VARCMP_LT;
3017 else if (fltLeft > dblRight)
3018 return VARCMP_GT;
3019 return VARCMP_EQ;
3020 }
3021
3022 /* R8
3023 */
3024
3025 /************************************************************************
3026 * VarR8FromUI1 (OLEAUT32.78)
3027 *
3028 * Convert a VT_UI1 to a VT_R8.
3029 *
3030 * PARAMS
3031 * bIn [I] Source
3032 * pDblOut [O] Destination
3033 *
3034 * RETURNS
3035 * S_OK.
3036 */
3037 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3038 {
3039 return _VarR8FromUI1(bIn, pDblOut);
3040 }
3041
3042 /************************************************************************
3043 * VarR8FromI2 (OLEAUT32.79)
3044 *
3045 * Convert a VT_I2 to a VT_R8.
3046 *
3047 * PARAMS
3048 * sIn [I] Source
3049 * pDblOut [O] Destination
3050 *
3051 * RETURNS
3052 * S_OK.
3053 */
3054 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3055 {
3056 return _VarR8FromI2(sIn, pDblOut);
3057 }
3058
3059 /************************************************************************
3060 * VarR8FromI4 (OLEAUT32.80)
3061 *
3062 * Convert a VT_I4 to a VT_R8.
3063 *
3064 * PARAMS
3065 * sIn [I] Source
3066 * pDblOut [O] Destination
3067 *
3068 * RETURNS
3069 * S_OK.
3070 */
3071 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3072 {
3073 return _VarR8FromI4(lIn, pDblOut);
3074 }
3075
3076 /************************************************************************
3077 * VarR8FromR4 (OLEAUT32.81)
3078 *
3079 * Convert a VT_R4 to a VT_R8.
3080 *
3081 * PARAMS
3082 * fltIn [I] Source
3083 * pDblOut [O] Destination
3084 *
3085 * RETURNS
3086 * S_OK.
3087 */
3088 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3089 {
3090 return _VarR8FromR4(fltIn, pDblOut);
3091 }
3092
3093 /************************************************************************
3094 * VarR8FromCy (OLEAUT32.82)
3095 *
3096 * Convert a VT_CY to a VT_R8.
3097 *
3098 * PARAMS
3099 * cyIn [I] Source
3100 * pDblOut [O] Destination
3101 *
3102 * RETURNS
3103 * S_OK.
3104 */
3105 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3106 {
3107 return _VarR8FromCy(cyIn, pDblOut);
3108 }
3109
3110 /************************************************************************
3111 * VarR8FromDate (OLEAUT32.83)
3112 *
3113 * Convert a VT_DATE to a VT_R8.
3114 *
3115 * PARAMS
3116 * dateIn [I] Source
3117 * pDblOut [O] Destination
3118 *
3119 * RETURNS
3120 * S_OK.
3121 */
3122 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3123 {
3124 return _VarR8FromDate(dateIn, pDblOut);
3125 }
3126
3127 /************************************************************************
3128 * VarR8FromStr (OLEAUT32.84)
3129 *
3130 * Convert a VT_BSTR to a VT_R8.
3131 *
3132 * PARAMS
3133 * strIn [I] Source
3134 * lcid [I] LCID for the conversion
3135 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3136 * pDblOut [O] Destination
3137 *
3138 * RETURNS
3139 * Success: S_OK.
3140 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3141 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3142 */
3143 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3144 {
3145 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3146 }
3147
3148 /************************************************************************
3149 * VarR8FromDisp (OLEAUT32.85)
3150 *
3151 * Convert a VT_DISPATCH to a VT_R8.
3152 *
3153 * PARAMS
3154 * pdispIn [I] Source
3155 * lcid [I] LCID for conversion
3156 * pDblOut [O] Destination
3157 *
3158 * RETURNS
3159 * Success: S_OK.
3160 * Failure: E_INVALIDARG, if the source value is invalid
3161 * DISP_E_OVERFLOW, if the value will not fit in the destination
3162 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3163 */
3164 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3165 {
3166 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3167 }
3168
3169 /************************************************************************
3170 * VarR8FromBool (OLEAUT32.86)
3171 *
3172 * Convert a VT_BOOL to a VT_R8.
3173 *
3174 * PARAMS
3175 * boolIn [I] Source
3176 * pDblOut [O] Destination
3177 *
3178 * RETURNS
3179 * S_OK.
3180 */
3181 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3182 {
3183 return VarR8FromI2(boolIn, pDblOut);
3184 }
3185
3186 /************************************************************************
3187 * VarR8FromI1 (OLEAUT32.217)
3188 *
3189 * Convert a VT_I1 to a VT_R8.
3190 *
3191 * PARAMS
3192 * cIn [I] Source
3193 * pDblOut [O] Destination
3194 *
3195 * RETURNS
3196 * Success: S_OK.
3197 * Failure: E_INVALIDARG, if the source value is invalid
3198 * DISP_E_OVERFLOW, if the value will not fit in the destination
3199 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3200 */
3201 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3202 {
3203 return _VarR8FromI1(cIn, pDblOut);
3204 }
3205
3206 /************************************************************************
3207 * VarR8FromUI2 (OLEAUT32.218)
3208 *
3209 * Convert a VT_UI2 to a VT_R8.
3210 *
3211 * PARAMS
3212 * usIn [I] Source
3213 * pDblOut [O] Destination
3214 *
3215 * RETURNS
3216 * Success: S_OK.
3217 * Failure: E_INVALIDARG, if the source value is invalid
3218 * DISP_E_OVERFLOW, if the value will not fit in the destination
3219 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3220 */
3221 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3222 {
3223 return _VarR8FromUI2(usIn, pDblOut);
3224 }
3225
3226 /************************************************************************
3227 * VarR8FromUI4 (OLEAUT32.219)
3228 *
3229 * Convert a VT_UI4 to a VT_R8.
3230 *
3231 * PARAMS
3232 * ulIn [I] Source
3233 * pDblOut [O] Destination
3234 *
3235 * RETURNS
3236 * Success: S_OK.
3237 * Failure: E_INVALIDARG, if the source value is invalid
3238 * DISP_E_OVERFLOW, if the value will not fit in the destination
3239 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3240 */
3241 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3242 {
3243 return _VarR8FromUI4(ulIn, pDblOut);
3244 }
3245
3246 /************************************************************************
3247 * VarR8FromDec (OLEAUT32.220)
3248 *
3249 * Convert a VT_DECIMAL to a VT_R8.
3250 *
3251 * PARAMS
3252 * pDecIn [I] Source
3253 * pDblOut [O] Destination
3254 *
3255 * RETURNS
3256 * Success: S_OK.
3257 * Failure: E_INVALIDARG, if the source value is invalid.
3258 */
3259 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut)
3260 {
3261 BYTE scale = DEC_SCALE(pDecIn);
3262 double divisor = 1.0, highPart;
3263
3264 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3265 return E_INVALIDARG;
3266
3267 while (scale--)
3268 divisor *= 10;
3269
3270 if (DEC_SIGN(pDecIn))
3271 divisor = -divisor;
3272
3273 if (DEC_HI32(pDecIn))
3274 {
3275 highPart = (double)DEC_HI32(pDecIn) / divisor;
3276 highPart *= 4294967296.0F;
3277 highPart *= 4294967296.0F;
3278 }
3279 else
3280 highPart = 0.0;
3281
3282 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3283 return S_OK;
3284 }
3285
3286 /************************************************************************
3287 * VarR8FromI8 (OLEAUT32.362)
3288 *
3289 * Convert a VT_I8 to a VT_R8.
3290 *
3291 * PARAMS
3292 * ullIn [I] Source
3293 * pDblOut [O] Destination
3294 *
3295 * RETURNS
3296 * S_OK.
3297 */
3298 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3299 {
3300 return _VarR8FromI8(llIn, pDblOut);
3301 }
3302
3303 /************************************************************************
3304 * VarR8FromUI8 (OLEAUT32.363)
3305 *
3306 * Convert a VT_UI8 to a VT_R8.
3307 *
3308 * PARAMS
3309 * ullIn [I] Source
3310 * pDblOut [O] Destination
3311 *
3312 * RETURNS
3313 * S_OK.
3314 */
3315 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3316 {
3317 return _VarR8FromUI8(ullIn, pDblOut);
3318 }
3319
3320 /************************************************************************
3321 * VarR8Pow (OLEAUT32.315)
3322 *
3323 * Raise a VT_R8 to a power.
3324 *
3325 * PARAMS
3326 * dblLeft [I] Source
3327 * dblPow [I] Power to raise dblLeft by
3328 * pDblOut [O] Destination
3329 *
3330 * RETURNS
3331 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3332 */
3333 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3334 {
3335 *pDblOut = pow(dblLeft, dblPow);
3336 return S_OK;
3337 }
3338
3339 /************************************************************************
3340 * VarR8Round (OLEAUT32.317)
3341 *
3342 * Round a VT_R8 to a given number of decimal points.
3343 *
3344 * PARAMS
3345 * dblIn [I] Source
3346 * nDig [I] Number of decimal points to round to
3347 * pDblOut [O] Destination for rounded number
3348 *
3349 * RETURNS
3350 * Success: S_OK. pDblOut is rounded to nDig digits.
3351 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3352 *
3353 * NOTES
3354 * The native version of this function rounds using the internal
3355 * binary representation of the number. Wine uses the dutch rounding
3356 * convention, so therefore small differences can occur in the value returned.
3357 * MSDN says that you should use your own rounding function if you want
3358 * rounding to be predictable in your application.
3359 */
3360 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3361 {
3362 double scale, whole, fract;
3363
3364 if (nDig < 0)
3365 return E_INVALIDARG;
3366
3367 scale = pow(10.0, nDig);
3368
3369 dblIn *= scale;
3370 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3371 fract = dblIn - whole;
3372
3373 if (fract > 0.5)
3374 dblIn = whole + 1.0;
3375 else if (fract == 0.5)
3376 dblIn = whole + fmod(whole, 2.0);
3377 else if (fract >= 0.0)
3378 dblIn = whole;
3379 else if (fract == -0.5)
3380 dblIn = whole - fmod(whole, 2.0);
3381 else if (fract > -0.5)
3382 dblIn = whole;
3383 else
3384 dblIn = whole - 1.0;
3385
3386 *pDblOut = dblIn / scale;
3387 return S_OK;
3388 }
3389
3390 /* CY
3391 */
3392
3393 /* Powers of 10 from 0..4 D.P. */
3394 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3395 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3396
3397 /************************************************************************
3398 * VarCyFromUI1 (OLEAUT32.98)
3399 *
3400 * Convert a VT_UI1 to a VT_CY.
3401 *
3402 * PARAMS
3403 * bIn [I] Source
3404 * pCyOut [O] Destination
3405 *
3406 * RETURNS
3407 * Success: S_OK.
3408 * Failure: E_INVALIDARG, if the source value is invalid
3409 * DISP_E_OVERFLOW, if the value will not fit in the destination
3410 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3411 */
3412 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3413 {
3414 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER;
3415 return S_OK;
3416 }
3417
3418 /************************************************************************
3419 * VarCyFromI2 (OLEAUT32.99)
3420 *
3421 * Convert a VT_I2 to a VT_CY.
3422 *
3423 * PARAMS
3424 * sIn [I] Source
3425 * pCyOut [O] Destination
3426 *
3427 * RETURNS
3428 * Success: S_OK.
3429 * Failure: E_INVALIDARG, if the source value is invalid
3430 * DISP_E_OVERFLOW, if the value will not fit in the destination
3431 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3432 */
3433 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3434 {
3435 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER;
3436 return S_OK;
3437 }
3438
3439 /************************************************************************
3440 * VarCyFromI4 (OLEAUT32.100)
3441 *
3442 * Convert a VT_I4 to a VT_CY.
3443 *
3444 * PARAMS
3445 * sIn [I] Source
3446 * pCyOut [O] Destination
3447 *
3448 * RETURNS
3449 * Success: S_OK.
3450 * Failure: E_INVALIDARG, if the source value is invalid
3451 * DISP_E_OVERFLOW, if the value will not fit in the destination
3452 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3453 */
3454 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3455 {
3456 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER;
3457 return S_OK;
3458 }
3459
3460 /************************************************************************
3461 * VarCyFromR4 (OLEAUT32.101)
3462 *
3463 * Convert a VT_R4 to a VT_CY.
3464 *
3465 * PARAMS
3466 * fltIn [I] Source
3467 * pCyOut [O] Destination
3468 *
3469 * RETURNS
3470 * Success: S_OK.
3471 * Failure: E_INVALIDARG, if the source value is invalid
3472 * DISP_E_OVERFLOW, if the value will not fit in the destination
3473 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3474 */
3475 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3476 {
3477 return VarCyFromR8(fltIn, pCyOut);
3478 }
3479
3480 /************************************************************************
3481 * VarCyFromR8 (OLEAUT32.102)
3482 *
3483 * Convert a VT_R8 to a VT_CY.
3484 *
3485 * PARAMS
3486 * dblIn [I] Source
3487 * pCyOut [O] Destination
3488 *
3489 * RETURNS
3490 * Success: S_OK.
3491 * Failure: E_INVALIDARG, if the source value is invalid
3492 * DISP_E_OVERFLOW, if the value will not fit in the destination
3493 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3494 */
3495 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3496 {
3497 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3498 /* This code gives identical results to Win32 on Intel.
3499 * Here we use fp exceptions to catch overflows when storing the value.
3500 */
3501 static const unsigned short r8_fpcontrol = 0x137f;
3502 static const double r8_multiplier = CY_MULTIPLIER_F;
3503 unsigned short old_fpcontrol, result_fpstatus;
3504
3505 /* Clear exceptions, save the old fp state and load the new state */
3506 __asm__ __volatile__( "fnclex" );
3507 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3508 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3509 /* Perform the conversion. */
3510 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3511 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3512 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3513 /* Save the resulting fp state, load the old state and clear exceptions */
3514 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3515 __asm__ __volatile__( "fnclex" );
3516 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3517
3518 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3519 return DISP_E_OVERFLOW;
3520 #else
3521 /* This version produces slightly different results for boundary cases */
3522 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3523 return DISP_E_OVERFLOW;
3524 dblIn *= CY_MULTIPLIER_F;
3525 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3526 #endif
3527 return S_OK;
3528 }
3529
3530 /************************************************************************
3531 * VarCyFromDate (OLEAUT32.103)
3532 *
3533 * Convert a VT_DATE to a VT_CY.
3534 *
3535 * PARAMS
3536 * dateIn [I] Source
3537 * pCyOut [O] Destination
3538 *
3539 * RETURNS
3540 * Success: S_OK.
3541 * Failure: E_INVALIDARG, if the source value is invalid
3542 * DISP_E_OVERFLOW, if the value will not fit in the destination
3543 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3544 */
3545 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3546 {
3547 return VarCyFromR8(dateIn, pCyOut);
3548 }
3549
3550 /************************************************************************
3551 * VarCyFromStr (OLEAUT32.104)
3552 *
3553 * Convert a VT_BSTR to a VT_CY.
3554 *
3555 * PARAMS
3556 * strIn [I] Source
3557 * lcid [I] LCID for the conversion
3558 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3559 * pCyOut [O] Destination
3560 *
3561 * RETURNS
3562 * Success: S_OK.
3563 * Failure: E_INVALIDARG, if the source value is invalid
3564 * DISP_E_OVERFLOW, if the value will not fit in the destination
3565 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3566 */
3567 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3568 {
3569 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3570 }
3571
3572 /************************************************************************
3573 * VarCyFromDisp (OLEAUT32.105)
3574 *
3575 * Convert a VT_DISPATCH to a VT_CY.
3576 *
3577 * PARAMS
3578 * pdispIn [I] Source
3579 * lcid [I] LCID for conversion
3580 * pCyOut [O] Destination
3581 *
3582 * RETURNS
3583 * Success: S_OK.
3584 * Failure: E_INVALIDARG, if the source value is invalid
3585 * DISP_E_OVERFLOW, if the value will not fit in the destination
3586 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3587 */
3588 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3589 {
3590 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3591 }
3592
3593 /************************************************************************
3594 * VarCyFromBool (OLEAUT32.106)
3595 *
3596 * Convert a VT_BOOL to a VT_CY.
3597 *
3598 * PARAMS
3599 * boolIn [I] Source
3600 * pCyOut [O] Destination
3601 *
3602 * RETURNS
3603 * Success: S_OK.
3604 * Failure: E_INVALIDARG, if the source value is invalid
3605 * DISP_E_OVERFLOW, if the value will not fit in the destination
3606 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3607 *
3608 * NOTES
3609 * While the sign of the boolean is stored in the currency, the value is
3610 * converted to either 0 or 1.
3611 */
3612 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3613 {
3614 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER;
3615 return S_OK;
3616 }
3617
3618 /************************************************************************
3619 * VarCyFromI1 (OLEAUT32.225)
3620 *
3621 * Convert a VT_I1 to a VT_CY.
3622 *
3623 * PARAMS
3624 * cIn [I] Source
3625 * pCyOut [O] Destination
3626 *
3627 * RETURNS
3628 * Success: S_OK.
3629 * Failure: E_INVALIDARG, if the source value is invalid
3630 * DISP_E_OVERFLOW, if the value will not fit in the destination
3631 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3632 */
3633 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3634 {
3635 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER;
3636 return S_OK;
3637 }
3638
3639 /************************************************************************
3640 * VarCyFromUI2 (OLEAUT32.226)
3641 *
3642 * Convert a VT_UI2 to a VT_CY.
3643 *
3644 * PARAMS
3645 * usIn [I] Source
3646 * pCyOut [O] Destination
3647 *
3648 * RETURNS
3649 * Success: S_OK.
3650 * Failure: E_INVALIDARG, if the source value is invalid
3651 * DISP_E_OVERFLOW, if the value will not fit in the destination
3652 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3653 */
3654 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3655 {
3656 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER;
3657 return S_OK;
3658 }
3659
3660 /************************************************************************
3661 * VarCyFromUI4 (OLEAUT32.227)
3662 *
3663 * Convert a VT_UI4 to a VT_CY.
3664 *
3665 * PARAMS
3666 * ulIn [I] Source
3667 * pCyOut [O] Destination
3668 *
3669 * RETURNS
3670 * Success: S_OK.
3671 * Failure: E_INVALIDARG, if the source value is invalid
3672 * DISP_E_OVERFLOW, if the value will not fit in the destination
3673 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3674 */
3675 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3676 {
3677 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER;
3678 return S_OK;
3679 }
3680
3681 /************************************************************************
3682 * VarCyFromDec (OLEAUT32.228)
3683 *
3684 * Convert a VT_DECIMAL to a VT_CY.
3685 *
3686 * PARAMS
3687 * pdecIn [I] Source
3688 * pCyOut [O] Destination
3689 *
3690 * RETURNS
3691 * Success: S_OK.
3692 * Failure: E_INVALIDARG, if the source value is invalid
3693 * DISP_E_OVERFLOW, if the value will not fit in the destination
3694 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3695 */
3696 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3697 {
3698 DECIMAL rounded;
3699 HRESULT hRet;
3700
3701 hRet = VarDecRound(pdecIn, 4, &rounded);
3702
3703 if (SUCCEEDED(hRet))
3704 {
3705 double d;
3706
3707 if (DEC_HI32(&rounded))
3708 return DISP_E_OVERFLOW;
3709
3710 /* Note: Without the casts this promotes to int64 which loses precision */
3711 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3712 if (DEC_SIGN(&rounded))
3713 d = -d;
3714 return VarCyFromR8(d, pCyOut);
3715 }
3716 return hRet;
3717 }
3718
3719 /************************************************************************
3720 * VarCyFromI8 (OLEAUT32.366)
3721 *
3722 * Convert a VT_I8 to a VT_CY.
3723 *
3724 * PARAMS
3725 * ullIn [I] Source
3726 * pCyOut [O] Destination
3727 *
3728 * RETURNS
3729 * Success: S_OK.
3730 * Failure: E_INVALIDARG, if the source value is invalid
3731 * DISP_E_OVERFLOW, if the value will not fit in the destination
3732 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3733 */
3734 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3735 {
3736 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3737 pCyOut->int64 = llIn * CY_MULTIPLIER;
3738 return S_OK;
3739 }
3740
3741 /************************************************************************
3742 * VarCyFromUI8 (OLEAUT32.375)
3743 *
3744 * Convert a VT_UI8 to a VT_CY.
3745 *
3746 * PARAMS
3747 * ullIn [I] Source
3748 * pCyOut [O] Destination
3749 *
3750 * RETURNS
3751 * Success: S_OK.
3752 * Failure: E_INVALIDARG, if the source value is invalid
3753 * DISP_E_OVERFLOW, if the value will not fit in the destination
3754 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3755 */
3756 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3757 {
3758 if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3759 pCyOut->int64 = ullIn * CY_MULTIPLIER;
3760 return S_OK;
3761 }
3762
3763 /************************************************************************
3764 * VarCyAdd (OLEAUT32.299)
3765 *
3766 * Add one CY to another.
3767 *
3768 * PARAMS
3769 * cyLeft [I] Source
3770 * cyRight [I] Value to add
3771 * pCyOut [O] Destination
3772 *
3773 * RETURNS
3774 * Success: S_OK.
3775 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3776 */
3777 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3778 {
3779 double l,r;
3780 _VarR8FromCy(cyLeft, &l);
3781 _VarR8FromCy(cyRight, &r);
3782 l = l + r;
3783 return VarCyFromR8(l, pCyOut);
3784 }
3785
3786 /************************************************************************
3787 * VarCyMul (OLEAUT32.303)
3788 *
3789 * Multiply one CY by another.
3790 *
3791 * PARAMS
3792 * cyLeft [I] Source
3793 * cyRight [I] Value to multiply by
3794 * pCyOut [O] Destination
3795 *
3796 * RETURNS
3797 * Success: S_OK.
3798 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3799 */
3800 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3801 {
3802 double l,r;
3803 _VarR8FromCy(cyLeft, &l);
3804 _VarR8FromCy(cyRight, &r);
3805 l = l * r;
3806 return VarCyFromR8(l, pCyOut);
3807 }
3808
3809 /************************************************************************
3810 * VarCyMulI4 (OLEAUT32.304)
3811 *
3812 * Multiply one CY by a VT_I4.
3813 *
3814 * PARAMS
3815 * cyLeft [I] Source
3816 * lRight [I] Value to multiply by
3817 * pCyOut [O] Destination
3818 *
3819 * RETURNS
3820 * Success: S_OK.
3821 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3822 */
3823 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3824 {
3825 double d;
3826
3827 _VarR8FromCy(cyLeft, &d);
3828 d = d * lRight;
3829 return VarCyFromR8(d, pCyOut);
3830 }
3831
3832 /************************************************************************
3833 * VarCySub (OLEAUT32.305)
3834 *
3835 * Subtract one CY from another.
3836 *
3837 * PARAMS
3838 * cyLeft [I] Source
3839 * cyRight [I] Value to subtract
3840 * pCyOut [O] Destination
3841 *
3842 * RETURNS
3843 * Success: S_OK.
3844 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3845 */
3846 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3847 {
3848 double l,r;
3849 _VarR8FromCy(cyLeft, &l);
3850 _VarR8FromCy(cyRight, &r);
3851 l = l - r;
3852 return VarCyFromR8(l, pCyOut);
3853 }
3854
3855 /************************************************************************
3856 * VarCyAbs (OLEAUT32.306)
3857 *
3858 * Convert a VT_CY into its absolute value.
3859 *
3860 * PARAMS
3861 * cyIn [I] Source
3862 * pCyOut [O] Destination
3863 *
3864 * RETURNS
3865 * Success: S_OK. pCyOut contains the absolute value.
3866 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3867 */
3868 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3869 {
3870 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3871 return DISP_E_OVERFLOW;
3872
3873 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3874 return S_OK;
3875 }
3876
3877 /************************************************************************
3878 * VarCyFix (OLEAUT32.307)
3879 *
3880 * Return the integer part of a VT_CY.
3881 *
3882 * PARAMS
3883 * cyIn [I] Source
3884 * pCyOut [O] Destination
3885 *
3886 * RETURNS
3887 * Success: S_OK.
3888 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3889 *
3890 * NOTES
3891 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3892 * negative numbers away from 0, while this function rounds them towards zero.
3893 */
3894 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3895 {
3896 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3897 pCyOut->int64 *= CY_MULTIPLIER;
3898 return S_OK;
3899 }
3900
3901 /************************************************************************
3902 * VarCyInt (OLEAUT32.308)
3903 *
3904 * Return the integer part of a VT_CY.
3905 *
3906 * PARAMS
3907 * cyIn [I] Source
3908 * pCyOut [O] Destination
3909 *
3910 * RETURNS
3911 * Success: S_OK.
3912 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3913 *
3914 * NOTES
3915 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3916 * negative numbers towards 0, while this function rounds them away from zero.
3917 */
3918 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3919 {
3920 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3921 pCyOut->int64 *= CY_MULTIPLIER;
3922
3923 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3924 {
3925 pCyOut->int64 -= CY_MULTIPLIER;
3926 }
3927 return S_OK;
3928 }
3929
3930 /************************************************************************
3931 * VarCyNeg (OLEAUT32.309)
3932 *
3933 * Change the sign of a VT_CY.
3934 *
3935 * PARAMS
3936 * cyIn [I] Source
3937 * pCyOut [O] Destination
3938 *
3939 * RETURNS
3940 * Success: S_OK.
3941 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3942 */
3943 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3944 {
3945 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3946 return DISP_E_OVERFLOW;
3947
3948 pCyOut->int64 = -cyIn.int64;
3949 return S_OK;
3950 }
3951
3952 /************************************************************************
3953 * VarCyRound (OLEAUT32.310)
3954 *
3955 * Change the precision of a VT_CY.
3956 *
3957 * PARAMS
3958 * cyIn [I] Source
3959 * cDecimals [I] New number of decimals to keep
3960 * pCyOut [O] Destination
3961 *
3962 * RETURNS
3963 * Success: S_OK.
3964 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3965 */
3966 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3967 {
3968 if (cDecimals < 0)
3969 return E_INVALIDARG;
3970
3971 if (cDecimals > 3)
3972 {
3973 /* Rounding to more precision than we have */
3974 *pCyOut = cyIn;
3975 return S_OK;
3976 }
3977 else
3978 {
3979 double d, div = CY_Divisors[cDecimals];
3980
3981 _VarR8FromCy(cyIn, &d);
3982 d = d * div;
3983 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3984 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3985 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3986 return S_OK;
3987 }
3988 }
3989
3990 /************************************************************************
3991 * VarCyCmp (OLEAUT32.311)
3992 *
3993 * Compare two VT_CY values.
3994 *
3995 * PARAMS
3996 * cyLeft [I] Source
3997 * cyRight [I] Value to compare
3998 *
3999 * RETURNS
4000 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
4001 * compare is less, equal or greater than source respectively.
4002 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4003 */
4004 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4005 {
4006 HRESULT hRet;
4007 CY result;
4008
4009 /* Subtract right from left, and compare the result to 0 */
4010 hRet = VarCySub(cyLeft, cyRight, &result);
4011
4012 if (SUCCEEDED(hRet))
4013 {
4014 if (result.int64 < 0)
4015 hRet = (HRESULT)VARCMP_LT;
4016 else if (result.int64 > 0)
4017 hRet = (HRESULT)VARCMP_GT;
4018 else
4019 hRet = (HRESULT)VARCMP_EQ;
4020 }
4021 return hRet;
4022 }
4023
4024 /************************************************************************
4025 * VarCyCmpR8 (OLEAUT32.312)
4026 *
4027 * Compare a VT_CY to a double
4028 *
4029 * PARAMS
4030 * cyLeft [I] Currency Source
4031 * dblRight [I] double to compare to cyLeft
4032 *
4033 * RETURNS
4034 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4035 * less than, equal to or greater than cyLeft respectively.
4036 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4037 */
4038 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4039 {
4040 HRESULT hRet;
4041 CY cyRight;
4042
4043 hRet = VarCyFromR8(dblRight, &cyRight);
4044
4045 if (SUCCEEDED(hRet))
4046 hRet = VarCyCmp(cyLeft, cyRight);
4047
4048 return hRet;
4049 }
4050
4051 /************************************************************************
4052 * VarCyMulI8 (OLEAUT32.329)
4053 *
4054 * Multiply a VT_CY by a VT_I8.
4055 *
4056 * PARAMS
4057 * cyLeft [I] Source
4058 * llRight [I] Value to multiply by
4059 * pCyOut [O] Destination
4060 *
4061 * RETURNS
4062 * Success: S_OK.
4063 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4064 */
4065 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4066 {
4067 double d;
4068
4069 _VarR8FromCy(cyLeft, &d);
4070 d = d * (double)llRight;
4071 return VarCyFromR8(d, pCyOut);
4072 }
4073
4074 /* DECIMAL
4075 */
4076
4077 /************************************************************************
4078 * VarDecFromUI1 (OLEAUT32.190)
4079 *
4080 * Convert a VT_UI1 to a DECIMAL.
4081 *
4082 * PARAMS
4083 * bIn [I] Source
4084 * pDecOut [O] Destination
4085 *
4086 * RETURNS
4087 * S_OK.
4088 */
4089 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4090 {
4091 return VarDecFromUI4(bIn, pDecOut);
4092 }
4093
4094 /************************************************************************
4095 * VarDecFromI2 (OLEAUT32.191)
4096 *
4097 * Convert a VT_I2 to a DECIMAL.
4098 *
4099 * PARAMS
4100 * sIn [I] Source
4101 * pDecOut [O] Destination
4102 *
4103 * RETURNS
4104 * S_OK.
4105 */
4106 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4107 {
4108 return VarDecFromI4(sIn, pDecOut);
4109 }
4110
4111 /************************************************************************
4112 * VarDecFromI4 (OLEAUT32.192)
4113 *
4114 * Convert a VT_I4 to a DECIMAL.
4115 *
4116 * PARAMS
4117 * sIn [I] Source
4118 * pDecOut [O] Destination
4119 *
4120 * RETURNS
4121 * S_OK.
4122 */
4123 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4124 {
4125 DEC_HI32(pDecOut) = 0;
4126 DEC_MID32(pDecOut) = 0;
4127
4128 if (lIn < 0)
4129 {
4130 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4131 DEC_LO32(pDecOut) = -lIn;
4132 }
4133 else
4134 {
4135 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4136 DEC_LO32(pDecOut) = lIn;
4137 }
4138 return S_OK;
4139 }
4140
4141 #define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT))
4142
4143 /* internal representation of the value stored in a DECIMAL. The bytes are
4144 stored from LSB at index 0 to MSB at index 11
4145 */
4146 typedef struct DECIMAL_internal
4147 {
4148 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4149 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4150 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4151 } VARIANT_DI;
4152
4153 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4154 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4155 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4156 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
4157
4158 /************************************************************************
4159 * VarDecFromR4 (OLEAUT32.193)
4160 *
4161 * Convert a VT_R4 to a DECIMAL.
4162 *
4163 * PARAMS
4164 * fltIn [I] Source
4165 * pDecOut [O] Destination
4166 *
4167 * RETURNS
4168 * S_OK.
4169 */
4170 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4171 {
4172 VARIANT_DI di;
4173 HRESULT hres;
4174
4175 hres = VARIANT_DI_FromR4(fltIn, &di);
4176 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4177 return hres;
4178 }
4179
4180 /************************************************************************
4181 * VarDecFromR8 (OLEAUT32.194)
4182 *
4183 * Convert a VT_R8 to a DECIMAL.
4184 *
4185 * PARAMS
4186 * dblIn [I] Source
4187 * pDecOut [O] Destination
4188 *
4189 * RETURNS
4190 * S_OK.
4191 */
4192 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4193 {
4194 VARIANT_DI di;
4195 HRESULT hres;
4196
4197 hres = VARIANT_DI_FromR8(dblIn, &di);
4198 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4199 return hres;
4200 }
4201
4202 /************************************************************************
4203 * VarDecFromDate (OLEAUT32.195)
4204 *
4205 * Convert a VT_DATE to a DECIMAL.
4206 *
4207 * PARAMS
4208 * dateIn [I] Source
4209 * pDecOut [O] Destination
4210 *
4211 * RETURNS
4212 * S_OK.
4213 */
4214 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4215 {
4216 return VarDecFromR8(dateIn, pDecOut);
4217 }
4218
4219 /************************************************************************
4220 * VarDecFromCy (OLEAUT32.196)
4221 *
4222 * Convert a VT_CY to a DECIMAL.
4223 *
4224 * PARAMS
4225 * cyIn [I] Source
4226 * pDecOut [O] Destination
4227 *
4228 * RETURNS
4229 * S_OK.
4230 */
4231 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4232 {
4233 DEC_HI32(pDecOut) = 0;
4234
4235 /* Note: This assumes 2s complement integer representation */
4236 if (cyIn.s.Hi & 0x80000000)
4237 {
4238 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4239 DEC_LO64(pDecOut) = -cyIn.int64;
4240 }
4241 else
4242 {
4243 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4244 DEC_MID32(pDecOut) = cyIn.s.Hi;
4245 DEC_LO32(pDecOut) = cyIn.s.Lo;
4246 }
4247 return S_OK;
4248 }
4249
4250 /************************************************************************
4251 * VarDecFromStr (OLEAUT32.197)
4252 *
4253 * Convert a VT_BSTR to a DECIMAL.
4254 *
4255 * PARAMS
4256 * strIn [I] Source
4257 * lcid [I] LCID for the conversion
4258 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4259 * pDecOut [O] Destination
4260 *
4261 * RETURNS
4262 * Success: S_OK.
4263 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4264 */
4265 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4266 {
4267 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4268 }
4269
4270 /************************************************************************
4271 * VarDecFromDisp (OLEAUT32.198)
4272 *
4273 * Convert a VT_DISPATCH to a DECIMAL.
4274 *
4275 * PARAMS
4276 * pdispIn [I] Source
4277 * lcid [I] LCID for conversion
4278 * pDecOut [O] Destination
4279 *
4280 * RETURNS
4281 * Success: S_OK.
4282 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4283 */
4284 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4285 {
4286 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4287 }
4288
4289 /************************************************************************
4290 * VarDecFromBool (OLEAUT32.199)
4291 *
4292 * Convert a VT_BOOL to a DECIMAL.
4293 *
4294 * PARAMS
4295 * bIn [I] Source
4296 * pDecOut [O] Destination
4297 *
4298 * RETURNS
4299 * S_OK.
4300 *
4301 * NOTES
4302 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4303 */
4304 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4305 {
4306 DEC_HI32(pDecOut) = 0;
4307 DEC_MID32(pDecOut) = 0;
4308 if (bIn)
4309 {
4310 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4311 DEC_LO32(pDecOut) = 1;
4312 }
4313 else
4314 {
4315 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4316 DEC_LO32(pDecOut) = 0;
4317 }
4318 return S_OK;
4319 }
4320
4321 /************************************************************************
4322 * VarDecFromI1 (OLEAUT32.241)
4323 *
4324 * Convert a VT_I1 to a DECIMAL.
4325 *
4326 * PARAMS
4327 * cIn [I] Source
4328 * pDecOut [O] Destination
4329 *
4330 * RETURNS
4331 * S_OK.
4332 */
4333 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4334 {
4335 return VarDecFromI4(cIn, pDecOut);
4336 }
4337
4338 /************************************************************************
4339 * VarDecFromUI2 (OLEAUT32.242)
4340 *
4341 * Convert a VT_UI2 to a DECIMAL.
4342 *
4343 * PARAMS
4344 * usIn [I] Source
4345 * pDecOut [O] Destination
4346 *
4347 * RETURNS
4348 * S_OK.
4349 */
4350 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4351 {
4352 return VarDecFromUI4(usIn, pDecOut);
4353 }
4354
4355 /************************************************************************
4356 * VarDecFromUI4 (OLEAUT32.243)
4357 *
4358 * Convert a VT_UI4 to a DECIMAL.
4359 *
4360 * PARAMS
4361 * ulIn [I] Source
4362 * pDecOut [O] Destination
4363 *
4364 * RETURNS
4365 * S_OK.
4366 */
4367 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4368 {
4369 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4370 DEC_HI32(pDecOut) = 0;
4371 DEC_MID32(pDecOut) = 0;
4372 DEC_LO32(pDecOut) = ulIn;
4373 return S_OK;
4374 }
4375
4376 /************************************************************************
4377 * VarDecFromI8 (OLEAUT32.374)
4378 *
4379 * Convert a VT_I8 to a DECIMAL.
4380 *
4381 * PARAMS
4382 * llIn [I] Source
4383 * pDecOut [O] Destination
4384 *
4385 * RETURNS
4386 * S_OK.
4387 */
4388 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4389 {
4390 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4391
4392 DEC_HI32(pDecOut) = 0;
4393
4394 /* Note: This assumes 2s complement integer representation */
4395 if (pLi->u.HighPart & 0x80000000)
4396 {
4397 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4398 DEC_LO64(pDecOut) = -pLi->QuadPart;
4399 }
4400 else
4401 {
4402 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4403 DEC_MID32(pDecOut) = pLi->u.HighPart;
4404 DEC_LO32(pDecOut) = pLi->u.LowPart;
4405 }
4406 return S_OK;
4407 }
4408
4409 /************************************************************************
4410 * VarDecFromUI8 (OLEAUT32.375)
4411 *
4412 * Convert a VT_UI8 to a DECIMAL.
4413 *
4414 * PARAMS
4415 * ullIn [I] Source
4416 * pDecOut [O] Destination
4417 *
4418 * RETURNS
4419 * S_OK.
4420 */
4421 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4422 {
4423 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4424 DEC_HI32(pDecOut) = 0;
4425 DEC_LO64(pDecOut) = ullIn;
4426 return S_OK;
4427 }
4428
4429 /* Make two DECIMALS the same scale; used by math functions below */
4430 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4431 const DECIMAL** ppDecRight,
4432 DECIMAL* pDecOut)
4433 {
4434 static DECIMAL scaleFactor;
4435 DECIMAL decTemp;
4436 int scaleAmount, i;
4437 HRESULT hRet = S_OK;
4438
4439 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4440 return E_INVALIDARG;
4441
4442 DEC_LO32(&scaleFactor) = 10;
4443
4444 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4445
4446 if (!scaleAmount)
4447 return S_OK; /* Same scale */
4448
4449 if (scaleAmount > 0)
4450 {
4451 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4452 *ppDecRight = pDecOut;
4453 }
4454 else
4455 {
4456 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4457 *ppDecLeft = pDecOut;
4458 i = scaleAmount = -scaleAmount;
4459 }
4460
4461 if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE)
4462 return DISP_E_OVERFLOW; /* Can't scale up */
4463
4464 /* Multiply up the value to be scaled by the correct amount */
4465 while (SUCCEEDED(hRet) && i--)
4466 {
4467 /* Note we are multiplying by a value with a scale of 0, so we don't recurse */
4468 hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut);
4469 decTemp = *pDecOut;
4470 }
4471 DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */
4472 return hRet;
4473 }
4474
4475 /* Add two unsigned 32 bit values with overflow */
4476 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4477 {
4478 ULARGE_INTEGER ul64;
4479
4480 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4481 *pulHigh = ul64.u.HighPart;
4482 return ul64.u.LowPart;
4483 }
4484
4485 /* Subtract two unsigned 32 bit values with underflow */
4486 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4487 {
4488 BOOL invert = FALSE;
4489 ULARGE_INTEGER ul64;
4490
4491 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4492 if (ulLeft < ulRight)
4493 invert = TRUE;
4494
4495 if (ul64.QuadPart > (ULONG64)*pulHigh)
4496 ul64.QuadPart -= (ULONG64)*pulHigh;
4497 else
4498 {
4499 ul64.QuadPart -= (ULONG64)*pulHigh;
4500 invert = TRUE;
4501 }
4502 if (invert)
4503 ul64.u.HighPart = -ul64.u.HighPart ;
4504
4505 *pulHigh = ul64.u.HighPart;
4506 return ul64.u.LowPart;
4507 }
4508
4509 /* Multiply two unsigned 32 bit values with overflow */
4510 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4511 {
4512 ULARGE_INTEGER ul64;
4513
4514 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4515 *pulHigh = ul64.u.HighPart;
4516 return ul64.u.LowPart;
4517 }
4518
4519 /* Compare two decimals that have the same scale */
4520 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4521 {
4522 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4523 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4524 return -1;
4525 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4526 return 0;
4527 return 1;
4528 }
4529
4530 /************************************************************************
4531 * VarDecAdd (OLEAUT32.177)
4532 *
4533 * Add one DECIMAL to another.
4534 *
4535 * PARAMS
4536 * pDecLeft [I] Source
4537 * pDecRight [I] Value to add
4538 * pDecOut [O] Destination
4539 *
4540 * RETURNS
4541 * Success: S_OK.
4542 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4543 */
4544 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4545 {
4546 HRESULT hRet;
4547 DECIMAL scaled;
4548
4549 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled);
4550
4551 if (SUCCEEDED(hRet))
4552 {
4553 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4554 ULONG overflow = 0;
4555 BYTE sign = DECIMAL_POS;
4556 int cmp;
4557
4558 /* Correct for the sign of the result */
4559 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4560 {
4561 /* -x + -y : Negative */
4562 sign = DECIMAL_NEG;
4563 goto VarDecAdd_AsPositive;
4564 }
4565 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4566 {
4567 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4568
4569 /* -x + y : Negative if x > y */
4570 if (cmp > 0)
4571 {
4572 sign = DECIMAL_NEG;
4573 VarDecAdd_AsNegative:
4574 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4575 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4576 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4577 }
4578 else
4579 {
4580 VarDecAdd_AsInvertedNegative:
4581 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4582 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4583 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4584 }
4585 }
4586 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4587 {
4588 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4589
4590 /* x + -y : Negative if x <= y */
4591 if (cmp <= 0)
4592 {
4593 sign = DECIMAL_NEG;
4594 goto VarDecAdd_AsInvertedNegative;
4595 }
4596 goto VarDecAdd_AsNegative;
4597 }
4598 else
4599 {
4600 /* x + y : Positive */
4601 VarDecAdd_AsPositive:
4602 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4603 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4604 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4605 }
4606
4607 if (overflow)
4608 return DISP_E_OVERFLOW; /* overflowed */
4609
4610 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4611 DEC_SIGN(pDecOut) = sign;
4612 }
4613 return hRet;
4614 }
4615
4616 /* translate from external DECIMAL format into an internal representation */
4617 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4618 {
4619 to->scale = DEC_SCALE(from);
4620 to->sign = DEC_SIGN(from) ? 1 : 0;
4621
4622 to->bitsnum[0] = DEC_LO32(from);
4623 to->bitsnum[1] = DEC_MID32(from);
4624 to->bitsnum[2] = DEC_HI32(from);
4625 }
4626
4627 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
4628 {
4629 if (from->sign) {
4630 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4631 } else {
4632 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4633 }
4634
4635 DEC_LO32(to) = from->bitsnum[0];
4636 DEC_MID32(to) = from->bitsnum[1];
4637 DEC_HI32(to) = from->bitsnum[2];
4638 }
4639
4640 /* clear an internal representation of a DECIMAL */
4641 static void VARIANT_DI_clear(VARIANT_DI * i)
4642 {
4643 memset(i, 0, sizeof(VARIANT_DI));
4644 }
4645
4646 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4647 size is supported. The value in p is replaced by the quotient of the division, and
4648 the remainder is returned as a result. This routine is most often used with a divisor
4649 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4650 */
4651 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4652 {
4653 if (divisor == 0) {
4654 /* division by 0 */
4655 return 0xFF;
4656 } else if (divisor == 1) {
4657 /* dividend remains unchanged */
4658 return 0;
4659 } else {
4660 unsigned char remainder = 0;
4661 ULONGLONG iTempDividend;
4662 signed int i;
4663
4664 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4665 for (; i >= 0; i--) {
4666 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4667 remainder = iTempDividend % divisor;
4668 p[i] = iTempDividend / divisor;
4669 }
4670
4671 return remainder;
4672 }
4673 }
4674
4675 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4676 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n)
4677 {
4678 for (; n > 0; n--) if (*p++ != 0) return FALSE;
4679 return TRUE;
4680 }
4681
4682 /* multiply two DECIMALS, without changing either one, and place result in third
4683 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4684 digits when scale > 0 in order to fit an overflowing result. Final overflow
4685 flag is returned.
4686 */
4687 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
4688 {
4689 BOOL r_overflow = FALSE;
4690 DWORD running[6];
4691 signed int mulstart;
4692
4693 VARIANT_DI_clear(result);
4694 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4695
4696 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4697 of the result is formed by adding the scales of the operands.
4698 */
4699 result->scale = a->scale + b->scale;
4700 memset(running, 0, sizeof(running));
4701
4702 /* count number of leading zero-bytes in operand A */
4703 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4704 if (mulstart < 0) {
4705 /* result is 0, because operand A is 0 */
4706 result->scale = 0;
4707 result->sign = 0;
4708 } else {
4709 unsigned char remainder = 0;
4710 int iA;
4711
4712 /* perform actual multiplication */
4713 for (iA = 0; iA <= mulstart; iA++) {
4714 ULONG iOverflowMul;
4715 int iB;
4716
4717 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4718 ULONG iRV;
4719 int iR;
4720
4721 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4722 iR = iA + iB;
4723 do {
4724 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4725 iR++;
4726 } while (iRV);
4727 }
4728 }
4729
4730 /* Too bad - native oleaut does not do this, so we should not either */
4731 #if 0
4732 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4733 This operation should not lose significant digits, and gives an
4734 opportunity to reduce the possibility of overflows in future
4735 operations issued by the application.
4736 */
4737 while (result->scale > 0) {
4738 memcpy(quotient, running, sizeof(quotient));
4739 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4740 if (remainder > 0) break;
4741 memcpy(running, quotient, sizeof(quotient));
4742 result->scale--;
4743 }
4744 #endif
4745 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4746 This operation *will* lose significant digits of the result because
4747 all the factors of 10 were consumed by the previous operation.
4748 */
4749 while (result->scale > 0 && !VARIANT_int_iszero(
4750 running + sizeof(result->bitsnum) / sizeof(DWORD),
4751 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4752
4753 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4754 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4755 result->scale--;
4756 }
4757
4758 /* round up the result - native oleaut32 does this */
4759 if (remainder >= 5) {
4760 unsigned int i;
4761 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4762 ULONGLONG digit = running[i] + 1;
4763 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4764 running[i] = digit & 0xFFFFFFFF;
4765 }
4766 }
4767
4768 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4769 and copy result bits into result structure
4770 */
4771 r_overflow = !VARIANT_int_iszero(
4772 running + sizeof(result->bitsnum)/sizeof(DWORD),
4773 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4774 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4775 }
4776 return r_overflow;
4777 }
4778
4779 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4780 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4781 success, FALSE if insufficient space in output buffer.
4782 */
4783 static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
4784 {
4785 BOOL overflow = FALSE;
4786 DWORD quotient[3];
4787 unsigned char remainder;
4788 unsigned int i;
4789
4790 /* place negative sign */
4791 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4792 if (n > 0) {
4793 *s++ = '-';
4794 n--;
4795 }
4796 else overflow = TRUE;
4797 }
4798
4799 /* prepare initial 0 */
4800 if (!overflow) {
4801 if (n >= 2) {
4802 s[0] = '0';
4803 s[1] = '\0';
4804 } else overflow = TRUE;
4805 }
4806
4807 i = 0;
4808 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4809 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4810 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4811 if (i + 2 > n) {
4812 overflow = TRUE;
4813 } else {
4814 s[i++] = '0' + remainder;
4815 s[i] = '\0';
4816 }
4817 }
4818
4819 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4820
4821 /* reverse order of digits */
4822 WCHAR * x = s; WCHAR * y = s + i - 1;
4823 while (x < y) {
4824 *x ^= *y;
4825 *y ^= *x;
4826 *x++ ^= *y--;
4827 }
4828
4829 /* check for decimal point. "i" now has string length */
4830 if (i <= a->scale) {
4831 unsigned int numzeroes = a->scale + 1 - i;
4832 if (i + 1 + numzeroes >= n) {
4833 overflow = TRUE;
4834 } else {
4835 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4836 i += numzeroes;
4837 while (numzeroes > 0) {
4838 s[--numzeroes] = '0';
4839 }
4840 }
4841 }
4842
4843 /* place decimal point */
4844 if (a->scale > 0) {
4845 unsigned int periodpos = i - a->scale;
4846 if (i + 2 >= n) {
4847 overflow = TRUE;
4848 } else {
4849 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4850 s[periodpos] = '.'; i++;
4851
4852 /* remove extra zeros at the end, if any */
4853 while (s[i - 1] == '0') s[--i] = '\0';
4854 if (s[i - 1] == '.') s[--i] = '\0';
4855 }
4856 }
4857 }
4858
4859 return !overflow;
4860 }
4861
4862 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4863 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4864 {
4865 DWORD shifted;
4866 unsigned int i;
4867
4868 /* shift whole DWORDs to the left */
4869 while (shift >= 32)
4870 {
4871 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4872 *p = 0; shift -= 32;
4873 }
4874
4875 /* shift remainder (1..31 bits) */
4876 shifted = 0;
4877 if (shift > 0) for (i = 0; i < n; i++)
4878 {
4879 DWORD b;
4880 b = p[i] >> (32 - shift);
4881 p[i] = (p[i] << shift) | shifted;
4882 shifted = b;
4883 }
4884 }
4885
4886 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4887 Value at v is incremented by the value at p. Any size is supported, provided
4888 that v is not shorter than p. Any unapplied carry is returned as a result.
4889 */
4890 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
4891 unsigned int np)
4892 {
4893 unsigned char carry = 0;
4894
4895 if (nv >= np) {
4896 ULONGLONG sum;
4897 unsigned int i;
4898
4899 for (i = 0; i < np; i++) {
4900 sum = (ULONGLONG)v[i]
4901 + (ULONGLONG)p[i]
4902 + (ULONGLONG)carry;
4903 v[i] = sum & 0xffffffff;
4904 carry = sum >> 32;
4905 }
4906 for (; i < nv && carry; i++) {
4907 sum = (ULONGLONG)v[i]
4908 + (ULONGLONG)carry;
4909 v[i] = sum & 0xffffffff;
4910 carry = sum >> 32;
4911 }
4912 }
4913 return carry;
4914 }
4915
4916 /* perform integral division with operand p as dividend. Parameter n indicates
4917 number of available DWORDs in divisor p, but available space in p must be
4918 actually at least 2 * n DWORDs, because the remainder of the integral
4919 division is built in the next n DWORDs past the start of the quotient. This
4920 routine replaces the dividend in p with the quotient, and appends n
4921 additional DWORDs for the remainder.
4922
4923 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4924 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4925 source code to the VLI (Very Large Integer) division operator. This algorithm
4926 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4927 variably-scaled integers such as the MS DECIMAL representation.
4928 */
4929 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
4930 unsigned int dn)
4931 {
4932 unsigned int i;
4933 DWORD tempsub[8];
4934 DWORD * negdivisor = tempsub + n;
4935
4936 /* build 2s-complement of divisor */
4937 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4938 p[n] = 1;
4939 VARIANT_int_add(negdivisor, n, p + n, 1);
4940 memset(p + n, 0, n * sizeof(DWORD));
4941
4942 /* skip all leading zero DWORDs in quotient */
4943 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4944 /* i is now number of DWORDs left to process */
4945 for (i <<= 5; i < (n << 5); i++) {
4946 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4947
4948 /* trial subtraction */
4949 memcpy(tempsub, p + n, n * sizeof(DWORD));
4950 VARIANT_int_add(tempsub, n, negdivisor, n);
4951
4952 /* check whether result of subtraction was negative */
4953 if ((tempsub[n - 1] & 0x80000000) == 0) {
4954 memcpy(p + n, tempsub, n * sizeof(DWORD));
4955 p[0] |= 1;
4956 }
4957 }
4958 }
4959
4960 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4961 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4962 {
4963 unsigned int i;
4964 ULONG iOverflowMul;
4965
4966 for (iOverflowMul = 0, i = 0; i < n; i++)
4967 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
4968 return (unsigned char)iOverflowMul;
4969 }
4970
4971 /* increment value in A by the value indicated in B, with scale adjusting.
4972 Modifies parameters by adjusting scales. Returns 0 if addition was
4973 successful, nonzero if a parameter underflowed before it could be
4974 successfully used in the addition.
4975 */
4976 static int VARIANT_int_addlossy(
4977 DWORD * a, int * ascale, unsigned int an,
4978 DWORD * b, int * bscale, unsigned int bn)
4979 {
4980 int underflow = 0;
4981
4982 if (VARIANT_int_iszero(a, an)) {
4983 /* if A is zero, copy B into A, after removing digits */
4984 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
4985 VARIANT_int_divbychar(b, bn, 10);
4986 (*bscale)--;
4987 }
4988 memcpy(a, b, an * sizeof(DWORD));
4989 *ascale = *bscale;
4990 } else if (!VARIANT_int_iszero(b, bn)) {
4991 unsigned int tn = an + 1;
4992 DWORD t[5];
4993
4994 if (bn + 1 > tn) tn = bn + 1;
4995 if (*ascale != *bscale) {
4996 /* first (optimistic) try - try to scale down the one with the bigger
4997 scale, while this number is divisible by 10 */
4998 DWORD * digitchosen;
4999 unsigned int nchosen;
5000 int * scalechosen;
5001 int targetscale;
5002
5003 if (*ascale < *bscale) {
5004 targetscale = *ascale;
5005 scalechosen = bscale;
5006 digitchosen = b;
5007 nchosen = bn;
5008 } else {
5009 targetscale = *bscale;
5010 scalechosen = ascale;
5011 digitchosen = a;
5012 nchosen = an;
5013 }
5014 memset(t, 0, tn * sizeof(DWORD));
5015 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5016
5017 /* divide by 10 until target scale is reached */
5018 while (*scalechosen > targetscale) {
5019 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5020 if (!remainder) {
5021 (*scalechosen)--;
5022 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5023 } else break;
5024 }
5025 }
5026
5027 if (*ascale != *bscale) {
5028 DWORD * digitchosen;
5029 unsigned int nchosen;
5030 int * scalechosen;
5031 int targetscale;
5032
5033 /* try to scale up the one with the smaller scale */
5034 if (*ascale > *bscale) {
5035 targetscale = *ascale;
5036 scalechosen = bscale;
5037 digitchosen = b;
5038 nchosen = bn;
5039 } else {
5040 targetscale = *bscale;
5041 scalechosen = ascale;
5042 digitchosen = a;
5043 nchosen = an;
5044 }
5045 memset(t, 0, tn * sizeof(DWORD));
5046 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5047
5048 /* multiply by 10 until target scale is reached, or
5049 significant bytes overflow the number
5050 */
5051 while (*scalechosen < targetscale && t[nchosen] == 0) {
5052 VARIANT_int_mulbychar(t, tn, 10);
5053 if (t[nchosen] == 0) {
5054 /* still does not overflow */
5055 (*scalechosen)++;
5056 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5057 }
5058 }
5059 }
5060
5061 if (*ascale != *bscale) {
5062 /* still different? try to scale down the one with the bigger scale
5063 (this *will* lose significant digits) */
5064 DWORD * digitchosen;
5065 unsigned int nchosen;
5066 int * scalechosen;
5067 int targetscale;
5068
5069 if (*ascale < *bscale) {
5070 targetscale = *ascale;
5071 scalechosen = bscale;
5072 digitchosen = b;
5073 nchosen = bn;
5074 } else {
5075 targetscale = *bscale;
5076 scalechosen = ascale;
5077 digitchosen = a;
5078 nchosen = an;
5079 }
5080 memset(t, 0, tn * sizeof(DWORD));
5081 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5082
5083 /* divide by 10 until target scale is reached */
5084 while (*scalechosen > targetscale) {
5085 VARIANT_int_divbychar(t, tn, 10);
5086 (*scalechosen)--;
5087 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5088 }
5089 }
5090
5091 /* check whether any of the operands still has significant digits
5092 (underflow case 1)
5093 */
5094 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5095 underflow = 1;
5096 } else {
5097 /* at this step, both numbers have the same scale and can be added
5098 as integers. However, the result might not fit in A, so further
5099 scaling down might be necessary.
5100 */
5101 while (!underflow) {
5102 memset(t, 0, tn * sizeof(DWORD));
5103 memcpy(t, a, an * sizeof(DWORD));
5104
5105 VARIANT_int_add(t, tn, b, bn);
5106 if (VARIANT_int_iszero(t + an, tn - an)) {
5107 /* addition was successful */
5108 memcpy(a, t, an * sizeof(DWORD));
5109 break;
5110 } else {
5111 /* addition overflowed - remove significant digits
5112 from both operands and try again */
5113 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5114 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5115 /* check whether any operand keeps significant digits after
5116 scaledown (underflow case 2)
5117 */
5118 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5119 }
5120 }
5121 }
5122 }
5123 return underflow;
5124 }
5125
5126 /* perform complete DECIMAL division in the internal representation. Returns
5127 0 if the division was completed (even if quotient is set to 0), or nonzero
5128 in case of quotient overflow.
5129 */
5130 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
5131 VARIANT_DI * quotient, BOOL round_remainder)
5132 {
5133 HRESULT r_overflow = S_OK;
5134
5135 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5136 /* division by 0 */
5137 r_overflow = DISP_E_DIVBYZERO;
5138 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5139 VARIANT_DI_clear(quotient);
5140 } else {
5141 int quotientscale, remainderscale, tempquotientscale;
5142 DWORD remainderplusquotient[8];
5143 int underflow;
5144
5145 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5146 tempquotientscale = quotientscale;
5147 VARIANT_DI_clear(quotient);
5148 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5149
5150 /* The following strategy is used for division
5151 1) if there was a nonzero remainder from previous iteration, use it as
5152 dividend for this iteration, else (for first iteration) use intended
5153 dividend
5154 2) perform integer division in temporary buffer, develop quotient in
5155 low-order part, remainder in high-order part
5156 3) add quotient from step 2 to final result, with possible loss of
5157 significant digits
5158 4) multiply integer part of remainder by 10, while incrementing the
5159 scale of the remainder. This operation preserves the intended value
5160 of the remainder.
5161 5) loop to step 1 until one of the following is true:
5162 a) remainder is zero (exact division achieved)
5163 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5164 */
5165 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5166 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5167 do {
5168 VARIANT_int_div(
5169 remainderplusquotient, 4,
5170 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5171 underflow = VARIANT_int_addlossy(
5172 quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5173 remainderplusquotient, &tempquotientscale, 4);
5174 if (round_remainder) {
5175 if(remainderplusquotient[4] >= 5){
5176 unsigned int i;
5177 unsigned char remainder = 1;
5178 for (i = 0; i < sizeof(quotient->bitsnum) / sizeof(DWORD) && remainder; i++) {
5179 ULONGLONG digit = quotient->bitsnum[i] + 1;
5180 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5181 quotient->bitsnum[i] = digit & 0xFFFFFFFF;
5182 }
5183 }
5184 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5185 } else {
5186 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5187 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5188 }
5189 tempquotientscale = ++remainderscale;
5190 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5191
5192 /* quotient scale might now be negative (extremely big number). If, so, try
5193 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5194 until scale is 0. If this cannot be done, it is a real overflow.
5195 */
5196 while (r_overflow == S_OK && quotientscale < 0) {
5197 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5198 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5199 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5200 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5201 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5202 quotientscale++;
5203 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5204 } else r_overflow = DISP_E_OVERFLOW;
5205 }
5206 if (r_overflow == S_OK) {
5207 if (quotientscale <= 255) quotient->scale = quotientscale;
5208 else VARIANT_DI_clear(quotient);
5209 }
5210 }
5211 return r_overflow;
5212 }
5213
5214 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5215 with an undefined scale, which will be assigned to (if possible). It also
5216 receives an exponent of 2. This procedure will then manipulate the mantissa
5217 and calculate a corresponding scale, so that the exponent2 value is assimilated
5218 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5219 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5220 a DECIMAL. */
5221 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble)
5222 {
5223 HRESULT hres = S_OK;
5224 int exponent5, exponent10;
5225
5226 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5227 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5228 exponent10 might be used to set the VARIANT_DI scale directly. However,
5229 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5230 exponent5 = -exponent2;
5231 exponent10 = exponent2;
5232
5233 /* Handle exponent5 > 0 */
5234 while (exponent5 > 0) {
5235 char bPrevCarryBit;
5236 char bCurrCarryBit;
5237
5238 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5239 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5240 somehow the mantissa should be divided by 2. */
5241 if ((val->bitsnum[0] & 1) == 0) {
5242 /* The mantissa is divisible by 2. Therefore the division can be done
5243 without losing significant digits. */
5244 exponent10++; exponent5--;
5245
5246 /* Shift right */
5247 bPrevCarryBit = val->bitsnum[2] & 1;
5248 val->bitsnum[2] >>= 1;
5249 bCurrCarryBit = val->bitsnum[1] & 1;
5250 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5251 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5252 } else {
5253 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5254 be multiplied by 5, unless the multiplication overflows. */
5255 DWORD temp_bitsnum[3];
5256
5257 exponent5--;
5258
5259 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5260 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5261 /* Multiplication succeeded without overflow, so copy result back
5262 into VARIANT_DI */
5263 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5264
5265 /* Mask out 3 extraneous bits introduced by the multiply */
5266 } else {
5267 /* Multiplication by 5 overflows. The mantissa should be divided
5268 by 2, and therefore will lose significant digits. */
5269 exponent10++;
5270
5271 /* Shift right */
5272 bPrevCarryBit = val->bitsnum[2] & 1;
5273 val->bitsnum[2] >>= 1;
5274 bCurrCarryBit = val->bitsnum[1] & 1;
5275 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5276 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5277 }
5278 }
5279 }
5280
5281 /* Handle exponent5 < 0 */
5282 while (exponent5 < 0) {
5283 /* In order to divide the value represented by the VARIANT_DI by 5, it
5284 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5285 and the mantissa should be multiplied by 2 */
5286 if ((val->bitsnum[2] & 0x80000000) == 0) {
5287 /* The mantissa can withstand a shift-left without overflowing */
5288 exponent10--; exponent5++;
5289 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5290 } else {
5291 /* The mantissa would overflow if shifted. Therefore it should be
5292 directly divided by 5. This will lose significant digits, unless
5293 by chance the mantissa happens to be divisible by 5 */
5294 exponent5++;
5295 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5296 }
5297 }
5298
5299 /* At this point, the mantissa has assimilated the exponent5, but the
5300 exponent10 might not be suitable for assignment. The exponent10 must be
5301 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5302 down appropriately. */
5303 while (hres == S_OK && exponent10 > 0) {
5304 /* In order to bring exponent10 down to 0, the mantissa should be
5305 multiplied by 10 to compensate. If the exponent10 is too big, this
5306 will cause the mantissa to overflow. */
5307 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5308 exponent10--;
5309 } else {
5310 hres = DISP_E_OVERFLOW;
5311 }
5312 }
5313 while (exponent10 < -DEC_MAX_SCALE) {
5314 int rem10;
5315 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5316 be divided by 10 to compensate. If the exponent10 is too small, this
5317 will cause the mantissa to underflow and become 0 */
5318 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5319 exponent10++;
5320 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5321 /* Underflow, unable to keep dividing */
5322 exponent10 = 0;
5323 } else if (rem10 >= 5) {
5324 DWORD x = 1;
5325 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5326 }
5327 }
5328 /* This step is required in order to remove excess bits of precision from the
5329 end of the bit representation, down to the precision guaranteed by the
5330 floating point number. */
5331 if (isDouble) {
5332 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[2] == 0 && (val->bitsnum[1] & 0xFFE00000) != 0))) {
5333 int rem10;
5334
5335 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5336 exponent10++;
5337 if (rem10 >= 5) {
5338 DWORD x = 1;
5339 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5340 }
5341 }
5342 } else {
5343 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5344 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5345 int rem10;
5346
5347 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5348 exponent10++;
5349 if (rem10 >= 5) {
5350 DWORD x = 1;
5351 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5352 }
5353 }
5354 }
5355 /* Remove multiples of 10 from the representation */
5356 while (exponent10 < 0) {
5357 DWORD temp_bitsnum[3];
5358
5359 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5360 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5361 exponent10++;
5362 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5363 } else break;
5364 }
5365
5366 /* Scale assignment */
5367 if (hres == S_OK) val->scale = -exponent10;
5368
5369 return hres;
5370 }
5371
5372 typedef union
5373 {
5374 struct
5375 {
5376 unsigned int m : 23;
5377 unsigned int exp_bias : 8;
5378 unsigned int sign : 1;
5379 } i;
5380 float f;
5381 } R4_FIELDS;
5382
5383 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5384 intermediate string step. */
5385 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5386 {
5387 HRESULT hres = S_OK;
5388 R4_FIELDS fx;
5389
5390 fx.f = source;
5391
5392 /* Detect special cases */
5393 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5394 /* Floating-point zero */
5395 VARIANT_DI_clear(dest);
5396 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5397 /* Floating-point infinity */
5398 hres = DISP_E_OVERFLOW;
5399 } else if (fx.i.exp_bias == 0xFF) {
5400 /* Floating-point NaN */
5401 hres = DISP_E_BADVARTYPE;
5402 } else {
5403 int exponent2;
5404 VARIANT_DI_clear(dest);
5405
5406 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5407 dest->sign = fx.i.sign; /* Sign is simply copied */
5408
5409 /* Copy significant bits to VARIANT_DI mantissa */
5410 dest->bitsnum[0] = fx.i.m;
5411 dest->bitsnum[0] &= 0x007FFFFF;
5412 if (fx.i.exp_bias == 0) {
5413 /* Denormalized number - correct exponent */
5414 exponent2++;
5415 } else {
5416 /* Add hidden bit to mantissa */
5417 dest->bitsnum[0] |= 0x00800000;
5418 }
5419
5420 /* The act of copying a FP mantissa as integer bits is equivalent to
5421 shifting left the mantissa 23 bits. The exponent2 is reduced to
5422 compensate. */
5423 exponent2 -= 23;
5424
5425 hres = VARIANT_DI_normalize(dest, exponent2, FALSE);
5426 }
5427
5428 return hres;
5429 }
5430
5431 typedef union
5432 {
5433 struct
5434 {
5435 unsigned int m_lo : 32; /* 52 bits of precision */
5436 unsigned int m_hi : 20;
5437 unsigned int exp_bias : 11; /* bias == 1023 */
5438 unsigned int sign : 1;
5439 } i;
5440 double d;
5441 } R8_FIELDS;
5442
5443 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5444 intermediate string step. */
5445 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5446 {
5447 HRESULT hres = S_OK;
5448 R8_FIELDS fx;
5449
5450 fx.d = source;
5451
5452 /* Detect special cases */
5453 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5454 /* Floating-point zero */
5455 VARIANT_DI_clear(dest);
5456 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5457 /* Floating-point infinity */
5458 hres = DISP_E_OVERFLOW;
5459 } else if (fx.i.exp_bias == 0x7FF) {
5460 /* Floating-point NaN */
5461 hres = DISP_E_BADVARTYPE;
5462 } else {
5463 int exponent2;
5464 VARIANT_DI_clear(dest);
5465
5466 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5467 dest->sign = fx.i.sign; /* Sign is simply copied */
5468
5469 /* Copy significant bits to VARIANT_DI mantissa */
5470 dest->bitsnum[0] = fx.i.m_lo;
5471 dest->bitsnum[1] = fx.i.m_hi;
5472 dest->bitsnum[1] &= 0x000FFFFF;
5473 if (fx.i.exp_bias == 0) {
5474 /* Denormalized number - correct exponent */
5475 exponent2++;
5476 } else {
5477 /* Add hidden bit to mantissa */
5478 dest->bitsnum[1] |= 0x00100000;
5479 }
5480
5481 /* The act of copying a FP mantissa as integer bits is equivalent to
5482 shifting left the mantissa 52 bits. The exponent2 is reduced to
5483 compensate. */
5484 exponent2 -= 52;
5485
5486 hres = VARIANT_DI_normalize(dest, exponent2, TRUE);
5487 }
5488
5489 return hres;
5490 }
5491
5492 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
5493 BOOL round)
5494 {
5495 HRESULT hRet = S_OK;
5496 VARIANT_DI di_left, di_right, di_result;
5497 HRESULT divresult;
5498
5499 VARIANT_DIFromDec(pDecLeft, &di_left);
5500 VARIANT_DIFromDec(pDecRight, &di_right);
5501 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
5502 if (divresult != S_OK)
5503 {
5504 /* division actually overflowed */
5505 hRet = divresult;
5506 }
5507 else
5508 {
5509 hRet = S_OK;
5510
5511 if (di_result.scale > DEC_MAX_SCALE)
5512 {
5513 unsigned char remainder = 0;
5514
5515 /* division underflowed. In order to comply with the MSDN
5516 specifications for DECIMAL ranges, some significant digits
5517 must be removed
5518 */
5519 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5520 di_result.scale);
5521 while (di_result.scale > DEC_MAX_SCALE &&
5522 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5523 {
5524 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5525 di_result.scale--;
5526 }
5527 if (di_result.scale > DEC_MAX_SCALE)
5528 {
5529 WARN("result underflowed, setting to 0\n");
5530 di_result.scale = 0;
5531 di_result.sign = 0;
5532 }
5533 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5534 {
5535 unsigned int i;
5536 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5537 ULONGLONG digit = di_result.bitsnum[i] + 1;
5538 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5539 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5540 }
5541 }
5542 }
5543 VARIANT_DecFromDI(&di_result, pDecOut);
5544 }
5545 return hRet;
5546 }
5547
5548 /************************************************************************
5549 * VarDecDiv (OLEAUT32.178)
5550 *
5551 * Divide one DECIMAL by another.
5552 *
5553 * PARAMS
5554 * pDecLeft [I] Source
5555 * pDecRight [I] Value to divide by
5556 * pDecOut [O] Destination
5557 *
5558 * RETURNS
5559 * Success: S_OK.
5560 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5561 */
5562 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5563 {
5564 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5565
5566 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
5567 }
5568
5569 /************************************************************************
5570 * VarDecMul (OLEAUT32.179)
5571 *
5572 * Multiply one DECIMAL by another.
5573 *
5574 * PARAMS
5575 * pDecLeft [I] Source
5576 * pDecRight [I] Value to multiply by
5577 * pDecOut [O] Destination
5578 *
5579 * RETURNS
5580 * Success: S_OK.
5581 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5582 */
5583 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5584 {
5585 HRESULT hRet = S_OK;
5586 VARIANT_DI di_left, di_right, di_result;
5587 int mulresult;
5588
5589 VARIANT_DIFromDec(pDecLeft, &di_left);
5590 VARIANT_DIFromDec(pDecRight, &di_right);
5591 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5592 if (mulresult)
5593 {
5594 /* multiplication actually overflowed */
5595 hRet = DISP_E_OVERFLOW;
5596 }
5597 else
5598 {
5599 if (di_result.scale > DEC_MAX_SCALE)
5600 {
5601 /* multiplication underflowed. In order to comply with the MSDN
5602 specifications for DECIMAL ranges, some significant digits
5603 must be removed
5604 */
5605 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5606 di_result.scale);
5607 while (di_result.scale > DEC_MAX_SCALE &&
5608 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5609 {
5610 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5611 di_result.scale--;
5612 }
5613 if (di_result.scale > DEC_MAX_SCALE)
5614 {
5615 WARN("result underflowed, setting to 0\n");
5616 di_result.scale = 0;
5617 di_result.sign = 0;
5618 }
5619 }
5620 VARIANT_DecFromDI(&di_result, pDecOut);
5621 }
5622 return hRet;
5623 }
5624
5625 /************************************************************************
5626 * VarDecSub (OLEAUT32.181)
5627 *
5628 * Subtract one DECIMAL from another.
5629 *
5630 * PARAMS
5631 * pDecLeft [I] Source
5632 * pDecRight [I] DECIMAL to subtract from pDecLeft
5633 * pDecOut [O] Destination
5634 *
5635 * RETURNS
5636 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5637 */
5638 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5639 {
5640 DECIMAL decRight;
5641
5642 /* Implement as addition of the negative */
5643 VarDecNeg(pDecRight, &decRight);
5644 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5645 }
5646
5647 /************************************************************************
5648 * VarDecAbs (OLEAUT32.182)
5649 *
5650 * Convert a DECIMAL into its absolute value.
5651 *
5652 * PARAMS
5653 * pDecIn [I] Source
5654 * pDecOut [O] Destination
5655 *
5656 * RETURNS
5657 * S_OK. This function does not fail.
5658 */
5659 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5660 {
5661 *pDecOut = *pDecIn;
5662 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5663 return S_OK;
5664 }
5665
5666 /************************************************************************
5667 * VarDecFix (OLEAUT32.187)
5668 *
5669 * Return the integer portion of a DECIMAL.
5670 *
5671 * PARAMS
5672 * pDecIn [I] Source
5673 * pDecOut [O] Destination
5674 *
5675 * RETURNS
5676 * Success: S_OK.
5677 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5678 *
5679 * NOTES
5680 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5681 * negative numbers away from 0, while this function rounds them towards zero.
5682 */
5683 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5684 {
5685 double dbl;
5686 HRESULT hr;
5687
5688 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5689 return E_INVALIDARG;
5690
5691 if (!DEC_SCALE(pDecIn))
5692 {
5693 *pDecOut = *pDecIn; /* Already an integer */
5694 return S_OK;
5695 }
5696
5697 hr = VarR8FromDec(pDecIn, &dbl);
5698 if (SUCCEEDED(hr)) {
5699 LONGLONG rounded = dbl;
5700
5701 hr = VarDecFromI8(rounded, pDecOut);
5702 }
5703 return hr;
5704 }
5705
5706 /************************************************************************
5707 * VarDecInt (OLEAUT32.188)
5708 *
5709 * Return the integer portion of a DECIMAL.
5710 *
5711 * PARAMS
5712 * pDecIn [I] Source
5713 * pDecOut [O] Destination
5714 *
5715 * RETURNS
5716 * Success: S_OK.
5717 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5718 *
5719 * NOTES
5720 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5721 * negative numbers towards 0, while this function rounds them away from zero.
5722 */
5723 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5724 {
5725 double dbl;
5726 HRESULT hr;
5727
5728 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5729 return E_INVALIDARG;
5730
5731 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5732 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5733
5734 hr = VarR8FromDec(pDecIn, &dbl);
5735 if (SUCCEEDED(hr)) {
5736 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
5737
5738 hr = VarDecFromI8(rounded, pDecOut);
5739 }
5740 return hr;
5741 }
5742
5743 /************************************************************************
5744 * VarDecNeg (OLEAUT32.189)
5745 *
5746 * Change the sign of a DECIMAL.
5747 *
5748 * PARAMS
5749 * pDecIn [I] Source
5750 * pDecOut [O] Destination
5751 *
5752 * RETURNS
5753 * S_OK. This function does not fail.
5754 */
5755 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5756 {
5757 *pDecOut = *pDecIn;
5758 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5759 return S_OK;
5760 }
5761
5762 /************************************************************************
5763 * VarDecRound (OLEAUT32.203)
5764 *
5765 * Change the precision of a DECIMAL.
5766 *
5767 * PARAMS
5768 * pDecIn [I] Source
5769 * cDecimals [I] New number of decimals to keep
5770 * pDecOut [O] Destination
5771 *
5772 * RETURNS
5773 * Success: S_OK. pDecOut contains the rounded value.
5774 * Failure: E_INVALIDARG if any argument is invalid.
5775 */
5776 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5777 {
5778 DECIMAL divisor, tmp;
5779 HRESULT hr;
5780 unsigned int i;
5781
5782 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5783 return E_INVALIDARG;
5784
5785 if (cDecimals >= DEC_SCALE(pDecIn))
5786 {
5787 *pDecOut = *pDecIn; /* More precision than we have */
5788 return S_OK;
5789 }
5790
5791 /* truncate significant digits and rescale */
5792 memset(&divisor, 0, sizeof(divisor));
5793 DEC_LO64(&divisor) = 1;
5794
5795 memset(&tmp, 0, sizeof(tmp));
5796 DEC_LO64(&tmp) = 10;
5797 for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i)
5798 {
5799 hr = VarDecMul(&divisor, &tmp, &divisor);
5800 if (FAILED(hr))
5801 return hr;
5802 }
5803
5804 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
5805 if (FAILED(hr))
5806 return hr;
5807
5808 DEC_SCALE(pDecOut) = cDecimals;
5809
5810 return S_OK;
5811 }
5812
5813 /************************************************************************
5814 * VarDecCmp (OLEAUT32.204)
5815 *
5816 * Compare two DECIMAL values.
5817 *
5818 * PARAMS
5819 * pDecLeft [I] Source
5820 * pDecRight [I] Value to compare
5821 *
5822 * RETURNS
5823 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5824 * is less than, equal to or greater than pDecRight respectively.
5825 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5826 */
5827 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5828 {
5829 HRESULT hRet;
5830 DECIMAL result;
5831
5832 if (!pDecLeft || !pDecRight)
5833 return VARCMP_NULL;
5834
5835 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) &&
5836 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5837 return VARCMP_GT;
5838 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) &&
5839 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5840 return VARCMP_LT;
5841
5842 /* Subtract right from left, and compare the result to 0 */
5843 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5844
5845 if (SUCCEEDED(hRet))
5846 {
5847 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5848
5849 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5850 hRet = (HRESULT)VARCMP_LT;
5851 else if (non_zero)
5852 hRet = (HRESULT)VARCMP_GT;
5853 else
5854 hRet = (HRESULT)VARCMP_EQ;
5855 }
5856 return hRet;
5857 }
5858
5859 /************************************************************************
5860 * VarDecCmpR8 (OLEAUT32.298)
5861 *
5862 * Compare a DECIMAL to a double
5863 *
5864 * PARAMS
5865 * pDecLeft [I] DECIMAL Source
5866 * dblRight [I] double to compare to pDecLeft
5867 *
5868 * RETURNS
5869 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5870 * is less than, equal to or greater than pDecLeft respectively.
5871 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5872 */
5873 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5874 {
5875 HRESULT hRet;
5876 DECIMAL decRight;
5877
5878 hRet = VarDecFromR8(dblRight, &decRight);
5879
5880 if (SUCCEEDED(hRet))
5881 hRet = VarDecCmp(pDecLeft, &decRight);
5882
5883 return hRet;
5884 }
5885
5886 /* BOOL
5887 */
5888
5889 /************************************************************************
5890 * VarBoolFromUI1 (OLEAUT32.118)
5891 *
5892 * Convert a VT_UI1 to a VT_BOOL.
5893 *
5894 * PARAMS
5895 * bIn [I] Source
5896 * pBoolOut [O] Destination
5897 *
5898 * RETURNS
5899 * S_OK.
5900 */
5901 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5902 {
5903 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5904 return S_OK;
5905 }
5906
5907 /************************************************************************
5908 * VarBoolFromI2 (OLEAUT32.119)
5909 *
5910 * Convert a VT_I2 to a VT_BOOL.
5911 *
5912 * PARAMS
5913 * sIn [I] Source
5914 * pBoolOut [O] Destination
5915 *
5916 * RETURNS
5917 * S_OK.
5918 */
5919 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5920 {
5921 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5922 return S_OK;
5923 }
5924
5925 /************************************************************************
5926 * VarBoolFromI4 (OLEAUT32.120)
5927 *
5928 * Convert a VT_I4 to a VT_BOOL.
5929 *
5930 * PARAMS
5931 * sIn [I] Source
5932 * pBoolOut [O] Destination
5933 *
5934 * RETURNS
5935 * S_OK.
5936 */
5937 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5938 {
5939 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5940 return S_OK;
5941 }
5942
5943 /************************************************************************
5944 * VarBoolFromR4 (OLEAUT32.121)
5945 *
5946 * Convert a VT_R4 to a VT_BOOL.
5947 *
5948 * PARAMS
5949 * fltIn [I] Source
5950 * pBoolOut [O] Destination
5951 *
5952 * RETURNS
5953 * S_OK.
5954 */
5955 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5956 {
5957 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5958 return S_OK;
5959 }
5960
5961 /************************************************************************
5962 * VarBoolFromR8 (OLEAUT32.122)
5963 *
5964 * Convert a VT_R8 to a VT_BOOL.
5965 *
5966 * PARAMS
5967 * dblIn [I] Source
5968 * pBoolOut [O] Destination
5969 *
5970 * RETURNS
5971 * S_OK.
5972 */
5973 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
5974 {
5975 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
5976 return S_OK;
5977 }
5978
5979 /************************************************************************
5980 * VarBoolFromDate (OLEAUT32.123)
5981 *
5982 * Convert a VT_DATE to a VT_BOOL.
5983 *
5984 * PARAMS
5985 * dateIn [I] Source
5986 * pBoolOut [O] Destination
5987 *
5988 * RETURNS
5989 * S_OK.
5990 */
5991 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
5992 {
5993 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
5994 return S_OK;
5995 }
5996
5997 /************************************************************************
5998 * VarBoolFromCy (OLEAUT32.124)
5999 *
6000 * Convert a VT_CY to a VT_BOOL.
6001 *
6002 * PARAMS
6003 * cyIn [I] Source
6004 * pBoolOut [O] Destination
6005 *
6006 * RETURNS
6007 * S_OK.
6008 */
6009 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
6010 {
6011 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
6012 return S_OK;
6013 }
6014
6015 /************************************************************************
6016 * VARIANT_GetLocalisedText [internal]
6017 *
6018 * Get a localized string from the resources
6019 *
6020 */
6021 BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
6022 {
6023 HRSRC hrsrc;
6024
6025 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
6026 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
6027 if (hrsrc)
6028 {
6029 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc );
6030
6031 if (hmem)
6032 {
6033 const WCHAR *p;
6034 unsigned int i;
6035
6036 p = LockResource( hmem );
6037 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
6038
6039 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
6040 lpszDest[*p] = '\0';
6041 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
6042 return TRUE;
6043 }
6044 }
6045 return FALSE;
6046 }
6047
6048 /************************************************************************
6049 * VarBoolFromStr (OLEAUT32.125)
6050 *
6051 * Convert a VT_BSTR to a VT_BOOL.
6052 *
6053 * PARAMS
6054 * strIn [I] Source
6055 * lcid [I] LCID for the conversion
6056 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6057 * pBoolOut [O] Destination
6058 *
6059 * RETURNS
6060 * Success: S_OK.
6061 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6062 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6063 *
6064 * NOTES
6065 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6066 * it may contain (in any case mapping) the text "true" or "false".
6067 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6068 * localised text of "True" or "False" in the language specified by lcid.
6069 * - If none of these matches occur, the string is treated as a numeric string
6070 * and the boolean pBoolOut will be set according to whether the number is zero
6071 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6072 * - If the text is not numeric and does not match any of the above, then
6073 * DISP_E_TYPEMISMATCH is returned.
6074 */
6075 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6076 {
6077 /* Any VB/VBA programmers out there should recognise these strings... */
6078 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
6079 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
6080 WCHAR szBuff[64];
6081 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6082 HRESULT hRes = S_OK;
6083
6084 if (!strIn || !pBoolOut)
6085 return DISP_E_TYPEMISMATCH;
6086
6087 /* Check if we should be comparing against localised text */
6088 if (dwFlags & VAR_LOCALBOOL)
6089 {
6090 /* Convert our LCID into a usable value */
6091 lcid = ConvertDefaultLocale(lcid);
6092
6093 langId = LANGIDFROMLCID(lcid);
6094
6095 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6096 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6097
6098 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6099 * I don't think this is needed unless any of the localised text strings
6100 * contain characters that can be so mapped. In the event that this is
6101 * true for a given language (possibly some Asian languages), then strIn
6102 * should be mapped here _only_ if langId is an Id for which this can occur.
6103 */
6104 }
6105
6106 /* Note that if we are not comparing against localised strings, langId
6107 * will have its default value of LANG_ENGLISH. This allows us to mimic
6108 * the native behaviour of always checking against English strings even
6109 * after we've checked for localised ones.
6110 */
6111 VarBoolFromStr_CheckLocalised:
6112 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6113 {
6114 /* Compare against localised strings, ignoring case */
6115 if (!strcmpiW(strIn, szBuff))
6116 {
6117 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6118 return hRes;
6119 }
6120 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6121 if (!strcmpiW(strIn, szBuff))
6122 {
6123 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6124 return hRes;
6125 }
6126 }
6127
6128 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6129 {
6130 /* We have checked the localised text, now check English */
6131 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6132 goto VarBoolFromStr_CheckLocalised;
6133 }
6134
6135 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6136 if (!strcmpW(strIn, szFalse))
6137 *pBoolOut = VARIANT_FALSE;
6138 else if (!strcmpW(strIn, szTrue))
6139 *pBoolOut = VARIANT_TRUE;
6140 else
6141 {
6142 double d;
6143
6144 /* If this string is a number, convert it as one */
6145 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6146 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6147 }
6148 return hRes;
6149 }
6150
6151 /************************************************************************
6152 * VarBoolFromDisp (OLEAUT32.126)
6153 *
6154 * Convert a VT_DISPATCH to a VT_BOOL.
6155 *
6156 * PARAMS
6157 * pdispIn [I] Source
6158 * lcid [I] LCID for conversion
6159 * pBoolOut [O] Destination
6160 *
6161 * RETURNS
6162 * Success: S_OK.
6163 * Failure: E_INVALIDARG, if the source value is invalid
6164 * DISP_E_OVERFLOW, if the value will not fit in the destination
6165 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6166 */
6167 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6168 {
6169 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6170 }
6171
6172 /************************************************************************
6173 * VarBoolFromI1 (OLEAUT32.233)
6174 *
6175 * Convert a VT_I1 to a VT_BOOL.
6176 *
6177 * PARAMS
6178 * cIn [I] Source
6179 * pBoolOut [O] Destination
6180 *
6181 * RETURNS
6182 * S_OK.
6183 */
6184 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6185 {
6186 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6187 return S_OK;
6188 }
6189
6190 /************************************************************************
6191 * VarBoolFromUI2 (OLEAUT32.234)
6192 *
6193 * Convert a VT_UI2 to a VT_BOOL.
6194 *
6195 * PARAMS
6196 * usIn [I] Source
6197 * pBoolOut [O] Destination
6198 *
6199 * RETURNS
6200 * S_OK.
6201 */
6202 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6203 {
6204 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6205 return S_OK;
6206 }
6207
6208 /************************************************************************
6209 * VarBoolFromUI4 (OLEAUT32.235)
6210 *
6211 * Convert a VT_UI4 to a VT_BOOL.
6212 *
6213 * PARAMS
6214 * ulIn [I] Source
6215 * pBoolOut [O] Destination
6216 *
6217 * RETURNS
6218 * S_OK.
6219 */
6220 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6221 {
6222 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6223 return S_OK;
6224 }
6225
6226 /************************************************************************
6227 * VarBoolFromDec (OLEAUT32.236)
6228 *
6229 * Convert a VT_DECIMAL to a VT_BOOL.
6230 *
6231 * PARAMS
6232 * pDecIn [I] Source
6233 * pBoolOut [O] Destination
6234 *
6235 * RETURNS
6236 * Success: S_OK.
6237 * Failure: E_INVALIDARG, if pDecIn is invalid.
6238 */
6239 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6240 {
6241 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6242 return E_INVALIDARG;
6243
6244 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6245 *pBoolOut = VARIANT_TRUE;
6246 else
6247 *pBoolOut = VARIANT_FALSE;
6248 return S_OK;
6249 }
6250
6251 /************************************************************************
6252 * VarBoolFromI8 (OLEAUT32.370)
6253 *
6254 * Convert a VT_I8 to a VT_BOOL.
6255 *
6256 * PARAMS
6257 * ullIn [I] Source
6258 * pBoolOut [O] Destination
6259 *
6260 * RETURNS
6261 * S_OK.
6262 */
6263 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6264 {
6265 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6266 return S_OK;
6267 }
6268
6269 /************************************************************************
6270 * VarBoolFromUI8 (OLEAUT32.371)
6271 *
6272 * Convert a VT_UI8 to a VT_BOOL.
6273 *
6274 * PARAMS
6275 * ullIn [I] Source
6276 * pBoolOut [O] Destination
6277 *
6278 * RETURNS
6279 * S_OK.
6280 */
6281 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6282 {
6283 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6284 return S_OK;
6285 }
6286
6287 /* BSTR
6288 */
6289
6290 /* Write a number from a UI8 and sign */
6291 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6292 {
6293 do
6294 {
6295 WCHAR ulNextDigit = ulVal % 10;
6296
6297 *szOut-- = '0' + ulNextDigit;
6298 ulVal = (ulVal - ulNextDigit) / 10;
6299 } while (ulVal);
6300
6301 szOut++;
6302 return szOut;
6303 }
6304
6305 /* Create a (possibly localised) BSTR from a UI8 and sign */
6306 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6307 {
6308 WCHAR szConverted[256];
6309
6310 if (dwFlags & VAR_NEGATIVE)
6311 *--szOut = '-';
6312
6313 if (dwFlags & LOCALE_USE_NLS)
6314 {
6315 /* Format the number for the locale */
6316 szConverted[0] = '\0';
6317 GetNumberFormatW(lcid,
6318 dwFlags & LOCALE_NOUSEROVERRIDE,
6319 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
6320 szOut = szConverted;
6321 }
6322 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
6323 }
6324
6325 /* Create a (possibly localised) BSTR from a UI8 and sign */
6326 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6327 {
6328 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
6329
6330 if (!pbstrOut)
6331 return E_INVALIDARG;
6332
6333 /* Create the basic number string */
6334 *szOut-- = '\0';
6335 szOut = VARIANT_WriteNumber(ulVal, szOut);
6336
6337 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6338 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6339 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6340 }
6341
6342 /******************************************************************************
6343 * VarBstrFromUI1 (OLEAUT32.108)
6344 *
6345 * Convert a VT_UI1 to a VT_BSTR.
6346 *
6347 * PARAMS
6348 * bIn [I] Source
6349 * lcid [I] LCID for the conversion
6350 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6351 * pbstrOut [O] Destination
6352 *
6353 * RETURNS
6354 * Success: S_OK.
6355 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6356 * E_OUTOFMEMORY, if memory allocation fails.
6357 */
6358 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6359 {
6360 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6361 }
6362
6363 /******************************************************************************
6364 * VarBstrFromI2 (OLEAUT32.109)
6365 *
6366 * Convert a VT_I2 to a VT_BSTR.
6367 *
6368 * PARAMS
6369 * sIn [I] Source
6370 * lcid [I] LCID for the conversion
6371 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6372 * pbstrOut [O] Destination
6373 *
6374 * RETURNS
6375 * Success: S_OK.
6376 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6377 * E_OUTOFMEMORY, if memory allocation fails.
6378 */
6379 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6380 {
6381 ULONG64 ul64 = sIn;
6382
6383 if (sIn < 0)
6384 {
6385 ul64 = -sIn;
6386 dwFlags |= VAR_NEGATIVE;
6387 }
6388 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6389 }
6390
6391 /******************************************************************************
6392 * VarBstrFromI4 (OLEAUT32.110)
6393 *
6394 * Convert a VT_I4 to a VT_BSTR.
6395 *
6396 * PARAMS
6397 * lIn [I] Source
6398 * lcid [I] LCID for the conversion
6399 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6400 * pbstrOut [O] Destination
6401 *
6402 * RETURNS
6403 * Success: S_OK.
6404 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6405 * E_OUTOFMEMORY, if memory allocation fails.
6406 */
6407 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6408 {
6409 ULONG64 ul64 = lIn;
6410
6411 if (lIn < 0)
6412 {
6413 ul64 = (ULONG)-lIn;
6414 dwFlags |= VAR_NEGATIVE;
6415 }
6416 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6417 }
6418
6419 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
6420 {
6421 BSTR bstrOut;
6422 WCHAR lpDecimalSep[16];
6423
6424 /* Native oleaut32 uses the locale-specific decimal separator even in the
6425 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6426 American locales will see "one thousand and one tenth" as "1000,1"
6427 instead of "1000.1" (notice the comma). The following code checks for
6428 the need to replace the decimal separator, and if so, will prepare an
6429 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6430 */
6431 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6432 lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6433 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6434 {
6435 /* locale is compatible with English - return original string */
6436 bstrOut = SysAllocString(buff);
6437 }
6438 else
6439 {
6440 WCHAR *p;
6441 WCHAR numbuff[256];
6442 WCHAR empty[] = {'\0'};
6443 NUMBERFMTW minFormat;
6444
6445 minFormat.NumDigits = 0;
6446 minFormat.LeadingZero = 0;
6447 minFormat.Grouping = 0;
6448 minFormat.lpDecimalSep = lpDecimalSep;
6449 minFormat.lpThousandSep = empty;
6450 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6451
6452 /* count number of decimal digits in string */
6453 p = strchrW( buff, '.' );
6454 if (p) minFormat.NumDigits = strlenW(p + 1);
6455
6456 numbuff[0] = '\0';
6457 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6458 {
6459 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6460 bstrOut = SysAllocString(buff);
6461 }
6462 else
6463 {
6464 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6465 bstrOut = SysAllocString(numbuff);
6466 }
6467 }
6468 return bstrOut;
6469 }
6470
6471 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6472 BSTR* pbstrOut, LPCWSTR lpszFormat)
6473 {
6474 WCHAR buff[256];
6475
6476 if (!pbstrOut)
6477 return E_INVALIDARG;
6478
6479 sprintfW( buff, lpszFormat, dblIn );
6480
6481 /* Negative zeroes are disallowed (some applications depend on this).
6482 If buff starts with a minus, and then nothing follows but zeroes
6483 and/or a period, it is a negative zero and is replaced with a
6484 canonical zero. This duplicates native oleaut32 behavior.
6485 */
6486 if (buff[0] == '-')
6487 {
6488 const WCHAR szAccept[] = {'0', '.', '\0'};
6489 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6490 { buff[0] = '0'; buff[1] = '\0'; }
6491 }
6492
6493 TRACE("created string %s\n", debugstr_w(buff));
6494 if (dwFlags & LOCALE_USE_NLS)
6495 {
6496 WCHAR numbuff[256];
6497
6498 /* Format the number for the locale */
6499 numbuff[0] = '\0';
6500 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6501 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6502 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6503 *pbstrOut = SysAllocString(numbuff);
6504 }
6505 else
6506 {
6507 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6508 }
6509 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6510 }
6511
6512 /******************************************************************************
6513 * VarBstrFromR4 (OLEAUT32.111)
6514 *
6515 * Convert a VT_R4 to a VT_BSTR.
6516 *
6517 * PARAMS
6518 * fltIn [I] Source
6519 * lcid [I] LCID for the conversion
6520 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6521 * pbstrOut [O] Destination
6522 *
6523 * RETURNS
6524 * Success: S_OK.
6525 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6526 * E_OUTOFMEMORY, if memory allocation fails.
6527 */
6528 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6529 {
6530 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6531 }
6532
6533 /******************************************************************************
6534 * VarBstrFromR8 (OLEAUT32.112)
6535 *
6536 * Convert a VT_R8 to a VT_BSTR.
6537 *
6538 * PARAMS
6539 * dblIn [I] Source
6540 * lcid [I] LCID for the conversion
6541 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6542 * pbstrOut [O] Destination
6543 *
6544 * RETURNS
6545 * Success: S_OK.
6546 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6547 * E_OUTOFMEMORY, if memory allocation fails.
6548 */
6549 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6550 {
6551 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6552 }
6553
6554 /******************************************************************************
6555 * VarBstrFromCy [OLEAUT32.113]
6556 *
6557 * Convert a VT_CY to a VT_BSTR.
6558 *
6559 * PARAMS
6560 * cyIn [I] Source
6561 * lcid [I] LCID for the conversion
6562 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6563 * pbstrOut [O] Destination
6564 *
6565 * RETURNS
6566 * Success: S_OK.
6567 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6568 * E_OUTOFMEMORY, if memory allocation fails.
6569 */
6570 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6571 {
6572 WCHAR buff[256];
6573 VARIANT_DI decVal;
6574
6575 if (!pbstrOut)
6576 return E_INVALIDARG;
6577
6578 decVal.scale = 4;
6579 decVal.sign = 0;
6580 decVal.bitsnum[0] = cyIn.s.Lo;
6581 decVal.bitsnum[1] = cyIn.s.Hi;
6582 if (cyIn.s.Hi & 0x80000000UL) {
6583 DWORD one = 1;
6584
6585 /* Negative number! */
6586 decVal.sign = 1;
6587 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6588 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6589 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6590 }
6591 decVal.bitsnum[2] = 0;
6592 VARIANT_DI_tostringW(&decVal, buff, sizeof(buff)/sizeof(buff[0]));
6593
6594 if (dwFlags & LOCALE_USE_NLS)
6595 {
6596 WCHAR cybuff[256];
6597
6598 /* Format the currency for the locale */
6599 cybuff[0] = '\0';
6600 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6601 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6602 *pbstrOut = SysAllocString(cybuff);
6603 }
6604 else
6605 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
6606
6607 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6608 }
6609
6610 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
6611 {
6612 int len, tmp;
6613
6614 if(min_len >= date_len)
6615 return -1;
6616
6617 for(len=0, tmp=o; tmp; tmp/=10) len++;
6618 if(!len) len++;
6619 if(len >= date_len)
6620 return -1;
6621
6622 for(tmp=min_len-len; tmp>0; tmp--)
6623 *date++ = '0';
6624 for(tmp=len; tmp>0; tmp--, o/=10)
6625 date[tmp-1] = '0' + o%10;
6626 return min_len>len ? min_len : len;
6627 }
6628
6629 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6630 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
6631 const WCHAR *fmt, WCHAR *date, int date_len)
6632 {
6633 static const LCTYPE dayname[] = {
6634 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
6635 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
6636 };
6637 static const LCTYPE sdayname[] = {
6638 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
6639 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
6640 LOCALE_SABBREVDAYNAME6
6641 };
6642 static const LCTYPE monthname[] = {
6643 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6644 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6645 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
6646 };
6647 static const LCTYPE smonthname[] = {
6648 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6649 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6650 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6651 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
6652 };
6653
6654 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
6655 FIXME("ignoring flags %x\n", flags);
6656 flags &= LOCALE_NOUSEROVERRIDE;
6657
6658 while(*fmt && date_len) {
6659 int count = 1;
6660
6661 switch(*fmt) {
6662 case 'd':
6663 case 'M':
6664 case 'y':
6665 case 'g':
6666 while(*fmt == *(fmt+count))
6667 count++;
6668 fmt += count-1;
6669 }
6670
6671 switch(*fmt) {
6672 case 'd':
6673 if(count >= 4)
6674 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
6675 else if(count == 3)
6676 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
6677 else
6678 count = output_int_len(st->wDay, count, date, date_len);
6679 break;
6680 case 'M':
6681 if(count >= 4)
6682 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
6683 else if(count == 3)
6684 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
6685 else
6686 count = output_int_len(st->wMonth, count, date, date_len);
6687 break;
6688 case 'y':
6689 if(count >= 3)
6690 count = output_int_len(st->wYear, 0, date, date_len);
6691 else
6692 count = output_int_len(st->wYear%100, count, date, date_len);
6693 break;
6694 case 'g':
6695 if(count == 2) {
6696 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6697
6698 *date++ = 'A';
6699 date_len--;
6700 if(date_len)
6701 *date = 'D';
6702 else
6703 count = -1;
6704 break;
6705 }
6706 /* fall through */
6707 default:
6708 *date = *fmt;
6709 }
6710
6711 if(count < 0)
6712 break;
6713 fmt++;
6714 date += count;
6715 date_len -= count;
6716 }
6717
6718 if(!date_len)
6719 return FALSE;
6720 *date++ = 0;
6721 return TRUE;
6722 }
6723
6724 /******************************************************************************
6725 * VarBstrFromDate [OLEAUT32.114]
6726 *
6727 * Convert a VT_DATE to a VT_BSTR.
6728 *
6729 * PARAMS
6730 * dateIn [I] Source
6731 * lcid [I] LCID for the conversion
6732 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6733 * pbstrOut [O] Destination
6734 *
6735 * RETURNS
6736 * Success: S_OK.
6737 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6738 * E_OUTOFMEMORY, if memory allocation fails.
6739 */
6740 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6741 {
6742 SYSTEMTIME st;
6743 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6744 WCHAR date[128], fmt_buff[80], *time;
6745
6746 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6747
6748 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6749 return E_INVALIDARG;
6750
6751 *pbstrOut = NULL;
6752
6753 if (dwFlags & VAR_CALENDAR_THAI)
6754 st.wYear += 553; /* Use the Thai buddhist calendar year */
6755 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6756 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6757
6758 if (dwFlags & LOCALE_USE_NLS)
6759 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6760 else
6761 {
6762 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6763 double partial = dateIn - whole;
6764
6765 if (whole == 0.0)
6766 dwFlags |= VAR_TIMEVALUEONLY;
6767 else if (partial > -1e-12 && partial < 1e-12)
6768 dwFlags |= VAR_DATEVALUEONLY;
6769 }
6770
6771 if (dwFlags & VAR_TIMEVALUEONLY)
6772 date[0] = '\0';
6773 else
6774 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, sizeof(fmt_buff)/sizeof(WCHAR)) ||
6775 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, sizeof(date)/sizeof(WCHAR)))
6776 return E_INVALIDARG;
6777
6778 if (!(dwFlags & VAR_DATEVALUEONLY))
6779 {
6780 time = date + strlenW(date);
6781 if (time != date)
6782 *time++ = ' ';
6783 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6784 sizeof(date)/sizeof(WCHAR)-(time-date)))
6785 return E_INVALIDARG;
6786 }
6787
6788 *pbstrOut = SysAllocString(date);
6789 if (*pbstrOut)
6790 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6791 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6792 }
6793
6794 /******************************************************************************
6795 * VarBstrFromBool (OLEAUT32.116)
6796 *
6797 * Convert a VT_BOOL to a VT_BSTR.
6798 *
6799 * PARAMS
6800 * boolIn [I] Source
6801 * lcid [I] LCID for the conversion
6802 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6803 * pbstrOut [O] Destination
6804 *
6805 * RETURNS
6806 * Success: S_OK.
6807 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6808 * E_OUTOFMEMORY, if memory allocation fails.
6809 *
6810 * NOTES
6811 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6812 * localised text of "True" or "False". To convert a bool into a
6813 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6814 */
6815 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6816 {
6817 WCHAR szBuff[64];
6818 DWORD dwResId = IDS_TRUE;
6819 LANGID langId;
6820
6821 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6822
6823 if (!pbstrOut)
6824 return E_INVALIDARG;
6825
6826 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6827 * for variant formatting */
6828 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6829 {
6830 case VAR_BOOLONOFF:
6831 dwResId = IDS_ON;
6832 break;
6833 case VAR_BOOLYESNO:
6834 dwResId = IDS_YES;
6835 break;
6836 case VAR_LOCALBOOL:
6837 break;
6838 default:
6839 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6840 }
6841
6842 lcid = ConvertDefaultLocale(lcid);
6843 langId = LANGIDFROMLCID(lcid);
6844 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6845 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6846
6847 if (boolIn == VARIANT_FALSE)
6848 dwResId++; /* Use negative form */
6849
6850 VarBstrFromBool_GetLocalised:
6851 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6852 {
6853 *pbstrOut = SysAllocString(szBuff);
6854 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6855 }
6856
6857 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6858 {
6859 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6860 goto VarBstrFromBool_GetLocalised;
6861 }
6862
6863 /* Should never get here */
6864 WARN("Failed to load bool text!\n");
6865 return E_OUTOFMEMORY;
6866 }
6867
6868 /******************************************************************************
6869 * VarBstrFromI1 (OLEAUT32.229)
6870 *
6871 * Convert a VT_I1 to a VT_BSTR.
6872 *
6873 * PARAMS
6874 * cIn [I] Source
6875 * lcid [I] LCID for the conversion
6876 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6877 * pbstrOut [O] Destination
6878 *
6879 * RETURNS
6880 * Success: S_OK.
6881 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6882 * E_OUTOFMEMORY, if memory allocation fails.
6883 */
6884 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6885 {
6886 ULONG64 ul64 = cIn;
6887
6888 if (cIn < 0)
6889 {
6890 ul64 = -cIn;
6891 dwFlags |= VAR_NEGATIVE;
6892 }
6893 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6894 }
6895
6896 /******************************************************************************
6897 * VarBstrFromUI2 (OLEAUT32.230)
6898 *
6899 * Convert a VT_UI2 to a VT_BSTR.
6900 *
6901 * PARAMS
6902 * usIn [I] Source
6903 * lcid [I] LCID for the conversion
6904 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6905 * pbstrOut [O] Destination
6906 *
6907 * RETURNS
6908 * Success: S_OK.
6909 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6910 * E_OUTOFMEMORY, if memory allocation fails.
6911 */
6912 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6913 {
6914 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6915 }
6916
6917 /******************************************************************************
6918 * VarBstrFromUI4 (OLEAUT32.231)
6919 *
6920 * Convert a VT_UI4 to a VT_BSTR.
6921 *
6922 * PARAMS
6923 * ulIn [I] Source
6924 * lcid [I] LCID for the conversion
6925 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6926 * pbstrOut [O] Destination
6927 *
6928 * RETURNS
6929 * Success: S_OK.
6930 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6931 * E_OUTOFMEMORY, if memory allocation fails.
6932 */
6933 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6934 {
6935 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6936 }
6937
6938 /******************************************************************************
6939 * VarBstrFromDec (OLEAUT32.232)
6940 *
6941 * Convert a VT_DECIMAL to a VT_BSTR.
6942 *
6943 * PARAMS
6944 * pDecIn [I] Source
6945 * lcid [I] LCID for the conversion
6946 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6947 * pbstrOut [O] Destination
6948 *
6949 * RETURNS
6950 * Success: S_OK.
6951 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6952 * E_OUTOFMEMORY, if memory allocation fails.
6953 */
6954 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6955 {
6956 WCHAR buff[256];
6957 VARIANT_DI temp;
6958
6959 if (!pbstrOut)
6960 return E_INVALIDARG;
6961
6962 VARIANT_DIFromDec(pDecIn, &temp);
6963 VARIANT_DI_tostringW(&temp, buff, 256);
6964
6965 if (dwFlags & LOCALE_USE_NLS)
6966 {
6967 WCHAR numbuff[256];
6968
6969 /* Format the number for the locale */
6970 numbuff[0] = '\0';
6971 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6972 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6973 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6974 *pbstrOut = SysAllocString(numbuff);
6975 }
6976 else
6977 {
6978 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6979 }
6980
6981 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6982 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6983 }
6984
6985 /************************************************************************
6986 * VarBstrFromI8 (OLEAUT32.370)
6987 *
6988 * Convert a VT_I8 to a VT_BSTR.
6989 *
6990 * PARAMS
6991 * llIn [I] Source
6992 * lcid [I] LCID for the conversion
6993 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6994 * pbstrOut [O] Destination
6995 *
6996 * RETURNS
6997 * Success: S_OK.
6998 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6999 * E_OUTOFMEMORY, if memory allocation fails.
7000 */
7001 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7002 {
7003 ULONG64 ul64 = llIn;
7004
7005 if (llIn < 0)
7006 {
7007 ul64 = -llIn;
7008 dwFlags |= VAR_NEGATIVE;
7009 }
7010 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
7011 }
7012
7013 /************************************************************************
7014 * VarBstrFromUI8 (OLEAUT32.371)
7015 *
7016 * Convert a VT_UI8 to a VT_BSTR.
7017 *
7018 * PARAMS
7019 * ullIn [I] Source
7020 * lcid [I] LCID for the conversion
7021 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7022 * pbstrOut [O] Destination
7023 *
7024 * RETURNS
7025 * Success: S_OK.
7026 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7027 * E_OUTOFMEMORY, if memory allocation fails.
7028 */
7029 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7030 {
7031 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
7032 }
7033
7034 /************************************************************************
7035 * VarBstrFromDisp (OLEAUT32.115)
7036 *
7037 * Convert a VT_DISPATCH to a BSTR.
7038 *
7039 * PARAMS
7040 * pdispIn [I] Source
7041 * lcid [I] LCID for conversion
7042 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7043 * pbstrOut [O] Destination
7044 *
7045 * RETURNS
7046 * Success: S_OK.
7047 * Failure: E_INVALIDARG, if the source value is invalid
7048 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7049 */
7050 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7051 {
7052 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
7053 }
7054
7055 /**********************************************************************
7056 * VarBstrCat (OLEAUT32.313)
7057 *
7058 * Concatenate two BSTR values.
7059 *
7060 * PARAMS
7061 * pbstrLeft [I] Source
7062 * pbstrRight [I] Value to concatenate
7063 * pbstrOut [O] Destination
7064 *
7065 * RETURNS
7066 * Success: S_OK.
7067 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7068 * E_OUTOFMEMORY, if memory allocation fails.
7069 */
7070 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
7071 {
7072 unsigned int lenLeft, lenRight;
7073
7074 TRACE("%s,%s,%p\n",
7075 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7076 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
7077
7078 if (!pbstrOut)
7079 return E_INVALIDARG;
7080
7081 /* use byte length here to properly handle ansi-allocated BSTRs */
7082 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
7083 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
7084
7085 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
7086 if (!*pbstrOut)
7087 return E_OUTOFMEMORY;
7088
7089 (*pbstrOut)[0] = '\0';
7090
7091 if (pbstrLeft)
7092 memcpy(*pbstrOut, pbstrLeft, lenLeft);
7093
7094 if (pbstrRight)
7095 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
7096
7097 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
7098 return S_OK;
7099 }
7100
7101 /**********************************************************************
7102 * VarBstrCmp (OLEAUT32.314)
7103 *
7104 * Compare two BSTR values.
7105 *
7106 * PARAMS
7107 * pbstrLeft [I] Source
7108 * pbstrRight [I] Value to compare
7109 * lcid [I] LCID for the comparison
7110 * dwFlags [I] Flags to pass directly to CompareStringW().
7111 *
7112 * RETURNS
7113 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7114 * than, equal to or greater than pbstrRight respectively.
7115 *
7116 * NOTES
7117 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7118 * states. A NULL BSTR pointer is equivalent to an empty string.
7119 * If LCID is equal to 0, a byte by byte comparison is performed.
7120 */
7121 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
7122 {
7123 HRESULT hres;
7124 int ret;
7125
7126 TRACE("%s,%s,%d,%08x\n",
7127 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7128 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
7129
7130 if (!pbstrLeft || !*pbstrLeft)
7131 {
7132 if (pbstrRight && *pbstrRight)
7133 return VARCMP_LT;
7134 }
7135 else if (!pbstrRight || !*pbstrRight)
7136 return VARCMP_GT;
7137
7138 if (lcid == 0)
7139 {
7140 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
7141 unsigned int lenRight = SysStringByteLen(pbstrRight);
7142 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
7143 if (ret < 0)
7144 return VARCMP_LT;
7145 if (ret > 0)
7146 return VARCMP_GT;
7147 if (lenLeft < lenRight)
7148 return VARCMP_LT;
7149 if (lenLeft > lenRight)
7150 return VARCMP_GT;
7151 return VARCMP_EQ;
7152 }
7153 else
7154 {
7155 unsigned int lenLeft = SysStringLen(pbstrLeft);
7156 unsigned int lenRight = SysStringLen(pbstrRight);
7157
7158 if (lenLeft == 0 || lenRight == 0)
7159 {
7160 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
7161 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
7162 }
7163
7164 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
7165 pbstrRight, lenRight) - CSTR_LESS_THAN;
7166 TRACE("%d\n", hres);
7167 return hres;
7168 }
7169 }
7170
7171 /*
7172 * DATE
7173 */
7174
7175 /******************************************************************************
7176 * VarDateFromUI1 (OLEAUT32.88)
7177 *
7178 * Convert a VT_UI1 to a VT_DATE.
7179 *
7180 * PARAMS
7181 * bIn [I] Source
7182 * pdateOut [O] Destination
7183 *
7184 * RETURNS
7185 * S_OK.
7186 */
7187 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7188 {
7189 return VarR8FromUI1(bIn, pdateOut);
7190 }
7191
7192 /******************************************************************************
7193 * VarDateFromI2 (OLEAUT32.89)
7194 *
7195 * Convert a VT_I2 to a VT_DATE.
7196 *
7197 * PARAMS
7198 * sIn [I] Source
7199 * pdateOut [O] Destination
7200 *
7201 * RETURNS
7202 * S_OK.
7203 */
7204 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7205 {
7206 return VarR8FromI2(sIn, pdateOut);
7207 }
7208
7209 /******************************************************************************
7210 * VarDateFromI4 (OLEAUT32.90)
7211 *
7212 * Convert a VT_I4 to a VT_DATE.
7213 *
7214 * PARAMS
7215 * lIn [I] Source
7216 * pdateOut [O] Destination
7217 *
7218 * RETURNS
7219 * S_OK.
7220 */
7221 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7222 {
7223 return VarDateFromR8(lIn, pdateOut);
7224 }
7225
7226 /******************************************************************************
7227 * VarDateFromR4 (OLEAUT32.91)
7228 *
7229 * Convert a VT_R4 to a VT_DATE.
7230 *
7231 * PARAMS
7232 * fltIn [I] Source
7233 * pdateOut [O] Destination
7234 *
7235 * RETURNS
7236 * S_OK.
7237 */
7238 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7239 {
7240 return VarR8FromR4(fltIn, pdateOut);
7241 }
7242
7243 /******************************************************************************
7244 * VarDateFromR8 (OLEAUT32.92)
7245 *
7246 * Convert a VT_R8 to a VT_DATE.
7247 *
7248 * PARAMS
7249 * dblIn [I] Source
7250 * pdateOut [O] Destination
7251 *
7252 * RETURNS
7253 * S_OK.
7254 */
7255 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7256 {
7257 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7258 *pdateOut = (DATE)dblIn;
7259 return S_OK;
7260 }
7261
7262 /**********************************************************************
7263 * VarDateFromDisp (OLEAUT32.95)
7264 *
7265 * Convert a VT_DISPATCH to a VT_DATE.
7266 *
7267 * PARAMS
7268 * pdispIn [I] Source
7269 * lcid [I] LCID for conversion
7270 * pdateOut [O] Destination
7271 *
7272 * RETURNS
7273 * Success: S_OK.
7274 * Failure: E_INVALIDARG, if the source value is invalid
7275 * DISP_E_OVERFLOW, if the value will not fit in the destination
7276 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7277 */
7278 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7279 {
7280 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7281 }
7282
7283 /******************************************************************************
7284 * VarDateFromBool (OLEAUT32.96)
7285 *
7286 * Convert a VT_BOOL to a VT_DATE.
7287 *
7288 * PARAMS
7289 * boolIn [I] Source
7290 * pdateOut [O] Destination
7291 *
7292 * RETURNS
7293 * S_OK.
7294 */
7295 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7296 {
7297 return VarR8FromBool(boolIn, pdateOut);
7298 }
7299
7300 /**********************************************************************
7301 * VarDateFromCy (OLEAUT32.93)
7302 *
7303 * Convert a VT_CY to a VT_DATE.
7304 *
7305 * PARAMS
7306 * lIn [I] Source
7307 * pdateOut [O] Destination
7308 *
7309 * RETURNS
7310 * S_OK.
7311 */
7312 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7313 {
7314 return VarR8FromCy(cyIn, pdateOut);
7315 }
7316
7317 /* Date string parsing */
7318 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7319 #define DP_DATESEP 0x02 /* Date separator */
7320 #define DP_MONTH 0x04 /* Month name */
7321 #define DP_AM 0x08 /* AM */
7322 #define DP_PM 0x10 /* PM */
7323
7324 typedef struct tagDATEPARSE
7325 {
7326 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7327 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7328 DWORD dwFlags[6]; /* Flags for each field */
7329 DWORD dwValues[6]; /* Value of each field */
7330 } DATEPARSE;
7331
7332 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7333
7334 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7335
7336 /* Determine if a day is valid in a given month of a given year */
7337 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7338 {
7339 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7340
7341 if (day && month && month < 13)
7342 {
7343 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7344 return TRUE;
7345 }
7346 return FALSE;
7347 }
7348
7349 /* Possible orders for 3 numbers making up a date */
7350 #define ORDER_MDY 0x01
7351 #define ORDER_YMD 0x02
7352 #define ORDER_YDM 0x04
7353 #define ORDER_DMY 0x08
7354 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7355
7356 /* Determine a date for a particular locale, from 3 numbers */
7357 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7358 DWORD offset, SYSTEMTIME *st)
7359 {
7360 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7361
7362 if (!dp->dwCount)
7363 {
7364 v1 = 30; /* Default to (Variant) 0 date part */
7365 v2 = 12;
7366 v3 = 1899;
7367 goto VARIANT_MakeDate_OK;
7368 }
7369
7370 v1 = dp->dwValues[offset + 0];
7371 v2 = dp->dwValues[offset + 1];
7372 if (dp->dwCount == 2)
7373 {
7374 SYSTEMTIME current;
7375 GetSystemTime(&current);
7376 v3 = current.wYear;
7377 }
7378 else
7379 v3 = dp->dwValues[offset + 2];
7380
7381 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset);
7382
7383 /* If one number must be a month (Because a month name was given), then only
7384 * consider orders with the month in that position.
7385 * If we took the current year as 'v3', then only allow a year in that position.
7386 */
7387 if (dp->dwFlags[offset + 0] & DP_MONTH)
7388 {
7389 dwAllOrders = ORDER_MDY;
7390 }
7391 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7392 {
7393 dwAllOrders = ORDER_DMY;
7394 if (dp->dwCount > 2)
7395 dwAllOrders |= ORDER_YMD;
7396 }
7397 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7398 {
7399 dwAllOrders = ORDER_YDM;
7400 }
7401 else
7402 {
7403 dwAllOrders = ORDER_MDY|ORDER_DMY;
7404 if (dp->dwCount > 2)
7405 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7406 }
7407
7408 VARIANT_MakeDate_Start:
7409 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders);
7410
7411 while (dwAllOrders)
7412 {
7413 DWORD dwTemp;
7414
7415 if (dwCount == 0)
7416 {
7417 /* First: Try the order given by iDate */
7418 switch (iDate)
7419 {
7420 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7421 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7422 default: dwTry = dwAllOrders & ORDER_YMD; break;
7423 }
7424 }
7425 else if (dwCount == 1)
7426 {
7427 /* Second: Try all the orders compatible with iDate */
7428 switch (iDate)
7429 {
7430 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7431 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break;
7432 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7433 }
7434 }
7435 else
7436 {
7437 /* Finally: Try any remaining orders */
7438 dwTry = dwAllOrders;
7439 }
7440
7441 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry);
7442
7443 dwCount++;
7444 if (!dwTry)
7445 continue;
7446
7447 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7448
7449 if (dwTry & ORDER_MDY)
7450 {
7451 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7452 {
7453 DATE_SWAP(v1,v2);
7454 goto VARIANT_MakeDate_OK;
7455 }
7456 dwAllOrders &= ~ORDER_MDY;
7457 }
7458 if (dwTry & ORDER_YMD)
7459 {
7460 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7461 {
7462 DATE_SWAP(v1,v3);
7463 goto VARIANT_MakeDate_OK;
7464 }
7465 dwAllOrders &= ~ORDER_YMD;
7466 }
7467 if (dwTry & ORDER_YDM)
7468 {
7469 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7470 {
7471 DATE_SWAP(v1,v2);
7472 DATE_SWAP(v2,v3);
7473 goto VARIANT_MakeDate_OK;
7474 }
7475 dwAllOrders &= ~ORDER_YDM;
7476 }
7477 if (dwTry & ORDER_DMY)
7478 {
7479 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7480 goto VARIANT_MakeDate_OK;
7481 dwAllOrders &= ~ORDER_DMY;
7482 }
7483 if (dwTry & ORDER_MYD)
7484 {
7485 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7486 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7487 {
7488 DATE_SWAP(v1,v3);
7489 DATE_SWAP(v2,v3);
7490 goto VARIANT_MakeDate_OK;
7491 }
7492 dwAllOrders &= ~ORDER_MYD;
7493 }
7494 }
7495
7496 if (dp->dwCount == 2)
7497 {
7498 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7499 v3 = 1; /* 1st of the month */
7500 dwAllOrders = ORDER_YMD|ORDER_MYD;
7501 dp->dwCount = 0; /* Don't return to this code path again */
7502 dwCount = 0;
7503 goto VARIANT_MakeDate_Start;
7504 }
7505
7506 /* No valid dates were able to be constructed */
7507 return DISP_E_TYPEMISMATCH;
7508
7509 VARIANT_MakeDate_OK:
7510
7511 /* Check that the time part is ok */
7512 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7513 return DISP_E_TYPEMISMATCH;
7514
7515 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7516 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7517 st->wHour += 12;
7518 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7519 st->wHour = 0;
7520 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7521
7522 st->wDay = v1;
7523 st->wMonth = v2;
7524 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7525 * be retrieved from:
7526 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7527 * But Wine doesn't have/use that key as at the time of writing.
7528 */
7529 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7530 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear);
7531 return S_OK;
7532 }
7533
7534 /******************************************************************************
7535 * VarDateFromStr [OLEAUT32.94]
7536 *
7537 * Convert a VT_BSTR to at VT_DATE.
7538 *
7539 * PARAMS
7540 * strIn [I] String to convert
7541 * lcid [I] Locale identifier for the conversion
7542 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7543 * pdateOut [O] Destination for the converted value
7544 *
7545 * RETURNS
7546 * Success: S_OK. pdateOut contains the converted value.
7547 * FAILURE: An HRESULT error code indicating the problem.
7548 *
7549 * NOTES
7550 * Any date format that can be created using the date formats from lcid
7551 * (Either from kernel Nls functions, variant conversion or formatting) is a
7552 * valid input to this function. In addition, a few more esoteric formats are
7553 * also supported for compatibility with the native version. The date is
7554 * interpreted according to the date settings in the control panel, unless
7555 * the date is invalid in that format, in which the most compatible format
7556 * that produces a valid date will be used.
7557 */
7558 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7559 {
7560 static const USHORT ParseDateTokens[] =
7561 {
7562 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7563 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7564 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7565 LOCALE_SMONTHNAME13,
7566 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7567 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7568 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7569 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7570 LOCALE_SABBREVMONTHNAME13,
7571 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7572 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7573 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7574 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7575 LOCALE_SABBREVDAYNAME7,
7576 LOCALE_S1159, LOCALE_S2359,
7577 LOCALE_SDATE
7578 };
7579 static const BYTE ParseDateMonths[] =
7580 {
7581 1,2,3,4,5,6,7,8,9,10,11,12,13,
7582 1,2,3,4,5,6,7,8,9,10,11,12,13
7583 };
7584 unsigned int i;
7585 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7586 DATEPARSE dp;
7587 DWORD dwDateSeps = 0, iDate = 0;
7588 HRESULT hRet = S_OK;
7589
7590 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7591 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7592 return E_INVALIDARG;
7593
7594 if (!strIn)
7595 return DISP_E_TYPEMISMATCH;
7596
7597 *pdateOut = 0.0;
7598
7599 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7600
7601 memset(&dp, 0, sizeof(dp));
7602
7603 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7604 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7605 TRACE("iDate is %d\n", iDate);
7606
7607 /* Get the month/day/am/pm tokens for this locale */
7608 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7609 {
7610 WCHAR buff[128];
7611 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7612
7613 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7614 * GetAltMonthNames(). We should really cache these strings too.
7615 */
7616 buff[0] = '\0';
7617 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7618 tokens[i] = SysAllocString(buff);
7619 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7620 }
7621
7622 /* Parse the string into our structure */
7623 while (*strIn)
7624 {
7625 if (dp.dwCount >= 6)
7626 break;
7627
7628 if (isdigitW(*strIn))
7629 {
7630 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7631 dp.dwCount++;
7632 strIn--;
7633 }
7634 else if (isalpha(*strIn))
7635 {
7636 BOOL bFound = FALSE;
7637
7638 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7639 {
7640 DWORD dwLen = strlenW(tokens[i]);
7641 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7642 {
7643 if (i <= 25)
7644 {
7645 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7646 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7647 dp.dwCount++;
7648 }
7649 else if (i > 39 && i < 42)
7650 {
7651 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7652 hRet = DISP_E_TYPEMISMATCH;
7653 else
7654 {
7655 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7656 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7657 }
7658 }
7659 strIn += (dwLen - 1);
7660 bFound = TRUE;
7661 break;
7662 }
7663 }
7664
7665 if (!bFound)
7666 {
7667 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7668 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7669 {
7670 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7671 if (*strIn == 'a' || *strIn == 'A')
7672 {
7673 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7674 dp.dwParseFlags |= DP_AM;
7675 }
7676 else
7677 {
7678 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7679 dp.dwParseFlags |= DP_PM;
7680 }
7681 strIn++;
7682 }
7683 else
7684 {
7685 TRACE("No matching token for %s\n", debugstr_w(strIn));
7686 hRet = DISP_E_TYPEMISMATCH;
7687 break;
7688 }
7689 }
7690 }
7691 else if (*strIn == ':' || *strIn == '.')
7692 {
7693 if (!dp.dwCount || !strIn[1])
7694 hRet = DISP_E_TYPEMISMATCH;
7695 else
7696 if (tokens[42][0] == *strIn)
7697 {
7698 dwDateSeps++;
7699 if (dwDateSeps > 2)
7700 hRet = DISP_E_TYPEMISMATCH;
7701 else
7702 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7703 }
7704 else
7705 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7706 }
7707 else if (*strIn == '-' || *strIn == '/')
7708 {
7709 dwDateSeps++;
7710 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7711 hRet = DISP_E_TYPEMISMATCH;
7712 else
7713 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7714 }
7715 else if (*strIn == ',' || isspaceW(*strIn))
7716 {
7717 if (*strIn == ',' && !strIn[1])
7718 hRet = DISP_E_TYPEMISMATCH;
7719 }
7720 else
7721 {
7722 hRet = DISP_E_TYPEMISMATCH;
7723 }
7724 strIn++;
7725 }
7726
7727 if (!dp.dwCount || dp.dwCount > 6 ||
7728 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7729 hRet = DISP_E_TYPEMISMATCH;
7730
7731 if (SUCCEEDED(hRet))
7732 {
7733 SYSTEMTIME st;
7734 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7735
7736 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7737
7738 /* Figure out which numbers correspond to which fields.
7739 *
7740 * This switch statement works based on the fact that native interprets any
7741 * fields that are not joined with a time separator ('.' or ':') as date
7742 * fields. Thus we construct a value from 0-32 where each set bit indicates
7743 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7744 * For valid permutations, we set dwOffset to point to the first date field
7745 * and shorten dp.dwCount by the number of time fields found. The real
7746 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7747 * each date number must represent in the context of iDate.
7748 */
7749 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7750
7751 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7752 {
7753 case 0x1: /* TT TTDD TTDDD */
7754 if (dp.dwCount > 3 &&
7755 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7756 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7757 hRet = DISP_E_TYPEMISMATCH;
7758 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7759 hRet = DISP_E_TYPEMISMATCH;
7760 st.wHour = dp.dwValues[0];
7761 st.wMinute = dp.dwValues[1];
7762 dp.dwCount -= 2;
7763 dwOffset = 2;
7764 break;
7765
7766 case 0x3: /* TTT TTTDD TTTDDD */
7767 if (dp.dwCount > 4 &&
7768 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7769 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7770 hRet = DISP_E_TYPEMISMATCH;
7771 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7772 hRet = DISP_E_TYPEMISMATCH;
7773 st.wHour = dp.dwValues[0];
7774 st.wMinute = dp.dwValues[1];
7775 st.wSecond = dp.dwValues[2];
7776 dwOffset = 3;
7777 dp.dwCount -= 3;
7778 break;
7779
7780 case 0x4: /* DDTT */
7781 if (dp.dwCount != 4 ||
7782 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7783 hRet = DISP_E_TYPEMISMATCH;
7784
7785 st.wHour = dp.dwValues[2];
7786 st.wMinute = dp.dwValues[3];
7787 dp.dwCount -= 2;
7788 break;
7789
7790 case 0x0: /* T DD DDD TDDD TDDD */
7791 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7792 {
7793 st.wHour = dp.dwValues[0]; /* T */
7794 dp.dwCount = 0;
7795 break;
7796 }
7797 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7798 {
7799 hRet = DISP_E_TYPEMISMATCH;
7800 }
7801 else if (dp.dwCount == 3)
7802 {
7803 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7804 {
7805 dp.dwCount = 2;
7806 st.wHour = dp.dwValues[0];
7807 dwOffset = 1;
7808 break;
7809 }
7810 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7811 {
7812 dp.dwCount = 2;
7813 st.wHour = dp.dwValues[2];
7814 break;
7815 }
7816 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7817 hRet = DISP_E_TYPEMISMATCH;
7818 }
7819 else if (dp.dwCount == 4)
7820 {
7821 dp.dwCount = 3;
7822 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7823 {
7824 st.wHour = dp.dwValues[0];
7825 dwOffset = 1;
7826 }
7827 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7828 {
7829 st.wHour = dp.dwValues[3];
7830 }
7831 else
7832 hRet = DISP_E_TYPEMISMATCH;
7833 break;
7834 }
7835 /* .. fall through .. */
7836
7837 case 0x8: /* DDDTT */
7838 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7839 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7840 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7841 dp.dwCount == 4 || dp.dwCount == 6)
7842 hRet = DISP_E_TYPEMISMATCH;
7843 st.wHour = dp.dwValues[3];
7844 st.wMinute = dp.dwValues[4];
7845 if (dp.dwCount == 5)
7846 dp.dwCount -= 2;
7847 break;
7848
7849 case 0xC: /* DDTTT */
7850 if (dp.dwCount != 5 ||
7851 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7852 hRet = DISP_E_TYPEMISMATCH;
7853 st.wHour = dp.dwValues[2];
7854 st.wMinute = dp.dwValues[3];
7855 st.wSecond = dp.dwValues[4];
7856 dp.dwCount -= 3;
7857 break;
7858
7859 case 0x18: /* DDDTTT */
7860 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7861 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7862 hRet = DISP_E_TYPEMISMATCH;
7863 st.wHour = dp.dwValues[3];
7864 st.wMinute = dp.dwValues[4];
7865 st.wSecond = dp.dwValues[5];
7866 dp.dwCount -= 3;
7867 break;
7868
7869 default:
7870 hRet = DISP_E_TYPEMISMATCH;
7871 break;
7872 }
7873
7874 if (SUCCEEDED(hRet))
7875 {
7876 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7877
7878 if (dwFlags & VAR_TIMEVALUEONLY)
7879 {
7880 st.wYear = 1899;
7881 st.wMonth = 12;
7882 st.wDay = 30;
7883 }
7884 else if (dwFlags & VAR_DATEVALUEONLY)
7885 st.wHour = st.wMinute = st.wSecond = 0;
7886
7887 /* Finally, convert the value to a VT_DATE */
7888 if (SUCCEEDED(hRet))
7889 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7890 }
7891 }
7892
7893 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7894 SysFreeString(tokens[i]);
7895 return hRet;
7896 }
7897
7898 /******************************************************************************
7899 * VarDateFromI1 (OLEAUT32.221)
7900 *
7901 * Convert a VT_I1 to a VT_DATE.
7902 *
7903 * PARAMS
7904 * cIn [I] Source
7905 * pdateOut [O] Destination
7906 *
7907 * RETURNS
7908 * S_OK.
7909 */
7910 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7911 {
7912 return VarR8FromI1(cIn, pdateOut);
7913 }
7914
7915 /******************************************************************************
7916 * VarDateFromUI2 (OLEAUT32.222)
7917 *
7918 * Convert a VT_UI2 to a VT_DATE.
7919 *
7920 * PARAMS
7921 * uiIn [I] Source
7922 * pdateOut [O] Destination
7923 *
7924 * RETURNS
7925 * S_OK.
7926 */
7927 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7928 {
7929 return VarR8FromUI2(uiIn, pdateOut);
7930 }
7931
7932 /******************************************************************************
7933 * VarDateFromUI4 (OLEAUT32.223)
7934 *
7935 * Convert a VT_UI4 to a VT_DATE.
7936 *
7937 * PARAMS
7938 * ulIn [I] Source
7939 * pdateOut [O] Destination
7940 *
7941 * RETURNS
7942 * S_OK.
7943 */
7944 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7945 {
7946 return VarDateFromR8(ulIn, pdateOut);
7947 }
7948
7949 /**********************************************************************
7950 * VarDateFromDec (OLEAUT32.224)
7951 *
7952 * Convert a VT_DECIMAL to a VT_DATE.
7953 *
7954 * PARAMS
7955 * pdecIn [I] Source
7956 * pdateOut [O] Destination
7957 *
7958 * RETURNS
7959 * S_OK.
7960 */
7961 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7962 {
7963 return VarR8FromDec(pdecIn, pdateOut);
7964 }
7965
7966 /******************************************************************************
7967 * VarDateFromI8 (OLEAUT32.364)
7968 *
7969 * Convert a VT_I8 to a VT_DATE.
7970 *
7971 * PARAMS
7972 * llIn [I] Source
7973 * pdateOut [O] Destination
7974 *
7975 * RETURNS
7976 * Success: S_OK.
7977 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7978 */
7979 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
7980 {
7981 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
7982 *pdateOut = (DATE)llIn;
7983 return S_OK;
7984 }
7985
7986 /******************************************************************************
7987 * VarDateFromUI8 (OLEAUT32.365)
7988 *
7989 * Convert a VT_UI8 to a VT_DATE.
7990 *
7991 * PARAMS
7992 * ullIn [I] Source
7993 * pdateOut [O] Destination
7994 *
7995 * RETURNS
7996 * Success: S_OK.
7997 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7998 */
7999 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
8000 {
8001 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
8002 *pdateOut = (DATE)ullIn;
8003 return S_OK;
8004 }