Added support for registry values larger than the server buffer.
When loading a registry file, automatically determine overlap between
key name and file contents based on the first key name.
Removed v1 saving code.
Save USER\.Default separately into ~/.wine/userdef.reg.

diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index c287fd9..30a5f21 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -51,59 +51,6 @@
     return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
 }
 
-/* copy key value data into a user-specified buffer
- *
- * 'len' is the total length of the data
- * 'count' is the size of the user-specified buffer
- * and is updated to reflect the length copied
- *
- * if the type is REG_SZ and data is not 0-terminated and there is enough space in the
- * buffer nt appends a \0
- */
-static DWORD copy_data( void *data, const void *src, DWORD len, DWORD *count, DWORD type )
-{
-    DWORD ret = ERROR_SUCCESS;
-    if (data)
-    {
-        if (*count < len) ret = ERROR_MORE_DATA;
-        else memcpy( data, src, len );
-    }
-    if (count) 
-    {
-        if (len && data && is_string( type ) && (len < *count) && ((WCHAR *)data)[len-1])
-            ((WCHAR *)data)[len] = 0;
-        *count = len;
-    }
-    return ret;
-}
-
-/* same as copy_data but with optional Unicode->Ascii conversion depending on the type */
-static DWORD copy_data_WtoA( void *data, const void *src, DWORD len, DWORD *count, DWORD type )
-{
-    DWORD ret = ERROR_SUCCESS;
-    if (is_string( type ))
-    {
-        /* need to convert from Unicode */
-        len /= sizeof(WCHAR);
-        if (data)
-        {
-            if (*count < len) ret = ERROR_MORE_DATA;
-            else if (len)
-            {
-                memcpyWtoA( data, src, len );
-                if ((len < *count) && ((char*)data)[len-1]) ((char *)data)[len] = 0;
-            }
-        }
-    }
-    else if (data)
-    {
-        if (*count < len) ret = ERROR_MORE_DATA;
-        else memcpy( data, src, len );
-    }
-    if (count) *count = len;
-    return ret;
-}
-
 /* copy a key name into the request buffer */
 static inline DWORD copy_nameW( LPWSTR dest, LPCWSTR name )
 {
@@ -623,6 +570,7 @@
 {
     DWORD ret;
     struct set_key_value_request *req = get_req_buffer();
+    unsigned int max, pos;
 
     TRACE( "(0x%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_w(name), reserved, type, data, count );
 
@@ -635,13 +583,25 @@
         if (str[count / sizeof(WCHAR) - 1] && !str[count / sizeof(WCHAR)])
             count += sizeof(WCHAR);
     }
-    if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY;  /* FIXME */
+
     req->hkey = hkey;
     req->type = type;
-    req->len = count;
+    req->total = count;
     if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
-    memcpy( req->data, data, count );
-    return reg_server_call( REQ_SET_KEY_VALUE );
+
+    max = server_remaining( req->data );
+    pos = 0;
+    while (pos < count)
+    {
+        unsigned int len = count - pos;
+        if (len > max) len = max;
+        req->offset = pos;
+        req->len    = len;
+        memcpy( req->data, data + pos, len );
+        if ((ret = reg_server_call( REQ_SET_KEY_VALUE )) != ERROR_SUCCESS) break;
+        pos += len;
+    }
+    return ret;
 }
 
 
@@ -653,6 +613,7 @@
 {
     DWORD ret;
     struct set_key_value_request *req = get_req_buffer();
+    unsigned int max, pos;
 
     TRACE( "(0x%x,%s,%ld,%ld,%p,%ld)\n", hkey, debugstr_a(name), reserved, type, data, count );
 
@@ -663,23 +624,31 @@
         /* if user forgot to count terminating null, add it (yes NT does this) */
         if (data[count-1] && !data[count]) count++;
     }
-    if (is_string( type ))
-    {
-        /* need to convert to Unicode */
+    if (is_string( type )) /* need to convert to Unicode */
         count *= sizeof(WCHAR);
-        if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY;  /* FIXME */
-        memcpyAtoW( (LPWSTR)req->data, data, count / sizeof(WCHAR) );
-    }
-    else
-    {
-        if (count >= server_remaining( req->data )) return ERROR_OUTOFMEMORY;  /* FIXME */
-        memcpy( req->data, data, count );
-    }
+
     req->hkey = hkey;
     req->type = type;
-    req->len = count;
+    req->total = count;
     if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
-    return reg_server_call( REQ_SET_KEY_VALUE );
+
+    max = server_remaining( req->data );
+    pos = 0;
+    while (pos < count)
+    {
+        unsigned int len = count - pos;
+        if (len > max) len = max;
+        req->offset = pos;
+        req->len    = len;
+
+        if (is_string( type ))
+            memcpyAtoW( (LPWSTR)req->data, data + pos/sizeof(WCHAR), len/sizeof(WCHAR) );
+        else
+            memcpy( req->data, data + pos, len );
+        if ((ret = reg_server_call( REQ_SET_KEY_VALUE )) != ERROR_SUCCESS) break;
+        pos += len;
+    }
+    return ret;
 }
 
 
@@ -762,12 +731,35 @@
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
 
     req->hkey = hkey;
+    req->offset = 0;
     if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
-    if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) == ERROR_SUCCESS)
+    if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) != ERROR_SUCCESS) return ret;
+
+    if (data)
     {
-        if (type) *type = req->type;
-        ret = copy_data( data, req->data, req->len, count, req->type );
+        if (*count < req->len) ret = ERROR_MORE_DATA;
+        else
+        {
+            /* copy the data */
+            unsigned int max = server_remaining( req->data );
+            unsigned int pos = 0;
+            while (pos < req->len)
+            {
+                unsigned int len = min( req->len - pos, max );
+                memcpy( data + pos, req->data, len );
+                if ((pos += len) >= req->len) break;
+                req->offset = pos;
+                if ((ret = copy_nameW( req->name, name )) != ERROR_SUCCESS) return ret;
+                if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) != ERROR_SUCCESS) return ret;
+            }
+        }
+        /* if the type is REG_SZ and data is not 0-terminated
+         * and there is enough space in the buffer NT appends a \0 */
+        if (req->len && is_string(req->type) &&
+            (req->len < *count) && ((WCHAR *)data)[req->len-1]) ((WCHAR *)data)[req->len] = 0;
     }
+    if (type) *type = req->type;
+    if (count) *count = req->len;
     return ret;
 }
 
@@ -781,7 +773,7 @@
 DWORD WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
 			       LPBYTE data, LPDWORD count )
 {
-    DWORD ret;
+    DWORD ret, total_len;
     struct get_key_value_request *req = get_req_buffer();
 
     TRACE("(0x%x,%s,%p,%p,%p,%p=%ld)\n",
@@ -790,12 +782,41 @@
     if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
 
     req->hkey = hkey;
+    req->offset = 0;
     if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
-    if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) == ERROR_SUCCESS)
+    if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) != ERROR_SUCCESS) return ret;
+
+    total_len = is_string( req->type ) ? req->len/sizeof(WCHAR) : req->len;
+
+    if (data)
     {
-        if (type) *type = req->type;
-        ret = copy_data_WtoA( data, req->data, req->len, count, req->type );
+        if (*count < total_len) ret = ERROR_MORE_DATA;
+        else
+        {
+            /* copy the data */
+            unsigned int max = server_remaining( req->data );
+            unsigned int pos = 0;
+            while (pos < req->len)
+            {
+                unsigned int len = min( req->len - pos, max );
+                if (is_string( req->type ))
+                    memcpyWtoA( data + pos/sizeof(WCHAR), (WCHAR *)req->data, len/sizeof(WCHAR) );
+                else
+                    memcpy( data + pos, req->data, len );
+                if ((pos += len) >= req->len) break;
+                req->offset = pos;
+                if ((ret = copy_nameAtoW( req->name, name )) != ERROR_SUCCESS) return ret;
+                if ((ret = reg_server_call( REQ_GET_KEY_VALUE )) != ERROR_SUCCESS) return ret;
+            }
+        }
+        /* if the type is REG_SZ and data is not 0-terminated
+         * and there is enough space in the buffer NT appends a \0 */
+        if (total_len && is_string(req->type) && (total_len < *count) && data[total_len-1])
+            data[total_len] = 0;
     }
+
+    if (count) *count = total_len;
+    if (type) *type = req->type;
     return ret;
 }
 
@@ -882,6 +903,7 @@
 
     req->hkey = hkey;
     req->index = index;
+    req->offset = 0;
     if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
 
     len = lstrlenW( req->name ) + 1;
@@ -889,8 +911,31 @@
     memcpy( value, req->name, len * sizeof(WCHAR) );
     *val_count = len - 1;
 
+    if (data)
+    {
+        if (*count < req->len) ret = ERROR_MORE_DATA;
+        else
+        {
+            /* copy the data */
+            unsigned int max = server_remaining( req->data );
+            unsigned int pos = 0;
+            while (pos < req->len)
+            {
+                unsigned int len = min( req->len - pos, max );
+                memcpy( data + pos, req->data, len );
+                if ((pos += len) >= req->len) break;
+                req->offset = pos;
+                if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
+            }
+        }
+        /* if the type is REG_SZ and data is not 0-terminated
+         * and there is enough space in the buffer NT appends a \0 */
+        if (req->len && is_string(req->type) &&
+            (req->len < *count) && ((WCHAR *)data)[req->len-1]) ((WCHAR *)data)[req->len] = 0;
+    }
     if (type) *type = req->type;
-    return copy_data( data, req->data, req->len, count, req->type );
+    if (count) *count = req->len;
+    return ret;
 }
 
 
@@ -900,7 +945,7 @@
 DWORD WINAPI RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
                             LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
 {
-    DWORD ret, len;
+    DWORD ret, len, total_len;
     struct enum_key_value_request *req = get_req_buffer();
 
     TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
@@ -911,6 +956,7 @@
 
     req->hkey = hkey;
     req->index = index;
+    req->offset = 0;
     if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
 
     len = lstrlenW( req->name ) + 1;
@@ -918,8 +964,37 @@
     memcpyWtoA( value, req->name, len );
     *val_count = len - 1;
 
+    total_len = is_string( req->type ) ? req->len/sizeof(WCHAR) : req->len;
+
+    if (data)
+    {
+        if (*count < total_len) ret = ERROR_MORE_DATA;
+        else
+        {
+            /* copy the data */
+            unsigned int max = server_remaining( req->data );
+            unsigned int pos = 0;
+            while (pos < req->len)
+            {
+                unsigned int len = min( req->len - pos, max );
+                if (is_string( req->type ))
+                    memcpyWtoA( data + pos/sizeof(WCHAR), (WCHAR *)req->data, len/sizeof(WCHAR) );
+                else
+                    memcpy( data + pos, req->data, len );
+                if ((pos += len) >= req->len) break;
+                req->offset = pos;
+                if ((ret = reg_server_call( REQ_ENUM_KEY_VALUE )) != ERROR_SUCCESS) return ret;
+            }
+        }
+        /* if the type is REG_SZ and data is not 0-terminated
+         * and there is enough space in the buffer NT appends a \0 */
+        if (total_len && is_string(req->type) && (total_len < *count) && data[total_len-1])
+            data[total_len] = 0;
+    }
+
+    if (count) *count = total_len;
     if (type) *type = req->type;
-    return copy_data_WtoA( data, req->data, req->len, count, req->type );
+    return ret;
 }