This is main.m in view mode; [Download] [Up]
static char *ID = {"By:Kevin Peckover -- Dec.1994 Ottawa, Canada."};
#import <stdio.h>
#import <strings.h>
#import <bsd/libc.h>
#import <sys/types.h>
#import <servers/netname.h>
#import <mach/message.h>
#import <mach/mach_init.h>
#import <mach/mach_interface.h>
#import <mach/cthreads.h>
#import <mach/mach_error.h>
#import <dpsclient/dpsNeXT.h>
#import <dpsclient/dpsclient.h>
#import <windowserver/printmessage.h>
#import <appkit/NXBitmapImageRep.h>
#import <appkit/Application.h>
#import <appkit/tiff.h>
#import "tiff.h"
#define TIFF_SERVER_NAME "tiff_fd"
#define HEADDER_SIZE 1024
#define MAX_DEVICE_NAME_LEN 256
#define MAX_FILE_PATH 256
#define TIFFSERVER_NAME "TIFFServer"
#define DEF_DEVICE_NAME "NeXTLaser-400"
#define TIME_TO_WAIT_FOR_ACTIVE_PORT 5 // seconds
#define TIME_OUTOF_RENDEREDPAGE_FROM_WINDOWSERVER 20 // seconds
// First integer is number of pages, second int is to do with double sided
// pages or something like that.
#define PS_PAGES_SEARCH_FORMAT "%%%%Pages:%d%*s"
#define PAGES_MSG_ID 666
typedef struct ReplyMsg {
msg_header_t h;
msg_type_t t;
} replyMsg;
typedef struct _ChildParam {
char *basename;
int compression;
} ChildParam;
port_t tiff_look_up()
// This function checks for an advertized Mach Port.
{
port_t port;
kern_return_t ret;
// Use "" instead of "*", so we look only on this machine.
ret = netname_look_up(name_server_port, "", TIFF_SERVER_NAME, &port);
if (ret != KERN_SUCCESS) return PORT_NULL;
return port;
}
long rawTIFFData(NXStream *tiffFile,int imageNum)
// Function sets file pointer at begining of data and returns the number
// of bytes in that data block.
{
TIFFHeader TIFFhead;
// TIFFDirEntry seledtedDir;
// unsigned short itemSize = 0;
//Get TIFF Headder
NXSeek(tiffFile, 0, NX_FROMSTART);
NXRead(tiffFile, &TIFFhead.tiff_magic, sizeof(TIFFhead.tiff_magic));
NXRead(tiffFile, &TIFFhead.tiff_version, sizeof(TIFFhead.tiff_version));
NXRead(tiffFile, &TIFFhead.tiff_diroff, sizeof(TIFFhead.tiff_diroff));
//WARNING: This is a total hack! It works for G3, Probably G4, and probably
// any TIFF with one bitmap in it that has been generated by the
// NXBitmapImageRep class. This algorithm has only been tested with the
// G3 output from the NXBitmapImageRep.
//
// Image data will follow immediately after the TIFFhead. The image
// directory is located at the end if the bitmap. File structure
// for one TIFF only is:
//
// 2 bytes - TIFFhead.tiff_magic
// 2 bytes - TIFFhead.tiff_version
// 4 bytes - TIFFhead.tiff_diroff <- to first directoy
// n bytes - image data
// 1 bytes - number of directories (or is it two?)
// 2 bytes - seledtedDir.tdir_tag
// 2 bytes - seledtedDir.tdir_type
// m bytes - not exactly sure from here...
//
// n = TIFFhead.tiff_diroff - 2 bytes
//
// NOTE: TIFFhead.tiff_diroff is offset from the first byte of the
// offset number. NOT the byte following that number.
//
// A correct treatment of this issue of stripping bitmap data out of a
// TIFF file would be MUCH appreciated.
//
// I would think that the 3 should be a one or a two but...it isn't
return (TIFFhead.tiff_diroff-sizeof(TIFFhead.tiff_diroff)-3);
};
void server_loop(port_t port, char *baseFileName,
int compression)
{
id renderingImage;
int pagesPrinted=0, pagesExpected = -1;
NXPrintPageMessage msg;
replyMsg reply;
kern_return_t ret;
NXStream *stream ;
FILE *out;
BOOL getNextPage = TRUE;
char fname[MAX_FILE_PATH];
// The reply message which does not change
reply.h.msg_simple = TRUE;
reply.h.msg_size = sizeof(replyMsg);
reply.h.msg_type = MSG_TYPE_NORMAL ;
reply.h.msg_id = NX_PRINTPAGEMSGID;
reply.t.msg_type_name = MSG_TYPE_INTEGER_32 ;
reply.t.msg_type_size = 32;
reply.t.msg_type_number = 0;
reply.t.msg_type_inline = TRUE;
reply.t.msg_type_longform = FALSE;
do {
msg.msgHeader.msg_local_port = port;
msg.msgHeader.msg_size = sizeof(NXPrintPageMessage);
ret = msg_receive(&msg.msgHeader
, RCV_TIMEOUT, TIME_OUTOF_RENDEREDPAGE_FROM_WINDOWSERVER*1000);
switch(ret) {
case RCV_SUCCESS:
switch(msg.msgHeader.msg_id) {
case PAGES_MSG_ID:
if(pagesExpected < 0) {
pagesExpected = (int)msg.msgHeader.msg_unused ;
}
break;
case NX_PRINTPAGEMSGID:
sprintf(fname,"%s.%.3d", baseFileName, msg.pageNum);
if((out=fopen(fname,"wb")))
{
NXStream *tmpFile;
tmpFile = NXOpenMemory(0, 0, NX_READWRITE);
stream = NXOpenFile(fileno(out), NX_WRITEONLY);
renderingImage = [[NXBitmapImageRep alloc]
initData:msg.printerData
pixelsWide:(int)msg.pixelsWide
pixelsHigh:(int)msg.pixelsHigh
bitsPerSample:msg.bitsPerSample
samplesPerPixel:msg.samplesPerPixel
hasAlpha:NO
isPlanar:msg.isPlanar
colorSpace:msg.colorSpace
bytesPerRow:0
bitsPerPixel:0
];
[renderingImage writeTIFF:tmpFile
usingCompression:compression];
[renderingImage free];
NXWrite(stream, tmpFile->buf_ptr, rawTIFFData(tmpFile,1));
NXClose(stream);
NXCloseMemory(tmpFile, NX_FREEBUFFER);
fclose(out);
} else fprintf(stderr,"** Could Not open file %s\n", fname);
vm_deallocate(task_self(),
(vm_address_t)msg.printerData,
(vm_size_t)(msg.samplesPerPixel*msg.pixelsWide*
msg.pixelsHigh*msg.bitsPerSample/8));
// Send the reply to Window Server that we are ready for next page
reply.h.msg_local_port = port ; //send to
reply.h.msg_remote_port = msg.msgHeader.msg_remote_port; // sent from
reply.h.msg_id = NX_PRINTPAGEMSGID;
ret = msg_send(&reply.h, MSG_OPTION_NONE, 0);
switch(ret) {
case SEND_SUCCESS: // Continue in loop for next page
pagesPrinted++;
if(pagesExpected>0)
if(pagesPrinted >= pagesExpected) getNextPage = FALSE;
break;
case SEND_INVALID_PORT: // There is Probably no more pages
getNextPage = FALSE;
break;
default:
mach_error("TIFFServer:** SEND error to Window Server.\n", ret);
};
break;
}
break;
case RCV_TIMED_OUT:
getNextPage = FALSE;
return ; // exit receive loop completely with no error message
default:
mach_error("TIFFServer:** RECV error from Window Server.\n", ret);
};
// 'pagesExpected < 0' flags that expected pages are unknown
} while (getNextPage && (pagesExpected>0 || pagesExpected < 0)) ;
}
int TIFFReceptorMain(ChildParam *param)
{
port_t server_port;
kern_return_t r;
if(!strstr(ID, "Peckover")) exit(1);
r = port_allocate(task_self(), &server_port);
if (r != KERN_SUCCESS) {
mach_error("port_allocate failed",r);
return 0;
}
r = netname_check_in(name_server_port, TIFF_SERVER_NAME,
PORT_NULL, server_port);
if (r != KERN_SUCCESS) {
mach_error("netname_check_in failed ",r);
return 0;
}
server_loop(server_port, param->basename, param->compression);
return 1;
}
extern void DPSMyTextProc(
DPSContext ctxt,
const char *buf,
long unsigned int count )
{
fprintf(stderr,"Context:\t%s\n", ctxt->priv);
fprintf(stderr,"Message:\t%s\n", buf);
};
extern void DPSMyErrorProc(
DPSContext ctxt,
DPSErrorCode errorCode,
long unsigned int arg1,
long unsigned int arg2 )
{
char *string = (char *)arg1;
string[arg2] = 0;
fprintf(stderr,"PS_ERROR: Context:\t%s\t", ctxt->priv);
fprintf(stderr,"ErrCode:\t%d\t", errorCode);
fprintf(stderr,"A1:\t%s\n", string);
};
void usage(char *progName) {
fprintf(stderr,"Usage: %s [Pwhrg] <infn> <outfn>\n %s %s %s %s %s %s\n",
progName,
"[-w<0|1|2>]\t width of 0-215 mm, 1-255 mm, 2-303 mm (def=0)\n",
"[-h<0|1|2>]\t hight of 0-281 mm, 1-297 mm, 2-364 mm (def=0)\n",
"[-r<0|1>]\t vert.res.of 0-98 lpi or 1-196 lpi (def=0)\n",
"[-g<0|1>]\t comp.type 0-G3 Fax, 1-G4 Fax (def=0)\n",
"<infn>\t\t name of PostScript file to convert\n",
"<outfn>\t base name for G3/4 files\n");
exit(1);
};
void main(int argc, char *argv[])
{
port_t server;
DPSContext toWindowServer;
int pages = 0;
time_t checkInTime, currTime;
char line[BUFSIZ], c,
device_name[MAX_DEVICE_NAME_LEN] = {DEF_DEVICE_NAME},
server_name[MAX_DEVICE_NAME_LEN] = {TIFF_SERVER_NAME} ;
FILE *psin = 0;
int width = 1728, height = 2166, topMargin = 0,
leftMargin = 0, vFaxDpi = 98,
compType = NX_TIFF_COMPRESSION_CCITTFAX3;
const float hFaxDpi = 204.1451;
cthread_t proc=0;
ChildParam param;
msg_header_t send;
kern_return_t ret;
port_t parentPort;
while ((c = getopt(argc, argv, "w:h:r:g:")) != -1)
switch (c) {
case 'w':
width = (atoi(optarg)==1)?2048:(atoi(optarg)==2)?2432:1728 ;
break;
case 'h':
height = (atoi(optarg)==1)?2292:(atoi(optarg)==2)?2810:2166 ;
break;
case 'r':
vFaxDpi = (atoi(optarg)==0)?98:196 ;
break;
case 'g':
compType = (atoi(optarg)==1)
?NX_TIFF_COMPRESSION_CCITTFAX4
:NX_TIFF_COMPRESSION_CCITTFAX3 ;
break;
case '?':
usage(argv[0]);
};
if (vFaxDpi == 98) height /= 2;
switch(argc - optind){
case 1:
psin = stdin ;
break;
case 2:
if (!(psin = fopen(argv[argc-2],"r"))) {
fprintf(stderr,"** Could not open \'%s\'.\n", argv[argc-2]);
exit(1);
};
break;
default:
usage(argv[0]);
}
// Run the child here.
param.basename = argv[argc-1];
param.compression = compType;
proc=cthread_fork((cthread_fn_t)TIFFReceptorMain,(any_t)¶m);
// Check if the server is up
time(&checkInTime);
do {
server = tiff_look_up();
time(&currTime);
} while (TIME_TO_WAIT_FOR_ACTIVE_PORT
> difftime(checkInTime, currTime)
&& server == PORT_NULL);
if (server == PORT_NULL)
{
fprintf(stderr, "** Couldn't find the Tiff server.\n");
fclose(psin);
if(proc>0) {
thread_suspend((thread_t)proc);
cthread_abort(proc);
cthread_join(proc);
}
exit(5);
}
//Communicating with Window Server
toWindowServer = DPSCreateContext(NULL, NULL,
(DPSTextProc)DPSMyTextProc,
(DPSErrorProc)DPSMyErrorProc) ;
DPSSetContext(toWindowServer) ;
DPSWaitContext(toWindowServer) ;
// Sifft through Comments and insert our headder to send image to port
// immediately after them.
do {
fgets(line, BUFSIZ, psin) ;
sscanf(line, PS_PAGES_SEARCH_FORMAT, &pages);
DPSPrintf(toWindowServer,"%s", line) ;
} while (strstr(line,"%%")||strstr(line,"%!"));
// This is the next line after the comments. (or mabe within the comments)
// put mach port description here.
DPSPrintf(toWindowServer,"\n");
DPSPrintf(toWindowServer,"/width %d def ", width);
DPSPrintf(toWindowServer,"/height %d def ", height);
DPSPrintf(toWindowServer,"/topdots %d def ", topMargin);
DPSPrintf(toWindowServer,"/leftdots %d def ", leftMargin);
DPSPrintf(toWindowServer,
"width height [ leftdots topdots width leftdots sub height topdots sub]");
DPSPrintf(toWindowServer,
"[%f 72 div 0 0 %d -72 div leftdots height topdots sub] () ",
hFaxDpi, vFaxDpi);
DPSPrintf(toWindowServer,"(%s) %s machportdevice \n\n",
server_name, device_name);
//Continue sending the rest of the postScript
while(!feof(psin))
{
fgets(line, BUFSIZ, psin) ;
if(pages<=0)
sscanf(line, PS_PAGES_SEARCH_FORMAT, &pages);
DPSPrintf(toWindowServer,"%s", line) ;
};
DPSFlushContext(toWindowServer);
DPSSendEOF(toWindowServer);
// Send the number of pages message for child to expect
ret = port_allocate(task_self(), &parentPort);
if (ret == KERN_SUCCESS) {
send.msg_unused = (unsigned int)pages;
send.msg_simple = TRUE;
send.msg_size = sizeof(msg_header_t);
send.msg_type = MSG_TYPE_NORMAL ;
send.msg_local_port = parentPort; //send to
send.msg_remote_port = server; // sent from
send.msg_id = PAGES_MSG_ID;
ret = msg_send(&send, MSG_OPTION_NONE, 0);
switch(ret) {
case SEND_SUCCESS: // Continue in loop for next page
case SEND_INVALID_PORT: // printing has finished by time-out
break;
default:
mach_error("TIFFServer:** SEND error to Window Server", ret);
};
ret=port_deallocate(task_self(), parentPort);
if (ret != KERN_SUCCESS) {
mach_error("port_deallocate", ret);
exit(1);
}
} else mach_error("port_allocate",ret);
// Wait here for child to finish
cthread_join(proc);
DPSDestroyContext(toWindowServer);
fclose(psin);
exit(0);
};
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.