setupapi: Add an initial implementation of SetupGetInfInformation.
[wine] / dlls / mscms / profile.c
1 /*
2  * MSCMS - Color Management System for Wine
3  *
4  * Copyright 2004, 2005 Hans Leidekker
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/debug.h"
23
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "icm.h"
32
33 #include "mscms_priv.h"
34
35 #define IS_SEPARATOR(ch)  ((ch) == '\\' || (ch) == '/')
36
37 static void MSCMS_basename( LPCWSTR path, LPWSTR name )
38 {
39     INT i = lstrlenW( path );
40
41     while (i > 0 && !IS_SEPARATOR(path[i - 1])) i--;
42     lstrcpyW( name, &path[i] );
43 }
44
45 WINE_DEFAULT_DEBUG_CHANNEL(mscms);
46
47 /******************************************************************************
48  * GetColorDirectoryA               [MSCMS.@]
49  *
50  * See GetColorDirectoryW.
51  */
52 BOOL WINAPI GetColorDirectoryA( PCSTR machine, PSTR buffer, PDWORD size )
53 {
54     INT len;
55     LPWSTR bufferW;
56     BOOL ret = FALSE;
57     DWORD sizeW;
58
59     TRACE( "( %p, %p )\n", buffer, size );
60
61     if (machine || !size) return FALSE;
62
63     if (!buffer)
64     {
65         ret = GetColorDirectoryW( NULL, NULL, &sizeW );
66         *size = sizeW / sizeof(WCHAR);
67         return FALSE;
68     }
69
70     sizeW = *size * sizeof(WCHAR);
71
72     bufferW = HeapAlloc( GetProcessHeap(), 0, sizeW );
73
74     if (bufferW)
75     {
76         ret = GetColorDirectoryW( NULL, bufferW, &sizeW );
77         *size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
78
79         if (ret)
80         {
81             len = WideCharToMultiByte( CP_ACP, 0, bufferW, *size, buffer, *size, NULL, NULL );
82             if (!len) ret = FALSE;
83         }
84
85         HeapFree( GetProcessHeap(), 0, bufferW );
86     }
87     return ret;
88 }
89
90 /******************************************************************************
91  * GetColorDirectoryW               [MSCMS.@]
92  *
93  * Get the directory where color profiles are stored.
94  *
95  * PARAMS
96  *  machine  [I]   Name of the machine for which to get the color directory.
97  *                 Must be NULL, which indicates the local machine.
98  *  buffer   [I]   Buffer to receive the path name.
99  *  size     [I/O] Size of the buffer in bytes. On return the variable holds
100  *                 the number of bytes actually needed.
101  */
102 BOOL WINAPI GetColorDirectoryW( PCWSTR machine, PWSTR buffer, PDWORD size )
103 {
104     WCHAR colordir[MAX_PATH];
105     static const WCHAR colorsubdir[] = { '\\','c','o','l','o','r',0 };
106     DWORD len;
107
108     TRACE( "( %p, %p )\n", buffer, size );
109
110     if (machine || !size) return FALSE;
111
112     GetSystemDirectoryW( colordir, sizeof(colordir) / sizeof(WCHAR) );
113     lstrcatW( colordir, colorsubdir );
114
115     len = lstrlenW( colordir ) * sizeof(WCHAR);
116
117     if (len <= *size && buffer)
118     {
119         lstrcpyW( buffer, colordir );
120         *size = len;
121         return TRUE;
122     }
123
124     *size = len;
125     return FALSE;
126 }
127
128 /******************************************************************************
129  * GetColorProfileElement               [MSCMS.@]
130  *
131  * Retrieve data for a specified tag type.
132  *
133  * PARAMS
134  *  profile  [I]   Handle to a color profile.
135  *  type     [I]   ICC tag type. 
136  *  offset   [I]   Offset in bytes to start copying from. 
137  *  size     [I/O] Size of the buffer in bytes. On return the variable holds
138  *                 the number of bytes actually needed.
139  *  buffer   [O]   Buffer to receive the tag data.
140  *  ref      [O]   Pointer to a BOOL that specifies whether more than one tag
141  *                 references the data.
142  *
143  * RETURNS
144  *  Success: TRUE
145  *  Failure: FALSE
146  */
147 BOOL WINAPI GetColorProfileElement( HPROFILE profile, TAGTYPE type, DWORD offset, PDWORD size,
148                                     PVOID buffer, PBOOL ref )
149 {
150     BOOL ret = FALSE;
151 #ifdef HAVE_LCMS
152     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
153     DWORD i, count;
154     icTag tag;
155
156     TRACE( "( %p, 0x%08lx, %ld, %p, %p, %p )\n", profile, type, offset, size, buffer, ref );
157
158     if (!iccprofile || !size || !ref) return FALSE;
159     count = MSCMS_get_tag_count( iccprofile );
160
161     for (i = 0; i < count; i++)
162     {
163         MSCMS_get_tag_by_index( iccprofile, i, &tag );
164
165         if (tag.sig == type)
166         {
167             if ((tag.size - offset) > *size || !buffer)
168             {
169                 *size = (tag.size - offset);
170                 return FALSE;
171             }
172
173             MSCMS_get_tag_data( iccprofile, &tag, offset, buffer );
174
175             *ref = FALSE; /* FIXME: calculate properly */
176             return TRUE;
177         }
178     }
179
180 #endif /* HAVE_LCMS */
181     return ret;
182 }
183
184 /******************************************************************************
185  * GetColorProfileElementTag               [MSCMS.@]
186  *
187  * Get the tag type from a color profile by index. 
188  *
189  * PARAMS
190  *  profile  [I]   Handle to a color profile.
191  *  index    [I]   Index into the tag table of the color profile.
192  *  type     [O]   Pointer to a variable that holds the ICC tag type on return.
193  *
194  * RETURNS
195  *  Success: TRUE
196  *  Failure: FALSE
197  *
198  * NOTES
199  *  The tag table index starts at 1.
200  *  Use GetCountColorProfileElements to retrieve a count of tagged elements.
201  */
202 BOOL WINAPI GetColorProfileElementTag( HPROFILE profile, DWORD index, PTAGTYPE type )
203 {
204     BOOL ret = FALSE;
205 #ifdef HAVE_LCMS
206     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
207     DWORD count;
208     icTag tag;
209
210     TRACE( "( %p, %ld, %p )\n", profile, index, type );
211
212     if (!iccprofile || !type) return FALSE;
213
214     count = MSCMS_get_tag_count( iccprofile );
215     if (index > count || index < 1) return FALSE;
216
217     MSCMS_get_tag_by_index( iccprofile, index - 1, &tag );
218     *type = tag.sig;
219
220     ret = TRUE;
221
222 #endif /* HAVE_LCMS */
223     return ret;
224 }
225
226 /******************************************************************************
227  * GetColorProfileFromHandle               [MSCMS.@]
228  *
229  * Retrieve an ICC color profile by handle.
230  *
231  * PARAMS
232  *  profile  [I]   Handle to a color profile.
233  *  buffer   [O]   Buffer to receive the ICC profile.
234  *  size     [I/O] Size of the buffer in bytes. On return the variable holds the
235  *                 number of bytes actually needed.
236  *
237  * RETURNS
238  *  Success: TRUE
239  *  Failure: FALSE
240  *
241  * NOTES
242  *  The profile returned will be in big-endian format.
243  */
244 BOOL WINAPI GetColorProfileFromHandle( HPROFILE profile, PBYTE buffer, PDWORD size )
245 {
246     BOOL ret = FALSE;
247 #ifdef HAVE_LCMS
248     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
249     PROFILEHEADER header;
250
251     TRACE( "( %p, %p, %p )\n", profile, buffer, size );
252
253     if (!iccprofile || !size) return FALSE;
254     MSCMS_get_profile_header( iccprofile, &header );
255
256     if (!buffer || header.phSize > *size)
257     {
258         *size = header.phSize;
259         return FALSE;
260     }
261
262     /* No endian conversion needed */
263     memcpy( buffer, iccprofile, header.phSize );
264
265     *size = header.phSize;
266     ret = TRUE;
267
268 #endif /* HAVE_LCMS */
269     return ret;
270 }
271
272 /******************************************************************************
273  * GetColorProfileHeader               [MSCMS.@]
274  *
275  * Retrieve a color profile header by handle.
276  *
277  * PARAMS
278  *  profile  [I]   Handle to a color profile.
279  *  header   [O]   Buffer to receive the ICC profile header.
280  *
281  * RETURNS
282  *  Success: TRUE
283  *  Failure: FALSE
284  *
285  * NOTES
286  *  The profile header returned will be adjusted for endianess.
287  */
288 BOOL WINAPI GetColorProfileHeader( HPROFILE profile, PPROFILEHEADER header )
289 {
290     BOOL ret = FALSE;
291 #ifdef HAVE_LCMS
292     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
293
294     TRACE( "( %p, %p )\n", profile, header );
295
296     if (!iccprofile || !header) return FALSE;
297
298     MSCMS_get_profile_header( iccprofile, header );
299     return TRUE;
300
301 #endif /* HAVE_LCMS */
302     return ret;
303 }
304
305 /******************************************************************************
306  * GetCountColorProfileElements               [MSCMS.@]
307  *
308  * Retrieve the number of elements in a color profile.
309  *
310  * PARAMS
311  *  profile  [I] Handle to a color profile.
312  *  count    [O] Pointer to a variable which is set to the number of elements
313  *               in the color profile.
314  *
315  * RETURNS
316  *  Success: TRUE
317  *  Failure: FALSE
318  */
319 BOOL WINAPI GetCountColorProfileElements( HPROFILE profile, PDWORD count )
320 {
321     BOOL ret = FALSE;
322 #ifdef HAVE_LCMS
323     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
324
325     TRACE( "( %p, %p )\n", profile, count );
326
327     if (!iccprofile || !count) return FALSE;
328     *count = MSCMS_get_tag_count( iccprofile );
329     ret = TRUE;
330
331 #endif /* HAVE_LCMS */
332     return ret;
333 }
334
335 /******************************************************************************
336  * GetStandardColorSpaceProfileA               [MSCMS.@]
337  *
338  * See GetStandardColorSpaceProfileW.
339  */
340 BOOL WINAPI GetStandardColorSpaceProfileA( PCSTR machine, DWORD id, PSTR profile, PDWORD size )
341 {
342     INT len;
343     LPWSTR profileW;
344     BOOL ret = FALSE;
345     DWORD sizeW;
346
347     TRACE( "( 0x%08lx, %p, %p )\n", id, profile, size );
348
349     if (machine) 
350     {
351         SetLastError(ERROR_NOT_SUPPORTED);
352         return FALSE;
353     }
354
355     if (!size) 
356     {
357         SetLastError(ERROR_INSUFFICIENT_BUFFER);
358         return FALSE;
359     }
360
361     sizeW = *size * sizeof(WCHAR);
362
363     if (!profile)
364     {
365         ret = GetStandardColorSpaceProfileW( NULL, id, NULL, &sizeW );
366         *size = sizeW / sizeof(WCHAR);
367         return FALSE;
368     }
369
370     profileW = HeapAlloc( GetProcessHeap(), 0, sizeW );
371
372     if (profileW)
373     {
374         ret = GetStandardColorSpaceProfileW( NULL, id, profileW, &sizeW );
375         *size = WideCharToMultiByte( CP_ACP, 0, profileW, -1, NULL, 0, NULL, NULL );
376
377         if (ret)
378         {
379             len = WideCharToMultiByte( CP_ACP, 0, profileW, *size, profile, *size, NULL, NULL );
380             if (!len) ret = FALSE;
381         }
382
383         HeapFree( GetProcessHeap(), 0, profileW );
384     }
385     return ret;
386 }
387
388 /******************************************************************************
389  * GetStandardColorSpaceProfileW               [MSCMS.@]
390  *
391  * Retrieve the profile filename for a given standard color space id.
392  *
393  * PARAMS
394  *  machine  [I]   Name of the machine for which to get the standard color space.
395  *                 Must be NULL, which indicates the local machine.
396  *  id       [I]   Id of a standard color space.
397  *  profile  [O]   Buffer to receive the profile filename.
398  *  size     [I/O] Size of the filename buffer in bytes.
399  *
400  * RETURNS
401  *  Success: TRUE
402  *  Failure: FALSE
403  */
404 BOOL WINAPI GetStandardColorSpaceProfileW( PCWSTR machine, DWORD id, PWSTR profile, PDWORD size )
405 {
406     static const WCHAR rgbprofilefile[] =
407         { '\\','s','r','g','b',' ','c','o','l','o','r',' ',
408           's','p','a','c','e',' ','p','r','o','f','i','l','e','.','i','c','m',0 };
409     WCHAR rgbprofile[MAX_PATH];
410     DWORD len = sizeof(rgbprofile);
411
412     TRACE( "( 0x%08lx, %p, %p )\n", id, profile, size );
413
414     if (machine) 
415     {
416         SetLastError(ERROR_NOT_SUPPORTED);
417         return FALSE;
418     }
419
420     if (!size) 
421     {
422         SetLastError(ERROR_INSUFFICIENT_BUFFER);
423         return FALSE;
424     }
425
426     GetColorDirectoryW( machine, rgbprofile, &len );
427
428     switch (id)
429     {
430         case 0x52474220: /* 'RGB ' */
431             lstrcatW( rgbprofile, rgbprofilefile );
432             len = lstrlenW( rgbprofile ) * sizeof(WCHAR);
433
434             if (*size < len || !profile)
435             {
436                 *size = len;
437                 return TRUE;
438             }
439
440             lstrcpyW( profile, rgbprofile );
441             break;
442
443         default:
444             return FALSE;
445     }
446     return TRUE;
447 }
448
449 /******************************************************************************
450  * InstallColorProfileA               [MSCMS.@]
451  *
452  * See InstallColorProfileW.
453  */
454 BOOL WINAPI InstallColorProfileA( PCSTR machine, PCSTR profile )
455 {
456     UINT len;
457     LPWSTR profileW;
458     BOOL ret = FALSE;
459
460     TRACE( "( %s )\n", debugstr_a(profile) );
461
462     if (machine || !profile) return FALSE;
463
464     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
465     profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
466
467     if (profileW)
468     {
469         MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
470
471         ret = InstallColorProfileW( NULL, profileW );
472         HeapFree( GetProcessHeap(), 0, profileW );
473     }
474     return ret;
475 }
476
477 /******************************************************************************
478  * InstallColorProfileW               [MSCMS.@]
479  *
480  * Install a color profile.
481  *
482  * PARAMS
483  *  machine  [I] Name of the machine to install the profile on. Must be NULL,
484  *               which indicates the local machine.
485  *  profile  [I] Full path name of the profile to install.
486  *
487  * RETURNS
488  *  Success: TRUE
489  *  Failure: FALSE
490  */
491 BOOL WINAPI InstallColorProfileW( PCWSTR machine, PCWSTR profile )
492 {
493     WCHAR dest[MAX_PATH], base[MAX_PATH];
494     DWORD size = sizeof(dest);
495     static const WCHAR slash[] = { '\\', 0 };
496
497     TRACE( "( %s )\n", debugstr_w(profile) );
498
499     if (machine || !profile) return FALSE;
500
501     if (!GetColorDirectoryW( machine, dest, &size )) return FALSE;
502
503     MSCMS_basename( profile, base );
504
505     lstrcatW( dest, slash );
506     lstrcatW( dest, base );
507
508     /* Is source equal to destination? */
509     if (!lstrcmpW( profile, dest )) return TRUE;
510
511     return CopyFileW( profile, dest, TRUE );
512 }
513
514 /******************************************************************************
515  * IsColorProfileTagPresent               [MSCMS.@]
516  *
517  * Determine if a given ICC tag type is present in a color profile.
518  *
519  * PARAMS
520  *  profile  [I] Color profile handle.
521  *  tag      [I] ICC tag type.
522  *  present  [O] Pointer to a BOOL variable. Set to TRUE if tag type is present,
523  *               FALSE otherwise.
524  *
525  * RETURNS
526  *  Success: TRUE
527  *  Failure: FALSE
528  */
529 BOOL WINAPI IsColorProfileTagPresent( HPROFILE profile, TAGTYPE type, PBOOL present )
530 {
531     BOOL ret = FALSE;
532 #ifdef HAVE_LCMS
533     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
534     DWORD i, count;
535     icTag tag;
536
537     TRACE( "( %p, 0x%08lx, %p )\n", profile, type, present );
538
539     if (!iccprofile || !present) return FALSE;
540
541     count = MSCMS_get_tag_count( iccprofile );
542
543     for (i = 0; i < count; i++)
544     {
545         MSCMS_get_tag_by_index( iccprofile, i, &tag );
546
547         if (tag.sig == type)
548         {
549             *present = ret = TRUE;
550             break;
551         }
552     }
553
554 #endif /* HAVE_LCMS */
555     return ret;
556 }
557
558 /******************************************************************************
559  * IsColorProfileValid               [MSCMS.@]
560  *
561  * Determine if a given color profile is valid.
562  *
563  * PARAMS
564  *  profile  [I] Color profile handle.
565  *  valid    [O] Pointer to a BOOL variable. Set to TRUE if profile is valid,
566  *               FALSE otherwise.
567  *
568  * RETURNS
569  *  Success: TRUE
570  *  Failure: FALSE 
571  */
572 BOOL WINAPI IsColorProfileValid( HPROFILE profile, PBOOL valid )
573 {
574     BOOL ret = FALSE;
575 #ifdef HAVE_LCMS
576     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
577
578     TRACE( "( %p, %p )\n", profile, valid );
579
580     if (!valid) return FALSE;
581     if (iccprofile) return *valid = TRUE;
582
583 #endif /* HAVE_LCMS */
584     return ret;
585 }
586
587 /******************************************************************************
588  * SetColorProfileElement               [MSCMS.@]
589  *
590  * Set data for a specified tag type.
591  *
592  * PARAMS
593  *  profile  [I]   Handle to a color profile.
594  *  type     [I]   ICC tag type.
595  *  offset   [I]   Offset in bytes to start copying to.
596  *  size     [I/O] Size of the buffer in bytes. On return the variable holds the
597  *                 number of bytes actually needed.
598  *  buffer   [O]   Buffer holding the tag data.
599  *
600  * RETURNS
601  *  Success: TRUE
602  *  Failure: FALSE
603  */
604 BOOL WINAPI SetColorProfileElement( HPROFILE profile, TAGTYPE type, DWORD offset, PDWORD size,
605                                     PVOID buffer )
606 {
607     BOOL ret = FALSE;
608 #ifdef HAVE_LCMS
609     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
610     DWORD i, count, access = MSCMS_hprofile2access( profile );
611     icTag tag;
612
613     TRACE( "( %p, 0x%08lx, %ld, %p, %p )\n", profile, type, offset, size, buffer );
614
615     if (!iccprofile || !size || !buffer) return FALSE;
616     if (!(access & PROFILE_READWRITE)) return FALSE;
617
618     count = MSCMS_get_tag_count( iccprofile );
619
620     for (i = 0; i < count; i++)
621     {
622         MSCMS_get_tag_by_index( iccprofile, i, &tag );
623
624         if (tag.sig == type)
625         {
626             if (offset > tag.size) return FALSE;
627
628             MSCMS_set_tag_data( iccprofile, &tag, offset, buffer );
629             return TRUE;
630         }
631     }
632
633 #endif /* HAVE_LCMS */
634     return ret;
635 }
636
637 /******************************************************************************
638  * SetColorProfileHeader               [MSCMS.@]
639  *
640  * Set header data for a given profile.
641  *
642  * PARAMS
643  *  profile  [I] Handle to a color profile.
644  *  header   [I] Buffer holding the header data.
645  *
646  * RETURNS
647  *  Success: TRUE
648  *  Failure: FALSE
649  */
650 BOOL WINAPI SetColorProfileHeader( HPROFILE profile, PPROFILEHEADER header )
651 {
652     BOOL ret = FALSE;
653 #ifdef HAVE_LCMS
654     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
655     DWORD access = MSCMS_hprofile2access( profile );
656
657     TRACE( "( %p, %p )\n", profile, header );
658
659     if (!iccprofile || !header) return FALSE;
660     if (!(access & PROFILE_READWRITE)) return FALSE;
661
662     MSCMS_set_profile_header( iccprofile, header );
663     return TRUE;
664
665 #endif /* HAVE_LCMS */
666     return ret;
667 }
668
669 /******************************************************************************
670  * UninstallColorProfileA               [MSCMS.@]
671  *
672  * See UninstallColorProfileW.
673  */
674 BOOL WINAPI UninstallColorProfileA( PCSTR machine, PCSTR profile, BOOL delete )
675 {
676     UINT len;
677     LPWSTR profileW;
678     BOOL ret = FALSE;
679
680     TRACE( "( %s, %x )\n", debugstr_a(profile), delete );
681
682     if (machine || !profile) return FALSE;
683
684     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
685     profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
686
687     if (profileW)
688     {
689         MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
690
691         ret = UninstallColorProfileW( NULL, profileW , delete );
692
693         HeapFree( GetProcessHeap(), 0, profileW );
694     }
695     return ret;
696 }
697
698 /******************************************************************************
699  * UninstallColorProfileW               [MSCMS.@]
700  *
701  * Uninstall a color profile.
702  *
703  * PARAMS
704  *  machine  [I] Name of the machine to uninstall the profile on. Must be NULL,
705  *               which indicates the local machine.
706  *  profile  [I] Full path name of the profile to uninstall.
707  *  delete   [I] Bool that specifies whether the profile file should be deleted.
708  *
709  * RETURNS
710  *  Success: TRUE
711  *  Failure: FALSE
712  */
713 BOOL WINAPI UninstallColorProfileW( PCWSTR machine, PCWSTR profile, BOOL delete )
714 {
715     TRACE( "( %s, %x )\n", debugstr_w(profile), delete );
716
717     if (machine || !profile) return FALSE;
718
719     if (delete) return DeleteFileW( profile );
720
721     return TRUE;
722 }
723
724 /******************************************************************************
725  * OpenColorProfileA               [MSCMS.@]
726  *
727  * See OpenColorProfileW.
728  */
729 HPROFILE WINAPI OpenColorProfileA( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
730 {
731     HPROFILE handle = NULL;
732
733     TRACE( "( %p, 0x%08lx, 0x%08lx, 0x%08lx )\n", profile, access, sharing, creation );
734
735     if (!profile || !profile->pProfileData) return NULL;
736
737     /* No AW conversion needed for memory based profiles */
738     if (profile->dwType & PROFILE_MEMBUFFER)
739         return OpenColorProfileW( profile, access, sharing, creation );
740
741     if (profile->dwType & PROFILE_FILENAME)
742     {
743         UINT len;
744         PROFILE profileW;
745
746         profileW.dwType = profile->dwType;
747  
748         len = MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, NULL, 0 );
749         profileW.pProfileData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
750
751         if (profileW.pProfileData)
752         {
753             profileW.cbDataSize = len * sizeof(WCHAR);
754             MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, profileW.pProfileData, len );
755
756             handle = OpenColorProfileW( &profileW, access, sharing, creation );
757             HeapFree( GetProcessHeap(), 0, profileW.pProfileData );
758         }
759     }
760     return handle;
761 }
762
763 /******************************************************************************
764  * OpenColorProfileW               [MSCMS.@]
765  *
766  * Open a color profile.
767  *
768  * PARAMS
769  *  profile   [I] Pointer to a color profile structure.
770  *  access    [I] Desired access.
771  *  sharing   [I] Sharing mode.
772  *  creation  [I] Creation mode.
773  *
774  * RETURNS
775  *  Success: Handle to the opened profile.
776  *  Failure: NULL
777  *
778  * NOTES
779  *  Values for access:   PROFILE_READ or PROFILE_READWRITE.
780  *  Values for sharing:  0 (no sharing), FILE_SHARE_READ and/or FILE_SHARE_WRITE.
781  *  Values for creation: one of CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
782  *                       OPEN_ALWAYS, TRUNCATE_EXISTING.
783  *  Sharing and creation flags are ignored for memory based profiles.
784  */
785 HPROFILE WINAPI OpenColorProfileW( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
786 {
787 #ifdef HAVE_LCMS
788     cmsHPROFILE cmsprofile = NULL;
789     icProfile *iccprofile = NULL;
790     HANDLE handle = NULL;
791     DWORD size;
792
793     TRACE( "( %p, 0x%08lx, 0x%08lx, 0x%08lx )\n", profile, access, sharing, creation );
794
795     if (!profile || !profile->pProfileData) return NULL;
796
797     if (profile->dwType & PROFILE_MEMBUFFER)
798     {
799         /* FIXME: access flags not implemented for memory based profiles */
800
801         iccprofile = profile->pProfileData;
802         size = profile->cbDataSize;
803     
804         cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
805     }
806
807     if (profile->dwType & PROFILE_FILENAME)
808     {
809         DWORD read, flags = 0;
810
811         TRACE( "profile file: %s\n", debugstr_w( (WCHAR *)profile->pProfileData ) );
812
813         if (access & PROFILE_READ) flags = GENERIC_READ;
814         if (access & PROFILE_READWRITE) flags = GENERIC_READ|GENERIC_WRITE;
815
816         if (!flags) return NULL;
817
818         handle = CreateFileW( profile->pProfileData, flags, sharing, NULL, creation, 0, NULL );
819         if (handle == INVALID_HANDLE_VALUE)
820         {
821             WARN( "Unable to open color profile\n" );
822             return NULL;
823         }
824
825         if ((size = GetFileSize( handle, NULL )) == INVALID_FILE_SIZE)
826         {
827             ERR( "Unable to retrieve size of color profile\n" );
828             CloseHandle( handle );
829             return NULL;
830         }
831
832         iccprofile = HeapAlloc( GetProcessHeap(), 0, size );
833         if (!iccprofile)
834         {
835             ERR( "Unable to allocate memory for color profile\n" );
836             CloseHandle( handle );
837             return NULL;
838         }
839
840         if (!ReadFile( handle, iccprofile, size, &read, NULL ) || read != size)
841         {
842             ERR( "Unable to read color profile\n" );
843
844             CloseHandle( handle );
845             HeapFree( GetProcessHeap, 0, iccprofile );
846             return NULL;
847         }
848
849         cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
850     }
851
852     if (cmsprofile)
853         return MSCMS_create_hprofile_handle( handle, iccprofile, cmsprofile, access );
854
855 #endif /* HAVE_LCMS */
856     return NULL;
857 }
858
859 /******************************************************************************
860  * CloseColorProfile               [MSCMS.@]
861  *
862  * Close a color profile.
863  *
864  * PARAMS
865  *  profile  [I] Handle to the profile.
866  *
867  * RETURNS
868  *  Success: TRUE
869  *  Failure: FALSE
870  */
871 BOOL WINAPI CloseColorProfile( HPROFILE profile )
872 {
873     BOOL ret = FALSE;
874 #ifdef HAVE_LCMS
875     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
876     HANDLE file = MSCMS_hprofile2handle( profile );
877     DWORD access = MSCMS_hprofile2access( profile );
878
879     TRACE( "( %p )\n", profile );
880
881     if (file && (access & PROFILE_READWRITE))
882     {
883         DWORD written, size = MSCMS_get_profile_size( iccprofile );
884
885         if (SetFilePointer( file, 0, NULL, FILE_BEGIN ) ||
886             !WriteFile( file, iccprofile, size, &written, NULL ) || written != size)
887             ERR( "Unable to write color profile\n" );
888     }
889
890     ret = cmsCloseProfile( MSCMS_hprofile2cmsprofile( profile ) );
891     HeapFree( GetProcessHeap(), 0, MSCMS_hprofile2iccprofile( profile ) );
892
893     CloseHandle( MSCMS_hprofile2handle( profile ) );
894     MSCMS_destroy_hprofile_handle( profile );
895
896 #endif /* HAVE_LCMS */
897     return ret;
898 }