diff --git a/reactos/baseaddress.rbuild b/reactos/baseaddress.rbuild
index 76c98778079..04965b3a154 100644
--- a/reactos/baseaddress.rbuild
+++ b/reactos/baseaddress.rbuild
@@ -13,6 +13,7 @@
+
@@ -116,8 +117,10 @@
+
+
diff --git a/reactos/boot/bootdata/packages/reactos.dff b/reactos/boot/bootdata/packages/reactos.dff
index b95007eae58..726c508bd76 100644
--- a/reactos/boot/bootdata/packages/reactos.dff
+++ b/reactos/boot/bootdata/packages/reactos.dff
@@ -298,13 +298,16 @@ dll\win32\mprapi\mprapi.dll 1
dll\win32\msacm32\msacm32.dll 1
dll\win32\msafd\msafd.dll 1
dll\win32\mscat32\mscat32.dll 1
+dll\win32\mscms\mscms.dll 1
dll\win32\mscoree\mscoree.dll 1
+dll\win32\msftedit\msftedit.dll 1
dll\win32\msgina\msgina.dll 1
dll\win32\mshtml\mshtml.dll 1
dll\win32\mshtml.tlb\mshtml.tlb 1
dll\win32\msi\msi.dll 1
dll\win32\msimg32\msimg32.dll 1
dll\win32\msimtf\msimtf.dll 1
+dll\win32\msrle32\msrle32.dll 1
dll\win32\mstask\mstask.dll 1
dll\win32\msvcrt\msvcrt.dll 1
dll\win32\msvcrt20\msvcrt20.dll 1
diff --git a/reactos/dll/win32/mscms/handle.c b/reactos/dll/win32/mscms/handle.c
new file mode 100644
index 00000000000..84f1d8ba30f
--- /dev/null
+++ b/reactos/dll/win32/mscms/handle.c
@@ -0,0 +1,250 @@
+/*
+ * MSCMS - Color Management System for Wine
+ *
+ * Copyright 2004, 2005, 2008 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "wine/debug.h"
+
+#include
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "icm.h"
+
+#include "mscms_priv.h"
+
+#ifdef HAVE_LCMS
+
+static CRITICAL_SECTION MSCMS_handle_cs;
+static CRITICAL_SECTION_DEBUG MSCMS_handle_cs_debug =
+{
+ 0, 0, &MSCMS_handle_cs,
+ { &MSCMS_handle_cs_debug.ProcessLocksList,
+ &MSCMS_handle_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": MSCMS_handle_cs") }
+};
+static CRITICAL_SECTION MSCMS_handle_cs = { &MSCMS_handle_cs_debug, -1, 0, 0, 0, 0 };
+
+static struct profile *profiletable;
+static struct transform *transformtable;
+
+static unsigned int num_profile_handles;
+static unsigned int num_transform_handles;
+
+WINE_DEFAULT_DEBUG_CHANNEL(mscms);
+
+void free_handle_tables( void )
+{
+ HeapFree( GetProcessHeap(), 0, profiletable );
+ profiletable = NULL;
+ num_profile_handles = 0;
+
+ HeapFree( GetProcessHeap(), 0, transformtable );
+ transformtable = NULL;
+ num_transform_handles = 0;
+}
+
+struct profile *grab_profile( HPROFILE handle )
+{
+ DWORD_PTR index;
+
+ EnterCriticalSection( &MSCMS_handle_cs );
+
+ index = (DWORD_PTR)handle - 1;
+ if (index > num_profile_handles)
+ {
+ LeaveCriticalSection( &MSCMS_handle_cs );
+ return NULL;
+ }
+ return &profiletable[index];
+}
+
+void release_profile( struct profile *profile )
+{
+ LeaveCriticalSection( &MSCMS_handle_cs );
+}
+
+struct transform *grab_transform( HTRANSFORM handle )
+{
+ DWORD_PTR index;
+
+ EnterCriticalSection( &MSCMS_handle_cs );
+
+ index = (DWORD_PTR)handle - 1;
+ if (index > num_transform_handles)
+ {
+ LeaveCriticalSection( &MSCMS_handle_cs );
+ return NULL;
+ }
+ return &transformtable[index];
+}
+
+void release_transform( struct transform *transform )
+{
+ LeaveCriticalSection( &MSCMS_handle_cs );
+}
+
+static HPROFILE alloc_profile_handle( void )
+{
+ DWORD_PTR index;
+ struct profile *p;
+ unsigned int count = 128;
+
+ for (index = 0; index < num_profile_handles; index++)
+ {
+ if (!profiletable[index].iccprofile) return (HPROFILE)(index + 1);
+ }
+ if (!profiletable)
+ {
+ p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(struct profile) );
+ }
+ else
+ {
+ count = num_profile_handles * 2;
+ p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, profiletable, count * sizeof(struct profile) );
+ }
+ if (!p) return NULL;
+
+ profiletable = p;
+ num_profile_handles = count;
+
+ return (HPROFILE)(index + 1);
+}
+
+HPROFILE create_profile( struct profile *profile )
+{
+ HPROFILE handle;
+
+ EnterCriticalSection( &MSCMS_handle_cs );
+
+ if ((handle = alloc_profile_handle()))
+ {
+ DWORD_PTR index = (DWORD_PTR)handle - 1;
+ memcpy( &profiletable[index], profile, sizeof(struct profile) );
+ }
+ LeaveCriticalSection( &MSCMS_handle_cs );
+ return handle;
+}
+
+BOOL close_profile( HPROFILE handle )
+{
+ DWORD_PTR index;
+ struct profile *profile;
+
+ EnterCriticalSection( &MSCMS_handle_cs );
+
+ index = (DWORD_PTR)handle - 1;
+ if (index > num_profile_handles)
+ {
+ LeaveCriticalSection( &MSCMS_handle_cs );
+ return FALSE;
+ }
+ profile = &profiletable[index];
+
+ if (profile->file != INVALID_HANDLE_VALUE)
+ {
+ if (profile->access & PROFILE_READWRITE)
+ {
+ DWORD written, size = MSCMS_get_profile_size( profile->iccprofile );
+
+ if (SetFilePointer( profile->file, 0, NULL, FILE_BEGIN ) ||
+ !WriteFile( profile->file, profile->iccprofile, size, &written, NULL ) ||
+ written != size)
+ {
+ ERR( "Unable to write color profile\n" );
+ }
+ }
+ CloseHandle( profile->file );
+ }
+ cmsCloseProfile( profile->cmsprofile );
+ HeapFree( GetProcessHeap(), 0, profile->iccprofile );
+
+ memset( profile, 0, sizeof(struct profile) );
+
+ LeaveCriticalSection( &MSCMS_handle_cs );
+ return TRUE;
+}
+
+static HTRANSFORM alloc_transform_handle( void )
+{
+ DWORD_PTR index;
+ struct transform *p;
+ unsigned int count = 128;
+
+ for (index = 0; index < num_transform_handles; index++)
+ {
+ if (!transformtable[index].cmstransform) return (HTRANSFORM)(index + 1);
+ }
+ if (!transformtable)
+ {
+ p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(struct transform) );
+ }
+ else
+ {
+ count = num_transform_handles * 2;
+ p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, transformtable, count * sizeof(struct transform) );
+ }
+ if (!p) return NULL;
+
+ transformtable = p;
+ num_transform_handles = count;
+
+ return (HTRANSFORM)(index + 1);
+}
+
+HTRANSFORM create_transform( struct transform *transform )
+{
+ HTRANSFORM handle;
+
+ EnterCriticalSection( &MSCMS_handle_cs );
+
+ if ((handle = alloc_transform_handle()))
+ {
+ DWORD_PTR index = (DWORD_PTR)handle - 1;
+ memcpy( &transformtable[index], transform, sizeof(struct transform) );
+ }
+ LeaveCriticalSection( &MSCMS_handle_cs );
+ return handle;
+}
+
+BOOL close_transform( HTRANSFORM handle )
+{
+ DWORD_PTR index;
+ struct transform *transform;
+
+ EnterCriticalSection( &MSCMS_handle_cs );
+
+ index = (DWORD_PTR)handle - 1;
+ if (index > num_transform_handles)
+ {
+ LeaveCriticalSection( &MSCMS_handle_cs );
+ return FALSE;
+ }
+ transform = &transformtable[index];
+
+ cmsDeleteTransform( transform->cmstransform );
+ memset( transform, 0, sizeof(struct transform) );
+
+ LeaveCriticalSection( &MSCMS_handle_cs );
+ return TRUE;
+}
+
+#endif /* HAVE_LCMS */
diff --git a/reactos/dll/win32/mscms/icc.c b/reactos/dll/win32/mscms/icc.c
new file mode 100644
index 00000000000..67b65ed6643
--- /dev/null
+++ b/reactos/dll/win32/mscms/icc.c
@@ -0,0 +1,105 @@
+/*
+ * MSCMS - Color Management System for Wine
+ *
+ * Copyright 2004, 2005 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winternl.h"
+#include "icm.h"
+
+#include "mscms_priv.h"
+
+#ifdef HAVE_LCMS
+
+static inline void MSCMS_adjust_endianess32( ULONG *ptr )
+{
+#ifndef WORDS_BIGENDIAN
+ *ptr = RtlUlongByteSwap(*ptr);
+#endif
+}
+
+void MSCMS_get_profile_header( const icProfile *iccprofile, PROFILEHEADER *header )
+{
+ unsigned int i;
+
+ memcpy( header, iccprofile, sizeof(PROFILEHEADER) );
+
+ /* ICC format is big-endian, swap bytes if necessary */
+ for (i = 0; i < sizeof(PROFILEHEADER) / sizeof(ULONG); i++)
+ MSCMS_adjust_endianess32( (ULONG *)header + i );
+}
+
+void MSCMS_set_profile_header( icProfile *iccprofile, const PROFILEHEADER *header )
+{
+ unsigned int i;
+ icHeader *iccheader = (icHeader *)iccprofile;
+
+ memcpy( iccheader, header, sizeof(icHeader) );
+
+ /* ICC format is big-endian, swap bytes if necessary */
+ for (i = 0; i < sizeof(icHeader) / sizeof(ULONG); i++)
+ MSCMS_adjust_endianess32( (ULONG *)iccheader + i );
+}
+
+DWORD MSCMS_get_tag_count( const icProfile *iccprofile )
+{
+ ULONG count = iccprofile->count;
+
+ MSCMS_adjust_endianess32( &count );
+ return count;
+}
+
+void MSCMS_get_tag_by_index( icProfile *iccprofile, DWORD index, icTag *tag )
+{
+ icTag *tmp = (icTag *)((char *)iccprofile->data + index * sizeof(icTag));
+
+ tag->sig = tmp->sig;
+ tag->offset = tmp->offset;
+ tag->size = tmp->size;
+
+ MSCMS_adjust_endianess32( &tag->sig );
+ MSCMS_adjust_endianess32( &tag->offset );
+ MSCMS_adjust_endianess32( &tag->size );
+}
+
+void MSCMS_get_tag_data( const icProfile *iccprofile, const icTag *tag, DWORD offset, void *buffer )
+{
+ memcpy( buffer, (const char *)iccprofile + tag->offset + offset, tag->size - offset );
+}
+
+void MSCMS_set_tag_data( icProfile *iccprofile, const icTag *tag, DWORD offset, const void *buffer )
+{
+ memcpy( (char *)iccprofile + tag->offset + offset, buffer, tag->size - offset );
+}
+
+DWORD MSCMS_get_profile_size( const icProfile *iccprofile )
+{
+ DWORD size = ((const icHeader *)iccprofile)->size;
+
+ MSCMS_adjust_endianess32( &size );
+ return size;
+}
+
+#endif /* HAVE_LCMS */
diff --git a/reactos/dll/win32/mscms/mscms.rbuild b/reactos/dll/win32/mscms/mscms.rbuild
new file mode 100644
index 00000000000..49e3866d165
--- /dev/null
+++ b/reactos/dll/win32/mscms/mscms.rbuild
@@ -0,0 +1,17 @@
+
+
+ .
+ include/reactos/wine
+
+ handle.c
+ icc.c
+ mscms_main.c
+ profile.c
+ stub.c
+ transform.c
+ version.rc
+ wine
+ advapi32
+ kernel32
+ ntdll
+
diff --git a/reactos/dll/win32/mscms/mscms.spec b/reactos/dll/win32/mscms/mscms.spec
new file mode 100644
index 00000000000..f728c7950bf
--- /dev/null
+++ b/reactos/dll/win32/mscms/mscms.spec
@@ -0,0 +1,61 @@
+@ stdcall AssociateColorProfileWithDeviceA(ptr ptr ptr)
+@ stdcall AssociateColorProfileWithDeviceW(ptr ptr ptr)
+@ stdcall CheckBitmapBits(ptr ptr ptr long long long ptr ptr long)
+@ stdcall CheckColors(ptr ptr long long ptr)
+@ stdcall CloseColorProfile(ptr)
+@ stdcall ConvertColorNameToIndex(ptr ptr ptr long)
+@ stdcall ConvertIndexToColorName(ptr ptr ptr long)
+@ stdcall CreateColorTransformA(ptr ptr ptr long)
+@ stdcall CreateColorTransformW(ptr ptr ptr long)
+@ stdcall CreateDeviceLinkProfile(ptr long ptr long long ptr long)
+@ stdcall CreateMultiProfileTransform(ptr long ptr long long long)
+@ stdcall CreateProfileFromLogColorSpaceA(ptr ptr)
+@ stdcall CreateProfileFromLogColorSpaceW(ptr ptr)
+@ stdcall DeleteColorTransform(ptr)
+@ stdcall DisassociateColorProfileFromDeviceA(ptr ptr ptr)
+@ stdcall DisassociateColorProfileFromDeviceW(ptr ptr ptr)
+@ stdcall EnumColorProfilesA(ptr ptr ptr ptr ptr)
+@ stdcall EnumColorProfilesW(ptr ptr ptr ptr ptr)
+@ stdcall GenerateCopyFilePaths(wstr wstr ptr long ptr ptr ptr ptr long)
+@ stdcall GetCMMInfo(ptr long)
+@ stdcall GetColorDirectoryA(ptr ptr long)
+@ stdcall GetColorDirectoryW(ptr ptr long)
+@ stdcall GetColorProfileElement(ptr long long ptr ptr ptr)
+@ stdcall GetColorProfileElementTag(ptr long ptr)
+@ stdcall GetColorProfileFromHandle(ptr ptr ptr)
+@ stdcall GetColorProfileHeader(ptr ptr)
+@ stdcall GetCountColorProfileElements(ptr long)
+@ stdcall GetNamedProfileInfo(ptr ptr)
+@ stdcall GetPS2ColorRenderingDictionary(ptr long ptr ptr ptr)
+@ stdcall GetPS2ColorRenderingIntent(ptr long ptr ptr)
+@ stdcall GetPS2ColorSpaceArray(ptr long long ptr ptr ptr)
+@ stdcall GetStandardColorSpaceProfileA(ptr long ptr ptr)
+@ stdcall GetStandardColorSpaceProfileW(ptr long ptr ptr)
+@ stdcall InstallColorProfileA(ptr ptr)
+@ stdcall InstallColorProfileW(ptr ptr)
+@ stub InternalGetDeviceConfig
+@ stub InternalGetPS2CSAFromLCS
+@ stub InternalGetPS2ColorRenderingDictionary
+@ stub InternalGetPS2ColorSpaceArray
+@ stub InternalGetPS2PreviewCRD
+@ stub InternalSetDeviceConfig
+@ stdcall IsColorProfileTagPresent(ptr long ptr)
+@ stdcall IsColorProfileValid(ptr long)
+@ stdcall OpenColorProfileA(ptr long long long)
+@ stdcall OpenColorProfileW(ptr long long long)
+@ stdcall RegisterCMMA(ptr long ptr)
+@ stdcall RegisterCMMW(ptr long ptr)
+@ stdcall SelectCMM(long)
+@ stdcall SetColorProfileElement(ptr long long ptr ptr)
+@ stdcall SetColorProfileElementReference(ptr long long)
+@ stdcall SetColorProfileElementSize(ptr long long)
+@ stdcall SetColorProfileHeader(ptr ptr)
+@ stdcall SetStandardColorSpaceProfileA(ptr long ptr)
+@ stdcall SetStandardColorSpaceProfileW(ptr long ptr)
+@ stdcall SpoolerCopyFileEvent(wstr wstr long)
+@ stdcall TranslateBitmapBits(ptr ptr long long long long ptr long long ptr long)
+@ stdcall TranslateColors(ptr ptr long long ptr long)
+@ stdcall UninstallColorProfileA(ptr ptr long)
+@ stdcall UninstallColorProfileW(ptr ptr long)
+@ stdcall UnregisterCMMA(ptr long)
+@ stdcall UnregisterCMMW(ptr long)
diff --git a/reactos/dll/win32/mscms/mscms_main.c b/reactos/dll/win32/mscms/mscms_main.c
new file mode 100644
index 00000000000..00e2a753e87
--- /dev/null
+++ b/reactos/dll/win32/mscms/mscms_main.c
@@ -0,0 +1,55 @@
+/*
+ * MSCMS - Color Management System for Wine
+ *
+ * Copyright 2004, 2005 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include "wine/port.h"
+#include "wine/debug.h"
+#include "wine/library.h"
+
+#include
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "icm.h"
+
+#include "mscms_priv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mscms);
+
+BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
+{
+ TRACE( "(%p, %d, %p)\n", hinst, reason, reserved );
+
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls( hinst );
+ break;
+ case DLL_PROCESS_DETACH:
+#ifdef HAVE_LCMS
+ free_handle_tables();
+#endif
+ break;
+ }
+ return TRUE;
+}
diff --git a/reactos/dll/win32/mscms/mscms_priv.h b/reactos/dll/win32/mscms/mscms_priv.h
new file mode 100644
index 00000000000..479148bee80
--- /dev/null
+++ b/reactos/dll/win32/mscms/mscms_priv.h
@@ -0,0 +1,114 @@
+/*
+ * MSCMS - Color Management System for Wine
+ *
+ * Copyright 2004, 2005 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_LCMS
+
+/* These basic Windows types are defined in lcms.h when compiling on
+ * a non-Windows platform (why?), so they would normally not conflict
+ * with anything included earlier. But since we are building Wine they
+ * most certainly will have been defined before we include lcms.h.
+ * The preprocessor comes to the rescue.
+ */
+
+#define BYTE LCMS_BYTE
+#define LPBYTE LCMS_LPBYTE
+#define WORD LCMS_WORD
+#define LPWORD LCMS_LPWORD
+#define DWORD LCMS_DWORD
+#define LPDWORD LCMS_LPDWORD
+#define BOOL LCMS_BOOL
+#define LPSTR LCMS_LPSTR
+#define LPVOID LCMS_LPVOID
+
+#undef cdecl
+#undef FAR
+
+#undef ZeroMemory
+#undef CopyMemory
+
+#undef LOWORD
+#undef HIWORD
+#undef MAX_PATH
+
+#ifdef HAVE_LCMS_LCMS_H
+#include
+#else
+#include
+#endif
+
+/* Funny thing is lcms.h defines DWORD as an 'unsigned long' whereas Wine
+ * defines it as an 'unsigned int'. To avoid compiler warnings we use a
+ * preprocessor define for DWORD and LPDWORD to get back Wine's original
+ * (typedef) definitions.
+ */
+
+#undef BOOL
+#undef DWORD
+#undef LPDWORD
+
+#define BOOL BOOL
+#define DWORD DWORD
+#define LPDWORD LPDWORD
+
+/* A simple structure to tie together a pointer to an icc profile, an lcms
+ * color profile handle and a Windows file handle. If the profile is memory
+ * based the file handle field is set to INVALID_HANDLE_VALUE. The 'access'
+ * field records the access parameter supplied to an OpenColorProfile()
+ * call, i.e. PROFILE_READ or PROFILE_READWRITE.
+ */
+
+struct profile
+{
+ HANDLE file;
+ DWORD access;
+ icProfile *iccprofile;
+ cmsHPROFILE cmsprofile;
+};
+
+struct transform
+{
+ cmsHTRANSFORM cmstransform;
+};
+
+extern HPROFILE create_profile( struct profile * );
+extern BOOL close_profile( HPROFILE );
+
+extern HTRANSFORM create_transform( struct transform * );
+extern BOOL close_transform( HTRANSFORM );
+
+struct profile *grab_profile( HPROFILE );
+struct transform *grab_transform( HTRANSFORM );
+
+void release_profile( struct profile * );
+void release_transform( struct transform * );
+
+extern void free_handle_tables( void );
+
+extern DWORD MSCMS_get_tag_count( const icProfile *iccprofile );
+extern void MSCMS_get_tag_by_index( icProfile *iccprofile, DWORD index, icTag *tag );
+extern void MSCMS_get_tag_data( const icProfile *iccprofile, const icTag *tag, DWORD offset, void *buffer );
+extern void MSCMS_set_tag_data( icProfile *iccprofile, const icTag *tag, DWORD offset, const void *buffer );
+extern void MSCMS_get_profile_header( const icProfile *iccprofile, PROFILEHEADER *header );
+extern void MSCMS_set_profile_header( icProfile *iccprofile, const PROFILEHEADER *header );
+extern DWORD MSCMS_get_profile_size( const icProfile *iccprofile );
+
+extern const char *MSCMS_dbgstr_tag(DWORD);
+
+#endif /* HAVE_LCMS */
diff --git a/reactos/dll/win32/mscms/profile.c b/reactos/dll/win32/mscms/profile.c
new file mode 100644
index 00000000000..1c6811e0689
--- /dev/null
+++ b/reactos/dll/win32/mscms/profile.c
@@ -0,0 +1,1549 @@
+/*
+ * MSCMS - Color Management System for Wine
+ *
+ * Copyright 2004, 2005, 2006, 2008 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+#include
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "icm.h"
+
+#include "mscms_priv.h"
+
+#define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/')
+
+static void MSCMS_basename( LPCWSTR path, LPWSTR name )
+{
+ INT i = lstrlenW( path );
+
+ while (i > 0 && !IS_SEPARATOR(path[i - 1])) i--;
+ lstrcpyW( name, &path[i] );
+}
+
+static inline LPWSTR MSCMS_strdupW( LPCSTR str )
+{
+ LPWSTR ret = NULL;
+ if (str)
+ {
+ DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
+ if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+ MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
+ }
+ return ret;
+}
+
+const char *MSCMS_dbgstr_tag( DWORD tag )
+{
+ return wine_dbg_sprintf( "'%c%c%c%c'",
+ (char)(tag >> 24), (char)(tag >> 16), (char)(tag >> 8), (char)(tag) );
+}
+
+WINE_DEFAULT_DEBUG_CHANNEL(mscms);
+
+/******************************************************************************
+ * AssociateColorProfileWithDeviceA [MSCMS.@]
+ */
+BOOL WINAPI AssociateColorProfileWithDeviceA( PCSTR machine, PCSTR profile, PCSTR device )
+{
+ int len;
+ BOOL ret = FALSE;
+ WCHAR *profileW, *deviceW;
+
+ TRACE( "( %s, %s, %s )\n", debugstr_a(machine), debugstr_a(profile), debugstr_a(device) );
+
+ if (!profile || !device)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+ if (machine)
+ {
+ SetLastError( ERROR_NOT_SUPPORTED );
+ return FALSE;
+ }
+
+ len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
+ if (!(profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
+
+ MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
+
+ len = MultiByteToWideChar( CP_ACP, 0, device, -1, NULL, 0 );
+ if ((deviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+ {
+ MultiByteToWideChar( CP_ACP, 0, device, -1, deviceW, len );
+ ret = AssociateColorProfileWithDeviceW( NULL, profileW, deviceW );
+ }
+
+ HeapFree( GetProcessHeap(), 0, profileW );
+ HeapFree( GetProcessHeap(), 0, deviceW );
+ return ret;
+}
+
+static BOOL set_profile_device_key( PCWSTR file, const BYTE *value, DWORD size )
+{
+ static const WCHAR fmtW[] = {'%','c','%','c','%','c','%','c',0};
+ static const WCHAR icmW[] = {'S','o','f','t','w','a','r','e','\\',
+ 'M','i','c','r','o','s','o','f','t','\\',
+ 'W','i','n','d','o','w','s',' ','N','T','\\',
+ 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+ 'I','C','M',0};
+ PROFILEHEADER header;
+ PROFILE profile;
+ HPROFILE handle;
+ HKEY icm_key, class_key;
+ WCHAR basenameW[MAX_PATH], classW[5];
+
+ profile.dwType = PROFILE_FILENAME;
+ profile.pProfileData = (PVOID)file;
+ profile.cbDataSize = (lstrlenW( file ) + 1) * sizeof(WCHAR);
+
+ /* FIXME is the profile installed? */
+ if (!(handle = OpenColorProfileW( &profile, PROFILE_READ, 0, OPEN_EXISTING )))
+ {
+ SetLastError( ERROR_INVALID_PROFILE );
+ return FALSE;
+ }
+ if (!GetColorProfileHeader( handle, &header ))
+ {
+ CloseColorProfile( handle );
+ SetLastError( ERROR_INVALID_PROFILE );
+ return FALSE;
+ }
+ RegCreateKeyExW( HKEY_LOCAL_MACHINE, icmW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &icm_key, NULL );
+
+ MSCMS_basename( file, basenameW );
+ sprintfW( classW, fmtW, (header.phClass >> 24) & 0xff, (header.phClass >> 16) & 0xff,
+ (header.phClass >> 8) & 0xff, header.phClass & 0xff );
+
+ RegCreateKeyExW( icm_key, classW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &class_key, NULL );
+ if (value) RegSetValueExW( class_key, basenameW, 0, REG_BINARY, value, size );
+ else RegDeleteValueW( class_key, basenameW );
+
+ RegCloseKey( class_key );
+ RegCloseKey( icm_key );
+ CloseColorProfile( handle );
+ return TRUE;
+}
+
+/******************************************************************************
+ * AssociateColorProfileWithDeviceW [MSCMS.@]
+ */
+BOOL WINAPI AssociateColorProfileWithDeviceW( PCWSTR machine, PCWSTR profile, PCWSTR device )
+{
+ static const BYTE dummy_value[12];
+
+ TRACE( "( %s, %s, %s )\n", debugstr_w(machine), debugstr_w(profile), debugstr_w(device) );
+
+ if (!profile || !device)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+ if (machine)
+ {
+ SetLastError( ERROR_NOT_SUPPORTED );
+ return FALSE;
+ }
+
+ return set_profile_device_key( profile, dummy_value, sizeof(dummy_value) );
+}
+
+/******************************************************************************
+ * DisassociateColorProfileFromDeviceA [MSCMS.@]
+ */
+BOOL WINAPI DisassociateColorProfileFromDeviceA( PCSTR machine, PCSTR profile, PCSTR device )
+{
+ int len;
+ BOOL ret = FALSE;
+ WCHAR *profileW, *deviceW;
+
+ TRACE( "( %s, %s, %s )\n", debugstr_a(machine), debugstr_a(profile), debugstr_a(device) );
+
+ if (!profile || !device)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+ if (machine)
+ {
+ SetLastError( ERROR_NOT_SUPPORTED );
+ return FALSE;
+ }
+
+ len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
+ if (!(profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
+
+ MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
+
+ len = MultiByteToWideChar( CP_ACP, 0, device, -1, NULL, 0 );
+ if ((deviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+ {
+ MultiByteToWideChar( CP_ACP, 0, device, -1, deviceW, len );
+ ret = DisassociateColorProfileFromDeviceW( NULL, profileW, deviceW );
+ }
+
+ HeapFree( GetProcessHeap(), 0, profileW );
+ HeapFree( GetProcessHeap(), 0, deviceW );
+ return ret;
+}
+
+/******************************************************************************
+ * DisassociateColorProfileFromDeviceW [MSCMS.@]
+ */
+BOOL WINAPI DisassociateColorProfileFromDeviceW( PCWSTR machine, PCWSTR profile, PCWSTR device )
+{
+ TRACE( "( %s, %s, %s )\n", debugstr_w(machine), debugstr_w(profile), debugstr_w(device) );
+
+ if (!profile || !device)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+ if (machine)
+ {
+ SetLastError( ERROR_NOT_SUPPORTED );
+ return FALSE;
+ }
+
+ return set_profile_device_key( profile, NULL, 0 );
+}
+
+/******************************************************************************
+ * GetColorDirectoryA [MSCMS.@]
+ *
+ * See GetColorDirectoryW.
+ */
+BOOL WINAPI GetColorDirectoryA( PCSTR machine, PSTR buffer, PDWORD size )
+{
+ INT len;
+ LPWSTR bufferW;
+ BOOL ret = FALSE;
+ DWORD sizeW;
+
+ TRACE( "( %p, %p )\n", buffer, size );
+
+ if (machine || !size) return FALSE;
+
+ if (!buffer)
+ {
+ ret = GetColorDirectoryW( NULL, NULL, &sizeW );
+ *size = sizeW / sizeof(WCHAR);
+ return FALSE;
+ }
+
+ sizeW = *size * sizeof(WCHAR);
+
+ bufferW = HeapAlloc( GetProcessHeap(), 0, sizeW );
+
+ if (bufferW)
+ {
+ if ((ret = GetColorDirectoryW( NULL, bufferW, &sizeW )))
+ {
+ *size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
+ len = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, *size, NULL, NULL );
+ if (!len) ret = FALSE;
+ }
+ else *size = sizeW / sizeof(WCHAR);
+
+ HeapFree( GetProcessHeap(), 0, bufferW );
+ }
+ return ret;
+}
+
+/******************************************************************************
+ * GetColorDirectoryW [MSCMS.@]
+ *
+ * Get the directory where color profiles are stored.
+ *
+ * PARAMS
+ * machine [I] Name of the machine for which to get the color directory.
+ * Must be NULL, which indicates the local machine.
+ * buffer [I] Buffer to receive the path name.
+ * size [I/O] Size of the buffer in bytes. On return the variable holds
+ * the number of bytes actually needed.
+ */
+BOOL WINAPI GetColorDirectoryW( PCWSTR machine, PWSTR buffer, PDWORD size )
+{
+ WCHAR colordir[MAX_PATH];
+ static const WCHAR colorsubdir[] =
+ {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\','c','o','l','o','r',0};
+ DWORD len;
+
+ TRACE( "( %p, %p )\n", buffer, size );
+
+ if (machine || !size) return FALSE;
+
+ GetSystemDirectoryW( colordir, sizeof(colordir) / sizeof(WCHAR) );
+ lstrcatW( colordir, colorsubdir );
+
+ len = lstrlenW( colordir ) * sizeof(WCHAR);
+
+ if (buffer && len <= *size)
+ {
+ lstrcpyW( buffer, colordir );
+ *size = len;
+ return TRUE;
+ }
+
+ SetLastError( ERROR_MORE_DATA );
+ *size = len;
+ return FALSE;
+}
+
+/******************************************************************************
+ * GetColorProfileElement [MSCMS.@]
+ *
+ * Retrieve data for a specified tag type.
+ *
+ * PARAMS
+ * profile [I] Handle to a color profile.
+ * type [I] ICC tag type.
+ * offset [I] Offset in bytes to start copying from.
+ * size [I/O] Size of the buffer in bytes. On return the variable holds
+ * the number of bytes actually needed.
+ * buffer [O] Buffer to receive the tag data.
+ * ref [O] Pointer to a BOOL that specifies whether more than one tag
+ * references the data.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI GetColorProfileElement( HPROFILE handle, TAGTYPE type, DWORD offset, PDWORD size,
+ PVOID buffer, PBOOL ref )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+ struct profile *profile = grab_profile( handle );
+ DWORD i, count;
+ icTag tag;
+
+ TRACE( "( %p, 0x%08x, %d, %p, %p, %p )\n", handle, type, offset, size, buffer, ref );
+
+ if (!profile) return FALSE;
+
+ if (!size || !ref)
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ count = MSCMS_get_tag_count( profile->iccprofile );
+
+ for (i = 0; i < count; i++)
+ {
+ MSCMS_get_tag_by_index( profile->iccprofile, i, &tag );
+
+ if (tag.sig == type)
+ {
+ if ((tag.size - offset) > *size || !buffer)
+ {
+ *size = (tag.size - offset);
+ release_profile( profile );
+ return FALSE;
+ }
+ MSCMS_get_tag_data( profile->iccprofile, &tag, offset, buffer );
+
+ *ref = FALSE; /* FIXME: calculate properly */
+ release_profile( profile );
+ return TRUE;
+ }
+ }
+ release_profile( profile );
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * GetColorProfileElementTag [MSCMS.@]
+ *
+ * Get the tag type from a color profile by index.
+ *
+ * PARAMS
+ * profile [I] Handle to a color profile.
+ * index [I] Index into the tag table of the color profile.
+ * type [O] Pointer to a variable that holds the ICC tag type on return.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ *
+ * NOTES
+ * The tag table index starts at 1.
+ * Use GetCountColorProfileElements to retrieve a count of tagged elements.
+ */
+BOOL WINAPI GetColorProfileElementTag( HPROFILE handle, DWORD index, PTAGTYPE type )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+ struct profile *profile = grab_profile( handle );
+ DWORD count;
+ icTag tag;
+
+ TRACE( "( %p, %d, %p )\n", handle, index, type );
+
+ if (!profile) return FALSE;
+
+ if (!type)
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ count = MSCMS_get_tag_count( profile->iccprofile );
+ if (index > count || index < 1)
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ MSCMS_get_tag_by_index( profile->iccprofile, index - 1, &tag );
+ *type = tag.sig;
+
+ release_profile( profile );
+ ret = TRUE;
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * GetColorProfileFromHandle [MSCMS.@]
+ *
+ * Retrieve an ICC color profile by handle.
+ *
+ * PARAMS
+ * profile [I] Handle to a color profile.
+ * buffer [O] Buffer to receive the ICC profile.
+ * size [I/O] Size of the buffer in bytes. On return the variable holds the
+ * number of bytes actually needed.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ *
+ * NOTES
+ * The profile returned will be in big-endian format.
+ */
+BOOL WINAPI GetColorProfileFromHandle( HPROFILE handle, PBYTE buffer, PDWORD size )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+ struct profile *profile = grab_profile( handle );
+ PROFILEHEADER header;
+
+ TRACE( "( %p, %p, %p )\n", handle, buffer, size );
+
+ if (!profile) return FALSE;
+
+ if (!size)
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ MSCMS_get_profile_header( profile->iccprofile, &header );
+
+ if (!buffer || header.phSize > *size)
+ {
+ *size = header.phSize;
+ release_profile( profile );
+ return FALSE;
+ }
+
+ /* No endian conversion needed */
+ memcpy( buffer, profile->iccprofile, header.phSize );
+ *size = header.phSize;
+
+ release_profile( profile );
+ ret = TRUE;
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * GetColorProfileHeader [MSCMS.@]
+ *
+ * Retrieve a color profile header by handle.
+ *
+ * PARAMS
+ * profile [I] Handle to a color profile.
+ * header [O] Buffer to receive the ICC profile header.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ *
+ * NOTES
+ * The profile header returned will be adjusted for endianess.
+ */
+BOOL WINAPI GetColorProfileHeader( HPROFILE handle, PPROFILEHEADER header )
+{
+#ifdef HAVE_LCMS
+ struct profile *profile = grab_profile( handle );
+
+ TRACE( "( %p, %p )\n", handle, header );
+
+ if (!profile) return FALSE;
+
+ if (!header)
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ MSCMS_get_profile_header( profile->iccprofile, header );
+
+ release_profile( profile );
+ return TRUE;
+
+#else
+ return FALSE;
+#endif /* HAVE_LCMS */
+}
+
+/******************************************************************************
+ * GetCountColorProfileElements [MSCMS.@]
+ *
+ * Retrieve the number of elements in a color profile.
+ *
+ * PARAMS
+ * profile [I] Handle to a color profile.
+ * count [O] Pointer to a variable which is set to the number of elements
+ * in the color profile.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI GetCountColorProfileElements( HPROFILE handle, PDWORD count )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+ struct profile *profile = grab_profile( handle );
+
+ TRACE( "( %p, %p )\n", handle, count );
+
+ if (!profile) return FALSE;
+
+ if (!count)
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ *count = MSCMS_get_tag_count( profile->iccprofile );
+
+ release_profile( profile );
+ ret = TRUE;
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * GetStandardColorSpaceProfileA [MSCMS.@]
+ *
+ * See GetStandardColorSpaceProfileW.
+ */
+BOOL WINAPI GetStandardColorSpaceProfileA( PCSTR machine, DWORD id, PSTR profile, PDWORD size )
+{
+ INT len;
+ LPWSTR profileW;
+ BOOL ret = FALSE;
+ DWORD sizeW;
+
+ TRACE( "( 0x%08x, %p, %p )\n", id, profile, size );
+
+ if (machine)
+ {
+ SetLastError( ERROR_NOT_SUPPORTED );
+ return FALSE;
+ }
+
+ if (!size)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+
+ sizeW = *size * sizeof(WCHAR);
+
+ if (!profile)
+ {
+ ret = GetStandardColorSpaceProfileW( NULL, id, NULL, &sizeW );
+ *size = sizeW / sizeof(WCHAR);
+ return FALSE;
+ }
+
+ profileW = HeapAlloc( GetProcessHeap(), 0, sizeW );
+
+ if (profileW)
+ {
+ if ((ret = GetStandardColorSpaceProfileW( NULL, id, profileW, &sizeW )))
+ {
+ *size = WideCharToMultiByte( CP_ACP, 0, profileW, -1, NULL, 0, NULL, NULL );
+ len = WideCharToMultiByte( CP_ACP, 0, profileW, -1, profile, *size, NULL, NULL );
+ if (!len) ret = FALSE;
+ }
+ else *size = sizeW / sizeof(WCHAR);
+
+ HeapFree( GetProcessHeap(), 0, profileW );
+ }
+ return ret;
+}
+
+/******************************************************************************
+ * GetStandardColorSpaceProfileW [MSCMS.@]
+ *
+ * Retrieve the profile filename for a given standard color space id.
+ *
+ * PARAMS
+ * machine [I] Name of the machine for which to get the standard color space.
+ * Must be NULL, which indicates the local machine.
+ * id [I] Id of a standard color space.
+ * profile [O] Buffer to receive the profile filename.
+ * size [I/O] Size of the filename buffer in bytes.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI GetStandardColorSpaceProfileW( PCWSTR machine, DWORD id, PWSTR profile, PDWORD size )
+{
+ static const WCHAR rgbprofilefile[] =
+ { '\\','s','r','g','b',' ','c','o','l','o','r',' ',
+ 's','p','a','c','e',' ','p','r','o','f','i','l','e','.','i','c','m',0 };
+ WCHAR rgbprofile[MAX_PATH];
+ DWORD len = sizeof(rgbprofile);
+
+ TRACE( "( 0x%08x, %p, %p )\n", id, profile, size );
+
+ if (machine)
+ {
+ SetLastError( ERROR_NOT_SUPPORTED );
+ return FALSE;
+ }
+
+ if (!size)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+
+ if (!profile)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+
+ GetColorDirectoryW( machine, rgbprofile, &len );
+
+ switch (id)
+ {
+ case SPACE_RGB: /* 'RGB ' */
+ lstrcatW( rgbprofile, rgbprofilefile );
+ len = lstrlenW( rgbprofile ) * sizeof(WCHAR);
+
+ if (*size < len || !profile)
+ {
+ *size = len;
+ SetLastError( ERROR_MORE_DATA );
+ return FALSE;
+ }
+
+ lstrcpyW( profile, rgbprofile );
+ break;
+
+ default:
+ SetLastError( ERROR_FILE_NOT_FOUND );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL MSCMS_header_from_file( LPCWSTR file, PPROFILEHEADER header )
+{
+ BOOL ret;
+ PROFILE profile;
+ WCHAR path[MAX_PATH], slash[] = {'\\',0};
+ DWORD size = sizeof(path);
+ HANDLE handle;
+
+ ret = GetColorDirectoryW( NULL, path, &size );
+ if (!ret)
+ {
+ WARN( "Can't retrieve color directory\n" );
+ return FALSE;
+ }
+ if (size + sizeof(slash) + sizeof(WCHAR) * lstrlenW( file ) > sizeof(path))
+ {
+ WARN( "Filename too long\n" );
+ return FALSE;
+ }
+
+ lstrcatW( path, slash );
+ lstrcatW( path, file );
+
+ profile.dwType = PROFILE_FILENAME;
+ profile.pProfileData = path;
+ profile.cbDataSize = lstrlenW( path ) + 1;
+
+ handle = OpenColorProfileW( &profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING );
+ if (!handle)
+ {
+ WARN( "Can't open color profile\n" );
+ return FALSE;
+ }
+
+ ret = GetColorProfileHeader( handle, header );
+ if (!ret)
+ WARN( "Can't retrieve color profile header\n" );
+
+ CloseColorProfile( handle );
+ return ret;
+}
+
+static BOOL MSCMS_match_profile( PENUMTYPEW rec, PPROFILEHEADER hdr )
+{
+ if (rec->dwFields & ET_DEVICENAME)
+ {
+ FIXME( "ET_DEVICENAME: %s\n", debugstr_w(rec->pDeviceName) );
+ }
+ if (rec->dwFields & ET_MEDIATYPE)
+ {
+ FIXME( "ET_MEDIATYPE: 0x%08x\n", rec->dwMediaType );
+ }
+ if (rec->dwFields & ET_DITHERMODE)
+ {
+ FIXME( "ET_DITHERMODE: 0x%08x\n", rec->dwDitheringMode );
+ }
+ if (rec->dwFields & ET_RESOLUTION)
+ {
+ FIXME( "ET_RESOLUTION: 0x%08x, 0x%08x\n",
+ rec->dwResolution[0], rec->dwResolution[1] );
+ }
+ if (rec->dwFields & ET_DEVICECLASS)
+ {
+ FIXME( "ET_DEVICECLASS: %s\n", MSCMS_dbgstr_tag(rec->dwMediaType) );
+ }
+ if (rec->dwFields & ET_CMMTYPE)
+ {
+ TRACE( "ET_CMMTYPE: %s\n", MSCMS_dbgstr_tag(rec->dwCMMType) );
+ if (rec->dwCMMType != hdr->phCMMType) return FALSE;
+ }
+ if (rec->dwFields & ET_CLASS)
+ {
+ TRACE( "ET_CLASS: %s\n", MSCMS_dbgstr_tag(rec->dwClass) );
+ if (rec->dwClass != hdr->phClass) return FALSE;
+ }
+ if (rec->dwFields & ET_DATACOLORSPACE)
+ {
+ TRACE( "ET_DATACOLORSPACE: %s\n", MSCMS_dbgstr_tag(rec->dwDataColorSpace) );
+ if (rec->dwDataColorSpace != hdr->phDataColorSpace) return FALSE;
+ }
+ if (rec->dwFields & ET_CONNECTIONSPACE)
+ {
+ TRACE( "ET_CONNECTIONSPACE: %s\n", MSCMS_dbgstr_tag(rec->dwConnectionSpace) );
+ if (rec->dwConnectionSpace != hdr->phConnectionSpace) return FALSE;
+ }
+ if (rec->dwFields & ET_SIGNATURE)
+ {
+ TRACE( "ET_SIGNATURE: %s\n", MSCMS_dbgstr_tag(rec->dwSignature) );
+ if (rec->dwSignature != hdr->phSignature) return FALSE;
+ }
+ if (rec->dwFields & ET_PLATFORM)
+ {
+ TRACE( "ET_PLATFORM: %s\n", MSCMS_dbgstr_tag(rec->dwPlatform) );
+ if (rec->dwPlatform != hdr->phPlatform) return FALSE;
+ }
+ if (rec->dwFields & ET_PROFILEFLAGS)
+ {
+ TRACE( "ET_PROFILEFLAGS: 0x%08x\n", rec->dwProfileFlags );
+ if (rec->dwProfileFlags != hdr->phProfileFlags) return FALSE;
+ }
+ if (rec->dwFields & ET_MANUFACTURER)
+ {
+ TRACE( "ET_MANUFACTURER: %s\n", MSCMS_dbgstr_tag(rec->dwManufacturer) );
+ if (rec->dwManufacturer != hdr->phManufacturer) return FALSE;
+ }
+ if (rec->dwFields & ET_MODEL)
+ {
+ TRACE( "ET_MODEL: %s\n", MSCMS_dbgstr_tag(rec->dwModel) );
+ if (rec->dwModel != hdr->phModel) return FALSE;
+ }
+ if (rec->dwFields & ET_ATTRIBUTES)
+ {
+ TRACE( "ET_ATTRIBUTES: 0x%08x, 0x%08x\n",
+ rec->dwAttributes[0], rec->dwAttributes[1] );
+ if (rec->dwAttributes[0] != hdr->phAttributes[0] ||
+ rec->dwAttributes[1] != hdr->phAttributes[1]) return FALSE;
+ }
+ if (rec->dwFields & ET_RENDERINGINTENT)
+ {
+ TRACE( "ET_RENDERINGINTENT: 0x%08x\n", rec->dwRenderingIntent );
+ if (rec->dwRenderingIntent != hdr->phRenderingIntent) return FALSE;
+ }
+ if (rec->dwFields & ET_CREATOR)
+ {
+ TRACE( "ET_CREATOR: %s\n", MSCMS_dbgstr_tag(rec->dwCreator) );
+ if (rec->dwCreator != hdr->phCreator) return FALSE;
+ }
+ return TRUE;
+}
+
+/******************************************************************************
+ * EnumColorProfilesA [MSCMS.@]
+ *
+ * See EnumColorProfilesW.
+ */
+BOOL WINAPI EnumColorProfilesA( PCSTR machine, PENUMTYPEA record, PBYTE buffer,
+ PDWORD size, PDWORD number )
+{
+ BOOL match, ret = FALSE;
+ char spec[] = "\\*.icm";
+ char colordir[MAX_PATH], glob[MAX_PATH], **profiles = NULL;
+ DWORD i, len = sizeof(colordir), count = 0, totalsize = 0;
+ PROFILEHEADER header;
+ WIN32_FIND_DATAA data;
+ ENUMTYPEW recordW;
+ WCHAR *fileW = NULL, *deviceW = NULL;
+ HANDLE find;
+
+ TRACE( "( %p, %p, %p, %p, %p )\n", machine, record, buffer, size, number );
+
+ if (machine || !record || !size ||
+ record->dwSize != sizeof(ENUMTYPEA) ||
+ record->dwVersion != ENUM_TYPE_VERSION) return FALSE;
+
+ ret = GetColorDirectoryA( machine, colordir, &len );
+ if (!ret || len + sizeof(spec) > MAX_PATH)
+ {
+ WARN( "can't retrieve color directory\n" );
+ return FALSE;
+ }
+
+ lstrcpyA( glob, colordir );
+ lstrcatA( glob, spec );
+
+ find = FindFirstFileA( glob, &data );
+ if (find == INVALID_HANDLE_VALUE) return FALSE;
+
+ profiles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(char *) + 1 );
+ if (!profiles) goto exit;
+
+ memcpy( &recordW, record, sizeof(ENUMTYPEA) );
+ if (record->pDeviceName)
+ {
+ deviceW = MSCMS_strdupW( record->pDeviceName );
+ if (!(recordW.pDeviceName = deviceW)) goto exit;
+ }
+
+ fileW = MSCMS_strdupW( data.cFileName );
+ if (!fileW) goto exit;
+
+ ret = MSCMS_header_from_file( fileW, &header );
+ if (ret)
+ {
+ match = MSCMS_match_profile( &recordW, &header );
+ if (match)
+ {
+ len = sizeof(char) * (lstrlenA( data.cFileName ) + 1);
+ profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
+
+ if (!profiles[count]) goto exit;
+ else
+ {
+ TRACE( "matching profile: %s\n", debugstr_a(data.cFileName) );
+ lstrcpyA( profiles[count], data.cFileName );
+ totalsize += len;
+ count++;
+ }
+ }
+ }
+ HeapFree( GetProcessHeap(), 0, fileW );
+ fileW = NULL;
+
+ while (FindNextFileA( find, &data ))
+ {
+ fileW = MSCMS_strdupW( data.cFileName );
+ if (!fileW) goto exit;
+
+ ret = MSCMS_header_from_file( fileW, &header );
+ if (!ret)
+ {
+ HeapFree( GetProcessHeap(), 0, fileW );
+ continue;
+ }
+
+ match = MSCMS_match_profile( &recordW, &header );
+ if (match)
+ {
+ char **tmp = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+ profiles, sizeof(char *) * (count + 1) );
+ if (!tmp) goto exit;
+ else profiles = tmp;
+
+ len = sizeof(char) * (lstrlenA( data.cFileName ) + 1);
+ profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
+
+ if (!profiles[count]) goto exit;
+ else
+ {
+ TRACE( "matching profile: %s\n", debugstr_a(data.cFileName) );
+ lstrcpyA( profiles[count], data.cFileName );
+ totalsize += len;
+ count++;
+ }
+ }
+ HeapFree( GetProcessHeap(), 0, fileW );
+ fileW = NULL;
+ }
+
+ totalsize++;
+ if (buffer && *size >= totalsize)
+ {
+ char *p = (char *)buffer;
+
+ for (i = 0; i < count; i++)
+ {
+ lstrcpyA( p, profiles[i] );
+ p += lstrlenA( profiles[i] ) + 1;
+ }
+ *p = 0;
+ ret = TRUE;
+ }
+ else ret = FALSE;
+
+ *size = totalsize;
+ if (number) *number = count;
+
+exit:
+ for (i = 0; i < count; i++)
+ HeapFree( GetProcessHeap(), 0, profiles[i] );
+ HeapFree( GetProcessHeap(), 0, profiles );
+ HeapFree( GetProcessHeap(), 0, deviceW );
+ HeapFree( GetProcessHeap(), 0, fileW );
+ FindClose( find );
+
+ return ret;
+}
+
+/******************************************************************************
+ * EnumColorProfilesW [MSCMS.@]
+ *
+ * Enumerate profiles that match given criteria.
+ *
+ * PARAMS
+ * machine [I] Name of the machine for which to enumerate profiles.
+ * Must be NULL, which indicates the local machine.
+ * record [I] Record of criteria that a profile must match.
+ * buffer [O] Buffer to receive a string array of profile filenames.
+ * size [I/O] Size of the filename buffer in bytes.
+ * number [O] Number of filenames copied into buffer.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI EnumColorProfilesW( PCWSTR machine, PENUMTYPEW record, PBYTE buffer,
+ PDWORD size, PDWORD number )
+{
+ BOOL match, ret = FALSE;
+ WCHAR spec[] = {'\\','*','i','c','m',0};
+ WCHAR colordir[MAX_PATH], glob[MAX_PATH], **profiles = NULL;
+ DWORD i, len = sizeof(colordir), count = 0, totalsize = 0;
+ PROFILEHEADER header;
+ WIN32_FIND_DATAW data;
+ HANDLE find;
+
+ TRACE( "( %p, %p, %p, %p, %p )\n", machine, record, buffer, size, number );
+
+ if (machine || !record || !size ||
+ record->dwSize != sizeof(ENUMTYPEW) ||
+ record->dwVersion != ENUM_TYPE_VERSION) return FALSE;
+
+ ret = GetColorDirectoryW( machine, colordir, &len );
+ if (!ret || len + sizeof(spec) > MAX_PATH)
+ {
+ WARN( "Can't retrieve color directory\n" );
+ return FALSE;
+ }
+
+ lstrcpyW( glob, colordir );
+ lstrcatW( glob, spec );
+
+ find = FindFirstFileW( glob, &data );
+ if (find == INVALID_HANDLE_VALUE) return FALSE;
+
+ profiles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR *) + 1 );
+ if (!profiles) goto exit;
+
+ ret = MSCMS_header_from_file( data.cFileName, &header );
+ if (ret)
+ {
+ match = MSCMS_match_profile( record, &header );
+ if (match)
+ {
+ len = sizeof(WCHAR) * (lstrlenW( data.cFileName ) + 1);
+ profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
+
+ if (!profiles[count]) goto exit;
+ else
+ {
+ TRACE( "matching profile: %s\n", debugstr_w(data.cFileName) );
+ lstrcpyW( profiles[count], data.cFileName );
+ totalsize += len;
+ count++;
+ }
+ }
+ }
+
+ while (FindNextFileW( find, &data ))
+ {
+ ret = MSCMS_header_from_file( data.cFileName, &header );
+ if (!ret) continue;
+
+ match = MSCMS_match_profile( record, &header );
+ if (match)
+ {
+ WCHAR **tmp = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+ profiles, sizeof(WCHAR *) * (count + 1) );
+ if (!tmp) goto exit;
+ else profiles = tmp;
+
+ len = sizeof(WCHAR) * (lstrlenW( data.cFileName ) + 1);
+ profiles[count] = HeapAlloc( GetProcessHeap(), 0, len );
+
+ if (!profiles[count]) goto exit;
+ else
+ {
+ TRACE( "matching profile: %s\n", debugstr_w(data.cFileName) );
+ lstrcpyW( profiles[count], data.cFileName );
+ totalsize += len;
+ count++;
+ }
+ }
+ }
+
+ totalsize++;
+ if (buffer && *size >= totalsize)
+ {
+ WCHAR *p = (WCHAR *)buffer;
+
+ for (i = 0; i < count; i++)
+ {
+ lstrcpyW( p, profiles[i] );
+ p += lstrlenW( profiles[i] ) + 1;
+ }
+ *p = 0;
+ ret = TRUE;
+ }
+ else ret = FALSE;
+
+ *size = totalsize;
+ if (number) *number = count;
+
+exit:
+ for (i = 0; i < count; i++)
+ HeapFree( GetProcessHeap(), 0, profiles[i] );
+ HeapFree( GetProcessHeap(), 0, profiles );
+ FindClose( find );
+
+ return ret;
+}
+
+/******************************************************************************
+ * InstallColorProfileA [MSCMS.@]
+ *
+ * See InstallColorProfileW.
+ */
+BOOL WINAPI InstallColorProfileA( PCSTR machine, PCSTR profile )
+{
+ UINT len;
+ LPWSTR profileW;
+ BOOL ret = FALSE;
+
+ TRACE( "( %s )\n", debugstr_a(profile) );
+
+ if (machine || !profile) return FALSE;
+
+ len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
+ profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+
+ if (profileW)
+ {
+ MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
+
+ ret = InstallColorProfileW( NULL, profileW );
+ HeapFree( GetProcessHeap(), 0, profileW );
+ }
+ return ret;
+}
+
+/******************************************************************************
+ * InstallColorProfileW [MSCMS.@]
+ *
+ * Install a color profile.
+ *
+ * PARAMS
+ * machine [I] Name of the machine to install the profile on. Must be NULL,
+ * which indicates the local machine.
+ * profile [I] Full path name of the profile to install.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI InstallColorProfileW( PCWSTR machine, PCWSTR profile )
+{
+ WCHAR dest[MAX_PATH], base[MAX_PATH];
+ DWORD size = sizeof(dest);
+ static const WCHAR slash[] = { '\\', 0 };
+
+ TRACE( "( %s )\n", debugstr_w(profile) );
+
+ if (machine || !profile) return FALSE;
+
+ if (!GetColorDirectoryW( machine, dest, &size )) return FALSE;
+
+ MSCMS_basename( profile, base );
+
+ lstrcatW( dest, slash );
+ lstrcatW( dest, base );
+
+ /* Is source equal to destination? */
+ if (!lstrcmpW( profile, dest )) return TRUE;
+
+ return CopyFileW( profile, dest, TRUE );
+}
+
+/******************************************************************************
+ * IsColorProfileTagPresent [MSCMS.@]
+ *
+ * Determine if a given ICC tag type is present in a color profile.
+ *
+ * PARAMS
+ * profile [I] Color profile handle.
+ * tag [I] ICC tag type.
+ * present [O] Pointer to a BOOL variable. Set to TRUE if tag type is present,
+ * FALSE otherwise.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI IsColorProfileTagPresent( HPROFILE handle, TAGTYPE type, PBOOL present )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+ struct profile *profile = grab_profile( handle );
+ DWORD i, count;
+ icTag tag;
+
+ TRACE( "( %p, 0x%08x, %p )\n", handle, type, present );
+
+ if (!profile) return FALSE;
+
+ if (!present)
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ count = MSCMS_get_tag_count( profile->iccprofile );
+
+ for (i = 0; i < count; i++)
+ {
+ MSCMS_get_tag_by_index( profile->iccprofile, i, &tag );
+
+ if (tag.sig == type)
+ {
+ *present = ret = TRUE;
+ break;
+ }
+ }
+ release_profile( profile );
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * IsColorProfileValid [MSCMS.@]
+ *
+ * Determine if a given color profile is valid.
+ *
+ * PARAMS
+ * profile [I] Color profile handle.
+ * valid [O] Pointer to a BOOL variable. Set to TRUE if profile is valid,
+ * FALSE otherwise.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI IsColorProfileValid( HPROFILE handle, PBOOL valid )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+ struct profile *profile = grab_profile( handle );
+
+ TRACE( "( %p, %p )\n", handle, valid );
+
+ if (!profile) return FALSE;
+
+ if (!valid)
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ if (profile->iccprofile) ret = *valid = TRUE;
+ release_profile( profile );
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * SetColorProfileElement [MSCMS.@]
+ *
+ * Set data for a specified tag type.
+ *
+ * PARAMS
+ * profile [I] Handle to a color profile.
+ * type [I] ICC tag type.
+ * offset [I] Offset in bytes to start copying to.
+ * size [I/O] Size of the buffer in bytes. On return the variable holds the
+ * number of bytes actually needed.
+ * buffer [O] Buffer holding the tag data.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI SetColorProfileElement( HPROFILE handle, TAGTYPE type, DWORD offset, PDWORD size,
+ PVOID buffer )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+ struct profile *profile = grab_profile( handle );
+ DWORD i, count;
+ icTag tag;
+
+ TRACE( "( %p, 0x%08x, %d, %p, %p )\n", handle, type, offset, size, buffer );
+
+ if (!profile) return FALSE;
+
+ if (!size || !buffer || !(profile->access & PROFILE_READWRITE))
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ count = MSCMS_get_tag_count( profile->iccprofile );
+
+ for (i = 0; i < count; i++)
+ {
+ MSCMS_get_tag_by_index( profile->iccprofile, i, &tag );
+
+ if (tag.sig == type)
+ {
+ if (offset > tag.size)
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ MSCMS_set_tag_data( profile->iccprofile, &tag, offset, buffer );
+
+ release_profile( profile );
+ return TRUE;
+ }
+ }
+ release_profile( profile );
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * SetColorProfileHeader [MSCMS.@]
+ *
+ * Set header data for a given profile.
+ *
+ * PARAMS
+ * profile [I] Handle to a color profile.
+ * header [I] Buffer holding the header data.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI SetColorProfileHeader( HPROFILE handle, PPROFILEHEADER header )
+{
+#ifdef HAVE_LCMS
+ struct profile *profile = grab_profile( handle );
+
+ TRACE( "( %p, %p )\n", handle, header );
+
+ if (!profile) return FALSE;
+
+ if (!header || !(profile->access & PROFILE_READWRITE))
+ {
+ release_profile( profile );
+ return FALSE;
+ }
+ MSCMS_set_profile_header( profile->iccprofile, header );
+
+ release_profile( profile );
+ return TRUE;
+
+#else
+ return FALSE;
+#endif /* HAVE_LCMS */
+}
+
+/******************************************************************************
+ * UninstallColorProfileA [MSCMS.@]
+ *
+ * See UninstallColorProfileW.
+ */
+BOOL WINAPI UninstallColorProfileA( PCSTR machine, PCSTR profile, BOOL delete )
+{
+ UINT len;
+ LPWSTR profileW;
+ BOOL ret = FALSE;
+
+ TRACE( "( %s, %x )\n", debugstr_a(profile), delete );
+
+ if (machine || !profile) return FALSE;
+
+ len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
+ profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+
+ if (profileW)
+ {
+ MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
+
+ ret = UninstallColorProfileW( NULL, profileW , delete );
+
+ HeapFree( GetProcessHeap(), 0, profileW );
+ }
+ return ret;
+}
+
+/******************************************************************************
+ * UninstallColorProfileW [MSCMS.@]
+ *
+ * Uninstall a color profile.
+ *
+ * PARAMS
+ * machine [I] Name of the machine to uninstall the profile on. Must be NULL,
+ * which indicates the local machine.
+ * profile [I] Full path name of the profile to uninstall.
+ * delete [I] Bool that specifies whether the profile file should be deleted.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI UninstallColorProfileW( PCWSTR machine, PCWSTR profile, BOOL delete )
+{
+ TRACE( "( %s, %x )\n", debugstr_w(profile), delete );
+
+ if (machine || !profile) return FALSE;
+
+ if (delete) return DeleteFileW( profile );
+
+ return TRUE;
+}
+
+/******************************************************************************
+ * OpenColorProfileA [MSCMS.@]
+ *
+ * See OpenColorProfileW.
+ */
+HPROFILE WINAPI OpenColorProfileA( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
+{
+ HPROFILE handle = NULL;
+
+ TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile, access, sharing, creation );
+
+ if (!profile || !profile->pProfileData) return NULL;
+
+ /* No AW conversion needed for memory based profiles */
+ if (profile->dwType & PROFILE_MEMBUFFER)
+ return OpenColorProfileW( profile, access, sharing, creation );
+
+ if (profile->dwType & PROFILE_FILENAME)
+ {
+ UINT len;
+ PROFILE profileW;
+
+ profileW.dwType = profile->dwType;
+
+ len = MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, NULL, 0 );
+ profileW.pProfileData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+
+ if (profileW.pProfileData)
+ {
+ profileW.cbDataSize = len * sizeof(WCHAR);
+ MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, profileW.pProfileData, len );
+
+ handle = OpenColorProfileW( &profileW, access, sharing, creation );
+ HeapFree( GetProcessHeap(), 0, profileW.pProfileData );
+ }
+ }
+ return handle;
+}
+
+/******************************************************************************
+ * OpenColorProfileW [MSCMS.@]
+ *
+ * Open a color profile.
+ *
+ * PARAMS
+ * profile [I] Pointer to a color profile structure.
+ * access [I] Desired access.
+ * sharing [I] Sharing mode.
+ * creation [I] Creation mode.
+ *
+ * RETURNS
+ * Success: Handle to the opened profile.
+ * Failure: NULL
+ *
+ * NOTES
+ * Values for access: PROFILE_READ or PROFILE_READWRITE.
+ * Values for sharing: 0 (no sharing), FILE_SHARE_READ and/or FILE_SHARE_WRITE.
+ * Values for creation: one of CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
+ * OPEN_ALWAYS, TRUNCATE_EXISTING.
+ * Sharing and creation flags are ignored for memory based profiles.
+ */
+HPROFILE WINAPI OpenColorProfileW( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
+{
+#ifdef HAVE_LCMS
+ cmsHPROFILE cmsprofile = NULL;
+ icProfile *iccprofile = NULL;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+
+ TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile, access, sharing, creation );
+
+ if (!profile || !profile->pProfileData) return NULL;
+
+ if (profile->dwType == PROFILE_MEMBUFFER)
+ {
+ /* FIXME: access flags not implemented for memory based profiles */
+
+ if (!(iccprofile = HeapAlloc( GetProcessHeap(), 0, profile->cbDataSize ))) return NULL;
+ memcpy( iccprofile, profile->pProfileData, profile->cbDataSize );
+
+ cmsprofile = cmsOpenProfileFromMem( iccprofile, profile->cbDataSize );
+ }
+ else if (profile->dwType == PROFILE_FILENAME)
+ {
+ DWORD size, read, flags = 0;
+
+ TRACE( "profile file: %s\n", debugstr_w( profile->pProfileData ) );
+
+ if (access & PROFILE_READ) flags = GENERIC_READ;
+ if (access & PROFILE_READWRITE) flags = GENERIC_READ|GENERIC_WRITE;
+
+ if (!flags) return NULL;
+ if (!sharing) sharing = FILE_SHARE_READ;
+
+ handle = CreateFileW( profile->pProfileData, flags, sharing, NULL, creation, 0, NULL );
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ WARN( "Unable to open color profile %u\n", GetLastError() );
+ return NULL;
+ }
+
+ if ((size = GetFileSize( handle, NULL )) == INVALID_FILE_SIZE)
+ {
+ ERR( "Unable to retrieve size of color profile\n" );
+ CloseHandle( handle );
+ return NULL;
+ }
+
+ iccprofile = HeapAlloc( GetProcessHeap(), 0, size );
+ if (!iccprofile)
+ {
+ ERR( "Unable to allocate memory for color profile\n" );
+ CloseHandle( handle );
+ return NULL;
+ }
+
+ if (!ReadFile( handle, iccprofile, size, &read, NULL ) || read != size)
+ {
+ ERR( "Unable to read color profile\n" );
+
+ CloseHandle( handle );
+ HeapFree( GetProcessHeap(), 0, iccprofile );
+ return NULL;
+ }
+
+ cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
+ }
+ else
+ {
+ ERR( "Invalid profile type %u\n", profile->dwType );
+ return NULL;
+ }
+
+ if (cmsprofile)
+ {
+ struct profile profile;
+
+ profile.file = handle;
+ profile.access = access;
+ profile.iccprofile = iccprofile;
+ profile.cmsprofile = cmsprofile;
+
+ return create_profile( &profile );
+ }
+
+#endif /* HAVE_LCMS */
+ return NULL;
+}
+
+/******************************************************************************
+ * CloseColorProfile [MSCMS.@]
+ *
+ * Close a color profile.
+ *
+ * PARAMS
+ * profile [I] Handle to the profile.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI CloseColorProfile( HPROFILE profile )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+
+ TRACE( "( %p )\n", profile );
+ ret = close_profile( profile );
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
diff --git a/reactos/dll/win32/mscms/stub.c b/reactos/dll/win32/mscms/stub.c
new file mode 100644
index 00000000000..d7e6877f7fd
--- /dev/null
+++ b/reactos/dll/win32/mscms/stub.c
@@ -0,0 +1,203 @@
+/*
+ * MSCMS - Color Management System for Wine
+ *
+ * Copyright 2004, 2005 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "wine/debug.h"
+
+#include
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "icm.h"
+
+#include "mscms_priv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mscms);
+
+BOOL WINAPI CheckBitmapBits( HTRANSFORM transform, PVOID srcbits, BMFORMAT format, DWORD width,
+ DWORD height, DWORD stride, PBYTE result, PBMCALLBACKFN callback,
+ LPARAM data )
+{
+ FIXME( "( %p, %p, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, %p, 0x%08lx ) stub\n",
+ transform, srcbits, format, width, height, stride, result, callback, data );
+
+ return FALSE;
+}
+
+BOOL WINAPI CheckColors( HTRANSFORM transform, PCOLOR colors, DWORD number, COLORTYPE type,
+ PBYTE result )
+{
+ FIXME( "( %p, %p, 0x%08x, 0x%08x, %p ) stub\n", transform, colors, number, type, result );
+
+ return FALSE;
+}
+
+BOOL WINAPI ConvertColorNameToIndex( HPROFILE profile, PCOLOR_NAME name, PDWORD index, DWORD count )
+{
+ FIXME( "( %p, %p, %p, 0x%08x ) stub\n", profile, name, index, count );
+
+ return FALSE;
+}
+
+BOOL WINAPI ConvertIndexToColorName( HPROFILE profile, PDWORD index, PCOLOR_NAME name, DWORD count )
+{
+ FIXME( "( %p, %p, %p, 0x%08x ) stub\n", profile, index, name, count );
+
+ return FALSE;
+}
+
+BOOL WINAPI CreateDeviceLinkProfile( PHPROFILE profiles, DWORD nprofiles, PDWORD intents,
+ DWORD nintents, DWORD flags, PBYTE *data, DWORD index )
+{
+ FIXME( "( %p, 0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08x ) stub\n",
+ profiles, nprofiles, intents, nintents, flags, data, index );
+
+ return FALSE;
+}
+
+BOOL WINAPI CreateProfileFromLogColorSpaceA( LPLOGCOLORSPACEA space, PBYTE *buffer )
+{
+ FIXME( "( %p, %p ) stub\n", space, buffer );
+
+ return FALSE;
+}
+
+BOOL WINAPI CreateProfileFromLogColorSpaceW( LPLOGCOLORSPACEW space, PBYTE *buffer )
+{
+ FIXME( "( %p, %p ) stub\n", space, buffer );
+
+ return FALSE;
+}
+
+DWORD WINAPI GenerateCopyFilePaths( LPCWSTR printer, LPCWSTR directory, LPBYTE clientinfo,
+ DWORD level, LPWSTR sourcedir, LPDWORD sourcedirsize,
+ LPWSTR targetdir, LPDWORD targetdirsize, DWORD flags )
+{
+ FIXME( "( %s, %s, %p, 0x%08x, %p, %p, %p, %p, 0x%08x ) stub\n",
+ debugstr_w(printer), debugstr_w(directory), clientinfo, level, sourcedir,
+ sourcedirsize, targetdir, targetdirsize, flags );
+ return ERROR_SUCCESS;
+}
+
+DWORD WINAPI GetCMMInfo( HTRANSFORM transform, DWORD info )
+{
+ FIXME( "( %p, 0x%08x ) stub\n", transform, info );
+
+ return 0;
+}
+
+BOOL WINAPI GetNamedProfileInfo( HPROFILE profile, PNAMED_PROFILE_INFO info )
+{
+ FIXME( "( %p, %p ) stub\n", profile, info );
+
+ return FALSE;
+}
+
+BOOL WINAPI GetPS2ColorRenderingDictionary( HPROFILE profile, DWORD intent, PBYTE buffer,
+ PDWORD size, PBOOL binary )
+{
+ FIXME( "( %p, 0x%08x, %p, %p, %p ) stub\n", profile, intent, buffer, size, binary );
+
+ return FALSE;
+}
+
+BOOL WINAPI GetPS2ColorRenderingIntent( HPROFILE profile, DWORD intent, PBYTE buffer, PDWORD size )
+{
+ FIXME( "( %p, 0x%08x, %p, %p ) stub\n", profile, intent, buffer, size );
+
+ return FALSE;
+}
+
+BOOL WINAPI GetPS2ColorSpaceArray( HPROFILE profile, DWORD intent, DWORD type, PBYTE buffer,
+ PDWORD size, PBOOL binary )
+{
+ FIXME( "( %p, 0x%08x, 0x%08x, %p, %p, %p ) stub\n", profile, intent, type, buffer, size, binary );
+
+ return FALSE;
+}
+
+BOOL WINAPI RegisterCMMA( PCSTR machine, DWORD id, PCSTR dll )
+{
+ FIXME( "( %p, 0x%08x, %p ) stub\n", machine, id, dll );
+
+ return TRUE;
+}
+
+BOOL WINAPI RegisterCMMW( PCWSTR machine, DWORD id, PCWSTR dll )
+{
+ FIXME( "( %p, 0x%08x, %p ) stub\n", machine, id, dll );
+
+ return TRUE;
+}
+
+BOOL WINAPI SelectCMM( DWORD id )
+{
+ FIXME( "(%x) stub\n", id );
+
+ return TRUE;
+}
+
+BOOL WINAPI SetColorProfileElementReference( HPROFILE profile, TAGTYPE type, TAGTYPE ref )
+{
+ FIXME( "( %p, 0x%08x, 0x%08x ) stub\n", profile, type, ref );
+
+ return TRUE;
+}
+
+BOOL WINAPI SetColorProfileElementSize( HPROFILE profile, TAGTYPE type, DWORD size )
+{
+ FIXME( "( %p, 0x%08x, 0x%08x ) stub\n", profile, type, size );
+
+ return FALSE;
+}
+
+BOOL WINAPI SetStandardColorSpaceProfileA( PCSTR machine, DWORD id, PSTR profile )
+{
+ FIXME( "( 0x%08x, %p ) stub\n", id, profile );
+ return TRUE;
+}
+
+BOOL WINAPI SetStandardColorSpaceProfileW( PCWSTR machine, DWORD id, PWSTR profile )
+{
+ FIXME( "( 0x%08x, %p ) stub\n", id, profile );
+ return TRUE;
+}
+
+BOOL WINAPI SpoolerCopyFileEvent( LPWSTR printer, LPWSTR key, DWORD event )
+{
+ FIXME( "( %s, %s, 0x%08x ) stub\n", debugstr_w(printer), debugstr_w(key), event );
+ return TRUE;
+}
+
+BOOL WINAPI UnregisterCMMA( PCSTR machine, DWORD id )
+{
+ FIXME( "( %p, 0x%08x ) stub\n", machine, id );
+
+ return TRUE;
+}
+
+BOOL WINAPI UnregisterCMMW( PCWSTR machine, DWORD id )
+{
+ FIXME( "( %p, 0x%08x ) stub\n", machine, id );
+
+ return TRUE;
+}
diff --git a/reactos/dll/win32/mscms/transform.c b/reactos/dll/win32/mscms/transform.c
new file mode 100644
index 00000000000..a795386d35f
--- /dev/null
+++ b/reactos/dll/win32/mscms/transform.c
@@ -0,0 +1,451 @@
+/*
+ * MSCMS - Color Management System for Wine
+ *
+ * Copyright 2005, 2006, 2008 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "wine/debug.h"
+
+#include
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "icm.h"
+
+#include "mscms_priv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mscms);
+
+#ifdef HAVE_LCMS
+
+static DWORD from_profile( HPROFILE profile )
+{
+ PROFILEHEADER header;
+
+ GetColorProfileHeader( profile, &header );
+ TRACE( "color space: 0x%08x %s\n", header.phDataColorSpace, MSCMS_dbgstr_tag( header.phDataColorSpace ) );
+
+ switch (header.phDataColorSpace)
+ {
+ case 0x434d594b: return TYPE_CMYK_16; /* 'CMYK' */
+ case 0x47524159: return TYPE_GRAY_16; /* 'GRAY' */
+ case 0x4c616220: return TYPE_Lab_16; /* 'Lab ' */
+ case 0x52474220: return TYPE_RGB_16; /* 'RGB ' */
+ case 0x58595a20: return TYPE_XYZ_16; /* 'XYZ ' */
+ default:
+ WARN("unhandled format\n");
+ return TYPE_RGB_16;
+ }
+}
+
+static DWORD from_bmformat( BMFORMAT format )
+{
+ static int quietfixme = 0;
+ TRACE( "bitmap format: 0x%08x\n", format );
+
+ switch (format)
+ {
+ case BM_RGBTRIPLETS: return TYPE_RGB_8;
+ case BM_BGRTRIPLETS: return TYPE_BGR_8;
+ case BM_GRAY: return TYPE_GRAY_8;
+ default:
+ if (quietfixme == 0)
+ {
+ FIXME("unhandled bitmap format 0x%x\n", format);
+ quietfixme = 1;
+ }
+ return TYPE_RGB_8;
+ }
+}
+
+static DWORD from_type( COLORTYPE type )
+{
+ TRACE( "color type: 0x%08x\n", type );
+
+ switch (type)
+ {
+ case COLOR_GRAY: return TYPE_GRAY_16;
+ case COLOR_RGB: return TYPE_RGB_16;
+ case COLOR_XYZ: return TYPE_XYZ_16;
+ case COLOR_Yxy: return TYPE_Yxy_16;
+ case COLOR_Lab: return TYPE_Lab_16;
+ case COLOR_CMYK: return TYPE_CMYK_16;
+ default:
+ FIXME("unhandled color type\n");
+ return TYPE_RGB_16;
+ }
+}
+
+#endif /* HAVE_LCMS */
+
+/******************************************************************************
+ * CreateColorTransformA [MSCMS.@]
+ *
+ * See CreateColorTransformW.
+ */
+HTRANSFORM WINAPI CreateColorTransformA( LPLOGCOLORSPACEA space, HPROFILE dest,
+ HPROFILE target, DWORD flags )
+{
+ LOGCOLORSPACEW spaceW;
+ DWORD len;
+
+ TRACE( "( %p, %p, %p, 0x%08x )\n", space, dest, target, flags );
+
+ if (!space || !dest) return FALSE;
+
+ memcpy( &spaceW, space, FIELD_OFFSET(LOGCOLORSPACEA, lcsFilename) );
+ spaceW.lcsSize = sizeof(LOGCOLORSPACEW);
+
+ len = MultiByteToWideChar( CP_ACP, 0, space->lcsFilename, -1, NULL, 0 );
+ MultiByteToWideChar( CP_ACP, 0, space->lcsFilename, -1, spaceW.lcsFilename, len );
+
+ return CreateColorTransformW( &spaceW, dest, target, flags );
+}
+
+/******************************************************************************
+ * CreateColorTransformW [MSCMS.@]
+ *
+ * Create a color transform.
+ *
+ * PARAMS
+ * space [I] Input color space.
+ * dest [I] Color profile of destination device.
+ * target [I] Color profile of target device.
+ * flags [I] Flags.
+ *
+ * RETURNS
+ * Success: Handle to a transform.
+ * Failure: NULL
+ */
+HTRANSFORM WINAPI CreateColorTransformW( LPLOGCOLORSPACEW space, HPROFILE dest,
+ HPROFILE target, DWORD flags )
+{
+ HTRANSFORM ret = NULL;
+#ifdef HAVE_LCMS
+ struct transform transform;
+ struct profile *dst, *tgt = NULL;
+ cmsHPROFILE cmsinput, cmsoutput, cmstarget = NULL;
+ DWORD in_format, out_format, proofing = 0;
+ int intent;
+
+ TRACE( "( %p, %p, %p, 0x%08x )\n", space, dest, target, flags );
+
+ if (!space || !(dst = grab_profile( dest ))) return FALSE;
+
+ if (target && !(tgt = grab_profile( target )))
+ {
+ release_profile( dst );
+ return FALSE;
+ }
+ intent = space->lcsIntent > 3 ? INTENT_PERCEPTUAL : space->lcsIntent;
+
+ TRACE( "lcsIntent: %x\n", space->lcsIntent );
+ TRACE( "lcsCSType: %s\n", MSCMS_dbgstr_tag( space->lcsCSType ) );
+ TRACE( "lcsFilename: %s\n", debugstr_w( space->lcsFilename ) );
+
+ in_format = TYPE_RGB_16;
+ out_format = from_profile( dest );
+
+ cmsinput = cmsCreate_sRGBProfile(); /* FIXME: create from supplied color space */
+ if (target)
+ {
+ proofing = cmsFLAGS_SOFTPROOFING;
+ cmstarget = tgt->cmsprofile;
+ }
+ cmsoutput = dst->cmsprofile;
+ transform.cmstransform = cmsCreateProofingTransform(cmsinput, in_format, cmsoutput, out_format, cmstarget,
+ intent, INTENT_ABSOLUTE_COLORIMETRIC, proofing);
+
+ ret = create_transform( &transform );
+
+ if (tgt) release_profile( tgt );
+ release_profile( dst );
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * CreateMultiProfileTransform [MSCMS.@]
+ *
+ * Create a color transform from an array of color profiles.
+ *
+ * PARAMS
+ * profiles [I] Array of color profiles.
+ * nprofiles [I] Number of color profiles.
+ * intents [I] Array of rendering intents.
+ * flags [I] Flags.
+ * cmm [I] Profile to take the CMM from.
+ *
+ * RETURNS
+ * Success: Handle to a transform.
+ * Failure: NULL
+ */
+HTRANSFORM WINAPI CreateMultiProfileTransform( PHPROFILE profiles, DWORD nprofiles,
+ PDWORD intents, DWORD nintents, DWORD flags, DWORD cmm )
+{
+ HTRANSFORM ret = NULL;
+#ifdef HAVE_LCMS
+ cmsHPROFILE *cmsprofiles, cmsconvert = NULL;
+ struct transform transform;
+ struct profile *profile0, *profile1;
+ DWORD in_format, out_format;
+
+ TRACE( "( %p, 0x%08x, %p, 0x%08x, 0x%08x, 0x%08x )\n",
+ profiles, nprofiles, intents, nintents, flags, cmm );
+
+ if (!profiles || !nprofiles || !intents) return NULL;
+
+ if (nprofiles > 2)
+ {
+ FIXME("more than 2 profiles not supported\n");
+ return NULL;
+ }
+
+ profile0 = grab_profile( profiles[0] );
+ if (!profile0) return NULL;
+ profile1 = grab_profile( profiles[1] );
+ if (!profile1)
+ {
+ release_profile( profile0 );
+ return NULL;
+ }
+ in_format = from_profile( profiles[0] );
+ out_format = from_profile( profiles[nprofiles - 1] );
+
+ if (in_format != out_format)
+ {
+ /* insert a conversion profile for pairings that lcms doesn't handle */
+ if (out_format == TYPE_RGB_16) cmsconvert = cmsCreate_sRGBProfile();
+ if (out_format == TYPE_Lab_16) cmsconvert = cmsCreateLabProfile( NULL );
+ }
+
+ cmsprofiles = HeapAlloc( GetProcessHeap(), 0, (nprofiles + 1) * sizeof(cmsHPROFILE *) );
+ if (cmsprofiles)
+ {
+ cmsprofiles[0] = profile0->cmsprofile;
+ if (cmsconvert)
+ {
+ cmsprofiles[1] = cmsconvert;
+ cmsprofiles[2] = profile1->cmsprofile;
+ nprofiles++;
+ }
+ else
+ {
+ cmsprofiles[1] = profile1->cmsprofile;
+ }
+ transform.cmstransform = cmsCreateMultiprofileTransform( cmsprofiles, nprofiles, in_format, out_format, *intents, 0 );
+
+ HeapFree( GetProcessHeap(), 0, cmsprofiles );
+ ret = create_transform( &transform );
+ }
+
+ release_profile( profile0 );
+ release_profile( profile1 );
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * DeleteColorTransform [MSCMS.@]
+ *
+ * Delete a color transform.
+ *
+ * PARAMS
+ * transform [I] Handle to a color transform.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI DeleteColorTransform( HTRANSFORM handle )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+
+ TRACE( "( %p )\n", handle );
+
+ ret = close_transform( handle );
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * TranslateBitmapBits [MSCMS.@]
+ *
+ * Perform color translation.
+ *
+ * PARAMS
+ * transform [I] Handle to a color transform.
+ * srcbits [I] Source bitmap.
+ * input [I] Format of the source bitmap.
+ * width [I] Width of the source bitmap.
+ * height [I] Height of the source bitmap.
+ * inputstride [I] Number of bytes in one scanline.
+ * destbits [I] Destination bitmap.
+ * output [I] Format of the destination bitmap.
+ * outputstride [I] Number of bytes in one scanline.
+ * callback [I] Callback function.
+ * data [I] Callback data.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI TranslateBitmapBits( HTRANSFORM handle, PVOID srcbits, BMFORMAT input,
+ DWORD width, DWORD height, DWORD inputstride, PVOID destbits, BMFORMAT output,
+ DWORD outputstride, PBMCALLBACKFN callback, ULONG data )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+ struct transform *transform = grab_transform( handle );
+
+ TRACE( "( %p, %p, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08x )\n",
+ handle, srcbits, input, width, height, inputstride, destbits, output,
+ outputstride, callback, data );
+
+ if (!transform) return FALSE;
+ cmsChangeBuffersFormat( transform->cmstransform, from_bmformat(input), from_bmformat(output) );
+
+ cmsDoTransform( transform->cmstransform, srcbits, destbits, width * height );
+ release_transform( transform );
+ ret = TRUE;
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
+
+/******************************************************************************
+ * TranslateColors [MSCMS.@]
+ *
+ * Perform color translation.
+ *
+ * PARAMS
+ * transform [I] Handle to a color transform.
+ * input [I] Array of input colors.
+ * number [I] Number of colors to translate.
+ * input_type [I] Input color format.
+ * output [O] Array of output colors.
+ * output_type [I] Output color format.
+ *
+ * RETURNS
+ * Success: TRUE
+ * Failure: FALSE
+ */
+BOOL WINAPI TranslateColors( HTRANSFORM handle, PCOLOR in, DWORD count,
+ COLORTYPE input_type, PCOLOR out, COLORTYPE output_type )
+{
+ BOOL ret = FALSE;
+#ifdef HAVE_LCMS
+ struct transform *transform = grab_transform( handle );
+ cmsHTRANSFORM xfrm;
+ unsigned int i;
+
+ TRACE( "( %p, %p, %d, %d, %p, %d )\n", handle, in, count, input_type, out, output_type );
+
+ if (!transform) return FALSE;
+
+ xfrm = transform->cmstransform;
+ cmsChangeBuffersFormat( xfrm, from_type(input_type), from_type(output_type) );
+
+ switch (input_type)
+ {
+ case COLOR_RGB:
+ {
+ switch (output_type)
+ {
+ case COLOR_RGB: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].rgb, 1 ); return TRUE;
+ case COLOR_Lab: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].Lab, 1 ); return TRUE;
+ case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].gray, 1 ); return TRUE;
+ case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].cmyk, 1 ); return TRUE;
+ case COLOR_XYZ: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].XYZ, 1 ); return TRUE;
+ default:
+ FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
+ return FALSE;
+ }
+ }
+ case COLOR_Lab:
+ {
+ switch (output_type)
+ {
+ case COLOR_RGB: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].rgb, 1 ); return TRUE;
+ case COLOR_Lab: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].Lab, 1 ); return TRUE;
+ case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].gray, 1 ); return TRUE;
+ case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].cmyk, 1 ); return TRUE;
+ case COLOR_XYZ: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].XYZ, 1 ); return TRUE;
+ default:
+ FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
+ return FALSE;
+ }
+ }
+ case COLOR_GRAY:
+ {
+ switch (output_type)
+ {
+ case COLOR_RGB: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].rgb, 1 ); return TRUE;
+ case COLOR_Lab: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].Lab, 1 ); return TRUE;
+ case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].gray, 1 ); return TRUE;
+ case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].cmyk, 1 ); return TRUE;
+ case COLOR_XYZ: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].XYZ, 1 ); return TRUE;
+ default:
+ FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
+ return FALSE;
+ }
+ }
+ case COLOR_CMYK:
+ {
+ switch (output_type)
+ {
+ case COLOR_RGB: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].rgb, 1 ); return TRUE;
+ case COLOR_Lab: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].Lab, 1 ); return TRUE;
+ case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].gray, 1 ); return TRUE;
+ case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].cmyk, 1 ); return TRUE;
+ case COLOR_XYZ: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].XYZ, 1 ); return TRUE;
+ default:
+ FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
+ return FALSE;
+ }
+ }
+ case COLOR_XYZ:
+ {
+ switch (output_type)
+ {
+ case COLOR_RGB: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].rgb, 1 ); return TRUE;
+ case COLOR_Lab: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].Lab, 1 ); return TRUE;
+ case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].gray, 1 ); return TRUE;
+ case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].cmyk, 1 ); return TRUE;
+ case COLOR_XYZ: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].XYZ, 1 ); return TRUE;
+ default:
+ FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
+ return FALSE;
+ }
+ }
+ default:
+ FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
+ break;
+ }
+ release_transform( transform );
+
+#endif /* HAVE_LCMS */
+ return ret;
+}
diff --git a/reactos/dll/win32/mscms/version.rc b/reactos/dll/win32/mscms/version.rc
new file mode 100644
index 00000000000..11ebdd64b09
--- /dev/null
+++ b/reactos/dll/win32/mscms/version.rc
@@ -0,0 +1,24 @@
+/*
+ * Version information for mscms.dll
+ *
+ * Copyright 2004 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WINE_FILEDESCRIPTION_STR "Wine Color Management System"
+#define WINE_FILENAME_STR "mscms.dll"
+
+#include
diff --git a/reactos/dll/win32/msftedit/msftedit.rbuild b/reactos/dll/win32/msftedit/msftedit.rbuild
new file mode 100644
index 00000000000..f9dd7bab417
--- /dev/null
+++ b/reactos/dll/win32/msftedit/msftedit.rbuild
@@ -0,0 +1,13 @@
+
+
+ .
+ include/reactos/wine
+
+ msftedit_main.c
+ version.rc
+ wine
+ uuid
+ riched20
+ kernel32
+ ntdll
+
diff --git a/reactos/dll/win32/msftedit/msftedit.spec b/reactos/dll/win32/msftedit/msftedit.spec
new file mode 100644
index 00000000000..0dd878d585a
--- /dev/null
+++ b/reactos/dll/win32/msftedit/msftedit.spec
@@ -0,0 +1,14 @@
+2 extern IID_IRichEditOle
+3 extern IID_IRichEditOleCallback
+4 stdcall CreateTextServices(ptr ptr ptr) riched20.CreateTextServices
+5 extern IID_ITextServices
+6 extern IID_ITextHost
+7 extern IID_ITextHost2
+8 stdcall REExtendedRegisterClass() riched20.REExtendedRegisterClass
+9 stdcall RichEdit10ANSIWndProc(ptr long long long) riched20.RichEdit10ANSIWndProc
+10 stdcall RichEditANSIWndProc(ptr long long long) riched20.RichEditANSIWndProc
+11 stub SetCustomTextOutHandlerEx
+12 stdcall -private DllGetVersion(ptr)
+13 stub RichEditWndProc
+14 stub RichListBoxWndProc
+15 stub RichComboBoxWndProc
diff --git a/reactos/dll/win32/msftedit/msftedit_main.c b/reactos/dll/win32/msftedit/msftedit_main.c
new file mode 100644
index 00000000000..b505999cdad
--- /dev/null
+++ b/reactos/dll/win32/msftedit/msftedit_main.c
@@ -0,0 +1,80 @@
+/*
+ * msftedit main file
+ *
+ * Copyright (C) 2008 Rico Schüller
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "richedit.h"
+#include "imm.h"
+#include "shlwapi.h"
+#include "oleidl.h"
+#include "initguid.h"
+#include "textserv.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msftedit);
+
+/***********************************************************************
+ * DllMain.
+ */
+BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved)
+{
+ static const WCHAR riched20W[] = {'r','i','c','h','e','d','2','0','.','d','l','l',0};
+ static HMODULE richedit;
+
+ switch(reason)
+ {
+ case DLL_WINE_PREATTACH:
+ return FALSE; /* prefer native version */
+ case DLL_PROCESS_ATTACH:
+ /* explicitly load riched20 since it creates the window classes at dll attach time */
+ richedit = LoadLibraryW( riched20W );
+ DisableThreadLibraryCalls(inst);
+ break;
+ case DLL_PROCESS_DETACH:
+ FreeLibrary( richedit );
+ break;
+ }
+ return TRUE;
+}
+
+/***********************************************************************
+ * DllGetVersion (msftedit.@)
+ */
+HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *info)
+{
+ if (info->cbSize != sizeof(DLLVERSIONINFO)) FIXME("support DLLVERSIONINFO2\n");
+
+ /* this is what WINXP SP2 reports */
+ info->dwMajorVersion = 41;
+ info->dwMinorVersion = 15;
+ info->dwBuildNumber = 1507;
+ info->dwPlatformID = 1;
+ return NOERROR;
+}
diff --git a/reactos/dll/win32/msftedit/version.rc b/reactos/dll/win32/msftedit/version.rc
new file mode 100644
index 00000000000..ce5ef0e7b32
--- /dev/null
+++ b/reactos/dll/win32/msftedit/version.rc
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 Rico Schüller
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WINE_FILEDESCRIPTION_STR "Rich Text Edit Control"
+#define WINE_FILENAME_STR "msftedit.dll"
+#define WINE_FILEVERSION 5,41,15,1509
+#define WINE_FILEVERSION_STR "5,41,15,1509"
+#define WINE_PRODUCTVERSION 5,41,15,1509
+#define WINE_PRODUCTVERSION_STR "5,41,15,1509"
+
+#include "wine/wine_common_ver.rc"
diff --git a/reactos/dll/win32/msrle32/msrle32.c b/reactos/dll/win32/msrle32/msrle32.c
new file mode 100644
index 00000000000..b0354b9be2f
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle32.c
@@ -0,0 +1,1924 @@
+/*
+ * Copyright 2002-2003 Michael Günnewig
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* TODO:
+ * - some improvements possible
+ * - implement DecompressSetPalette? -- do we need it for anything?
+ */
+
+#include
+
+#include "msrle_private.h"
+
+#include "winnls.h"
+#include "winuser.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msrle32);
+
+static HINSTANCE MSRLE32_hModule = 0;
+
+#define ABS(a) ((a) < 0 ? -(a) : (a))
+#define SQR(a) ((a) * (a))
+
+#define QUALITY_to_DIST(q) (ICQUALITY_HIGH - q)
+static inline WORD ColorCmp(WORD clr1, WORD clr2)
+{
+ register UINT a = (clr1-clr2);
+ return SQR(a);
+}
+static inline WORD Intensity(RGBQUAD clr)
+{
+ return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4;
+}
+
+#define GetRawPixel(lpbi,lp,x) \
+ ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
+ ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
+
+/*****************************************************************************/
+
+/* utility functions */
+static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi);
+static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi);
+static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);
+
+/* compression functions */
+static void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn);
+static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);
+static LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
+ LPBYTE lpOut, BOOL isKey);
+static LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
+ LPBYTE lpOut, BOOL isKey);
+
+/* decompression functions */
+static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
+ const BYTE *lpIn, LPBYTE lpOut);
+static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
+ const BYTE *lpIn, LPBYTE lpOut);
+
+/* API functions */
+static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPBITMAPINFOHEADER lpbiOut);
+static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);
+static LRESULT CompressEnd(CodecInfo *pi);
+
+static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPBITMAPINFOHEADER lpbiOut);
+static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut);
+static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);
+static LRESULT DecompressEnd(CodecInfo *pi);
+static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPBITMAPINFOHEADER lpbiOut);
+
+/*****************************************************************************/
+
+static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
+{
+ /* pre-conditions */
+ assert(lpbi != NULL);
+
+ if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
+ lpbi->biPlanes != 1)
+ return FALSE;
+
+ if (lpbi->biCompression == BI_RLE4) {
+ if (lpbi->biBitCount != 4 ||
+ (lpbi->biWidth % 2) != 0)
+ return FALSE;
+ } else if (lpbi->biCompression == BI_RLE8) {
+ if (lpbi->biBitCount != 8)
+ return FALSE;
+ } else
+ return FALSE;
+
+ return TRUE;
+}
+
+static BOOL isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
+{
+ /* pre-conditions */
+ assert(lpbi != NULL);
+
+ /* check structure version/planes/compression */
+ if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
+ lpbi->biPlanes != 1)
+ return FALSE;
+ if (lpbi->biCompression != BI_RGB &&
+ lpbi->biCompression != BI_BITFIELDS)
+ return FALSE;
+
+ /* check bit-depth */
+ if (lpbi->biBitCount != 1 &&
+ lpbi->biBitCount != 4 &&
+ lpbi->biBitCount != 8 &&
+ lpbi->biBitCount != 15 &&
+ lpbi->biBitCount != 16 &&
+ lpbi->biBitCount != 24 &&
+ lpbi->biBitCount != 32)
+ return FALSE;
+
+ /* check for size(s) */
+ if (!lpbi->biWidth || !lpbi->biHeight)
+ return FALSE; /* image with zero size, makes no sense so error ! */
+ if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1)
+ return FALSE; /* image too big ! */
+
+ /* check for nonexistent colortable for hi- and true-color DIB's */
+ if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
+{
+ INT diff = 0x00FFFFFF;
+ UINT i;
+ UINT idx = 0;
+
+ /* pre-conditions */
+ assert(clrs != NULL);
+
+ for (i = 0; i < count; i++) {
+ int r = ((int)clrs[i].rgbRed - (int)clr.rgbRed);
+ int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen);
+ int b = ((int)clrs[i].rgbBlue - (int)clr.rgbBlue);
+
+ r = r*r + g*g + b*b;
+
+ if (r < diff) {
+ idx = i;
+ diff = r;
+ if (diff == 0)
+ break;
+ }
+ }
+
+ return idx;
+}
+
+/*****************************************************************************/
+
+void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn)
+{
+ WORD wIntensityTbl[256];
+ DWORD lInLine, lOutLine;
+ LPWORD lpOut;
+ UINT i;
+ LONG y;
+
+ /* pre-conditions */
+ assert(pi != NULL && lpbiIn != NULL && lpIn != NULL);
+ assert(pi->pCurFrame != NULL);
+
+ lInLine = DIBWIDTHBYTES(*lpbiIn);
+ lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u;
+ lpOut = pi->pCurFrame;
+
+ assert(lpbiIn->biClrUsed != 0);
+
+ {
+ const RGBQUAD *lp =
+ (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize);
+
+ for (i = 0; i < lpbiIn->biClrUsed; i++)
+ wIntensityTbl[i] = Intensity(lp[i]);
+ }
+
+ for (y = 0; y < lpbiIn->biHeight; y++) {
+ LONG x;
+
+ switch (lpbiIn->biBitCount) {
+ case 1:
+ for (x = 0; x < lpbiIn->biWidth / 8; x++) {
+ for (i = 0; i < 7; i++)
+ lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1];
+ }
+ break;
+ case 4:
+ for (x = 0; x < lpbiIn->biWidth / 2; x++) {
+ lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)];
+ lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)];
+ }
+ break;
+ case 8:
+ for (x = 0; x < lpbiIn->biWidth; x++)
+ lpOut[x] = wIntensityTbl[lpIn[x]];
+ break;
+ }
+
+ lpIn += lInLine;
+ lpOut += lOutLine;
+ }
+}
+
+static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
+{
+ LONG a, b, size;
+
+ /* pre-condition */
+ assert(lpbi != NULL);
+
+ a = lpbi->biWidth / 255;
+ b = lpbi->biWidth % 255;
+ if (lpbi->biBitCount <= 4) {
+ a /= 2;
+ b /= 2;
+ }
+
+ size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
+ return size * lpbi->biHeight;
+}
+
+/* lpP => current pos in previous frame
+ * lpA => previous pos in current frame
+ * lpB => current pos in current frame
+ */
+static INT countDiffRLE4(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
+{
+ INT count;
+ WORD clr1, clr2;
+
+ /* pre-conditions */
+ assert(lpA && lpB && lDist >= 0 && width > 0);
+
+ if (pos >= width)
+ return 0;
+ if (pos+1 == width)
+ return 1;
+
+ clr1 = lpB[pos++];
+ clr2 = lpB[pos];
+
+ count = 2;
+ while (pos + 1 < width) {
+ WORD clr3, clr4;
+
+ clr3 = lpB[++pos];
+ if (pos + 1 >= width)
+ return count + 1;
+
+ clr4 = lpB[++pos];
+ if (ColorCmp(clr1, clr3) <= lDist &&
+ ColorCmp(clr2, clr4) <= lDist) {
+ /* diff at end? -- look-ahead for at least ?? more encodable pixels */
+ if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist &&
+ ColorCmp(clr2,lpB[pos+2]) <= lDist) {
+ if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist &&
+ ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist)
+ return count - 3; /* followed by at least 4 encodable pixels */
+ return count - 2;
+ }
+ } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
+ /* 'compare' with previous frame for end of diff */
+ INT count2 = 0;
+
+ /* FIXME */
+
+ if (count2 >= 8)
+ return count;
+
+ pos -= count2;
+ }
+
+ count += 2;
+ clr1 = clr3;
+ clr2 = clr4;
+ }
+
+ return count;
+}
+
+/* lpP => current pos in previous frame
+ * lpA => previous pos in current frame
+ * lpB => current pos in current frame
+ */
+static INT countDiffRLE8(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
+{
+ INT count;
+
+ for (count = 0; pos < width; pos++, count++) {
+ if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) {
+ /* diff at end? -- look-ahead for some more encodable pixel */
+ if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist)
+ return count - 1;
+ if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist)
+ return count - 1;
+ } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
+ /* 'compare' with previous frame for end of diff */
+ INT count2 = 0;
+
+ for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
+ if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
+ break;
+ }
+ if (count2 > 4)
+ return count;
+
+ pos -= count2;
+ }
+ }
+
+ return count;
+}
+
+static INT MSRLE32_CompressRLE4Line(const CodecInfo *pi, const WORD *lpP,
+ const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
+ const BYTE *lpIn, LONG lDist,
+ INT x, LPBYTE *ppOut,
+ DWORD *lpSizeImage)
+{
+ LPBYTE lpOut = *ppOut;
+ INT count, pos;
+ WORD clr1, clr2;
+
+ /* try to encode as many pixel as possible */
+ count = 1;
+ pos = x;
+ clr1 = lpC[pos++];
+ if (pos < lpbi->biWidth) {
+ clr2 = lpC[pos];
+ for (++count; pos + 1 < lpbi->biWidth; ) {
+ ++pos;
+ if (ColorCmp(clr1, lpC[pos]) > lDist)
+ break;
+ count++;
+ if (pos + 1 >= lpbi->biWidth)
+ break;
+ ++pos;
+ if (ColorCmp(clr2, lpC[pos]) > lDist)
+ break;
+ count++;
+ }
+ }
+
+ if (count < 4) {
+ /* add some pixel for absoluting if possible */
+ count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
+
+ assert(count > 0);
+
+ /* check for near end of line */
+ if (x + count > lpbi->biWidth)
+ count = lpbi->biWidth - x;
+
+ /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */
+ while (count > 2) {
+ INT i;
+ INT size = min(count, 254);
+ int bytes = ((size + 1) & (~1)) / 2;
+ int extra_byte = bytes & 0x01;
+
+ *lpSizeImage += 2 + bytes + extra_byte;
+ assert(((*lpSizeImage) % 2) == 0);
+ count -= size;
+ *lpOut++ = 0;
+ *lpOut++ = size;
+ for (i = 0; i < size; i += 2) {
+ clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+ x++;
+ if (i + 1 < size) {
+ clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+ x++;
+ } else
+ clr2 = 0;
+
+ *lpOut++ = (clr1 << 4) | clr2;
+ }
+ if (extra_byte)
+ *lpOut++ = 0;
+ }
+
+ if (count > 0) {
+ /* too little for absoluting so we must encode them */
+ assert(count <= 2);
+
+ *lpSizeImage += 2;
+ clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+ x++;
+ if (count == 2) {
+ clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+ x++;
+ } else
+ clr2 = 0;
+ *lpOut++ = count;
+ *lpOut++ = (clr1 << 4) | clr2;
+ }
+ } else {
+ /* encode count pixel(s) */
+ clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
+ pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
+
+ x += count;
+ while (count > 0) {
+ INT size = min(count, 254);
+
+ *lpSizeImage += 2;
+ count -= size;
+ *lpOut++ = size;
+ *lpOut++ = clr1;
+ }
+ }
+
+ *ppOut = lpOut;
+
+ return x;
+}
+
+static INT MSRLE32_CompressRLE8Line(const CodecInfo *pi, const WORD *lpP,
+ const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
+ const BYTE *lpIn, LONG lDist,
+ INT x, LPBYTE *ppOut,
+ DWORD *lpSizeImage)
+{
+ LPBYTE lpOut = *ppOut;
+ INT count, pos;
+ WORD clr;
+
+ assert(lpbi->biBitCount <= 8);
+ assert(lpbi->biCompression == BI_RGB);
+
+ /* try to encode as much as possible */
+ pos = x;
+ clr = lpC[pos++];
+ for (count = 1; pos < lpbi->biWidth; count++) {
+ if (ColorCmp(clr, lpC[pos++]) > lDist)
+ break;
+ }
+
+ if (count < 2) {
+ /* add some more pixels for absoluting if possible */
+ count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
+
+ assert(count > 0);
+
+ /* check for over end of line */
+ if (x + count > lpbi->biWidth)
+ count = lpbi->biWidth - x;
+
+ /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
+ while (count > 2) {
+ INT i;
+ INT size = min(count, 255);
+ int extra_byte = size % 2;
+
+ *lpSizeImage += 2 + size + extra_byte;
+ count -= size;
+ *lpOut++ = 0;
+ *lpOut++ = size;
+ for (i = 0; i < size; i++) {
+ *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+ x++;
+ }
+ if (extra_byte)
+ *lpOut++ = 0;
+ }
+ if (count > 0) {
+ /* too little for absoluting so we must encode them even if it's expensive! */
+ assert(count <= 2);
+
+ *lpSizeImage += 2 * count;
+ *lpOut++ = 1;
+ *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+ x++;
+
+ if (count == 2) {
+ *lpOut++ = 1;
+ *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+ x++;
+ }
+ }
+ } else {
+ /* encode count pixel(s) */
+ clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
+
+ /* optimize end of line */
+ if (x + count + 1 == lpbi->biWidth)
+ count++;
+
+ x += count;
+ while (count > 0) {
+ INT size = min(count, 255);
+
+ *lpSizeImage += 2;
+ count -= size;
+ *lpOut++ = size;
+ *lpOut++ = clr;
+ }
+ }
+
+ *ppOut = lpOut;
+
+ return x;
+}
+
+LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
+ LPBYTE lpOut, BOOL isKey)
+{
+ LPWORD lpC;
+ LONG lLine, lInLine, lDist;
+ LPBYTE lpOutStart = lpOut;
+
+ /* pre-conditions */
+ assert(pi != NULL && lpbiOut != NULL);
+ assert(lpIn != NULL && lpOut != NULL);
+ assert(pi->pCurFrame != NULL);
+
+ lpC = pi->pCurFrame;
+ lDist = QUALITY_to_DIST(pi->dwQuality);
+ lInLine = DIBWIDTHBYTES(*lpbiIn);
+ lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
+
+ lpbiOut->biSizeImage = 0;
+ if (isKey) {
+ /* keyframe -- convert internal frame to output format */
+ INT x, y;
+
+ for (y = 0; y < lpbiOut->biHeight; y++) {
+ x = 0;
+
+ do {
+ x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
+ &lpOut, &lpbiOut->biSizeImage);
+ } while (x < lpbiOut->biWidth);
+
+ lpC += lLine;
+ lpIn += lInLine;
+
+ /* add EOL -- end of line */
+ lpbiOut->biSizeImage += 2;
+ *(LPWORD)lpOut = 0;
+ lpOut += sizeof(WORD);
+ assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
+ }
+ } else {
+ /* delta-frame -- compute delta between last and this internal frame */
+ LPWORD lpP;
+ INT x, y;
+ INT jumpx, jumpy;
+
+ assert(pi->pPrevFrame != NULL);
+
+ lpP = pi->pPrevFrame;
+ jumpy = 0;
+ jumpx = -1;
+
+ for (y = 0; y < lpbiOut->biHeight; y++) {
+ x = 0;
+
+ do {
+ INT count, pos;
+
+ if (jumpx == -1)
+ jumpx = x;
+ for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
+ if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
+ break;
+ }
+
+ if (pos == lpbiOut->biWidth && count > 8) {
+ /* (count > 8) secures that we will save space */
+ jumpy++;
+ break;
+ } else if (jumpy || jumpx != pos) {
+ /* time to jump */
+ assert(jumpx != -1);
+
+ if (pos < jumpx) {
+ /* can only jump in positive direction -- jump until EOL, EOL */
+ INT w = lpbiOut->biWidth - jumpx;
+
+ assert(jumpy > 0);
+ assert(w >= 4);
+
+ jumpx = 0;
+ jumpy--;
+ /* if (w % 255 == 2) then equal costs
+ * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
+ * else it will be cheaper
+ */
+ while (w > 0) {
+ lpbiOut->biSizeImage += 4;
+ *lpOut++ = 0;
+ *lpOut++ = 2;
+ *lpOut = min(w, 255);
+ w -= *lpOut++;
+ *lpOut++ = 0;
+ }
+ /* add EOL -- end of line */
+ lpbiOut->biSizeImage += 2;
+ *((LPWORD)lpOut) = 0;
+ lpOut += sizeof(WORD);
+ }
+
+ /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
+
+ /* write out real jump(s) */
+ while (jumpy || pos != jumpx) {
+ lpbiOut->biSizeImage += 4;
+ *lpOut++ = 0;
+ *lpOut++ = 2;
+ *lpOut = min(pos - jumpx, 255);
+ x += *lpOut;
+ jumpx += *lpOut++;
+ *lpOut = min(jumpy, 255);
+ jumpy -= *lpOut++;
+ }
+
+ jumpy = 0;
+ }
+
+ jumpx = -1;
+
+ if (x < lpbiOut->biWidth) {
+ /* skipped the 'same' things corresponding to previous frame */
+ x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
+ &lpOut, &lpbiOut->biSizeImage);
+ }
+ } while (x < lpbiOut->biWidth);
+
+ lpP += lLine;
+ lpC += lLine;
+ lpIn += lInLine;
+
+ if (jumpy == 0) {
+ assert(jumpx == -1);
+
+ /* add EOL -- end of line */
+ lpbiOut->biSizeImage += 2;
+ *((LPWORD)lpOut) = 0;
+ lpOut += sizeof(WORD);
+ assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
+ }
+ }
+
+ /* add EOL -- will be changed to EOI */
+ lpbiOut->biSizeImage += 2;
+ *((LPWORD)lpOut) = 0;
+ lpOut += sizeof(WORD);
+ }
+
+ /* change EOL to EOI -- end of image */
+ lpOut[-1] = 1;
+ assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
+
+ return ICERR_OK;
+}
+
+LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
+ LPBYTE lpOut, BOOL isKey)
+{
+ LPWORD lpC;
+ LONG lDist, lInLine, lLine;
+ LPBYTE lpOutStart = lpOut;
+
+ assert(pi != NULL && lpbiOut != NULL);
+ assert(lpIn != NULL && lpOut != NULL);
+ assert(pi->pCurFrame != NULL);
+
+ lpC = pi->pCurFrame;
+ lDist = QUALITY_to_DIST(pi->dwQuality);
+ lInLine = DIBWIDTHBYTES(*lpbiIn);
+ lLine = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
+
+ lpbiOut->biSizeImage = 0;
+ if (isKey) {
+ /* keyframe -- convert internal frame to output format */
+ INT x, y;
+
+ for (y = 0; y < lpbiOut->biHeight; y++) {
+ x = 0;
+
+ do {
+ x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
+ &lpOut, &lpbiOut->biSizeImage);
+ assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
+ } while (x < lpbiOut->biWidth);
+
+ lpC += lLine;
+ lpIn += lInLine;
+
+ /* add EOL -- end of line */
+ lpbiOut->biSizeImage += 2;
+ *((LPWORD)lpOut) = 0;
+ lpOut += sizeof(WORD);
+ assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
+ }
+ } else {
+ /* delta-frame -- compute delta between last and this internal frame */
+ LPWORD lpP;
+ INT x, y;
+ INT jumpx, jumpy;
+
+ assert(pi->pPrevFrame != NULL);
+
+ lpP = pi->pPrevFrame;
+ jumpx = -1;
+ jumpy = 0;
+
+ for (y = 0; y < lpbiOut->biHeight; y++) {
+ x = 0;
+
+ do {
+ INT count, pos;
+
+ if (jumpx == -1)
+ jumpx = x;
+ for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
+ if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
+ break;
+ }
+
+ if (pos == lpbiOut->biWidth && count > 4) {
+ /* (count > 4) secures that we will save space */
+ jumpy++;
+ break;
+ } else if (jumpy || jumpx != pos) {
+ /* time to jump */
+ assert(jumpx != -1);
+
+ if (pos < jumpx) {
+ /* can only jump in positive direction -- do an EOL then jump */
+ assert(jumpy > 0);
+
+ jumpx = 0;
+ jumpy--;
+
+ /* add EOL -- end of line */
+ lpbiOut->biSizeImage += 2;
+ *((LPWORD)lpOut) = 0;
+ lpOut += sizeof(WORD);
+ assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
+ }
+
+ /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
+
+ /* write out real jump(s) */
+ while (jumpy || pos != jumpx) {
+ lpbiOut->biSizeImage += 4;
+ *lpOut++ = 0;
+ *lpOut++ = 2;
+ *lpOut = min(pos - jumpx, 255);
+ jumpx += *lpOut++;
+ *lpOut = min(jumpy, 255);
+ jumpy -= *lpOut++;
+ }
+ x = pos;
+
+ jumpy = 0;
+ }
+
+ jumpx = -1;
+
+ if (x < lpbiOut->biWidth) {
+ /* skip the 'same' things corresponding to previous frame */
+ x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
+ &lpOut, &lpbiOut->biSizeImage);
+ assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
+ }
+ } while (x < lpbiOut->biWidth);
+
+ lpP += lLine;
+ lpC += lLine;
+ lpIn += lInLine;
+
+ if (jumpy == 0) {
+ /* add EOL -- end of line */
+ lpbiOut->biSizeImage += 2;
+ *((LPWORD)lpOut) = 0;
+ lpOut += sizeof(WORD);
+ assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
+ }
+ }
+
+ /* add EOL -- will be changed to EOI */
+ lpbiOut->biSizeImage += 2;
+ *((LPWORD)lpOut) = 0;
+ lpOut += sizeof(WORD);
+ }
+
+ /* change EOL to EOI -- end of image */
+ lpOut[-1] = 1;
+ assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
+
+ return ICERR_OK;
+}
+
+/*****************************************************************************/
+
+static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
+ const BYTE *lpIn, LPBYTE lpOut)
+{
+ int bytes_per_pixel;
+ int line_size;
+ int pixel_ptr = 0;
+ int i;
+ BOOL bEndFlag = FALSE;
+
+ assert(pi != NULL);
+ assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
+ assert(lpIn != NULL && lpOut != NULL);
+
+ bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
+ line_size = DIBWIDTHBYTES(*lpbi);
+
+ do {
+ BYTE code0, code1;
+
+ code0 = *lpIn++;
+ code1 = *lpIn++;
+
+ if (code0 == 0) {
+ int extra_byte;
+
+ switch (code1) {
+ case 0: /* EOL - end of line */
+ pixel_ptr = 0;
+ lpOut += line_size;
+ break;
+ case 1: /* EOI - end of image */
+ bEndFlag = TRUE;
+ break;
+ case 2: /* skip */
+ pixel_ptr += *lpIn++ * bytes_per_pixel;
+ lpOut += *lpIn++ * line_size;
+ if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
+ pixel_ptr = 0;
+ lpOut += line_size;
+ }
+ break;
+ default: /* absolute mode */
+ extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
+
+ if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
+ return ICERR_ERROR;
+
+ code0 = code1;
+ for (i = 0; i < code0 / 2; i++) {
+ if (bytes_per_pixel == 1) {
+ code1 = lpIn[i];
+ lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
+ if (2 * i + 1 <= code0)
+ lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
+ } else if (bytes_per_pixel == 2) {
+ code1 = lpIn[i] >> 4;
+ lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
+ lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
+
+ if (2 * i + 1 <= code0) {
+ code1 = lpIn[i] & 0x0F;
+ lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
+ lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
+ }
+ } else {
+ code1 = lpIn[i] >> 4;
+ lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
+ lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
+ lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
+ pixel_ptr += bytes_per_pixel;
+
+ if (2 * i + 1 <= code0) {
+ code1 = lpIn[i] & 0x0F;
+ lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
+ lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
+ lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
+ pixel_ptr += bytes_per_pixel;
+ }
+ }
+ }
+ if (code0 & 0x01) {
+ if (bytes_per_pixel == 1) {
+ code1 = lpIn[i];
+ lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
+ } else if (bytes_per_pixel == 2) {
+ code1 = lpIn[i] >> 4;
+ lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
+ lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
+ } else {
+ code1 = lpIn[i] >> 4;
+ lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
+ lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
+ lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
+ pixel_ptr += bytes_per_pixel;
+ }
+ lpIn++;
+ }
+ lpIn += code0 / 2;
+
+ /* if the RLE code is odd, skip a byte in the stream */
+ if (extra_byte)
+ lpIn++;
+ };
+ } else {
+ /* coded mode */
+ if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
+ return ICERR_ERROR;
+
+ if (bytes_per_pixel == 1) {
+ BYTE c1 = pi->palette_map[(code1 >> 4)];
+ BYTE c2 = pi->palette_map[(code1 & 0x0F)];
+
+ for (i = 0; i < code0; i++) {
+ if ((i & 1) == 0)
+ lpOut[pixel_ptr++] = c1;
+ else
+ lpOut[pixel_ptr++] = c2;
+ }
+ } else if (bytes_per_pixel == 2) {
+ BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
+ BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
+
+ BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
+ BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
+
+ for (i = 0; i < code0; i++) {
+ if ((i & 1) == 0) {
+ lpOut[pixel_ptr++] = hi1;
+ lpOut[pixel_ptr++] = lo1;
+ } else {
+ lpOut[pixel_ptr++] = hi2;
+ lpOut[pixel_ptr++] = lo2;
+ }
+ }
+ } else {
+ BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
+ BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
+ BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
+
+ BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
+ BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
+ BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
+
+ for (i = 0; i < code0; i++) {
+ if ((i & 1) == 0) {
+ lpOut[pixel_ptr + 0] = b1;
+ lpOut[pixel_ptr + 1] = g1;
+ lpOut[pixel_ptr + 2] = r1;
+ } else {
+ lpOut[pixel_ptr + 0] = b2;
+ lpOut[pixel_ptr + 1] = g2;
+ lpOut[pixel_ptr + 2] = r2;
+ }
+ pixel_ptr += bytes_per_pixel;
+ }
+ }
+ }
+ } while (! bEndFlag);
+
+ return ICERR_OK;
+}
+
+static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
+ const BYTE *lpIn, LPBYTE lpOut)
+{
+ int bytes_per_pixel;
+ int line_size;
+ int pixel_ptr = 0;
+ BOOL bEndFlag = FALSE;
+
+ assert(pi != NULL);
+ assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
+ assert(lpIn != NULL && lpOut != NULL);
+
+ bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
+ line_size = DIBWIDTHBYTES(*lpbi);
+
+ do {
+ BYTE code0, code1;
+
+ code0 = *lpIn++;
+ code1 = *lpIn++;
+
+ if (code0 == 0) {
+ int extra_byte;
+
+ switch (code1) {
+ case 0: /* EOL - end of line */
+ pixel_ptr = 0;
+ lpOut += line_size;
+ break;
+ case 1: /* EOI - end of image */
+ bEndFlag = TRUE;
+ break;
+ case 2: /* skip */
+ pixel_ptr += *lpIn++ * bytes_per_pixel;
+ lpOut += *lpIn++ * line_size;
+ if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
+ pixel_ptr = 0;
+ lpOut += line_size;
+ }
+ break;
+ default: /* absolute mode */
+ if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
+ WARN("aborted absolute: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
+ return ICERR_ERROR;
+ }
+ extra_byte = code1 & 0x01;
+
+ code0 = code1;
+ while (code0--) {
+ code1 = *lpIn++;
+ if (bytes_per_pixel == 1) {
+ lpOut[pixel_ptr] = pi->palette_map[code1];
+ } else if (bytes_per_pixel == 2) {
+ lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
+ lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
+ } else {
+ lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
+ lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
+ lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
+ }
+ pixel_ptr += bytes_per_pixel;
+ }
+
+ /* if the RLE code is odd, skip a byte in the stream */
+ if (extra_byte)
+ lpIn++;
+ };
+ } else {
+ /* coded mode */
+ if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
+ WARN("aborted coded: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
+ return ICERR_ERROR;
+ }
+
+ if (bytes_per_pixel == 1) {
+ code1 = pi->palette_map[code1];
+ while (code0--)
+ lpOut[pixel_ptr++] = code1;
+ } else if (bytes_per_pixel == 2) {
+ BYTE hi = pi->palette_map[code1 * 2 + 0];
+ BYTE lo = pi->palette_map[code1 * 2 + 1];
+
+ while (code0--) {
+ lpOut[pixel_ptr + 0] = hi;
+ lpOut[pixel_ptr + 1] = lo;
+ pixel_ptr += bytes_per_pixel;
+ }
+ } else {
+ BYTE r = pi->palette_map[code1 * 4 + 2];
+ BYTE g = pi->palette_map[code1 * 4 + 1];
+ BYTE b = pi->palette_map[code1 * 4 + 0];
+
+ while (code0--) {
+ lpOut[pixel_ptr + 0] = b;
+ lpOut[pixel_ptr + 1] = g;
+ lpOut[pixel_ptr + 2] = r;
+ pixel_ptr += bytes_per_pixel;
+ }
+ }
+ }
+ } while (! bEndFlag);
+
+ return ICERR_OK;
+}
+
+/*****************************************************************************/
+
+static CodecInfo* Open(LPICOPEN icinfo)
+{
+ CodecInfo* pi = NULL;
+
+ if (icinfo == NULL) {
+ TRACE("(NULL)\n");
+ return (LPVOID)0xFFFF0000;
+ }
+
+ if (icinfo->fccType != ICTYPE_VIDEO) return NULL;
+
+ TRACE("(%p = {%u,0x%08X(%4.4s),0x%08X(%4.4s),0x%X,0x%X,...})\n", icinfo,
+ icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
+ icinfo->fccHandler, (char*)&icinfo->fccHandler,
+ icinfo->dwVersion,icinfo->dwFlags);
+
+ switch (icinfo->fccHandler) {
+ case FOURCC_RLE:
+ case FOURCC_RLE4:
+ case FOURCC_RLE8:
+ case FOURCC_MRLE:
+ break;
+ case mmioFOURCC('m','r','l','e'):
+ icinfo->fccHandler = FOURCC_MRLE;
+ break;
+ default:
+ WARN("unknown FOURCC = 0x%08X(%4.4s) !\n",
+ icinfo->fccHandler,(char*)&icinfo->fccHandler);
+ return NULL;
+ }
+
+ pi = LocalAlloc(LPTR, sizeof(CodecInfo));
+
+ if (pi != NULL) {
+ pi->fccHandler = icinfo->fccHandler;
+
+ pi->bCompress = FALSE;
+ pi->dwQuality = MSRLE32_DEFAULTQUALITY;
+ pi->nPrevFrame = -1;
+ pi->pPrevFrame = pi->pCurFrame = NULL;
+
+ pi->bDecompress = FALSE;
+ pi->palette_map = NULL;
+ }
+
+ icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
+
+ return pi;
+}
+
+static LRESULT Close(CodecInfo *pi)
+{
+ TRACE("(%p)\n", pi);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
+ CompressEnd(pi);
+
+ LocalFree(pi);
+ return 1;
+}
+
+static LRESULT GetInfo(const CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
+{
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* check parameters */
+ if (icinfo == NULL)
+ return sizeof(ICINFO);
+ if (dwSize < sizeof(ICINFO))
+ return 0;
+
+ icinfo->dwSize = sizeof(ICINFO);
+ icinfo->fccType = ICTYPE_VIDEO;
+ icinfo->fccHandler = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
+ icinfo->dwFlags = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
+ icinfo->dwVersion = ICVERSION;
+ icinfo->dwVersionICM = ICVERSION;
+
+ LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
+ LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
+
+ return sizeof(ICINFO);
+}
+
+static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
+{
+ /* pre-condition */
+ assert(pi != NULL);
+
+ if (lQuality == -1)
+ lQuality = MSRLE32_DEFAULTQUALITY;
+ else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
+ return ICERR_BADPARAM;
+
+ pi->dwQuality = (DWORD)lQuality;
+
+ return ICERR_OK;
+}
+
+static LRESULT Configure(const CodecInfo *pi, HWND hWnd)
+{
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* FIXME */
+ return ICERR_OK;
+}
+
+static LRESULT About(CodecInfo *pi, HWND hWnd)
+{
+ WCHAR szTitle[20];
+ WCHAR szAbout[128];
+
+ /* pre-condition */
+ assert(MSRLE32_hModule != 0);
+
+ LoadStringW(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
+ LoadStringW(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout)/sizeof(szAbout[0]));
+
+ MessageBoxW(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
+
+ return ICERR_OK;
+}
+
+static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPBITMAPINFOHEADER lpbiOut)
+{
+ LRESULT size;
+
+ TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* check parameters -- need at least input format */
+ if (lpbiIn == NULL) {
+ if (lpbiOut != NULL)
+ return ICERR_BADPARAM;
+ return 0;
+ }
+
+ /* handle unsupported input format */
+ if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
+ return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
+
+ assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
+
+ switch (pi->fccHandler) {
+ case FOURCC_RLE4:
+ size = 1 << 4;
+ break;
+ case FOURCC_RLE8:
+ size = 1 << 8;
+ break;
+ case FOURCC_RLE:
+ case FOURCC_MRLE:
+ size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
+ break;
+ default:
+ return ICERR_ERROR;
+ }
+
+ if (lpbiIn->biClrUsed != 0)
+ size = lpbiIn->biClrUsed;
+
+ size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
+
+ if (lpbiOut != NULL) {
+ lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
+ lpbiOut->biWidth = lpbiIn->biWidth;
+ lpbiOut->biHeight = lpbiIn->biHeight;
+ lpbiOut->biPlanes = 1;
+ if (pi->fccHandler == FOURCC_RLE4 ||
+ lpbiIn->biBitCount <= 4) {
+ lpbiOut->biCompression = BI_RLE4;
+ lpbiOut->biBitCount = 4;
+ } else {
+ lpbiOut->biCompression = BI_RLE8;
+ lpbiOut->biBitCount = 8;
+ }
+ lpbiOut->biSizeImage = MSRLE32_GetMaxCompressedSize(lpbiOut);
+ lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
+ lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
+ if (lpbiIn->biClrUsed == 0)
+ size = 1<biBitCount;
+ else
+ size = lpbiIn->biClrUsed;
+ lpbiOut->biClrUsed = min(size, 1 << lpbiOut->biBitCount);
+ lpbiOut->biClrImportant = 0;
+
+ memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
+ (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
+
+ return ICERR_OK;
+ } else
+ return size;
+}
+
+static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut)
+{
+ /* pre-condition */
+ assert(pi != NULL);
+
+ TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+ /* check parameter -- need at least one format */
+ if (lpbiIn == NULL && lpbiOut == NULL)
+ return 0;
+ /* check if the given format is supported */
+ if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
+ return 0;
+
+ /* the worst case is coding the complete image in absolute mode. */
+ if (lpbiIn)
+ return MSRLE32_GetMaxCompressedSize(lpbiIn);
+ else
+ return MSRLE32_GetMaxCompressedSize(lpbiOut);
+}
+
+static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut)
+{
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* need at least one format */
+ if (lpbiIn == NULL && lpbiOut == NULL)
+ return ICERR_BADPARAM;
+
+ /* check input format if given */
+ if (lpbiIn != NULL) {
+ if (!isSupportedDIB(lpbiIn))
+ return ICERR_BADFORMAT;
+
+ /* for 4-bit need an even width */
+ if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
+ return ICERR_BADFORMAT;
+
+ if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
+ return ICERR_UNSUPPORTED;
+ else if (lpbiIn->biBitCount > 8)
+ return ICERR_UNSUPPORTED;
+ }
+
+ /* check output format if given */
+ if (lpbiOut != NULL) {
+ if (!isSupportedMRLE(lpbiOut))
+ return ICERR_BADFORMAT;
+
+ if (lpbiIn != NULL) {
+ if (lpbiIn->biWidth != lpbiOut->biWidth)
+ return ICERR_UNSUPPORTED;
+ if (lpbiIn->biHeight != lpbiOut->biHeight)
+ return ICERR_UNSUPPORTED;
+ if (lpbiIn->biBitCount > lpbiOut->biBitCount)
+ return ICERR_UNSUPPORTED;
+ }
+ }
+
+ return ICERR_OK;
+}
+
+static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut)
+{
+ const RGBQUAD *rgbIn;
+ const RGBQUAD *rgbOut;
+ UINT i;
+ size_t size;
+
+ TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* check parameters -- need both formats */
+ if (lpbiIn == NULL || lpbiOut == NULL)
+ return ICERR_BADPARAM;
+ /* And both must be supported */
+ if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
+ return ICERR_BADFORMAT;
+
+ /* FIXME: cannot compress and decompress at same time! */
+ if (pi->bDecompress) {
+ FIXME("cannot compress and decompress at same time!\n");
+ return ICERR_ERROR;
+ }
+
+ if (pi->bCompress)
+ CompressEnd(pi);
+
+ size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
+ pi->pPrevFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
+ if (pi->pPrevFrame == NULL)
+ return ICERR_MEMORY;
+ pi->pCurFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
+ if (pi->pCurFrame == NULL) {
+ CompressEnd(pi);
+ return ICERR_MEMORY;
+ }
+ pi->nPrevFrame = -1;
+ pi->bCompress = TRUE;
+
+ rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
+ rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
+
+ switch (lpbiOut->biBitCount) {
+ case 4:
+ case 8:
+ pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed);
+ if (pi->palette_map == NULL) {
+ CompressEnd(pi);
+ return ICERR_MEMORY;
+ }
+
+ for (i = 0; i < lpbiIn->biClrUsed; i++) {
+ pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
+ }
+ break;
+ };
+
+ return ICERR_OK;
+}
+
+static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
+{
+ int i;
+
+ TRACE("(%p,%p,%u)\n",pi,lpic,dwSize);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* check parameters */
+ if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
+ return ICERR_BADPARAM;
+ if (!lpic->lpbiOutput || !lpic->lpOutput ||
+ !lpic->lpbiInput || !lpic->lpInput)
+ return ICERR_BADPARAM;
+
+ TRACE("lpic={0x%X,%p,%p,%p,%p,%p,%p,%d,%u,%u,%p,%p}\n",lpic->dwFlags,lpic->lpbiOutput,lpic->lpOutput,lpic->lpbiInput,lpic->lpInput,lpic->lpckid,lpic->lpdwFlags,lpic->lFrameNum,lpic->dwFrameSize,lpic->dwQuality,lpic->lpbiPrev,lpic->lpPrev);
+
+ if (! pi->bCompress) {
+ LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
+ if (hr != ICERR_OK)
+ return hr;
+ } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
+ return ICERR_BADFORMAT;
+
+ if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
+ /* we continue in the sequence so we need to initialize
+ * our internal framedata */
+
+ computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
+ } else if (lpic->lFrameNum == pi->nPrevFrame) {
+ /* Oops, compress same frame again ? Okay, as you wish.
+ * No need to recompute internal framedata, because we only swapped buffers */
+ LPWORD pTmp = pi->pPrevFrame;
+
+ pi->pPrevFrame = pi->pCurFrame;
+ pi->pCurFrame = pTmp;
+ } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
+ LPWORD pTmp;
+
+ WARN(": prev=%d cur=%d gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
+ if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
+ return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
+ if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
+ return ICERR_BADFORMAT;
+
+ WARN(": prev=%d cur=%d compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
+ computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
+
+ /* swap buffers for current and previous frame */
+ /* Don't free and alloc new -- costs to much time and they are of equal size ! */
+ pTmp = pi->pPrevFrame;
+ pi->pPrevFrame = pi->pCurFrame;
+ pi->pCurFrame = pTmp;
+ pi->nPrevFrame = lpic->lFrameNum;
+ }
+
+ for (i = 0; i < 3; i++) {
+ SetQuality(pi, lpic->dwQuality);
+
+ lpic->lpbiOutput->biSizeImage = 0;
+
+ if (lpic->lpbiOutput->biBitCount == 4)
+ MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput,
+ lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
+ else
+ MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput,
+ lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
+
+ if (lpic->dwFrameSize == 0 ||
+ lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
+ break;
+
+ if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
+ if (lpic->lpbiOutput->biBitCount == 4)
+ MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput,
+ lpic->lpbiOutput, lpic->lpOutput, TRUE);
+ else
+ MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput,
+ lpic->lpbiOutput, lpic->lpOutput, TRUE);
+
+ if (lpic->dwFrameSize == 0 ||
+ lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
+ WARN("switched to keyframe, was small enough!\n");
+ *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
+ *lpic->lpckid = MAKEAVICKID(cktypeDIBbits,
+ StreamFromFOURCC(*lpic->lpckid));
+ break;
+ }
+ }
+
+ if (lpic->dwQuality < 1000)
+ break;
+
+ lpic->dwQuality -= 1000; /* reduce quality by 10% */
+ }
+
+ { /* swap buffer for current and previous frame */
+ /* Don't free and alloc new -- costs to much time and they are of equal size ! */
+ register LPWORD pTmp = pi->pPrevFrame;
+
+ pi->pPrevFrame = pi->pCurFrame;
+ pi->pCurFrame = pTmp;
+ pi->nPrevFrame = lpic->lFrameNum;
+ }
+
+ return ICERR_OK;
+}
+
+static LRESULT CompressEnd(CodecInfo *pi)
+{
+ TRACE("(%p)\n",pi);
+
+ if (pi != NULL) {
+ if (pi->pPrevFrame != NULL)
+ {
+ GlobalUnlock(GlobalHandle(pi->pPrevFrame));
+ GlobalFree(GlobalHandle(pi->pPrevFrame));
+ }
+ if (pi->pCurFrame != NULL)
+ {
+ GlobalUnlock(GlobalHandle(pi->pCurFrame));
+ GlobalFree(GlobalHandle(pi->pCurFrame));
+ }
+ pi->pPrevFrame = NULL;
+ pi->pCurFrame = NULL;
+ pi->nPrevFrame = -1;
+ pi->bCompress = FALSE;
+ }
+
+ return ICERR_OK;
+}
+
+static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPBITMAPINFOHEADER lpbiOut)
+{
+ DWORD size;
+
+ TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ if (lpbiIn == NULL)
+ return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
+
+ if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
+ return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
+
+ size = lpbiIn->biSize;
+
+ if (lpbiIn->biBitCount <= 8)
+ size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
+
+ if (lpbiOut != NULL) {
+ memcpy(lpbiOut, lpbiIn, size);
+ lpbiOut->biCompression = BI_RGB;
+ lpbiOut->biSizeImage = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
+
+ return ICERR_OK;
+ } else
+ return size;
+}
+
+static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut)
+{
+ LRESULT hr = ICERR_OK;
+
+ TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* need at least one format */
+ if (lpbiIn == NULL && lpbiOut == NULL)
+ return ICERR_BADPARAM;
+
+ /* check input format if given */
+ if (lpbiIn != NULL) {
+ if (!isSupportedMRLE(lpbiIn))
+ return ICERR_BADFORMAT;
+ }
+
+ /* check output format if given */
+ if (lpbiOut != NULL) {
+ if (!isSupportedDIB(lpbiOut))
+ hr = ICERR_BADFORMAT;
+
+ if (lpbiIn != NULL) {
+ if (lpbiIn->biWidth != lpbiOut->biWidth)
+ hr = ICERR_UNSUPPORTED;
+ if (lpbiIn->biHeight != lpbiOut->biHeight)
+ hr = ICERR_UNSUPPORTED;
+ if (lpbiIn->biBitCount > lpbiOut->biBitCount)
+ hr = ICERR_UNSUPPORTED;
+ }
+ }
+
+ return hr;
+}
+
+static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPCBITMAPINFOHEADER lpbiOut)
+{
+ const RGBQUAD *rgbIn;
+ const RGBQUAD *rgbOut;
+ UINT i;
+
+ TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* check parameters */
+ if (lpbiIn == NULL || lpbiOut == NULL)
+ return ICERR_BADPARAM;
+ if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
+ return ICERR_BADFORMAT;
+
+ /* FIXME: cannot compress and decompress at a time! */
+ if (pi->bCompress) {
+ FIXME("cannot compress and decompress at same time!\n");
+ return ICERR_ERROR;
+ }
+
+ if (pi->bDecompress)
+ DecompressEnd(pi);
+
+ rgbIn = (const RGBQUAD*)((const BYTE*)lpbiIn + lpbiIn->biSize);
+ rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
+
+ switch (lpbiOut->biBitCount) {
+ case 4:
+ case 8:
+ pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed);
+ if (pi->palette_map == NULL)
+ return ICERR_MEMORY;
+
+ for (i = 0; i < lpbiIn->biClrUsed; i++) {
+ pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
+ }
+ break;
+ case 15:
+ case 16:
+ pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
+ if (pi->palette_map == NULL)
+ return ICERR_MEMORY;
+
+ for (i = 0; i < lpbiIn->biClrUsed; i++) {
+ WORD color;
+
+ if (lpbiOut->biBitCount == 15)
+ color = ((rgbIn[i].rgbRed >> 3) << 10)
+ | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
+ else
+ color = ((rgbIn[i].rgbRed >> 3) << 11)
+ | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
+
+ pi->palette_map[i * 2 + 1] = color >> 8;
+ pi->palette_map[i * 2 + 0] = color & 0xFF;
+ };
+ break;
+ case 24:
+ case 32:
+ pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
+ if (pi->palette_map == NULL)
+ return ICERR_MEMORY;
+ memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
+ break;
+ };
+
+ pi->bDecompress = TRUE;
+
+ return ICERR_OK;
+}
+
+static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
+{
+ TRACE("(%p,%p,%u)\n",pi,pic,dwSize);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* check parameters */
+ if (pic == NULL)
+ return ICERR_BADPARAM;
+ if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
+ pic->lpbiOutput == NULL || pic->lpOutput == NULL)
+ return ICERR_BADPARAM;
+
+ /* check formats */
+ if (! pi->bDecompress) {
+ LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
+ if (hr != ICERR_OK)
+ return hr;
+ } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
+ return ICERR_BADFORMAT;
+
+ assert(pic->lpbiInput->biWidth == pic->lpbiOutput->biWidth);
+ assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
+
+ pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
+ if (pic->lpbiInput->biBitCount == 4)
+ return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
+ else
+ return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
+}
+
+static LRESULT DecompressEnd(CodecInfo *pi)
+{
+ TRACE("(%p)\n",pi);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ pi->bDecompress = FALSE;
+
+ if (pi->palette_map != NULL) {
+ LocalFree(pi->palette_map);
+ pi->palette_map = NULL;
+ }
+
+ return ICERR_OK;
+}
+
+static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
+ LPBITMAPINFOHEADER lpbiOut)
+{
+ int size;
+
+ TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
+
+ /* pre-condition */
+ assert(pi != NULL);
+
+ /* check parameters */
+ if (lpbiIn == NULL || lpbiOut == NULL)
+ return ICERR_BADPARAM;
+
+ if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
+ return ICERR_BADFORMAT;
+
+ if (lpbiOut->biBitCount > 8)
+ return ICERR_ERROR;
+
+ if (lpbiIn->biBitCount <= 8) {
+ if (lpbiIn->biClrUsed > 0)
+ size = lpbiIn->biClrUsed;
+ else
+ size = (1 << lpbiIn->biBitCount);
+
+ lpbiOut->biClrUsed = size;
+
+ memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
+ } /* else could never occur ! */
+
+ return ICERR_OK;
+}
+
+/* DriverProc - entry point for an installable driver */
+LRESULT CALLBACK MSRLE32_DriverProc(DWORD_PTR dwDrvID, HDRVR hDrv, UINT uMsg,
+ LPARAM lParam1, LPARAM lParam2)
+{
+ CodecInfo *pi = (CodecInfo*)dwDrvID;
+
+ TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID, hDrv, uMsg, lParam1, lParam2);
+
+ switch (uMsg) {
+ /* standard driver messages */
+ case DRV_LOAD:
+ return DRVCNF_OK;
+ case DRV_OPEN:
+ return (LRESULT)Open((ICOPEN*)lParam2);
+ case DRV_CLOSE:
+ if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
+ Close(pi);
+ return DRVCNF_OK;
+ case DRV_ENABLE:
+ case DRV_DISABLE:
+ return DRVCNF_OK;
+ case DRV_FREE:
+ return DRVCNF_OK;
+ case DRV_QUERYCONFIGURE:
+ return DRVCNF_CANCEL; /* FIXME */
+ case DRV_CONFIGURE:
+ return DRVCNF_OK; /* FIXME */
+ case DRV_INSTALL:
+ case DRV_REMOVE:
+ return DRVCNF_OK;
+
+ /* installable compression manager messages */
+ case ICM_CONFIGURE:
+ FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
+ if (lParam1 == -1)
+ return ICERR_UNSUPPORTED; /* FIXME */
+ else
+ return Configure(pi, (HWND)lParam1);
+ case ICM_ABOUT:
+ if (lParam1 == -1)
+ return ICERR_OK;
+ else
+ return About(pi, (HWND)lParam1);
+ case ICM_GETSTATE:
+ case ICM_SETSTATE:
+ return 0; /* no state */
+ case ICM_GETINFO:
+ return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
+ case ICM_GETDEFAULTQUALITY:
+ if ((LPVOID)lParam1 != NULL) {
+ *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
+ return ICERR_OK;
+ }
+ break;
+ case ICM_GETQUALITY:
+ if ((LPVOID)lParam1 != NULL) {
+ *((LPDWORD)lParam1) = pi->dwQuality;
+ return ICERR_OK;
+ }
+ break;
+ case ICM_SETQUALITY:
+ return SetQuality(pi, *(LPLONG)lParam1);
+ case ICM_COMPRESS_GET_FORMAT:
+ return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
+ (LPBITMAPINFOHEADER)lParam2);
+ case ICM_COMPRESS_GET_SIZE:
+ return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
+ (LPCBITMAPINFOHEADER)lParam2);
+ case ICM_COMPRESS_QUERY:
+ return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
+ (LPCBITMAPINFOHEADER)lParam2);
+ case ICM_COMPRESS_BEGIN:
+ return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
+ (LPCBITMAPINFOHEADER)lParam2);
+ case ICM_COMPRESS:
+ return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
+ case ICM_COMPRESS_END:
+ return CompressEnd(pi);
+ case ICM_DECOMPRESS_GET_FORMAT:
+ return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
+ (LPBITMAPINFOHEADER)lParam2);
+ case ICM_DECOMPRESS_QUERY:
+ return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
+ (LPCBITMAPINFOHEADER)lParam2);
+ case ICM_DECOMPRESS_BEGIN:
+ return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
+ (LPCBITMAPINFOHEADER)lParam2);
+ case ICM_DECOMPRESS:
+ return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
+ case ICM_DECOMPRESS_END:
+ return DecompressEnd(pi);
+ case ICM_DECOMPRESS_SET_PALETTE:
+ FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
+ return ICERR_UNSUPPORTED;
+ case ICM_DECOMPRESS_GET_PALETTE:
+ return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
+ (LPBITMAPINFOHEADER)lParam2);
+ case ICM_GETDEFAULTKEYFRAMERATE:
+ if ((LPVOID)lParam1 != NULL)
+ *(LPDWORD)lParam1 = 15;
+ return ICERR_OK;
+ default:
+ if (uMsg < DRV_USER)
+ return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
+ else
+ FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
+ };
+
+ return ICERR_UNSUPPORTED;
+}
+
+/* DllMain - library initialization code */
+BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
+{
+ TRACE("(%p,%d,%p)\n",hModule,dwReason,lpReserved);
+
+ switch (dwReason) {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hModule);
+ MSRLE32_hModule = hModule;
+ break;
+
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+
+ return TRUE;
+}
diff --git a/reactos/dll/win32/msrle32/msrle32.rbuild b/reactos/dll/win32/msrle32/msrle32.rbuild
new file mode 100644
index 00000000000..a4db99ae7c7
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle32.rbuild
@@ -0,0 +1,13 @@
+
+
+ .
+ include/reactos/wine
+
+ msrle32.c
+ rsrc.rc
+ wine
+ winmm
+ user32
+ kernel32
+ ntdll
+
diff --git a/reactos/dll/win32/msrle32/msrle32.spec b/reactos/dll/win32/msrle32/msrle32.spec
new file mode 100644
index 00000000000..623cfea82bd
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle32.spec
@@ -0,0 +1 @@
+@ stdcall -private DriverProc(long long long long long) MSRLE32_DriverProc
diff --git a/reactos/dll/win32/msrle32/msrle_Bg.rc b/reactos/dll/win32/msrle32/msrle_Bg.rc
new file mode 100644
index 00000000000..7c0d4488a57
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Bg.rc
@@ -0,0 +1,28 @@
+/*
+ * Bulgarian resource file for MS-RLE
+ *
+ * Copyright 2005 Milko Krachounov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE âèäåî êîäåê"
+ IDS_ABOUT "Wine MS-RLE âèäåî êîäåê\nCopyright 2002 by Michael Gunnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Cs.rc b/reactos/dll/win32/msrle32/msrle_Cs.rc
new file mode 100644
index 00000000000..51fb1dfbef8
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Cs.rc
@@ -0,0 +1,32 @@
+/* Hey, Emacs, open this file with -*- coding: cp1250 -*-
+ *
+ * Czech resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ * Copyright 2004 David Kredba
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
+
+/* Czech strings in CP1250 */
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE video kodek"
+ IDS_ABOUT L"Wine MS-RLE video kodek\nCopyright 2002 Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Da.rc b/reactos/dll/win32/msrle32/msrle_Da.rc
new file mode 100644
index 00000000000..c3ea57b4f11
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Da.rc
@@ -0,0 +1,28 @@
+/*
+ * Danish language support
+ *
+ * Copyright (C) 2008 Jens Albretsen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_DANISH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE videokodeks"
+ IDS_ABOUT "Wine MS-RLE videokodeks\nOphavsret 2002 tilhører Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_De.rc b/reactos/dll/win32/msrle32/msrle_De.rc
new file mode 100644
index 00000000000..c5f4954e2ef
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_De.rc
@@ -0,0 +1,28 @@
+/*
+ * German resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE Videodekoder"
+ IDS_ABOUT "Wine MS-RLE Videodekoder\nCopyright 2002 by Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_En.rc b/reactos/dll/win32/msrle32/msrle_En.rc
new file mode 100644
index 00000000000..030a98a3aa5
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_En.rc
@@ -0,0 +1,28 @@
+/*
+ * English resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE video codec"
+ IDS_ABOUT "Wine MS-RLE video codec\nCopyright 2002 by Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Es.rc b/reactos/dll/win32/msrle32/msrle_Es.rc
new file mode 100644
index 00000000000..ca418cb7594
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Es.rc
@@ -0,0 +1,28 @@
+/*
+ * Spanish resource file for MS-RLE
+ *
+ * Copyright 2003 José Manuel Ferrer Ortiz
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Codec de vídeo MS-RLE de Wine"
+ IDS_ABOUT "Codec de vídeo MS-RLE de Wine\nCopyright 2002 por Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Fr.rc b/reactos/dll/win32/msrle32/msrle_Fr.rc
new file mode 100644
index 00000000000..e6eb31423f2
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Fr.rc
@@ -0,0 +1,28 @@
+/*
+ * French resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine: décodeur/encodeur vidéo MS-RLE"
+ IDS_ABOUT "Wine: décodeur/encodeur vidéo MS-RLE\nCopyright 2002 par Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Hu.rc b/reactos/dll/win32/msrle32/msrle_Hu.rc
new file mode 100644
index 00000000000..95016acb4d2
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Hu.rc
@@ -0,0 +1,28 @@
+/*
+ * Hungarian resource file for MS-RLE
+ *
+ * Copyright 2006 Andras Kovacs
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE video kodek"
+ IDS_ABOUT L"Wine MS-RLE video kodek\nCopyright 2002, Michael G\x00fcnnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_It.rc b/reactos/dll/win32/msrle32/msrle_It.rc
new file mode 100644
index 00000000000..695a78285f8
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_It.rc
@@ -0,0 +1,29 @@
+/*
+ * Italian resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ * Copyright 2003 Ivan Leo Puoti
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Codec video MS-RLE di Wine"
+ IDS_ABOUT "Codec video MS-RLE di Wine\nCopyright 2002 Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Ja.rc b/reactos/dll/win32/msrle32/msrle_Ja.rc
new file mode 100644
index 00000000000..c2866a155c1
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Ja.rc
@@ -0,0 +1,33 @@
+/*
+ * Japanese resource file for MS-RLE
+ *
+ * Copyright 2004 Hajime Segawa
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE ビデオコーデック"
+ IDS_ABOUT "Wine MS-RLE ビデオコーデック\nCopyright 2002 by Michael Günewig"
+}
+
+#pragma code_page(default)
diff --git a/reactos/dll/win32/msrle32/msrle_Ko.rc b/reactos/dll/win32/msrle32/msrle_Ko.rc
new file mode 100644
index 00000000000..3f9d137b009
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Ko.rc
@@ -0,0 +1,28 @@
+/*
+ * Korean resource file for MS-RLE
+ *
+ * Copyright 2005 YunSong Hwang
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE ºñµð¿À ÄÚµ¦"
+ IDS_ABOUT "Wine MS-RLE ºñµð¿À ÄÚµ¦\nCopyright 2002 by Michael Gunnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Nl.rc b/reactos/dll/win32/msrle32/msrle_Nl.rc
new file mode 100644
index 00000000000..f98f5fd9835
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Nl.rc
@@ -0,0 +1,28 @@
+/*
+ * MS-RLE (Dutch resources)
+ *
+ * Copyright 2003 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE videodecoder"
+ IDS_ABOUT "Wine MS-RLE videodecoder\nCopyright 2002 Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_No.rc b/reactos/dll/win32/msrle32/msrle_No.rc
new file mode 100644
index 00000000000..411e4590447
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_No.rc
@@ -0,0 +1,28 @@
+/*
+ * Norwegian Bokmål resource file for MS-RLE
+ *
+ * Copyright 2005 Alexander N. Sørnes
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE-videokodek"
+ IDS_ABOUT "Wine MS-RLE-videokodek\nKopirett 2002 tilhører Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Pl.rc b/reactos/dll/win32/msrle32/msrle_Pl.rc
new file mode 100644
index 00000000000..013fea5a0ed
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Pl.rc
@@ -0,0 +1,29 @@
+/*
+ * English resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Gnnewig
+ * Copyright 2006 Mikolaj Zalewski
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Kodek Wine MS-RLE"
+ IDS_ABOUT L"Koder-dekoder Wine MS-RLE\nCopyright 2002 - Michael G\x00fcnnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Pt.rc b/reactos/dll/win32/msrle32/msrle_Pt.rc
new file mode 100644
index 00000000000..cc74b38e981
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Pt.rc
@@ -0,0 +1,38 @@
+/*
+ * Portuguese resource file for MS-RLE
+ *
+ * Copyright 2003 Marcelo Duarte
+ * Copyright 2006 Américo José Melo
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE codificador/decodificador de vídeo"
+ IDS_ABOUT "Wine MS-RLE codificador/decodificador de vídeo\nCopyright 2002 por Michael Günnewig"
+}
+
+LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE codificador/decodificador de vídeo"
+ IDS_ABOUT "Wine MS-RLE codificador/decodificador de vídeo\nDireitos de autor 2002 por Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Ro.rc b/reactos/dll/win32/msrle32/msrle_Ro.rc
new file mode 100644
index 00000000000..64366c36a91
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Ro.rc
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2002 Michael Günnewig
+ * Copyright 2008 Michael Stefaniuc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
+
+#pragma code_page(65001)
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Codecul video Wine MS-RLE"
+ IDS_ABOUT "Codecul video Wine MS-RLE\nCopyright 2002 by Michael Günnewig"
+}
+
+#pragma code_page(default)
diff --git a/reactos/dll/win32/msrle32/msrle_Ru.rc b/reactos/dll/win32/msrle32/msrle_Ru.rc
new file mode 100644
index 00000000000..4f8bd56b158
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Ru.rc
@@ -0,0 +1,28 @@
+/*
+ * Russian resource file for MS-RLE
+ *
+ * Copyright 2003 Igor Stepin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Âèäåî êîäåê Wine MS-RLE"
+ IDS_ABOUT "Âèäåî êîäåê Wine MS-RLE\nCopyright 2002 by Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Si.rc b/reactos/dll/win32/msrle32/msrle_Si.rc
new file mode 100644
index 00000000000..eeb23739f7d
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Si.rc
@@ -0,0 +1,32 @@
+/*
+ * Slovenian resource file for MS-RLE
+ *
+ * Copyright 2003, 2008 Rok Mandeljc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#pragma code_page(65001)
+
+LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE video kodek"
+ IDS_ABOUT "Wine MS-RLE video kodek\nCopyright 2002 by Michael Günnewig"
+}
+
+#pragma code_page(default)
diff --git a/reactos/dll/win32/msrle32/msrle_Sv.rc b/reactos/dll/win32/msrle32/msrle_Sv.rc
new file mode 100644
index 00000000000..fba656a33d0
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Sv.rc
@@ -0,0 +1,28 @@
+/*
+ * Swedish resource file for MS-RLE
+ *
+ * Copyright 2007 Daniel Nylander
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE videokodek"
+ IDS_ABOUT "Wine MS-RLE videokodek\nCopyright 2002 Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_Tr.rc b/reactos/dll/win32/msrle32/msrle_Tr.rc
new file mode 100644
index 00000000000..36cee7531f1
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_Tr.rc
@@ -0,0 +1,28 @@
+/*
+ * Turkish resource file for MS-RLE
+ *
+ * Copyright 2006 Fatih Aþýcý
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_NAME "WINE-MS-RLE"
+ IDS_DESCRIPTION "Wine MS-RLE vidyo çözücü"
+ IDS_ABOUT "Wine MS-RLE vidyo çözücü\nTelif Hakký 2002 Michael Günnewig"
+}
diff --git a/reactos/dll/win32/msrle32/msrle_private.h b/reactos/dll/win32/msrle32/msrle_private.h
new file mode 100644
index 00000000000..bf2aed03213
--- /dev/null
+++ b/reactos/dll/win32/msrle32/msrle_private.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __MSRLE32_PRIVATE_H
+#define __MSRLE32_PRIVATE_H
+
+#ifndef RC_INVOKED
+#include
+#endif
+
+#include "windef.h"
+#include "winbase.h"
+#include "mmsystem.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "vfw.h"
+
+#define IDS_NAME 100
+#define IDS_DESCRIPTION 101
+#define IDS_ABOUT 102
+
+#define MSRLE32_DEFAULTQUALITY (75 * ICQUALITY_HIGH) / 100
+
+#define FOURCC_RLE mmioFOURCC('R','L','E',' ')
+#define FOURCC_RLE4 mmioFOURCC('R','L','E','4')
+#define FOURCC_RLE8 mmioFOURCC('R','L','E','8')
+#define FOURCC_MRLE mmioFOURCC('M','R','L','E')
+
+#define WIDTHBYTES(i) ((WORD)((i+31u)&(~31u))/8u) /* ULONG aligned ! */
+#define DIBWIDTHBYTES(bi) WIDTHBYTES((WORD)(bi).biWidth * (WORD)(bi).biBitCount)
+
+typedef struct _CodecInfo {
+ FOURCC fccHandler;
+ DWORD dwQuality;
+
+ BOOL bCompress;
+ LONG nPrevFrame;
+ LPWORD pPrevFrame;
+ LPWORD pCurFrame;
+
+ BOOL bDecompress;
+ LPBYTE palette_map;
+} CodecInfo;
+
+typedef const BITMAPINFOHEADER * LPCBITMAPINFOHEADER;
+
+#endif
diff --git a/reactos/dll/win32/msrle32/rsrc.rc b/reactos/dll/win32/msrle32/rsrc.rc
new file mode 100644
index 00000000000..6d3ff958153
--- /dev/null
+++ b/reactos/dll/win32/msrle32/rsrc.rc
@@ -0,0 +1,53 @@
+/*
+ * Top level resource file for MS-RLE
+ *
+ * Copyright 2002 Michael Günnewig
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "windef.h"
+#include "winbase.h"
+
+#include "msrle_private.h"
+
+/*
+ * Everything specific to any language goes
+ * in one of the specific files.
+ * Note that you can and may override resources
+ * which also have a neutral version. This is to
+ * get localized bitmaps for example.
+ */
+
+#include "msrle_Bg.rc"
+#include "msrle_Cs.rc"
+#include "msrle_Da.rc"
+#include "msrle_De.rc"
+#include "msrle_En.rc"
+#include "msrle_Es.rc"
+#include "msrle_Fr.rc"
+#include "msrle_Hu.rc"
+#include "msrle_It.rc"
+#include "msrle_Ja.rc"
+#include "msrle_Ko.rc"
+#include "msrle_Nl.rc"
+#include "msrle_No.rc"
+#include "msrle_Pl.rc"
+#include "msrle_Pt.rc"
+#include "msrle_Ro.rc"
+#include "msrle_Ru.rc"
+#include "msrle_Si.rc"
+#include "msrle_Sv.rc"
+#include "msrle_Tr.rc"
diff --git a/reactos/dll/win32/win32.rbuild b/reactos/dll/win32/win32.rbuild
index 681aeb99d75..17cb60f4dd1 100644
--- a/reactos/dll/win32/win32.rbuild
+++ b/reactos/dll/win32/win32.rbuild
@@ -193,9 +193,15 @@
+
+
+
+
+
+
@@ -214,6 +220,9 @@
+
+
+
diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE
index 99c4ab08bff..491e743fc2b 100644
--- a/reactos/media/doc/README.WINE
+++ b/reactos/media/doc/README.WINE
@@ -65,11 +65,14 @@ reactos/dll/win32/mlang # Autosync
reactos/dll/win32/mpr # Autosync
reactos/dll/win32/msacm32 # Out of sync
reactos/dll/win32/mscat32 # Autosync
+reactos/dll/win32/mscms # Autosync
reactos/dll/win32/mscoree # Autosync
+reactos/dll/win32/msftedit # Autosync
reactos/dll/win32/mshtml # Autosync
reactos/dll/win32/msimg32 # Autosync
reactos/dll/win32/msi # Autosync
reactos/dll/win32/msimtf # Autosync
+reactos/dll/win32/msrle32 # Autosync
reactos/dll/win32/mstask # Autosync
reactos/dll/win32/msvcrt20 # Autosync
reactos/dll/win32/msvfw32 # Autosync