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