[OLEAUT32] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / 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 double divisor = 1.0;
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.0;
2949
2950 if (DEC_SIGN(pDecIn))
2951 divisor = -divisor;
2952
2953 if (DEC_HI32(pDecIn))
2954 {
2955 highPart = (double)DEC_HI32(pDecIn) / divisor;
2956 highPart *= 4294967296.0F;
2957 highPart *= 4294967296.0F;
2958 }
2959 else
2960 highPart = 0.0;
2961
2962 *pFltOut = (double)DEC_LO64(pDecIn) / 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 /* internal representation of the value stored in a DECIMAL. The bytes are
4142 stored from LSB at index 0 to MSB at index 11
4143 */
4144 typedef struct DECIMAL_internal
4145 {
4146 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4147 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4148 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4149 } VARIANT_DI;
4150
4151 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4152 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4153 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4154 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
4155 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor);
4156 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n);
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[2])
4433 {
4434 static DECIMAL scaleFactor;
4435 unsigned char remainder;
4436 DECIMAL decTemp;
4437 VARIANT_DI di;
4438 int scaleAmount, i;
4439
4440 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4441 return E_INVALIDARG;
4442
4443 DEC_LO32(&scaleFactor) = 10;
4444
4445 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4446
4447 if (!scaleAmount)
4448 return S_OK; /* Same scale */
4449
4450 if (scaleAmount > 0)
4451 {
4452 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4453 *ppDecRight = &pDecOut[0];
4454 }
4455 else
4456 {
4457 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4458 *ppDecLeft = &pDecOut[0];
4459 i = -scaleAmount;
4460 }
4461
4462 /* Multiply up the value to be scaled by the correct amount (if possible) */
4463 while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0])))
4464 {
4465 decTemp = pDecOut[0];
4466 i--;
4467 }
4468
4469 if (!i)
4470 {
4471 DEC_SCALE(&pDecOut[0]) += (scaleAmount > 0) ? scaleAmount : (-scaleAmount);
4472 return S_OK; /* Same scale */
4473 }
4474
4475 /* Scaling further not possible, reduce accuracy of other argument */
4476 pDecOut[0] = decTemp;
4477 if (scaleAmount > 0)
4478 {
4479 DEC_SCALE(&pDecOut[0]) += scaleAmount - i;
4480 VARIANT_DIFromDec(*ppDecLeft, &di);
4481 *ppDecLeft = &pDecOut[1];
4482 }
4483 else
4484 {
4485 DEC_SCALE(&pDecOut[0]) += (-scaleAmount) - i;
4486 VARIANT_DIFromDec(*ppDecRight, &di);
4487 *ppDecRight = &pDecOut[1];
4488 }
4489
4490 di.scale -= i;
4491 remainder = 0;
4492 while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD)))
4493 {
4494 remainder = VARIANT_int_divbychar(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD), 10);
4495 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4496 }
4497
4498 /* round up the result - native oleaut32 does this */
4499 if (remainder >= 5) {
4500 for (remainder = 1, i = 0; i < sizeof(di.bitsnum)/sizeof(DWORD) && remainder; i++) {
4501 ULONGLONG digit = di.bitsnum[i] + 1;
4502 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4503 di.bitsnum[i] = digit & 0xFFFFFFFF;
4504 }
4505 }
4506
4507 VARIANT_DecFromDI(&di, &pDecOut[1]);
4508 return S_OK;
4509 }
4510
4511 /* Add two unsigned 32 bit values with overflow */
4512 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4513 {
4514 ULARGE_INTEGER ul64;
4515
4516 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4517 *pulHigh = ul64.u.HighPart;
4518 return ul64.u.LowPart;
4519 }
4520
4521 /* Subtract two unsigned 32 bit values with underflow */
4522 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4523 {
4524 BOOL invert = FALSE;
4525 ULARGE_INTEGER ul64;
4526
4527 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4528 if (ulLeft < ulRight)
4529 invert = TRUE;
4530
4531 if (ul64.QuadPart > (ULONG64)*pulHigh)
4532 ul64.QuadPart -= (ULONG64)*pulHigh;
4533 else
4534 {
4535 ul64.QuadPart -= (ULONG64)*pulHigh;
4536 invert = TRUE;
4537 }
4538 if (invert)
4539 ul64.u.HighPart = -ul64.u.HighPart ;
4540
4541 *pulHigh = ul64.u.HighPart;
4542 return ul64.u.LowPart;
4543 }
4544
4545 /* Multiply two unsigned 32 bit values with overflow */
4546 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4547 {
4548 ULARGE_INTEGER ul64;
4549
4550 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4551 *pulHigh = ul64.u.HighPart;
4552 return ul64.u.LowPart;
4553 }
4554
4555 /* Compare two decimals that have the same scale */
4556 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4557 {
4558 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4559 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4560 return -1;
4561 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4562 return 0;
4563 return 1;
4564 }
4565
4566 /************************************************************************
4567 * VarDecAdd (OLEAUT32.177)
4568 *
4569 * Add one DECIMAL to another.
4570 *
4571 * PARAMS
4572 * pDecLeft [I] Source
4573 * pDecRight [I] Value to add
4574 * pDecOut [O] Destination
4575 *
4576 * RETURNS
4577 * Success: S_OK.
4578 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4579 */
4580 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4581 {
4582 HRESULT hRet;
4583 DECIMAL scaled[2];
4584
4585 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, scaled);
4586
4587 if (SUCCEEDED(hRet))
4588 {
4589 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4590 ULONG overflow = 0;
4591 BYTE sign = DECIMAL_POS;
4592 int cmp;
4593
4594 /* Correct for the sign of the result */
4595 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4596 {
4597 /* -x + -y : Negative */
4598 sign = DECIMAL_NEG;
4599 goto VarDecAdd_AsPositive;
4600 }
4601 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4602 {
4603 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4604
4605 /* -x + y : Negative if x > y */
4606 if (cmp > 0)
4607 {
4608 sign = DECIMAL_NEG;
4609 VarDecAdd_AsNegative:
4610 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4611 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4612 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4613 }
4614 else
4615 {
4616 VarDecAdd_AsInvertedNegative:
4617 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4618 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4619 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4620 }
4621 }
4622 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4623 {
4624 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4625
4626 /* x + -y : Negative if x <= y */
4627 if (cmp <= 0)
4628 {
4629 sign = DECIMAL_NEG;
4630 goto VarDecAdd_AsInvertedNegative;
4631 }
4632 goto VarDecAdd_AsNegative;
4633 }
4634 else
4635 {
4636 /* x + y : Positive */
4637 VarDecAdd_AsPositive:
4638 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4639 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4640 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4641 }
4642
4643 if (overflow)
4644 return DISP_E_OVERFLOW; /* overflowed */
4645
4646 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4647 DEC_SIGN(pDecOut) = sign;
4648 }
4649 return hRet;
4650 }
4651
4652 /* translate from external DECIMAL format into an internal representation */
4653 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4654 {
4655 to->scale = DEC_SCALE(from);
4656 to->sign = DEC_SIGN(from) ? 1 : 0;
4657
4658 to->bitsnum[0] = DEC_LO32(from);
4659 to->bitsnum[1] = DEC_MID32(from);
4660 to->bitsnum[2] = DEC_HI32(from);
4661 }
4662
4663 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
4664 {
4665 if (from->sign) {
4666 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4667 } else {
4668 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4669 }
4670
4671 DEC_LO32(to) = from->bitsnum[0];
4672 DEC_MID32(to) = from->bitsnum[1];
4673 DEC_HI32(to) = from->bitsnum[2];
4674 }
4675
4676 /* clear an internal representation of a DECIMAL */
4677 static void VARIANT_DI_clear(VARIANT_DI * i)
4678 {
4679 memset(i, 0, sizeof(VARIANT_DI));
4680 }
4681
4682 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4683 size is supported. The value in p is replaced by the quotient of the division, and
4684 the remainder is returned as a result. This routine is most often used with a divisor
4685 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4686 */
4687 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4688 {
4689 if (divisor == 0) {
4690 /* division by 0 */
4691 return 0xFF;
4692 } else if (divisor == 1) {
4693 /* dividend remains unchanged */
4694 return 0;
4695 } else {
4696 unsigned char remainder = 0;
4697 ULONGLONG iTempDividend;
4698 signed int i;
4699
4700 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4701 for (; i >= 0; i--) {
4702 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4703 remainder = iTempDividend % divisor;
4704 p[i] = iTempDividend / divisor;
4705 }
4706
4707 return remainder;
4708 }
4709 }
4710
4711 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4712 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n)
4713 {
4714 for (; n > 0; n--) if (*p++ != 0) return FALSE;
4715 return TRUE;
4716 }
4717
4718 /* multiply two DECIMALS, without changing either one, and place result in third
4719 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4720 digits when scale > 0 in order to fit an overflowing result. Final overflow
4721 flag is returned.
4722 */
4723 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
4724 {
4725 BOOL r_overflow = FALSE;
4726 DWORD running[6];
4727 signed int mulstart;
4728
4729 VARIANT_DI_clear(result);
4730 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4731
4732 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4733 of the result is formed by adding the scales of the operands.
4734 */
4735 result->scale = a->scale + b->scale;
4736 memset(running, 0, sizeof(running));
4737
4738 /* count number of leading zero-bytes in operand A */
4739 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4740 if (mulstart < 0) {
4741 /* result is 0, because operand A is 0 */
4742 result->scale = 0;
4743 result->sign = 0;
4744 } else {
4745 unsigned char remainder = 0;
4746 int iA;
4747
4748 /* perform actual multiplication */
4749 for (iA = 0; iA <= mulstart; iA++) {
4750 ULONG iOverflowMul;
4751 int iB;
4752
4753 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4754 ULONG iRV;
4755 int iR;
4756
4757 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4758 iR = iA + iB;
4759 do {
4760 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4761 iR++;
4762 } while (iRV);
4763 }
4764 }
4765
4766 /* Too bad - native oleaut does not do this, so we should not either */
4767 #if 0
4768 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4769 This operation should not lose significant digits, and gives an
4770 opportunity to reduce the possibility of overflows in future
4771 operations issued by the application.
4772 */
4773 while (result->scale > 0) {
4774 memcpy(quotient, running, sizeof(quotient));
4775 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4776 if (remainder > 0) break;
4777 memcpy(running, quotient, sizeof(quotient));
4778 result->scale--;
4779 }
4780 #endif
4781 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4782 This operation *will* lose significant digits of the result because
4783 all the factors of 10 were consumed by the previous operation.
4784 */
4785 while (result->scale > 0 && !VARIANT_int_iszero(
4786 running + sizeof(result->bitsnum) / sizeof(DWORD),
4787 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4788
4789 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4790 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4791 result->scale--;
4792 }
4793
4794 /* round up the result - native oleaut32 does this */
4795 if (remainder >= 5) {
4796 unsigned int i;
4797 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4798 ULONGLONG digit = running[i] + 1;
4799 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4800 running[i] = digit & 0xFFFFFFFF;
4801 }
4802 }
4803
4804 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4805 and copy result bits into result structure
4806 */
4807 r_overflow = !VARIANT_int_iszero(
4808 running + sizeof(result->bitsnum)/sizeof(DWORD),
4809 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4810 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4811 }
4812 return r_overflow;
4813 }
4814
4815 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4816 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4817 success, FALSE if insufficient space in output buffer.
4818 */
4819 static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
4820 {
4821 BOOL overflow = FALSE;
4822 DWORD quotient[3];
4823 unsigned char remainder;
4824 unsigned int i;
4825
4826 /* place negative sign */
4827 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4828 if (n > 0) {
4829 *s++ = '-';
4830 n--;
4831 }
4832 else overflow = TRUE;
4833 }
4834
4835 /* prepare initial 0 */
4836 if (!overflow) {
4837 if (n >= 2) {
4838 s[0] = '0';
4839 s[1] = '\0';
4840 } else overflow = TRUE;
4841 }
4842
4843 i = 0;
4844 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4845 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4846 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4847 if (i + 2 > n) {
4848 overflow = TRUE;
4849 } else {
4850 s[i++] = '0' + remainder;
4851 s[i] = '\0';
4852 }
4853 }
4854
4855 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4856
4857 /* reverse order of digits */
4858 WCHAR * x = s; WCHAR * y = s + i - 1;
4859 while (x < y) {
4860 *x ^= *y;
4861 *y ^= *x;
4862 *x++ ^= *y--;
4863 }
4864
4865 /* check for decimal point. "i" now has string length */
4866 if (i <= a->scale) {
4867 unsigned int numzeroes = a->scale + 1 - i;
4868 if (i + 1 + numzeroes >= n) {
4869 overflow = TRUE;
4870 } else {
4871 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4872 i += numzeroes;
4873 while (numzeroes > 0) {
4874 s[--numzeroes] = '0';
4875 }
4876 }
4877 }
4878
4879 /* place decimal point */
4880 if (a->scale > 0) {
4881 unsigned int periodpos = i - a->scale;
4882 if (i + 2 >= n) {
4883 overflow = TRUE;
4884 } else {
4885 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4886 s[periodpos] = '.'; i++;
4887
4888 /* remove extra zeros at the end, if any */
4889 while (s[i - 1] == '0') s[--i] = '\0';
4890 if (s[i - 1] == '.') s[--i] = '\0';
4891 }
4892 }
4893 }
4894
4895 return !overflow;
4896 }
4897
4898 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4899 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4900 {
4901 DWORD shifted;
4902 unsigned int i;
4903
4904 /* shift whole DWORDs to the left */
4905 while (shift >= 32)
4906 {
4907 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4908 *p = 0; shift -= 32;
4909 }
4910
4911 /* shift remainder (1..31 bits) */
4912 shifted = 0;
4913 if (shift > 0) for (i = 0; i < n; i++)
4914 {
4915 DWORD b;
4916 b = p[i] >> (32 - shift);
4917 p[i] = (p[i] << shift) | shifted;
4918 shifted = b;
4919 }
4920 }
4921
4922 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4923 Value at v is incremented by the value at p. Any size is supported, provided
4924 that v is not shorter than p. Any unapplied carry is returned as a result.
4925 */
4926 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
4927 unsigned int np)
4928 {
4929 unsigned char carry = 0;
4930
4931 if (nv >= np) {
4932 ULONGLONG sum;
4933 unsigned int i;
4934
4935 for (i = 0; i < np; i++) {
4936 sum = (ULONGLONG)v[i]
4937 + (ULONGLONG)p[i]
4938 + (ULONGLONG)carry;
4939 v[i] = sum & 0xffffffff;
4940 carry = sum >> 32;
4941 }
4942 for (; i < nv && carry; i++) {
4943 sum = (ULONGLONG)v[i]
4944 + (ULONGLONG)carry;
4945 v[i] = sum & 0xffffffff;
4946 carry = sum >> 32;
4947 }
4948 }
4949 return carry;
4950 }
4951
4952 /* perform integral division with operand p as dividend. Parameter n indicates
4953 number of available DWORDs in divisor p, but available space in p must be
4954 actually at least 2 * n DWORDs, because the remainder of the integral
4955 division is built in the next n DWORDs past the start of the quotient. This
4956 routine replaces the dividend in p with the quotient, and appends n
4957 additional DWORDs for the remainder.
4958
4959 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4960 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4961 source code to the VLI (Very Large Integer) division operator. This algorithm
4962 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4963 variably-scaled integers such as the MS DECIMAL representation.
4964 */
4965 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
4966 unsigned int dn)
4967 {
4968 unsigned int i;
4969 DWORD tempsub[8];
4970 DWORD * negdivisor = tempsub + n;
4971
4972 /* build 2s-complement of divisor */
4973 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4974 p[n] = 1;
4975 VARIANT_int_add(negdivisor, n, p + n, 1);
4976 memset(p + n, 0, n * sizeof(DWORD));
4977
4978 /* skip all leading zero DWORDs in quotient */
4979 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4980 /* i is now number of DWORDs left to process */
4981 for (i <<= 5; i < (n << 5); i++) {
4982 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4983
4984 /* trial subtraction */
4985 memcpy(tempsub, p + n, n * sizeof(DWORD));
4986 VARIANT_int_add(tempsub, n, negdivisor, n);
4987
4988 /* check whether result of subtraction was negative */
4989 if ((tempsub[n - 1] & 0x80000000) == 0) {
4990 memcpy(p + n, tempsub, n * sizeof(DWORD));
4991 p[0] |= 1;
4992 }
4993 }
4994 }
4995
4996 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4997 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4998 {
4999 unsigned int i;
5000 ULONG iOverflowMul;
5001
5002 for (iOverflowMul = 0, i = 0; i < n; i++)
5003 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
5004 return (unsigned char)iOverflowMul;
5005 }
5006
5007 /* increment value in A by the value indicated in B, with scale adjusting.
5008 Modifies parameters by adjusting scales. Returns 0 if addition was
5009 successful, nonzero if a parameter underflowed before it could be
5010 successfully used in the addition.
5011 */
5012 static int VARIANT_int_addlossy(
5013 DWORD * a, int * ascale, unsigned int an,
5014 DWORD * b, int * bscale, unsigned int bn)
5015 {
5016 int underflow = 0;
5017
5018 if (VARIANT_int_iszero(a, an)) {
5019 /* if A is zero, copy B into A, after removing digits */
5020 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
5021 VARIANT_int_divbychar(b, bn, 10);
5022 (*bscale)--;
5023 }
5024 memcpy(a, b, an * sizeof(DWORD));
5025 *ascale = *bscale;
5026 } else if (!VARIANT_int_iszero(b, bn)) {
5027 unsigned int tn = an + 1;
5028 DWORD t[5];
5029
5030 if (bn + 1 > tn) tn = bn + 1;
5031 if (*ascale != *bscale) {
5032 /* first (optimistic) try - try to scale down the one with the bigger
5033 scale, while this number is divisible by 10 */
5034 DWORD * digitchosen;
5035 unsigned int nchosen;
5036 int * scalechosen;
5037 int targetscale;
5038
5039 if (*ascale < *bscale) {
5040 targetscale = *ascale;
5041 scalechosen = bscale;
5042 digitchosen = b;
5043 nchosen = bn;
5044 } else {
5045 targetscale = *bscale;
5046 scalechosen = ascale;
5047 digitchosen = a;
5048 nchosen = an;
5049 }
5050 memset(t, 0, tn * sizeof(DWORD));
5051 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5052
5053 /* divide by 10 until target scale is reached */
5054 while (*scalechosen > targetscale) {
5055 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5056 if (!remainder) {
5057 (*scalechosen)--;
5058 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5059 } else break;
5060 }
5061 }
5062
5063 if (*ascale != *bscale) {
5064 DWORD * digitchosen;
5065 unsigned int nchosen;
5066 int * scalechosen;
5067 int targetscale;
5068
5069 /* try to scale up the one with the smaller scale */
5070 if (*ascale > *bscale) {
5071 targetscale = *ascale;
5072 scalechosen = bscale;
5073 digitchosen = b;
5074 nchosen = bn;
5075 } else {
5076 targetscale = *bscale;
5077 scalechosen = ascale;
5078 digitchosen = a;
5079 nchosen = an;
5080 }
5081 memset(t, 0, tn * sizeof(DWORD));
5082 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5083
5084 /* multiply by 10 until target scale is reached, or
5085 significant bytes overflow the number
5086 */
5087 while (*scalechosen < targetscale && t[nchosen] == 0) {
5088 VARIANT_int_mulbychar(t, tn, 10);
5089 if (t[nchosen] == 0) {
5090 /* still does not overflow */
5091 (*scalechosen)++;
5092 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5093 }
5094 }
5095 }
5096
5097 if (*ascale != *bscale) {
5098 /* still different? try to scale down the one with the bigger scale
5099 (this *will* lose significant digits) */
5100 DWORD * digitchosen;
5101 unsigned int nchosen;
5102 int * scalechosen;
5103 int targetscale;
5104
5105 if (*ascale < *bscale) {
5106 targetscale = *ascale;
5107 scalechosen = bscale;
5108 digitchosen = b;
5109 nchosen = bn;
5110 } else {
5111 targetscale = *bscale;
5112 scalechosen = ascale;
5113 digitchosen = a;
5114 nchosen = an;
5115 }
5116 memset(t, 0, tn * sizeof(DWORD));
5117 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5118
5119 /* divide by 10 until target scale is reached */
5120 while (*scalechosen > targetscale) {
5121 VARIANT_int_divbychar(t, tn, 10);
5122 (*scalechosen)--;
5123 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5124 }
5125 }
5126
5127 /* check whether any of the operands still has significant digits
5128 (underflow case 1)
5129 */
5130 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5131 underflow = 1;
5132 } else {
5133 /* at this step, both numbers have the same scale and can be added
5134 as integers. However, the result might not fit in A, so further
5135 scaling down might be necessary.
5136 */
5137 while (!underflow) {
5138 memset(t, 0, tn * sizeof(DWORD));
5139 memcpy(t, a, an * sizeof(DWORD));
5140
5141 VARIANT_int_add(t, tn, b, bn);
5142 if (VARIANT_int_iszero(t + an, tn - an)) {
5143 /* addition was successful */
5144 memcpy(a, t, an * sizeof(DWORD));
5145 break;
5146 } else {
5147 /* addition overflowed - remove significant digits
5148 from both operands and try again */
5149 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5150 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5151 /* check whether any operand keeps significant digits after
5152 scaledown (underflow case 2)
5153 */
5154 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5155 }
5156 }
5157 }
5158 }
5159 return underflow;
5160 }
5161
5162 /* perform complete DECIMAL division in the internal representation. Returns
5163 0 if the division was completed (even if quotient is set to 0), or nonzero
5164 in case of quotient overflow.
5165 */
5166 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
5167 VARIANT_DI * quotient, BOOL round_remainder)
5168 {
5169 HRESULT r_overflow = S_OK;
5170
5171 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5172 /* division by 0 */
5173 r_overflow = DISP_E_DIVBYZERO;
5174 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5175 VARIANT_DI_clear(quotient);
5176 } else {
5177 int quotientscale, remainderscale, tempquotientscale;
5178 DWORD remainderplusquotient[8];
5179 int underflow;
5180
5181 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5182 tempquotientscale = quotientscale;
5183 VARIANT_DI_clear(quotient);
5184 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5185
5186 /* The following strategy is used for division
5187 1) if there was a nonzero remainder from previous iteration, use it as
5188 dividend for this iteration, else (for first iteration) use intended
5189 dividend
5190 2) perform integer division in temporary buffer, develop quotient in
5191 low-order part, remainder in high-order part
5192 3) add quotient from step 2 to final result, with possible loss of
5193 significant digits
5194 4) multiply integer part of remainder by 10, while incrementing the
5195 scale of the remainder. This operation preserves the intended value
5196 of the remainder.
5197 5) loop to step 1 until one of the following is true:
5198 a) remainder is zero (exact division achieved)
5199 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5200 */
5201 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5202 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5203 do {
5204 VARIANT_int_div(
5205 remainderplusquotient, 4,
5206 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5207 underflow = VARIANT_int_addlossy(
5208 quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5209 remainderplusquotient, &tempquotientscale, 4);
5210 if (round_remainder) {
5211 if(remainderplusquotient[4] >= 5){
5212 unsigned int i;
5213 unsigned char remainder = 1;
5214 for (i = 0; i < sizeof(quotient->bitsnum) / sizeof(DWORD) && remainder; i++) {
5215 ULONGLONG digit = quotient->bitsnum[i] + 1;
5216 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5217 quotient->bitsnum[i] = digit & 0xFFFFFFFF;
5218 }
5219 }
5220 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5221 } else {
5222 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5223 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5224 }
5225 tempquotientscale = ++remainderscale;
5226 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5227
5228 /* quotient scale might now be negative (extremely big number). If, so, try
5229 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5230 until scale is 0. If this cannot be done, it is a real overflow.
5231 */
5232 while (r_overflow == S_OK && quotientscale < 0) {
5233 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5234 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5235 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5236 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5237 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5238 quotientscale++;
5239 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5240 } else r_overflow = DISP_E_OVERFLOW;
5241 }
5242 if (r_overflow == S_OK) {
5243 if (quotientscale <= 255) quotient->scale = quotientscale;
5244 else VARIANT_DI_clear(quotient);
5245 }
5246 }
5247 return r_overflow;
5248 }
5249
5250 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5251 with an undefined scale, which will be assigned to (if possible). It also
5252 receives an exponent of 2. This procedure will then manipulate the mantissa
5253 and calculate a corresponding scale, so that the exponent2 value is assimilated
5254 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5255 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5256 a DECIMAL. */
5257 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble)
5258 {
5259 HRESULT hres = S_OK;
5260 int exponent5, exponent10;
5261
5262 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5263 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5264 exponent10 might be used to set the VARIANT_DI scale directly. However,
5265 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5266 exponent5 = -exponent2;
5267 exponent10 = exponent2;
5268
5269 /* Handle exponent5 > 0 */
5270 while (exponent5 > 0) {
5271 char bPrevCarryBit;
5272 char bCurrCarryBit;
5273
5274 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5275 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5276 somehow the mantissa should be divided by 2. */
5277 if ((val->bitsnum[0] & 1) == 0) {
5278 /* The mantissa is divisible by 2. Therefore the division can be done
5279 without losing significant digits. */
5280 exponent10++; exponent5--;
5281
5282 /* Shift right */
5283 bPrevCarryBit = val->bitsnum[2] & 1;
5284 val->bitsnum[2] >>= 1;
5285 bCurrCarryBit = val->bitsnum[1] & 1;
5286 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5287 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5288 } else {
5289 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5290 be multiplied by 5, unless the multiplication overflows. */
5291 DWORD temp_bitsnum[3];
5292
5293 exponent5--;
5294
5295 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5296 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5297 /* Multiplication succeeded without overflow, so copy result back
5298 into VARIANT_DI */
5299 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5300
5301 /* Mask out 3 extraneous bits introduced by the multiply */
5302 } else {
5303 /* Multiplication by 5 overflows. The mantissa should be divided
5304 by 2, and therefore will lose significant digits. */
5305 exponent10++;
5306
5307 /* Shift right */
5308 bPrevCarryBit = val->bitsnum[2] & 1;
5309 val->bitsnum[2] >>= 1;
5310 bCurrCarryBit = val->bitsnum[1] & 1;
5311 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5312 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5313 }
5314 }
5315 }
5316
5317 /* Handle exponent5 < 0 */
5318 while (exponent5 < 0) {
5319 /* In order to divide the value represented by the VARIANT_DI by 5, it
5320 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5321 and the mantissa should be multiplied by 2 */
5322 if ((val->bitsnum[2] & 0x80000000) == 0) {
5323 /* The mantissa can withstand a shift-left without overflowing */
5324 exponent10--; exponent5++;
5325 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5326 } else {
5327 /* The mantissa would overflow if shifted. Therefore it should be
5328 directly divided by 5. This will lose significant digits, unless
5329 by chance the mantissa happens to be divisible by 5 */
5330 exponent5++;
5331 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5332 }
5333 }
5334
5335 /* At this point, the mantissa has assimilated the exponent5, but the
5336 exponent10 might not be suitable for assignment. The exponent10 must be
5337 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5338 down appropriately. */
5339 while (hres == S_OK && exponent10 > 0) {
5340 /* In order to bring exponent10 down to 0, the mantissa should be
5341 multiplied by 10 to compensate. If the exponent10 is too big, this
5342 will cause the mantissa to overflow. */
5343 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5344 exponent10--;
5345 } else {
5346 hres = DISP_E_OVERFLOW;
5347 }
5348 }
5349 while (exponent10 < -DEC_MAX_SCALE) {
5350 int rem10;
5351 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5352 be divided by 10 to compensate. If the exponent10 is too small, this
5353 will cause the mantissa to underflow and become 0 */
5354 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5355 exponent10++;
5356 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5357 /* Underflow, unable to keep dividing */
5358 exponent10 = 0;
5359 } else if (rem10 >= 5) {
5360 DWORD x = 1;
5361 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5362 }
5363 }
5364 /* This step is required in order to remove excess bits of precision from the
5365 end of the bit representation, down to the precision guaranteed by the
5366 floating point number. */
5367 if (isDouble) {
5368 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[2] == 0 && (val->bitsnum[1] & 0xFFE00000) != 0))) {
5369 int rem10;
5370
5371 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5372 exponent10++;
5373 if (rem10 >= 5) {
5374 DWORD x = 1;
5375 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5376 }
5377 }
5378 } else {
5379 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5380 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5381 int rem10;
5382
5383 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5384 exponent10++;
5385 if (rem10 >= 5) {
5386 DWORD x = 1;
5387 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5388 }
5389 }
5390 }
5391 /* Remove multiples of 10 from the representation */
5392 while (exponent10 < 0) {
5393 DWORD temp_bitsnum[3];
5394
5395 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5396 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5397 exponent10++;
5398 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5399 } else break;
5400 }
5401
5402 /* Scale assignment */
5403 if (hres == S_OK) val->scale = -exponent10;
5404
5405 return hres;
5406 }
5407
5408 typedef union
5409 {
5410 struct
5411 {
5412 unsigned int m : 23;
5413 unsigned int exp_bias : 8;
5414 unsigned int sign : 1;
5415 } i;
5416 float f;
5417 } R4_FIELDS;
5418
5419 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5420 intermediate string step. */
5421 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5422 {
5423 HRESULT hres = S_OK;
5424 R4_FIELDS fx;
5425
5426 fx.f = source;
5427
5428 /* Detect special cases */
5429 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5430 /* Floating-point zero */
5431 VARIANT_DI_clear(dest);
5432 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5433 /* Floating-point infinity */
5434 hres = DISP_E_OVERFLOW;
5435 } else if (fx.i.exp_bias == 0xFF) {
5436 /* Floating-point NaN */
5437 hres = DISP_E_BADVARTYPE;
5438 } else {
5439 int exponent2;
5440 VARIANT_DI_clear(dest);
5441
5442 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5443 dest->sign = fx.i.sign; /* Sign is simply copied */
5444
5445 /* Copy significant bits to VARIANT_DI mantissa */
5446 dest->bitsnum[0] = fx.i.m;
5447 dest->bitsnum[0] &= 0x007FFFFF;
5448 if (fx.i.exp_bias == 0) {
5449 /* Denormalized number - correct exponent */
5450 exponent2++;
5451 } else {
5452 /* Add hidden bit to mantissa */
5453 dest->bitsnum[0] |= 0x00800000;
5454 }
5455
5456 /* The act of copying a FP mantissa as integer bits is equivalent to
5457 shifting left the mantissa 23 bits. The exponent2 is reduced to
5458 compensate. */
5459 exponent2 -= 23;
5460
5461 hres = VARIANT_DI_normalize(dest, exponent2, FALSE);
5462 }
5463
5464 return hres;
5465 }
5466
5467 typedef union
5468 {
5469 struct
5470 {
5471 unsigned int m_lo : 32; /* 52 bits of precision */
5472 unsigned int m_hi : 20;
5473 unsigned int exp_bias : 11; /* bias == 1023 */
5474 unsigned int sign : 1;
5475 } i;
5476 double d;
5477 } R8_FIELDS;
5478
5479 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5480 intermediate string step. */
5481 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5482 {
5483 HRESULT hres = S_OK;
5484 R8_FIELDS fx;
5485
5486 fx.d = source;
5487
5488 /* Detect special cases */
5489 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5490 /* Floating-point zero */
5491 VARIANT_DI_clear(dest);
5492 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5493 /* Floating-point infinity */
5494 hres = DISP_E_OVERFLOW;
5495 } else if (fx.i.exp_bias == 0x7FF) {
5496 /* Floating-point NaN */
5497 hres = DISP_E_BADVARTYPE;
5498 } else {
5499 int exponent2;
5500 VARIANT_DI_clear(dest);
5501
5502 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5503 dest->sign = fx.i.sign; /* Sign is simply copied */
5504
5505 /* Copy significant bits to VARIANT_DI mantissa */
5506 dest->bitsnum[0] = fx.i.m_lo;
5507 dest->bitsnum[1] = fx.i.m_hi;
5508 dest->bitsnum[1] &= 0x000FFFFF;
5509 if (fx.i.exp_bias == 0) {
5510 /* Denormalized number - correct exponent */
5511 exponent2++;
5512 } else {
5513 /* Add hidden bit to mantissa */
5514 dest->bitsnum[1] |= 0x00100000;
5515 }
5516
5517 /* The act of copying a FP mantissa as integer bits is equivalent to
5518 shifting left the mantissa 52 bits. The exponent2 is reduced to
5519 compensate. */
5520 exponent2 -= 52;
5521
5522 hres = VARIANT_DI_normalize(dest, exponent2, TRUE);
5523 }
5524
5525 return hres;
5526 }
5527
5528 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
5529 BOOL round)
5530 {
5531 HRESULT hRet = S_OK;
5532 VARIANT_DI di_left, di_right, di_result;
5533 HRESULT divresult;
5534
5535 VARIANT_DIFromDec(pDecLeft, &di_left);
5536 VARIANT_DIFromDec(pDecRight, &di_right);
5537 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
5538 if (divresult != S_OK)
5539 {
5540 /* division actually overflowed */
5541 hRet = divresult;
5542 }
5543 else
5544 {
5545 hRet = S_OK;
5546
5547 if (di_result.scale > DEC_MAX_SCALE)
5548 {
5549 unsigned char remainder = 0;
5550
5551 /* division underflowed. In order to comply with the MSDN
5552 specifications for DECIMAL ranges, some significant digits
5553 must be removed
5554 */
5555 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5556 di_result.scale);
5557 while (di_result.scale > DEC_MAX_SCALE &&
5558 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5559 {
5560 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5561 di_result.scale--;
5562 }
5563 if (di_result.scale > DEC_MAX_SCALE)
5564 {
5565 WARN("result underflowed, setting to 0\n");
5566 di_result.scale = 0;
5567 di_result.sign = 0;
5568 }
5569 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5570 {
5571 unsigned int i;
5572 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5573 ULONGLONG digit = di_result.bitsnum[i] + 1;
5574 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5575 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5576 }
5577 }
5578 }
5579 VARIANT_DecFromDI(&di_result, pDecOut);
5580 }
5581 return hRet;
5582 }
5583
5584 /************************************************************************
5585 * VarDecDiv (OLEAUT32.178)
5586 *
5587 * Divide one DECIMAL by another.
5588 *
5589 * PARAMS
5590 * pDecLeft [I] Source
5591 * pDecRight [I] Value to divide by
5592 * pDecOut [O] Destination
5593 *
5594 * RETURNS
5595 * Success: S_OK.
5596 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5597 */
5598 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5599 {
5600 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5601
5602 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
5603 }
5604
5605 /************************************************************************
5606 * VarDecMul (OLEAUT32.179)
5607 *
5608 * Multiply one DECIMAL by another.
5609 *
5610 * PARAMS
5611 * pDecLeft [I] Source
5612 * pDecRight [I] Value to multiply by
5613 * pDecOut [O] Destination
5614 *
5615 * RETURNS
5616 * Success: S_OK.
5617 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5618 */
5619 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5620 {
5621 HRESULT hRet = S_OK;
5622 VARIANT_DI di_left, di_right, di_result;
5623 int mulresult;
5624
5625 VARIANT_DIFromDec(pDecLeft, &di_left);
5626 VARIANT_DIFromDec(pDecRight, &di_right);
5627 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5628 if (mulresult)
5629 {
5630 /* multiplication actually overflowed */
5631 hRet = DISP_E_OVERFLOW;
5632 }
5633 else
5634 {
5635 if (di_result.scale > DEC_MAX_SCALE)
5636 {
5637 /* multiplication underflowed. In order to comply with the MSDN
5638 specifications for DECIMAL ranges, some significant digits
5639 must be removed
5640 */
5641 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5642 di_result.scale);
5643 while (di_result.scale > DEC_MAX_SCALE &&
5644 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5645 {
5646 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5647 di_result.scale--;
5648 }
5649 if (di_result.scale > DEC_MAX_SCALE)
5650 {
5651 WARN("result underflowed, setting to 0\n");
5652 di_result.scale = 0;
5653 di_result.sign = 0;
5654 }
5655 }
5656 VARIANT_DecFromDI(&di_result, pDecOut);
5657 }
5658 return hRet;
5659 }
5660
5661 /************************************************************************
5662 * VarDecSub (OLEAUT32.181)
5663 *
5664 * Subtract one DECIMAL from another.
5665 *
5666 * PARAMS
5667 * pDecLeft [I] Source
5668 * pDecRight [I] DECIMAL to subtract from pDecLeft
5669 * pDecOut [O] Destination
5670 *
5671 * RETURNS
5672 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5673 */
5674 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5675 {
5676 DECIMAL decRight;
5677
5678 /* Implement as addition of the negative */
5679 VarDecNeg(pDecRight, &decRight);
5680 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5681 }
5682
5683 /************************************************************************
5684 * VarDecAbs (OLEAUT32.182)
5685 *
5686 * Convert a DECIMAL into its absolute value.
5687 *
5688 * PARAMS
5689 * pDecIn [I] Source
5690 * pDecOut [O] Destination
5691 *
5692 * RETURNS
5693 * S_OK. This function does not fail.
5694 */
5695 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5696 {
5697 *pDecOut = *pDecIn;
5698 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5699 return S_OK;
5700 }
5701
5702 /************************************************************************
5703 * VarDecFix (OLEAUT32.187)
5704 *
5705 * Return the integer portion of a DECIMAL.
5706 *
5707 * PARAMS
5708 * pDecIn [I] Source
5709 * pDecOut [O] Destination
5710 *
5711 * RETURNS
5712 * Success: S_OK.
5713 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5714 *
5715 * NOTES
5716 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5717 * negative numbers away from 0, while this function rounds them towards zero.
5718 */
5719 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5720 {
5721 double dbl;
5722 HRESULT hr;
5723
5724 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5725 return E_INVALIDARG;
5726
5727 if (!DEC_SCALE(pDecIn))
5728 {
5729 *pDecOut = *pDecIn; /* Already an integer */
5730 return S_OK;
5731 }
5732
5733 hr = VarR8FromDec(pDecIn, &dbl);
5734 if (SUCCEEDED(hr)) {
5735 LONGLONG rounded = dbl;
5736
5737 hr = VarDecFromI8(rounded, pDecOut);
5738 }
5739 return hr;
5740 }
5741
5742 /************************************************************************
5743 * VarDecInt (OLEAUT32.188)
5744 *
5745 * Return the integer portion of a DECIMAL.
5746 *
5747 * PARAMS
5748 * pDecIn [I] Source
5749 * pDecOut [O] Destination
5750 *
5751 * RETURNS
5752 * Success: S_OK.
5753 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5754 *
5755 * NOTES
5756 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5757 * negative numbers towards 0, while this function rounds them away from zero.
5758 */
5759 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5760 {
5761 double dbl;
5762 HRESULT hr;
5763
5764 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5765 return E_INVALIDARG;
5766
5767 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5768 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5769
5770 hr = VarR8FromDec(pDecIn, &dbl);
5771 if (SUCCEEDED(hr)) {
5772 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
5773
5774 hr = VarDecFromI8(rounded, pDecOut);
5775 }
5776 return hr;
5777 }
5778
5779 /************************************************************************
5780 * VarDecNeg (OLEAUT32.189)
5781 *
5782 * Change the sign of a DECIMAL.
5783 *
5784 * PARAMS
5785 * pDecIn [I] Source
5786 * pDecOut [O] Destination
5787 *
5788 * RETURNS
5789 * S_OK. This function does not fail.
5790 */
5791 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5792 {
5793 *pDecOut = *pDecIn;
5794 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5795 return S_OK;
5796 }
5797
5798 /************************************************************************
5799 * VarDecRound (OLEAUT32.203)
5800 *
5801 * Change the precision of a DECIMAL.
5802 *
5803 * PARAMS
5804 * pDecIn [I] Source
5805 * cDecimals [I] New number of decimals to keep
5806 * pDecOut [O] Destination
5807 *
5808 * RETURNS
5809 * Success: S_OK. pDecOut contains the rounded value.
5810 * Failure: E_INVALIDARG if any argument is invalid.
5811 */
5812 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5813 {
5814 DECIMAL divisor, tmp;
5815 HRESULT hr;
5816 unsigned int i;
5817
5818 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5819 return E_INVALIDARG;
5820
5821 if (cDecimals >= DEC_SCALE(pDecIn))
5822 {
5823 *pDecOut = *pDecIn; /* More precision than we have */
5824 return S_OK;
5825 }
5826
5827 /* truncate significant digits and rescale */
5828 memset(&divisor, 0, sizeof(divisor));
5829 DEC_LO64(&divisor) = 1;
5830
5831 memset(&tmp, 0, sizeof(tmp));
5832 DEC_LO64(&tmp) = 10;
5833 for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i)
5834 {
5835 hr = VarDecMul(&divisor, &tmp, &divisor);
5836 if (FAILED(hr))
5837 return hr;
5838 }
5839
5840 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
5841 if (FAILED(hr))
5842 return hr;
5843
5844 DEC_SCALE(pDecOut) = cDecimals;
5845
5846 return S_OK;
5847 }
5848
5849 /************************************************************************
5850 * VarDecCmp (OLEAUT32.204)
5851 *
5852 * Compare two DECIMAL values.
5853 *
5854 * PARAMS
5855 * pDecLeft [I] Source
5856 * pDecRight [I] Value to compare
5857 *
5858 * RETURNS
5859 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5860 * is less than, equal to or greater than pDecRight respectively.
5861 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5862 */
5863 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5864 {
5865 HRESULT hRet;
5866 DECIMAL result;
5867
5868 if (!pDecLeft || !pDecRight)
5869 return VARCMP_NULL;
5870
5871 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) &&
5872 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5873 return VARCMP_GT;
5874 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) &&
5875 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5876 return VARCMP_LT;
5877
5878 /* Subtract right from left, and compare the result to 0 */
5879 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5880
5881 if (SUCCEEDED(hRet))
5882 {
5883 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5884
5885 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5886 hRet = (HRESULT)VARCMP_LT;
5887 else if (non_zero)
5888 hRet = (HRESULT)VARCMP_GT;
5889 else
5890 hRet = (HRESULT)VARCMP_EQ;
5891 }
5892 return hRet;
5893 }
5894
5895 /************************************************************************
5896 * VarDecCmpR8 (OLEAUT32.298)
5897 *
5898 * Compare a DECIMAL to a double
5899 *
5900 * PARAMS
5901 * pDecLeft [I] DECIMAL Source
5902 * dblRight [I] double to compare to pDecLeft
5903 *
5904 * RETURNS
5905 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5906 * is less than, equal to or greater than pDecLeft respectively.
5907 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5908 */
5909 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5910 {
5911 HRESULT hRet;
5912 DECIMAL decRight;
5913
5914 hRet = VarDecFromR8(dblRight, &decRight);
5915
5916 if (SUCCEEDED(hRet))
5917 hRet = VarDecCmp(pDecLeft, &decRight);
5918
5919 return hRet;
5920 }
5921
5922 /* BOOL
5923 */
5924
5925 /************************************************************************
5926 * VarBoolFromUI1 (OLEAUT32.118)
5927 *
5928 * Convert a VT_UI1 to a VT_BOOL.
5929 *
5930 * PARAMS
5931 * bIn [I] Source
5932 * pBoolOut [O] Destination
5933 *
5934 * RETURNS
5935 * S_OK.
5936 */
5937 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5938 {
5939 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5940 return S_OK;
5941 }
5942
5943 /************************************************************************
5944 * VarBoolFromI2 (OLEAUT32.119)
5945 *
5946 * Convert a VT_I2 to a VT_BOOL.
5947 *
5948 * PARAMS
5949 * sIn [I] Source
5950 * pBoolOut [O] Destination
5951 *
5952 * RETURNS
5953 * S_OK.
5954 */
5955 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5956 {
5957 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5958 return S_OK;
5959 }
5960
5961 /************************************************************************
5962 * VarBoolFromI4 (OLEAUT32.120)
5963 *
5964 * Convert a VT_I4 to a VT_BOOL.
5965 *
5966 * PARAMS
5967 * sIn [I] Source
5968 * pBoolOut [O] Destination
5969 *
5970 * RETURNS
5971 * S_OK.
5972 */
5973 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5974 {
5975 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5976 return S_OK;
5977 }
5978
5979 /************************************************************************
5980 * VarBoolFromR4 (OLEAUT32.121)
5981 *
5982 * Convert a VT_R4 to a VT_BOOL.
5983 *
5984 * PARAMS
5985 * fltIn [I] Source
5986 * pBoolOut [O] Destination
5987 *
5988 * RETURNS
5989 * S_OK.
5990 */
5991 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5992 {
5993 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5994 return S_OK;
5995 }
5996
5997 /************************************************************************
5998 * VarBoolFromR8 (OLEAUT32.122)
5999 *
6000 * Convert a VT_R8 to a VT_BOOL.
6001 *
6002 * PARAMS
6003 * dblIn [I] Source
6004 * pBoolOut [O] Destination
6005 *
6006 * RETURNS
6007 * S_OK.
6008 */
6009 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
6010 {
6011 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
6012 return S_OK;
6013 }
6014
6015 /************************************************************************
6016 * VarBoolFromDate (OLEAUT32.123)
6017 *
6018 * Convert a VT_DATE to a VT_BOOL.
6019 *
6020 * PARAMS
6021 * dateIn [I] Source
6022 * pBoolOut [O] Destination
6023 *
6024 * RETURNS
6025 * S_OK.
6026 */
6027 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
6028 {
6029 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
6030 return S_OK;
6031 }
6032
6033 /************************************************************************
6034 * VarBoolFromCy (OLEAUT32.124)
6035 *
6036 * Convert a VT_CY to a VT_BOOL.
6037 *
6038 * PARAMS
6039 * cyIn [I] Source
6040 * pBoolOut [O] Destination
6041 *
6042 * RETURNS
6043 * S_OK.
6044 */
6045 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
6046 {
6047 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
6048 return S_OK;
6049 }
6050
6051 /************************************************************************
6052 * VARIANT_GetLocalisedText [internal]
6053 *
6054 * Get a localized string from the resources
6055 *
6056 */
6057 BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
6058 {
6059 HRSRC hrsrc;
6060
6061 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
6062 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
6063 if (hrsrc)
6064 {
6065 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc );
6066
6067 if (hmem)
6068 {
6069 const WCHAR *p;
6070 unsigned int i;
6071
6072 p = LockResource( hmem );
6073 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
6074
6075 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
6076 lpszDest[*p] = '\0';
6077 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
6078 return TRUE;
6079 }
6080 }
6081 return FALSE;
6082 }
6083
6084 /************************************************************************
6085 * VarBoolFromStr (OLEAUT32.125)
6086 *
6087 * Convert a VT_BSTR to a VT_BOOL.
6088 *
6089 * PARAMS
6090 * strIn [I] Source
6091 * lcid [I] LCID for the conversion
6092 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6093 * pBoolOut [O] Destination
6094 *
6095 * RETURNS
6096 * Success: S_OK.
6097 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6098 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6099 *
6100 * NOTES
6101 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6102 * it may contain (in any case mapping) the text "true" or "false".
6103 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6104 * localised text of "True" or "False" in the language specified by lcid.
6105 * - If none of these matches occur, the string is treated as a numeric string
6106 * and the boolean pBoolOut will be set according to whether the number is zero
6107 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6108 * - If the text is not numeric and does not match any of the above, then
6109 * DISP_E_TYPEMISMATCH is returned.
6110 */
6111 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6112 {
6113 /* Any VB/VBA programmers out there should recognise these strings... */
6114 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
6115 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
6116 WCHAR szBuff[64];
6117 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6118 HRESULT hRes = S_OK;
6119
6120 if (!strIn || !pBoolOut)
6121 return DISP_E_TYPEMISMATCH;
6122
6123 /* Check if we should be comparing against localised text */
6124 if (dwFlags & VAR_LOCALBOOL)
6125 {
6126 /* Convert our LCID into a usable value */
6127 lcid = ConvertDefaultLocale(lcid);
6128
6129 langId = LANGIDFROMLCID(lcid);
6130
6131 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6132 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6133
6134 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6135 * I don't think this is needed unless any of the localised text strings
6136 * contain characters that can be so mapped. In the event that this is
6137 * true for a given language (possibly some Asian languages), then strIn
6138 * should be mapped here _only_ if langId is an Id for which this can occur.
6139 */
6140 }
6141
6142 /* Note that if we are not comparing against localised strings, langId
6143 * will have its default value of LANG_ENGLISH. This allows us to mimic
6144 * the native behaviour of always checking against English strings even
6145 * after we've checked for localised ones.
6146 */
6147 VarBoolFromStr_CheckLocalised:
6148 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6149 {
6150 /* Compare against localised strings, ignoring case */
6151 if (!strcmpiW(strIn, szBuff))
6152 {
6153 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6154 return hRes;
6155 }
6156 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6157 if (!strcmpiW(strIn, szBuff))
6158 {
6159 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6160 return hRes;
6161 }
6162 }
6163
6164 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6165 {
6166 /* We have checked the localised text, now check English */
6167 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6168 goto VarBoolFromStr_CheckLocalised;
6169 }
6170
6171 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6172 if (!strcmpW(strIn, szFalse))
6173 *pBoolOut = VARIANT_FALSE;
6174 else if (!strcmpW(strIn, szTrue))
6175 *pBoolOut = VARIANT_TRUE;
6176 else
6177 {
6178 double d;
6179
6180 /* If this string is a number, convert it as one */
6181 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6182 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6183 }
6184 return hRes;
6185 }
6186
6187 /************************************************************************
6188 * VarBoolFromDisp (OLEAUT32.126)
6189 *
6190 * Convert a VT_DISPATCH to a VT_BOOL.
6191 *
6192 * PARAMS
6193 * pdispIn [I] Source
6194 * lcid [I] LCID for conversion
6195 * pBoolOut [O] Destination
6196 *
6197 * RETURNS
6198 * Success: S_OK.
6199 * Failure: E_INVALIDARG, if the source value is invalid
6200 * DISP_E_OVERFLOW, if the value will not fit in the destination
6201 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6202 */
6203 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6204 {
6205 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6206 }
6207
6208 /************************************************************************
6209 * VarBoolFromI1 (OLEAUT32.233)
6210 *
6211 * Convert a VT_I1 to a VT_BOOL.
6212 *
6213 * PARAMS
6214 * cIn [I] Source
6215 * pBoolOut [O] Destination
6216 *
6217 * RETURNS
6218 * S_OK.
6219 */
6220 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6221 {
6222 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6223 return S_OK;
6224 }
6225
6226 /************************************************************************
6227 * VarBoolFromUI2 (OLEAUT32.234)
6228 *
6229 * Convert a VT_UI2 to a VT_BOOL.
6230 *
6231 * PARAMS
6232 * usIn [I] Source
6233 * pBoolOut [O] Destination
6234 *
6235 * RETURNS
6236 * S_OK.
6237 */
6238 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6239 {
6240 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6241 return S_OK;
6242 }
6243
6244 /************************************************************************
6245 * VarBoolFromUI4 (OLEAUT32.235)
6246 *
6247 * Convert a VT_UI4 to a VT_BOOL.
6248 *
6249 * PARAMS
6250 * ulIn [I] Source
6251 * pBoolOut [O] Destination
6252 *
6253 * RETURNS
6254 * S_OK.
6255 */
6256 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6257 {
6258 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6259 return S_OK;
6260 }
6261
6262 /************************************************************************
6263 * VarBoolFromDec (OLEAUT32.236)
6264 *
6265 * Convert a VT_DECIMAL to a VT_BOOL.
6266 *
6267 * PARAMS
6268 * pDecIn [I] Source
6269 * pBoolOut [O] Destination
6270 *
6271 * RETURNS
6272 * Success: S_OK.
6273 * Failure: E_INVALIDARG, if pDecIn is invalid.
6274 */
6275 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6276 {
6277 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6278 return E_INVALIDARG;
6279
6280 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6281 *pBoolOut = VARIANT_TRUE;
6282 else
6283 *pBoolOut = VARIANT_FALSE;
6284 return S_OK;
6285 }
6286
6287 /************************************************************************
6288 * VarBoolFromI8 (OLEAUT32.370)
6289 *
6290 * Convert a VT_I8 to a VT_BOOL.
6291 *
6292 * PARAMS
6293 * ullIn [I] Source
6294 * pBoolOut [O] Destination
6295 *
6296 * RETURNS
6297 * S_OK.
6298 */
6299 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6300 {
6301 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6302 return S_OK;
6303 }
6304
6305 /************************************************************************
6306 * VarBoolFromUI8 (OLEAUT32.371)
6307 *
6308 * Convert a VT_UI8 to a VT_BOOL.
6309 *
6310 * PARAMS
6311 * ullIn [I] Source
6312 * pBoolOut [O] Destination
6313 *
6314 * RETURNS
6315 * S_OK.
6316 */
6317 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6318 {
6319 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6320 return S_OK;
6321 }
6322
6323 /* BSTR
6324 */
6325
6326 /* Write a number from a UI8 and sign */
6327 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6328 {
6329 do
6330 {
6331 WCHAR ulNextDigit = ulVal % 10;
6332
6333 *szOut-- = '0' + ulNextDigit;
6334 ulVal = (ulVal - ulNextDigit) / 10;
6335 } while (ulVal);
6336
6337 szOut++;
6338 return szOut;
6339 }
6340
6341 /* Create a (possibly localised) BSTR from a UI8 and sign */
6342 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6343 {
6344 WCHAR szConverted[256];
6345
6346 if (dwFlags & VAR_NEGATIVE)
6347 *--szOut = '-';
6348
6349 if (dwFlags & LOCALE_USE_NLS)
6350 {
6351 /* Format the number for the locale */
6352 szConverted[0] = '\0';
6353 GetNumberFormatW(lcid,
6354 dwFlags & LOCALE_NOUSEROVERRIDE,
6355 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
6356 szOut = szConverted;
6357 }
6358 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
6359 }
6360
6361 /* Create a (possibly localised) BSTR from a UI8 and sign */
6362 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6363 {
6364 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
6365
6366 if (!pbstrOut)
6367 return E_INVALIDARG;
6368
6369 /* Create the basic number string */
6370 *szOut-- = '\0';
6371 szOut = VARIANT_WriteNumber(ulVal, szOut);
6372
6373 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6374 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6375 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6376 }
6377
6378 /******************************************************************************
6379 * VarBstrFromUI1 (OLEAUT32.108)
6380 *
6381 * Convert a VT_UI1 to a VT_BSTR.
6382 *
6383 * PARAMS
6384 * bIn [I] Source
6385 * lcid [I] LCID for the conversion
6386 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6387 * pbstrOut [O] Destination
6388 *
6389 * RETURNS
6390 * Success: S_OK.
6391 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6392 * E_OUTOFMEMORY, if memory allocation fails.
6393 */
6394 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6395 {
6396 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6397 }
6398
6399 /******************************************************************************
6400 * VarBstrFromI2 (OLEAUT32.109)
6401 *
6402 * Convert a VT_I2 to a VT_BSTR.
6403 *
6404 * PARAMS
6405 * sIn [I] Source
6406 * lcid [I] LCID for the conversion
6407 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6408 * pbstrOut [O] Destination
6409 *
6410 * RETURNS
6411 * Success: S_OK.
6412 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6413 * E_OUTOFMEMORY, if memory allocation fails.
6414 */
6415 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6416 {
6417 ULONG64 ul64 = sIn;
6418
6419 if (sIn < 0)
6420 {
6421 ul64 = -sIn;
6422 dwFlags |= VAR_NEGATIVE;
6423 }
6424 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6425 }
6426
6427 /******************************************************************************
6428 * VarBstrFromI4 (OLEAUT32.110)
6429 *
6430 * Convert a VT_I4 to a VT_BSTR.
6431 *
6432 * PARAMS
6433 * lIn [I] Source
6434 * lcid [I] LCID for the conversion
6435 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6436 * pbstrOut [O] Destination
6437 *
6438 * RETURNS
6439 * Success: S_OK.
6440 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6441 * E_OUTOFMEMORY, if memory allocation fails.
6442 */
6443 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6444 {
6445 ULONG64 ul64 = lIn;
6446
6447 if (lIn < 0)
6448 {
6449 ul64 = (ULONG)-lIn;
6450 dwFlags |= VAR_NEGATIVE;
6451 }
6452 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6453 }
6454
6455 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
6456 {
6457 BSTR bstrOut;
6458 WCHAR lpDecimalSep[16];
6459
6460 /* Native oleaut32 uses the locale-specific decimal separator even in the
6461 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6462 American locales will see "one thousand and one tenth" as "1000,1"
6463 instead of "1000.1" (notice the comma). The following code checks for
6464 the need to replace the decimal separator, and if so, will prepare an
6465 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6466 */
6467 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6468 lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6469 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6470 {
6471 /* locale is compatible with English - return original string */
6472 bstrOut = SysAllocString(buff);
6473 }
6474 else
6475 {
6476 WCHAR *p;
6477 WCHAR numbuff[256];
6478 WCHAR empty[] = {'\0'};
6479 NUMBERFMTW minFormat;
6480
6481 minFormat.NumDigits = 0;
6482 minFormat.LeadingZero = 0;
6483 minFormat.Grouping = 0;
6484 minFormat.lpDecimalSep = lpDecimalSep;
6485 minFormat.lpThousandSep = empty;
6486 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6487
6488 /* count number of decimal digits in string */
6489 p = strchrW( buff, '.' );
6490 if (p) minFormat.NumDigits = strlenW(p + 1);
6491
6492 numbuff[0] = '\0';
6493 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6494 {
6495 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6496 bstrOut = SysAllocString(buff);
6497 }
6498 else
6499 {
6500 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6501 bstrOut = SysAllocString(numbuff);
6502 }
6503 }
6504 return bstrOut;
6505 }
6506
6507 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6508 BSTR* pbstrOut, LPCWSTR lpszFormat)
6509 {
6510 WCHAR buff[256];
6511
6512 if (!pbstrOut)
6513 return E_INVALIDARG;
6514
6515 sprintfW( buff, lpszFormat, dblIn );
6516
6517 /* Negative zeroes are disallowed (some applications depend on this).
6518 If buff starts with a minus, and then nothing follows but zeroes
6519 and/or a period, it is a negative zero and is replaced with a
6520 canonical zero. This duplicates native oleaut32 behavior.
6521 */
6522 if (buff[0] == '-')
6523 {
6524 const WCHAR szAccept[] = {'0', '.', '\0'};
6525 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6526 { buff[0] = '0'; buff[1] = '\0'; }
6527 }
6528
6529 TRACE("created string %s\n", debugstr_w(buff));
6530 if (dwFlags & LOCALE_USE_NLS)
6531 {
6532 WCHAR numbuff[256];
6533
6534 /* Format the number for the locale */
6535 numbuff[0] = '\0';
6536 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6537 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6538 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6539 *pbstrOut = SysAllocString(numbuff);
6540 }
6541 else
6542 {
6543 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6544 }
6545 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6546 }
6547
6548 /******************************************************************************
6549 * VarBstrFromR4 (OLEAUT32.111)
6550 *
6551 * Convert a VT_R4 to a VT_BSTR.
6552 *
6553 * PARAMS
6554 * fltIn [I] Source
6555 * lcid [I] LCID for the conversion
6556 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6557 * pbstrOut [O] Destination
6558 *
6559 * RETURNS
6560 * Success: S_OK.
6561 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6562 * E_OUTOFMEMORY, if memory allocation fails.
6563 */
6564 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6565 {
6566 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6567 }
6568
6569 /******************************************************************************
6570 * VarBstrFromR8 (OLEAUT32.112)
6571 *
6572 * Convert a VT_R8 to a VT_BSTR.
6573 *
6574 * PARAMS
6575 * dblIn [I] Source
6576 * lcid [I] LCID for the conversion
6577 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6578 * pbstrOut [O] Destination
6579 *
6580 * RETURNS
6581 * Success: S_OK.
6582 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6583 * E_OUTOFMEMORY, if memory allocation fails.
6584 */
6585 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6586 {
6587 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6588 }
6589
6590 /******************************************************************************
6591 * VarBstrFromCy [OLEAUT32.113]
6592 *
6593 * Convert a VT_CY to a VT_BSTR.
6594 *
6595 * PARAMS
6596 * cyIn [I] Source
6597 * lcid [I] LCID for the conversion
6598 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6599 * pbstrOut [O] Destination
6600 *
6601 * RETURNS
6602 * Success: S_OK.
6603 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6604 * E_OUTOFMEMORY, if memory allocation fails.
6605 */
6606 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6607 {
6608 WCHAR buff[256];
6609 VARIANT_DI decVal;
6610
6611 if (!pbstrOut)
6612 return E_INVALIDARG;
6613
6614 decVal.scale = 4;
6615 decVal.sign = 0;
6616 decVal.bitsnum[0] = cyIn.s.Lo;
6617 decVal.bitsnum[1] = cyIn.s.Hi;
6618 if (cyIn.s.Hi & 0x80000000UL) {
6619 DWORD one = 1;
6620
6621 /* Negative number! */
6622 decVal.sign = 1;
6623 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6624 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6625 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6626 }
6627 decVal.bitsnum[2] = 0;
6628 VARIANT_DI_tostringW(&decVal, buff, sizeof(buff)/sizeof(buff[0]));
6629
6630 if (dwFlags & LOCALE_USE_NLS)
6631 {
6632 WCHAR cybuff[256];
6633
6634 /* Format the currency for the locale */
6635 cybuff[0] = '\0';
6636 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6637 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6638 *pbstrOut = SysAllocString(cybuff);
6639 }
6640 else
6641 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
6642
6643 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6644 }
6645
6646 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
6647 {
6648 int len, tmp;
6649
6650 if(min_len >= date_len)
6651 return -1;
6652
6653 for(len=0, tmp=o; tmp; tmp/=10) len++;
6654 if(!len) len++;
6655 if(len >= date_len)
6656 return -1;
6657
6658 for(tmp=min_len-len; tmp>0; tmp--)
6659 *date++ = '0';
6660 for(tmp=len; tmp>0; tmp--, o/=10)
6661 date[tmp-1] = '0' + o%10;
6662 return min_len>len ? min_len : len;
6663 }
6664
6665 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6666 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
6667 const WCHAR *fmt, WCHAR *date, int date_len)
6668 {
6669 static const LCTYPE dayname[] = {
6670 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
6671 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
6672 };
6673 static const LCTYPE sdayname[] = {
6674 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
6675 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
6676 LOCALE_SABBREVDAYNAME6
6677 };
6678 static const LCTYPE monthname[] = {
6679 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6680 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6681 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
6682 };
6683 static const LCTYPE smonthname[] = {
6684 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6685 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6686 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6687 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
6688 };
6689
6690 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
6691 FIXME("ignoring flags %x\n", flags);
6692 flags &= LOCALE_NOUSEROVERRIDE;
6693
6694 while(*fmt && date_len) {
6695 int count = 1;
6696
6697 switch(*fmt) {
6698 case 'd':
6699 case 'M':
6700 case 'y':
6701 case 'g':
6702 while(*fmt == *(fmt+count))
6703 count++;
6704 fmt += count-1;
6705 }
6706
6707 switch(*fmt) {
6708 case 'd':
6709 if(count >= 4)
6710 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
6711 else if(count == 3)
6712 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
6713 else
6714 count = output_int_len(st->wDay, count, date, date_len);
6715 break;
6716 case 'M':
6717 if(count >= 4)
6718 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
6719 else if(count == 3)
6720 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
6721 else
6722 count = output_int_len(st->wMonth, count, date, date_len);
6723 break;
6724 case 'y':
6725 if(count >= 3)
6726 count = output_int_len(st->wYear, 0, date, date_len);
6727 else
6728 count = output_int_len(st->wYear%100, count, date, date_len);
6729 break;
6730 case 'g':
6731 if(count == 2) {
6732 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6733
6734 *date++ = 'A';
6735 date_len--;
6736 if(date_len)
6737 *date = 'D';
6738 else
6739 count = -1;
6740 break;
6741 }
6742 /* fall through */
6743 default:
6744 *date = *fmt;
6745 }
6746
6747 if(count < 0)
6748 break;
6749 fmt++;
6750 date += count;
6751 date_len -= count;
6752 }
6753
6754 if(!date_len)
6755 return FALSE;
6756 *date++ = 0;
6757 return TRUE;
6758 }
6759
6760 /******************************************************************************
6761 * VarBstrFromDate [OLEAUT32.114]
6762 *
6763 * Convert a VT_DATE to a VT_BSTR.
6764 *
6765 * PARAMS
6766 * dateIn [I] Source
6767 * lcid [I] LCID for the conversion
6768 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6769 * pbstrOut [O] Destination
6770 *
6771 * RETURNS
6772 * Success: S_OK.
6773 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6774 * E_OUTOFMEMORY, if memory allocation fails.
6775 */
6776 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6777 {
6778 SYSTEMTIME st;
6779 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6780 WCHAR date[128], fmt_buff[80], *time;
6781
6782 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6783
6784 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6785 return E_INVALIDARG;
6786
6787 *pbstrOut = NULL;
6788
6789 if (dwFlags & VAR_CALENDAR_THAI)
6790 st.wYear += 553; /* Use the Thai buddhist calendar year */
6791 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6792 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6793
6794 if (dwFlags & LOCALE_USE_NLS)
6795 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6796 else
6797 {
6798 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6799 double partial = dateIn - whole;
6800
6801 if (whole == 0.0)
6802 dwFlags |= VAR_TIMEVALUEONLY;
6803 else if (partial > -1e-12 && partial < 1e-12)
6804 dwFlags |= VAR_DATEVALUEONLY;
6805 }
6806
6807 if (dwFlags & VAR_TIMEVALUEONLY)
6808 date[0] = '\0';
6809 else
6810 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, sizeof(fmt_buff)/sizeof(WCHAR)) ||
6811 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, sizeof(date)/sizeof(WCHAR)))
6812 return E_INVALIDARG;
6813
6814 if (!(dwFlags & VAR_DATEVALUEONLY))
6815 {
6816 time = date + strlenW(date);
6817 if (time != date)
6818 *time++ = ' ';
6819 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6820 sizeof(date)/sizeof(WCHAR)-(time-date)))
6821 return E_INVALIDARG;
6822 }
6823
6824 *pbstrOut = SysAllocString(date);
6825 if (*pbstrOut)
6826 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6827 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6828 }
6829
6830 /******************************************************************************
6831 * VarBstrFromBool (OLEAUT32.116)
6832 *
6833 * Convert a VT_BOOL to a VT_BSTR.
6834 *
6835 * PARAMS
6836 * boolIn [I] Source
6837 * lcid [I] LCID for the conversion
6838 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6839 * pbstrOut [O] Destination
6840 *
6841 * RETURNS
6842 * Success: S_OK.
6843 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6844 * E_OUTOFMEMORY, if memory allocation fails.
6845 *
6846 * NOTES
6847 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6848 * localised text of "True" or "False". To convert a bool into a
6849 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6850 */
6851 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6852 {
6853 WCHAR szBuff[64];
6854 DWORD dwResId = IDS_TRUE;
6855 LANGID langId;
6856
6857 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6858
6859 if (!pbstrOut)
6860 return E_INVALIDARG;
6861
6862 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6863 * for variant formatting */
6864 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6865 {
6866 case VAR_BOOLONOFF:
6867 dwResId = IDS_ON;
6868 break;
6869 case VAR_BOOLYESNO:
6870 dwResId = IDS_YES;
6871 break;
6872 case VAR_LOCALBOOL:
6873 break;
6874 default:
6875 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6876 }
6877
6878 lcid = ConvertDefaultLocale(lcid);
6879 langId = LANGIDFROMLCID(lcid);
6880 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6881 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6882
6883 if (boolIn == VARIANT_FALSE)
6884 dwResId++; /* Use negative form */
6885
6886 VarBstrFromBool_GetLocalised:
6887 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6888 {
6889 *pbstrOut = SysAllocString(szBuff);
6890 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6891 }
6892
6893 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6894 {
6895 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6896 goto VarBstrFromBool_GetLocalised;
6897 }
6898
6899 /* Should never get here */
6900 WARN("Failed to load bool text!\n");
6901 return E_OUTOFMEMORY;
6902 }
6903
6904 /******************************************************************************
6905 * VarBstrFromI1 (OLEAUT32.229)
6906 *
6907 * Convert a VT_I1 to a VT_BSTR.
6908 *
6909 * PARAMS
6910 * cIn [I] Source
6911 * lcid [I] LCID for the conversion
6912 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6913 * pbstrOut [O] Destination
6914 *
6915 * RETURNS
6916 * Success: S_OK.
6917 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6918 * E_OUTOFMEMORY, if memory allocation fails.
6919 */
6920 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6921 {
6922 ULONG64 ul64 = cIn;
6923
6924 if (cIn < 0)
6925 {
6926 ul64 = -cIn;
6927 dwFlags |= VAR_NEGATIVE;
6928 }
6929 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6930 }
6931
6932 /******************************************************************************
6933 * VarBstrFromUI2 (OLEAUT32.230)
6934 *
6935 * Convert a VT_UI2 to a VT_BSTR.
6936 *
6937 * PARAMS
6938 * usIn [I] Source
6939 * lcid [I] LCID for the conversion
6940 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6941 * pbstrOut [O] Destination
6942 *
6943 * RETURNS
6944 * Success: S_OK.
6945 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6946 * E_OUTOFMEMORY, if memory allocation fails.
6947 */
6948 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6949 {
6950 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6951 }
6952
6953 /******************************************************************************
6954 * VarBstrFromUI4 (OLEAUT32.231)
6955 *
6956 * Convert a VT_UI4 to a VT_BSTR.
6957 *
6958 * PARAMS
6959 * ulIn [I] Source
6960 * lcid [I] LCID for the conversion
6961 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6962 * pbstrOut [O] Destination
6963 *
6964 * RETURNS
6965 * Success: S_OK.
6966 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6967 * E_OUTOFMEMORY, if memory allocation fails.
6968 */
6969 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6970 {
6971 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6972 }
6973
6974 /******************************************************************************
6975 * VarBstrFromDec (OLEAUT32.232)
6976 *
6977 * Convert a VT_DECIMAL to a VT_BSTR.
6978 *
6979 * PARAMS
6980 * pDecIn [I] Source
6981 * lcid [I] LCID for the conversion
6982 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6983 * pbstrOut [O] Destination
6984 *
6985 * RETURNS
6986 * Success: S_OK.
6987 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6988 * E_OUTOFMEMORY, if memory allocation fails.
6989 */
6990 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6991 {
6992 WCHAR buff[256];
6993 VARIANT_DI temp;
6994
6995 if (!pbstrOut)
6996 return E_INVALIDARG;
6997
6998 VARIANT_DIFromDec(pDecIn, &temp);
6999 VARIANT_DI_tostringW(&temp, buff, 256);
7000
7001 if (dwFlags & LOCALE_USE_NLS)
7002 {
7003 WCHAR numbuff[256];
7004
7005 /* Format the number for the locale */
7006 numbuff[0] = '\0';
7007 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
7008 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
7009 TRACE("created NLS string %s\n", debugstr_w(numbuff));
7010 *pbstrOut = SysAllocString(numbuff);
7011 }
7012 else
7013 {
7014 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
7015 }
7016
7017 TRACE("returning %s\n", debugstr_w(*pbstrOut));
7018 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
7019 }
7020
7021 /************************************************************************
7022 * VarBstrFromI8 (OLEAUT32.370)
7023 *
7024 * Convert a VT_I8 to a VT_BSTR.
7025 *
7026 * PARAMS
7027 * llIn [I] Source
7028 * lcid [I] LCID for the conversion
7029 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7030 * pbstrOut [O] Destination
7031 *
7032 * RETURNS
7033 * Success: S_OK.
7034 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7035 * E_OUTOFMEMORY, if memory allocation fails.
7036 */
7037 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7038 {
7039 ULONG64 ul64 = llIn;
7040
7041 if (llIn < 0)
7042 {
7043 ul64 = -llIn;
7044 dwFlags |= VAR_NEGATIVE;
7045 }
7046 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
7047 }
7048
7049 /************************************************************************
7050 * VarBstrFromUI8 (OLEAUT32.371)
7051 *
7052 * Convert a VT_UI8 to a VT_BSTR.
7053 *
7054 * PARAMS
7055 * ullIn [I] Source
7056 * lcid [I] LCID for the conversion
7057 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7058 * pbstrOut [O] Destination
7059 *
7060 * RETURNS
7061 * Success: S_OK.
7062 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7063 * E_OUTOFMEMORY, if memory allocation fails.
7064 */
7065 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7066 {
7067 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
7068 }
7069
7070 /************************************************************************
7071 * VarBstrFromDisp (OLEAUT32.115)
7072 *
7073 * Convert a VT_DISPATCH to a BSTR.
7074 *
7075 * PARAMS
7076 * pdispIn [I] Source
7077 * lcid [I] LCID for conversion
7078 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7079 * pbstrOut [O] Destination
7080 *
7081 * RETURNS
7082 * Success: S_OK.
7083 * Failure: E_INVALIDARG, if the source value is invalid
7084 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7085 */
7086 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7087 {
7088 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
7089 }
7090
7091 /**********************************************************************
7092 * VarBstrCat (OLEAUT32.313)
7093 *
7094 * Concatenate two BSTR values.
7095 *
7096 * PARAMS
7097 * pbstrLeft [I] Source
7098 * pbstrRight [I] Value to concatenate
7099 * pbstrOut [O] Destination
7100 *
7101 * RETURNS
7102 * Success: S_OK.
7103 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7104 * E_OUTOFMEMORY, if memory allocation fails.
7105 */
7106 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
7107 {
7108 unsigned int lenLeft, lenRight;
7109
7110 TRACE("%s,%s,%p\n",
7111 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7112 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
7113
7114 if (!pbstrOut)
7115 return E_INVALIDARG;
7116
7117 /* use byte length here to properly handle ansi-allocated BSTRs */
7118 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
7119 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
7120
7121 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
7122 if (!*pbstrOut)
7123 return E_OUTOFMEMORY;
7124
7125 (*pbstrOut)[0] = '\0';
7126
7127 if (pbstrLeft)
7128 memcpy(*pbstrOut, pbstrLeft, lenLeft);
7129
7130 if (pbstrRight)
7131 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
7132
7133 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
7134 return S_OK;
7135 }
7136
7137 /**********************************************************************
7138 * VarBstrCmp (OLEAUT32.314)
7139 *
7140 * Compare two BSTR values.
7141 *
7142 * PARAMS
7143 * pbstrLeft [I] Source
7144 * pbstrRight [I] Value to compare
7145 * lcid [I] LCID for the comparison
7146 * dwFlags [I] Flags to pass directly to CompareStringW().
7147 *
7148 * RETURNS
7149 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7150 * than, equal to or greater than pbstrRight respectively.
7151 *
7152 * NOTES
7153 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7154 * states. A NULL BSTR pointer is equivalent to an empty string.
7155 * If LCID is equal to 0, a byte by byte comparison is performed.
7156 */
7157 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
7158 {
7159 HRESULT hres;
7160 int ret;
7161
7162 TRACE("%s,%s,%d,%08x\n",
7163 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7164 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
7165
7166 if (!pbstrLeft || !*pbstrLeft)
7167 {
7168 if (pbstrRight && *pbstrRight)
7169 return VARCMP_LT;
7170 }
7171 else if (!pbstrRight || !*pbstrRight)
7172 return VARCMP_GT;
7173
7174 if (lcid == 0)
7175 {
7176 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
7177 unsigned int lenRight = SysStringByteLen(pbstrRight);
7178 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
7179 if (ret < 0)
7180 return VARCMP_LT;
7181 if (ret > 0)
7182 return VARCMP_GT;
7183 if (lenLeft < lenRight)
7184 return VARCMP_LT;
7185 if (lenLeft > lenRight)
7186 return VARCMP_GT;
7187 return VARCMP_EQ;
7188 }
7189 else
7190 {
7191 unsigned int lenLeft = SysStringLen(pbstrLeft);
7192 unsigned int lenRight = SysStringLen(pbstrRight);
7193
7194 if (lenLeft == 0 || lenRight == 0)
7195 {
7196 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
7197 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
7198 }
7199
7200 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
7201 pbstrRight, lenRight) - CSTR_LESS_THAN;
7202 TRACE("%d\n", hres);
7203 return hres;
7204 }
7205 }
7206
7207 /*
7208 * DATE
7209 */
7210
7211 /******************************************************************************
7212 * VarDateFromUI1 (OLEAUT32.88)
7213 *
7214 * Convert a VT_UI1 to a VT_DATE.
7215 *
7216 * PARAMS
7217 * bIn [I] Source
7218 * pdateOut [O] Destination
7219 *
7220 * RETURNS
7221 * S_OK.
7222 */
7223 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7224 {
7225 return VarR8FromUI1(bIn, pdateOut);
7226 }
7227
7228 /******************************************************************************
7229 * VarDateFromI2 (OLEAUT32.89)
7230 *
7231 * Convert a VT_I2 to a VT_DATE.
7232 *
7233 * PARAMS
7234 * sIn [I] Source
7235 * pdateOut [O] Destination
7236 *
7237 * RETURNS
7238 * S_OK.
7239 */
7240 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7241 {
7242 return VarR8FromI2(sIn, pdateOut);
7243 }
7244
7245 /******************************************************************************
7246 * VarDateFromI4 (OLEAUT32.90)
7247 *
7248 * Convert a VT_I4 to a VT_DATE.
7249 *
7250 * PARAMS
7251 * lIn [I] Source
7252 * pdateOut [O] Destination
7253 *
7254 * RETURNS
7255 * S_OK.
7256 */
7257 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7258 {
7259 return VarDateFromR8(lIn, pdateOut);
7260 }
7261
7262 /******************************************************************************
7263 * VarDateFromR4 (OLEAUT32.91)
7264 *
7265 * Convert a VT_R4 to a VT_DATE.
7266 *
7267 * PARAMS
7268 * fltIn [I] Source
7269 * pdateOut [O] Destination
7270 *
7271 * RETURNS
7272 * S_OK.
7273 */
7274 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7275 {
7276 return VarR8FromR4(fltIn, pdateOut);
7277 }
7278
7279 /******************************************************************************
7280 * VarDateFromR8 (OLEAUT32.92)
7281 *
7282 * Convert a VT_R8 to a VT_DATE.
7283 *
7284 * PARAMS
7285 * dblIn [I] Source
7286 * pdateOut [O] Destination
7287 *
7288 * RETURNS
7289 * S_OK.
7290 */
7291 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7292 {
7293 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7294 *pdateOut = (DATE)dblIn;
7295 return S_OK;
7296 }
7297
7298 /**********************************************************************
7299 * VarDateFromDisp (OLEAUT32.95)
7300 *
7301 * Convert a VT_DISPATCH to a VT_DATE.
7302 *
7303 * PARAMS
7304 * pdispIn [I] Source
7305 * lcid [I] LCID for conversion
7306 * pdateOut [O] Destination
7307 *
7308 * RETURNS
7309 * Success: S_OK.
7310 * Failure: E_INVALIDARG, if the source value is invalid
7311 * DISP_E_OVERFLOW, if the value will not fit in the destination
7312 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7313 */
7314 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7315 {
7316 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7317 }
7318
7319 /******************************************************************************
7320 * VarDateFromBool (OLEAUT32.96)
7321 *
7322 * Convert a VT_BOOL to a VT_DATE.
7323 *
7324 * PARAMS
7325 * boolIn [I] Source
7326 * pdateOut [O] Destination
7327 *
7328 * RETURNS
7329 * S_OK.
7330 */
7331 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7332 {
7333 return VarR8FromBool(boolIn, pdateOut);
7334 }
7335
7336 /**********************************************************************
7337 * VarDateFromCy (OLEAUT32.93)
7338 *
7339 * Convert a VT_CY to a VT_DATE.
7340 *
7341 * PARAMS
7342 * lIn [I] Source
7343 * pdateOut [O] Destination
7344 *
7345 * RETURNS
7346 * S_OK.
7347 */
7348 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7349 {
7350 return VarR8FromCy(cyIn, pdateOut);
7351 }
7352
7353 /* Date string parsing */
7354 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7355 #define DP_DATESEP 0x02 /* Date separator */
7356 #define DP_MONTH 0x04 /* Month name */
7357 #define DP_AM 0x08 /* AM */
7358 #define DP_PM 0x10 /* PM */
7359
7360 typedef struct tagDATEPARSE
7361 {
7362 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7363 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7364 DWORD dwFlags[6]; /* Flags for each field */
7365 DWORD dwValues[6]; /* Value of each field */
7366 } DATEPARSE;
7367
7368 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7369
7370 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7371
7372 /* Determine if a day is valid in a given month of a given year */
7373 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7374 {
7375 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7376
7377 if (day && month && month < 13)
7378 {
7379 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7380 return TRUE;
7381 }
7382 return FALSE;
7383 }
7384
7385 /* Possible orders for 3 numbers making up a date */
7386 #define ORDER_MDY 0x01
7387 #define ORDER_YMD 0x02
7388 #define ORDER_YDM 0x04
7389 #define ORDER_DMY 0x08
7390 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7391
7392 /* Determine a date for a particular locale, from 3 numbers */
7393 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7394 DWORD offset, SYSTEMTIME *st)
7395 {
7396 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7397
7398 if (!dp->dwCount)
7399 {
7400 v1 = 30; /* Default to (Variant) 0 date part */
7401 v2 = 12;
7402 v3 = 1899;
7403 goto VARIANT_MakeDate_OK;
7404 }
7405
7406 v1 = dp->dwValues[offset + 0];
7407 v2 = dp->dwValues[offset + 1];
7408 if (dp->dwCount == 2)
7409 {
7410 SYSTEMTIME current;
7411 GetSystemTime(&current);
7412 v3 = current.wYear;
7413 }
7414 else
7415 v3 = dp->dwValues[offset + 2];
7416
7417 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset);
7418
7419 /* If one number must be a month (Because a month name was given), then only
7420 * consider orders with the month in that position.
7421 * If we took the current year as 'v3', then only allow a year in that position.
7422 */
7423 if (dp->dwFlags[offset + 0] & DP_MONTH)
7424 {
7425 dwAllOrders = ORDER_MDY;
7426 }
7427 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7428 {
7429 dwAllOrders = ORDER_DMY;
7430 if (dp->dwCount > 2)
7431 dwAllOrders |= ORDER_YMD;
7432 }
7433 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7434 {
7435 dwAllOrders = ORDER_YDM;
7436 }
7437 else
7438 {
7439 dwAllOrders = ORDER_MDY|ORDER_DMY;
7440 if (dp->dwCount > 2)
7441 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7442 }
7443
7444 VARIANT_MakeDate_Start:
7445 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders);
7446
7447 while (dwAllOrders)
7448 {
7449 DWORD dwTemp;
7450
7451 if (dwCount == 0)
7452 {
7453 /* First: Try the order given by iDate */
7454 switch (iDate)
7455 {
7456 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7457 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7458 default: dwTry = dwAllOrders & ORDER_YMD; break;
7459 }
7460 }
7461 else if (dwCount == 1)
7462 {
7463 /* Second: Try all the orders compatible with iDate */
7464 switch (iDate)
7465 {
7466 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7467 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break;
7468 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7469 }
7470 }
7471 else
7472 {
7473 /* Finally: Try any remaining orders */
7474 dwTry = dwAllOrders;
7475 }
7476
7477 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry);
7478
7479 dwCount++;
7480 if (!dwTry)
7481 continue;
7482
7483 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7484
7485 if (dwTry & ORDER_MDY)
7486 {
7487 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7488 {
7489 DATE_SWAP(v1,v2);
7490 goto VARIANT_MakeDate_OK;
7491 }
7492 dwAllOrders &= ~ORDER_MDY;
7493 }
7494 if (dwTry & ORDER_YMD)
7495 {
7496 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7497 {
7498 DATE_SWAP(v1,v3);
7499 goto VARIANT_MakeDate_OK;
7500 }
7501 dwAllOrders &= ~ORDER_YMD;
7502 }
7503 if (dwTry & ORDER_YDM)
7504 {
7505 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7506 {
7507 DATE_SWAP(v1,v2);
7508 DATE_SWAP(v2,v3);
7509 goto VARIANT_MakeDate_OK;
7510 }
7511 dwAllOrders &= ~ORDER_YDM;
7512 }
7513 if (dwTry & ORDER_DMY)
7514 {
7515 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7516 goto VARIANT_MakeDate_OK;
7517 dwAllOrders &= ~ORDER_DMY;
7518 }
7519 if (dwTry & ORDER_MYD)
7520 {
7521 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7522 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7523 {
7524 DATE_SWAP(v1,v3);
7525 DATE_SWAP(v2,v3);
7526 goto VARIANT_MakeDate_OK;
7527 }
7528 dwAllOrders &= ~ORDER_MYD;
7529 }
7530 }
7531
7532 if (dp->dwCount == 2)
7533 {
7534 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7535 v3 = 1; /* 1st of the month */
7536 dwAllOrders = ORDER_YMD|ORDER_MYD;
7537 dp->dwCount = 0; /* Don't return to this code path again */
7538 dwCount = 0;
7539 goto VARIANT_MakeDate_Start;
7540 }
7541
7542 /* No valid dates were able to be constructed */
7543 return DISP_E_TYPEMISMATCH;
7544
7545 VARIANT_MakeDate_OK:
7546
7547 /* Check that the time part is ok */
7548 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7549 return DISP_E_TYPEMISMATCH;
7550
7551 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7552 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7553 st->wHour += 12;
7554 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7555 st->wHour = 0;
7556 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7557
7558 st->wDay = v1;
7559 st->wMonth = v2;
7560 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7561 * be retrieved from:
7562 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7563 * But Wine doesn't have/use that key as at the time of writing.
7564 */
7565 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7566 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear);
7567 return S_OK;
7568 }
7569
7570 /******************************************************************************
7571 * VarDateFromStr [OLEAUT32.94]
7572 *
7573 * Convert a VT_BSTR to at VT_DATE.
7574 *
7575 * PARAMS
7576 * strIn [I] String to convert
7577 * lcid [I] Locale identifier for the conversion
7578 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7579 * pdateOut [O] Destination for the converted value
7580 *
7581 * RETURNS
7582 * Success: S_OK. pdateOut contains the converted value.
7583 * FAILURE: An HRESULT error code indicating the problem.
7584 *
7585 * NOTES
7586 * Any date format that can be created using the date formats from lcid
7587 * (Either from kernel Nls functions, variant conversion or formatting) is a
7588 * valid input to this function. In addition, a few more esoteric formats are
7589 * also supported for compatibility with the native version. The date is
7590 * interpreted according to the date settings in the control panel, unless
7591 * the date is invalid in that format, in which the most compatible format
7592 * that produces a valid date will be used.
7593 */
7594 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7595 {
7596 static const USHORT ParseDateTokens[] =
7597 {
7598 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7599 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7600 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7601 LOCALE_SMONTHNAME13,
7602 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7603 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7604 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7605 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7606 LOCALE_SABBREVMONTHNAME13,
7607 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7608 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7609 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7610 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7611 LOCALE_SABBREVDAYNAME7,
7612 LOCALE_S1159, LOCALE_S2359,
7613 LOCALE_SDATE
7614 };
7615 static const BYTE ParseDateMonths[] =
7616 {
7617 1,2,3,4,5,6,7,8,9,10,11,12,13,
7618 1,2,3,4,5,6,7,8,9,10,11,12,13
7619 };
7620 unsigned int i;
7621 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7622 DATEPARSE dp;
7623 DWORD dwDateSeps = 0, iDate = 0;
7624 HRESULT hRet = S_OK;
7625
7626 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7627 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7628 return E_INVALIDARG;
7629
7630 if (!strIn)
7631 return DISP_E_TYPEMISMATCH;
7632
7633 *pdateOut = 0.0;
7634
7635 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7636
7637 memset(&dp, 0, sizeof(dp));
7638
7639 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7640 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7641 TRACE("iDate is %d\n", iDate);
7642
7643 /* Get the month/day/am/pm tokens for this locale */
7644 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7645 {
7646 WCHAR buff[128];
7647 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7648
7649 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7650 * GetAltMonthNames(). We should really cache these strings too.
7651 */
7652 buff[0] = '\0';
7653 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7654 tokens[i] = SysAllocString(buff);
7655 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7656 }
7657
7658 /* Parse the string into our structure */
7659 while (*strIn)
7660 {
7661 if (dp.dwCount >= 6)
7662 break;
7663
7664 if (isdigitW(*strIn))
7665 {
7666 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7667 dp.dwCount++;
7668 strIn--;
7669 }
7670 else if (isalpha(*strIn))
7671 {
7672 BOOL bFound = FALSE;
7673
7674 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7675 {
7676 DWORD dwLen = strlenW(tokens[i]);
7677 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7678 {
7679 if (i <= 25)
7680 {
7681 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7682 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7683 dp.dwCount++;
7684 }
7685 else if (i > 39 && i < 42)
7686 {
7687 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7688 hRet = DISP_E_TYPEMISMATCH;
7689 else
7690 {
7691 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7692 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7693 }
7694 }
7695 strIn += (dwLen - 1);
7696 bFound = TRUE;
7697 break;
7698 }
7699 }
7700
7701 if (!bFound)
7702 {
7703 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7704 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7705 {
7706 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7707 if (*strIn == 'a' || *strIn == 'A')
7708 {
7709 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7710 dp.dwParseFlags |= DP_AM;
7711 }
7712 else
7713 {
7714 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7715 dp.dwParseFlags |= DP_PM;
7716 }
7717 strIn++;
7718 }
7719 else
7720 {
7721 TRACE("No matching token for %s\n", debugstr_w(strIn));
7722 hRet = DISP_E_TYPEMISMATCH;
7723 break;
7724 }
7725 }
7726 }
7727 else if (*strIn == ':' || *strIn == '.')
7728 {
7729 if (!dp.dwCount || !strIn[1])
7730 hRet = DISP_E_TYPEMISMATCH;
7731 else
7732 if (tokens[42][0] == *strIn)
7733 {
7734 dwDateSeps++;
7735 if (dwDateSeps > 2)
7736 hRet = DISP_E_TYPEMISMATCH;
7737 else
7738 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7739 }
7740 else
7741 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7742 }
7743 else if (*strIn == '-' || *strIn == '/')
7744 {
7745 dwDateSeps++;
7746 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7747 hRet = DISP_E_TYPEMISMATCH;
7748 else
7749 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7750 }
7751 else if (*strIn == ',' || isspaceW(*strIn))
7752 {
7753 if (*strIn == ',' && !strIn[1])
7754 hRet = DISP_E_TYPEMISMATCH;
7755 }
7756 else
7757 {
7758 hRet = DISP_E_TYPEMISMATCH;
7759 }
7760 strIn++;
7761 }
7762
7763 if (!dp.dwCount || dp.dwCount > 6 ||
7764 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7765 hRet = DISP_E_TYPEMISMATCH;
7766
7767 if (SUCCEEDED(hRet))
7768 {
7769 SYSTEMTIME st;
7770 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7771
7772 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7773
7774 /* Figure out which numbers correspond to which fields.
7775 *
7776 * This switch statement works based on the fact that native interprets any
7777 * fields that are not joined with a time separator ('.' or ':') as date
7778 * fields. Thus we construct a value from 0-32 where each set bit indicates
7779 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7780 * For valid permutations, we set dwOffset to point to the first date field
7781 * and shorten dp.dwCount by the number of time fields found. The real
7782 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7783 * each date number must represent in the context of iDate.
7784 */
7785 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7786
7787 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7788 {
7789 case 0x1: /* TT TTDD TTDDD */
7790 if (dp.dwCount > 3 &&
7791 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7792 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7793 hRet = DISP_E_TYPEMISMATCH;
7794 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7795 hRet = DISP_E_TYPEMISMATCH;
7796 st.wHour = dp.dwValues[0];
7797 st.wMinute = dp.dwValues[1];
7798 dp.dwCount -= 2;
7799 dwOffset = 2;
7800 break;
7801
7802 case 0x3: /* TTT TTTDD TTTDDD */
7803 if (dp.dwCount > 4 &&
7804 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7805 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7806 hRet = DISP_E_TYPEMISMATCH;
7807 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7808 hRet = DISP_E_TYPEMISMATCH;
7809 st.wHour = dp.dwValues[0];
7810 st.wMinute = dp.dwValues[1];
7811 st.wSecond = dp.dwValues[2];
7812 dwOffset = 3;
7813 dp.dwCount -= 3;
7814 break;
7815
7816 case 0x4: /* DDTT */
7817 if (dp.dwCount != 4 ||
7818 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7819 hRet = DISP_E_TYPEMISMATCH;
7820
7821 st.wHour = dp.dwValues[2];
7822 st.wMinute = dp.dwValues[3];
7823 dp.dwCount -= 2;
7824 break;
7825
7826 case 0x0: /* T DD DDD TDDD TDDD */
7827 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7828 {
7829 st.wHour = dp.dwValues[0]; /* T */
7830 dp.dwCount = 0;
7831 break;
7832 }
7833 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7834 {
7835 hRet = DISP_E_TYPEMISMATCH;
7836 }
7837 else if (dp.dwCount == 3)
7838 {
7839 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7840 {
7841 dp.dwCount = 2;
7842 st.wHour = dp.dwValues[0];
7843 dwOffset = 1;
7844 break;
7845 }
7846 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7847 {
7848 dp.dwCount = 2;
7849 st.wHour = dp.dwValues[2];
7850 break;
7851 }
7852 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7853 hRet = DISP_E_TYPEMISMATCH;
7854 }
7855 else if (dp.dwCount == 4)
7856 {
7857 dp.dwCount = 3;
7858 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7859 {
7860 st.wHour = dp.dwValues[0];
7861 dwOffset = 1;
7862 }
7863 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7864 {
7865 st.wHour = dp.dwValues[3];
7866 }
7867 else
7868 hRet = DISP_E_TYPEMISMATCH;
7869 break;
7870 }
7871 /* .. fall through .. */
7872
7873 case 0x8: /* DDDTT */
7874 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7875 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7876 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7877 dp.dwCount == 4 || dp.dwCount == 6)
7878 hRet = DISP_E_TYPEMISMATCH;
7879 st.wHour = dp.dwValues[3];
7880 st.wMinute = dp.dwValues[4];
7881 if (dp.dwCount == 5)
7882 dp.dwCount -= 2;
7883 break;
7884
7885 case 0xC: /* DDTTT */
7886 if (dp.dwCount != 5 ||
7887 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7888 hRet = DISP_E_TYPEMISMATCH;
7889 st.wHour = dp.dwValues[2];
7890 st.wMinute = dp.dwValues[3];
7891 st.wSecond = dp.dwValues[4];
7892 dp.dwCount -= 3;
7893 break;
7894
7895 case 0x18: /* DDDTTT */
7896 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7897 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7898 hRet = DISP_E_TYPEMISMATCH;
7899 st.wHour = dp.dwValues[3];
7900 st.wMinute = dp.dwValues[4];
7901 st.wSecond = dp.dwValues[5];
7902 dp.dwCount -= 3;
7903 break;
7904
7905 default:
7906 hRet = DISP_E_TYPEMISMATCH;
7907 break;
7908 }
7909
7910 if (SUCCEEDED(hRet))
7911 {
7912 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7913
7914 if (dwFlags & VAR_TIMEVALUEONLY)
7915 {
7916 st.wYear = 1899;
7917 st.wMonth = 12;
7918 st.wDay = 30;
7919 }
7920 else if (dwFlags & VAR_DATEVALUEONLY)
7921 st.wHour = st.wMinute = st.wSecond = 0;
7922
7923 /* Finally, convert the value to a VT_DATE */
7924 if (SUCCEEDED(hRet))
7925 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7926 }
7927 }
7928
7929 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7930 SysFreeString(tokens[i]);
7931 return hRet;
7932 }
7933
7934 /******************************************************************************
7935 * VarDateFromI1 (OLEAUT32.221)
7936 *
7937 * Convert a VT_I1 to a VT_DATE.
7938 *
7939 * PARAMS
7940 * cIn [I] Source
7941 * pdateOut [O] Destination
7942 *
7943 * RETURNS
7944 * S_OK.
7945 */
7946 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7947 {
7948 return VarR8FromI1(cIn, pdateOut);
7949 }
7950
7951 /******************************************************************************
7952 * VarDateFromUI2 (OLEAUT32.222)
7953 *
7954 * Convert a VT_UI2 to a VT_DATE.
7955 *
7956 * PARAMS
7957 * uiIn [I] Source
7958 * pdateOut [O] Destination
7959 *
7960 * RETURNS
7961 * S_OK.
7962 */
7963 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7964 {
7965 return VarR8FromUI2(uiIn, pdateOut);
7966 }
7967
7968 /******************************************************************************
7969 * VarDateFromUI4 (OLEAUT32.223)
7970 *
7971 * Convert a VT_UI4 to a VT_DATE.
7972 *
7973 * PARAMS
7974 * ulIn [I] Source
7975 * pdateOut [O] Destination
7976 *
7977 * RETURNS
7978 * S_OK.
7979 */
7980 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7981 {
7982 return VarDateFromR8(ulIn, pdateOut);
7983 }
7984
7985 /**********************************************************************
7986 * VarDateFromDec (OLEAUT32.224)
7987 *
7988 * Convert a VT_DECIMAL to a VT_DATE.
7989 *
7990 * PARAMS
7991 * pdecIn [I] Source
7992 * pdateOut [O] Destination
7993 *
7994 * RETURNS
7995 * S_OK.
7996 */
7997 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
7998 {
7999 return VarR8FromDec(pdecIn, pdateOut);
8000 }
8001
8002 /******************************************************************************
8003 * VarDateFromI8 (OLEAUT32.364)
8004 *
8005 * Convert a VT_I8 to a VT_DATE.
8006 *
8007 * PARAMS
8008 * llIn [I] Source
8009 * pdateOut [O] Destination
8010 *
8011 * RETURNS
8012 * Success: S_OK.
8013 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8014 */
8015 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
8016 {
8017 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
8018 *pdateOut = (DATE)llIn;
8019 return S_OK;
8020 }
8021
8022 /******************************************************************************
8023 * VarDateFromUI8 (OLEAUT32.365)
8024 *
8025 * Convert a VT_UI8 to a VT_DATE.
8026 *
8027 * PARAMS
8028 * ullIn [I] Source
8029 * pdateOut [O] Destination
8030 *
8031 * RETURNS
8032 * Success: S_OK.
8033 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8034 */
8035 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
8036 {
8037 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
8038 *pdateOut = (DATE)ullIn;
8039 return S_OK;
8040 }