TestPrinterClass.c

// File TestPrinterClass.c
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <types.h>
 
#include <gestalt.h>
#include <errors.h>
 
#ifndef __DIALOGS__
#include <Dialogs.h>
#endif
#ifndef __EVENTS__
#include <Events.h>
#endif
#ifndef __FILES__
#include <Files.h>
#endif
#ifndef __DEVICES__
#include <Devices.h>
#endif
#include <textedit.h>
 
#ifndef __NUMBERFORMATTING__
#include <numberformatting.h>
#endif
 
#include "TestPrinterClass.h"
#include "SafeNameRegistry.h"
 
enum {
    kUSBNoErr                   = 0,
    kUSBNoTran                  = 0,
    kUSBNoDelay                 = 0,
    kUSBPending                 = 1,                            /* */
                                                                /* USB assigned error numbers in range -6900 .. -6999 */
    kUSBBaseError               = -7000,                        /* */
                                                                /* USB Services Errors */
    kUSBInternalErr             = -6999,                        /* Internal error */
    kUSBUnknownDeviceErr        = -6998,                        /*  device ref not recognised */
    kUSBUnknownPipeErr          = -6997,                        /*  Pipe ref not recognised */
    kUSBTooManyPipesErr         = -6996,                        /*  Too many pipes */
    kUSBIncorrectTypeErr        = -6995,                        /*  Incorrect type */
    kUSBRqErr                   = -6994,                        /*  Request error */
    kUSBUnknownRequestErr       = -6993,                        /*  Unknown request */
    kUSBTooManyTransactionsErr  = -6992,                        /*  Too many transactions */
    kUSBAlreadyOpenErr          = -6991,                        /*  Already open */
    kUSBNoDeviceErr             = -6990,                        /*  No device */
    kUSBDeviceErr               = -6989,                        /*  Device error */
    kUSBOutOfMemoryErr          = -6988,                        /*  Out of memory */
    kUSBNotFound                = -6987,                        /*  Not found */
    kUSBPBVersionError          = -6986,                        /*  Wrong pbVersion */
    kUSBPBLengthError           = -6985,                        /*  pbLength too small */
    kUSBCompletionError         = -6984,                        /*  no completion routine specified */
    kUSBFlagsError              = -6983,                        /*  Flags not zeroed */
    kUSBAbortedError            = -6982,                        /*  Pipe aborted */
    kUSBNoBandwidthError        = -6981,                        /*  Not enough bandwidth available */
    kUSBPipeIdleError           = -6980,                        /*  Pipe is Idle, it will not accept transactions */
    kUSBPipeStalledError        = -6979,                        /*  Pipe has stalled, error needs to be cleared */
    kUSBUnknownInterfaceErr     = -6978,                        /*  Interface ref not recognised */
                                                                /* */
                                                                /* USB Manager Errors */
    kUSBBadDispatchTable        = -6950,                        /* Improper driver dispatch table */
                                                                /* */
                                                                /* Hardware Errors */
                                                                /* Note pipe stalls are communication */
                                                                /* errors. The affected pipe can not */
                                                                /* be used until USBClearPipeStallByReference  */
                                                                /* is used */
                                                                /* kUSBEndpointStallErr is returned in */
                                                                /* response to a stall handshake */
                                                                /* from a device. The device has to be */
                                                                /* cleared before a USBClearPipeStallByReference */
                                                                /* can be used */
    kUSBLinkErr                 = -6916,
    kUSBCRCErr                  = -6915,                        /*  Pipe stall, bad CRC */
    kUSBBitstufErr              = -6914,                        /*  Pipe stall, bitstuffing */
    kUSBDataToggleErr           = -6913,                        /*  Pipe stall, Bad data toggle */
    kUSBEndpointStallErr        = -6912,                        /*  Device didn't understand */
    kUSBNotRespondingErr        = -6911,                        /*  Pipe stall, No device, device hung */
    kUSBPIDCheckErr             = -6910,                        /*  Pipe stall, PID CRC error */
    kUSBWrongPIDErr             = -6909,                        /*  Pipe stall, Bad or wrong PID */
    kUSBOverRunErr              = -6908,                        /*  Packet too large or more data than buffer */
    kUSBUnderRunErr             = -6907,                        /*  Less data than buffer */
    kUSBRes1Err                 = -6906,
    kUSBRes2Err                 = -6905,
    kUSBBufOvrRunErr            = -6904,                        /*  Host hardware failure on data in, PCI busy? */
    kUSBBufUnderRunErr          = -6903,                        /*  Host hardware failure on data out, PCI busy? */
    kUSBNotSent1Err             = -6902,                        /*  Transaction not sent */
    kUSBNotSent2Err             = -6901                         /*  Transaction not sent */
};
 
#define SECONDS( n )            (n*60)
#define PROGRAM             "DropPrint¥USB"
#define kStrPrinterClass    PROGRAM ": "
 
enum {
    kStatusDialog = 513
};
 
enum {
    kStatusBarItem = 1
};
 
 
char                *outbuffer = NULL;
IOParam         fsendblk;
unsigned long   fUSBReference;
char                *filename;
DialogPtr       gStatusDlg;
 
void        dump( char *p, long count );
OSErr       sendfile( char *sourcefile, long buffersize );
OSStatus OpenClassDriver( char *which_printer );
void        showstatus( long current, long endfile );
 
void
dump( char *p, long count )
{
    char    *q, *e, *f,
            *d, line[64+32+1+1];    //2bytes per hex, 1 byte per char, 1 tab, 1 nul
    short   nibble;
 
    while ( count > 0 )
    {
        q = p;                                  // start of line
        e = p + 32;                             // proposed end of line
        f = p + (count > 32? 32: count);    // actual end of line
        d = line;
        //
        //  standard hex dump
        //
        for ( ; count > 0 && p < e; ++p, --count )
        {
            nibble = (*p >> 4) & 0x0F;
            *d++ = nibble + (nibble > 9? 'A' - 10:'0');
            nibble = *p & 0x0F;
            *d++ = nibble + (nibble > 9? 'A' - 10:'0');
        }
        for ( ; p < e; ++p )
        {
            *d++ = ' ';
            *d++ = ' ';
        }
        *d++ = '\t';
        //
        //  ascii sidebar
        //
        for ( p = q; p < f; ++p )
            *d++ = *p < ' ' || *p >= 0x7F? '.': *p;
        *d = '\0';
        fprintf( stderr, "%s\n", line );
    }
}
 
OSStatus
OpenClassDriver( char *which_printer )
{
    Str255          driverName;     // unit table driver name
    OSStatus            err = -192;     // resNotFound
    RegEntryID      self;
    unsigned long   length;
    
    
    fsendblk.ioRefNum = -1;                 // preload our IOParms in engvars
    fsendblk.ioResult = 0;
    fsendblk.ioCompletion = 0L;
 
    err = SafeRegistryEntryIDInit( &self );
    if ( err == noErr )
    {
    
        err = SafeRegistryCStrEntryLookup( nil, which_printer, &self );
 
        length = sizeof(driverName);
        if ( err == noErr )
            err = SafeRegistryPropertyGet( &self, "drvrOut", &driverName, &length );
        if ( err == noErr )
            err = OpenDriver( driverName, &fsendblk.ioRefNum );
 
        length = sizeof(fUSBReference);
        if ( err == noErr )
            err = SafeRegistryPropertyGet( &self, "privateData", &fUSBReference, &length );
 
        SafeRegistryEntryIDDispose(&self);
    }
 
    return err;
}
 
void
showstatus( long current, long endfile )
{
    GrafPtr oldport;
    Rect        r;
    Handle  h;
    short       type;
    long        width;
    char        info[526];
    
    GetPort( &oldport );
    SetPort( gStatusDlg );
    GetDialogItem( gStatusDlg, kStatusBarItem, &type, &h, &r );
    
    // we have, width/ (r.right - r.left) == current/endfile
    width = current *(r.right - r.left);
    width /= endfile;
    
    FrameRect( &r );
 
    InsetRect( &r, 1, 1 );
    sprintf( info, "%ld of %ld", current, endfile );
    TETextBox( info, strlen(info), &r, teJustCenter );
 
    r.right = width + r.left;
    InvertRect( &r );
    
    SetPort( oldport );
}
 
OSErr
sendfile( char *sourcefile, long buffersize )
{
    FILE                *fin = fopen( sourcefile, "rb" );
    long                count;
    EventRecord     e;
    OSStatus            err;
    long                eoffin; // length of input file
    
    gStatusDlg = GetNewDialog( kStatusDialog, nil, (WindowPtr)-1);
 
    if ( !fin )
        err = fnfErr;       // cant open file
    else
    {
        fseek( fin, 0, 2 /*fsFromEnd*/ );
        eoffin = ftell( fin );
        fseek( fin, 0, 0 /*fsFromStart*/ );
        do {
            count = fread( outbuffer, sizeof(char), buffersize, fin );
            if ( count <= 0 )
                break;
        //  dump( outbuffer, count );
 
            fsendblk.ioBuffer = outbuffer;
            fsendblk.ioReqCount = count;
            err = PBWriteAsync( (ParamBlockRec*) &fsendblk );
            if ( err != noErr )
                break;
            showstatus( ftell( fin ), eoffin );
 
            // wait for i/o to complete
            while ( fsendblk.ioResult == 1 )
            {
                WaitNextEvent( keyDownMask, &e, 0, NULL );
                if (e.what == keyDown && e.modifiers & cmdKey) {
                    if ( (e.message & charCodeMask) == '.' )
                        break;
                }
            }
            if ( fsendblk.ioResult != noErr )
                break;
            // if user canceled, exit the download
            WaitNextEvent( keyDownMask, &e, 0, NULL );
            
            if (e.what == keyDown && e.modifiers & cmdKey) {
                if ( (e.message & charCodeMask) == '.' )
                    break;
            }
            
        } while ( count > 0 );
    
        DisposeDialog(gStatusDlg);
        if ( err == noErr && fsendblk.ioResult != noErr )
            err = fsendblk.ioResult;
        fclose( fin );
    }
    
    return err;
}
 
OSErr
sendusb( char *printer_name, char *sourcefile, long blocksize, int repeat_count )
{
    OSStatus err = noErr;
    outbuffer = (char *) malloc( blocksize );
    memset( &fsendblk, 0, sizeof(fsendblk) );
    
    if ( !outbuffer )
        err = iMemFullErr;  // memfull error
    if ( err == noErr )
        err = OpenClassDriver( printer_name );
    if ( err == noErr )
    {
        for ( ; err == noErr && repeat_count > 0; --repeat_count )
            err = sendfile( sourcefile, blocksize );
 
        if ( err != noErr )
            KillIO( fsendblk.ioRefNum );
            
        if ( fsendblk.ioRefNum != -1 )
            CloseDriver(fsendblk.ioRefNum);
    }
    if ( outbuffer )
        free( outbuffer );
    
    if ( err != noErr )
    {
        unsigned char *p;
        int             slen;
        switch ( err )
        {   
            case  iMemFullErr:                      p = "\p" PROGRAM "Not enough memory. (Increase App heap, or use smaller block)"; break;
            case    kUSBInternalErr:                    p = "\p" kStrPrinterClass "Internal error"; break;
            case    kUSBUnknownDeviceErr:           p = "\p" kStrPrinterClass "Unknown device"; break;
            case    kUSBUnknownPipeErr:                 p = "\p" kStrPrinterClass "Unknown pipe"; break;
            case    kUSBTooManyPipesErr:                p = "\p" kStrPrinterClass "Too many pipes"; break;
            case    kUSBIncorrectTypeErr:           p = "\p" kStrPrinterClass "Incorrect type"; break;
            case    kUSBRqErr:                          p = "\p" kStrPrinterClass "Request error"; break;
            case    kUSBUnknownRequestErr:          p = "\p" kStrPrinterClass "Unknown request"; break;
            case    kUSBTooManyTransactionsErr: p = "\p" kStrPrinterClass "Too many transactions"; break;
            case    kUSBAlreadyOpenErr:             p = "\p" kStrPrinterClass "Already open"; break;
            case    kUSBNoDeviceErr:                    p = "\p" kStrPrinterClass "No device"; break;
            case    kUSBDeviceErr:                      p = "\p" kStrPrinterClass "Device error"; break;
            case    kUSBOutOfMemoryErr:             p = "\p" kStrPrinterClass "Out of memory"; break;
            case    kUSBNotFound:                       p = "\p" kStrPrinterClass "Not found"; break;
            case    kUSBLinkErr:                        p = "\p" kStrPrinterClass "Link Err"; break;
            case    kUSBCRCErr:                         p = "\p" kStrPrinterClass "Comms/Device err, bad CRC";  break;      
            case    kUSBBitstufErr:                 p = "\p" kStrPrinterClass "Comms/Device err, bitstuffing"; break;       
            case    kUSBDataToggleErr:              p = "\p" kStrPrinterClass "Comms/Device err, Bad data toggle"; break;       
            case    kUSBEndpointStallErr:           p = "\p" kStrPrinterClass "Device didn't understand"; break;        
            case    kUSBNotRespondingErr:           p = "\p" kStrPrinterClass "No device, device hung"; break;      
            case    kUSBPIDCheckErr:                    p = "\p" kStrPrinterClass "Comms/Device err, PID CRC error"; break;     
            case    kUSBWrongPIDErr:                    p = "\p" kStrPrinterClass "Comms/Device err, Bad or wrong PID"; break;      
            case    kUSBOverRunErr:                 p = "\p" kStrPrinterClass "Packet too large or more data than buffer"; break;       
            case    kUSBUnderRunErr:                    p = "\p" kStrPrinterClass "Less data than buffer"; break;       
            case    kUSBRes1Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;     
            case    kUSBRes2Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;     
            case    kUSBBufOvrRunErr:                   p = "\p" kStrPrinterClass "Buffer over run error"; break;       
            case    kUSBBufUnderRunErr:             p = "\p" kStrPrinterClass "Buffer under run error"; break;      
            case    kUSBNotSent1Err:                    p = "\p" kStrPrinterClass "Transaction not sent1"; break;       
            case    kUSBNotSent2Err:                    p = "\p" kStrPrinterClass "Transaction not sent2"; break;   
            default:
                p = "\p" kStrPrinterClass "Unknown error nnnnnnnn";
                NumToString( err, p + *p - 8 );
                slen = *(p + *p - 8);
                *(p + *p - 8) = ' ';
                *p += slen - 8;
                break;
        }
        
        ParamText( p, nil, nil, nil );
        StopAlert( 768, nil );
        err = noErr;
    }
    return err;
}
 
/* eof */