Make lcms support depend on headers _and_ libraries, not just the
[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 || !size) return FALSE;
350
351     sizeW = *size * sizeof(WCHAR);
352
353     if (!profile)
354     {
355         ret = GetStandardColorSpaceProfileW( NULL, id, NULL, &sizeW );
356         *size = sizeW / sizeof(WCHAR);
357         return FALSE;
358     }
359
360     profileW = HeapAlloc( GetProcessHeap(), 0, sizeW );
361
362     if (profileW)
363     {
364         ret = GetStandardColorSpaceProfileW( NULL, id, profileW, &sizeW );
365         *size = WideCharToMultiByte( CP_ACP, 0, profileW, -1, NULL, 0, NULL, NULL );
366
367         if (ret)
368         {
369             len = WideCharToMultiByte( CP_ACP, 0, profileW, *size, profile, *size, NULL, NULL );
370             if (!len) ret = FALSE;
371         }
372
373         HeapFree( GetProcessHeap(), 0, profileW );
374     }
375     return ret;
376 }
377
378 /******************************************************************************
379  * GetStandardColorSpaceProfileW               [MSCMS.@]
380  *
381  * Retrieve the profile filename for a given standard color space id.
382  *
383  * PARAMS
384  *  machine  [I]   Name of the machine for which to get the standard color space.
385  *                 Must be NULL, which indicates the local machine.
386  *  id       [I]   Id of a standard color space.
387  *  profile  [O]   Buffer to receive the profile filename.
388  *  size     [I/O] Size of the filename buffer in bytes.
389  *
390  * RETURNS
391  *  Success: TRUE
392  *  Failure: FALSE
393  */
394 BOOL WINAPI GetStandardColorSpaceProfileW( PCWSTR machine, DWORD id, PWSTR profile, PDWORD size )
395 {
396     static const WCHAR rgbprofilefile[] =
397         { '\\','s','r','g','b',' ','c','o','l','o','r',' ',
398           's','p','a','c','e',' ','p','r','o','f','i','l','e','.','i','c','m',0 };
399     WCHAR rgbprofile[MAX_PATH];
400     DWORD len = sizeof(rgbprofile);
401
402     TRACE( "( 0x%08lx, %p, %p )\n", id, profile, size );
403
404     if (machine || !size) return FALSE;
405     GetColorDirectoryW( machine, rgbprofile, &len );
406
407     switch (id)
408     {
409         case 0x52474220: /* 'RGB ' */
410             lstrcatW( rgbprofile, rgbprofilefile );
411             len = lstrlenW( rgbprofile ) * sizeof(WCHAR);
412
413             if (*size < len || !profile)
414             {
415                 *size = len;
416                 return TRUE;
417             }
418
419             lstrcpyW( profile, rgbprofile );
420             break;
421
422         default:
423             return FALSE;
424     }
425     return TRUE;
426 }
427
428 /******************************************************************************
429  * InstallColorProfileA               [MSCMS.@]
430  *
431  * See InstallColorProfileW.
432  */
433 BOOL WINAPI InstallColorProfileA( PCSTR machine, PCSTR profile )
434 {
435     UINT len;
436     LPWSTR profileW;
437     BOOL ret = FALSE;
438
439     TRACE( "( %s )\n", debugstr_a(profile) );
440
441     if (machine || !profile) return FALSE;
442
443     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
444     profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
445
446     if (profileW)
447     {
448         MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
449
450         ret = InstallColorProfileW( NULL, profileW );
451         HeapFree( GetProcessHeap(), 0, profileW );
452     }
453     return ret;
454 }
455
456 /******************************************************************************
457  * InstallColorProfileW               [MSCMS.@]
458  *
459  * Install a color profile.
460  *
461  * PARAMS
462  *  machine  [I] Name of the machine to install the profile on. Must be NULL,
463  *               which indicates the local machine.
464  *  profile  [I] Full path name of the profile to install.
465  *
466  * RETURNS
467  *  Success: TRUE
468  *  Failure: FALSE
469  */
470 BOOL WINAPI InstallColorProfileW( PCWSTR machine, PCWSTR profile )
471 {
472     WCHAR dest[MAX_PATH], base[MAX_PATH];
473     DWORD size = sizeof(dest);
474     static const WCHAR slash[] = { '\\', 0 };
475
476     TRACE( "( %s )\n", debugstr_w(profile) );
477
478     if (machine || !profile) return FALSE;
479
480     if (!GetColorDirectoryW( machine, dest, &size )) return FALSE;
481
482     MSCMS_basename( profile, base );
483
484     lstrcatW( dest, slash );
485     lstrcatW( dest, base );
486
487     /* Is source equal to destination? */
488     if (!lstrcmpW( profile, dest )) return TRUE;
489
490     return CopyFileW( profile, dest, TRUE );
491 }
492
493 /******************************************************************************
494  * IsColorProfileTagPresent               [MSCMS.@]
495  *
496  * Determine if a given ICC tag type is present in a color profile.
497  *
498  * PARAMS
499  *  profile  [I] Color profile handle.
500  *  tag      [I] ICC tag type.
501  *  present  [O] Pointer to a BOOL variable. Set to TRUE if tag type is present,
502  *               FALSE otherwise.
503  *
504  * RETURNS
505  *  Success: TRUE
506  *  Failure: FALSE
507  */
508 BOOL WINAPI IsColorProfileTagPresent( HPROFILE profile, TAGTYPE type, PBOOL present )
509 {
510     BOOL ret = FALSE;
511 #ifdef HAVE_LCMS
512     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
513     DWORD i, count;
514     icTag tag;
515
516     TRACE( "( %p, 0x%08lx, %p )\n", profile, type, present );
517
518     if (!iccprofile || !present) return FALSE;
519
520     count = MSCMS_get_tag_count( iccprofile );
521
522     for (i = 0; i < count; i++)
523     {
524         MSCMS_get_tag_by_index( iccprofile, i, &tag );
525
526         if (tag.sig == type)
527         {
528             *present = ret = TRUE;
529             break;
530         }
531     }
532
533 #endif /* HAVE_LCMS */
534     return ret;
535 }
536
537 /******************************************************************************
538  * IsColorProfileValid               [MSCMS.@]
539  *
540  * Determine if a given color profile is valid.
541  *
542  * PARAMS
543  *  profile  [I] Color profile handle.
544  *  valid    [O] Pointer to a BOOL variable. Set to TRUE if profile is valid,
545  *               FALSE otherwise.
546  *
547  * RETURNS
548  *  Success: TRUE
549  *  Failure: FALSE 
550  */
551 BOOL WINAPI IsColorProfileValid( HPROFILE profile, PBOOL valid )
552 {
553     BOOL ret = FALSE;
554 #ifdef HAVE_LCMS
555     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
556
557     TRACE( "( %p, %p )\n", profile, valid );
558
559     if (!valid) return FALSE;
560     if (iccprofile) return *valid = TRUE;
561
562 #endif /* HAVE_LCMS */
563     return ret;
564 }
565
566 /******************************************************************************
567  * SetColorProfileElement               [MSCMS.@]
568  *
569  * Set data for a specified tag type.
570  *
571  * PARAMS
572  *  profile  [I]   Handle to a color profile.
573  *  type     [I]   ICC tag type.
574  *  offset   [I]   Offset in bytes to start copying to.
575  *  size     [I/O] Size of the buffer in bytes. On return the variable holds the
576  *                 number of bytes actually needed.
577  *  buffer   [O]   Buffer holding the tag data.
578  *
579  * RETURNS
580  *  Success: TRUE
581  *  Failure: FALSE
582  */
583 BOOL WINAPI SetColorProfileElement( HPROFILE profile, TAGTYPE type, DWORD offset, PDWORD size,
584                                     PVOID buffer )
585 {
586     BOOL ret = FALSE;
587 #ifdef HAVE_LCMS
588     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
589     DWORD i, count, access = MSCMS_hprofile2access( profile );
590     icTag tag;
591
592     TRACE( "( %p, 0x%08lx, %ld, %p, %p )\n", profile, type, offset, size, buffer );
593
594     if (!iccprofile || !size || !buffer) return FALSE;
595     if (!(access & PROFILE_READWRITE)) return FALSE;
596
597     count = MSCMS_get_tag_count( iccprofile );
598
599     for (i = 0; i < count; i++)
600     {
601         MSCMS_get_tag_by_index( iccprofile, i, &tag );
602
603         if (tag.sig == type)
604         {
605             if (offset > tag.size) return FALSE;
606
607             MSCMS_set_tag_data( iccprofile, &tag, offset, buffer );
608             return TRUE;
609         }
610     }
611
612 #endif /* HAVE_LCMS */
613     return ret;
614 }
615
616 /******************************************************************************
617  * SetColorProfileHeader               [MSCMS.@]
618  *
619  * Set header data for a given profile.
620  *
621  * PARAMS
622  *  profile  [I] Handle to a color profile.
623  *  header   [I] Buffer holding the header data.
624  *
625  * RETURNS
626  *  Success: TRUE
627  *  Failure: FALSE
628  */
629 BOOL WINAPI SetColorProfileHeader( HPROFILE profile, PPROFILEHEADER header )
630 {
631     BOOL ret = FALSE;
632 #ifdef HAVE_LCMS
633     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
634     DWORD access = MSCMS_hprofile2access( profile );
635
636     TRACE( "( %p, %p )\n", profile, header );
637
638     if (!iccprofile || !header) return FALSE;
639     if (!(access & PROFILE_READWRITE)) return FALSE;
640
641     MSCMS_set_profile_header( iccprofile, header );
642     return TRUE;
643
644 #endif /* HAVE_LCMS */
645     return ret;
646 }
647
648 /******************************************************************************
649  * UninstallColorProfileA               [MSCMS.@]
650  *
651  * See UninstallColorProfileW.
652  */
653 BOOL WINAPI UninstallColorProfileA( PCSTR machine, PCSTR profile, BOOL delete )
654 {
655     UINT len;
656     LPWSTR profileW;
657     BOOL ret = FALSE;
658
659     TRACE( "( %s, %x )\n", debugstr_a(profile), delete );
660
661     if (machine || !profile) return FALSE;
662
663     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
664     profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
665
666     if (profileW)
667     {
668         MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
669
670         ret = UninstallColorProfileW( NULL, profileW , delete );
671
672         HeapFree( GetProcessHeap(), 0, profileW );
673     }
674     return ret;
675 }
676
677 /******************************************************************************
678  * UninstallColorProfileW               [MSCMS.@]
679  *
680  * Uninstall a color profile.
681  *
682  * PARAMS
683  *  machine  [I] Name of the machine to uninstall the profile on. Must be NULL,
684  *               which indicates the local machine.
685  *  profile  [I] Full path name of the profile to uninstall.
686  *  delete   [I] Bool that specifies whether the profile file should be deleted.
687  *
688  * RETURNS
689  *  Success: TRUE
690  *  Failure: FALSE
691  */
692 BOOL WINAPI UninstallColorProfileW( PCWSTR machine, PCWSTR profile, BOOL delete )
693 {
694     TRACE( "( %s, %x )\n", debugstr_w(profile), delete );
695
696     if (machine || !profile) return FALSE;
697
698     if (delete) return DeleteFileW( profile );
699
700     return TRUE;
701 }
702
703 /******************************************************************************
704  * OpenColorProfileA               [MSCMS.@]
705  *
706  * See OpenColorProfileW.
707  */
708 HPROFILE WINAPI OpenColorProfileA( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
709 {
710     HPROFILE handle = NULL;
711
712     TRACE( "( %p, 0x%08lx, 0x%08lx, 0x%08lx )\n", profile, access, sharing, creation );
713
714     if (!profile || !profile->pProfileData) return NULL;
715
716     /* No AW conversion needed for memory based profiles */
717     if (profile->dwType & PROFILE_MEMBUFFER)
718         return OpenColorProfileW( profile, access, sharing, creation );
719
720     if (profile->dwType & PROFILE_FILENAME)
721     {
722         UINT len;
723         PROFILE profileW;
724
725         profileW.dwType = profile->dwType;
726  
727         len = MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, NULL, 0 );
728         profileW.pProfileData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
729
730         if (profileW.pProfileData)
731         {
732             profileW.cbDataSize = len * sizeof(WCHAR);
733             MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, profileW.pProfileData, len );
734
735             handle = OpenColorProfileW( &profileW, access, sharing, creation );
736             HeapFree( GetProcessHeap(), 0, profileW.pProfileData );
737         }
738     }
739     return handle;
740 }
741
742 /******************************************************************************
743  * OpenColorProfileW               [MSCMS.@]
744  *
745  * Open a color profile.
746  *
747  * PARAMS
748  *  profile   [I] Pointer to a color profile structure.
749  *  access    [I] Desired access.
750  *  sharing   [I] Sharing mode.
751  *  creation  [I] Creation mode.
752  *
753  * RETURNS
754  *  Success: Handle to the opened profile.
755  *  Failure: NULL
756  *
757  * NOTES
758  *  Values for access:   PROFILE_READ or PROFILE_READWRITE.
759  *  Values for sharing:  0 (no sharing), FILE_SHARE_READ and/or FILE_SHARE_WRITE.
760  *  Values for creation: one of CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
761  *                       OPEN_ALWAYS, TRUNCATE_EXISTING.
762  *  Sharing and creation flags are ignored for memory based profiles.
763  */
764 HPROFILE WINAPI OpenColorProfileW( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
765 {
766 #ifdef HAVE_LCMS
767     cmsHPROFILE cmsprofile = NULL;
768     icProfile *iccprofile = NULL;
769     HANDLE handle = NULL;
770     DWORD size;
771
772     TRACE( "( %p, 0x%08lx, 0x%08lx, 0x%08lx )\n", profile, access, sharing, creation );
773
774     if (!profile || !profile->pProfileData) return NULL;
775
776     if (profile->dwType & PROFILE_MEMBUFFER)
777     {
778         FIXME( "access flags not implemented for memory based profiles\n" );
779
780         iccprofile = profile->pProfileData;
781         size = profile->cbDataSize;
782     
783         cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
784     }
785
786     if (profile->dwType & PROFILE_FILENAME)
787     {
788         DWORD read, flags = 0;
789
790         TRACE( "profile file: %s\n", debugstr_w( (WCHAR *)profile->pProfileData ) );
791
792         if (access & PROFILE_READ) flags = GENERIC_READ;
793         if (access & PROFILE_READWRITE) flags = GENERIC_READ|GENERIC_WRITE;
794
795         if (!flags) return NULL;
796
797         handle = CreateFileW( profile->pProfileData, flags, sharing, NULL, creation, 0, NULL );
798         if (handle == INVALID_HANDLE_VALUE)
799         {
800             WARN( "Unable to open color profile\n" );
801             return NULL;
802         }
803
804         if ((size = GetFileSize( handle, NULL )) == INVALID_FILE_SIZE)
805         {
806             ERR( "Unable to retrieve size of color profile\n" );
807             CloseHandle( handle );
808             return NULL;
809         }
810
811         iccprofile = HeapAlloc( GetProcessHeap(), 0, size );
812         if (!iccprofile)
813         {
814             ERR( "Unable to allocate memory for color profile\n" );
815             CloseHandle( handle );
816             return NULL;
817         }
818
819         if (!ReadFile( handle, iccprofile, size, &read, NULL ) || read != size)
820         {
821             ERR( "Unable to read color profile\n" );
822
823             CloseHandle( handle );
824             HeapFree( GetProcessHeap, 0, iccprofile );
825             return NULL;
826         }
827
828         cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
829     }
830
831     if (cmsprofile)
832         return MSCMS_create_hprofile_handle( handle, iccprofile, cmsprofile, access );
833
834 #endif /* HAVE_LCMS */
835     return NULL;
836 }
837
838 /******************************************************************************
839  * CloseColorProfile               [MSCMS.@]
840  *
841  * Close a color profile.
842  *
843  * PARAMS
844  *  profile  [I] Handle to the profile.
845  *
846  * RETURNS
847  *  Success: TRUE
848  *  Failure: FALSE
849  */
850 BOOL WINAPI CloseColorProfile( HPROFILE profile )
851 {
852     BOOL ret = FALSE;
853 #ifdef HAVE_LCMS
854     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
855     HANDLE file = MSCMS_hprofile2handle( profile );
856     DWORD access = MSCMS_hprofile2access( profile );
857
858     TRACE( "( %p )\n", profile );
859
860     if (file && (access & PROFILE_READWRITE))
861     {
862         DWORD written, size = MSCMS_get_profile_size( iccprofile );
863
864         if (SetFilePointer( file, 0, NULL, FILE_BEGIN ) ||
865             !WriteFile( file, iccprofile, size, &written, NULL ) || written != size)
866             ERR( "Unable to write color profile\n" );
867     }
868
869     ret = cmsCloseProfile( MSCMS_hprofile2cmsprofile( profile ) );
870     HeapFree( GetProcessHeap(), 0, MSCMS_hprofile2iccprofile( profile ) );
871
872     CloseHandle( MSCMS_hprofile2handle( profile ) );
873     MSCMS_destroy_hprofile_handle( profile );
874
875 #endif /* HAVE_LCMS */
876     return ret;
877 }