1141cc406Sopenharmony_ci/* 2141cc406Sopenharmony_ci sane - Scanner Access Now Easy. 3141cc406Sopenharmony_ci Copyright (C) 2006 Jon Chambers <jon@jon.demon.co.uk> 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This file is part of the SANE package. 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 8141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 9141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 10141cc406Sopenharmony_ci License, or (at your option) any later version. 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 13141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 14141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15141cc406Sopenharmony_ci General Public License for more details. 16141cc406Sopenharmony_ci 17141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 18141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 19141cc406Sopenharmony_ci 20141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 21141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 24141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 25141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 26141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 27141cc406Sopenharmony_ci account of linking the SANE library code into it. 28141cc406Sopenharmony_ci 29141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 30141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 31141cc406Sopenharmony_ci License. 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 34141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 35141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 36141cc406Sopenharmony_ci 37141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 38141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 39141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 40141cc406Sopenharmony_ci 41141cc406Sopenharmony_ci Dell 1600n network scan driver for SANE. 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci To debug: 44141cc406Sopenharmony_ci SANE_DEBUG_DELL1600N_NET=255 scanimage --verbose 2>scan.errs 1>scan.png 45141cc406Sopenharmony_ci*/ 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci/*********************************************************** 48141cc406Sopenharmony_ci * INCLUDES 49141cc406Sopenharmony_ci ***********************************************************/ 50141cc406Sopenharmony_ci 51141cc406Sopenharmony_ci#include "../include/sane/config.h" 52141cc406Sopenharmony_ci#include "../include/sane/sane.h" 53141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 54141cc406Sopenharmony_ci 55141cc406Sopenharmony_ci#define BACKEND_NAME dell1600n_net 56141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 57141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci#include <stdlib.h> 60141cc406Sopenharmony_ci#include <string.h> 61141cc406Sopenharmony_ci#include <stdio.h> 62141cc406Sopenharmony_ci#include <math.h> 63141cc406Sopenharmony_ci#include <unistd.h> 64141cc406Sopenharmony_ci 65141cc406Sopenharmony_ci/* :NOTE: these are likely to be platform-specific! */ 66141cc406Sopenharmony_ci#include <sys/types.h> 67141cc406Sopenharmony_ci#include <sys/socket.h> 68141cc406Sopenharmony_ci#include <sys/time.h> 69141cc406Sopenharmony_ci#include <netinet/in.h> 70141cc406Sopenharmony_ci#include <netdb.h> 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ci#include <jpeglib.h> 73141cc406Sopenharmony_ci#include <tiffio.h> 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ci/* OS/2... */ 76141cc406Sopenharmony_ci#ifndef SHUT_RDWR 77141cc406Sopenharmony_ci#define SHUT_RDWR 2 78141cc406Sopenharmony_ci#endif 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci 81141cc406Sopenharmony_ci/*********************************************************** 82141cc406Sopenharmony_ci * DEFINITIONS 83141cc406Sopenharmony_ci ***********************************************************/ 84141cc406Sopenharmony_ci 85141cc406Sopenharmony_ci/* Maximum number of scanners */ 86141cc406Sopenharmony_ci#define MAX_SCANNERS 32 87141cc406Sopenharmony_ci 88141cc406Sopenharmony_ci/* version number */ 89141cc406Sopenharmony_ci#define DRIVER_VERSION SANE_VERSION_CODE( SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0 ) 90141cc406Sopenharmony_ci 91141cc406Sopenharmony_ci/* size of buffer for socket communication */ 92141cc406Sopenharmony_ci#define SOCK_BUF_SIZE 2048 93141cc406Sopenharmony_ci 94141cc406Sopenharmony_ci/* size of registation name */ 95141cc406Sopenharmony_ci#define REG_NAME_SIZE 64 96141cc406Sopenharmony_ci 97141cc406Sopenharmony_cistruct DeviceRecord 98141cc406Sopenharmony_ci{ 99141cc406Sopenharmony_ci SANE_Device m_device; 100141cc406Sopenharmony_ci char * m_pName; /* storage of name */ 101141cc406Sopenharmony_ci char * m_pModel; /* storage of model */ 102141cc406Sopenharmony_ci}; 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_ci/* a buffer struct to store "stuff" */ 105141cc406Sopenharmony_cistruct ComBuf 106141cc406Sopenharmony_ci{ 107141cc406Sopenharmony_ci size_t m_capacity; /* current allocated size in bytes */ 108141cc406Sopenharmony_ci size_t m_used; /* current used size in bytes */ 109141cc406Sopenharmony_ci unsigned char *m_pBuf; /* storage (or NULL if none allocated) */ 110141cc406Sopenharmony_ci}; 111141cc406Sopenharmony_ci 112141cc406Sopenharmony_ci/* state data for a single scanner connection */ 113141cc406Sopenharmony_cistruct ScannerState 114141cc406Sopenharmony_ci{ 115141cc406Sopenharmony_ci int m_udpFd; /* file descriptor to UDP socket */ 116141cc406Sopenharmony_ci int m_tcpFd; /* file descriptor to TCP socket */ 117141cc406Sopenharmony_ci struct sockaddr_in m_sockAddr; /* printer address */ 118141cc406Sopenharmony_ci struct ComBuf m_buf; /* buffer for network data */ 119141cc406Sopenharmony_ci struct ComBuf m_imageData; /* storage for decoded image data */ 120141cc406Sopenharmony_ci int m_numPages; /* number of complete pages (host byte order) */ 121141cc406Sopenharmony_ci struct ComBuf m_pageInfo; /* "array" of numPages PageInfo structs */ 122141cc406Sopenharmony_ci int m_bFinish; /* set non-0 to signal that we are finished */ 123141cc406Sopenharmony_ci int m_bCancelled; /* set non-0 that bFinish state arose from cancellation */ 124141cc406Sopenharmony_ci char m_regName[REG_NAME_SIZE]; /* name with which to register */ 125141cc406Sopenharmony_ci unsigned short m_xres; /* x resolution (network byte order) */ 126141cc406Sopenharmony_ci unsigned short m_yres; /* y resolution (network byte order) */ 127141cc406Sopenharmony_ci unsigned int m_composition; /* composition (0x01=>TIFF/PDF,0x40=>JPEG) (network byte order) */ 128141cc406Sopenharmony_ci unsigned char m_brightness; /* brightness */ 129141cc406Sopenharmony_ci unsigned int m_compression; /* compression (0x08=>CCIT Group 4,0x20=>JPEG) (network byte order) */ 130141cc406Sopenharmony_ci unsigned int m_fileType; /* file type (2=>TIFF,4=>PDF,8=>JPEG)(network byte order) */ 131141cc406Sopenharmony_ci unsigned int m_pixelWidth; /* width in pixels (network byte order) */ 132141cc406Sopenharmony_ci unsigned int m_pixelHeight; /* height in pixels (network byte order) */ 133141cc406Sopenharmony_ci unsigned int m_bytesRead; /* bytes read by SANE (host byte order) */ 134141cc406Sopenharmony_ci unsigned int m_currentPageBytes;/* number of bytes of current page read (host byte order) */ 135141cc406Sopenharmony_ci}; 136141cc406Sopenharmony_ci 137141cc406Sopenharmony_ci/* state data for a single page 138141cc406Sopenharmony_ci NOTE: all ints are in host byte order 139141cc406Sopenharmony_ci*/ 140141cc406Sopenharmony_cistruct PageInfo 141141cc406Sopenharmony_ci{ 142141cc406Sopenharmony_ci int m_width; /* pixel width */ 143141cc406Sopenharmony_ci int m_height; /* pixel height */ 144141cc406Sopenharmony_ci int m_totalSize; /* total page size (bytes) */ 145141cc406Sopenharmony_ci int m_bytesRemaining; /* number of bytes not yet passed to SANE client */ 146141cc406Sopenharmony_ci}; 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_ci/* struct for in-memory jpeg decompression */ 149141cc406Sopenharmony_cistruct JpegDataDecompState 150141cc406Sopenharmony_ci{ 151141cc406Sopenharmony_ci struct jpeg_decompress_struct m_cinfo; /* base struct */ 152141cc406Sopenharmony_ci unsigned char *m_pData; /* data pointer */ 153141cc406Sopenharmony_ci unsigned int m_bytesRemaining; /* amount of unprocessed data */ 154141cc406Sopenharmony_ci}; 155141cc406Sopenharmony_ci 156141cc406Sopenharmony_ci/* initial ComBuf allocation */ 157141cc406Sopenharmony_ci#define INITIAL_COM_BUF_SIZE 1024 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci/*********************************************************** 160141cc406Sopenharmony_ci * FUNCTION PROTOTYPES 161141cc406Sopenharmony_ci ***********************************************************/ 162141cc406Sopenharmony_ci 163141cc406Sopenharmony_ci/* print hex buffer to stdout */ 164141cc406Sopenharmony_cistatic void HexDump (int debugLevel, const unsigned char *buf, 165141cc406Sopenharmony_ci size_t bufSize); 166141cc406Sopenharmony_ci 167141cc406Sopenharmony_ci/* clears gKnownDevices array */ 168141cc406Sopenharmony_cistatic void ClearKnownDevices (void); 169141cc406Sopenharmony_ci 170141cc406Sopenharmony_ci/* initialise a ComBuf struct */ 171141cc406Sopenharmony_cistatic int InitComBuf (struct ComBuf *pBuf); 172141cc406Sopenharmony_ci 173141cc406Sopenharmony_ci/* free a ComBuf struct */ 174141cc406Sopenharmony_cistatic void FreeComBuf (struct ComBuf *pBuf); 175141cc406Sopenharmony_ci 176141cc406Sopenharmony_ci/* add data to a ComBuf struct */ 177141cc406Sopenharmony_cistatic int AppendToComBuf (struct ComBuf *pBuf, const unsigned char *pData, 178141cc406Sopenharmony_ci size_t datSize); 179141cc406Sopenharmony_ci 180141cc406Sopenharmony_ci/* remove data from the front of a ComBuf struct */ 181141cc406Sopenharmony_cistatic int PopFromComBuf (struct ComBuf *pBuf, size_t datSize); 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_ci/* initialise a packet */ 184141cc406Sopenharmony_cistatic int InitPacket (struct ComBuf *pBuf, char type); 185141cc406Sopenharmony_ci 186141cc406Sopenharmony_ci/* append message to a packet */ 187141cc406Sopenharmony_cistatic int AppendMessageToPacket (struct ComBuf *pBuf, 188141cc406Sopenharmony_ci char messageType, 189141cc406Sopenharmony_ci char *messageName, 190141cc406Sopenharmony_ci char valueType, 191141cc406Sopenharmony_ci void *pValue, size_t valueLen); 192141cc406Sopenharmony_ci 193141cc406Sopenharmony_ci/* write length data to packet header */ 194141cc406Sopenharmony_cistatic void FinalisePacket (struct ComBuf *pBuf); 195141cc406Sopenharmony_ci 196141cc406Sopenharmony_ci/* \return 1 if message is complete, 0 otherwise */ 197141cc406Sopenharmony_cistatic int MessageIsComplete (unsigned char *pData, size_t size); 198141cc406Sopenharmony_ci 199141cc406Sopenharmony_ci/* process a registration broadcast response 200141cc406Sopenharmony_ci \return DeviceRecord pointer on success (caller frees), NULL on failure 201141cc406Sopenharmony_ci*/ 202141cc406Sopenharmony_cistatic struct DeviceRecord *ProcessFindResponse (unsigned char *pData, size_t size); 203141cc406Sopenharmony_ci 204141cc406Sopenharmony_ci/* frees a scanner state struct stored in gOpenScanners */ 205141cc406Sopenharmony_cistatic void FreeScannerState (int iHandle); 206141cc406Sopenharmony_ci 207141cc406Sopenharmony_ci/* \return 1 if iHandle is a valid member of gOpenScanners, 0 otherwise */ 208141cc406Sopenharmony_cistatic int ValidScannerNumber (int iHandle); 209141cc406Sopenharmony_ci 210141cc406Sopenharmony_ci/* process UDP responses, \return 0 in success, >0 otherwise */ 211141cc406Sopenharmony_cistatic int ProcessUdpResponse (unsigned char *pData, size_t size, 212141cc406Sopenharmony_ci struct ScannerState *pState); 213141cc406Sopenharmony_ci 214141cc406Sopenharmony_ci/* process TCP responses, \return 0 in success, >0 otherwise */ 215141cc406Sopenharmony_cistatic int ProcessTcpResponse (struct ScannerState *pState, 216141cc406Sopenharmony_ci struct ComBuf *pTcpBufBuf); 217141cc406Sopenharmony_ci 218141cc406Sopenharmony_ci/* Process the data from a single scanned page, \return 0 in success, >0 otherwise */ 219141cc406Sopenharmony_cistatic int ProcessPageData (struct ScannerState *pState); 220141cc406Sopenharmony_ci 221141cc406Sopenharmony_ci/* Libjpeg decompression interface */ 222141cc406Sopenharmony_cistatic void JpegDecompInitSource (j_decompress_ptr cinfo); 223141cc406Sopenharmony_cistatic boolean JpegDecompFillInputBuffer (j_decompress_ptr cinfo); 224141cc406Sopenharmony_cistatic void JpegDecompSkipInputData (j_decompress_ptr cinfo, long numBytes); 225141cc406Sopenharmony_cistatic void JpegDecompTermSource (j_decompress_ptr cinfo); 226141cc406Sopenharmony_ci 227141cc406Sopenharmony_ci/*********************************************************** 228141cc406Sopenharmony_ci * GLOBALS 229141cc406Sopenharmony_ci ***********************************************************/ 230141cc406Sopenharmony_ci 231141cc406Sopenharmony_ci/* Results of last call to sane_get_devices */ 232141cc406Sopenharmony_cistatic struct DeviceRecord *gKnownDevices[MAX_SCANNERS]; 233141cc406Sopenharmony_ci 234141cc406Sopenharmony_ci/* Empty list for when network devices are not wanted */ 235141cc406Sopenharmony_cistatic const SANE_Device *gEmptyDeviceList[1]; 236141cc406Sopenharmony_ci 237141cc406Sopenharmony_ci/* Array of open scanner device states. 238141cc406Sopenharmony_ci :NOTE: (int)SANE_Handle is an offset into this array */ 239141cc406Sopenharmony_cistatic struct ScannerState *gOpenScanners[MAX_SCANNERS]; 240141cc406Sopenharmony_ci 241141cc406Sopenharmony_ci/* scanner port */ 242141cc406Sopenharmony_cistatic unsigned short gScannerPort = 1124; 243141cc406Sopenharmony_ci 244141cc406Sopenharmony_ci/* ms to wait for registration replies */ 245141cc406Sopenharmony_cistatic unsigned short gRegReplyWaitMs = 300; 246141cc406Sopenharmony_ci 247141cc406Sopenharmony_ci/*********************************************************** 248141cc406Sopenharmony_ci * FUNCTION IMPLEMENTATIONS 249141cc406Sopenharmony_ci ***********************************************************/ 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_ciSANE_Status 252141cc406Sopenharmony_cisane_init (SANE_Int * version_code, 253141cc406Sopenharmony_ci SANE_Auth_Callback __sane_unused__ authorize) 254141cc406Sopenharmony_ci{ 255141cc406Sopenharmony_ci 256141cc406Sopenharmony_ci /* init globals */ 257141cc406Sopenharmony_ci memset (gKnownDevices, 0, sizeof (gKnownDevices)); 258141cc406Sopenharmony_ci memset (gOpenScanners, 0, sizeof (gOpenScanners)); 259141cc406Sopenharmony_ci 260141cc406Sopenharmony_ci /* report version */ 261141cc406Sopenharmony_ci *version_code = DRIVER_VERSION; 262141cc406Sopenharmony_ci 263141cc406Sopenharmony_ci /* init debug */ 264141cc406Sopenharmony_ci DBG_INIT (); 265141cc406Sopenharmony_ci 266141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 267141cc406Sopenharmony_ci 268141cc406Sopenharmony_ci} /* sane_init */ 269141cc406Sopenharmony_ci 270141cc406Sopenharmony_ci/***********************************************************/ 271141cc406Sopenharmony_ci 272141cc406Sopenharmony_civoid 273141cc406Sopenharmony_cisane_exit (void) 274141cc406Sopenharmony_ci{ 275141cc406Sopenharmony_ci 276141cc406Sopenharmony_ci int iHandle; 277141cc406Sopenharmony_ci 278141cc406Sopenharmony_ci /* clean up */ 279141cc406Sopenharmony_ci ClearKnownDevices (); 280141cc406Sopenharmony_ci 281141cc406Sopenharmony_ci for (iHandle = 0; iHandle < MAX_SCANNERS; ++iHandle) 282141cc406Sopenharmony_ci { 283141cc406Sopenharmony_ci if (gOpenScanners[iHandle]) 284141cc406Sopenharmony_ci FreeScannerState (iHandle); 285141cc406Sopenharmony_ci } 286141cc406Sopenharmony_ci 287141cc406Sopenharmony_ci} /* sane_exit */ 288141cc406Sopenharmony_ci 289141cc406Sopenharmony_ci/***********************************************************/ 290141cc406Sopenharmony_ci 291141cc406Sopenharmony_ciSANE_Status 292141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 293141cc406Sopenharmony_ci{ 294141cc406Sopenharmony_ci 295141cc406Sopenharmony_ci int ret; 296141cc406Sopenharmony_ci unsigned char sockBuf[SOCK_BUF_SIZE]; 297141cc406Sopenharmony_ci int sock, optYes; 298141cc406Sopenharmony_ci struct DeviceRecord *pDevice; 299141cc406Sopenharmony_ci struct ComBuf queryPacket; 300141cc406Sopenharmony_ci struct sockaddr_in remoteAddr; 301141cc406Sopenharmony_ci unsigned char ucVal; 302141cc406Sopenharmony_ci fd_set readFds; 303141cc406Sopenharmony_ci struct timeval selTimeVal; 304141cc406Sopenharmony_ci int nread, iNextDevice; 305141cc406Sopenharmony_ci FILE *fConfig; 306141cc406Sopenharmony_ci char configBuf[ 256 ]; 307141cc406Sopenharmony_ci const char *pVal; 308141cc406Sopenharmony_ci int valLen; 309141cc406Sopenharmony_ci 310141cc406Sopenharmony_ci if (local_only) { 311141cc406Sopenharmony_ci *device_list = gEmptyDeviceList; 312141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 313141cc406Sopenharmony_ci } 314141cc406Sopenharmony_ci 315141cc406Sopenharmony_ci /* init variables */ 316141cc406Sopenharmony_ci ret = SANE_STATUS_GOOD; 317141cc406Sopenharmony_ci sock = 0; 318141cc406Sopenharmony_ci pDevice = NULL; 319141cc406Sopenharmony_ci optYes = 1; 320141cc406Sopenharmony_ci 321141cc406Sopenharmony_ci InitComBuf (&queryPacket); 322141cc406Sopenharmony_ci 323141cc406Sopenharmony_ci /* clear previous results */ 324141cc406Sopenharmony_ci ClearKnownDevices (); 325141cc406Sopenharmony_ci iNextDevice = 0; 326141cc406Sopenharmony_ci 327141cc406Sopenharmony_ci /* look for a config file */ 328141cc406Sopenharmony_ci fConfig = sanei_config_open( "dell1600n_net.conf" ); 329141cc406Sopenharmony_ci if ( fConfig ) 330141cc406Sopenharmony_ci { 331141cc406Sopenharmony_ci while ( ! feof( fConfig ) ) 332141cc406Sopenharmony_ci { 333141cc406Sopenharmony_ci if ( ! sanei_config_read ( configBuf, sizeof( configBuf ), fConfig ) ) break; 334141cc406Sopenharmony_ci 335141cc406Sopenharmony_ci /* skip whitespace */ 336141cc406Sopenharmony_ci pVal = sanei_config_skip_whitespace ( configBuf ); 337141cc406Sopenharmony_ci 338141cc406Sopenharmony_ci /* skip comments */ 339141cc406Sopenharmony_ci if ( *pVal == '#' ) continue; 340141cc406Sopenharmony_ci 341141cc406Sopenharmony_ci /* process named_scanner */ 342141cc406Sopenharmony_ci valLen = strlen( "named_scanner:" ); 343141cc406Sopenharmony_ci if ( ! strncmp( pVal, "extra_scanner:", valLen ) ){ 344141cc406Sopenharmony_ci 345141cc406Sopenharmony_ci pVal = sanei_config_skip_whitespace ( pVal + valLen ); 346141cc406Sopenharmony_ci 347141cc406Sopenharmony_ci pDevice = malloc (sizeof (struct DeviceRecord)); 348141cc406Sopenharmony_ci if (!pDevice) 349141cc406Sopenharmony_ci { 350141cc406Sopenharmony_ci DBG (1, "sane_get_devices: memory allocation failure\n"); 351141cc406Sopenharmony_ci break; 352141cc406Sopenharmony_ci } 353141cc406Sopenharmony_ci 354141cc406Sopenharmony_ci pDevice->m_pName = strdup (pVal); 355141cc406Sopenharmony_ci pDevice->m_device.vendor = "Dell"; 356141cc406Sopenharmony_ci pDevice->m_pModel = strdup( "1600n" ); 357141cc406Sopenharmony_ci pDevice->m_device.type = "multi-function peripheral"; 358141cc406Sopenharmony_ci 359141cc406Sopenharmony_ci pDevice->m_device.name = pDevice->m_pName; 360141cc406Sopenharmony_ci pDevice->m_device.model = pDevice->m_pModel; 361141cc406Sopenharmony_ci 362141cc406Sopenharmony_ci /* add to list */ 363141cc406Sopenharmony_ci gKnownDevices[iNextDevice++] = pDevice; 364141cc406Sopenharmony_ci 365141cc406Sopenharmony_ci continue; 366141cc406Sopenharmony_ci } /* if */ 367141cc406Sopenharmony_ci 368141cc406Sopenharmony_ci } /* while */ 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_ci /* Close the file */ 371141cc406Sopenharmony_ci fclose( fConfig ); 372141cc406Sopenharmony_ci } 373141cc406Sopenharmony_ci 374141cc406Sopenharmony_ci /* open UDP socket */ 375141cc406Sopenharmony_ci sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); 376141cc406Sopenharmony_ci if (sock == -1) 377141cc406Sopenharmony_ci { 378141cc406Sopenharmony_ci DBG (1, "Error creating socket\n"); 379141cc406Sopenharmony_ci ret = SANE_STATUS_NO_MEM; 380141cc406Sopenharmony_ci goto cleanup; 381141cc406Sopenharmony_ci } 382141cc406Sopenharmony_ci setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &optYes, sizeof (optYes)); 383141cc406Sopenharmony_ci 384141cc406Sopenharmony_ci /* prepare select mask */ 385141cc406Sopenharmony_ci FD_ZERO (&readFds); 386141cc406Sopenharmony_ci FD_SET (sock, &readFds); 387141cc406Sopenharmony_ci selTimeVal.tv_sec = 0; 388141cc406Sopenharmony_ci selTimeVal.tv_usec = gRegReplyWaitMs * 1000; 389141cc406Sopenharmony_ci 390141cc406Sopenharmony_ci /* init a packet */ 391141cc406Sopenharmony_ci InitPacket (&queryPacket, 0x01); 392141cc406Sopenharmony_ci 393141cc406Sopenharmony_ci /* add query */ 394141cc406Sopenharmony_ci ucVal = 0; 395141cc406Sopenharmony_ci AppendMessageToPacket (&queryPacket, 0x25, "std-scan-discovery-all", 396141cc406Sopenharmony_ci 0x02, &ucVal, sizeof (ucVal)); 397141cc406Sopenharmony_ci 398141cc406Sopenharmony_ci FinalisePacket (&queryPacket); 399141cc406Sopenharmony_ci 400141cc406Sopenharmony_ci DBG (10, "Sending:\n"); 401141cc406Sopenharmony_ci HexDump (10, queryPacket.m_pBuf, queryPacket.m_used); 402141cc406Sopenharmony_ci 403141cc406Sopenharmony_ci 404141cc406Sopenharmony_ci remoteAddr.sin_family = AF_INET; 405141cc406Sopenharmony_ci remoteAddr.sin_port = htons (gScannerPort); 406141cc406Sopenharmony_ci remoteAddr.sin_addr.s_addr = 0xFFFFFFFF; /* broadcast */ 407141cc406Sopenharmony_ci 408141cc406Sopenharmony_ci if (sendto (sock, queryPacket.m_pBuf, queryPacket.m_used, 0, 409141cc406Sopenharmony_ci (struct sockaddr *) &remoteAddr, sizeof (remoteAddr)) == -1) 410141cc406Sopenharmony_ci { 411141cc406Sopenharmony_ci DBG (1, "Error sending broadcast packet\n"); 412141cc406Sopenharmony_ci ret = SANE_STATUS_NO_MEM; 413141cc406Sopenharmony_ci goto cleanup; 414141cc406Sopenharmony_ci } 415141cc406Sopenharmony_ci 416141cc406Sopenharmony_ci /* process replies */ 417141cc406Sopenharmony_ci while (select (sock + 1, &readFds, NULL, NULL, &selTimeVal)) 418141cc406Sopenharmony_ci { 419141cc406Sopenharmony_ci 420141cc406Sopenharmony_ci /* break if we've got no more storage space in array */ 421141cc406Sopenharmony_ci if (iNextDevice >= MAX_SCANNERS) 422141cc406Sopenharmony_ci { 423141cc406Sopenharmony_ci DBG (1, "sane_get_devices: more than %d devices, ignoring\n", 424141cc406Sopenharmony_ci MAX_SCANNERS); 425141cc406Sopenharmony_ci break; 426141cc406Sopenharmony_ci } 427141cc406Sopenharmony_ci 428141cc406Sopenharmony_ci nread = read (sock, sockBuf, sizeof (sockBuf)); 429141cc406Sopenharmony_ci DBG (5, "Got a broadcast response, (%d bytes)\n", nread); 430141cc406Sopenharmony_ci 431141cc406Sopenharmony_ci if (nread <= 0) 432141cc406Sopenharmony_ci break; 433141cc406Sopenharmony_ci 434141cc406Sopenharmony_ci HexDump (10, sockBuf, nread); 435141cc406Sopenharmony_ci 436141cc406Sopenharmony_ci /* process response (skipping bad ones) */ 437141cc406Sopenharmony_ci if (!(pDevice = ProcessFindResponse (sockBuf, nread))) continue; 438141cc406Sopenharmony_ci 439141cc406Sopenharmony_ci /* add to list */ 440141cc406Sopenharmony_ci gKnownDevices[iNextDevice++] = pDevice; 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_ci } /* while */ 443141cc406Sopenharmony_ci 444141cc406Sopenharmony_ci /* report our finds */ 445141cc406Sopenharmony_ci *device_list = (const SANE_Device **) gKnownDevices; 446141cc406Sopenharmony_ci 447141cc406Sopenharmony_cicleanup: 448141cc406Sopenharmony_ci 449141cc406Sopenharmony_ci if (sock) 450141cc406Sopenharmony_ci close (sock); 451141cc406Sopenharmony_ci FreeComBuf (&queryPacket); 452141cc406Sopenharmony_ci 453141cc406Sopenharmony_ci return ret; 454141cc406Sopenharmony_ci 455141cc406Sopenharmony_ci} /* sane_get_devices */ 456141cc406Sopenharmony_ci 457141cc406Sopenharmony_ci/***********************************************************/ 458141cc406Sopenharmony_ci 459141cc406Sopenharmony_ciSANE_Status 460141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle) 461141cc406Sopenharmony_ci{ 462141cc406Sopenharmony_ci 463141cc406Sopenharmony_ci int iHandle = -1, i; 464141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 465141cc406Sopenharmony_ci struct hostent *pHostent; 466141cc406Sopenharmony_ci char *pDot; 467141cc406Sopenharmony_ci 468141cc406Sopenharmony_ci DBG( 5, "sane_open: %s\n", devicename ); 469141cc406Sopenharmony_ci 470141cc406Sopenharmony_ci /* find the next available scanner pointer in gOpenScanners */ 471141cc406Sopenharmony_ci for (i = 0; i < MAX_SCANNERS; ++i) 472141cc406Sopenharmony_ci { 473141cc406Sopenharmony_ci 474141cc406Sopenharmony_ci if (gOpenScanners[i]) continue; 475141cc406Sopenharmony_ci 476141cc406Sopenharmony_ci iHandle = i; 477141cc406Sopenharmony_ci break; 478141cc406Sopenharmony_ci 479141cc406Sopenharmony_ci } /* for */ 480141cc406Sopenharmony_ci if (iHandle == -1) 481141cc406Sopenharmony_ci { 482141cc406Sopenharmony_ci DBG (1, "sane_open: no space left in gOpenScanners array\n"); 483141cc406Sopenharmony_ci status = SANE_STATUS_NO_MEM; 484141cc406Sopenharmony_ci goto cleanup; 485141cc406Sopenharmony_ci } 486141cc406Sopenharmony_ci 487141cc406Sopenharmony_ci /* allocate some space */ 488141cc406Sopenharmony_ci if (!(gOpenScanners[iHandle] = malloc (sizeof (struct ScannerState)))) 489141cc406Sopenharmony_ci { 490141cc406Sopenharmony_ci status = SANE_STATUS_NO_MEM; 491141cc406Sopenharmony_ci goto cleanup; 492141cc406Sopenharmony_ci } 493141cc406Sopenharmony_ci 494141cc406Sopenharmony_ci /* init data */ 495141cc406Sopenharmony_ci memset (gOpenScanners[iHandle], 0, sizeof (struct ScannerState)); 496141cc406Sopenharmony_ci InitComBuf (&gOpenScanners[iHandle]->m_buf); 497141cc406Sopenharmony_ci InitComBuf (&gOpenScanners[iHandle]->m_imageData); 498141cc406Sopenharmony_ci InitComBuf (&gOpenScanners[iHandle]->m_pageInfo); 499141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_xres = ntohs (200); 500141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_yres = ntohs (200); 501141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_composition = ntohl (0x01); 502141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_brightness = 0x80; 503141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_compression = ntohl (0x08); 504141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_fileType = ntohl (0x02); 505141cc406Sopenharmony_ci 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_ci /* look up scanner name */ 508141cc406Sopenharmony_ci pHostent = gethostbyname (devicename); 509141cc406Sopenharmony_ci if ((!pHostent) || (!pHostent->h_addr_list)) 510141cc406Sopenharmony_ci { 511141cc406Sopenharmony_ci DBG (1, "sane_open: error looking up scanner name %s\n", devicename); 512141cc406Sopenharmony_ci status = SANE_STATUS_INVAL; 513141cc406Sopenharmony_ci goto cleanup; 514141cc406Sopenharmony_ci } 515141cc406Sopenharmony_ci 516141cc406Sopenharmony_ci /* open a UDP socket */ 517141cc406Sopenharmony_ci if (!(gOpenScanners[iHandle]->m_udpFd = 518141cc406Sopenharmony_ci socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP))) 519141cc406Sopenharmony_ci { 520141cc406Sopenharmony_ci DBG (1, "sane_open: error opening socket\n"); 521141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 522141cc406Sopenharmony_ci goto cleanup; 523141cc406Sopenharmony_ci } 524141cc406Sopenharmony_ci 525141cc406Sopenharmony_ci /* connect to the scanner */ 526141cc406Sopenharmony_ci memset (&gOpenScanners[iHandle]->m_sockAddr, 0, 527141cc406Sopenharmony_ci sizeof (gOpenScanners[iHandle]->m_sockAddr)); 528141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_sockAddr.sin_family = AF_INET; 529141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_sockAddr.sin_port = htons (gScannerPort); 530141cc406Sopenharmony_ci memcpy (&gOpenScanners[iHandle]->m_sockAddr.sin_addr, 531141cc406Sopenharmony_ci pHostent->h_addr_list[0], pHostent->h_length); 532141cc406Sopenharmony_ci if (connect (gOpenScanners[iHandle]->m_udpFd, 533141cc406Sopenharmony_ci (struct sockaddr *) &gOpenScanners[iHandle]->m_sockAddr, 534141cc406Sopenharmony_ci sizeof (gOpenScanners[iHandle]->m_sockAddr))) 535141cc406Sopenharmony_ci { 536141cc406Sopenharmony_ci DBG (1, "sane_open: error connecting to %s:%d\n", devicename, 537141cc406Sopenharmony_ci gScannerPort); 538141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 539141cc406Sopenharmony_ci goto cleanup; 540141cc406Sopenharmony_ci } 541141cc406Sopenharmony_ci 542141cc406Sopenharmony_ci /* set fallback registration name */ 543141cc406Sopenharmony_ci sprintf (gOpenScanners[iHandle]->m_regName, "Sane"); 544141cc406Sopenharmony_ci 545141cc406Sopenharmony_ci /* try to fill in hostname */ 546141cc406Sopenharmony_ci gethostname (gOpenScanners[iHandle]->m_regName, REG_NAME_SIZE); 547141cc406Sopenharmony_ci 548141cc406Sopenharmony_ci /* just in case... */ 549141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_regName[REG_NAME_SIZE - 1] = 0; 550141cc406Sopenharmony_ci 551141cc406Sopenharmony_ci /* chop off any domain (if any) */ 552141cc406Sopenharmony_ci if ((pDot = strchr (gOpenScanners[iHandle]->m_regName, '.'))) 553141cc406Sopenharmony_ci *pDot = 0; 554141cc406Sopenharmony_ci 555141cc406Sopenharmony_ci DBG (5, "sane_open: connected to %s:%d as %s\n", devicename, gScannerPort, 556141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_regName); 557141cc406Sopenharmony_ci 558141cc406Sopenharmony_ci 559141cc406Sopenharmony_ci /* set the handle */ 560141cc406Sopenharmony_ci *handle = (SANE_Handle) (unsigned long)iHandle; 561141cc406Sopenharmony_ci 562141cc406Sopenharmony_ci return status; 563141cc406Sopenharmony_ci 564141cc406Sopenharmony_cicleanup: 565141cc406Sopenharmony_ci 566141cc406Sopenharmony_ci if (iHandle != -1) 567141cc406Sopenharmony_ci FreeScannerState (iHandle); 568141cc406Sopenharmony_ci 569141cc406Sopenharmony_ci return status; 570141cc406Sopenharmony_ci 571141cc406Sopenharmony_ci} /* sane_open */ 572141cc406Sopenharmony_ci 573141cc406Sopenharmony_ci/***********************************************************/ 574141cc406Sopenharmony_ci 575141cc406Sopenharmony_civoid 576141cc406Sopenharmony_cisane_close (SANE_Handle handle) 577141cc406Sopenharmony_ci{ 578141cc406Sopenharmony_ci 579141cc406Sopenharmony_ci DBG( 5, "sane_close: %lx\n", (unsigned long)handle ); 580141cc406Sopenharmony_ci 581141cc406Sopenharmony_ci FreeScannerState ((unsigned long) handle); 582141cc406Sopenharmony_ci 583141cc406Sopenharmony_ci} /* sane_close */ 584141cc406Sopenharmony_ci 585141cc406Sopenharmony_ci/***********************************************************/ 586141cc406Sopenharmony_ci 587141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 588141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle __sane_unused__ handle, 589141cc406Sopenharmony_ci SANE_Int option) 590141cc406Sopenharmony_ci{ 591141cc406Sopenharmony_ci 592141cc406Sopenharmony_ci static SANE_Option_Descriptor numOptions = { 593141cc406Sopenharmony_ci "num_options", 594141cc406Sopenharmony_ci "Number of options", 595141cc406Sopenharmony_ci "Number of options", 596141cc406Sopenharmony_ci SANE_TYPE_INT, 597141cc406Sopenharmony_ci SANE_UNIT_NONE, 598141cc406Sopenharmony_ci 1, 599141cc406Sopenharmony_ci 0, 600141cc406Sopenharmony_ci 0, 601141cc406Sopenharmony_ci {0} 602141cc406Sopenharmony_ci }; 603141cc406Sopenharmony_ci 604141cc406Sopenharmony_ci if (option == 0) 605141cc406Sopenharmony_ci return &numOptions; 606141cc406Sopenharmony_ci else 607141cc406Sopenharmony_ci return NULL; 608141cc406Sopenharmony_ci 609141cc406Sopenharmony_ci} /* sane_get_option_descriptor */ 610141cc406Sopenharmony_ci 611141cc406Sopenharmony_ci/***********************************************************/ 612141cc406Sopenharmony_ci 613141cc406Sopenharmony_ciSANE_Status 614141cc406Sopenharmony_cisane_control_option (SANE_Handle __sane_unused__ handle, SANE_Int option, 615141cc406Sopenharmony_ci SANE_Action action, void *value, 616141cc406Sopenharmony_ci SANE_Int __sane_unused__ * info) 617141cc406Sopenharmony_ci{ 618141cc406Sopenharmony_ci 619141cc406Sopenharmony_ci static int numOptions = 1; 620141cc406Sopenharmony_ci 621141cc406Sopenharmony_ci if (action == SANE_ACTION_GET_VALUE && option == 0) 622141cc406Sopenharmony_ci *(int *) value = numOptions; 623141cc406Sopenharmony_ci 624141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 625141cc406Sopenharmony_ci 626141cc406Sopenharmony_ci} /* sane_control_option */ 627141cc406Sopenharmony_ci 628141cc406Sopenharmony_ci/***********************************************************/ 629141cc406Sopenharmony_ci 630141cc406Sopenharmony_ciSANE_Status 631141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 632141cc406Sopenharmony_ci{ 633141cc406Sopenharmony_ci int iHandle = (int) (unsigned long)handle; 634141cc406Sopenharmony_ci unsigned int width, height, imageSize; 635141cc406Sopenharmony_ci struct PageInfo pageInfo; 636141cc406Sopenharmony_ci 637141cc406Sopenharmony_ci if (!gOpenScanners[iHandle]) 638141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 639141cc406Sopenharmony_ci 640141cc406Sopenharmony_ci /* fetch page info */ 641141cc406Sopenharmony_ci memcpy( & pageInfo, gOpenScanners[iHandle]->m_pageInfo.m_pBuf, sizeof( pageInfo ) ); 642141cc406Sopenharmony_ci 643141cc406Sopenharmony_ci width = pageInfo.m_width; 644141cc406Sopenharmony_ci height = pageInfo.m_height; 645141cc406Sopenharmony_ci imageSize = width * height * 3; 646141cc406Sopenharmony_ci 647141cc406Sopenharmony_ci DBG( 5, "sane_get_parameters: bytes remaining on this page: %d, num pages: %d, size: %dx%d\n", 648141cc406Sopenharmony_ci pageInfo.m_bytesRemaining, 649141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_numPages, 650141cc406Sopenharmony_ci width, 651141cc406Sopenharmony_ci height ); 652141cc406Sopenharmony_ci 653141cc406Sopenharmony_ci DBG (5, 654141cc406Sopenharmony_ci "sane_get_parameters: handle %x: bytes outstanding: %lu, image size: %d\n", 655141cc406Sopenharmony_ci iHandle, (unsigned long)gOpenScanners[iHandle]->m_imageData.m_used, imageSize); 656141cc406Sopenharmony_ci 657141cc406Sopenharmony_ci /* check for enough data */ 658141cc406Sopenharmony_ci /* 659141cc406Sopenharmony_ci if (gOpenScanners[iHandle]->m_imageData.m_used < imageSize) 660141cc406Sopenharmony_ci { 661141cc406Sopenharmony_ci DBG (1, "sane_get_parameters: handle %d: not enough data: %d < %d\n", 662141cc406Sopenharmony_ci iHandle, gOpenScanners[iHandle]->m_imageData.m_used, imageSize); 663141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 664141cc406Sopenharmony_ci } 665141cc406Sopenharmony_ci */ 666141cc406Sopenharmony_ci 667141cc406Sopenharmony_ci 668141cc406Sopenharmony_ci params->format = SANE_FRAME_RGB; 669141cc406Sopenharmony_ci params->last_frame = SANE_TRUE; 670141cc406Sopenharmony_ci params->lines = height; 671141cc406Sopenharmony_ci params->depth = 8; 672141cc406Sopenharmony_ci params->pixels_per_line = width; 673141cc406Sopenharmony_ci params->bytes_per_line = width * 3; 674141cc406Sopenharmony_ci 675141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 676141cc406Sopenharmony_ci 677141cc406Sopenharmony_ci} /* sane_get_parameters */ 678141cc406Sopenharmony_ci 679141cc406Sopenharmony_ci/***********************************************************/ 680141cc406Sopenharmony_ci 681141cc406Sopenharmony_ciSANE_Status 682141cc406Sopenharmony_cisane_start (SANE_Handle handle) 683141cc406Sopenharmony_ci{ 684141cc406Sopenharmony_ci 685141cc406Sopenharmony_ci SANE_Status status = SANE_STATUS_GOOD; 686141cc406Sopenharmony_ci struct ComBuf buf; 687141cc406Sopenharmony_ci unsigned char sockBuf[SOCK_BUF_SIZE]; 688141cc406Sopenharmony_ci int iHandle, nread; 689141cc406Sopenharmony_ci int errorCheck = 0; 690141cc406Sopenharmony_ci struct sockaddr_in myAddr; 691141cc406Sopenharmony_ci socklen_t addrSize; 692141cc406Sopenharmony_ci fd_set readFds; 693141cc406Sopenharmony_ci struct timeval selTimeVal; 694141cc406Sopenharmony_ci 695141cc406Sopenharmony_ci iHandle = (int) (unsigned long)handle; 696141cc406Sopenharmony_ci 697141cc406Sopenharmony_ci DBG( 5, "sane_start: %x\n", iHandle ); 698141cc406Sopenharmony_ci 699141cc406Sopenharmony_ci /* fetch and check scanner index */ 700141cc406Sopenharmony_ci if (!ValidScannerNumber (iHandle)) 701141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 702141cc406Sopenharmony_ci 703141cc406Sopenharmony_ci /* check if we still have outstanding pages of data on this handle */ 704141cc406Sopenharmony_ci if (gOpenScanners[iHandle]->m_imageData.m_used){ 705141cc406Sopenharmony_ci 706141cc406Sopenharmony_ci /* remove empty page */ 707141cc406Sopenharmony_ci PopFromComBuf ( & gOpenScanners[iHandle]->m_pageInfo, sizeof( struct PageInfo ) ); 708141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 709141cc406Sopenharmony_ci 710141cc406Sopenharmony_ci } 711141cc406Sopenharmony_ci 712141cc406Sopenharmony_ci /* determine local IP address */ 713141cc406Sopenharmony_ci addrSize = sizeof (myAddr); 714141cc406Sopenharmony_ci if (getsockname (gOpenScanners[iHandle]->m_udpFd, (struct sockaddr *) &myAddr, &addrSize)) 715141cc406Sopenharmony_ci { 716141cc406Sopenharmony_ci DBG (1, "sane_start: Error getting own IP address\n"); 717141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 718141cc406Sopenharmony_ci } 719141cc406Sopenharmony_ci 720141cc406Sopenharmony_ci /* init a buffer for our registration message */ 721141cc406Sopenharmony_ci errorCheck |= InitComBuf (&buf); 722141cc406Sopenharmony_ci 723141cc406Sopenharmony_ci /* build packet */ 724141cc406Sopenharmony_ci errorCheck |= InitPacket (&buf, 1); 725141cc406Sopenharmony_ci errorCheck |= 726141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, "std-scan-subscribe-user-name", 0x0b, 727141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_regName, 728141cc406Sopenharmony_ci strlen (gOpenScanners[iHandle]->m_regName)); 729141cc406Sopenharmony_ci errorCheck |= 730141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, "std-scan-subscribe-ip-address", 0x0a, 731141cc406Sopenharmony_ci &myAddr.sin_addr, 4); 732141cc406Sopenharmony_ci FinalisePacket (&buf); 733141cc406Sopenharmony_ci 734141cc406Sopenharmony_ci /* check nothing went wrong along the way */ 735141cc406Sopenharmony_ci if (errorCheck) 736141cc406Sopenharmony_ci { 737141cc406Sopenharmony_ci status = SANE_STATUS_NO_MEM; 738141cc406Sopenharmony_ci goto cleanup; 739141cc406Sopenharmony_ci } 740141cc406Sopenharmony_ci 741141cc406Sopenharmony_ci /* send the packet */ 742141cc406Sopenharmony_ci send (gOpenScanners[iHandle]->m_udpFd, buf.m_pBuf, buf.m_used, 0); 743141cc406Sopenharmony_ci 744141cc406Sopenharmony_ci 745141cc406Sopenharmony_ci /* loop until done */ 746141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_bFinish = 0; 747141cc406Sopenharmony_ci while (!gOpenScanners[iHandle]->m_bFinish) 748141cc406Sopenharmony_ci { 749141cc406Sopenharmony_ci 750141cc406Sopenharmony_ci /* prepare select mask */ 751141cc406Sopenharmony_ci FD_ZERO (&readFds); 752141cc406Sopenharmony_ci FD_SET (gOpenScanners[iHandle]->m_udpFd, &readFds); 753141cc406Sopenharmony_ci selTimeVal.tv_sec = 1; 754141cc406Sopenharmony_ci selTimeVal.tv_usec = 0; 755141cc406Sopenharmony_ci 756141cc406Sopenharmony_ci 757141cc406Sopenharmony_ci 758141cc406Sopenharmony_ci DBG (5, "sane_start: waiting for scan signal\n"); 759141cc406Sopenharmony_ci 760141cc406Sopenharmony_ci /* wait again if nothing received */ 761141cc406Sopenharmony_ci if (!select (gOpenScanners[iHandle]->m_udpFd + 1, 762141cc406Sopenharmony_ci &readFds, NULL, NULL, &selTimeVal)) 763141cc406Sopenharmony_ci continue; 764141cc406Sopenharmony_ci 765141cc406Sopenharmony_ci /* read from socket */ 766141cc406Sopenharmony_ci nread = 767141cc406Sopenharmony_ci read (gOpenScanners[iHandle]->m_udpFd, sockBuf, sizeof (sockBuf)); 768141cc406Sopenharmony_ci 769141cc406Sopenharmony_ci if (nread <= 0) 770141cc406Sopenharmony_ci { 771141cc406Sopenharmony_ci DBG (1, "sane_start: read returned %d\n", nread); 772141cc406Sopenharmony_ci break; 773141cc406Sopenharmony_ci } 774141cc406Sopenharmony_ci 775141cc406Sopenharmony_ci /* process the response */ 776141cc406Sopenharmony_ci if (ProcessUdpResponse (sockBuf, nread, gOpenScanners[iHandle])) 777141cc406Sopenharmony_ci { 778141cc406Sopenharmony_ci status = SANE_STATUS_IO_ERROR; 779141cc406Sopenharmony_ci goto cleanup; 780141cc406Sopenharmony_ci } 781141cc406Sopenharmony_ci 782141cc406Sopenharmony_ci } /* while */ 783141cc406Sopenharmony_ci 784141cc406Sopenharmony_ci /* check whether we were cancelled */ 785141cc406Sopenharmony_ci if ( gOpenScanners[iHandle]->m_bCancelled ) status = SANE_STATUS_CANCELLED; 786141cc406Sopenharmony_ci 787141cc406Sopenharmony_cicleanup: 788141cc406Sopenharmony_ci 789141cc406Sopenharmony_ci FreeComBuf (&buf); 790141cc406Sopenharmony_ci 791141cc406Sopenharmony_ci return status; 792141cc406Sopenharmony_ci 793141cc406Sopenharmony_ci} /* sane_start */ 794141cc406Sopenharmony_ci 795141cc406Sopenharmony_ci/***********************************************************/ 796141cc406Sopenharmony_ci 797141cc406Sopenharmony_ciSANE_Status 798141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * data, 799141cc406Sopenharmony_ci SANE_Int max_length, SANE_Int * length) 800141cc406Sopenharmony_ci{ 801141cc406Sopenharmony_ci 802141cc406Sopenharmony_ci int iHandle = (int) (unsigned long)handle; 803141cc406Sopenharmony_ci int dataSize; 804141cc406Sopenharmony_ci struct PageInfo pageInfo; 805141cc406Sopenharmony_ci 806141cc406Sopenharmony_ci DBG( 5, "sane_read: %x (max_length=%d)\n", iHandle, max_length ); 807141cc406Sopenharmony_ci 808141cc406Sopenharmony_ci *length = 0; 809141cc406Sopenharmony_ci 810141cc406Sopenharmony_ci if (!gOpenScanners[iHandle]) 811141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 812141cc406Sopenharmony_ci 813141cc406Sopenharmony_ci /* check for end of data (no further pages) */ 814141cc406Sopenharmony_ci if ( ( ! gOpenScanners[iHandle]->m_imageData.m_used ) 815141cc406Sopenharmony_ci || ( ! gOpenScanners[iHandle]->m_numPages ) ) 816141cc406Sopenharmony_ci { 817141cc406Sopenharmony_ci /* remove empty page if there are no more cached pages */ 818141cc406Sopenharmony_ci PopFromComBuf ( & gOpenScanners[iHandle]->m_pageInfo, sizeof( struct PageInfo ) ); 819141cc406Sopenharmony_ci 820141cc406Sopenharmony_ci return SANE_STATUS_EOF; 821141cc406Sopenharmony_ci } 822141cc406Sopenharmony_ci 823141cc406Sopenharmony_ci /* fetch page info */ 824141cc406Sopenharmony_ci memcpy( & pageInfo, gOpenScanners[iHandle]->m_pageInfo.m_pBuf, sizeof( pageInfo ) ); 825141cc406Sopenharmony_ci 826141cc406Sopenharmony_ci /* check for end of page data (we still have further cached pages) */ 827141cc406Sopenharmony_ci if ( pageInfo.m_bytesRemaining < 1 ) return SANE_STATUS_EOF; 828141cc406Sopenharmony_ci 829141cc406Sopenharmony_ci /* send the remainder of the current image */ 830141cc406Sopenharmony_ci dataSize = pageInfo.m_bytesRemaining; 831141cc406Sopenharmony_ci 832141cc406Sopenharmony_ci /* unless there's not enough room in the output buffer */ 833141cc406Sopenharmony_ci if (dataSize > max_length) 834141cc406Sopenharmony_ci dataSize = max_length; 835141cc406Sopenharmony_ci 836141cc406Sopenharmony_ci /* update the data sent counters */ 837141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_bytesRead += dataSize; 838141cc406Sopenharmony_ci pageInfo.m_bytesRemaining -= dataSize; 839141cc406Sopenharmony_ci 840141cc406Sopenharmony_ci /* update counter */ 841141cc406Sopenharmony_ci memcpy( gOpenScanners[iHandle]->m_pageInfo.m_pBuf, & pageInfo, sizeof( pageInfo ) ); 842141cc406Sopenharmony_ci 843141cc406Sopenharmony_ci /* check for end of page */ 844141cc406Sopenharmony_ci if ( pageInfo.m_bytesRemaining < 1 ){ 845141cc406Sopenharmony_ci 846141cc406Sopenharmony_ci /* yes, so remove page info */ 847141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_numPages--; 848141cc406Sopenharmony_ci 849141cc406Sopenharmony_ci } /* if */ 850141cc406Sopenharmony_ci 851141cc406Sopenharmony_ci DBG (5, 852141cc406Sopenharmony_ci "sane_read: sending %d bytes, image total %d, %d page bytes remaining, %lu total remaining, image: %dx%d\n", 853141cc406Sopenharmony_ci dataSize, gOpenScanners[iHandle]->m_bytesRead, pageInfo.m_bytesRemaining , 854141cc406Sopenharmony_ci (unsigned long)(gOpenScanners[iHandle]->m_imageData.m_used - dataSize), 855141cc406Sopenharmony_ci pageInfo.m_width, 856141cc406Sopenharmony_ci pageInfo.m_height); 857141cc406Sopenharmony_ci 858141cc406Sopenharmony_ci /* copy the data */ 859141cc406Sopenharmony_ci memcpy (data, gOpenScanners[iHandle]->m_imageData.m_pBuf, dataSize); 860141cc406Sopenharmony_ci if (PopFromComBuf (&gOpenScanners[iHandle]->m_imageData, dataSize)) 861141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 862141cc406Sopenharmony_ci 863141cc406Sopenharmony_ci *length = dataSize; 864141cc406Sopenharmony_ci 865141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 866141cc406Sopenharmony_ci 867141cc406Sopenharmony_ci} /* sane_read */ 868141cc406Sopenharmony_ci 869141cc406Sopenharmony_ci/***********************************************************/ 870141cc406Sopenharmony_ci 871141cc406Sopenharmony_civoid 872141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 873141cc406Sopenharmony_ci{ 874141cc406Sopenharmony_ci int iHandle = (int) (unsigned long)handle; 875141cc406Sopenharmony_ci 876141cc406Sopenharmony_ci DBG( 5, "sane_cancel: %x\n", iHandle ); 877141cc406Sopenharmony_ci 878141cc406Sopenharmony_ci /* signal that bad things are afoot */ 879141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_bFinish = 1; 880141cc406Sopenharmony_ci gOpenScanners[iHandle]->m_bCancelled = 1; 881141cc406Sopenharmony_ci 882141cc406Sopenharmony_ci} /* sane_cancel */ 883141cc406Sopenharmony_ci 884141cc406Sopenharmony_ci/***********************************************************/ 885141cc406Sopenharmony_ci 886141cc406Sopenharmony_ciSANE_Status 887141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle __sane_unused__ handle, 888141cc406Sopenharmony_ci SANE_Bool __sane_unused__ non_blocking) 889141cc406Sopenharmony_ci{ 890141cc406Sopenharmony_ci 891141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 892141cc406Sopenharmony_ci 893141cc406Sopenharmony_ci} /* sane_set_io_mode */ 894141cc406Sopenharmony_ci 895141cc406Sopenharmony_ci/***********************************************************/ 896141cc406Sopenharmony_ci 897141cc406Sopenharmony_ciSANE_Status 898141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle __sane_unused__ handle, 899141cc406Sopenharmony_ci SANE_Int __sane_unused__ * fd) 900141cc406Sopenharmony_ci{ 901141cc406Sopenharmony_ci 902141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 903141cc406Sopenharmony_ci 904141cc406Sopenharmony_ci} /* sane_get_select_fd */ 905141cc406Sopenharmony_ci 906141cc406Sopenharmony_ci/***********************************************************/ 907141cc406Sopenharmony_ci 908141cc406Sopenharmony_ci/* Clears the contents of gKnownDevices and zeros it */ 909141cc406Sopenharmony_civoid 910141cc406Sopenharmony_ciClearKnownDevices () 911141cc406Sopenharmony_ci{ 912141cc406Sopenharmony_ci 913141cc406Sopenharmony_ci int i; 914141cc406Sopenharmony_ci 915141cc406Sopenharmony_ci for (i = 0; i < MAX_SCANNERS; ++i) 916141cc406Sopenharmony_ci { 917141cc406Sopenharmony_ci 918141cc406Sopenharmony_ci if (gKnownDevices[i]) 919141cc406Sopenharmony_ci { 920141cc406Sopenharmony_ci if (gKnownDevices[i]->m_pName) free ( gKnownDevices[i]->m_pName ); 921141cc406Sopenharmony_ci if (gKnownDevices[i]->m_pModel) free ( gKnownDevices[i]->m_pModel ); 922141cc406Sopenharmony_ci free ( gKnownDevices[i] ); 923141cc406Sopenharmony_ci } 924141cc406Sopenharmony_ci gKnownDevices[i] = NULL; 925141cc406Sopenharmony_ci 926141cc406Sopenharmony_ci } 927141cc406Sopenharmony_ci 928141cc406Sopenharmony_ci} /* ClearKnownDevices */ 929141cc406Sopenharmony_ci 930141cc406Sopenharmony_ci/***********************************************************/ 931141cc406Sopenharmony_ci 932141cc406Sopenharmony_ci/* print hex buffer to debug output */ 933141cc406Sopenharmony_civoid 934141cc406Sopenharmony_ciHexDump (int debugLevel, const unsigned char *buf, size_t bufSize) 935141cc406Sopenharmony_ci{ 936141cc406Sopenharmony_ci 937141cc406Sopenharmony_ci unsigned int i, j; 938141cc406Sopenharmony_ci size_t lineBufFree; 939141cc406Sopenharmony_ci 940141cc406Sopenharmony_ci char itemBuf[16] = { 0 }, lineBuf[256] = { 0 }; 941141cc406Sopenharmony_ci 942141cc406Sopenharmony_ci if (DBG_LEVEL < debugLevel) 943141cc406Sopenharmony_ci return; 944141cc406Sopenharmony_ci 945141cc406Sopenharmony_ci for (i = 0; i < bufSize; ++i) 946141cc406Sopenharmony_ci { 947141cc406Sopenharmony_ci 948141cc406Sopenharmony_ci if (!(i % 16)) 949141cc406Sopenharmony_ci sprintf (lineBuf, "%p: ", (void *) &buf[i]); 950141cc406Sopenharmony_ci 951141cc406Sopenharmony_ci sprintf (itemBuf, "%02x ", (const unsigned int) buf[i]); 952141cc406Sopenharmony_ci 953141cc406Sopenharmony_ci lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1; 954141cc406Sopenharmony_ci strncat (lineBuf, itemBuf, lineBufFree); 955141cc406Sopenharmony_ci 956141cc406Sopenharmony_ci if ((i + 1) % 16) 957141cc406Sopenharmony_ci continue; 958141cc406Sopenharmony_ci 959141cc406Sopenharmony_ci /* print string equivalent */ 960141cc406Sopenharmony_ci for (j = i - 15; j <= i; ++j) 961141cc406Sopenharmony_ci { 962141cc406Sopenharmony_ci 963141cc406Sopenharmony_ci if ((buf[j] >= 0x20) && (!(buf[j] & 0x80))) 964141cc406Sopenharmony_ci { 965141cc406Sopenharmony_ci sprintf (itemBuf, "%c", buf[j]); 966141cc406Sopenharmony_ci } 967141cc406Sopenharmony_ci else 968141cc406Sopenharmony_ci { 969141cc406Sopenharmony_ci sprintf (itemBuf, "."); 970141cc406Sopenharmony_ci } 971141cc406Sopenharmony_ci lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1; 972141cc406Sopenharmony_ci strncat (lineBuf, itemBuf, lineBufFree); 973141cc406Sopenharmony_ci 974141cc406Sopenharmony_ci } /* for j */ 975141cc406Sopenharmony_ci 976141cc406Sopenharmony_ci DBG (debugLevel, "%s\n", lineBuf); 977141cc406Sopenharmony_ci lineBuf[0] = 0; 978141cc406Sopenharmony_ci 979141cc406Sopenharmony_ci } /* for i */ 980141cc406Sopenharmony_ci 981141cc406Sopenharmony_ci if (i % 16) 982141cc406Sopenharmony_ci { 983141cc406Sopenharmony_ci 984141cc406Sopenharmony_ci for (j = (i % 16); j < 16; ++j) 985141cc406Sopenharmony_ci { 986141cc406Sopenharmony_ci lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1; 987141cc406Sopenharmony_ci strncat (lineBuf, " ", lineBufFree); 988141cc406Sopenharmony_ci } 989141cc406Sopenharmony_ci for (j = 1 + i - ((i + 1) % 16); j < i; ++j) 990141cc406Sopenharmony_ci { 991141cc406Sopenharmony_ci if ((buf[j] >= 0x20) && (!(buf[j] & 0x80))) 992141cc406Sopenharmony_ci { 993141cc406Sopenharmony_ci sprintf (itemBuf, "%c", buf[j]); 994141cc406Sopenharmony_ci } 995141cc406Sopenharmony_ci else 996141cc406Sopenharmony_ci { 997141cc406Sopenharmony_ci strcpy (itemBuf, "."); 998141cc406Sopenharmony_ci } 999141cc406Sopenharmony_ci lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1; 1000141cc406Sopenharmony_ci strncat (lineBuf, itemBuf, lineBufFree); 1001141cc406Sopenharmony_ci } 1002141cc406Sopenharmony_ci DBG (debugLevel, "%s\n", lineBuf); 1003141cc406Sopenharmony_ci } 1004141cc406Sopenharmony_ci} /* HexDump */ 1005141cc406Sopenharmony_ci 1006141cc406Sopenharmony_ci/***********************************************************/ 1007141cc406Sopenharmony_ci 1008141cc406Sopenharmony_ci/* initialise a ComBuf struct 1009141cc406Sopenharmony_ci \return 0 on success, >0 on failure 1010141cc406Sopenharmony_ci*/ 1011141cc406Sopenharmony_ciint 1012141cc406Sopenharmony_ciInitComBuf (struct ComBuf *pBuf) 1013141cc406Sopenharmony_ci{ 1014141cc406Sopenharmony_ci 1015141cc406Sopenharmony_ci memset (pBuf, 0, sizeof (struct ComBuf)); 1016141cc406Sopenharmony_ci 1017141cc406Sopenharmony_ci pBuf->m_pBuf = malloc (INITIAL_COM_BUF_SIZE); 1018141cc406Sopenharmony_ci if (!pBuf->m_pBuf) 1019141cc406Sopenharmony_ci return 1; 1020141cc406Sopenharmony_ci 1021141cc406Sopenharmony_ci pBuf->m_capacity = INITIAL_COM_BUF_SIZE; 1022141cc406Sopenharmony_ci pBuf->m_used = 0; 1023141cc406Sopenharmony_ci 1024141cc406Sopenharmony_ci return 0; 1025141cc406Sopenharmony_ci 1026141cc406Sopenharmony_ci} /* InitComBuf */ 1027141cc406Sopenharmony_ci 1028141cc406Sopenharmony_ci/***********************************************************/ 1029141cc406Sopenharmony_ci 1030141cc406Sopenharmony_ci/* free a ComBuf struct */ 1031141cc406Sopenharmony_civoid 1032141cc406Sopenharmony_ciFreeComBuf (struct ComBuf *pBuf) 1033141cc406Sopenharmony_ci{ 1034141cc406Sopenharmony_ci 1035141cc406Sopenharmony_ci if (pBuf->m_pBuf) 1036141cc406Sopenharmony_ci free (pBuf->m_pBuf); 1037141cc406Sopenharmony_ci memset (pBuf, 0, sizeof (struct ComBuf)); 1038141cc406Sopenharmony_ci 1039141cc406Sopenharmony_ci} /* FreeComBuf */ 1040141cc406Sopenharmony_ci 1041141cc406Sopenharmony_ci/***********************************************************/ 1042141cc406Sopenharmony_ci 1043141cc406Sopenharmony_ci/* add data to a ComBuf struct 1044141cc406Sopenharmony_ci \return 0 on success, >0 on failure 1045141cc406Sopenharmony_ci \note If pData is NULL then buffer size will be increased but no copying will take place 1046141cc406Sopenharmony_ci \note In case of failure pBuf will be released using FreeComBuf 1047141cc406Sopenharmony_ci*/ 1048141cc406Sopenharmony_ciint 1049141cc406Sopenharmony_ciAppendToComBuf (struct ComBuf *pBuf, const unsigned char *pData, 1050141cc406Sopenharmony_ci size_t datSize) 1051141cc406Sopenharmony_ci{ 1052141cc406Sopenharmony_ci 1053141cc406Sopenharmony_ci size_t newSize; 1054141cc406Sopenharmony_ci 1055141cc406Sopenharmony_ci /* check we have enough space */ 1056141cc406Sopenharmony_ci if (pBuf->m_used + datSize > pBuf->m_capacity) 1057141cc406Sopenharmony_ci { 1058141cc406Sopenharmony_ci /* nope - allocate some more */ 1059141cc406Sopenharmony_ci newSize = pBuf->m_used + datSize + INITIAL_COM_BUF_SIZE; 1060141cc406Sopenharmony_ci pBuf->m_pBuf = realloc (pBuf->m_pBuf, newSize); 1061141cc406Sopenharmony_ci if (!pBuf->m_pBuf) 1062141cc406Sopenharmony_ci { 1063141cc406Sopenharmony_ci DBG (1, "AppendToComBuf: memory allocation error"); 1064141cc406Sopenharmony_ci FreeComBuf (pBuf); 1065141cc406Sopenharmony_ci return (1); 1066141cc406Sopenharmony_ci } 1067141cc406Sopenharmony_ci pBuf->m_capacity = newSize; 1068141cc406Sopenharmony_ci } /* if */ 1069141cc406Sopenharmony_ci 1070141cc406Sopenharmony_ci /* add data */ 1071141cc406Sopenharmony_ci if (pData) 1072141cc406Sopenharmony_ci memcpy (pBuf->m_pBuf + pBuf->m_used, pData, datSize); 1073141cc406Sopenharmony_ci pBuf->m_used += datSize; 1074141cc406Sopenharmony_ci 1075141cc406Sopenharmony_ci return 0; 1076141cc406Sopenharmony_ci 1077141cc406Sopenharmony_ci} /* AppendToComBuf */ 1078141cc406Sopenharmony_ci 1079141cc406Sopenharmony_ci/***********************************************************/ 1080141cc406Sopenharmony_ci 1081141cc406Sopenharmony_ci/* append message to a packet 1082141cc406Sopenharmony_ci \return 0 if ok, 1 if bad */ 1083141cc406Sopenharmony_ciint 1084141cc406Sopenharmony_ciAppendMessageToPacket (struct ComBuf *pBuf, /* packet to which to append */ 1085141cc406Sopenharmony_ci char messageType, /* type of message */ 1086141cc406Sopenharmony_ci char *messageName, /* name of message */ 1087141cc406Sopenharmony_ci char valueType, /* type of value */ 1088141cc406Sopenharmony_ci void *pValue, /* pointer to value */ 1089141cc406Sopenharmony_ci size_t valueLen /* length of value (bytes) */ 1090141cc406Sopenharmony_ci ) 1091141cc406Sopenharmony_ci{ 1092141cc406Sopenharmony_ci 1093141cc406Sopenharmony_ci unsigned short slen; 1094141cc406Sopenharmony_ci 1095141cc406Sopenharmony_ci /* message type */ 1096141cc406Sopenharmony_ci AppendToComBuf (pBuf, (void *) &messageType, 1); 1097141cc406Sopenharmony_ci 1098141cc406Sopenharmony_ci /* message length */ 1099141cc406Sopenharmony_ci slen = htons (strlen (messageName)); 1100141cc406Sopenharmony_ci AppendToComBuf (pBuf, (void *) &slen, 2); 1101141cc406Sopenharmony_ci 1102141cc406Sopenharmony_ci /* and name */ 1103141cc406Sopenharmony_ci AppendToComBuf (pBuf, (void *) messageName, strlen (messageName)); 1104141cc406Sopenharmony_ci 1105141cc406Sopenharmony_ci /* and value type */ 1106141cc406Sopenharmony_ci AppendToComBuf (pBuf, (void *) &valueType, 1); 1107141cc406Sopenharmony_ci 1108141cc406Sopenharmony_ci /* value length */ 1109141cc406Sopenharmony_ci slen = htons (valueLen); 1110141cc406Sopenharmony_ci AppendToComBuf (pBuf, (void *) &slen, 2); 1111141cc406Sopenharmony_ci 1112141cc406Sopenharmony_ci /* and value */ 1113141cc406Sopenharmony_ci return (AppendToComBuf (pBuf, (void *) pValue, valueLen)); 1114141cc406Sopenharmony_ci 1115141cc406Sopenharmony_ci} /* AppendMessageToPacket */ 1116141cc406Sopenharmony_ci 1117141cc406Sopenharmony_ci/***********************************************************/ 1118141cc406Sopenharmony_ci 1119141cc406Sopenharmony_ci/* Initialise a packet 1120141cc406Sopenharmony_ci \param pBuf : An initialise ComBuf 1121141cc406Sopenharmony_ci \param type : either 0x01 ("normal" ) or 0x02 ("reply" ) 1122141cc406Sopenharmony_ci \return 0 on success, >0 otherwise 1123141cc406Sopenharmony_ci*/ 1124141cc406Sopenharmony_ciint 1125141cc406Sopenharmony_ciInitPacket (struct ComBuf *pBuf, char type) 1126141cc406Sopenharmony_ci{ 1127141cc406Sopenharmony_ci 1128141cc406Sopenharmony_ci char header[8] = { 2, 0, 0, 2, 0, 0, 0, 0 }; 1129141cc406Sopenharmony_ci 1130141cc406Sopenharmony_ci header[2] = type; 1131141cc406Sopenharmony_ci 1132141cc406Sopenharmony_ci /* reset size */ 1133141cc406Sopenharmony_ci pBuf->m_used = 0; 1134141cc406Sopenharmony_ci 1135141cc406Sopenharmony_ci /* add header */ 1136141cc406Sopenharmony_ci return (AppendToComBuf (pBuf, (void *) &header, 8)); 1137141cc406Sopenharmony_ci 1138141cc406Sopenharmony_ci} /* InitPacket */ 1139141cc406Sopenharmony_ci 1140141cc406Sopenharmony_ci/***********************************************************/ 1141141cc406Sopenharmony_ci 1142141cc406Sopenharmony_ci/* write length data to packet header 1143141cc406Sopenharmony_ci*/ 1144141cc406Sopenharmony_civoid 1145141cc406Sopenharmony_ciFinalisePacket (struct ComBuf *pBuf) 1146141cc406Sopenharmony_ci{ 1147141cc406Sopenharmony_ci 1148141cc406Sopenharmony_ci /* sanity check */ 1149141cc406Sopenharmony_ci if (pBuf->m_used < 8) 1150141cc406Sopenharmony_ci return; 1151141cc406Sopenharmony_ci 1152141cc406Sopenharmony_ci /* set the size */ 1153141cc406Sopenharmony_ci *((unsigned short *) (pBuf->m_pBuf + 6)) = htons (pBuf->m_used - 8); 1154141cc406Sopenharmony_ci 1155141cc406Sopenharmony_ci DBG (20, "FinalisePacket: outgoing packet:\n"); 1156141cc406Sopenharmony_ci HexDump (20, pBuf->m_pBuf, pBuf->m_used); 1157141cc406Sopenharmony_ci 1158141cc406Sopenharmony_ci} /* FinalisePacket */ 1159141cc406Sopenharmony_ci 1160141cc406Sopenharmony_ci/***********************************************************/ 1161141cc406Sopenharmony_ci 1162141cc406Sopenharmony_ci/* \return 1 if message is complete, 0 otherwise */ 1163141cc406Sopenharmony_ciint 1164141cc406Sopenharmony_ciMessageIsComplete (unsigned char *pData, size_t size) 1165141cc406Sopenharmony_ci{ 1166141cc406Sopenharmony_ci unsigned short dataSize; 1167141cc406Sopenharmony_ci 1168141cc406Sopenharmony_ci /* sanity check */ 1169141cc406Sopenharmony_ci if (size < 8) 1170141cc406Sopenharmony_ci return 0; 1171141cc406Sopenharmony_ci 1172141cc406Sopenharmony_ci /* :NOTE: we can't just cast to a short as data may not be aligned */ 1173141cc406Sopenharmony_ci dataSize = (((unsigned short) pData[6]) << 8) | pData[7]; 1174141cc406Sopenharmony_ci 1175141cc406Sopenharmony_ci DBG (20, "MessageIsComplete: data size = %d\n", dataSize); 1176141cc406Sopenharmony_ci 1177141cc406Sopenharmony_ci if (size >= (size_t) (dataSize + 8)) 1178141cc406Sopenharmony_ci return 1; 1179141cc406Sopenharmony_ci else 1180141cc406Sopenharmony_ci return 0; 1181141cc406Sopenharmony_ci 1182141cc406Sopenharmony_ci} /* MessageIsComplete */ 1183141cc406Sopenharmony_ci 1184141cc406Sopenharmony_ci/***********************************************************/ 1185141cc406Sopenharmony_ci 1186141cc406Sopenharmony_ci/* process a registration broadcast response 1187141cc406Sopenharmony_ci \return struct DeviceRecord pointer on success (caller frees), NULL on failure 1188141cc406Sopenharmony_ci*/ 1189141cc406Sopenharmony_cistruct DeviceRecord * 1190141cc406Sopenharmony_ciProcessFindResponse (unsigned char *pData, size_t size) 1191141cc406Sopenharmony_ci{ 1192141cc406Sopenharmony_ci 1193141cc406Sopenharmony_ci struct DeviceRecord *pDevice = NULL; 1194141cc406Sopenharmony_ci unsigned short messageSize, nameSize, valueSize; 1195141cc406Sopenharmony_ci unsigned char *pItem, *pEnd, *pValue; 1196141cc406Sopenharmony_ci char printerName[256] = { 0 }; 1197141cc406Sopenharmony_ci char printerModel[256] = "1600n"; 1198141cc406Sopenharmony_ci char *pModel, *pName; 1199141cc406Sopenharmony_ci 1200141cc406Sopenharmony_ci 1201141cc406Sopenharmony_ci DBG (10, "ProcessFindResponse: processing %lu bytes, pData=%p\n", 1202141cc406Sopenharmony_ci (unsigned long) size, (void *) pData); 1203141cc406Sopenharmony_ci 1204141cc406Sopenharmony_ci /* check we have a complete packet */ 1205141cc406Sopenharmony_ci if (!MessageIsComplete (pData, size)) 1206141cc406Sopenharmony_ci { 1207141cc406Sopenharmony_ci DBG (1, "ProcessFindResponse: Ignoring incomplete packet\n"); 1208141cc406Sopenharmony_ci return NULL; 1209141cc406Sopenharmony_ci } 1210141cc406Sopenharmony_ci 1211141cc406Sopenharmony_ci /* extract data size */ 1212141cc406Sopenharmony_ci messageSize = (((unsigned short) (pData[6])) << 8) | pData[7]; 1213141cc406Sopenharmony_ci 1214141cc406Sopenharmony_ci /* loop through items in message */ 1215141cc406Sopenharmony_ci pItem = pData + 8; 1216141cc406Sopenharmony_ci pEnd = pItem + messageSize; 1217141cc406Sopenharmony_ci while (pItem < pEnd) 1218141cc406Sopenharmony_ci { 1219141cc406Sopenharmony_ci 1220141cc406Sopenharmony_ci pItem++; 1221141cc406Sopenharmony_ci nameSize = (((unsigned short) pItem[0]) << 8) | pItem[1]; 1222141cc406Sopenharmony_ci pItem += 2; 1223141cc406Sopenharmony_ci pName = (char *) pItem; 1224141cc406Sopenharmony_ci 1225141cc406Sopenharmony_ci pItem += nameSize; 1226141cc406Sopenharmony_ci 1227141cc406Sopenharmony_ci pItem++; 1228141cc406Sopenharmony_ci valueSize = (((unsigned short) pItem[0]) << 8) | pItem[1]; 1229141cc406Sopenharmony_ci pItem += 2; 1230141cc406Sopenharmony_ci 1231141cc406Sopenharmony_ci pValue = pItem; 1232141cc406Sopenharmony_ci 1233141cc406Sopenharmony_ci pItem += valueSize; 1234141cc406Sopenharmony_ci 1235141cc406Sopenharmony_ci /* process the item */ 1236141cc406Sopenharmony_ci if (!strncmp ("std-scan-discovery-ip", pName, nameSize)) 1237141cc406Sopenharmony_ci { 1238141cc406Sopenharmony_ci 1239141cc406Sopenharmony_ci snprintf (printerName, sizeof (printerName), "%d.%d.%d.%d", 1240141cc406Sopenharmony_ci (int) pValue[0], 1241141cc406Sopenharmony_ci (int) pValue[1], (int) pValue[2], (int) pValue[3]); 1242141cc406Sopenharmony_ci DBG (2, "%s\n", printerName); 1243141cc406Sopenharmony_ci 1244141cc406Sopenharmony_ci } 1245141cc406Sopenharmony_ci else if (!strncmp ("std-scan-discovery-model-name", pName, nameSize)) 1246141cc406Sopenharmony_ci { 1247141cc406Sopenharmony_ci 1248141cc406Sopenharmony_ci memset (printerModel, 0, sizeof (printerModel)); 1249141cc406Sopenharmony_ci if (valueSize > (sizeof (printerModel) - 1)) 1250141cc406Sopenharmony_ci valueSize = sizeof (printerModel) - 1; 1251141cc406Sopenharmony_ci memcpy (printerModel, pValue, valueSize); 1252141cc406Sopenharmony_ci DBG (2, "std-scan-discovery-model-name: %s\n", printerModel); 1253141cc406Sopenharmony_ci 1254141cc406Sopenharmony_ci } 1255141cc406Sopenharmony_ci 1256141cc406Sopenharmony_ci } /* while pItem */ 1257141cc406Sopenharmony_ci 1258141cc406Sopenharmony_ci /* just in case nothing sensible was found */ 1259141cc406Sopenharmony_ci if ( ! strlen( printerName ) ) return NULL; 1260141cc406Sopenharmony_ci 1261141cc406Sopenharmony_ci pDevice = malloc (sizeof (struct DeviceRecord)); 1262141cc406Sopenharmony_ci if (!pDevice) 1263141cc406Sopenharmony_ci { 1264141cc406Sopenharmony_ci DBG (1, "ProcessFindResponse: memory allocation failure\n"); 1265141cc406Sopenharmony_ci return NULL; 1266141cc406Sopenharmony_ci } 1267141cc406Sopenharmony_ci 1268141cc406Sopenharmony_ci /* knock off "Dell " from start of model name */ 1269141cc406Sopenharmony_ci pModel = printerModel; 1270141cc406Sopenharmony_ci if ( ! strncmp( pModel, "Dell ", 5 ) ) 1271141cc406Sopenharmony_ci pModel += 5; 1272141cc406Sopenharmony_ci 1273141cc406Sopenharmony_ci pDevice->m_pName = strdup( printerName ); 1274141cc406Sopenharmony_ci pDevice->m_device.vendor = "Dell"; 1275141cc406Sopenharmony_ci pDevice->m_pModel = strdup (pModel); 1276141cc406Sopenharmony_ci pDevice->m_device.type = "multi-function peripheral"; 1277141cc406Sopenharmony_ci 1278141cc406Sopenharmony_ci pDevice->m_device.name = pDevice->m_pName; 1279141cc406Sopenharmony_ci pDevice->m_device.model = pDevice->m_pModel; 1280141cc406Sopenharmony_ci 1281141cc406Sopenharmony_ci return pDevice; 1282141cc406Sopenharmony_ci 1283141cc406Sopenharmony_ci} /* ProcessFindResponse */ 1284141cc406Sopenharmony_ci 1285141cc406Sopenharmony_ci/***********************************************************/ 1286141cc406Sopenharmony_ci 1287141cc406Sopenharmony_ci/* frees a scanner state struct stored in gOpenScanners */ 1288141cc406Sopenharmony_civoid 1289141cc406Sopenharmony_ciFreeScannerState (int iHandle) 1290141cc406Sopenharmony_ci{ 1291141cc406Sopenharmony_ci 1292141cc406Sopenharmony_ci /* check range etc */ 1293141cc406Sopenharmony_ci if (!ValidScannerNumber (iHandle)) 1294141cc406Sopenharmony_ci return; 1295141cc406Sopenharmony_ci 1296141cc406Sopenharmony_ci /* close UDP handle */ 1297141cc406Sopenharmony_ci if (gOpenScanners[iHandle]->m_udpFd) 1298141cc406Sopenharmony_ci close (gOpenScanners[iHandle]->m_udpFd); 1299141cc406Sopenharmony_ci 1300141cc406Sopenharmony_ci /* free m_buf */ 1301141cc406Sopenharmony_ci FreeComBuf (&gOpenScanners[iHandle]->m_buf); 1302141cc406Sopenharmony_ci 1303141cc406Sopenharmony_ci /* free m_imageData */ 1304141cc406Sopenharmony_ci FreeComBuf (&gOpenScanners[iHandle]->m_imageData); 1305141cc406Sopenharmony_ci 1306141cc406Sopenharmony_ci /* free the struct */ 1307141cc406Sopenharmony_ci free (gOpenScanners[iHandle]); 1308141cc406Sopenharmony_ci 1309141cc406Sopenharmony_ci /* set pointer to NULL */ 1310141cc406Sopenharmony_ci gOpenScanners[iHandle] = NULL; 1311141cc406Sopenharmony_ci 1312141cc406Sopenharmony_ci} /* FreeScannerState */ 1313141cc406Sopenharmony_ci 1314141cc406Sopenharmony_ci/***********************************************************/ 1315141cc406Sopenharmony_ci 1316141cc406Sopenharmony_ci/* \return 1 if iHandle is a valid member of gOpenScanners, 0 otherwise */ 1317141cc406Sopenharmony_ciint 1318141cc406Sopenharmony_ciValidScannerNumber (int iHandle) 1319141cc406Sopenharmony_ci{ 1320141cc406Sopenharmony_ci /* check range */ 1321141cc406Sopenharmony_ci if ((iHandle < 0) || (iHandle >= MAX_SCANNERS)) 1322141cc406Sopenharmony_ci { 1323141cc406Sopenharmony_ci DBG (1, "ValidScannerNumber: invalid scanner index %d", iHandle); 1324141cc406Sopenharmony_ci return 0; 1325141cc406Sopenharmony_ci } 1326141cc406Sopenharmony_ci 1327141cc406Sopenharmony_ci /* check non-NULL pointer */ 1328141cc406Sopenharmony_ci if (!gOpenScanners[iHandle]) 1329141cc406Sopenharmony_ci { 1330141cc406Sopenharmony_ci DBG (1, "ValidScannerNumber: NULL scanner struct %d", iHandle); 1331141cc406Sopenharmony_ci return 0; 1332141cc406Sopenharmony_ci } 1333141cc406Sopenharmony_ci 1334141cc406Sopenharmony_ci /* OK */ 1335141cc406Sopenharmony_ci return 1; 1336141cc406Sopenharmony_ci 1337141cc406Sopenharmony_ci} /* ValidScannerNumber */ 1338141cc406Sopenharmony_ci 1339141cc406Sopenharmony_ci/***********************************************************/ 1340141cc406Sopenharmony_ci 1341141cc406Sopenharmony_ci/* process UDP responses 1342141cc406Sopenharmony_ci \return 0 in success, >0 otherwise */ 1343141cc406Sopenharmony_cistatic int 1344141cc406Sopenharmony_ciProcessUdpResponse (unsigned char *pData, size_t size, 1345141cc406Sopenharmony_ci struct ScannerState *pState) 1346141cc406Sopenharmony_ci{ 1347141cc406Sopenharmony_ci 1348141cc406Sopenharmony_ci unsigned short messageSize, nameSize, valueSize; 1349141cc406Sopenharmony_ci unsigned char *pItem, *pEnd; 1350141cc406Sopenharmony_ci char sockBuf[SOCK_BUF_SIZE], *pName; 1351141cc406Sopenharmony_ci struct ComBuf tcpBuf; 1352141cc406Sopenharmony_ci int nread; 1353141cc406Sopenharmony_ci unsigned int numUsed; 1354141cc406Sopenharmony_ci 1355141cc406Sopenharmony_ci HexDump (15, pData, size); 1356141cc406Sopenharmony_ci 1357141cc406Sopenharmony_ci DBG (10, "ProcessUdpResponse: processing %lu bytes, pData=%p\n", 1358141cc406Sopenharmony_ci (unsigned long) size, (void *) pData); 1359141cc406Sopenharmony_ci 1360141cc406Sopenharmony_ci /* check we have a complete packet */ 1361141cc406Sopenharmony_ci if (!MessageIsComplete (pData, size)) 1362141cc406Sopenharmony_ci { 1363141cc406Sopenharmony_ci DBG (1, "ProcessUdpResponse: Ignoring incomplete packet\n"); 1364141cc406Sopenharmony_ci return 1; 1365141cc406Sopenharmony_ci } 1366141cc406Sopenharmony_ci 1367141cc406Sopenharmony_ci /* init a com buf for use in tcp communication */ 1368141cc406Sopenharmony_ci InitComBuf (&tcpBuf); 1369141cc406Sopenharmony_ci 1370141cc406Sopenharmony_ci /* extract data size */ 1371141cc406Sopenharmony_ci messageSize = (((unsigned short) (pData[6])) << 8) | pData[7]; 1372141cc406Sopenharmony_ci 1373141cc406Sopenharmony_ci /* loop through items in message */ 1374141cc406Sopenharmony_ci pItem = pData + 8; 1375141cc406Sopenharmony_ci pEnd = pItem + messageSize; 1376141cc406Sopenharmony_ci while (pItem < pEnd) 1377141cc406Sopenharmony_ci { 1378141cc406Sopenharmony_ci 1379141cc406Sopenharmony_ci pItem++; 1380141cc406Sopenharmony_ci nameSize = (((unsigned short) pItem[0]) << 8) | pItem[1]; 1381141cc406Sopenharmony_ci pItem += 2; 1382141cc406Sopenharmony_ci pName = (char *) pItem; 1383141cc406Sopenharmony_ci 1384141cc406Sopenharmony_ci pItem += nameSize; 1385141cc406Sopenharmony_ci 1386141cc406Sopenharmony_ci pItem++; 1387141cc406Sopenharmony_ci valueSize = (((unsigned short) pItem[0]) << 8) | pItem[1]; 1388141cc406Sopenharmony_ci pItem += 2; 1389141cc406Sopenharmony_ci 1390141cc406Sopenharmony_ci pItem += valueSize; 1391141cc406Sopenharmony_ci 1392141cc406Sopenharmony_ci /* process the item */ 1393141cc406Sopenharmony_ci if (!strncmp ("std-scan-request-tcp-connection", pName, nameSize)) 1394141cc406Sopenharmony_ci { 1395141cc406Sopenharmony_ci 1396141cc406Sopenharmony_ci /* open TCP socket to scanner */ 1397141cc406Sopenharmony_ci if (!(pState->m_tcpFd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP))) 1398141cc406Sopenharmony_ci { 1399141cc406Sopenharmony_ci DBG (1, "ProcessUdpResponse: error opening TCP socket\n"); 1400141cc406Sopenharmony_ci return 2; 1401141cc406Sopenharmony_ci } 1402141cc406Sopenharmony_ci if (connect (pState->m_tcpFd, 1403141cc406Sopenharmony_ci (struct sockaddr *) &pState->m_sockAddr, 1404141cc406Sopenharmony_ci sizeof (pState->m_sockAddr))) 1405141cc406Sopenharmony_ci { 1406141cc406Sopenharmony_ci DBG (1, 1407141cc406Sopenharmony_ci "ProcessUdpResponse: error connecting to scanner TCP port\n"); 1408141cc406Sopenharmony_ci goto cleanup; 1409141cc406Sopenharmony_ci } 1410141cc406Sopenharmony_ci 1411141cc406Sopenharmony_ci DBG (1, "ProcessUdpResponse: opened TCP connection to scanner\n"); 1412141cc406Sopenharmony_ci 1413141cc406Sopenharmony_ci /* clear read buf */ 1414141cc406Sopenharmony_ci tcpBuf.m_used = 0; 1415141cc406Sopenharmony_ci 1416141cc406Sopenharmony_ci /* TCP read loop */ 1417141cc406Sopenharmony_ci while (1) 1418141cc406Sopenharmony_ci { 1419141cc406Sopenharmony_ci 1420141cc406Sopenharmony_ci nread = read (pState->m_tcpFd, sockBuf, sizeof (sockBuf)); 1421141cc406Sopenharmony_ci 1422141cc406Sopenharmony_ci if (nread <= 0) 1423141cc406Sopenharmony_ci { 1424141cc406Sopenharmony_ci DBG (1, "ProcessUdpResponse: TCP read returned %d\n", 1425141cc406Sopenharmony_ci nread); 1426141cc406Sopenharmony_ci break; 1427141cc406Sopenharmony_ci } 1428141cc406Sopenharmony_ci 1429141cc406Sopenharmony_ci /* append message to buffer */ 1430141cc406Sopenharmony_ci if (AppendToComBuf (&tcpBuf, (unsigned char *) sockBuf, nread)) 1431141cc406Sopenharmony_ci goto cleanup; 1432141cc406Sopenharmony_ci 1433141cc406Sopenharmony_ci /* process all available responses */ 1434141cc406Sopenharmony_ci while (tcpBuf.m_used) 1435141cc406Sopenharmony_ci { 1436141cc406Sopenharmony_ci 1437141cc406Sopenharmony_ci /* note the buffer size before the call */ 1438141cc406Sopenharmony_ci numUsed = tcpBuf.m_used; 1439141cc406Sopenharmony_ci 1440141cc406Sopenharmony_ci /* process the response */ 1441141cc406Sopenharmony_ci if (ProcessTcpResponse (pState, &tcpBuf)) 1442141cc406Sopenharmony_ci goto cleanup; 1443141cc406Sopenharmony_ci 1444141cc406Sopenharmony_ci /* if the buffer size has not changed then assume no more processing is possible */ 1445141cc406Sopenharmony_ci if (numUsed == tcpBuf.m_used) 1446141cc406Sopenharmony_ci break; 1447141cc406Sopenharmony_ci 1448141cc406Sopenharmony_ci } /* while */ 1449141cc406Sopenharmony_ci 1450141cc406Sopenharmony_ci } /* while */ 1451141cc406Sopenharmony_ci 1452141cc406Sopenharmony_ci close (pState->m_tcpFd); 1453141cc406Sopenharmony_ci DBG (1, "ProcessUdpResponse: closed TCP connection to scanner\n"); 1454141cc406Sopenharmony_ci 1455141cc406Sopenharmony_ci /* signal end of session */ 1456141cc406Sopenharmony_ci pState->m_bFinish = 1; 1457141cc406Sopenharmony_ci 1458141cc406Sopenharmony_ci } /* if */ 1459141cc406Sopenharmony_ci 1460141cc406Sopenharmony_ci } /* while pItem */ 1461141cc406Sopenharmony_ci 1462141cc406Sopenharmony_ci return 0; 1463141cc406Sopenharmony_ci 1464141cc406Sopenharmony_cicleanup: 1465141cc406Sopenharmony_ci 1466141cc406Sopenharmony_ci FreeComBuf (&tcpBuf); 1467141cc406Sopenharmony_ci close (pState->m_tcpFd); 1468141cc406Sopenharmony_ci return 3; 1469141cc406Sopenharmony_ci 1470141cc406Sopenharmony_ci} /* ProcessUdpResponse */ 1471141cc406Sopenharmony_ci 1472141cc406Sopenharmony_ci/***********************************************************/ 1473141cc406Sopenharmony_ci 1474141cc406Sopenharmony_ci/* process TCP responses, \return 0 in success, >0 otherwise */ 1475141cc406Sopenharmony_ciint 1476141cc406Sopenharmony_ciProcessTcpResponse (struct ScannerState *pState, struct ComBuf *pTcpBuf) 1477141cc406Sopenharmony_ci{ 1478141cc406Sopenharmony_ci 1479141cc406Sopenharmony_ci struct ComBuf buf; 1480141cc406Sopenharmony_ci unsigned short messageSize = 0, nameSize, valueSize, dataChunkSize; 1481141cc406Sopenharmony_ci unsigned char *pItem, *pEnd, *pValue; 1482141cc406Sopenharmony_ci unsigned char *pData = pTcpBuf->m_pBuf; 1483141cc406Sopenharmony_ci char *pName; 1484141cc406Sopenharmony_ci unsigned int uiVal; 1485141cc406Sopenharmony_ci int errorCheck = 0; 1486141cc406Sopenharmony_ci int bProcessImage = 0; 1487141cc406Sopenharmony_ci 1488141cc406Sopenharmony_ci DBG (10, "ProcessTcpResponse: processing %lu bytes, pData=%p\n", 1489141cc406Sopenharmony_ci (unsigned long) pTcpBuf->m_used, (void *) pData); 1490141cc406Sopenharmony_ci HexDump (15, pData, pTcpBuf->m_used); 1491141cc406Sopenharmony_ci 1492141cc406Sopenharmony_ci /* if message not complete then wait for more to arrive */ 1493141cc406Sopenharmony_ci if (!MessageIsComplete (pData, pTcpBuf->m_used)) 1494141cc406Sopenharmony_ci { 1495141cc406Sopenharmony_ci DBG (10, "ProcessTcpResponse: incomplete message, returning\n"); 1496141cc406Sopenharmony_ci return 0; 1497141cc406Sopenharmony_ci } 1498141cc406Sopenharmony_ci 1499141cc406Sopenharmony_ci /* init a buffer for our outbound messages */ 1500141cc406Sopenharmony_ci if (InitComBuf (&buf)) 1501141cc406Sopenharmony_ci { 1502141cc406Sopenharmony_ci errorCheck |= 1; 1503141cc406Sopenharmony_ci goto cleanup; 1504141cc406Sopenharmony_ci } 1505141cc406Sopenharmony_ci 1506141cc406Sopenharmony_ci /* extract data size */ 1507141cc406Sopenharmony_ci messageSize = (((unsigned short) (pData[6])) << 8) | pData[7]; 1508141cc406Sopenharmony_ci 1509141cc406Sopenharmony_ci /* loop through items in message */ 1510141cc406Sopenharmony_ci pItem = pData + 8; 1511141cc406Sopenharmony_ci pEnd = pItem + messageSize; 1512141cc406Sopenharmony_ci while (pItem < pEnd) 1513141cc406Sopenharmony_ci { 1514141cc406Sopenharmony_ci 1515141cc406Sopenharmony_ci pItem++; 1516141cc406Sopenharmony_ci nameSize = (((unsigned short) pItem[0]) << 8) | pItem[1]; 1517141cc406Sopenharmony_ci pItem += 2; 1518141cc406Sopenharmony_ci pName = (char *) pItem; 1519141cc406Sopenharmony_ci 1520141cc406Sopenharmony_ci pItem += nameSize; 1521141cc406Sopenharmony_ci 1522141cc406Sopenharmony_ci pItem++; 1523141cc406Sopenharmony_ci valueSize = (((unsigned short) pItem[0]) << 8) | pItem[1]; 1524141cc406Sopenharmony_ci pItem += 2; 1525141cc406Sopenharmony_ci 1526141cc406Sopenharmony_ci pValue = pItem; 1527141cc406Sopenharmony_ci 1528141cc406Sopenharmony_ci pItem += valueSize; 1529141cc406Sopenharmony_ci 1530141cc406Sopenharmony_ci /* process the item */ 1531141cc406Sopenharmony_ci if (!strncmp ("std-scan-session-open", pName, nameSize)) 1532141cc406Sopenharmony_ci { 1533141cc406Sopenharmony_ci 1534141cc406Sopenharmony_ci errorCheck |= InitPacket (&buf, 0x02); 1535141cc406Sopenharmony_ci uiVal = 0; 1536141cc406Sopenharmony_ci errorCheck |= 1537141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1538141cc406Sopenharmony_ci "std-scan-session-open-response", 0x05, 1539141cc406Sopenharmony_ci &uiVal, sizeof (uiVal)); 1540141cc406Sopenharmony_ci FinalisePacket (&buf); 1541141cc406Sopenharmony_ci send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0); 1542141cc406Sopenharmony_ci 1543141cc406Sopenharmony_ci } 1544141cc406Sopenharmony_ci else if (!strncmp ("std-scan-getclientpref", pName, nameSize)) 1545141cc406Sopenharmony_ci { 1546141cc406Sopenharmony_ci 1547141cc406Sopenharmony_ci errorCheck |= InitPacket (&buf, 0x02); 1548141cc406Sopenharmony_ci uiVal = 0; 1549141cc406Sopenharmony_ci errorCheck |= 1550141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, "std-scan-getclientpref-x1", 1551141cc406Sopenharmony_ci 0x05, &uiVal, sizeof (uiVal)); 1552141cc406Sopenharmony_ci errorCheck |= 1553141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, "std-scan-getclientpref-x2", 1554141cc406Sopenharmony_ci 0x05, &uiVal, sizeof (uiVal)); 1555141cc406Sopenharmony_ci errorCheck |= 1556141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, "std-scan-getclientpref-y1", 1557141cc406Sopenharmony_ci 0x05, &uiVal, sizeof (uiVal)); 1558141cc406Sopenharmony_ci errorCheck |= 1559141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, "std-scan-getclientpref-y2", 1560141cc406Sopenharmony_ci 0x05, &uiVal, sizeof (uiVal)); 1561141cc406Sopenharmony_ci errorCheck |= 1562141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1563141cc406Sopenharmony_ci "std-scan-getclientpref-xresolution", 0x04, 1564141cc406Sopenharmony_ci &pState->m_xres, sizeof (pState->m_xres)); 1565141cc406Sopenharmony_ci errorCheck |= 1566141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1567141cc406Sopenharmony_ci "std-scan-getclientpref-yresolution", 0x04, 1568141cc406Sopenharmony_ci &pState->m_yres, sizeof (pState->m_yres)); 1569141cc406Sopenharmony_ci errorCheck |= 1570141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1571141cc406Sopenharmony_ci "std-scan-getclientpref-image-composition", 1572141cc406Sopenharmony_ci 0x06, &pState->m_composition, 1573141cc406Sopenharmony_ci sizeof (pState->m_composition)); 1574141cc406Sopenharmony_ci errorCheck |= 1575141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1576141cc406Sopenharmony_ci "std-scan-getclientpref-brightness", 0x02, 1577141cc406Sopenharmony_ci &pState->m_brightness, 1578141cc406Sopenharmony_ci sizeof (pState->m_brightness)); 1579141cc406Sopenharmony_ci errorCheck |= 1580141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1581141cc406Sopenharmony_ci "std-scan-getclientpref-image-compression", 1582141cc406Sopenharmony_ci 0x06, &pState->m_compression, 1583141cc406Sopenharmony_ci sizeof (pState->m_compression)); 1584141cc406Sopenharmony_ci errorCheck |= 1585141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1586141cc406Sopenharmony_ci "std-scan-getclientpref-file-type", 0x06, 1587141cc406Sopenharmony_ci &pState->m_fileType, 1588141cc406Sopenharmony_ci sizeof (pState->m_fileType)); 1589141cc406Sopenharmony_ci errorCheck |= 1590141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1591141cc406Sopenharmony_ci "std-scan-getclientpref-paper-size-detect", 1592141cc406Sopenharmony_ci 0x06, &uiVal, sizeof (uiVal)); 1593141cc406Sopenharmony_ci errorCheck |= 1594141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1595141cc406Sopenharmony_ci "std-scan-getclientpref-paper-scanner-type", 1596141cc406Sopenharmony_ci 0x06, &uiVal, sizeof (uiVal)); 1597141cc406Sopenharmony_ci FinalisePacket (&buf); 1598141cc406Sopenharmony_ci send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0); 1599141cc406Sopenharmony_ci 1600141cc406Sopenharmony_ci } 1601141cc406Sopenharmony_ci else if (!strncmp ("std-scan-document-start", pName, nameSize)) 1602141cc406Sopenharmony_ci { 1603141cc406Sopenharmony_ci errorCheck |= InitPacket (&buf, 0x02); 1604141cc406Sopenharmony_ci uiVal = 0; 1605141cc406Sopenharmony_ci errorCheck |= 1606141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1607141cc406Sopenharmony_ci "std-scan-document-start-response", 0x05, 1608141cc406Sopenharmony_ci &uiVal, sizeof (uiVal)); 1609141cc406Sopenharmony_ci FinalisePacket (&buf); 1610141cc406Sopenharmony_ci send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0); 1611141cc406Sopenharmony_ci } 1612141cc406Sopenharmony_ci else if (!strncmp ("std-scan-document-file-type", pName, nameSize)) 1613141cc406Sopenharmony_ci { 1614141cc406Sopenharmony_ci memcpy (&pState->m_fileType, pValue, sizeof (pState->m_fileType)); 1615141cc406Sopenharmony_ci DBG (5, "File type: %x\n", ntohl (pState->m_fileType)); 1616141cc406Sopenharmony_ci } 1617141cc406Sopenharmony_ci else 1618141cc406Sopenharmony_ci if (!strncmp ("std-scan-document-image-compression", pName, nameSize)) 1619141cc406Sopenharmony_ci { 1620141cc406Sopenharmony_ci memcpy (&pState->m_compression, pValue, 1621141cc406Sopenharmony_ci sizeof (pState->m_compression)); 1622141cc406Sopenharmony_ci DBG (5, "Compression: %x\n", ntohl (pState->m_compression)); 1623141cc406Sopenharmony_ci 1624141cc406Sopenharmony_ci } 1625141cc406Sopenharmony_ci else if (!strncmp ("std-scan-document-xresolution", pName, nameSize)) 1626141cc406Sopenharmony_ci { 1627141cc406Sopenharmony_ci memcpy (&pState->m_xres, pValue, sizeof (pState->m_xres)); 1628141cc406Sopenharmony_ci DBG (5, "X resolution: %d\n", ntohs (pState->m_xres)); 1629141cc406Sopenharmony_ci } 1630141cc406Sopenharmony_ci else if (!strncmp ("std-scan-document-yresolution", pName, nameSize)) 1631141cc406Sopenharmony_ci { 1632141cc406Sopenharmony_ci memcpy (&pState->m_yres, pValue, sizeof (pState->m_yres)); 1633141cc406Sopenharmony_ci DBG (5, "Y resolution: %d\n", ntohs (pState->m_yres)); 1634141cc406Sopenharmony_ci } 1635141cc406Sopenharmony_ci else if (!strncmp ("std-scan-page-widthpixel", pName, nameSize)) 1636141cc406Sopenharmony_ci { 1637141cc406Sopenharmony_ci if (1 || !pState->m_pixelWidth) 1638141cc406Sopenharmony_ci { 1639141cc406Sopenharmony_ci memcpy (&pState->m_pixelWidth, pValue, 1640141cc406Sopenharmony_ci sizeof (pState->m_pixelWidth)); 1641141cc406Sopenharmony_ci DBG (5, "Width: %d\n", ntohl (pState->m_pixelWidth)); 1642141cc406Sopenharmony_ci } 1643141cc406Sopenharmony_ci else 1644141cc406Sopenharmony_ci { 1645141cc406Sopenharmony_ci DBG (5, "Ignoring width (already have a value)\n"); 1646141cc406Sopenharmony_ci } 1647141cc406Sopenharmony_ci } 1648141cc406Sopenharmony_ci else if (!strncmp ("std-scan-page-heightpixel", pName, nameSize)) 1649141cc406Sopenharmony_ci { 1650141cc406Sopenharmony_ci if (1 || !pState->m_pixelHeight) 1651141cc406Sopenharmony_ci { 1652141cc406Sopenharmony_ci memcpy (&pState->m_pixelHeight, pValue, 1653141cc406Sopenharmony_ci sizeof (pState->m_pixelHeight)); 1654141cc406Sopenharmony_ci DBG (5, "Height: %d\n", ntohl (pState->m_pixelHeight)); 1655141cc406Sopenharmony_ci } 1656141cc406Sopenharmony_ci else 1657141cc406Sopenharmony_ci { 1658141cc406Sopenharmony_ci DBG (5, "Ignoring height (already have a value)\n"); 1659141cc406Sopenharmony_ci } 1660141cc406Sopenharmony_ci } 1661141cc406Sopenharmony_ci else if (!strncmp ("std-scan-page-start", pName, nameSize)) 1662141cc406Sopenharmony_ci { 1663141cc406Sopenharmony_ci errorCheck |= InitPacket (&buf, 0x02); 1664141cc406Sopenharmony_ci uiVal = 0; 1665141cc406Sopenharmony_ci errorCheck |= 1666141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, "std-scan-page-start-response", 1667141cc406Sopenharmony_ci 0x05, &uiVal, sizeof (uiVal)); 1668141cc406Sopenharmony_ci FinalisePacket (&buf); 1669141cc406Sopenharmony_ci send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0); 1670141cc406Sopenharmony_ci 1671141cc406Sopenharmony_ci /* reset the data buffer ready to store a new page */ 1672141cc406Sopenharmony_ci pState->m_buf.m_used = 0; 1673141cc406Sopenharmony_ci 1674141cc406Sopenharmony_ci /* init current page size */ 1675141cc406Sopenharmony_ci pState->m_currentPageBytes = 0; 1676141cc406Sopenharmony_ci 1677141cc406Sopenharmony_ci pState->m_pixelWidth = 0; 1678141cc406Sopenharmony_ci pState->m_pixelHeight = 0; 1679141cc406Sopenharmony_ci } 1680141cc406Sopenharmony_ci else if (!strncmp ("std-scan-page-end", pName, nameSize)) 1681141cc406Sopenharmony_ci { 1682141cc406Sopenharmony_ci bProcessImage = 1; 1683141cc406Sopenharmony_ci 1684141cc406Sopenharmony_ci errorCheck |= InitPacket (&buf, 0x02); 1685141cc406Sopenharmony_ci uiVal = 0; 1686141cc406Sopenharmony_ci errorCheck |= 1687141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, "std-scan-page-end-response", 1688141cc406Sopenharmony_ci 0x05, &uiVal, sizeof (uiVal)); 1689141cc406Sopenharmony_ci FinalisePacket (&buf); 1690141cc406Sopenharmony_ci send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0); 1691141cc406Sopenharmony_ci } 1692141cc406Sopenharmony_ci else if (!strncmp ("std-scan-document-end", pName, nameSize)) 1693141cc406Sopenharmony_ci { 1694141cc406Sopenharmony_ci errorCheck |= InitPacket (&buf, 0x02); 1695141cc406Sopenharmony_ci uiVal = 0; 1696141cc406Sopenharmony_ci errorCheck |= 1697141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1698141cc406Sopenharmony_ci "std-scan-document-end-response", 0x05, 1699141cc406Sopenharmony_ci &uiVal, sizeof (uiVal)); 1700141cc406Sopenharmony_ci FinalisePacket (&buf); 1701141cc406Sopenharmony_ci send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0); 1702141cc406Sopenharmony_ci 1703141cc406Sopenharmony_ci /* reset the data buffer ready to store a new page */ 1704141cc406Sopenharmony_ci pState->m_buf.m_used = 0; 1705141cc406Sopenharmony_ci } 1706141cc406Sopenharmony_ci else if (!strncmp ("std-scan-session-end", pName, nameSize)) 1707141cc406Sopenharmony_ci { 1708141cc406Sopenharmony_ci errorCheck |= InitPacket (&buf, 0x02); 1709141cc406Sopenharmony_ci uiVal = 0; 1710141cc406Sopenharmony_ci errorCheck |= 1711141cc406Sopenharmony_ci AppendMessageToPacket (&buf, 0x22, 1712141cc406Sopenharmony_ci "std-scan-session-end-response", 0x05, 1713141cc406Sopenharmony_ci &uiVal, sizeof (uiVal)); 1714141cc406Sopenharmony_ci FinalisePacket (&buf); 1715141cc406Sopenharmony_ci send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0); 1716141cc406Sopenharmony_ci 1717141cc406Sopenharmony_ci /* initialise a shutodwn of the socket */ 1718141cc406Sopenharmony_ci shutdown (pState->m_tcpFd, SHUT_RDWR); 1719141cc406Sopenharmony_ci } 1720141cc406Sopenharmony_ci else if (!strncmp ("std-scan-scandata-error", pName, nameSize)) 1721141cc406Sopenharmony_ci { 1722141cc406Sopenharmony_ci /* determine the size of data in this chunk */ 1723141cc406Sopenharmony_ci dataChunkSize = (pItem[6] << 8) + pItem[7]; 1724141cc406Sopenharmony_ci 1725141cc406Sopenharmony_ci pItem += 8; 1726141cc406Sopenharmony_ci 1727141cc406Sopenharmony_ci DBG (10, "Reading %d bytes of scan data\n", dataChunkSize); 1728141cc406Sopenharmony_ci 1729141cc406Sopenharmony_ci /* append message to buffer */ 1730141cc406Sopenharmony_ci errorCheck |= AppendToComBuf (&pState->m_buf, pItem, dataChunkSize); 1731141cc406Sopenharmony_ci 1732141cc406Sopenharmony_ci pItem += dataChunkSize; 1733141cc406Sopenharmony_ci 1734141cc406Sopenharmony_ci DBG (10, "Accumulated %lu bytes of scan data so far\n", 1735141cc406Sopenharmony_ci (unsigned long)pState->m_buf.m_used); 1736141cc406Sopenharmony_ci } /* if */ 1737141cc406Sopenharmony_ci } /* while */ 1738141cc406Sopenharmony_ci 1739141cc406Sopenharmony_ci /* process page data if required */ 1740141cc406Sopenharmony_ci if ( bProcessImage ) errorCheck |= ProcessPageData (pState); 1741141cc406Sopenharmony_ci 1742141cc406Sopenharmony_cicleanup: 1743141cc406Sopenharmony_ci 1744141cc406Sopenharmony_ci /* remove processed data (including 8 byte header) from start of tcp buffer */ 1745141cc406Sopenharmony_ci PopFromComBuf (pTcpBuf, messageSize + 8); 1746141cc406Sopenharmony_ci 1747141cc406Sopenharmony_ci /* free com buf */ 1748141cc406Sopenharmony_ci FreeComBuf (&buf); 1749141cc406Sopenharmony_ci 1750141cc406Sopenharmony_ci return errorCheck; 1751141cc406Sopenharmony_ci 1752141cc406Sopenharmony_ci} /* ProcessTcpResponse */ 1753141cc406Sopenharmony_ci 1754141cc406Sopenharmony_ci/***********************************************************/ 1755141cc406Sopenharmony_ci 1756141cc406Sopenharmony_ci/* remove data from the front of a ComBuf struct 1757141cc406Sopenharmony_ci \return 0 if successful, >0 otherwise 1758141cc406Sopenharmony_ci*/ 1759141cc406Sopenharmony_ciint 1760141cc406Sopenharmony_ciPopFromComBuf (struct ComBuf *pBuf, size_t datSize) 1761141cc406Sopenharmony_ci{ 1762141cc406Sopenharmony_ci 1763141cc406Sopenharmony_ci /* check if we're trying to remove more data than is present */ 1764141cc406Sopenharmony_ci if (datSize > pBuf->m_used) 1765141cc406Sopenharmony_ci { 1766141cc406Sopenharmony_ci pBuf->m_used = 0; 1767141cc406Sopenharmony_ci return 1; 1768141cc406Sopenharmony_ci } 1769141cc406Sopenharmony_ci 1770141cc406Sopenharmony_ci /* check easy cases */ 1771141cc406Sopenharmony_ci if ((!datSize) || (datSize == pBuf->m_used)) 1772141cc406Sopenharmony_ci { 1773141cc406Sopenharmony_ci pBuf->m_used -= datSize; 1774141cc406Sopenharmony_ci return 0; 1775141cc406Sopenharmony_ci } 1776141cc406Sopenharmony_ci 1777141cc406Sopenharmony_ci /* move remaining memory contents to start */ 1778141cc406Sopenharmony_ci memmove (pBuf->m_pBuf, pBuf->m_pBuf + datSize, pBuf->m_used - datSize); 1779141cc406Sopenharmony_ci 1780141cc406Sopenharmony_ci pBuf->m_used -= datSize; 1781141cc406Sopenharmony_ci return 0; 1782141cc406Sopenharmony_ci 1783141cc406Sopenharmony_ci} /* PopFromComBuf */ 1784141cc406Sopenharmony_ci 1785141cc406Sopenharmony_ci/***********************************************************/ 1786141cc406Sopenharmony_ci 1787141cc406Sopenharmony_ci/* Process the data from a single scanned page, \return 0 in success, >0 otherwise */ 1788141cc406Sopenharmony_ciint 1789141cc406Sopenharmony_ciProcessPageData (struct ScannerState *pState) 1790141cc406Sopenharmony_ci{ 1791141cc406Sopenharmony_ci 1792141cc406Sopenharmony_ci FILE *fTmp; 1793141cc406Sopenharmony_ci int fdTmp; 1794141cc406Sopenharmony_ci struct jpeg_source_mgr jpegSrcMgr; 1795141cc406Sopenharmony_ci struct JpegDataDecompState jpegCinfo; 1796141cc406Sopenharmony_ci struct jpeg_error_mgr jpegErr; 1797141cc406Sopenharmony_ci int numPixels, iPixel, width, height, scanLineSize, imageBytes; 1798141cc406Sopenharmony_ci int ret = 0; 1799141cc406Sopenharmony_ci struct PageInfo pageInfo; 1800141cc406Sopenharmony_ci 1801141cc406Sopenharmony_ci JSAMPLE *pJpegLine = NULL; 1802141cc406Sopenharmony_ci uint32_t *pTiffRgba = NULL; 1803141cc406Sopenharmony_ci unsigned char *pOut; 1804141cc406Sopenharmony_ci char tiffErrBuf[1024]; 1805141cc406Sopenharmony_ci 1806141cc406Sopenharmony_ci TIFF *pTiff = NULL; 1807141cc406Sopenharmony_ci 1808141cc406Sopenharmony_ci /* If there's no data then there's nothing to write */ 1809141cc406Sopenharmony_ci if (!pState->m_buf.m_used) 1810141cc406Sopenharmony_ci return 0; 1811141cc406Sopenharmony_ci 1812141cc406Sopenharmony_ci DBG (1, "ProcessPageData: Got compression %x\n", 1813141cc406Sopenharmony_ci ntohl (pState->m_compression)); 1814141cc406Sopenharmony_ci 1815141cc406Sopenharmony_ci switch (ntohl (pState->m_compression)) 1816141cc406Sopenharmony_ci { 1817141cc406Sopenharmony_ci 1818141cc406Sopenharmony_ci case 0x20: 1819141cc406Sopenharmony_ci /* decode as JPEG if appropriate */ 1820141cc406Sopenharmony_ci { 1821141cc406Sopenharmony_ci 1822141cc406Sopenharmony_ci jpegSrcMgr.resync_to_restart = jpeg_resync_to_restart; 1823141cc406Sopenharmony_ci jpegSrcMgr.init_source = JpegDecompInitSource; 1824141cc406Sopenharmony_ci jpegSrcMgr.fill_input_buffer = JpegDecompFillInputBuffer; 1825141cc406Sopenharmony_ci jpegSrcMgr.skip_input_data = JpegDecompSkipInputData; 1826141cc406Sopenharmony_ci jpegSrcMgr.term_source = JpegDecompTermSource; 1827141cc406Sopenharmony_ci 1828141cc406Sopenharmony_ci jpegCinfo.m_cinfo.err = jpeg_std_error (&jpegErr); 1829141cc406Sopenharmony_ci jpeg_create_decompress (&jpegCinfo.m_cinfo); 1830141cc406Sopenharmony_ci jpegCinfo.m_cinfo.src = &jpegSrcMgr; 1831141cc406Sopenharmony_ci jpegCinfo.m_bytesRemaining = pState->m_buf.m_used; 1832141cc406Sopenharmony_ci jpegCinfo.m_pData = pState->m_buf.m_pBuf; 1833141cc406Sopenharmony_ci 1834141cc406Sopenharmony_ci jpeg_read_header (&jpegCinfo.m_cinfo, TRUE); 1835141cc406Sopenharmony_ci jpeg_start_decompress (&jpegCinfo.m_cinfo); 1836141cc406Sopenharmony_ci 1837141cc406Sopenharmony_ci /* allocate space for a single scanline */ 1838141cc406Sopenharmony_ci scanLineSize = jpegCinfo.m_cinfo.output_width 1839141cc406Sopenharmony_ci * jpegCinfo.m_cinfo.output_components; 1840141cc406Sopenharmony_ci DBG (1, "ProcessPageData: image dimensions: %d x %d, line size: %d\n", 1841141cc406Sopenharmony_ci jpegCinfo.m_cinfo.output_width, 1842141cc406Sopenharmony_ci jpegCinfo.m_cinfo.output_height, scanLineSize); 1843141cc406Sopenharmony_ci 1844141cc406Sopenharmony_ci pJpegLine = calloc (scanLineSize, sizeof (JSAMPLE)); 1845141cc406Sopenharmony_ci if (!pJpegLine) 1846141cc406Sopenharmony_ci { 1847141cc406Sopenharmony_ci DBG (1, "ProcessPageData: memory allocation error\n"); 1848141cc406Sopenharmony_ci ret = 1; 1849141cc406Sopenharmony_ci goto JPEG_CLEANUP; 1850141cc406Sopenharmony_ci } /* if */ 1851141cc406Sopenharmony_ci 1852141cc406Sopenharmony_ci /* note dimensions - may be different from those previously reported */ 1853141cc406Sopenharmony_ci pState->m_pixelWidth = htonl (jpegCinfo.m_cinfo.output_width); 1854141cc406Sopenharmony_ci pState->m_pixelHeight = htonl (jpegCinfo.m_cinfo.output_height); 1855141cc406Sopenharmony_ci 1856141cc406Sopenharmony_ci /* decode scanlines */ 1857141cc406Sopenharmony_ci while (jpegCinfo.m_cinfo.output_scanline 1858141cc406Sopenharmony_ci < jpegCinfo.m_cinfo.output_height) 1859141cc406Sopenharmony_ci { 1860141cc406Sopenharmony_ci DBG (20, "Reading scanline %d of %d\n", 1861141cc406Sopenharmony_ci jpegCinfo.m_cinfo.output_scanline, 1862141cc406Sopenharmony_ci jpegCinfo.m_cinfo.output_height); 1863141cc406Sopenharmony_ci 1864141cc406Sopenharmony_ci /* read scanline */ 1865141cc406Sopenharmony_ci jpeg_read_scanlines (&jpegCinfo.m_cinfo, &pJpegLine, 1); 1866141cc406Sopenharmony_ci 1867141cc406Sopenharmony_ci /* append to output buffer */ 1868141cc406Sopenharmony_ci ret |= AppendToComBuf (&pState->m_imageData, 1869141cc406Sopenharmony_ci pJpegLine, scanLineSize); 1870141cc406Sopenharmony_ci 1871141cc406Sopenharmony_ci } /* while */ 1872141cc406Sopenharmony_ci 1873141cc406Sopenharmony_ci /* update info for this page */ 1874141cc406Sopenharmony_ci pageInfo.m_width = jpegCinfo.m_cinfo.output_width; 1875141cc406Sopenharmony_ci pageInfo.m_height = jpegCinfo.m_cinfo.output_height; 1876141cc406Sopenharmony_ci pageInfo.m_totalSize = pageInfo.m_width * pageInfo.m_height * 3; 1877141cc406Sopenharmony_ci pageInfo.m_bytesRemaining = pageInfo.m_totalSize; 1878141cc406Sopenharmony_ci 1879141cc406Sopenharmony_ci DBG( 1, "Process page data: page %d: JPEG image: %d x %d, %d bytes\n", 1880141cc406Sopenharmony_ci pState->m_numPages, pageInfo.m_width, pageInfo.m_height, pageInfo.m_totalSize ); 1881141cc406Sopenharmony_ci 1882141cc406Sopenharmony_ci ret |= AppendToComBuf( & pState->m_pageInfo, (unsigned char*)& pageInfo, sizeof( pageInfo ) ); 1883141cc406Sopenharmony_ci ++( pState->m_numPages ); 1884141cc406Sopenharmony_ci 1885141cc406Sopenharmony_ci JPEG_CLEANUP: 1886141cc406Sopenharmony_ci jpeg_finish_decompress (&jpegCinfo.m_cinfo); 1887141cc406Sopenharmony_ci jpeg_destroy_decompress (&jpegCinfo.m_cinfo); 1888141cc406Sopenharmony_ci 1889141cc406Sopenharmony_ci if (pJpegLine) 1890141cc406Sopenharmony_ci free (pJpegLine); 1891141cc406Sopenharmony_ci 1892141cc406Sopenharmony_ci return ret; 1893141cc406Sopenharmony_ci } /* case JPEG */ 1894141cc406Sopenharmony_ci 1895141cc406Sopenharmony_ci case 0x08: 1896141cc406Sopenharmony_ci /* CCITT Group 4 Fax data */ 1897141cc406Sopenharmony_ci { 1898141cc406Sopenharmony_ci /* get a temp file 1899141cc406Sopenharmony_ci :TODO: 2006-04-18: Use TIFFClientOpen and do everything in RAM 1900141cc406Sopenharmony_ci */ 1901141cc406Sopenharmony_ci fTmp = tmpfile (); 1902141cc406Sopenharmony_ci fdTmp = fileno (fTmp); 1903141cc406Sopenharmony_ci 1904141cc406Sopenharmony_ci pTiff = TIFFFdOpen (fdTmp, "tempfile", "w"); 1905141cc406Sopenharmony_ci if (!pTiff) 1906141cc406Sopenharmony_ci { 1907141cc406Sopenharmony_ci DBG (1, "ProcessPageData: Error opening temp TIFF file"); 1908141cc406Sopenharmony_ci ret = SANE_STATUS_IO_ERROR; 1909141cc406Sopenharmony_ci goto TIFF_CLEANUP; 1910141cc406Sopenharmony_ci } 1911141cc406Sopenharmony_ci 1912141cc406Sopenharmony_ci /* create a TIFF file */ 1913141cc406Sopenharmony_ci width = ntohl (pState->m_pixelWidth); 1914141cc406Sopenharmony_ci height = ntohl (pState->m_pixelHeight); 1915141cc406Sopenharmony_ci TIFFSetField (pTiff, TIFFTAG_IMAGEWIDTH, width); 1916141cc406Sopenharmony_ci TIFFSetField (pTiff, TIFFTAG_IMAGELENGTH, height); 1917141cc406Sopenharmony_ci TIFFSetField (pTiff, TIFFTAG_BITSPERSAMPLE, 1); 1918141cc406Sopenharmony_ci TIFFSetField (pTiff, TIFFTAG_PHOTOMETRIC, 0); /* 0 is white */ 1919141cc406Sopenharmony_ci TIFFSetField (pTiff, TIFFTAG_COMPRESSION, 4); /* CCITT Group 4 */ 1920141cc406Sopenharmony_ci TIFFSetField (pTiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); 1921141cc406Sopenharmony_ci 1922141cc406Sopenharmony_ci TIFFWriteRawStrip (pTiff, 0, pState->m_buf.m_pBuf, 1923141cc406Sopenharmony_ci pState->m_buf.m_used); 1924141cc406Sopenharmony_ci 1925141cc406Sopenharmony_ci if (0 > TIFFRGBAImageOK (pTiff, tiffErrBuf)) 1926141cc406Sopenharmony_ci { 1927141cc406Sopenharmony_ci DBG (1, "ProcessPageData: %s\n", tiffErrBuf); 1928141cc406Sopenharmony_ci ret = SANE_STATUS_IO_ERROR; 1929141cc406Sopenharmony_ci goto TIFF_CLEANUP; 1930141cc406Sopenharmony_ci } 1931141cc406Sopenharmony_ci 1932141cc406Sopenharmony_ci /* allocate space for RGBA representation of image */ 1933141cc406Sopenharmony_ci numPixels = height * width; 1934141cc406Sopenharmony_ci DBG (20, "ProcessPageData: num TIFF RGBA pixels: %d\n", numPixels); 1935141cc406Sopenharmony_ci if (!(pTiffRgba = calloc (numPixels, sizeof (u_long)))) 1936141cc406Sopenharmony_ci { 1937141cc406Sopenharmony_ci ret = SANE_STATUS_NO_MEM; 1938141cc406Sopenharmony_ci goto TIFF_CLEANUP; 1939141cc406Sopenharmony_ci } 1940141cc406Sopenharmony_ci 1941141cc406Sopenharmony_ci /* make space in image buffer to store the results */ 1942141cc406Sopenharmony_ci imageBytes = width * height * 3; 1943141cc406Sopenharmony_ci ret |= AppendToComBuf (&pState->m_imageData, NULL, imageBytes); 1944141cc406Sopenharmony_ci if (ret) 1945141cc406Sopenharmony_ci goto TIFF_CLEANUP; 1946141cc406Sopenharmony_ci 1947141cc406Sopenharmony_ci /* get a pointer to the start of the output data */ 1948141cc406Sopenharmony_ci pOut = pState->m_imageData.m_pBuf 1949141cc406Sopenharmony_ci + pState->m_imageData.m_used - imageBytes; 1950141cc406Sopenharmony_ci 1951141cc406Sopenharmony_ci /* read RGBA image */ 1952141cc406Sopenharmony_ci DBG (20, "ProcessPageData: setting up read buffer\n"); 1953141cc406Sopenharmony_ci TIFFReadBufferSetup (pTiff, NULL, width * height * sizeof (u_long)); 1954141cc406Sopenharmony_ci DBG (20, "ProcessPageData: reading RGBA data\n"); 1955141cc406Sopenharmony_ci TIFFReadRGBAImageOriented (pTiff, width, height, pTiffRgba, 1956141cc406Sopenharmony_ci ORIENTATION_TOPLEFT, 0); 1957141cc406Sopenharmony_ci 1958141cc406Sopenharmony_ci /* loop over pixels */ 1959141cc406Sopenharmony_ci for (iPixel = 0; iPixel < numPixels; ++iPixel) 1960141cc406Sopenharmony_ci { 1961141cc406Sopenharmony_ci 1962141cc406Sopenharmony_ci *(pOut++) = TIFFGetR (pTiffRgba[iPixel]); 1963141cc406Sopenharmony_ci *(pOut++) = TIFFGetG (pTiffRgba[iPixel]); 1964141cc406Sopenharmony_ci *(pOut++) = TIFFGetB (pTiffRgba[iPixel]); 1965141cc406Sopenharmony_ci 1966141cc406Sopenharmony_ci } /* for iRow */ 1967141cc406Sopenharmony_ci 1968141cc406Sopenharmony_ci 1969141cc406Sopenharmony_ci 1970141cc406Sopenharmony_ci /* update info for this page */ 1971141cc406Sopenharmony_ci pageInfo.m_width = width; 1972141cc406Sopenharmony_ci pageInfo.m_height = height; 1973141cc406Sopenharmony_ci pageInfo.m_totalSize = pageInfo.m_width * pageInfo.m_height * 3; 1974141cc406Sopenharmony_ci pageInfo.m_bytesRemaining = pageInfo.m_totalSize; 1975141cc406Sopenharmony_ci 1976141cc406Sopenharmony_ci DBG( 1, "Process page data: page %d: TIFF image: %d x %d, %d bytes\n", 1977141cc406Sopenharmony_ci pState->m_numPages, width, height, pageInfo.m_totalSize ); 1978141cc406Sopenharmony_ci 1979141cc406Sopenharmony_ci ret |= AppendToComBuf( & pState->m_pageInfo, (unsigned char*)& pageInfo, sizeof( pageInfo ) ); 1980141cc406Sopenharmony_ci ++( pState->m_numPages ); 1981141cc406Sopenharmony_ci 1982141cc406Sopenharmony_ci TIFF_CLEANUP: 1983141cc406Sopenharmony_ci if (pTiff) 1984141cc406Sopenharmony_ci TIFFClose (pTiff); 1985141cc406Sopenharmony_ci if (fTmp) 1986141cc406Sopenharmony_ci fclose (fTmp); 1987141cc406Sopenharmony_ci if (pTiffRgba) 1988141cc406Sopenharmony_ci free (pTiffRgba); 1989141cc406Sopenharmony_ci return ret; 1990141cc406Sopenharmony_ci 1991141cc406Sopenharmony_ci } /* case CCITT */ 1992141cc406Sopenharmony_ci default: 1993141cc406Sopenharmony_ci /* this is not expected or very useful */ 1994141cc406Sopenharmony_ci { 1995141cc406Sopenharmony_ci DBG (1, "ProcessPageData: Unexpected compression flag %d\n", ntohl (pState->m_compression)); 1996141cc406Sopenharmony_ci ret = SANE_STATUS_IO_ERROR; 1997141cc406Sopenharmony_ci } 1998141cc406Sopenharmony_ci } /* switch */ 1999141cc406Sopenharmony_ci 2000141cc406Sopenharmony_ci return ret; 2001141cc406Sopenharmony_ci} /* ProcessPageData */ 2002141cc406Sopenharmony_ci 2003141cc406Sopenharmony_ci/***********************************************************/ 2004141cc406Sopenharmony_ci 2005141cc406Sopenharmony_civoid 2006141cc406Sopenharmony_ciJpegDecompInitSource (j_decompress_ptr cinfo) 2007141cc406Sopenharmony_ci/* Libjpeg decompression interface */ 2008141cc406Sopenharmony_ci{ 2009141cc406Sopenharmony_ci cinfo->src->bytes_in_buffer = 0; 2010141cc406Sopenharmony_ci 2011141cc406Sopenharmony_ci} /* JpegDecompInitSource */ 2012141cc406Sopenharmony_ci 2013141cc406Sopenharmony_ci/***********************************************************/ 2014141cc406Sopenharmony_ci 2015141cc406Sopenharmony_ciboolean 2016141cc406Sopenharmony_ciJpegDecompFillInputBuffer (j_decompress_ptr cinfo) 2017141cc406Sopenharmony_ci/* Libjpeg decompression interface */ 2018141cc406Sopenharmony_ci{ 2019141cc406Sopenharmony_ci struct JpegDataDecompState *pState = (struct JpegDataDecompState *) cinfo; 2020141cc406Sopenharmony_ci static const unsigned char eoiByte[] = { 2021141cc406Sopenharmony_ci 0xFF, JPEG_EOI 2022141cc406Sopenharmony_ci }; 2023141cc406Sopenharmony_ci 2024141cc406Sopenharmony_ci DBG (10, "JpegDecompFillInputBuffer: bytes remaining: %d\n", 2025141cc406Sopenharmony_ci pState->m_bytesRemaining); 2026141cc406Sopenharmony_ci 2027141cc406Sopenharmony_ci if (!pState->m_bytesRemaining) 2028141cc406Sopenharmony_ci { 2029141cc406Sopenharmony_ci 2030141cc406Sopenharmony_ci /* no input data available so return dummy data */ 2031141cc406Sopenharmony_ci cinfo->src->bytes_in_buffer = 2; 2032141cc406Sopenharmony_ci cinfo->src->next_input_byte = (const JOCTET *) eoiByte; 2033141cc406Sopenharmony_ci 2034141cc406Sopenharmony_ci } 2035141cc406Sopenharmony_ci else 2036141cc406Sopenharmony_ci { 2037141cc406Sopenharmony_ci 2038141cc406Sopenharmony_ci /* point to data */ 2039141cc406Sopenharmony_ci cinfo->src->bytes_in_buffer = pState->m_bytesRemaining; 2040141cc406Sopenharmony_ci cinfo->src->next_input_byte = (const JOCTET *) pState->m_pData; 2041141cc406Sopenharmony_ci 2042141cc406Sopenharmony_ci /* note that data is now gone */ 2043141cc406Sopenharmony_ci pState->m_bytesRemaining = 0; 2044141cc406Sopenharmony_ci 2045141cc406Sopenharmony_ci } /* if */ 2046141cc406Sopenharmony_ci 2047141cc406Sopenharmony_ci return TRUE; 2048141cc406Sopenharmony_ci 2049141cc406Sopenharmony_ci} /* JpegDecompFillInputBuffer */ 2050141cc406Sopenharmony_ci 2051141cc406Sopenharmony_ci/***********************************************************/ 2052141cc406Sopenharmony_ci 2053141cc406Sopenharmony_civoid 2054141cc406Sopenharmony_ciJpegDecompSkipInputData (j_decompress_ptr cinfo, long numBytes) 2055141cc406Sopenharmony_ci/* Libjpeg decompression interface */ 2056141cc406Sopenharmony_ci{ 2057141cc406Sopenharmony_ci DBG (10, "JpegDecompSkipInputData: skipping %ld bytes\n", numBytes); 2058141cc406Sopenharmony_ci 2059141cc406Sopenharmony_ci cinfo->src->bytes_in_buffer -= numBytes; 2060141cc406Sopenharmony_ci cinfo->src->next_input_byte += numBytes; 2061141cc406Sopenharmony_ci 2062141cc406Sopenharmony_ci} /* JpegDecompSkipInputData */ 2063141cc406Sopenharmony_ci 2064141cc406Sopenharmony_ci/***********************************************************/ 2065141cc406Sopenharmony_ci 2066141cc406Sopenharmony_civoid 2067141cc406Sopenharmony_ciJpegDecompTermSource (j_decompress_ptr __sane_unused__ cinfo) 2068141cc406Sopenharmony_ci/* Libjpeg decompression interface */ 2069141cc406Sopenharmony_ci{ 2070141cc406Sopenharmony_ci /* nothing to do */ 2071141cc406Sopenharmony_ci 2072141cc406Sopenharmony_ci} /* JpegDecompTermSource */ 2073141cc406Sopenharmony_ci 2074141cc406Sopenharmony_ci/***********************************************************/ 2075