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