push 37d76373165707dfd5c864bc2126a42ed39183b4
[wine/hacks.git] / dlls / mscms / profile.c
blob3f0a50d44ac7387e011fcd6d02bb0ed1df43372f
1 /*
2 * MSCMS - Color Management System for Wine
4 * Copyright 2004, 2005, 2006 Hans Leidekker
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.
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.
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
21 #include "config.h"
22 #include "wine/debug.h"
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "icm.h"
33 #include "mscms_priv.h"
35 #define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/')
37 static void MSCMS_basename( LPCWSTR path, LPWSTR name )
39 INT i = lstrlenW( path );
41 while (i > 0 && !IS_SEPARATOR(path[i - 1])) i--;
42 lstrcpyW( name, &path[i] );
45 static inline LPWSTR MSCMS_strdupW( LPCSTR str )
47 LPWSTR ret = NULL;
48 if (str)
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 );
54 return ret;
57 static const char *MSCMS_dbgstr_tag( DWORD tag )
59 return wine_dbg_sprintf( "'%c%c%c%c'",
60 (char)(tag >> 24), (char)(tag >> 16), (char)(tag >> 8), (char)(tag) );
63 WINE_DEFAULT_DEBUG_CHANNEL(mscms);
65 /******************************************************************************
66 * GetColorDirectoryA [MSCMS.@]
68 * See GetColorDirectoryW.
70 BOOL WINAPI GetColorDirectoryA( PCSTR machine, PSTR buffer, PDWORD size )
72 INT len;
73 LPWSTR bufferW;
74 BOOL ret = FALSE;
75 DWORD sizeW;
77 TRACE( "( %p, %p )\n", buffer, size );
79 if (machine || !size) return FALSE;
81 if (!buffer)
83 ret = GetColorDirectoryW( NULL, NULL, &sizeW );
84 *size = sizeW / sizeof(WCHAR);
85 return FALSE;
88 sizeW = *size * sizeof(WCHAR);
90 bufferW = HeapAlloc( GetProcessHeap(), 0, sizeW );
92 if (bufferW)
94 if ((ret = GetColorDirectoryW( NULL, bufferW, &sizeW )))
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;
100 else *size = sizeW / sizeof(WCHAR);
102 HeapFree( GetProcessHeap(), 0, bufferW );
104 return ret;
107 /******************************************************************************
108 * GetColorDirectoryW [MSCMS.@]
110 * Get the directory where color profiles are stored.
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.
119 BOOL WINAPI GetColorDirectoryW( PCWSTR machine, PWSTR buffer, PDWORD size )
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;
126 TRACE( "( %p, %p )\n", buffer, size );
128 if (machine || !size) return FALSE;
130 GetSystemDirectoryW( colordir, sizeof(colordir) / sizeof(WCHAR) );
131 lstrcatW( colordir, colorsubdir );
133 len = lstrlenW( colordir ) * sizeof(WCHAR);
135 if (buffer && len <= *size)
137 lstrcpyW( buffer, colordir );
138 *size = len;
139 return TRUE;
142 SetLastError( ERROR_MORE_DATA );
143 *size = len;
144 return FALSE;
147 /******************************************************************************
148 * GetColorProfileElement [MSCMS.@]
150 * Retrieve data for a specified tag type.
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.
162 * RETURNS
163 * Success: TRUE
164 * Failure: FALSE
166 BOOL WINAPI GetColorProfileElement( HPROFILE profile, TAGTYPE type, DWORD offset, PDWORD size,
167 PVOID buffer, PBOOL ref )
169 BOOL ret = FALSE;
170 #ifdef HAVE_LCMS
171 icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
172 DWORD i, count;
173 icTag tag;
175 TRACE( "( %p, 0x%08x, %d, %p, %p, %p )\n", profile, type, offset, size, buffer, ref );
177 if (!iccprofile || !size || !ref) return FALSE;
178 count = MSCMS_get_tag_count( iccprofile );
180 for (i = 0; i < count; i++)
182 MSCMS_get_tag_by_index( iccprofile, i, &tag );
184 if (tag.sig == type)
186 if ((tag.size - offset) > *size || !buffer)
188 *size = (tag.size - offset);
189 return FALSE;
192 MSCMS_get_tag_data( iccprofile, &tag, offset, buffer );
194 *ref = FALSE; /* FIXME: calculate properly */
195 return TRUE;
199 #endif /* HAVE_LCMS */
200 return ret;
203 /******************************************************************************
204 * GetColorProfileElementTag [MSCMS.@]
206 * Get the tag type from a color profile by index.
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.
213 * RETURNS
214 * Success: TRUE
215 * Failure: FALSE
217 * NOTES
218 * The tag table index starts at 1.
219 * Use GetCountColorProfileElements to retrieve a count of tagged elements.
221 BOOL WINAPI GetColorProfileElementTag( HPROFILE profile, DWORD index, PTAGTYPE type )
223 BOOL ret = FALSE;
224 #ifdef HAVE_LCMS
225 icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
226 DWORD count;
227 icTag tag;
229 TRACE( "( %p, %d, %p )\n", profile, index, type );
231 if (!iccprofile || !type) return FALSE;
233 count = MSCMS_get_tag_count( iccprofile );
234 if (index > count || index < 1) return FALSE;
236 MSCMS_get_tag_by_index( iccprofile, index - 1, &tag );
237 *type = tag.sig;
239 ret = TRUE;
241 #endif /* HAVE_LCMS */
242 return ret;
245 /******************************************************************************
246 * GetColorProfileFromHandle [MSCMS.@]
248 * Retrieve an ICC color profile by handle.
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.
256 * RETURNS
257 * Success: TRUE
258 * Failure: FALSE
260 * NOTES
261 * The profile returned will be in big-endian format.
263 BOOL WINAPI GetColorProfileFromHandle( HPROFILE profile, PBYTE buffer, PDWORD size )
265 BOOL ret = FALSE;
266 #ifdef HAVE_LCMS
267 icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
268 PROFILEHEADER header;
270 TRACE( "( %p, %p, %p )\n", profile, buffer, size );
272 if (!iccprofile || !size) return FALSE;
273 MSCMS_get_profile_header( iccprofile, &header );
275 if (!buffer || header.phSize > *size)
277 *size = header.phSize;
278 return FALSE;
281 /* No endian conversion needed */
282 memcpy( buffer, iccprofile, header.phSize );
284 *size = header.phSize;
285 ret = TRUE;
287 #endif /* HAVE_LCMS */
288 return ret;
291 /******************************************************************************
292 * GetColorProfileHeader [MSCMS.@]
294 * Retrieve a color profile header by handle.
296 * PARAMS
297 * profile [I] Handle to a color profile.
298 * header [O] Buffer to receive the ICC profile header.
300 * RETURNS
301 * Success: TRUE
302 * Failure: FALSE
304 * NOTES
305 * The profile header returned will be adjusted for endianess.
307 BOOL WINAPI GetColorProfileHeader( HPROFILE profile, PPROFILEHEADER header )
309 #ifdef HAVE_LCMS
310 icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
312 TRACE( "( %p, %p )\n", profile, header );
314 if (!iccprofile || !header) return FALSE;
316 MSCMS_get_profile_header( iccprofile, header );
317 return TRUE;
319 #else
320 return FALSE;
321 #endif /* HAVE_LCMS */
324 /******************************************************************************
325 * GetCountColorProfileElements [MSCMS.@]
327 * Retrieve the number of elements in a color profile.
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.
334 * RETURNS
335 * Success: TRUE
336 * Failure: FALSE
338 BOOL WINAPI GetCountColorProfileElements( HPROFILE profile, PDWORD count )
340 BOOL ret = FALSE;
341 #ifdef HAVE_LCMS
342 icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
344 TRACE( "( %p, %p )\n", profile, count );
346 if (!iccprofile || !count) return FALSE;
347 *count = MSCMS_get_tag_count( iccprofile );
348 ret = TRUE;
350 #endif /* HAVE_LCMS */
351 return ret;
354 /******************************************************************************
355 * GetStandardColorSpaceProfileA [MSCMS.@]
357 * See GetStandardColorSpaceProfileW.
359 BOOL WINAPI GetStandardColorSpaceProfileA( PCSTR machine, DWORD id, PSTR profile, PDWORD size )
361 INT len;
362 LPWSTR profileW;
363 BOOL ret = FALSE;
364 DWORD sizeW;
366 TRACE( "( 0x%08x, %p, %p )\n", id, profile, size );
368 if (machine)
370 SetLastError( ERROR_NOT_SUPPORTED );
371 return FALSE;
374 if (!size)
376 SetLastError( ERROR_INVALID_PARAMETER );
377 return FALSE;
380 sizeW = *size * sizeof(WCHAR);
382 if (!profile)
384 ret = GetStandardColorSpaceProfileW( NULL, id, NULL, &sizeW );
385 *size = sizeW / sizeof(WCHAR);
386 return FALSE;
389 profileW = HeapAlloc( GetProcessHeap(), 0, sizeW );
391 if (profileW)
393 if ((ret = GetStandardColorSpaceProfileW( NULL, id, profileW, &sizeW )))
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;
399 else *size = sizeW / sizeof(WCHAR);
401 HeapFree( GetProcessHeap(), 0, profileW );
403 return ret;
406 /******************************************************************************
407 * GetStandardColorSpaceProfileW [MSCMS.@]
409 * Retrieve the profile filename for a given standard color space id.
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.
418 * RETURNS
419 * Success: TRUE
420 * Failure: FALSE
422 BOOL WINAPI GetStandardColorSpaceProfileW( PCWSTR machine, DWORD id, PWSTR profile, PDWORD size )
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);
430 TRACE( "( 0x%08x, %p, %p )\n", id, profile, size );
432 if (machine)
434 SetLastError( ERROR_NOT_SUPPORTED );
435 return FALSE;
438 if (!size)
440 SetLastError( ERROR_INVALID_PARAMETER );
441 return FALSE;
444 if (!profile)
446 SetLastError( ERROR_INSUFFICIENT_BUFFER );
447 return FALSE;
450 GetColorDirectoryW( machine, rgbprofile, &len );
452 switch (id)
454 case SPACE_RGB: /* 'RGB ' */
455 lstrcatW( rgbprofile, rgbprofilefile );
456 len = lstrlenW( rgbprofile ) * sizeof(WCHAR);
458 if (*size < len || !profile)
460 *size = len;
461 SetLastError( ERROR_MORE_DATA );
462 return FALSE;
465 lstrcpyW( profile, rgbprofile );
466 break;
468 default:
469 SetLastError( ERROR_FILE_NOT_FOUND );
470 return FALSE;
472 return TRUE;
475 static BOOL MSCMS_header_from_file( LPCWSTR file, PPROFILEHEADER header )
477 BOOL ret;
478 PROFILE profile;
479 WCHAR path[MAX_PATH], slash[] = {'\\',0};
480 DWORD size = sizeof(path);
481 HANDLE handle;
483 ret = GetColorDirectoryW( NULL, path, &size );
484 if (!ret)
486 WARN( "Can't retrieve color directory\n" );
487 return FALSE;
489 if (size + sizeof(slash) + sizeof(WCHAR) * lstrlenW( file ) > sizeof(path))
491 WARN( "Filename too long\n" );
492 return FALSE;
495 lstrcatW( path, slash );
496 lstrcatW( path, file );
498 profile.dwType = PROFILE_FILENAME;
499 profile.pProfileData = path;
500 profile.cbDataSize = lstrlenW( path ) + 1;
502 handle = OpenColorProfileW( &profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING );
503 if (!handle)
505 WARN( "Can't open color profile\n" );
506 return FALSE;
509 ret = GetColorProfileHeader( handle, header );
510 if (!ret)
511 WARN( "Can't retrieve color profile header\n" );
513 CloseColorProfile( handle );
514 return ret;
517 static BOOL MSCMS_match_profile( PENUMTYPEW rec, PPROFILEHEADER hdr )
519 if (rec->dwFields & ET_DEVICENAME)
521 FIXME( "ET_DEVICENAME: %s\n", debugstr_w(rec->pDeviceName) );
523 if (rec->dwFields & ET_MEDIATYPE)
525 FIXME( "ET_MEDIATYPE: 0x%08x\n", rec->dwMediaType );
527 if (rec->dwFields & ET_DITHERMODE)
529 FIXME( "ET_DITHERMODE: 0x%08x\n", rec->dwDitheringMode );
531 if (rec->dwFields & ET_RESOLUTION)
533 FIXME( "ET_RESOLUTION: 0x%08x, 0x%08x\n",
534 rec->dwResolution[0], rec->dwResolution[1] );
536 if (rec->dwFields & ET_DEVICECLASS)
538 FIXME( "ET_DEVICECLASS: %s\n", MSCMS_dbgstr_tag(rec->dwMediaType) );
540 if (rec->dwFields & ET_CMMTYPE)
542 TRACE( "ET_CMMTYPE: %s\n", MSCMS_dbgstr_tag(rec->dwCMMType) );
543 if (rec->dwCMMType != hdr->phCMMType) return FALSE;
545 if (rec->dwFields & ET_CLASS)
547 TRACE( "ET_CLASS: %s\n", MSCMS_dbgstr_tag(rec->dwClass) );
548 if (rec->dwClass != hdr->phClass) return FALSE;
550 if (rec->dwFields & ET_DATACOLORSPACE)
552 TRACE( "ET_DATACOLORSPACE: %s\n", MSCMS_dbgstr_tag(rec->dwDataColorSpace) );
553 if (rec->dwDataColorSpace != hdr->phDataColorSpace) return FALSE;
555 if (rec->dwFields & ET_CONNECTIONSPACE)
557 TRACE( "ET_CONNECTIONSPACE: %s\n", MSCMS_dbgstr_tag(rec->dwConnectionSpace) );
558 if (rec->dwConnectionSpace != hdr->phConnectionSpace) return FALSE;
560 if (rec->dwFields & ET_SIGNATURE)
562 TRACE( "ET_SIGNATURE: %s\n", MSCMS_dbgstr_tag(rec->dwSignature) );
563 if (rec->dwSignature != hdr->phSignature) return FALSE;
565 if (rec->dwFields & ET_PLATFORM)
567 TRACE( "ET_PLATFORM: %s\n", MSCMS_dbgstr_tag(rec->dwPlatform) );
568 if (rec->dwPlatform != hdr->phPlatform) return FALSE;
570 if (rec->dwFields & ET_PROFILEFLAGS)
572 TRACE( "ET_PROFILEFLAGS: 0x%08x\n", rec->dwProfileFlags );
573 if (rec->dwProfileFlags != hdr->phProfileFlags) return FALSE;
575 if (rec->dwFields & ET_MANUFACTURER)
577 TRACE( "ET_MANUFACTURER: %s\n", MSCMS_dbgstr_tag(rec->dwManufacturer) );
578 if (rec->dwManufacturer != hdr->phManufacturer) return FALSE;
580 if (rec->dwFields & ET_MODEL)
582 TRACE( "ET_MODEL: %s\n", MSCMS_dbgstr_tag(rec->dwModel) );
583 if (rec->dwModel != hdr->phModel) return FALSE;
585 if (rec->dwFields & ET_ATTRIBUTES)
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;
592 if (rec->dwFields & ET_RENDERINGINTENT)
594 TRACE( "ET_RENDERINGINTENT: 0x%08x\n", rec->dwRenderingIntent );
595 if (rec->dwRenderingIntent != hdr->phRenderingIntent) return FALSE;
597 if (rec->dwFields & ET_CREATOR)
599 TRACE( "ET_CREATOR: %s\n", MSCMS_dbgstr_tag(rec->dwCreator) );
600 if (rec->dwCreator != hdr->phCreator) return FALSE;
602 return TRUE;
605 /******************************************************************************
606 * EnumColorProfilesA [MSCMS.@]
608 * See EnumColorProfilesW.
610 BOOL WINAPI EnumColorProfilesA( PCSTR machine, PENUMTYPEA record, PBYTE buffer,
611 PDWORD size, PDWORD number )
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;
623 TRACE( "( %p, %p, %p, %p, %p )\n", machine, record, buffer, size, number );
625 if (machine || !record || !size ||
626 record->dwSize != sizeof(ENUMTYPEA) ||
627 record->dwVersion != ENUM_TYPE_VERSION) return FALSE;
629 ret = GetColorDirectoryA( machine, colordir, &len );
630 if (!ret || len + sizeof(spec) > MAX_PATH)
632 WARN( "can't retrieve color directory\n" );
633 return FALSE;
636 lstrcpyA( glob, colordir );
637 lstrcatA( glob, spec );
639 find = FindFirstFileA( glob, &data );
640 if (find == INVALID_HANDLE_VALUE) return FALSE;
642 profiles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(char *) + 1 );
643 if (!profiles) goto exit;
645 memcpy( &recordW, record, sizeof(ENUMTYPEA) );
646 if (record->pDeviceName)
648 deviceW = MSCMS_strdupW( record->pDeviceName );
649 if (!(recordW.pDeviceName = deviceW)) goto exit;
652 fileW = MSCMS_strdupW( data.cFileName );
653 if (!fileW) goto exit;
655 ret = MSCMS_header_from_file( fileW, &header );
656 if (ret)
658 match = MSCMS_match_profile( &recordW, &header );
659 if (match)
661 len = sizeof(char) * (lstrlenA( data.cFileName ) + 1);
662 profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
664 if (!profiles[count]) goto exit;
665 else
667 TRACE( "matching profile: %s\n", debugstr_a(data.cFileName) );
668 lstrcpyA( profiles[count], data.cFileName );
669 totalsize += len;
670 count++;
674 HeapFree( GetProcessHeap(), 0, fileW );
675 fileW = NULL;
677 while (FindNextFileA( find, &data ))
679 fileW = MSCMS_strdupW( data.cFileName );
680 if (!fileW) goto exit;
682 ret = MSCMS_header_from_file( fileW, &header );
683 if (!ret)
685 HeapFree( GetProcessHeap(), 0, fileW );
686 continue;
689 match = MSCMS_match_profile( &recordW, &header );
690 if (match)
692 char **tmp = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
693 profiles, sizeof(char *) * (count + 1) );
694 if (!tmp) goto exit;
695 else profiles = tmp;
697 len = sizeof(char) * (lstrlenA( data.cFileName ) + 1);
698 profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
700 if (!profiles[count]) goto exit;
701 else
703 TRACE( "matching profile: %s\n", debugstr_a(data.cFileName) );
704 lstrcpyA( profiles[count], data.cFileName );
705 totalsize += len;
706 count++;
709 HeapFree( GetProcessHeap(), 0, fileW );
710 fileW = NULL;
713 totalsize++;
714 if (buffer && *size >= totalsize)
716 char *p = (char *)buffer;
718 for (i = 0; i < count; i++)
720 lstrcpyA( p, profiles[i] );
721 p += lstrlenA( profiles[i] ) + 1;
723 *p = 0;
724 ret = TRUE;
726 else ret = FALSE;
728 *size = totalsize;
729 if (number) *number = count;
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 );
739 return ret;
742 /******************************************************************************
743 * EnumColorProfilesW [MSCMS.@]
745 * Enumerate profiles that match given criteria.
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.
755 * RETURNS
756 * Success: TRUE
757 * Failure: FALSE
759 BOOL WINAPI EnumColorProfilesW( PCWSTR machine, PENUMTYPEW record, PBYTE buffer,
760 PDWORD size, PDWORD number )
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;
770 TRACE( "( %p, %p, %p, %p, %p )\n", machine, record, buffer, size, number );
772 if (machine || !record || !size ||
773 record->dwSize != sizeof(ENUMTYPEW) ||
774 record->dwVersion != ENUM_TYPE_VERSION) return FALSE;
776 ret = GetColorDirectoryW( machine, colordir, &len );
777 if (!ret || len + sizeof(spec) > MAX_PATH)
779 WARN( "Can't retrieve color directory\n" );
780 return FALSE;
783 lstrcpyW( glob, colordir );
784 lstrcatW( glob, spec );
786 find = FindFirstFileW( glob, &data );
787 if (find == INVALID_HANDLE_VALUE) return FALSE;
789 profiles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR *) + 1 );
790 if (!profiles) goto exit;
792 ret = MSCMS_header_from_file( data.cFileName, &header );
793 if (ret)
795 match = MSCMS_match_profile( record, &header );
796 if (match)
798 len = sizeof(WCHAR) * (lstrlenW( data.cFileName ) + 1);
799 profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
801 if (!profiles[count]) goto exit;
802 else
804 TRACE( "matching profile: %s\n", debugstr_w(data.cFileName) );
805 lstrcpyW( profiles[count], data.cFileName );
806 totalsize += len;
807 count++;
812 while (FindNextFileW( find, &data ))
814 ret = MSCMS_header_from_file( data.cFileName, &header );
815 if (!ret) continue;
817 match = MSCMS_match_profile( record, &header );
818 if (match)
820 WCHAR **tmp = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
821 profiles, sizeof(WCHAR *) * (count + 1) );
822 if (!tmp) goto exit;
823 else profiles = tmp;
825 len = sizeof(WCHAR) * (lstrlenW( data.cFileName ) + 1);
826 profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
828 if (!profiles[count]) goto exit;
829 else
831 TRACE( "matching profile: %s\n", debugstr_w(data.cFileName) );
832 lstrcpyW( profiles[count], data.cFileName );
833 totalsize += len;
834 count++;
839 totalsize++;
840 if (buffer && *size >= totalsize)
842 WCHAR *p = (WCHAR *)buffer;
844 for (i = 0; i < count; i++)
846 lstrcpyW( p, profiles[i] );
847 p += lstrlenW( profiles[i] ) + 1;
849 *p = 0;
850 ret = TRUE;
852 else ret = FALSE;
854 *size = totalsize;
855 if (number) *number = count;
857 exit:
858 for (i = 0; i < count; i++)
859 HeapFree( GetProcessHeap(), 0, profiles[i] );
860 HeapFree( GetProcessHeap(), 0, profiles );
861 FindClose( find );
863 return ret;
866 /******************************************************************************
867 * InstallColorProfileA [MSCMS.@]
869 * See InstallColorProfileW.
871 BOOL WINAPI InstallColorProfileA( PCSTR machine, PCSTR profile )
873 UINT len;
874 LPWSTR profileW;
875 BOOL ret = FALSE;
877 TRACE( "( %s )\n", debugstr_a(profile) );
879 if (machine || !profile) return FALSE;
881 len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
882 profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
884 if (profileW)
886 MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
888 ret = InstallColorProfileW( NULL, profileW );
889 HeapFree( GetProcessHeap(), 0, profileW );
891 return ret;
894 /******************************************************************************
895 * InstallColorProfileW [MSCMS.@]
897 * Install a color profile.
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.
904 * RETURNS
905 * Success: TRUE
906 * Failure: FALSE
908 BOOL WINAPI InstallColorProfileW( PCWSTR machine, PCWSTR profile )
910 WCHAR dest[MAX_PATH], base[MAX_PATH];
911 DWORD size = sizeof(dest);
912 static const WCHAR slash[] = { '\\', 0 };
914 TRACE( "( %s )\n", debugstr_w(profile) );
916 if (machine || !profile) return FALSE;
918 if (!GetColorDirectoryW( machine, dest, &size )) return FALSE;
920 MSCMS_basename( profile, base );
922 lstrcatW( dest, slash );
923 lstrcatW( dest, base );
925 /* Is source equal to destination? */
926 if (!lstrcmpW( profile, dest )) return TRUE;
928 return CopyFileW( profile, dest, TRUE );
931 /******************************************************************************
932 * IsColorProfileTagPresent [MSCMS.@]
934 * Determine if a given ICC tag type is present in a color profile.
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.
942 * RETURNS
943 * Success: TRUE
944 * Failure: FALSE
946 BOOL WINAPI IsColorProfileTagPresent( HPROFILE profile, TAGTYPE type, PBOOL present )
948 BOOL ret = FALSE;
949 #ifdef HAVE_LCMS
950 icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
951 DWORD i, count;
952 icTag tag;
954 TRACE( "( %p, 0x%08x, %p )\n", profile, type, present );
956 if (!iccprofile || !present) return FALSE;
958 count = MSCMS_get_tag_count( iccprofile );
960 for (i = 0; i < count; i++)
962 MSCMS_get_tag_by_index( iccprofile, i, &tag );
964 if (tag.sig == type)
966 *present = ret = TRUE;
967 break;
971 #endif /* HAVE_LCMS */
972 return ret;
975 /******************************************************************************
976 * IsColorProfileValid [MSCMS.@]
978 * Determine if a given color profile is valid.
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.
985 * RETURNS
986 * Success: TRUE
987 * Failure: FALSE
989 BOOL WINAPI IsColorProfileValid( HPROFILE profile, PBOOL valid )
991 BOOL ret = FALSE;
992 #ifdef HAVE_LCMS
993 icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
995 TRACE( "( %p, %p )\n", profile, valid );
997 if (!valid) return FALSE;
998 if (iccprofile) return *valid = TRUE;
1000 #endif /* HAVE_LCMS */
1001 return ret;
1004 /******************************************************************************
1005 * SetColorProfileElement [MSCMS.@]
1007 * Set data for a specified tag type.
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.
1017 * RETURNS
1018 * Success: TRUE
1019 * Failure: FALSE
1021 BOOL WINAPI SetColorProfileElement( HPROFILE profile, TAGTYPE type, DWORD offset, PDWORD size,
1022 PVOID buffer )
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;
1030 TRACE( "( %p, 0x%08x, %d, %p, %p )\n", profile, type, offset, size, buffer );
1032 if (!iccprofile || !size || !buffer) return FALSE;
1033 if (!(access & PROFILE_READWRITE)) return FALSE;
1035 count = MSCMS_get_tag_count( iccprofile );
1037 for (i = 0; i < count; i++)
1039 MSCMS_get_tag_by_index( iccprofile, i, &tag );
1041 if (tag.sig == type)
1043 if (offset > tag.size) return FALSE;
1045 MSCMS_set_tag_data( iccprofile, &tag, offset, buffer );
1046 return TRUE;
1050 #endif /* HAVE_LCMS */
1051 return ret;
1054 /******************************************************************************
1055 * SetColorProfileHeader [MSCMS.@]
1057 * Set header data for a given profile.
1059 * PARAMS
1060 * profile [I] Handle to a color profile.
1061 * header [I] Buffer holding the header data.
1063 * RETURNS
1064 * Success: TRUE
1065 * Failure: FALSE
1067 BOOL WINAPI SetColorProfileHeader( HPROFILE profile, PPROFILEHEADER header )
1069 #ifdef HAVE_LCMS
1070 icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
1071 DWORD access = MSCMS_hprofile2access( profile );
1073 TRACE( "( %p, %p )\n", profile, header );
1075 if (!iccprofile || !header) return FALSE;
1076 if (!(access & PROFILE_READWRITE)) return FALSE;
1078 MSCMS_set_profile_header( iccprofile, header );
1079 return TRUE;
1081 #else
1082 return FALSE;
1083 #endif /* HAVE_LCMS */
1086 /******************************************************************************
1087 * UninstallColorProfileA [MSCMS.@]
1089 * See UninstallColorProfileW.
1091 BOOL WINAPI UninstallColorProfileA( PCSTR machine, PCSTR profile, BOOL delete )
1093 UINT len;
1094 LPWSTR profileW;
1095 BOOL ret = FALSE;
1097 TRACE( "( %s, %x )\n", debugstr_a(profile), delete );
1099 if (machine || !profile) return FALSE;
1101 len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
1102 profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1104 if (profileW)
1106 MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
1108 ret = UninstallColorProfileW( NULL, profileW , delete );
1110 HeapFree( GetProcessHeap(), 0, profileW );
1112 return ret;
1115 /******************************************************************************
1116 * UninstallColorProfileW [MSCMS.@]
1118 * Uninstall a color profile.
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.
1126 * RETURNS
1127 * Success: TRUE
1128 * Failure: FALSE
1130 BOOL WINAPI UninstallColorProfileW( PCWSTR machine, PCWSTR profile, BOOL delete )
1132 TRACE( "( %s, %x )\n", debugstr_w(profile), delete );
1134 if (machine || !profile) return FALSE;
1136 if (delete) return DeleteFileW( profile );
1138 return TRUE;
1141 /******************************************************************************
1142 * OpenColorProfileA [MSCMS.@]
1144 * See OpenColorProfileW.
1146 HPROFILE WINAPI OpenColorProfileA( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
1148 HPROFILE handle = NULL;
1150 TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile, access, sharing, creation );
1152 if (!profile || !profile->pProfileData) return NULL;
1154 /* No AW conversion needed for memory based profiles */
1155 if (profile->dwType & PROFILE_MEMBUFFER)
1156 return OpenColorProfileW( profile, access, sharing, creation );
1158 if (profile->dwType & PROFILE_FILENAME)
1160 UINT len;
1161 PROFILE profileW;
1163 profileW.dwType = profile->dwType;
1165 len = MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, NULL, 0 );
1166 profileW.pProfileData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1168 if (profileW.pProfileData)
1170 profileW.cbDataSize = len * sizeof(WCHAR);
1171 MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, profileW.pProfileData, len );
1173 handle = OpenColorProfileW( &profileW, access, sharing, creation );
1174 HeapFree( GetProcessHeap(), 0, profileW.pProfileData );
1177 return handle;
1180 /******************************************************************************
1181 * OpenColorProfileW [MSCMS.@]
1183 * Open a color profile.
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.
1191 * RETURNS
1192 * Success: Handle to the opened profile.
1193 * Failure: NULL
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.
1202 HPROFILE WINAPI OpenColorProfileW( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
1204 #ifdef HAVE_LCMS
1205 cmsHPROFILE cmsprofile = NULL;
1206 icProfile *iccprofile = NULL;
1207 HANDLE handle = NULL;
1208 DWORD size;
1210 TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile, access, sharing, creation );
1212 if (!profile || !profile->pProfileData) return NULL;
1214 if (profile->dwType & PROFILE_MEMBUFFER)
1216 /* FIXME: access flags not implemented for memory based profiles */
1218 iccprofile = profile->pProfileData;
1219 size = profile->cbDataSize;
1221 cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
1224 if (profile->dwType & PROFILE_FILENAME)
1226 DWORD read, flags = 0;
1228 TRACE( "profile file: %s\n", debugstr_w( (WCHAR *)profile->pProfileData ) );
1230 if (access & PROFILE_READ) flags = GENERIC_READ;
1231 if (access & PROFILE_READWRITE) flags = GENERIC_READ|GENERIC_WRITE;
1233 if (!flags) return NULL;
1235 handle = CreateFileW( profile->pProfileData, flags, sharing, NULL, creation, 0, NULL );
1236 if (handle == INVALID_HANDLE_VALUE)
1238 WARN( "Unable to open color profile\n" );
1239 return NULL;
1242 if ((size = GetFileSize( handle, NULL )) == INVALID_FILE_SIZE)
1244 ERR( "Unable to retrieve size of color profile\n" );
1245 CloseHandle( handle );
1246 return NULL;
1249 iccprofile = HeapAlloc( GetProcessHeap(), 0, size );
1250 if (!iccprofile)
1252 ERR( "Unable to allocate memory for color profile\n" );
1253 CloseHandle( handle );
1254 return NULL;
1257 if (!ReadFile( handle, iccprofile, size, &read, NULL ) || read != size)
1259 ERR( "Unable to read color profile\n" );
1261 CloseHandle( handle );
1262 HeapFree( GetProcessHeap(), 0, iccprofile );
1263 return NULL;
1266 cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
1269 if (cmsprofile)
1270 return MSCMS_create_hprofile_handle( handle, iccprofile, cmsprofile, access );
1272 #endif /* HAVE_LCMS */
1273 return NULL;
1276 /******************************************************************************
1277 * CloseColorProfile [MSCMS.@]
1279 * Close a color profile.
1281 * PARAMS
1282 * profile [I] Handle to the profile.
1284 * RETURNS
1285 * Success: TRUE
1286 * Failure: FALSE
1288 BOOL WINAPI CloseColorProfile( HPROFILE profile )
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 );
1296 TRACE( "( %p )\n", profile );
1298 if (file && (access & PROFILE_READWRITE))
1300 DWORD written, size = MSCMS_get_profile_size( iccprofile );
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" );
1307 ret = cmsCloseProfile( MSCMS_hprofile2cmsprofile( profile ) );
1308 HeapFree( GetProcessHeap(), 0, MSCMS_hprofile2iccprofile( profile ) );
1310 CloseHandle( MSCMS_hprofile2handle( profile ) );
1311 MSCMS_destroy_hprofile_handle( profile );
1313 #endif /* HAVE_LCMS */
1314 return ret;