[TWAIN] Reconcile sane's long names to TWAIN's 32 byte limit

Jeremy White jwhite at codeweavers.com
Mon Feb 13 09:35:11 CST 2006


libsane can return arbitrarily long names, but TWAIN supports only a maximum of 32.
Further, the name is a unique identifier, and so must be returned to libsane for processing.

This algorithm tries to convert a long libsane name into a more reasonable short name,
but adds a crude signature process in an attempt to ensure a unique short identifier.

-------------- next part --------------

 dlls/twain/dsm_ctrl.c |   85 ++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 73 insertions(+), 12 deletions(-)

eabadf1c3584adda1a36b199f82bc6bbb17b71da
diff --git a/dlls/twain/dsm_ctrl.c b/dlls/twain/dsm_ctrl.c
index f744939..6d1318d 100644
--- a/dlls/twain/dsm_ctrl.c
+++ b/dlls/twain/dsm_ctrl.c
@@ -22,6 +22,7 @@
 
 #include <stdlib.h>
 #include <stdarg.h>
+#include <stdio.h>
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
@@ -33,6 +34,14 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(twain);
 
+inline static LPSTR TWAIN_strdup( LPCSTR str )
+{
+    LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
+    if (ret) strcpy( ret, str );
+    return ret;
+}
+
+
 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
 TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
@@ -83,6 +92,38 @@ TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pO
 #endif
 }
 
+/* Sane returns device names that are longer than the 32 bytes allowed
+   by TWAIN.  However, it colon separates them, and the last bit is
+   the most interesting.  So we use the last bit, and add a signature
+   to ensure uniqueness */
+static char * get_sane_short_name(const char *in)
+{
+    char *p;
+    LPSTR ret;
+    int  signature = 0;
+
+    if (strlen(in) <= 32)
+        return TWAIN_strdup((char *) in);
+
+    for (p = (char *) in; *p; p++)
+        signature += *p;
+
+    p = strrchr(in, ':');
+    if (!p)
+        p = (char *) in;
+    else
+        p++;
+
+    while (strlen(p) > 25)
+        p++;
+
+    ret = HeapAlloc( GetProcessHeap(), 0, strlen(p) + 1 + 7 );
+    if (! ret)
+        return NULL;
+    sprintf(ret, "%s (%04X)", p, signature % 0x10000);
+    return(ret);
+}
+
 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
 {
@@ -108,15 +149,20 @@ TW_UINT16 TWAIN_IdentityGetDefault (pTW_
      * Users should be able to choose the default device               */
     if (device_list && device_list[0])
     {
+        char *shortname = get_sane_short_name(device_list[0]->name);
+        TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, shortname, device_list[0]->vendor, device_list[0]->model);
         pSourceIdentity->Id = DSM_sourceId ++;
-        strcpy (pSourceIdentity->ProductName, device_list[0]->name);
-        strcpy (pSourceIdentity->Manufacturer, device_list[0]->vendor);
-        strcpy (pSourceIdentity->ProductFamily, device_list[0]->model);
+        lstrcpynA (pSourceIdentity->ProductName, shortname, sizeof(pSourceIdentity->ProductName) - 2);
+        lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 2);
+        lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 2);
         pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
         pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
 
         twRC = TWRC_SUCCESS;
         DSM_twCC = TWCC_SUCCESS;
+
+        if (shortname)
+            HeapFree (GetProcessHeap(), 0, shortname);
     }
     else
     {
@@ -146,17 +192,21 @@ TW_UINT16 TWAIN_IdentityGetFirst (pTW_ID
     {
         if (device_list[0])
         {
-            TRACE("got: %s, %s, %s\n", device_list[0]->name, device_list[0]->vendor, device_list[0]->model);
+            char *shortname = get_sane_short_name(device_list[0]->name);
+            TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, shortname, device_list[0]->vendor, device_list[0]->model);
             pSourceIdentity->Id = DSM_sourceId ++;
-            strcpy (pSourceIdentity->ProductName, device_list[0]->name);
-            strcpy (pSourceIdentity->Manufacturer, device_list[0]->vendor);
-            strcpy (pSourceIdentity->ProductFamily, device_list[0]->model);
+            lstrcpynA (pSourceIdentity->ProductName, shortname, sizeof(pSourceIdentity->ProductName) - 2);
+            lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 2);
+            lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 2);
             pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
             pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
 
             DSM_currentDevice = 1;
             twRC = TWRC_SUCCESS;
             DSM_twCC = TWCC_SUCCESS;
+
+            if (shortname)
+                HeapFree (GetProcessHeap(), 0, shortname);
         }
         else
         {
@@ -198,16 +248,20 @@ TW_UINT16 TWAIN_IdentityGetNext (pTW_IDE
         device_list[DSM_currentDevice]->vendor &&
         device_list[DSM_currentDevice]->model)
     {
+        char *shortname = get_sane_short_name(device_list[DSM_currentDevice]->name);
         pSourceIdentity->Id = DSM_sourceId ++;
-        strcpy (pSourceIdentity->ProductName, device_list[DSM_currentDevice]->name);
-        strcpy (pSourceIdentity->Manufacturer, device_list[DSM_currentDevice]->vendor);
-        strcpy (pSourceIdentity->ProductFamily, device_list[DSM_currentDevice]->model);
+        TRACE("got: %s (short [%s]), %s, %s\n", device_list[DSM_currentDevice]->name, shortname, device_list[DSM_currentDevice]->vendor, device_list[DSM_currentDevice]->model);
+        lstrcpynA (pSourceIdentity->ProductName, shortname, sizeof(pSourceIdentity->ProductName) - 2);
+        lstrcpynA (pSourceIdentity->Manufacturer, device_list[DSM_currentDevice]->vendor, sizeof(pSourceIdentity->Manufacturer) - 2);
+        lstrcpynA (pSourceIdentity->ProductFamily, device_list[DSM_currentDevice]->model, sizeof(pSourceIdentity->ProductFamily) - 2);
         pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
         pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
         DSM_currentDevice ++;
 
         twRC = TWRC_SUCCESS;
         DSM_twCC = TWCC_SUCCESS;
+        if (shortname)
+            HeapFree (GetProcessHeap(), 0, shortname);
     }
     else
     {
@@ -230,6 +284,7 @@ TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOr
     pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
     activeDS *newSource;
     SANE_Status status;
+    char *shortname = NULL;
 
     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
 
@@ -251,9 +306,13 @@ TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOr
         /* Make sure the source to be opened exists in the device list */
         for (i = 0; device_list[i]; i ++)
         {
-            if (strcmp (device_list[i]->name, pIdentity->ProductName) == 0)
+            shortname = get_sane_short_name(device_list[i]->name);
+            if (strcmp (shortname, pIdentity->ProductName) == 0)
                 break;
+            if (shortname)
+                HeapFree (GetProcessHeap(), 0, shortname);
         }
+
     }
 
     if (device_list[i])
@@ -266,7 +325,9 @@ TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOr
             if (status == SANE_STATUS_GOOD)
             {
                 /* Assign name and id for the opened data source */
-                strcpy (pIdentity->ProductName, device_list[i]->name);
+                lstrcpynA (pIdentity->ProductName, shortname, sizeof(pIdentity->ProductName) - 2);
+                if (shortname)
+                    HeapFree (GetProcessHeap(), 0, shortname);
                 pIdentity->Id = DSM_sourceId ++;
                 /* add the data source to an internal active source list */
                 newSource->next = activeSources;
-- 
1.1.5


More information about the wine-patches mailing list