#!/usr/bin/perl
# Final CUPS image/urf filter. Preserve every byte; group the first 44 bytes.
use strict;
use warnings;
use Errno qw(EINTR);

$SIG{PIPE} = 'IGNORE';
$SIG{TERM} = sub { exit 0; };

sub fail {
    my ($message) = @_;
    print STDERR "ERROR: HP178nw header buffer: $message\n";
    exit 1;
}

(@ARGV == 5 || @ARGV == 6) or fail('invalid CUPS filter arguments');
if (@ARGV == 6) {
    open(STDIN, '<', $ARGV[5]) or fail('cannot open the supplied print file');
}
binmode(STDIN) or fail('cannot set binary input');
binmode(STDOUT) or fail('cannot set binary output');

my $header = '';
while (length($header) < 44) {
    my $part = '';
    my $count = sysread(STDIN, $part, 44 - length($header));
    if (!defined($count)) {
        next if $! == EINTR;
        fail('cannot read raster header');
    }
    $count > 0 or fail('incomplete raster header; no data forwarded');
    $header .= $part;
}
substr($header, 0, 8) eq "UNIRAST\0"
    or fail('expected Apple Raster input; no data forwarded');

# A blocking pipe write of 44 bytes fits within PIPE_BUF. Request the entire
# header in one syscall; never deliberately split it into the four-byte sync.
my $written;
do { $written = syswrite(STDOUT, $header, 44); }
    while (!defined($written) && $! == EINTR);
defined($written) && $written == 44 or fail('cannot forward complete header');
my $total = 44;

while (1) {
    my $buffer = '';
    my $count = sysread(STDIN, $buffer, 65536);
    if (!defined($count)) {
        next if $! == EINTR;
        fail('cannot read raster data');
    }
    last if $count == 0;
    my $offset = 0;
    while ($offset < $count) {
        my $sent = syswrite(STDOUT, $buffer, $count - $offset, $offset);
        if (!defined($sent)) {
            next if $! == EINTR;
            fail('cannot forward raster data');
        }
        $sent > 0 or fail('output closed');
        $offset += $sent;
    }
    $total += $count;
}
print STDERR "DEBUG: HP178nw header buffer: first write 44 bytes; forwarded $total unchanged bytes.\n";
exit 0;
