1 
2 
3 #ifdef _MSC_VER
4 #pragma warning(disable : 4996)
5 #endif
6 
7 #define TTWAINLIB_MAIN
8 #include <assert.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include "ttwain_state.h"
14 #include "ttwain_statePD.h"
15 #include "ttwain_error.h"
16 #include "ttwain_win.h"
17 #include "ttwain_winPD.h"
18 #include "ttwain_util.h"
19 #include "ttwain_utilP.h"
20 #include "ttwain_conversion.h"
21 #include "ttwainP.h"
22 
23 #include "ttwain_global_def.h"
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 #ifdef MACOSX
29 extern int exitTwainSession(void);
30 #endif
31 static void TTWAIN_FreeVar(void);
32 
33 #define RELEASE_STR "5.1"
34 #define TITLEBAR_STR "Toonz5.1"
35 #define TwProgramName "Toonz5.1"
36 
37 #define COMPANY "Digital Video"
38 #define PRODUCT "TOONZ"
39 
40 #ifndef min
41 #define min(a, b) (((a) < (b)) ? (a) : (b))
42 #endif
43 #ifndef max
44 #define max(a, b) (((a) > (b)) ? (a) : (b))
45 #endif
46 
47 #define CEIL(x) ((int)(x) < (x) ? (int)(x) + 1 : (int)(x))
48 
49 #ifndef _WIN32
50 #define PRINTF(args...)
51 #else
52 #define PRINTF
53 #endif
54 /*---------------------------------------------------------------------------*/
55 /* LOCAL PROTOTYPES
56  */
57 /*---------------------------------------------------------------------------*/
58 static int TTWAIN_DoOneTransfer(void);
59 static int TTWAIN_WaitForXfer(void *hwnd);
60 static void *TTWAIN_WaitForNativeXfer(void *hwnd);
61 static int TTWAIN_WaitForMemoryXfer(void *hwnd);
62 static int TTWAIN_NativeXferHandler(void);
63 static int TTWAIN_MemoryXferHandler(void);
64 static int TTWAIN_AbortAllPendingXfers(void);
65 static void TTWAIN_ModalEventLoop(void);
66 static void TTWAIN_BreakModalLoop(void);
67 static void TTWAIN_EmptyMessageQueue(void);
68 /*---------------------------------------------------------------------------*/
69 void TTWAIN_SetState(TWAINSTATE status);
70 /*---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------*/
72 /* int TTWAIN_LoadSourceManager(void)      <- this is in ttwain_state.h */
73 
74 /* int TTWAIN_SelectImageSource(void* hwnd) <-\
75    int TTWAIN_SelectImageSource(void* hwnd) <-|--\
76    int TTWAIN_OpenDefaultSource(void)       <-|-- these are in ttwain.h
77    int TTWAIN_CloseAll        (void *hwnd)  <-/
78 */
79 
80 /* these are local */
81 static int TTWAIN_EnableSource(void *hwnd);
82 int TTWAIN_MessageHook(void *lpmsg);
83 static int TTWAIN_EndXfer(void);
84 static int TTWAIN_DisableSource(void);
85 static int TTWAIN_CloseSource(void);
86 static int TTWAIN_CloseSourceManager(void *hwnd);
87 
88 /* int TTWAIN_UnloadSourceManager(void)       <- this is in ttwain_state.h */
89 
90 static int TTWAIN_MGR(TUINT32 dg, TUINT32 dat, TUINT32 msg, void *pd);
91 
92 #define INVERT_BYTE(START, HOWMANY)                                            \
93   {                                                                            \
94     UCHAR *p = (START);                                                        \
95     unsigned int ijk;                                                          \
96     for (ijk = 0; ijk < (HOWMANY); ijk++, p++) {                               \
97       *p = ~*p;                                                                \
98     }                                                                          \
99   }
100 
101 #define BB(H, L) (H << 8 | L)
102 /*---------------------------------------------------------------------------*/
103 /*	  TWAIN STATE		 					     */
104 /*---------------------------------------------------------------------------*/
105 /*STATE 1 TO 2*/
TTWAIN_LoadSourceManager(void)106 int TTWAIN_LoadSourceManager(void) {
107   TTWAIN_InitVar();
108   return TTWAIN_LoadSourceManagerPD();
109 }
110 /*---------------------------------------------------------------------------*/
111 /*STATE 2 TO 3*/
TTWAIN_OpenSourceManager(void * hwnd)112 int TTWAIN_OpenSourceManager(void *hwnd) {
113   TTwainData.hwnd32SM = (TW_INT32)TTWAIN_GetValidHwnd(hwnd);
114 
115   if (TTWAIN_GetState() < TWAIN_SM_OPEN) {
116     if (TTWAIN_LoadSourceManager() &&
117         TTWAIN_MGR(DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &TTwainData.hwnd32SM)) {
118       assert(TTWAIN_GetState() == TWAIN_SM_OPEN);
119     }
120   }
121   return (TTWAIN_GetState() >= TWAIN_SM_OPEN);
122 }
123 /*---------------------------------------------------------------------------*/
124 /*STATE 3*/
125 static TW_IDENTITY newSourceId;
TTWAIN_SelectImageSource(void * hwnd)126 int TTWAIN_SelectImageSource(void *hwnd) {
127   int success           = FALSE;
128   TWAINSTATE entryState = TTWAIN_GetState();
129 
130   if (TTWAIN_GetState() >= TWAIN_SM_OPEN || TTWAIN_OpenSourceManager(hwnd)) {
131     // TW_IDENTITY	newSourceId;
132     memset(&newSourceId, 0, sizeof newSourceId);
133 
134     TTWAIN_MGR(DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &newSourceId);
135     /* Post the Select Source dialog */
136     success =
137         TTWAIN_MGR(DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &newSourceId);
138   } else {
139     char msg[2048];
140     snprintf(msg, sizeof(msg), "Unable to open Source Manager (%s)",
141              DSM_FILENAME);
142     TTWAIN_ErrorBox(msg);
143     return FALSE;
144   }
145 
146   if (entryState < TWAIN_SM_OPEN) {
147     TTWAIN_CloseSourceManager(hwnd);
148     if (entryState < TWAIN_SM_LOADED) {
149       TTWAIN_UnloadSourceManager();
150     }
151   }
152   return success;
153 }
154 /*---------------------------------------------------------------------------*/
155 /*STATE 3 TO 4*/
TTWAIN_OpenDefaultSource(void)156 int TTWAIN_OpenDefaultSource(void) {
157   TW_IDENTITY tempId;
158   int rc;
159   static int first_time = TRUE;
160 
161   if (TTWAIN_GetState() < TWAIN_SOURCE_OPEN) {
162     if (TTWAIN_GetState() < TWAIN_SM_OPEN && !TTWAIN_OpenSourceManager(NULL))
163       return FALSE;
164 
165     rc = TTWAIN_MGR(DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &tempId);
166     while (rc && tempId.Id != 0) {
167       if (strcmp((char *)newSourceId.ProductName, (char *)tempId.ProductName) ==
168           0) {
169         newSourceId = tempId;
170         break;
171       }
172       rc = TTWAIN_MGR(DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &tempId);
173     }
174 
175     if (TTWAIN_MGR(DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &newSourceId)) {
176       assert(TTWAIN_GetState() == TWAIN_SOURCE_OPEN);
177     }
178   }
179 
180   if (first_time && (TTWAIN_GetState() == TWAIN_SOURCE_OPEN)) {
181     TTWAIN_GetSupportedCaps();
182     /*first_time = FALSE;*/
183   }
184   return (TTWAIN_GetState() == TWAIN_SOURCE_OPEN);
185 }
186 /*---------------------------------------------------------------------------*/
187 /*STATE 4 TO 5*/
TTWAIN_EnableSource(void * hwnd)188 static int TTWAIN_EnableSource(void *hwnd) {
189   if (TTWAIN_GetState() < TWAIN_SOURCE_OPEN && !TTWAIN_OpenDefaultSource())
190     return FALSE;
191 
192   TTwainData.twainUI.ShowUI  = TTWAIN_GetUIStatus();
193   TTwainData.twainUI.ModalUI = TTWAIN_GetModalStatus();
194   TTwainData.twainUI.hParent = (TW_HANDLE)TTWAIN_GetValidHwnd(hwnd);
195   TTWAIN_DS(DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &TTwainData.twainUI);
196   return (TTWAIN_GetState() == TWAIN_SOURCE_ENABLED);
197 }
198 /*---------------------------------------------------------------------------*/
199 /*STATE 5 TO 6 TO 7*/
TTWAIN_MessageHook(void * lpmsg)200 int TTWAIN_MessageHook(void *lpmsg)
201 /* returns TRUE if msg processed by TWAIN (source) */
202 {
203   int bProcessed = FALSE;
204   // printf("%s\n", __PRETTY_FUNCTION__);
205   if (TTWAIN_GetState() >= TWAIN_SOURCE_ENABLED) {
206 /* source enabled */
207 #ifdef _WIN32
208     TW_EVENT twEvent;
209     twEvent.pEvent    = (TW_MEMREF)lpmsg;
210     twEvent.TWMessage = MSG_NULL;
211     /* see if source wants to process (eat) the message */
212     bProcessed = (TTWAIN_DS(DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT,
213                             &twEvent) == TWRC_DSEVENT);
214 #else
215     TW_EVENT twEvent;
216     twEvent.pEvent    = (TW_MEMREF)0;
217     twEvent.TWMessage = (TW_UINT32)lpmsg;
218 #endif
219     switch (twEvent.TWMessage) {
220     case MSG_XFERREADY:
221 #ifdef MACOSX
222       TTWAIN_SetState(TWAIN_TRANSFER_READY);
223 #endif
224       assert(TTWAIN_GetState() == TWAIN_TRANSFER_READY);
225       TTWAIN_DoOneTransfer();
226       break;
227     case MSG_CLOSEDSREQ:
228       TTWAIN_DisableSource();
229       break;
230     case MSG_NULL:
231       /* no message returned from DS */
232       break;
233     } /* switch */
234   }
235   return bProcessed;
236 }
237 /*---------------------------------------------------------------------------*/
238 /*STATE 7 TO 6 TO 5*/
TTWAIN_EndXfer(void)239 static int TTWAIN_EndXfer(void) {
240   if (TTWAIN_GetState() == TWAIN_TRANSFERRING)
241     TTWAIN_DS(DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER,
242               &TTwainData.transferInfo.pendingXfers);
243   return (TTWAIN_GetState() < TWAIN_TRANSFERRING);
244 }
245 /*---------------------------------------------------------------------------*/
246 /* STATE 5 TO 1 */
247 /* 3 OP + 1 PD OP*/
248 
249 /*STATE 5 TO 4*/
TTWAIN_DisableSource(void)250 static int TTWAIN_DisableSource(void) {
251   TTWAIN_AbortAllPendingXfers();
252 
253   if ((TTWAIN_GetState() >= TWAIN_SOURCE_ENABLED) &&
254       (TTWAIN_DS(DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS,
255                  &TTwainData.twainUI) == TWRC_SUCCESS)) {
256     assert(TTWAIN_GetState() == TWAIN_SOURCE_OPEN);
257     return FALSE;
258   }
259   TTWAIN_EmptyMessageQueue();
260   return (TTWAIN_GetState() < TWAIN_SOURCE_ENABLED);
261 }
262 /*---------------------------------------------------------------------------*/
263 /*STATE 4 TO 3*/
TTWAIN_CloseSource(void)264 static int TTWAIN_CloseSource(void) {
265   TTwainData.resultCode = TWRC_SUCCESS;
266 
267   TTWAIN_DisableSource();
268   if (TTWAIN_GetState() == TWAIN_SOURCE_OPEN &&
269       TTWAIN_MGR(DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &TTwainData.sourceId)) {
270     assert(TTWAIN_GetState() == TWAIN_SM_OPEN);
271   }
272   return (TTWAIN_GetState() <= TWAIN_SM_OPEN);
273 }
274 /*---------------------------------------------------------------------------*/
275 /*STATE 3 TO 2*/
TTWAIN_CloseSourceManager(void * hwnd)276 static int TTWAIN_CloseSourceManager(void *hwnd) {
277   TTWAIN_EmptyMessageQueue();
278   TTwainData.hwnd32SM = (TW_INT32)TTWAIN_GetValidHwnd(hwnd);
279 
280   TTwainData.resultCode = TWRC_SUCCESS;
281 
282   if (TTWAIN_CloseSource() &&
283       TTWAIN_MGR(DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &TTwainData.hwnd32SM)) {
284     assert(TTWAIN_GetState() == TWAIN_SM_LOADED);
285   }
286   return (TTWAIN_GetState() <= TWAIN_SM_LOADED);
287 }
288 /*---------------------------------------------------------------------------*/
289 /*STATE 2 TO 1*/
TTWAIN_UnloadSourceManager(void)290 int TTWAIN_UnloadSourceManager(void) {
291   TTWAIN_CloseSourceManager(NULL);
292   return TTWAIN_UnloadSourceManagerPD();
293 }
294 /*---------------------------------------------------------------------------*/
TTWAIN_CloseAll(void * hwnd)295 int TTWAIN_CloseAll(void *hwnd) {
296   TTWAIN_EndXfer();
297   TTWAIN_DisableSource();
298   TTWAIN_CloseSource();
299   TTWAIN_CloseSourceManager(hwnd);
300   TTWAIN_UnloadSourceManager();
301   TTWAIN_FreeVar();
302   return 1;
303 }
304 /*---------------------------------------------------------------------------*/
305 /*---------------------------------------------------------------------------*/
306 /*---------------------------------------------------------------------------*/
307 /*    MISC. AUX FUNCTIONS						     */
308 /*---------------------------------------------------------------------------*/
TTWAIN_GetState(void)309 TWAINSTATE TTWAIN_GetState(void) { return TTwainData.twainState; }
310 /*---------------------------------------------------------------------------*/
TTWAIN_SetState(TWAINSTATE status)311 void TTWAIN_SetState(TWAINSTATE status) { TTwainData.twainState = status; }
312 /*---------------------------------------------------------------------------*/
TTWAIN_AbortAllPendingXfers(void)313 static int TTWAIN_AbortAllPendingXfers(void) {
314   TTWAIN_EndXfer();
315   if (TTWAIN_GetState() == TWAIN_TRANSFER_READY) {
316     TTWAIN_DS(DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET,
317               &TTwainData.transferInfo.pendingXfers);
318   }
319   TTWAIN_EmptyMessageQueue();
320   return (TTWAIN_GetState() < TWAIN_TRANSFER_READY);
321 }
322 /*---------------------------------------------------------------------------*/
323 /*---------------------------------------------------------------------------*/
324 /*		DATA SOURCE						     */
325 /*---------------------------------------------------------------------------*/
TTWAIN_DS(TUINT32 dg,TUINT32 dat,TUINT32 msg,void * pd)326 TW_INT16 TTWAIN_DS(TUINT32 dg, TUINT32 dat, TUINT32 msg,
327                    void *pd) { /* Call the current source with a triplet */
328   int bOk                   = FALSE;
329   static TUINT32 nMemBuffer = 0;
330 
331   PRINTF("%s dg=0x%x dat=0x%x msg=0x%x pd=0x%x\n", __FUNCTION__, dg, dat, msg,
332          pd);
333 
334   assert(TTWAIN_GetState() >= TWAIN_SOURCE_OPEN);
335   TTwainData.resultCode = TWRC_FAILURE;
336   if (dg == DG_IMAGE) {
337     if (dat == DAT_IMAGEMEMXFER) {
338       if (msg == MSG_GET && pd != NULL) {
339         pTW_IMAGEMEMXFER pmxb = (pTW_IMAGEMEMXFER)pd;
340         pmxb->Compression     = TWON_DONTCARE16;
341         pmxb->BytesPerRow     = TWON_DONTCARE32;
342         pmxb->Columns         = TWON_DONTCARE32;
343         pmxb->Rows            = TWON_DONTCARE32;
344         pmxb->XOffset         = TWON_DONTCARE32;
345         pmxb->YOffset         = TWON_DONTCARE32;
346         pmxb->BytesWritten    = TWON_DONTCARE32;
347       }
348     }
349   }
350   if (TTwainData.DSM_Entry) {
351     TTwainData.resultCode = (*TTwainData.DSM_Entry)(
352         &TTwainData.appId, &TTwainData.sourceId, (TW_UINT32)dg, (TW_UINT16)dat,
353         (TW_UINT16)msg, (TW_MEMREF)pd);
354     bOk = (TTwainData.resultCode == TWRC_SUCCESS);
355 
356     if (dg == DG_CONTROL) {
357       switch (dat) {
358       case DAT_EVENT:
359         if (msg == MSG_PROCESSEVENT) {
360           if (((pTW_EVENT)pd)->TWMessage == MSG_XFERREADY) {
361             TTWAIN_SetState(TWAIN_TRANSFER_READY);
362           }
363           bOk = (TTwainData.resultCode == TWRC_DSEVENT);
364         }
365         break;
366 
367       case DAT_CAPABILITY:
368         break;
369 
370       case DAT_PENDINGXFERS:
371         if (msg == MSG_ENDXFER && bOk) {
372           TTWAIN_SetState(((pTW_PENDINGXFERS)pd)->Count ? TWAIN_TRANSFER_READY
373                                                         : TWAIN_SOURCE_ENABLED);
374         }
375         if (msg == MSG_RESET && bOk) {
376           TTWAIN_SetState(TWAIN_SOURCE_ENABLED);
377         }
378         break;
379 
380       case DAT_USERINTERFACE:
381         if (msg == MSG_ENABLEDS) {
382           if (TTwainData.resultCode == TWRC_FAILURE ||
383               TTwainData.resultCode == TWRC_CANCEL) {
384             TTWAIN_RecordError();
385           } else {
386             /* TTwainData.resultCode could be either SUCCESS or CHECKSTATUS */
387             TTWAIN_SetState(TWAIN_SOURCE_ENABLED);
388             bOk = TRUE;
389           }
390         }
391         if (msg == MSG_DISABLEDS && bOk) {
392           TTWAIN_SetState(TWAIN_SOURCE_OPEN);
393 #ifdef MACOSX
394           exitTwainSession();  // exited from TwainUI using close button
395 #endif
396         }
397         break;
398 
399       case DAT_SETUPMEMXFER:
400         if (msg == MSG_GET && bOk) {
401           nMemBuffer = 0;
402         }
403         break;
404       } /* switch */
405     } else if (dg == DG_IMAGE) {
406       if (dat == DAT_IMAGENATIVEXFER || dat == DAT_IMAGEFILEXFER) {
407         /* Native and File transfers work much the same way. */
408         if (msg == MSG_GET) {
409           bOk = (TTwainData.resultCode == TWRC_XFERDONE);
410           switch (TTwainData.resultCode) {
411           case TWRC_XFERDONE:
412           case TWRC_CANCEL:
413             TTWAIN_SetState(TWAIN_TRANSFERRING);
414             /* Need to acknowledge end of transfer with */
415             /* DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER */
416             break;
417 
418           case TWRC_FAILURE:
419           default:
420             /* Transfer failed (e.g. insufficient memory, write-locked file) */
421             /* check condition code for more info */
422             TTWAIN_SetState(TWAIN_TRANSFER_READY);
423             /* The image is still pending */
424             break;
425           } /* switch */
426         }
427       } else if (dat == DAT_IMAGEMEMXFER) {
428         if (msg == MSG_GET) {
429           bOk = FALSE;
430           switch (TTwainData.resultCode) {
431           case TWRC_SUCCESS:
432           case TWRC_XFERDONE:
433             bOk = TRUE;
434             nMemBuffer++;
435             TTWAIN_SetState(TWAIN_TRANSFERRING);
436             break;
437 
438           case TWRC_FAILURE:
439             /* "If the failure occurred during the transfer of the first
440 buffer, the session is in State 6. If the failure occurred
441 on a subsequent buffer, the session is in State 7."
442 */
443             TTWAIN_SetState(nMemBuffer == 0 ? TWAIN_TRANSFER_READY
444                                             : TWAIN_TRANSFERRING);
445             break;
446 
447           case TWRC_CANCEL:
448             /* Transfer cancelled, no state change. */
449             TTWAIN_BreakModalLoop();
450             break;
451           } /* switch */
452         }
453       }
454     }
455   }
456 
457   /*
458 if (!bOk)
459 TTWAIN_RecordError();
460 */
461   return TTwainData.resultCode;
462 }
463 /*---------------------------------------------------------------------------*/
464 /*---------------------------------------------------------------------------*/
465 /*	    DATA SOURCE MANAGER						     */
466 /*---------------------------------------------------------------------------*/
TTWAIN_MGR(TUINT32 dg,TUINT32 dat,TUINT32 msg,void * pd)467 static int TTWAIN_MGR(TUINT32 dg, TUINT32 dat, TUINT32 msg, void *pd)
468 /* Call the Source Manager with a triplet */
469 {
470   int bOk               = FALSE;
471   TTwainData.resultCode = TWRC_FAILURE;
472 
473   if (TTwainData.DSM_Entry) {
474     TTwainData.resultCode =
475         (*TTwainData.DSM_Entry)(&TTwainData.appId, NULL, (TW_UINT32)dg,
476                                 (TW_UINT16)dat, (TW_UINT16)msg, (TW_MEMREF)pd);
477     bOk = (TTwainData.resultCode == TWRC_SUCCESS);
478     if (dg == DG_CONTROL) {
479       if (dat == DAT_IDENTITY) {
480         if (msg == MSG_OPENDS) {
481           if (bOk) {
482             /* Source opened - record identity for future triplets */
483             memcpy(&TTwainData.sourceId, pd, sizeof(TW_IDENTITY));
484             TTWAIN_SetState(TWAIN_SOURCE_OPEN);
485           } else { /*RecordError(ED_DSM_FAILURE);*/
486             TTWAIN_RecordError();
487           }
488         }
489         if (msg == MSG_CLOSEDS && bOk) {
490           TTWAIN_SetState(TWAIN_SM_OPEN);
491         }
492       }
493       if (dat == DAT_PARENT) {
494         if (msg == MSG_OPENDSM && bOk) {
495           TTWAIN_SetState(TWAIN_SM_OPEN);
496         }
497         if (msg == MSG_CLOSEDSM && bOk) {
498           TTWAIN_SetState(TWAIN_SM_LOADED);
499         }
500       }
501     }
502   }
503   return bOk;
504 }
505 /*---------------------------------------------------------------------------*/
506 /*---------------------------------------------------------------------------*/
507 /*			ERRORS						     */
508 /*---------------------------------------------------------------------------*/
TTWAIN_GetConditionCode(void)509 TUINT32 TTWAIN_GetConditionCode(void) {
510   TW_STATUS twStatus;
511   TW_INT16 rcLast        = TTwainData.resultCode;
512   TW_INT16 rc            = TWRC_FAILURE;
513   twStatus.ConditionCode = TWCC_BUMMER;
514 
515   if (TTWAIN_GetState() >= 4) {
516     /* get source status if open */
517     rc = TTWAIN_DS(DG_CONTROL, DAT_STATUS, MSG_GET, (TW_MEMREF)&twStatus);
518   } else if (TTWAIN_GetState() == 3) {
519     /* otherwise get source manager status */
520     rc = TTWAIN_MGR(DG_CONTROL, DAT_STATUS, MSG_GET, (TW_MEMREF)&twStatus);
521   }
522   TTwainData.resultCode = rcLast;
523 
524   if (rc != TWRC_SUCCESS) return -1;
525   return twStatus.ConditionCode;
526 }
527 /*---------------------------------------------------------------------------*/
TTWAIN_GetResultCode(void)528 TUINT32 TTWAIN_GetResultCode(void) { return TTwainData.resultCode; }
529 /*---------------------------------------------------------------------------*/
TTWAIN_DSM_HasEntryPoint(void)530 int TTWAIN_DSM_HasEntryPoint(void) { return !!(TTwainData.DSM_Entry); }
531 /*---------------------------------------------------------------------------*/
TTWAIN_DoOneTransfer(void)532 static int TTWAIN_DoOneTransfer(void) {
533   int rc = FALSE;
534   switch (TTwainData.transferInfo.transferMech) {
535   case TTWAIN_TRANSFERMODE_NATIVE:
536     rc = TTWAIN_NativeXferHandler();
537     break;
538   case TTWAIN_TRANSFERMODE_FILE:
539     assert(!"NOT IMPL!");
540     /*TTWAIN_FileXferHandler(); */
541     break;
542   case TTWAIN_TRANSFERMODE_MEMORY:
543     rc = TTWAIN_MemoryXferHandler();
544     break;
545   } /* switch */
546 
547   TTwainData.transferInfo.lastTransferWasOk = rc;
548   /* If inside ModalEventLoop, break out */
549   TTWAIN_BreakModalLoop();
550 
551   /* Acknowledge transfer */
552   TTWAIN_EndXfer();
553   assert(TTWAIN_GetState() == TWAIN_TRANSFER_READY ||
554          TTWAIN_GetState() == TWAIN_SOURCE_ENABLED);
555   return rc;
556 }
557 /*---------------------------------------------------------------------------*/
TTWAIN_RegisterApp(int majorNum,int minorNum,int nLanguage,int nCountry,char * version,char * manufacter,char * family,char * product)558 void TTWAIN_RegisterApp(
559     int majorNum, int minorNum, /* app. revision*/
560     int nLanguage,    /* (human) language (use TWLG_xxx from TWAIN.H) */
561     int nCountry,     /* country (use TWCY_xxx from TWAIN.H)	     */
562     char *version,    /* version info string                          */
563     char *manufacter, /* name of manufacter			     */
564     char *family,     /* product family				     */
565     char *product)    /* specific product			     */
566 {
567   memset(&TTwainData.appId, 0, sizeof(TTwainData.appId));
568   TTwainData.appId.Id =
569       0; /* init to 0, but Source Manager will assign THE real value*/
570   TTwainData.appId.Version.MajorNum = majorNum;
571   TTwainData.appId.Version.MinorNum = minorNum;
572   TTwainData.appId.Version.Language = nLanguage;
573   TTwainData.appId.Version.Country  = nCountry;
574   TTwainData.appId.ProtocolMajor    = TWON_PROTOCOLMAJOR;
575   TTwainData.appId.ProtocolMinor    = TWON_PROTOCOLMINOR;
576   TTwainData.appId.SupportedGroups  = DG_IMAGE | DG_CONTROL;
577   strcpy((char *)TTwainData.appId.Version.Info, version);
578   strcpy((char *)TTwainData.appId.Manufacturer, manufacter);
579   strcpy((char *)TTwainData.appId.ProductFamily, family);
580   strcpy((char *)TTwainData.appId.ProductName, product);
581 }
582 /*---------------------------------------------------------------------------*/
TTWAIN_AcquireNative(void * hwnd)583 void *TTWAIN_AcquireNative(void *hwnd) {
584   void *hnative = NULL;
585 
586   TTwainData.transferInfo.lastTransferWasOk = FALSE;
587 
588   if (TTwainData.transferInfo.transferMech != TTWAIN_TRANSFERMODE_NATIVE)
589     return 0;
590 
591   hwnd = TTWAIN_GetValidHwnd(hwnd);
592   if (TTWAIN_GetState() < TWAIN_SOURCE_OPEN) {
593     if (!TTWAIN_OpenSourceManager(hwnd)) /* Bring up to state 4 */
594     {
595       char msg[2048];
596       snprintf(msg, sizeof(msg), "Unable to open Source Manager (%s)",
597                DSM_FILENAME);
598       TTWAIN_ErrorBox(msg);
599       return 0;
600     }
601     if (!TTWAIN_OpenDefaultSource())
602       /*TTWAIN_ReportLastError("Unable to open default Data Source.");*/
603       TTWAIN_RecordError();
604     else
605       assert(TTWAIN_GetState() == TWAIN_SOURCE_OPEN);
606   }
607 
608   if (TTWAIN_GetState() >= TWAIN_SOURCE_OPEN)
609     hnative = TTWAIN_WaitForNativeXfer(hwnd);
610 
611   if (!TTwainData.transferInfo.multiTransfer) {
612     /* shut everything down in the right sequence */
613     TTWAIN_AbortAllPendingXfers(); /* TRANSFER_READY or TRANSFERRING ->
614                                       SOURCE_ENABLED */
615     TTWAIN_UnloadSourceManager();
616   }
617 
618   TTwainData.transferInfo.lastTransferWasOk = !!(hnative);
619   return hnative;
620 }
621 /*---------------------------------------------------------------------------*/
622 #ifdef _WIN32
623 
624 typedef void(MyFun)(HWND);
625 
626 /*it's an hack function to force bring to top the twain UI module window     */
myHackEnumFunction(HWND hwnd,LPARAM lParam)627 static BOOL CALLBACK myHackEnumFunction(HWND hwnd, LPARAM lParam) {
628   MyFun *f = 0;
629 
630 #define TITLESIZE (1024)
631   char title[TITLESIZE + 1];
632   int len;
633 
634   GetWindowText(hwnd, (char *)&title, TITLESIZE);
635   if (title[0] == 0x00) return 1; /*continue the search....*/
636 
637   len = strlen(TTwainData.sourceId.ProductName);
638   if (!len) return 0;
639 
640   len--;
641 
642   while (
643       len &&
644       (isdigit(TTwainData.sourceId.ProductName[len]) /*skip digit at the end*/
645        || TTwainData.sourceId.ProductName[len] == '.')) /*skip . */
646     len--;
647 
648   if (len && !strncmp(title, TTwainData.sourceId.ProductName, len)) {
649     /*
650 char dbg_str[1024];
651 snprintf(dbg_str, sizeof(dbg_str), "set focus on 0x%8x %s\n",hwnd, title);
652 OutputDebugString(dbg_str);
653 */
654     f = (MyFun *)lParam;
655     f(hwnd);
656 
657     return FALSE; /*it means stop the search...*/
658   }
659   return 1; /*continue the search....*/
660 }
661 
662 /*---------------------------------------------------------------------------*/
663 
myHackEnumFunction2(HWND hwnd,LPARAM lParam)664 static BOOL CALLBACK myHackEnumFunction2(HWND hwnd, LPARAM lParam) {
665   MyFun *f = 0;
666   char *ptr;
667 
668 #define TITLESIZE (1024)
669   char title[TITLESIZE + 1];
670 
671   GetWindowText(hwnd, (char *)&title, TITLESIZE);
672   if (title[0] == 0x00) return 1; /*continue the search....*/
673 
674   ptr = strstr(title, TTwainData.sourceId.Manufacturer);
675   if (!ptr) return 1; /*continue the search....*/
676 
677   f = (MyFun *)lParam;
678   f(hwnd);
679 
680   return FALSE; /*it means stop the search...*/
681 }
682 
683 /*---------------------------------------------------------------------------*/
684 
bringToTop(HWND hwnd)685 static void bringToTop(HWND hwnd) { BringWindowToTop(hwnd); }
686 
putToBottom(HWND hwnd)687 static void putToBottom(HWND hwnd) {
688   const int unused = 0;
689 
690   BOOL rc = SetWindowPos(hwnd,         // handle to window
691                          HWND_BOTTOM,  // placement-order handle
692                          unused,       // horizontal position
693                          unused,       // vertical position
694                          unused,       // width
695                          unused,       // height
696                          SWP_ASYNCWINDOWPOS | SWP_NOMOVE |
697                              SWP_NOSIZE  // window-positioning options
698                          );
699 }
700 
myHackFunction(int v)701 static void myHackFunction(int v) {
702   BOOL rc;
703   if (v == 1)
704     rc = EnumWindows((WNDENUMPROC)myHackEnumFunction, (LPARAM)&bringToTop);
705   else
706     rc = EnumWindows((WNDENUMPROC)myHackEnumFunction, (LPARAM)&putToBottom);
707 
708   if (rc) /* it means that myHackEnumFunction fails to find the proper window to
709              bring up or put down*/
710   {
711     if (v == 1)
712       rc = EnumWindows((WNDENUMPROC)myHackEnumFunction2, (LPARAM)&bringToTop);
713     else
714       rc = EnumWindows((WNDENUMPROC)myHackEnumFunction2, (LPARAM)&putToBottom);
715   }
716 }
717 #else
myHackFunction(int v)718 static void myHackFunction(int v) { /*it's empty...*/
719 }
720 #endif
721 /*---------------------------------------------------------------------------*/
TTWAIN_AcquireMemory(void * hwnd)722 int TTWAIN_AcquireMemory(void *hwnd) {
723   int rc                                    = FALSE;
724   TTwainData.transferInfo.lastTransferWasOk = FALSE;
725 
726   if (TTwainData.transferInfo.transferMech != TTWAIN_TRANSFERMODE_MEMORY)
727     return FALSE;
728 
729   myHackFunction(1);
730 
731   hwnd = TTWAIN_GetValidHwnd(hwnd);
732   if (TTWAIN_GetState() < TWAIN_SOURCE_OPEN) {
733     if (!TTWAIN_OpenSourceManager(hwnd)) /* Bring up to state 4 */
734     {
735       TTWAIN_ErrorBox("Unable to open Source Manager (" DSM_FILENAME ")");
736       return FALSE;
737     }
738     if (!TTWAIN_OpenDefaultSource())
739       /*TTWAIN_ReportLastError("Unable to open default Data Source.");*/
740       TTWAIN_RecordError();
741     else
742       assert(TTWAIN_GetState() == TWAIN_SOURCE_OPEN);
743   }
744 
745   if (TTWAIN_GetState() >= TWAIN_SOURCE_OPEN)
746     rc = TTWAIN_WaitForMemoryXfer(hwnd);
747 
748   if (!TTwainData.transferInfo.multiTransfer) {
749     /* shut everything down in the right sequence */
750     TTWAIN_AbortAllPendingXfers(); /* TRANSFER_READY or TRANSFERRING ->
751                                       SOURCE_ENABLED */
752     TTWAIN_UnloadSourceManager();
753   }
754 
755   myHackFunction(0);
756 
757   return TTwainData.transferInfo.lastTransferWasOk;
758 }
759 /*---------------------------------------------------------------------------*/
TTWAIN_StopAcquire(void)760 void TTWAIN_StopAcquire(void) { TTwainData.transferInfo.oneAtLeast = FALSE; }
761 /*---------------------------------------------------------------------------*/
TTWAIN_WaitForNativeXfer(void * hwnd)762 static void *TTWAIN_WaitForNativeXfer(void *hwnd) {
763   TTwainData.transferInfo.hDib = NULL;
764   if (TTWAIN_GetState() >= TWAIN_SOURCE_OPEN)
765     TTWAIN_WaitForXfer(hwnd);
766   else
767     TTWAIN_ErrorBox("TWAIN_WaitForNativeXfer called in state < 4.");
768   return TTwainData.transferInfo.hDib;
769 }
770 /*---------------------------------------------------------------------------*/
TTWAIN_WaitForMemoryXfer(void * hwnd)771 static int TTWAIN_WaitForMemoryXfer(void *hwnd) {
772   int rc = FALSE;
773   if (TTWAIN_GetState() >= TWAIN_SOURCE_OPEN)
774     rc = TTWAIN_WaitForXfer(hwnd);
775   else
776     TTWAIN_ErrorBox("TWAIN_WaitForNativeXfer called in state < 4.");
777   return rc;
778 }
779 /*---------------------------------------------------------------------------*/
TTWAIN_WaitForXfer(void * hwnd)780 static int TTWAIN_WaitForXfer(void *hwnd) {
781   int bWasEnabled;
782   int rc = FALSE;
783   /* Make up a valid window if we weren't given one */
784   hwnd = TTWAIN_GetValidHwnd(hwnd);
785   /* Disable the parent window during the modal acquire */
786   bWasEnabled = (TTWAIN_EnableWindow(hwnd, FALSE) == 0);
787 
788   TTwainData.transferInfo.oneAtLeast = TRUE;
789   /*
790 TTWAIN_DS( DG_CONTROL,DAT_PENDINGXFERS, MSG_ENDXFER,
791        (TW_MEMREF)&TTwainData.transferInfo.pendingXfers);
792 */
793   do {
794     if (TTWAIN_GetState() == TWAIN_TRANSFER_READY)
795       rc = TTWAIN_DoOneTransfer();
796     else if (TTWAIN_GetState() >= TWAIN_SOURCE_ENABLED ||
797              TTWAIN_EnableSource(hwnd)) {
798       /* source is enabled, wait for transfer or source closed */
799       if (TTwainData.resultCode != TWRC_CANCEL)
800         TTWAIN_ModalEventLoop();
801       else {
802         TTWAIN_BreakModalLoop();
803         break;
804       }
805     } else
806       /*TTWAIN_ReportLastError("Failed to enable Data Source.");*/
807       TTWAIN_RecordError();
808   } while (TTwainData.transferInfo.pendingXfers.Count &&
809            TTwainData.transferInfo.oneAtLeast /*&& rc*/);
810 
811   /* Re-enable the parent window if it was enabled */
812   TTWAIN_EnableWindow(hwnd, bWasEnabled);
813   return rc;
814 }
815 /*---------------------------------------------------------------------------*/
TTWAIN_FreeMemory(void * hMem)816 void TTWAIN_FreeMemory(void *hMem) {
817   free(hMem);
818   /*
819 if (hMem)
820 GLOBAL_FREE(hMem);
821 */
822 }
823 /*---------------------------------------------------------------------------*/
TTWAIN_ModalEventLoop(void)824 static void TTWAIN_ModalEventLoop(void) { TTWAIN_ModalEventLoopPD(); }
825 /*---------------------------------------------------------------------------*/
TTWAIN_BreakModalLoop(void)826 static void TTWAIN_BreakModalLoop(void) { TTwainData.breakModalLoop = TRUE; }
827 /*---------------------------------------------------------------------------*/
TTWAIN_EmptyMessageQueue(void)828 static void TTWAIN_EmptyMessageQueue(void) { TTWAIN_EmptyMessageQueuePD(); }
829 /*---------------------------------------------------------------------------*/
TTWAIN_NativeXferHandler(void)830 static int TTWAIN_NativeXferHandler(void) {
831   TW_UINT32 hNative;
832 
833   assert(TTWAIN_GetState() == TWAIN_TRANSFER_READY);
834   if (TTWAIN_DS(DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hNative) ==
835       TWRC_XFERDONE)
836     TTwainData.transferInfo.hDib = (void *)hNative;
837   else
838     TTwainData.transferInfo.hDib = NULL;
839   return (!!TTwainData.transferInfo.hDib);
840 }
841 /*---------------------------------------------------------------------------*/
TTWAIN_MemoryXferHandler(void)842 static int TTWAIN_MemoryXferHandler(void) {
843   TW_IMAGEMEMXFER *imageMemXfer = 0;
844   TW_HANDLE imageMemXferH       = 0;
845   TW_HANDLE transferBufferH     = 0;
846   TW_SETUPMEMXFER setup;
847   TW_IMAGEINFO info;
848   TW_IMAGELAYOUT imageLayout;
849   TUINT32 nTransferDone;
850   TW_INT16 rc1, rc2, rc3, rc4, twRC2;
851   int ret               = FALSE;
852   int stopScanning      = 0;
853   UCHAR *transferBuffer = 0;
854   UCHAR *sourceBuffer   = 0;
855   UCHAR *targetBuffer   = 0;
856   unsigned int rows;
857   double pixSize;
858   int extraX              = 0;
859   int extraY              = 0;
860   TW_UINT32 rowsToCopy    = 0;
861   TW_UINT32 rowsRemaining = 0;
862   TW_UINT32 bytesToCopy   = 0;
863   TW_UINT32 bytesToWrap   = 0;
864   TW_UINT32 memorySize    = 0;
865   int imgInfoOk; /* on Mac often (always) is impossible to get the imageinfo
866                                                                            about
867                     the transfer... so no I can't prealloc memory
868                                                                            and
869                     do other checks about size etc...
870                                                                   */
871 
872   /*printf("%s\n", __PRETTY_FUNCTION__);*/
873 
874   memset(&info, 0, sizeof(TW_IMAGEINFO));
875   rc1       = TTWAIN_DS(DG_IMAGE, DAT_IMAGEINFO, MSG_GET, (TW_MEMREF)&info);
876   imgInfoOk = (rc1 == TWRC_SUCCESS);
877 
878   /*printf("get image info returns %d\n", imgInfoOk);*/
879 
880   rc4 = TTWAIN_DS(DG_IMAGE, DAT_IMAGELAYOUT, MSG_GET, &imageLayout);
881 
882   /* determine the transfer buffer size */
883   rc2 = TTWAIN_DS(DG_CONTROL, DAT_SETUPMEMXFER, MSG_GET, (TW_MEMREF)&setup);
884   transferBufferH = GLOBAL_ALLOC(GMEM_FIXED, setup.Preferred);
885   if (!transferBufferH) return FALSE;
886   transferBuffer = (UCHAR *)GLOBAL_LOCK(transferBufferH);
887 
888   if (imgInfoOk) {
889     pixSize    = info.BitsPerPixel / 8.0;
890     memorySize = info.ImageLength * CEIL(info.ImageWidth * pixSize);
891   } else {
892     /* we need to allocate incrementally the memory needs to store the image*/
893     memorySize =
894         setup.Preferred; /* start using the setupmemxfer.preferred size*/
895     pixSize = 3;
896   }
897 
898   if (TTwainData.transferInfo.usageMode == TTWAIN_MODE_UNLEASHED) {
899     /*
900 TTwainData.transferInfo = GLOBAL_ALLOC(GMEM_FIXED, memorySize);
901 */
902     TTwainData.transferInfo.memoryBuffer = (UCHAR *)malloc(memorySize);
903 
904     if (!TTwainData.transferInfo.memoryBuffer) {
905       /*tmsg_error("unable to allocate memory!");*/
906       return FALSE;
907     }
908     if (imgInfoOk) {
909       TTwainData.transferInfo.memorySize  = memorySize;
910       TTwainData.transferInfo.preferredLx = info.ImageWidth;
911       TTwainData.transferInfo.preferredLy = info.ImageLength;
912     } else {
913       TTwainData.transferInfo.memorySize  = setup.Preferred;
914       TTwainData.transferInfo.preferredLx = 0;
915       TTwainData.transferInfo.preferredLy = 0;
916     }
917   }
918 
919   extraX = info.ImageWidth - TTwainData.transferInfo.preferredLx;
920   extraY = info.ImageLength - TTwainData.transferInfo.preferredLy;
921 
922   rowsRemaining = min(TTwainData.transferInfo.preferredLy, info.ImageLength);
923 
924   targetBuffer = TTwainData.transferInfo.memoryBuffer;
925 
926   /*clean-up the buffer
927 memset(targetBuffer, 0xff, TTwainData.transferInfo.memorySize);
928 */
929 
930   imageMemXferH = GLOBAL_ALLOC(GMEM_FIXED, sizeof(TW_IMAGEMEMXFER));
931   if (!imageMemXferH) return FALSE;
932 
933   imageMemXfer = (TW_IMAGEMEMXFER *)GLOBAL_LOCK(imageMemXferH);
934 
935   imageMemXfer->Memory.TheMem                = (char *)transferBuffer;
936   imageMemXfer->Memory.Length                = setup.Preferred;
937   imageMemXfer->Memory.Flags                 = TWMF_APPOWNS | TWMF_POINTER;
938   TTwainData.transferInfo.pendingXfers.Count = 0;
939   /* transfer the data -- loop until done or canceled */
940   nTransferDone = 0;
941   do {
942     rc3 =
943         TTWAIN_DS(DG_IMAGE, DAT_IMAGEMEMXFER, MSG_GET, (TW_MEMREF)imageMemXfer);
944     nTransferDone++;
945     switch (rc3) {
946     case TWRC_SUCCESS:
947       PRINTF("IMAGEMEMXFER, GET, returns SUCCESS\n");
948       if (imgInfoOk) {
949         TW_UINT32 colsToCopy;
950         rowsToCopy = min(imageMemXfer->Rows, rowsRemaining);
951         colsToCopy = min(imageMemXfer->Columns,
952                          (unsigned long)TTwainData.transferInfo.preferredLx);
953         bytesToCopy = CEIL(colsToCopy * pixSize);
954         bytesToWrap = CEIL(TTwainData.transferInfo.preferredLx * pixSize);
955       } else {
956         TW_UINT32 newMemorySize;
957         rowsToCopy  = imageMemXfer->Rows;
958         bytesToCopy = imageMemXfer->BytesPerRow;
959         bytesToWrap = bytesToCopy;
960         newMemorySize =
961             (TTwainData.transferInfo.preferredLy + imageMemXfer->Rows) *
962             imageMemXfer->BytesPerRow;
963         if (TTwainData.transferInfo.memorySize < newMemorySize) {
964           TTwainData.transferInfo.memoryBuffer = (UCHAR *)realloc(
965               TTwainData.transferInfo.memoryBuffer, newMemorySize);
966           TTwainData.transferInfo.memorySize = newMemorySize;
967           targetBuffer =
968               TTwainData.transferInfo.memoryBuffer +
969               (TTwainData.transferInfo.preferredLy * imageMemXfer->BytesPerRow);
970         }
971         TTwainData.transferInfo.preferredLy += rowsToCopy;
972         if ((int)imageMemXfer->Columns > TTwainData.transferInfo.preferredLx)
973           TTwainData.transferInfo.preferredLx = imageMemXfer->Columns;
974       }
975 
976       sourceBuffer = (UCHAR *)imageMemXfer->Memory.TheMem;
977       if (TTwainData.transferInfo.nextImageNeedsToBeInverted)
978         INVERT_BYTE(sourceBuffer, bytesToCopy)
979 
980       for (rows = 0; rows < rowsToCopy; rows++) {
981         memcpy(targetBuffer, sourceBuffer, bytesToCopy);
982         targetBuffer += bytesToWrap;
983         sourceBuffer += imageMemXfer->BytesPerRow;
984       }
985       rowsRemaining -= rowsToCopy;
986       break;
987 
988     case TWRC_XFERDONE:
989       PRINTF("IMAGEMEMXFER, GET, returns XFERDONE\n");
990       /*copy the last transfer data*/
991       if (imgInfoOk) {
992         TW_UINT32 colsToCopy;
993         rowsToCopy = min(imageMemXfer->Rows, rowsRemaining);
994         colsToCopy = min(imageMemXfer->Columns,
995                          (unsigned long)TTwainData.transferInfo.preferredLx);
996         bytesToCopy = CEIL(colsToCopy * pixSize);
997         bytesToWrap = CEIL(TTwainData.transferInfo.preferredLx * pixSize);
998       } else {
999         TW_UINT32 newMemorySize;
1000         rowsToCopy  = imageMemXfer->Rows;
1001         bytesToCopy = imageMemXfer->BytesPerRow;
1002         bytesToWrap = bytesToCopy;
1003         newMemorySize =
1004             (TTwainData.transferInfo.preferredLy + imageMemXfer->Rows) *
1005             imageMemXfer->BytesPerRow;
1006         if (TTwainData.transferInfo.memorySize < newMemorySize) {
1007           TTwainData.transferInfo.memoryBuffer = (UCHAR *)realloc(
1008               TTwainData.transferInfo.memoryBuffer, newMemorySize);
1009           TTwainData.transferInfo.memorySize = newMemorySize;
1010           targetBuffer =
1011               TTwainData.transferInfo.memoryBuffer +
1012               (TTwainData.transferInfo.preferredLy * imageMemXfer->BytesPerRow);
1013         }
1014         TTwainData.transferInfo.preferredLy += rowsToCopy;
1015         if ((int)imageMemXfer->Columns > TTwainData.transferInfo.preferredLx)
1016           TTwainData.transferInfo.preferredLx = imageMemXfer->Columns;
1017       }
1018       sourceBuffer = (UCHAR *)imageMemXfer->Memory.TheMem;
1019       if (TTwainData.transferInfo.nextImageNeedsToBeInverted)
1020         INVERT_BYTE(sourceBuffer, bytesToCopy)
1021 
1022       for (rows = 0; rows < rowsToCopy; rows++) {
1023         memcpy(targetBuffer, sourceBuffer, bytesToCopy);
1024         targetBuffer += bytesToWrap;
1025         sourceBuffer += imageMemXfer->BytesPerRow;
1026       }
1027       rowsRemaining -= rowsToCopy;
1028       PRINTF("get pending xfers\n");
1029       twRC2 = TTWAIN_DS(DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER,
1030                         (TW_MEMREF)&TTwainData.transferInfo.pendingXfers);
1031       if (twRC2 != TWRC_SUCCESS) {
1032         printf("pending xfers != success");
1033         ret = FALSE;
1034         goto done;
1035       }
1036       PRINTF(" pending count = %d\n",
1037              TTwainData.transferInfo.pendingXfers.Count);
1038       if (TTwainData.transferInfo.pendingXfers.Count == 0) {
1039         ret = TRUE;
1040         goto done;
1041       }
1042       if (TTwainData.transferInfo.pendingXfers.Count == 0xffff) {
1043         ret = TRUE;
1044         goto done;
1045       }
1046       if (TTwainData.transferInfo.pendingXfers.Count == 0xfffe) {
1047         ret = TRUE;
1048         goto done;
1049       }
1050       ret = TRUE;
1051       goto done;
1052 
1053     case TWRC_CANCEL:
1054       TTWAIN_RecordError();
1055       twRC2 = TTWAIN_DS(DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER,
1056                         (TW_MEMREF)&TTwainData.transferInfo.pendingXfers);
1057       if (twRC2 != TWRC_SUCCESS) {
1058         ret = FALSE;
1059         goto done;
1060       }
1061       if (TTwainData.transferInfo.pendingXfers.Count == 0) {
1062         ret = FALSE;
1063         goto done;
1064       }
1065       break;
1066 
1067     case TWRC_FAILURE:
1068       PRINTF("IMAGEMEMXFER, GET, returns FAILURE\n");
1069       TTWAIN_RecordError();
1070       twRC2 = TTWAIN_DS(DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER,
1071                         (TW_MEMREF)&TTwainData.transferInfo.pendingXfers);
1072       if (twRC2 != TWRC_SUCCESS) {
1073         ret = FALSE;
1074         goto done;
1075       }
1076       if (TTwainData.transferInfo.pendingXfers.Count == 0) {
1077         ret = FALSE;
1078         goto done;
1079       }
1080       break;
1081 
1082     default:
1083       PRINTF("IMAGEMEMXFER, GET, returns ?!? Default handler called\n");
1084       /* Abort the image */
1085       TTWAIN_RecordError();
1086       twRC2 = TTWAIN_DS(DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER,
1087                         (TW_MEMREF)&TTwainData.transferInfo.pendingXfers);
1088       if (twRC2 != TWRC_SUCCESS) {
1089         ret = FALSE;
1090         goto done;
1091       }
1092       if (TTwainData.transferInfo.pendingXfers.Count == 0) {
1093         ret = FALSE;
1094         goto done;
1095       }
1096     }
1097   } while (rc3 == TWRC_SUCCESS);
1098 
1099 done:
1100   if (ret == TRUE) {
1101     if (TTwainData.callback.onDoneCb) {
1102       float xdpi, ydpi;
1103       TTWAIN_PIXTYPE pixType;
1104       xdpi = TTWAIN_Fix32ToFloat(info.XResolution);
1105       ydpi = TTWAIN_Fix32ToFloat(info.YResolution);
1106 
1107       if (imgInfoOk) {
1108         xdpi = TTWAIN_Fix32ToFloat(info.XResolution);
1109         ydpi = TTWAIN_Fix32ToFloat(info.YResolution);
1110         switch (BB(info.PixelType, info.BitsPerPixel)) {
1111         case BB(TWPT_BW, 1):
1112           pixType = TTWAIN_BW;
1113           break;
1114         case BB(TWPT_GRAY, 8):
1115           pixType = TTWAIN_GRAY8;
1116           break;
1117         case BB(TWPT_RGB, 24):
1118           pixType = TTWAIN_RGB24;
1119           break;
1120         default:
1121           pixType = TTWAIN_RGB24;
1122           break;
1123         }
1124       } else {
1125         float lx = TTWAIN_Fix32ToFloat(imageLayout.Frame.Right) -
1126                    TTWAIN_Fix32ToFloat(imageLayout.Frame.Left);
1127         float ly = TTWAIN_Fix32ToFloat(imageLayout.Frame.Bottom) -
1128                    TTWAIN_Fix32ToFloat(imageLayout.Frame.Top);
1129 
1130         xdpi = (float)TTwainData.transferInfo.preferredLx / lx;
1131         ydpi = (float)TTwainData.transferInfo.preferredLy / ly;
1132 
1133         switch (imageMemXfer->BytesPerRow /
1134                 TTwainData.transferInfo.preferredLx) {
1135         case 1:
1136           pixType = TTWAIN_GRAY8;
1137           break;
1138         case 3:
1139           pixType = TTWAIN_RGB24;
1140           break;
1141         default: {
1142           double b = (imageMemXfer->BytesPerRow /
1143                       (double)TTwainData.transferInfo.preferredLx);
1144           if ((b >= 0.125) && (b < 8))
1145             pixType = TTWAIN_BW;
1146           else {
1147             printf("unable to det pix type assume RGB24\n");
1148             pixType = TTWAIN_RGB24;
1149           }
1150           break;
1151         }
1152         }
1153       }
1154       stopScanning = !TTwainData.callback.onDoneCb(
1155           TTwainData.transferInfo.memoryBuffer, pixType,
1156           TTwainData.transferInfo.preferredLx,
1157           TTwainData.transferInfo.preferredLy,
1158           TTwainData.transferInfo.preferredLx, xdpi, ydpi,
1159           TTwainData.callback.onDoneArg);
1160 #ifdef MACOSX
1161       PRINTF("stopScanning = %d\n", stopScanning);
1162       exitTwainSession();
1163 #endif
1164     }
1165   } else /*ret == FALSE*/
1166   {
1167     if (TTwainData.callback.onErrorCb) {
1168       TTwainData.callback.onErrorCb(TTwainData.callback.onErrorArg, 0);
1169     }
1170   }
1171 
1172   if (imageMemXferH) {
1173     GLOBAL_UNLOCK(imageMemXferH);
1174     GLOBAL_FREE(imageMemXferH);
1175   }
1176 
1177   if (transferBufferH) {
1178     GLOBAL_UNLOCK(transferBuffer);
1179     GLOBAL_FREE(transferBufferH);
1180   }
1181   return ret && !stopScanning;
1182 }
1183 /*---------------------------------------------------------------------------*/
TTWAIN_InitVar(void)1184 int TTWAIN_InitVar(void) {
1185   char *c;
1186   if (TTwainData.initDone) return TRUE;
1187 
1188   TTwainData.DSM_Entry                  = 0;
1189   TTwainData.hwnd32SM                   = 0;
1190   TTwainData.twainAvailable             = AVAIABLE_DONTKNOW;
1191   TTwainData.breakModalLoop             = FALSE;
1192   TTwainData.UIStatus                   = FALSE;
1193   TTwainData.twainState                 = TWAIN_PRESESSION;
1194   TTwainData.transferInfo.hDib          = 0;
1195   TTwainData.transferInfo.multiTransfer = TRUE;
1196   TTwainData.supportedCaps              = 0;
1197   TTwainData.resultCode                 = 0;
1198   TTwainData.ErrRC                      = 0;
1199   TTwainData.ErrCC                      = 0;
1200   TTwainData.modalStatus                = FALSE;
1201   TTwainData.appId.Id                   = 0;
1202   TTWAIN_ConvertRevStrToRevNum(RELEASE_STR, &TTwainData.appId.Version.MajorNum,
1203                                &TTwainData.appId.Version.MinorNum);
1204   TTwainData.appId.Version.Language = TWLG_USA;
1205   TTwainData.appId.Version.Country  = TWCY_USA;
1206   strcpy((char *)TTwainData.appId.Version.Info, TITLEBAR_STR);
1207 
1208   TTwainData.appId.ProtocolMajor   = TWON_PROTOCOLMAJOR;
1209   TTwainData.appId.ProtocolMinor   = TWON_PROTOCOLMINOR;
1210   TTwainData.appId.SupportedGroups = DG_IMAGE | DG_CONTROL;
1211 
1212   c = (char *)TTwainData.appId.Manufacturer;
1213 #ifdef MACOSX
1214   *c = strlen(COMPANY);
1215   c++;
1216 #endif
1217   strcpy(c, COMPANY);
1218 
1219   c = (char *)TTwainData.appId.ProductFamily;
1220 #ifdef MACOSX
1221   *c = strlen(PRODUCT);
1222   c++;
1223 #endif
1224   strcpy(c, PRODUCT);
1225 
1226   c = (char *)TTwainData.appId.ProductName;
1227 #ifdef MACOSX
1228   *c = strlen(TwProgramName);
1229   c++;
1230 #endif
1231   strcpy(c, TwProgramName);
1232 
1233   TTwainData.initDone = TRUE;
1234   return TRUE;
1235 }
1236 /*---------------------------------------------------------------------------*/
TTWAIN_FreeVar(void)1237 static void TTWAIN_FreeVar(void) {
1238   if (TTwainData.supportedCaps) {
1239     /* MEMORY LEAK !
1240 GLOBAL_FREE(TTwainData.supportedCaps);
1241 */
1242     TTwainData.supportedCaps = 0;
1243   }
1244 }
1245 /*---------------------------------------------------------------------------*/
1246 
1247 #ifdef __cplusplus
1248 }
1249 #endif
1250