kernel32: Use double-fork to avoid leaving zombie processes.
[wine] / dlls / mscms / profile.c
1 /*
2  * MSCMS - Color Management System for Wine
3  *
4  * Copyright 2004, 2005, 2006, 2008 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/debug.h"
23 #include "wine/unicode.h"
24
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winnls.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winreg.h"
33 #include "shlwapi.h"
34 #include "icm.h"
35
36 #include "mscms_priv.h"
37
38 #define IS_SEPARATOR(ch)  ((ch) == '\\' || (ch) == '/')
39
40 static void MSCMS_basename( LPCWSTR path, LPWSTR name )
41 {
42     INT i = lstrlenW( path );
43
44     while (i > 0 && !IS_SEPARATOR(path[i - 1])) i--;
45     lstrcpyW( name, &path[i] );
46 }
47
48 static inline LPWSTR MSCMS_strdupW( LPCSTR str )
49 {
50     LPWSTR ret = NULL;
51     if (str)
52     {
53         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
54         if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
55             MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
56     }
57     return ret;
58 }
59
60 const char *MSCMS_dbgstr_tag( DWORD tag )
61 {
62     return wine_dbg_sprintf( "'%c%c%c%c'",
63         (char)(tag >> 24), (char)(tag >> 16), (char)(tag >> 8), (char)(tag) );
64 }
65
66 WINE_DEFAULT_DEBUG_CHANNEL(mscms);
67
68 /******************************************************************************
69  * AssociateColorProfileWithDeviceA               [MSCMS.@]
70  */
71 BOOL WINAPI AssociateColorProfileWithDeviceA( PCSTR machine, PCSTR profile, PCSTR device )
72 {
73     int len;
74     BOOL ret = FALSE;
75     WCHAR *profileW, *deviceW;
76
77     TRACE( "( %s, %s, %s )\n", debugstr_a(machine), debugstr_a(profile), debugstr_a(device) );
78
79     if (!profile || !device)
80     {
81         SetLastError( ERROR_INVALID_PARAMETER );
82         return FALSE;
83     }
84     if (machine)
85     {
86         SetLastError( ERROR_NOT_SUPPORTED );
87         return FALSE;
88     }
89
90     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
91     if (!(profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
92
93     MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
94
95     len = MultiByteToWideChar( CP_ACP, 0, device, -1, NULL, 0 );
96     if ((deviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
97     {
98         MultiByteToWideChar( CP_ACP, 0, device, -1, deviceW, len );
99         ret = AssociateColorProfileWithDeviceW( NULL, profileW, deviceW );
100     }
101
102     HeapFree( GetProcessHeap(), 0, profileW );
103     HeapFree( GetProcessHeap(), 0, deviceW );
104     return ret;
105 }
106
107 static BOOL set_profile_device_key( PCWSTR file, const BYTE *value, DWORD size )
108 {
109     static const WCHAR fmtW[] = {'%','c','%','c','%','c','%','c',0};
110     static const WCHAR icmW[] = {'S','o','f','t','w','a','r','e','\\',
111                                  'M','i','c','r','o','s','o','f','t','\\',
112                                  'W','i','n','d','o','w','s',' ','N','T','\\',
113                                  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
114                                  'I','C','M',0};
115     PROFILEHEADER header;
116     PROFILE profile;
117     HPROFILE handle;
118     HKEY icm_key, class_key;
119     WCHAR basenameW[MAX_PATH], classW[5];
120
121     profile.dwType = PROFILE_FILENAME;
122     profile.pProfileData = (PVOID)file;
123     profile.cbDataSize = (lstrlenW( file ) + 1) * sizeof(WCHAR);
124
125     /* FIXME is the profile installed? */
126     if (!(handle = OpenColorProfileW( &profile, PROFILE_READ, 0, OPEN_EXISTING )))
127     {
128         SetLastError( ERROR_INVALID_PROFILE );
129         return FALSE;
130     }
131     if (!GetColorProfileHeader( handle, &header ))
132     {
133         CloseColorProfile( handle );
134         SetLastError( ERROR_INVALID_PROFILE );
135         return FALSE;
136     }
137     RegCreateKeyExW( HKEY_LOCAL_MACHINE, icmW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &icm_key, NULL );
138
139     MSCMS_basename( file, basenameW );
140     sprintfW( classW, fmtW, (header.phClass >> 24) & 0xff, (header.phClass >> 16) & 0xff,
141                             (header.phClass >> 8) & 0xff,  header.phClass & 0xff );
142
143     RegCreateKeyExW( icm_key, classW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &class_key, NULL );
144     if (value) RegSetValueExW( class_key, basenameW, 0, REG_BINARY, value, size );
145     else RegDeleteValueW( class_key, basenameW );
146
147     RegCloseKey( class_key );
148     RegCloseKey( icm_key );
149     CloseColorProfile( handle );
150     return TRUE;
151 }
152
153 /******************************************************************************
154  * AssociateColorProfileWithDeviceW               [MSCMS.@]
155  */
156 BOOL WINAPI AssociateColorProfileWithDeviceW( PCWSTR machine, PCWSTR profile, PCWSTR device )
157 {
158     static const BYTE dummy_value[12];
159
160     TRACE( "( %s, %s, %s )\n", debugstr_w(machine), debugstr_w(profile), debugstr_w(device) );
161
162     if (!profile || !device)
163     {
164         SetLastError( ERROR_INVALID_PARAMETER );
165         return FALSE;
166     }
167     if (machine)
168     {
169         SetLastError( ERROR_NOT_SUPPORTED );
170         return FALSE;
171     }
172
173     return set_profile_device_key( profile, dummy_value, sizeof(dummy_value) );
174 }
175
176 /******************************************************************************
177  * DisassociateColorProfileFromDeviceA            [MSCMS.@]
178  */
179 BOOL WINAPI DisassociateColorProfileFromDeviceA( PCSTR machine, PCSTR profile, PCSTR device )
180 {
181     int len;
182     BOOL ret = FALSE;
183     WCHAR *profileW, *deviceW;
184
185     TRACE( "( %s, %s, %s )\n", debugstr_a(machine), debugstr_a(profile), debugstr_a(device) );
186
187     if (!profile || !device)
188     {
189         SetLastError( ERROR_INVALID_PARAMETER );
190         return FALSE;
191     }
192     if (machine)
193     {
194         SetLastError( ERROR_NOT_SUPPORTED );
195         return FALSE;
196     }
197
198     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
199     if (!(profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
200
201     MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
202
203     len = MultiByteToWideChar( CP_ACP, 0, device, -1, NULL, 0 );
204     if ((deviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
205     {
206         MultiByteToWideChar( CP_ACP, 0, device, -1, deviceW, len );
207         ret = DisassociateColorProfileFromDeviceW( NULL, profileW, deviceW );
208     }
209
210     HeapFree( GetProcessHeap(), 0, profileW );
211     HeapFree( GetProcessHeap(), 0, deviceW );
212     return ret;
213 }
214
215 /******************************************************************************
216  * DisassociateColorProfileFromDeviceW            [MSCMS.@]
217  */
218 BOOL WINAPI DisassociateColorProfileFromDeviceW( PCWSTR machine, PCWSTR profile, PCWSTR device )
219 {
220     TRACE( "( %s, %s, %s )\n", debugstr_w(machine), debugstr_w(profile), debugstr_w(device) );
221
222     if (!profile || !device)
223     {
224         SetLastError( ERROR_INVALID_PARAMETER );
225         return FALSE;
226     }
227     if (machine)
228     {
229         SetLastError( ERROR_NOT_SUPPORTED );
230         return FALSE;
231     }
232
233     return set_profile_device_key( profile, NULL, 0 );
234 }
235
236 /******************************************************************************
237  * GetColorDirectoryA               [MSCMS.@]
238  *
239  * See GetColorDirectoryW.
240  */
241 BOOL WINAPI GetColorDirectoryA( PCSTR machine, PSTR buffer, PDWORD size )
242 {
243     INT len;
244     LPWSTR bufferW;
245     BOOL ret = FALSE;
246     DWORD sizeW;
247
248     TRACE( "( %p, %p )\n", buffer, size );
249
250     if (machine || !size) return FALSE;
251
252     if (!buffer)
253     {
254         ret = GetColorDirectoryW( NULL, NULL, &sizeW );
255         *size = sizeW / sizeof(WCHAR);
256         return FALSE;
257     }
258
259     sizeW = *size * sizeof(WCHAR);
260
261     bufferW = HeapAlloc( GetProcessHeap(), 0, sizeW );
262
263     if (bufferW)
264     {
265         if ((ret = GetColorDirectoryW( NULL, bufferW, &sizeW )))
266         {
267             *size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
268             len = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, *size, NULL, NULL );
269             if (!len) ret = FALSE;
270         }
271         else *size = sizeW / sizeof(WCHAR);
272
273         HeapFree( GetProcessHeap(), 0, bufferW );
274     }
275     return ret;
276 }
277
278 /******************************************************************************
279  * GetColorDirectoryW               [MSCMS.@]
280  *
281  * Get the directory where color profiles are stored.
282  *
283  * PARAMS
284  *  machine  [I]   Name of the machine for which to get the color directory.
285  *                 Must be NULL, which indicates the local machine.
286  *  buffer   [I]   Buffer to receive the path name.
287  *  size     [I/O] Size of the buffer in bytes. On return the variable holds
288  *                 the number of bytes actually needed.
289  */
290 BOOL WINAPI GetColorDirectoryW( PCWSTR machine, PWSTR buffer, PDWORD size )
291 {
292     WCHAR colordir[MAX_PATH];
293     static const WCHAR colorsubdir[] =
294         {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\','c','o','l','o','r',0};
295     DWORD len;
296
297     TRACE( "( %p, %p )\n", buffer, size );
298
299     if (machine || !size) return FALSE;
300
301     GetSystemDirectoryW( colordir, sizeof(colordir) / sizeof(WCHAR) );
302     lstrcatW( colordir, colorsubdir );
303
304     len = lstrlenW( colordir ) * sizeof(WCHAR);
305
306     if (buffer && len <= *size)
307     {
308         lstrcpyW( buffer, colordir );
309         *size = len;
310         return TRUE;
311     }
312
313     SetLastError( ERROR_MORE_DATA );
314     *size = len;
315     return FALSE;
316 }
317
318 /******************************************************************************
319  * GetColorProfileElement               [MSCMS.@]
320  *
321  * Retrieve data for a specified tag type.
322  *
323  * PARAMS
324  *  profile  [I]   Handle to a color profile.
325  *  type     [I]   ICC tag type. 
326  *  offset   [I]   Offset in bytes to start copying from. 
327  *  size     [I/O] Size of the buffer in bytes. On return the variable holds
328  *                 the number of bytes actually needed.
329  *  buffer   [O]   Buffer to receive the tag data.
330  *  ref      [O]   Pointer to a BOOL that specifies whether more than one tag
331  *                 references the data.
332  *
333  * RETURNS
334  *  Success: TRUE
335  *  Failure: FALSE
336  */
337 BOOL WINAPI GetColorProfileElement( HPROFILE handle, TAGTYPE type, DWORD offset, PDWORD size,
338                                     PVOID buffer, PBOOL ref )
339 {
340     BOOL ret = FALSE;
341 #ifdef HAVE_LCMS
342     struct profile *profile = grab_profile( handle );
343     DWORD i, count;
344     icTag tag;
345
346     TRACE( "( %p, 0x%08x, %d, %p, %p, %p )\n", handle, type, offset, size, buffer, ref );
347
348     if (!profile) return FALSE;
349
350     if (!size || !ref)
351     {
352         release_profile( profile );
353         return FALSE;
354     }
355     count = MSCMS_get_tag_count( profile->iccprofile );
356
357     for (i = 0; i < count; i++)
358     {
359         MSCMS_get_tag_by_index( profile->iccprofile, i, &tag );
360
361         if (tag.sig == type)
362         {
363             if ((tag.size - offset) > *size || !buffer)
364             {
365                 *size = (tag.size - offset);
366                 release_profile( profile );
367                 return FALSE;
368             }
369             MSCMS_get_tag_data( profile->iccprofile, &tag, offset, buffer );
370
371             *ref = FALSE; /* FIXME: calculate properly */
372             release_profile( profile );
373             return TRUE;
374         }
375     }
376     release_profile( profile );
377
378 #endif /* HAVE_LCMS */
379     return ret;
380 }
381
382 /******************************************************************************
383  * GetColorProfileElementTag               [MSCMS.@]
384  *
385  * Get the tag type from a color profile by index. 
386  *
387  * PARAMS
388  *  profile  [I]   Handle to a color profile.
389  *  index    [I]   Index into the tag table of the color profile.
390  *  type     [O]   Pointer to a variable that holds the ICC tag type on return.
391  *
392  * RETURNS
393  *  Success: TRUE
394  *  Failure: FALSE
395  *
396  * NOTES
397  *  The tag table index starts at 1.
398  *  Use GetCountColorProfileElements to retrieve a count of tagged elements.
399  */
400 BOOL WINAPI GetColorProfileElementTag( HPROFILE handle, DWORD index, PTAGTYPE type )
401 {
402     BOOL ret = FALSE;
403 #ifdef HAVE_LCMS
404     struct profile *profile = grab_profile( handle );
405     DWORD count;
406     icTag tag;
407
408     TRACE( "( %p, %d, %p )\n", handle, index, type );
409
410     if (!profile) return FALSE;
411
412     if (!type)
413     {
414         release_profile( profile );
415         return FALSE;
416     }
417     count = MSCMS_get_tag_count( profile->iccprofile );
418     if (index > count || index < 1)
419     {
420         release_profile( profile );
421         return FALSE;
422     }
423     MSCMS_get_tag_by_index( profile->iccprofile, index - 1, &tag );
424     *type = tag.sig;
425
426     release_profile( profile );
427     ret = TRUE;
428
429 #endif /* HAVE_LCMS */
430     return ret;
431 }
432
433 /******************************************************************************
434  * GetColorProfileFromHandle               [MSCMS.@]
435  *
436  * Retrieve an ICC color profile by handle.
437  *
438  * PARAMS
439  *  profile  [I]   Handle to a color profile.
440  *  buffer   [O]   Buffer to receive the ICC profile.
441  *  size     [I/O] Size of the buffer in bytes. On return the variable holds the
442  *                 number of bytes actually needed.
443  *
444  * RETURNS
445  *  Success: TRUE
446  *  Failure: FALSE
447  *
448  * NOTES
449  *  The profile returned will be in big-endian format.
450  */
451 BOOL WINAPI GetColorProfileFromHandle( HPROFILE handle, PBYTE buffer, PDWORD size )
452 {
453     BOOL ret = FALSE;
454 #ifdef HAVE_LCMS
455     struct profile *profile = grab_profile( handle );
456     PROFILEHEADER header;
457
458     TRACE( "( %p, %p, %p )\n", handle, buffer, size );
459
460     if (!profile) return FALSE;
461
462     if (!size)
463     {
464         release_profile( profile );
465         return FALSE;
466     }
467     MSCMS_get_profile_header( profile->iccprofile, &header );
468
469     if (!buffer || header.phSize > *size)
470     {
471         *size = header.phSize;
472         release_profile( profile );
473         return FALSE;
474     }
475
476     /* No endian conversion needed */
477     memcpy( buffer, profile->iccprofile, header.phSize );
478     *size = header.phSize;
479
480     release_profile( profile );
481     ret = TRUE;
482
483 #endif /* HAVE_LCMS */
484     return ret;
485 }
486
487 /******************************************************************************
488  * GetColorProfileHeader               [MSCMS.@]
489  *
490  * Retrieve a color profile header by handle.
491  *
492  * PARAMS
493  *  profile  [I]   Handle to a color profile.
494  *  header   [O]   Buffer to receive the ICC profile header.
495  *
496  * RETURNS
497  *  Success: TRUE
498  *  Failure: FALSE
499  *
500  * NOTES
501  *  The profile header returned will be adjusted for endianness.
502  */
503 BOOL WINAPI GetColorProfileHeader( HPROFILE handle, PPROFILEHEADER header )
504 {
505 #ifdef HAVE_LCMS
506     struct profile *profile = grab_profile( handle );
507
508     TRACE( "( %p, %p )\n", handle, header );
509
510     if (!profile) return FALSE;
511
512     if (!header)
513     {
514         release_profile( profile );
515         return FALSE;
516     }
517     MSCMS_get_profile_header( profile->iccprofile, header );
518
519     release_profile( profile );
520     return TRUE;
521
522 #else
523     return FALSE;
524 #endif /* HAVE_LCMS */
525 }
526
527 /******************************************************************************
528  * GetCountColorProfileElements               [MSCMS.@]
529  *
530  * Retrieve the number of elements in a color profile.
531  *
532  * PARAMS
533  *  profile  [I] Handle to a color profile.
534  *  count    [O] Pointer to a variable which is set to the number of elements
535  *               in the color profile.
536  *
537  * RETURNS
538  *  Success: TRUE
539  *  Failure: FALSE
540  */
541 BOOL WINAPI GetCountColorProfileElements( HPROFILE handle, PDWORD count )
542 {
543     BOOL ret = FALSE;
544 #ifdef HAVE_LCMS
545     struct profile *profile = grab_profile( handle );
546
547     TRACE( "( %p, %p )\n", handle, count );
548
549     if (!profile) return FALSE;
550
551     if (!count)
552     {
553         release_profile( profile );
554         return FALSE;
555     }
556     *count = MSCMS_get_tag_count( profile->iccprofile );
557
558     release_profile( profile );
559     ret = TRUE;
560
561 #endif /* HAVE_LCMS */
562     return ret;
563 }
564
565 /******************************************************************************
566  * GetStandardColorSpaceProfileA               [MSCMS.@]
567  *
568  * See GetStandardColorSpaceProfileW.
569  */
570 BOOL WINAPI GetStandardColorSpaceProfileA( PCSTR machine, DWORD id, PSTR profile, PDWORD size )
571 {
572     INT len;
573     LPWSTR profileW;
574     BOOL ret = FALSE;
575     DWORD sizeW;
576
577     TRACE( "( 0x%08x, %p, %p )\n", id, profile, size );
578
579     if (machine) 
580     {
581         SetLastError( ERROR_NOT_SUPPORTED );
582         return FALSE;
583     }
584
585     if (!size) 
586     {
587         SetLastError( ERROR_INVALID_PARAMETER );
588         return FALSE;
589     }
590
591     sizeW = *size * sizeof(WCHAR);
592
593     if (!profile)
594     {
595         ret = GetStandardColorSpaceProfileW( NULL, id, NULL, &sizeW );
596         *size = sizeW / sizeof(WCHAR);
597         return FALSE;
598     }
599
600     profileW = HeapAlloc( GetProcessHeap(), 0, sizeW );
601
602     if (profileW)
603     {
604         if ((ret = GetStandardColorSpaceProfileW( NULL, id, profileW, &sizeW )))
605         {
606             *size = WideCharToMultiByte( CP_ACP, 0, profileW, -1, NULL, 0, NULL, NULL );
607             len = WideCharToMultiByte( CP_ACP, 0, profileW, -1, profile, *size, NULL, NULL );
608             if (!len) ret = FALSE;
609         }
610         else *size = sizeW / sizeof(WCHAR);
611
612         HeapFree( GetProcessHeap(), 0, profileW );
613     }
614     return ret;
615 }
616
617 /******************************************************************************
618  * GetStandardColorSpaceProfileW               [MSCMS.@]
619  *
620  * Retrieve the profile filename for a given standard color space id.
621  *
622  * PARAMS
623  *  machine  [I]   Name of the machine for which to get the standard color space.
624  *                 Must be NULL, which indicates the local machine.
625  *  id       [I]   Id of a standard color space.
626  *  profile  [O]   Buffer to receive the profile filename.
627  *  size     [I/O] Size of the filename buffer in bytes.
628  *
629  * RETURNS
630  *  Success: TRUE
631  *  Failure: FALSE
632  */
633 BOOL WINAPI GetStandardColorSpaceProfileW( PCWSTR machine, DWORD id, PWSTR profile, PDWORD size )
634 {
635     static const WCHAR rgbprofilefile[] =
636         { '\\','s','r','g','b',' ','c','o','l','o','r',' ',
637           's','p','a','c','e',' ','p','r','o','f','i','l','e','.','i','c','m',0 };
638     WCHAR rgbprofile[MAX_PATH];
639     DWORD len = sizeof(rgbprofile);
640
641     TRACE( "( 0x%08x, %p, %p )\n", id, profile, size );
642
643     if (machine) 
644     {
645         SetLastError( ERROR_NOT_SUPPORTED );
646         return FALSE;
647     }
648
649     if (!size) 
650     {
651         SetLastError( ERROR_INVALID_PARAMETER );
652         return FALSE;
653     }
654
655     if (!profile)
656     {
657         SetLastError( ERROR_INSUFFICIENT_BUFFER );
658         return FALSE;
659     }
660
661     GetColorDirectoryW( machine, rgbprofile, &len );
662
663     switch (id)
664     {
665         case LCS_sRGB:
666         case LCS_WINDOWS_COLOR_SPACE: /* FIXME */
667             lstrcatW( rgbprofile, rgbprofilefile );
668             len = lstrlenW( rgbprofile ) * sizeof(WCHAR);
669
670             if (*size < len || !profile)
671             {
672                 *size = len;
673                 SetLastError( ERROR_MORE_DATA );
674                 return FALSE;
675             }
676
677             lstrcpyW( profile, rgbprofile );
678             break;
679
680         default:
681             SetLastError( ERROR_FILE_NOT_FOUND );
682             return FALSE;
683     }
684     return TRUE;
685 }
686
687 static BOOL MSCMS_header_from_file( LPCWSTR file, PPROFILEHEADER header )
688 {
689     BOOL ret;
690     PROFILE profile;
691     WCHAR path[MAX_PATH], slash[] = {'\\',0};
692     DWORD size = sizeof(path);
693     HANDLE handle;
694
695     ret = GetColorDirectoryW( NULL, path, &size );
696     if (!ret)
697     {
698         WARN( "Can't retrieve color directory\n" );
699         return FALSE;
700     }
701     if (size + sizeof(slash) + sizeof(WCHAR) * lstrlenW( file ) > sizeof(path))
702     {
703         WARN( "Filename too long\n" );
704         return FALSE;
705     }
706
707     lstrcatW( path, slash );
708     lstrcatW( path, file );
709
710     profile.dwType = PROFILE_FILENAME;
711     profile.pProfileData = path;
712     profile.cbDataSize = lstrlenW( path ) + 1;
713
714     handle = OpenColorProfileW( &profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING );
715     if (!handle)
716     {
717         WARN( "Can't open color profile\n" );
718         return FALSE;
719     }
720
721     ret = GetColorProfileHeader( handle, header );
722     if (!ret)
723         WARN( "Can't retrieve color profile header\n" );
724
725     CloseColorProfile( handle );
726     return ret;
727 }
728
729 static BOOL MSCMS_match_profile( PENUMTYPEW rec, PPROFILEHEADER hdr )
730 {
731     if (rec->dwFields & ET_DEVICENAME)
732     {
733         FIXME( "ET_DEVICENAME: %s\n", debugstr_w(rec->pDeviceName) );
734     }
735     if (rec->dwFields & ET_MEDIATYPE)
736     {
737         FIXME( "ET_MEDIATYPE: 0x%08x\n", rec->dwMediaType );
738     }
739     if (rec->dwFields & ET_DITHERMODE)
740     {
741         FIXME( "ET_DITHERMODE: 0x%08x\n", rec->dwDitheringMode );
742     }
743     if (rec->dwFields & ET_RESOLUTION)
744     {
745         FIXME( "ET_RESOLUTION: 0x%08x, 0x%08x\n",
746                rec->dwResolution[0], rec->dwResolution[1] );
747     }
748     if (rec->dwFields & ET_DEVICECLASS)
749     {
750         FIXME( "ET_DEVICECLASS: %s\n", MSCMS_dbgstr_tag(rec->dwMediaType) );
751     }
752     if (rec->dwFields & ET_CMMTYPE)
753     {
754         TRACE( "ET_CMMTYPE: %s\n", MSCMS_dbgstr_tag(rec->dwCMMType) );
755         if (rec->dwCMMType != hdr->phCMMType) return FALSE;
756     }
757     if (rec->dwFields & ET_CLASS)
758     {
759         TRACE( "ET_CLASS: %s\n", MSCMS_dbgstr_tag(rec->dwClass) );
760         if (rec->dwClass != hdr->phClass) return FALSE;
761     }
762     if (rec->dwFields & ET_DATACOLORSPACE)
763     {
764         TRACE( "ET_DATACOLORSPACE: %s\n", MSCMS_dbgstr_tag(rec->dwDataColorSpace) );
765         if (rec->dwDataColorSpace != hdr->phDataColorSpace) return FALSE;
766     }
767     if (rec->dwFields & ET_CONNECTIONSPACE)
768     {
769         TRACE( "ET_CONNECTIONSPACE: %s\n", MSCMS_dbgstr_tag(rec->dwConnectionSpace) );
770         if (rec->dwConnectionSpace != hdr->phConnectionSpace) return FALSE;
771     }
772     if (rec->dwFields & ET_SIGNATURE)
773     {
774         TRACE( "ET_SIGNATURE: %s\n", MSCMS_dbgstr_tag(rec->dwSignature) );
775         if (rec->dwSignature != hdr->phSignature) return FALSE;
776     }
777     if (rec->dwFields & ET_PLATFORM)
778     {
779         TRACE( "ET_PLATFORM: %s\n", MSCMS_dbgstr_tag(rec->dwPlatform) );
780         if (rec->dwPlatform != hdr->phPlatform) return FALSE;
781     }
782     if (rec->dwFields & ET_PROFILEFLAGS)
783     {
784         TRACE( "ET_PROFILEFLAGS: 0x%08x\n", rec->dwProfileFlags );
785         if (rec->dwProfileFlags != hdr->phProfileFlags) return FALSE;
786     }
787     if (rec->dwFields & ET_MANUFACTURER)
788     {
789         TRACE( "ET_MANUFACTURER: %s\n", MSCMS_dbgstr_tag(rec->dwManufacturer) );
790         if (rec->dwManufacturer != hdr->phManufacturer) return FALSE;
791     }
792     if (rec->dwFields & ET_MODEL)
793     {
794         TRACE( "ET_MODEL: %s\n", MSCMS_dbgstr_tag(rec->dwModel) );
795         if (rec->dwModel != hdr->phModel) return FALSE;
796     }
797     if (rec->dwFields & ET_ATTRIBUTES)
798     {
799         TRACE( "ET_ATTRIBUTES: 0x%08x, 0x%08x\n",
800                rec->dwAttributes[0], rec->dwAttributes[1] );
801         if (rec->dwAttributes[0] != hdr->phAttributes[0] || 
802             rec->dwAttributes[1] != hdr->phAttributes[1]) return FALSE;
803     }
804     if (rec->dwFields & ET_RENDERINGINTENT)
805     {
806         TRACE( "ET_RENDERINGINTENT: 0x%08x\n", rec->dwRenderingIntent );
807         if (rec->dwRenderingIntent != hdr->phRenderingIntent) return FALSE;
808     }
809     if (rec->dwFields & ET_CREATOR)
810     {
811         TRACE( "ET_CREATOR: %s\n", MSCMS_dbgstr_tag(rec->dwCreator) );
812         if (rec->dwCreator != hdr->phCreator) return FALSE;
813     }
814     return TRUE;
815 }
816
817 /******************************************************************************
818  * EnumColorProfilesA               [MSCMS.@]
819  *
820  * See EnumColorProfilesW.
821  */
822 BOOL WINAPI EnumColorProfilesA( PCSTR machine, PENUMTYPEA record, PBYTE buffer,
823                                 PDWORD size, PDWORD number )
824 {
825     BOOL match, ret = FALSE;
826     char spec[] = "\\*.icm";
827     char colordir[MAX_PATH], glob[MAX_PATH], **profiles = NULL;
828     DWORD i, len = sizeof(colordir), count = 0, totalsize = 0;
829     PROFILEHEADER header;
830     WIN32_FIND_DATAA data;
831     ENUMTYPEW recordW;
832     WCHAR *fileW = NULL, *deviceW = NULL;
833     HANDLE find;
834
835     TRACE( "( %p, %p, %p, %p, %p )\n", machine, record, buffer, size, number );
836
837     if (machine || !record || !size ||
838         record->dwSize != sizeof(ENUMTYPEA) ||
839         record->dwVersion != ENUM_TYPE_VERSION) return FALSE;
840
841     ret = GetColorDirectoryA( machine, colordir, &len );
842     if (!ret || len + sizeof(spec) > MAX_PATH)
843     {
844         WARN( "can't retrieve color directory\n" );
845         return FALSE;
846     }
847
848     lstrcpyA( glob, colordir );
849     lstrcatA( glob, spec );
850
851     find = FindFirstFileA( glob, &data );
852     if (find == INVALID_HANDLE_VALUE) return FALSE;
853
854     profiles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(char *) + 1 );
855     if (!profiles) goto exit;
856
857     memcpy( &recordW, record, sizeof(ENUMTYPEA) );
858     if (record->pDeviceName)
859     {
860         deviceW = MSCMS_strdupW( record->pDeviceName );
861         if (!(recordW.pDeviceName = deviceW)) goto exit;
862     }
863
864     fileW = MSCMS_strdupW( data.cFileName );
865     if (!fileW) goto exit;
866
867     ret = MSCMS_header_from_file( fileW, &header );
868     if (ret)
869     {
870         match = MSCMS_match_profile( &recordW, &header );
871         if (match)
872         {
873             len = sizeof(char) * (lstrlenA( data.cFileName ) + 1);
874             profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
875
876             if (!profiles[count]) goto exit;
877             else
878             {
879                 TRACE( "matching profile: %s\n", debugstr_a(data.cFileName) );
880                 lstrcpyA( profiles[count], data.cFileName );
881                 totalsize += len;
882                 count++;
883             }
884         }
885     }
886     HeapFree( GetProcessHeap(), 0, fileW );
887     fileW = NULL;
888
889     while (FindNextFileA( find, &data ))
890     {
891         fileW = MSCMS_strdupW( data.cFileName );
892         if (!fileW) goto exit;
893
894         ret = MSCMS_header_from_file( fileW, &header );
895         if (!ret)
896         {
897             HeapFree( GetProcessHeap(), 0, fileW );
898             continue;
899         }
900
901         match = MSCMS_match_profile( &recordW, &header );
902         if (match)
903         {
904             char **tmp = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
905                                       profiles, sizeof(char *) * (count + 1) );
906             if (!tmp) goto exit;
907             else profiles = tmp;
908
909             len = sizeof(char) * (lstrlenA( data.cFileName ) + 1);
910             profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
911
912             if (!profiles[count]) goto exit;
913             else
914             {
915                 TRACE( "matching profile: %s\n", debugstr_a(data.cFileName) );
916                 lstrcpyA( profiles[count], data.cFileName );
917                 totalsize += len;
918                 count++;
919             }
920         }
921         HeapFree( GetProcessHeap(), 0, fileW );
922         fileW = NULL;
923     }
924
925     totalsize++;
926     if (buffer && *size >= totalsize)
927     {
928         char *p = (char *)buffer;
929
930         for (i = 0; i < count; i++)
931         {
932             lstrcpyA( p, profiles[i] );
933             p += lstrlenA( profiles[i] ) + 1;
934         }
935         *p = 0;
936         ret = TRUE;
937     }
938     else ret = FALSE;
939
940     *size = totalsize;
941     if (number) *number = count;
942
943 exit:
944     for (i = 0; i < count; i++)
945         HeapFree( GetProcessHeap(), 0, profiles[i] );
946     HeapFree( GetProcessHeap(), 0, profiles );
947     HeapFree( GetProcessHeap(), 0, deviceW );
948     HeapFree( GetProcessHeap(), 0, fileW );
949     FindClose( find );
950
951     return ret;
952 }
953
954 /******************************************************************************
955  * EnumColorProfilesW               [MSCMS.@]
956  *
957  * Enumerate profiles that match given criteria.
958  *
959  * PARAMS
960  *  machine  [I]   Name of the machine for which to enumerate profiles.
961  *                 Must be NULL, which indicates the local machine.
962  *  record   [I]   Record of criteria that a profile must match.
963  *  buffer   [O]   Buffer to receive a string array of profile filenames.
964  *  size     [I/O] Size of the filename buffer in bytes.
965  *  number   [O]   Number of filenames copied into buffer.
966  *
967  * RETURNS
968  *  Success: TRUE
969  *  Failure: FALSE
970  */
971 BOOL WINAPI EnumColorProfilesW( PCWSTR machine, PENUMTYPEW record, PBYTE buffer,
972                                 PDWORD size, PDWORD number )
973 {
974     BOOL match, ret = FALSE;
975     WCHAR spec[] = {'\\','*','i','c','m',0};
976     WCHAR colordir[MAX_PATH], glob[MAX_PATH], **profiles = NULL;
977     DWORD i, len = sizeof(colordir), count = 0, totalsize = 0;
978     PROFILEHEADER header;
979     WIN32_FIND_DATAW data;
980     HANDLE find;
981
982     TRACE( "( %p, %p, %p, %p, %p )\n", machine, record, buffer, size, number );
983
984     if (machine || !record || !size ||
985         record->dwSize != sizeof(ENUMTYPEW) ||
986         record->dwVersion != ENUM_TYPE_VERSION) return FALSE;
987
988     ret = GetColorDirectoryW( machine, colordir, &len );
989     if (!ret || len + sizeof(spec) > MAX_PATH)
990     {
991         WARN( "Can't retrieve color directory\n" );
992         return FALSE;
993     }
994
995     lstrcpyW( glob, colordir );
996     lstrcatW( glob, spec );
997
998     find = FindFirstFileW( glob, &data );
999     if (find == INVALID_HANDLE_VALUE) return FALSE;
1000
1001     profiles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR *) + 1 );
1002     if (!profiles) goto exit;
1003
1004     ret = MSCMS_header_from_file( data.cFileName, &header );
1005     if (ret)
1006     {
1007         match = MSCMS_match_profile( record, &header );
1008         if (match)
1009         {
1010             len = sizeof(WCHAR) * (lstrlenW( data.cFileName ) + 1);
1011             profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
1012
1013             if (!profiles[count]) goto exit;
1014             else
1015             {
1016                 TRACE( "matching profile: %s\n", debugstr_w(data.cFileName) );
1017                 lstrcpyW( profiles[count], data.cFileName );
1018                 totalsize += len;
1019                 count++;
1020             }
1021         }
1022     }
1023
1024     while (FindNextFileW( find, &data ))
1025     {
1026         ret = MSCMS_header_from_file( data.cFileName, &header );
1027         if (!ret) continue;
1028
1029         match = MSCMS_match_profile( record, &header );
1030         if (match)
1031         {
1032             WCHAR **tmp = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1033                                        profiles, sizeof(WCHAR *) * (count + 1) );
1034             if (!tmp) goto exit;
1035             else profiles = tmp;
1036
1037             len = sizeof(WCHAR) * (lstrlenW( data.cFileName ) + 1);
1038             profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
1039
1040             if (!profiles[count]) goto exit;
1041             else
1042             {
1043                 TRACE( "matching profile: %s\n", debugstr_w(data.cFileName) );
1044                 lstrcpyW( profiles[count], data.cFileName );
1045                 totalsize += len;
1046                 count++;
1047             }
1048         }
1049     }
1050
1051     totalsize++;
1052     if (buffer && *size >= totalsize)
1053     {
1054         WCHAR *p = (WCHAR *)buffer;
1055
1056         for (i = 0; i < count; i++)
1057         {
1058             lstrcpyW( p, profiles[i] );
1059             p += lstrlenW( profiles[i] ) + 1;
1060         }
1061         *p = 0;
1062         ret = TRUE;
1063     }
1064     else ret = FALSE;
1065
1066     *size = totalsize;
1067     if (number) *number = count;
1068
1069 exit:
1070     for (i = 0; i < count; i++)
1071         HeapFree( GetProcessHeap(), 0, profiles[i] );
1072     HeapFree( GetProcessHeap(), 0, profiles );
1073     FindClose( find );
1074
1075     return ret;
1076 }
1077
1078 /******************************************************************************
1079  * InstallColorProfileA               [MSCMS.@]
1080  *
1081  * See InstallColorProfileW.
1082  */
1083 BOOL WINAPI InstallColorProfileA( PCSTR machine, PCSTR profile )
1084 {
1085     UINT len;
1086     LPWSTR profileW;
1087     BOOL ret = FALSE;
1088
1089     TRACE( "( %s )\n", debugstr_a(profile) );
1090
1091     if (machine || !profile) return FALSE;
1092
1093     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
1094     profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1095
1096     if (profileW)
1097     {
1098         MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
1099
1100         ret = InstallColorProfileW( NULL, profileW );
1101         HeapFree( GetProcessHeap(), 0, profileW );
1102     }
1103     return ret;
1104 }
1105
1106 /******************************************************************************
1107  * InstallColorProfileW               [MSCMS.@]
1108  *
1109  * Install a color profile.
1110  *
1111  * PARAMS
1112  *  machine  [I] Name of the machine to install the profile on. Must be NULL,
1113  *               which indicates the local machine.
1114  *  profile  [I] Full path name of the profile to install.
1115  *
1116  * RETURNS
1117  *  Success: TRUE
1118  *  Failure: FALSE
1119  */
1120 BOOL WINAPI InstallColorProfileW( PCWSTR machine, PCWSTR profile )
1121 {
1122     WCHAR dest[MAX_PATH], base[MAX_PATH];
1123     DWORD size = sizeof(dest);
1124     static const WCHAR slash[] = { '\\', 0 };
1125
1126     TRACE( "( %s )\n", debugstr_w(profile) );
1127
1128     if (machine || !profile) return FALSE;
1129
1130     if (!GetColorDirectoryW( machine, dest, &size )) return FALSE;
1131
1132     MSCMS_basename( profile, base );
1133
1134     lstrcatW( dest, slash );
1135     lstrcatW( dest, base );
1136
1137     /* Is source equal to destination? */
1138     if (!lstrcmpW( profile, dest )) return TRUE;
1139
1140     return CopyFileW( profile, dest, TRUE );
1141 }
1142
1143 /******************************************************************************
1144  * IsColorProfileTagPresent               [MSCMS.@]
1145  *
1146  * Determine if a given ICC tag type is present in a color profile.
1147  *
1148  * PARAMS
1149  *  profile  [I] Color profile handle.
1150  *  tag      [I] ICC tag type.
1151  *  present  [O] Pointer to a BOOL variable. Set to TRUE if tag type is present,
1152  *               FALSE otherwise.
1153  *
1154  * RETURNS
1155  *  Success: TRUE
1156  *  Failure: FALSE
1157  */
1158 BOOL WINAPI IsColorProfileTagPresent( HPROFILE handle, TAGTYPE type, PBOOL present )
1159 {
1160     BOOL ret = FALSE;
1161 #ifdef HAVE_LCMS
1162     struct profile *profile = grab_profile( handle );
1163     DWORD i, count;
1164     icTag tag;
1165
1166     TRACE( "( %p, 0x%08x, %p )\n", handle, type, present );
1167
1168     if (!profile) return FALSE;
1169
1170     if (!present)
1171     {
1172         release_profile( profile );
1173         return FALSE;
1174     }
1175     count = MSCMS_get_tag_count( profile->iccprofile );
1176
1177     for (i = 0; i < count; i++)
1178     {
1179         MSCMS_get_tag_by_index( profile->iccprofile, i, &tag );
1180
1181         if (tag.sig == type)
1182         {
1183             *present = ret = TRUE;
1184             break;
1185         }
1186     }
1187     release_profile( profile );
1188
1189 #endif /* HAVE_LCMS */
1190     return ret;
1191 }
1192
1193 /******************************************************************************
1194  * IsColorProfileValid               [MSCMS.@]
1195  *
1196  * Determine if a given color profile is valid.
1197  *
1198  * PARAMS
1199  *  profile  [I] Color profile handle.
1200  *  valid    [O] Pointer to a BOOL variable. Set to TRUE if profile is valid,
1201  *               FALSE otherwise.
1202  *
1203  * RETURNS
1204  *  Success: TRUE
1205  *  Failure: FALSE 
1206  */
1207 BOOL WINAPI IsColorProfileValid( HPROFILE handle, PBOOL valid )
1208 {
1209     BOOL ret = FALSE;
1210 #ifdef HAVE_LCMS
1211     struct profile *profile = grab_profile( handle );
1212
1213     TRACE( "( %p, %p )\n", handle, valid );
1214
1215     if (!profile) return FALSE;
1216
1217     if (!valid)
1218     {
1219         release_profile( profile );
1220         return FALSE;
1221     }
1222     if (profile->iccprofile) ret = *valid = TRUE;
1223     release_profile( profile );
1224
1225 #endif /* HAVE_LCMS */
1226     return ret;
1227 }
1228
1229 /******************************************************************************
1230  * SetColorProfileElement               [MSCMS.@]
1231  *
1232  * Set data for a specified tag type.
1233  *
1234  * PARAMS
1235  *  profile  [I]   Handle to a color profile.
1236  *  type     [I]   ICC tag type.
1237  *  offset   [I]   Offset in bytes to start copying to.
1238  *  size     [I/O] Size of the buffer in bytes. On return the variable holds the
1239  *                 number of bytes actually needed.
1240  *  buffer   [O]   Buffer holding the tag data.
1241  *
1242  * RETURNS
1243  *  Success: TRUE
1244  *  Failure: FALSE
1245  */
1246 BOOL WINAPI SetColorProfileElement( HPROFILE handle, TAGTYPE type, DWORD offset, PDWORD size,
1247                                     PVOID buffer )
1248 {
1249     BOOL ret = FALSE;
1250 #ifdef HAVE_LCMS
1251     struct profile *profile = grab_profile( handle );
1252     DWORD i, count;
1253     icTag tag;
1254
1255     TRACE( "( %p, 0x%08x, %d, %p, %p )\n", handle, type, offset, size, buffer );
1256
1257     if (!profile) return FALSE;
1258
1259     if (!size || !buffer || !(profile->access & PROFILE_READWRITE))
1260     {
1261         release_profile( profile );
1262         return FALSE;
1263     }
1264     count = MSCMS_get_tag_count( profile->iccprofile );
1265
1266     for (i = 0; i < count; i++)
1267     {
1268         MSCMS_get_tag_by_index( profile->iccprofile, i, &tag );
1269
1270         if (tag.sig == type)
1271         {
1272             if (offset > tag.size)
1273             {
1274                 release_profile( profile );
1275                 return FALSE;
1276             }
1277             MSCMS_set_tag_data( profile->iccprofile, &tag, offset, buffer );
1278
1279             release_profile( profile );
1280             return TRUE;
1281         }
1282     }
1283     release_profile( profile );
1284
1285 #endif /* HAVE_LCMS */
1286     return ret;
1287 }
1288
1289 /******************************************************************************
1290  * SetColorProfileHeader               [MSCMS.@]
1291  *
1292  * Set header data for a given profile.
1293  *
1294  * PARAMS
1295  *  profile  [I] Handle to a color profile.
1296  *  header   [I] Buffer holding the header data.
1297  *
1298  * RETURNS
1299  *  Success: TRUE
1300  *  Failure: FALSE
1301  */
1302 BOOL WINAPI SetColorProfileHeader( HPROFILE handle, PPROFILEHEADER header )
1303 {
1304 #ifdef HAVE_LCMS
1305     struct profile *profile = grab_profile( handle );
1306
1307     TRACE( "( %p, %p )\n", handle, header );
1308
1309     if (!profile) return FALSE;
1310
1311     if (!header || !(profile->access & PROFILE_READWRITE))
1312     {
1313         release_profile( profile );
1314         return FALSE;
1315     }
1316     MSCMS_set_profile_header( profile->iccprofile, header );
1317
1318     release_profile( profile );
1319     return TRUE;
1320
1321 #else
1322     return FALSE;
1323 #endif /* HAVE_LCMS */
1324 }
1325
1326 /******************************************************************************
1327  * UninstallColorProfileA               [MSCMS.@]
1328  *
1329  * See UninstallColorProfileW.
1330  */
1331 BOOL WINAPI UninstallColorProfileA( PCSTR machine, PCSTR profile, BOOL delete )
1332 {
1333     UINT len;
1334     LPWSTR profileW;
1335     BOOL ret = FALSE;
1336
1337     TRACE( "( %s, %x )\n", debugstr_a(profile), delete );
1338
1339     if (machine || !profile) return FALSE;
1340
1341     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
1342     profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1343
1344     if (profileW)
1345     {
1346         MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
1347
1348         ret = UninstallColorProfileW( NULL, profileW , delete );
1349
1350         HeapFree( GetProcessHeap(), 0, profileW );
1351     }
1352     return ret;
1353 }
1354
1355 /******************************************************************************
1356  * UninstallColorProfileW               [MSCMS.@]
1357  *
1358  * Uninstall a color profile.
1359  *
1360  * PARAMS
1361  *  machine  [I] Name of the machine to uninstall the profile on. Must be NULL,
1362  *               which indicates the local machine.
1363  *  profile  [I] Full path name of the profile to uninstall.
1364  *  delete   [I] Bool that specifies whether the profile file should be deleted.
1365  *
1366  * RETURNS
1367  *  Success: TRUE
1368  *  Failure: FALSE
1369  */
1370 BOOL WINAPI UninstallColorProfileW( PCWSTR machine, PCWSTR profile, BOOL delete )
1371 {
1372     TRACE( "( %s, %x )\n", debugstr_w(profile), delete );
1373
1374     if (machine || !profile) return FALSE;
1375
1376     if (delete) return DeleteFileW( profile );
1377
1378     return TRUE;
1379 }
1380
1381 /******************************************************************************
1382  * OpenColorProfileA               [MSCMS.@]
1383  *
1384  * See OpenColorProfileW.
1385  */
1386 HPROFILE WINAPI OpenColorProfileA( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
1387 {
1388     HPROFILE handle = NULL;
1389
1390     TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile, access, sharing, creation );
1391
1392     if (!profile || !profile->pProfileData) return NULL;
1393
1394     /* No AW conversion needed for memory based profiles */
1395     if (profile->dwType & PROFILE_MEMBUFFER)
1396         return OpenColorProfileW( profile, access, sharing, creation );
1397
1398     if (profile->dwType & PROFILE_FILENAME)
1399     {
1400         UINT len;
1401         PROFILE profileW;
1402
1403         profileW.dwType = profile->dwType;
1404  
1405         len = MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, NULL, 0 );
1406         profileW.pProfileData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1407
1408         if (profileW.pProfileData)
1409         {
1410             profileW.cbDataSize = len * sizeof(WCHAR);
1411             MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, profileW.pProfileData, len );
1412
1413             handle = OpenColorProfileW( &profileW, access, sharing, creation );
1414             HeapFree( GetProcessHeap(), 0, profileW.pProfileData );
1415         }
1416     }
1417     return handle;
1418 }
1419
1420 /******************************************************************************
1421  * OpenColorProfileW               [MSCMS.@]
1422  *
1423  * Open a color profile.
1424  *
1425  * PARAMS
1426  *  profile   [I] Pointer to a color profile structure.
1427  *  access    [I] Desired access.
1428  *  sharing   [I] Sharing mode.
1429  *  creation  [I] Creation mode.
1430  *
1431  * RETURNS
1432  *  Success: Handle to the opened profile.
1433  *  Failure: NULL
1434  *
1435  * NOTES
1436  *  Values for access:   PROFILE_READ or PROFILE_READWRITE.
1437  *  Values for sharing:  0 (no sharing), FILE_SHARE_READ and/or FILE_SHARE_WRITE.
1438  *  Values for creation: one of CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
1439  *                       OPEN_ALWAYS, TRUNCATE_EXISTING.
1440  *  Sharing and creation flags are ignored for memory based profiles.
1441  */
1442 HPROFILE WINAPI OpenColorProfileW( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
1443 {
1444 #ifdef HAVE_LCMS
1445     cmsHPROFILE cmsprofile = NULL;
1446     icProfile *iccprofile = NULL;
1447     HANDLE handle = INVALID_HANDLE_VALUE;
1448
1449     TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile, access, sharing, creation );
1450
1451     if (!profile || !profile->pProfileData) return NULL;
1452
1453     if (profile->dwType == PROFILE_MEMBUFFER)
1454     {
1455         /* FIXME: access flags not implemented for memory based profiles */
1456
1457         if (!(iccprofile = HeapAlloc( GetProcessHeap(), 0, profile->cbDataSize ))) return NULL;
1458         memcpy( iccprofile, profile->pProfileData, profile->cbDataSize );
1459
1460         cmsprofile = cmsOpenProfileFromMem( iccprofile, profile->cbDataSize );
1461     }
1462     else if (profile->dwType == PROFILE_FILENAME)
1463     {
1464         DWORD size, read, flags = 0;
1465
1466         TRACE( "profile file: %s\n", debugstr_w( profile->pProfileData ) );
1467
1468         if (access & PROFILE_READ) flags = GENERIC_READ;
1469         if (access & PROFILE_READWRITE) flags = GENERIC_READ|GENERIC_WRITE;
1470
1471         if (!flags) return NULL;
1472         if (!sharing) sharing = FILE_SHARE_READ;
1473
1474         if (!PathIsRelativeW( profile->pProfileData ))
1475             handle = CreateFileW( profile->pProfileData, flags, sharing, NULL, creation, 0, NULL );
1476         else
1477         {
1478             DWORD size;
1479             WCHAR *path;
1480
1481             if (!GetColorDirectoryW( NULL, NULL, &size ) && GetLastError() == ERROR_MORE_DATA)
1482             {
1483                 size += (strlenW( profile->pProfileData ) + 2) * sizeof(WCHAR);
1484                 if (!(path = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
1485                 GetColorDirectoryW( NULL, path, &size );
1486                 PathAddBackslashW( path );
1487                 strcatW( path, profile->pProfileData );
1488             }
1489             else return NULL;
1490             handle = CreateFileW( path, flags, sharing, NULL, creation, 0, NULL );
1491             HeapFree( GetProcessHeap(), 0, path );
1492         }
1493         if (handle == INVALID_HANDLE_VALUE)
1494         {
1495             WARN( "Unable to open color profile %u\n", GetLastError() );
1496             return NULL;
1497         }
1498
1499         if ((size = GetFileSize( handle, NULL )) == INVALID_FILE_SIZE)
1500         {
1501             ERR( "Unable to retrieve size of color profile\n" );
1502             CloseHandle( handle );
1503             return NULL;
1504         }
1505
1506         iccprofile = HeapAlloc( GetProcessHeap(), 0, size );
1507         if (!iccprofile)
1508         {
1509             ERR( "Unable to allocate memory for color profile\n" );
1510             CloseHandle( handle );
1511             return NULL;
1512         }
1513
1514         if (!ReadFile( handle, iccprofile, size, &read, NULL ) || read != size)
1515         {
1516             ERR( "Unable to read color profile\n" );
1517
1518             CloseHandle( handle );
1519             HeapFree( GetProcessHeap(), 0, iccprofile );
1520             return NULL;
1521         }
1522
1523         cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
1524     }
1525     else
1526     {
1527         ERR( "Invalid profile type %u\n", profile->dwType );
1528         return NULL;
1529     }
1530
1531     if (cmsprofile)
1532     {
1533         struct profile profile;
1534
1535         profile.file = handle;
1536         profile.access = access;
1537         profile.iccprofile = iccprofile;
1538         profile.cmsprofile = cmsprofile;
1539
1540         return create_profile( &profile );
1541     }
1542
1543 #endif /* HAVE_LCMS */
1544     return NULL;
1545 }
1546
1547 /******************************************************************************
1548  * CloseColorProfile               [MSCMS.@]
1549  *
1550  * Close a color profile.
1551  *
1552  * PARAMS
1553  *  profile  [I] Handle to the profile.
1554  *
1555  * RETURNS
1556  *  Success: TRUE
1557  *  Failure: FALSE
1558  */
1559 BOOL WINAPI CloseColorProfile( HPROFILE profile )
1560 {
1561     BOOL ret = FALSE;
1562 #ifdef HAVE_LCMS
1563
1564     TRACE( "( %p )\n", profile );
1565     ret = close_profile( profile );
1566
1567 #endif /* HAVE_LCMS */
1568     return ret;
1569 }