Index: dlls/kernel/profile.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/profile.c,v
retrieving revision 1.4
diff -u -r1.4 profile.c
--- dlls/kernel/profile.c	17 Nov 2003 20:31:30 -0000	1.4
+++ dlls/kernel/profile.c	15 Dec 2003 01:59:37 -0000
@@ -3,6 +3,7 @@
  *
  * Copyright 1993 Miguel de Icaza
  * Copyright 1996 Alexandre Julliard
+ * Copyright 2003 Kevin Koltzau
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -63,10 +64,13 @@
     WCHAR                       name[1];
 } PROFILESECTION;
 
+#define PROFILE_UNICODE     1
+#define PROFILE_UNICODE_REV 2
 
 typedef struct
 {
     BOOL             changed;
+    BOOL            unicode;
     PROFILESECTION  *section;
     WCHAR           *dos_name;
     char            *unix_name;
@@ -123,34 +127,89 @@
     if (quote && (len >= strlenW(value))) buffer[strlenW(buffer)-1] = '\0';
 }
 
+/***********************************************************************
+ *           PROFILE_Frob
+ *
+ * Reverse the byte order for a string.
+ */
+static void PROFILE_Frob(LPWSTR lpStr)
+{
+    LPWSTR s = lpStr;
+    char tmp[2];
+    while (*s)
+    {
+        tmp[0] = ((char*)s)[1];
+        tmp[1] = ((char*)s)[0];
+        *s++ = *(WCHAR*)tmp;
+    }
+}
+
+/***********************************************************************
+ *           PROFILE_WriteLine
+ *
+ * Writes a line of data to file, converting text as needed.
+ */
+static void PROFILE_WriteLine( FILE *file, LPWSTR line, BOOL unicode )
+{
+    char buffer[PROFILE_MAX_LINE_LEN];
+    int len;
+
+    TRACE("%s %d\n", debugstr_w(line), unicode);
+
+    if (!unicode)
+    {
+        len = WideCharToMultiByte(CP_ACP, 0, line, -1, buffer, sizeof(buffer), NULL, NULL)-1;
+        fwrite( buffer, len, 1, file );
+    }
+    else
+    {
+        len = strlenW( line );
+        if (unicode == PROFILE_UNICODE_REV)
+            PROFILE_Frob( line );
+        fwrite( line, len * sizeof(WCHAR), 1, file );
+    }
+}
 
 /***********************************************************************
  *           PROFILE_Save
  *
  * Save a profile tree to a file.
  */
-static void PROFILE_Save( FILE *file, PROFILESECTION *section )
+static void PROFILE_Save( FILE *file, PROFILESECTION *section, BOOL unicode )
 {
     PROFILEKEY *key;
-    char buffer[PROFILE_MAX_LINE_LEN];
+    WCHAR buffer[PROFILE_MAX_LINE_LEN];
 
+    WCHAR equ[] = {'=',0};
+    WCHAR lf[] = {'\r','\n',0};
+    WCHAR secstart[] = {'\r','\n','[',0};
+    WCHAR secend[] = {']','\r','\n',0};
+
+    if (unicode == PROFILE_UNICODE)
+        fwrite( "\xFF\xFE", 2, 1, file );
+    else if (unicode == PROFILE_UNICODE_REV)
+        fwrite( "\xFE\xFF", 2, 1, file );
     for ( ; section; section = section->next)
     {
         if (section->name[0])
         {
-            WideCharToMultiByte(CP_ACP, 0, section->name, -1, buffer, sizeof(buffer), NULL, NULL);
-            fprintf( file, "\r\n[%s]\r\n", buffer );
+            int len;
+            strcpyW(buffer, secstart);
+            strcatW(buffer, section->name);
+            strcatW(buffer, secend);
+            PROFILE_WriteLine( file, buffer, unicode );
         }
         for (key = section->key; key; key = key->next)
         {
-            WideCharToMultiByte(CP_ACP, 0, key->name, -1, buffer, sizeof(buffer), NULL, NULL);
-            fprintf( file, "%s", buffer );
+            int len;
+            strcpyW(buffer, key->name);
             if (key->value)
             {
-                 WideCharToMultiByte(CP_ACP, 0, key->value, -1, buffer, sizeof(buffer), NULL, NULL);
-                 fprintf( file, "=%s", buffer );
+                strcatW(buffer, equ);
+                strcatW(buffer, key->value);
+                strcatW(buffer, lf);
             }
-            fprintf( file, "\r\n" );
+            PROFILE_WriteLine( file, buffer, unicode );
         }
     }
 }
@@ -179,24 +238,76 @@
     }
 }
 
-static inline int PROFILE_isspace(char c)
+static inline int PROFILE_isspace(WCHAR c)
 {
-	if (isspace(c)) return 1;
+	if (isspaceW(c)) return 1;
 	if (c=='\r' || c==0x1a) return 1;
 	/* CR and ^Z (DOS EOF) are spaces too  (found on CD-ROMs) */
 	return 0;
 }
 
+/***********************************************************************
+ *           PROFILE_fgets
+ *
+ * Psudo clone of fgets, for reading wide char files
+ */
+WCHAR *PROFILE_fgets(FILE* file, LPWSTR s, BOOL unicode)
+{
+    char tmp[2];
+    WCHAR cc;
+    WCHAR *buf_start = s;
+    size_t amtread;
+    int size = PROFILE_MAX_LINE_LEN;
+
+    while ((size >1) && (amtread = fread(&cc, sizeof(cc), 1, file)) == 1)
+    {
+        if (unicode == PROFILE_UNICODE_REV)
+        {
+            tmp[0] = ((char*)&cc)[1];
+            tmp[1] = ((char*)&cc)[0];
+            cc = *(WCHAR*)tmp;
+        }
+        if (cc == '\n')
+            break;
+        *s++ = cc;
+        size --;
+    }
+    if ((amtread != 1) && (s == buf_start)) /* If nothing read, return 0*/
+        return NULL;
+    *s = 0;
+    return buf_start;
+}
+
+/***********************************************************************
+ *           PROFILE_ReadLine
+ *
+ * Reads a line from a file, converting to unicode if needed.
+ */
+static BOOL PROFILE_ReadLine( FILE *file, LPWSTR buffer, BOOL unicode )
+{
+    if (!unicode)
+    {
+        char tmp[PROFILE_MAX_LINE_LEN];
+        if (fgets( tmp, PROFILE_MAX_LINE_LEN, file ))
+        {
+            MultiByteToWideChar(CP_ACP, 0, tmp, -1, buffer, PROFILE_MAX_LINE_LEN);
+            return TRUE;
+        }
+    }
+    if (PROFILE_fgets( file, buffer, unicode ))
+        return TRUE;
+    return FALSE;
+}
 
 /***********************************************************************
  *           PROFILE_Load
  *
  * Load a profile tree from a file.
  */
-static PROFILESECTION *PROFILE_Load( FILE *file )
+static PROFILESECTION *PROFILE_Load( FILE *file, BOOL unicode )
 {
-    char buffer[PROFILE_MAX_LINE_LEN];
-    char *p, *p2;
+    WCHAR buffer[PROFILE_MAX_LINE_LEN];
+    WCHAR *p, *p2;
     int line = 0, len;
     PROFILESECTION *section, *first_section;
     PROFILESECTION **next_section;
@@ -211,26 +322,26 @@
     next_key     = &first_section->key;
     prev_key     = NULL;
 
-    while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
+    while (PROFILE_ReadLine( file, buffer, unicode ))
     {
         line++;
         p = buffer;
         while (*p && PROFILE_isspace(*p)) p++;
         if (*p == '[')  /* section start */
         {
-            if (!(p2 = strrchr( p, ']' )))
+            if (!(p2 = strrchrW( p, ']' )))
             {
                 WARN("Invalid section header at line %d: '%s'\n",
-		     line, p );
+                     line, debugstr_w(p) );
             }
             else
             {
                 *p2 = '\0';
                 p++;
-                len = strlen(p);
+                len = strlenW(p);
                 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR) )))
                     break;
-                MultiByteToWideChar(CP_ACP, 0, p, -1, section->name, len + 1);
+                strcpyW(section->name, p);
                 section->key  = NULL;
                 section->next = NULL;
                 *next_section = section;
@@ -244,10 +355,10 @@
             }
         }
 
-        p2=p+strlen(p) - 1;
+        p2=p+strlenW(p) - 1;
         while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
 
-        if ((p2 = strchr( p, '=' )) != NULL)
+        if ((p2 = strchrW( p, '=' )) != NULL)
         {
             char *p3 = p2 - 1;
             while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
@@ -257,14 +368,14 @@
 
         if(*p || !prev_key || *prev_key->name)
         {
-            len = strlen(p);
+            len = strlenW(p);
             if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + len * sizeof(WCHAR) ))) break;
-            MultiByteToWideChar(CP_ACP, 0, p, -1, key->name, len + 1);
+            strcpyW(key->name, p);
             if (p2)
             {
-                len = strlen(p2) + 1;
+                len = strlenW(p2) + 1;
                 key->value = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
-                MultiByteToWideChar(CP_ACP, 0, p2, -1, key->value, len);
+                strcpyW(key->value, p2);
             }
             else key->value = NULL;
 
@@ -484,7 +595,7 @@
     }
 
     TRACE("Saving %s into '%s'\n", debugstr_w(CurProfile->dos_name), unix_name );
-    PROFILE_Save( file, CurProfile->section );
+    PROFILE_Save( file, CurProfile->section, CurProfile->unicode );
     fclose( file );
     CurProfile->changed = FALSE;
     if(!stat(unix_name,&buf))
@@ -506,6 +617,7 @@
     if (CurProfile->unix_name) HeapFree( GetProcessHeap(), 0, CurProfile->unix_name );
     if (CurProfile->filename) HeapFree( GetProcessHeap(), 0, CurProfile->filename );
     CurProfile->changed   = FALSE;
+    CurProfile->unicode   = 0;
     CurProfile->section   = NULL;
     CurProfile->dos_name  = NULL;
     CurProfile->unix_name = NULL;
@@ -513,6 +625,23 @@
     CurProfile->mtime     = 0;
 }
 
+/***********************************************************************
+ *           PROFILE_IsUnicode
+ *
+ * Determine if file is unicode based on BOM
+ */
+static BOOL PROFILE_IsUnicode( FILE *file )
+{
+    WORD sig;
+    fread(&sig, 2, 1, file);
+
+    if( sig == 0xFEFF )
+        return PROFILE_UNICODE;
+    if( sig == 0xFFFE )
+      return PROFILE_UNICODE_REV;
+    rewind( file );
+    return FALSE;
+}
 
 /***********************************************************************
  *           PROFILE_Open
@@ -539,6 +668,7 @@
           MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) );
 	  if(MRUProfile[i] == NULL) break;
           MRUProfile[i]->changed=FALSE;
+          MRUProfile[i]->unicode=0;
           MRUProfile[i]->section=NULL;
           MRUProfile[i]->dos_name=NULL;
           MRUProfile[i]->unix_name=NULL;
@@ -641,7 +771,8 @@
 
     if (file)
     {
-        CurProfile->section = PROFILE_Load( file );
+        CurProfile->unicode = PROFILE_IsUnicode( file );
+        CurProfile->section = PROFILE_Load( file, CurProfile->unicode );
         fclose( file );
         if(!stat(CurProfile->unix_name,&buf))
            CurProfile->mtime=buf.st_mtime;
