Initial commit as release 1.1.0

This commit is contained in:
2026-02-14 11:07:25 -05:00
parent 6b49566e58
commit a6331f7fed
141 changed files with 50383 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2013 Peter De Wachter
//
// brlaser is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// brlaser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
#ifndef BLOCK_H
#define BLOCK_H
#include <assert.h>
#include <stdio.h>
#include <vector>
class block {
public:
block(): line_bytes_(0) {
lines_.reserve(max_lines_per_block_);
}
bool empty() const {
return line_bytes_ == 0;
}
void add_line(std::vector<uint8_t> &&line) {
assert(!line.empty());
assert(line_fits(line.size()));
line_bytes_ += line.size();
lines_.emplace_back(line);
}
bool line_fits(unsigned size) {
return lines_.size() != max_lines_per_block_
&& line_bytes_ + size < max_block_size_;
}
void flush(FILE *f) {
if (!empty()) {
fprintf(f, "%dw%c%c",
line_bytes_ + 2, 0,
static_cast<int>(lines_.size()));
for (auto &line : lines_) {
fwrite(line.data(), 1, line.size(), f);
}
line_bytes_ = 0;
lines_.clear();
}
}
private:
static const unsigned max_block_size_ = 16350;
static const unsigned max_lines_per_block_ = 128;
std::vector<std::vector<uint8_t>> lines_;
int line_bytes_;
};
#endif // BLOCK_H

View File

@@ -0,0 +1,225 @@
// A quick-and-dirty tool to convert print files back to pbm images.
//
// Copyright 2013 Peter De Wachter
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <algorithm>
#include <exception>
#include <vector>
#include <string>
namespace {
const size_t MAX_LINE_SIZE = 2000;
FILE *in_file;
std::vector<std::vector<uint8_t>> page;
std::vector<uint8_t> line;
size_t line_offset;
class unexpected_eof: public std::exception {
public:
virtual const char *what() const noexcept {
return "Unexpected EOF";
}
};
class line_overflow: public std::exception {
public:
virtual const char *what() const noexcept {
return "Unreasonable long line, aborting";
}
};
uint8_t get() {
int ch = getc(in_file);
if (ch < 0)
throw unexpected_eof();
return ch;
}
unsigned read_overflow() {
uint8_t ch;
unsigned sum = 0;
do {
ch = get();
sum += ch;
} while (ch == 255);
return sum;
}
void read_repeat(uint8_t cmd) {
uint16_t offset = (cmd >> 5) & 3;
if (offset == 3)
offset += read_overflow();
uint16_t count = cmd & 31;
if (count == 31)
count += read_overflow();
count += 2;
uint8_t data = get();
size_t end = line_offset + offset + count;
if (end > line.size()) {
if (end > MAX_LINE_SIZE)
throw line_overflow();
line.resize(end);
}
line_offset += offset;
std::fill_n(line.begin() + line_offset, count, data);
line_offset += count;
}
void read_substitute(uint8_t cmd) {
uint16_t offset = (cmd >> 3) & 15;
if (offset == 15)
offset += read_overflow();
uint16_t count = cmd & 7;
if (count == 7)
count += read_overflow();
count += 1;
size_t end = line_offset + offset + count;
if (end > line.size()) {
if (end > MAX_LINE_SIZE)
throw line_overflow();
line.resize(end);
}
line_offset += offset;
std::generate_n(line.begin() + line_offset, count, get);
line_offset += count;
}
void read_edit() {
int8_t cmd = get();
if (cmd < 0) {
read_repeat(cmd);
} else {
read_substitute(cmd);
}
}
void read_line() {
uint8_t num_edits = get();
if (num_edits == 255) {
line.clear();
} else {
line_offset = 0;
for (int i = 0; i < num_edits; ++i) {
read_edit();
}
}
page.push_back(line);
}
void read_block() {
unsigned count = get();
count = count * 256 + get();
for (unsigned i = 0; i < count; ++i) {
read_line();
}
}
bool read_page() {
bool in_esc = false;
int ch;
page.clear();
line.clear();
while ((ch = getc(in_file)) >= 0) {
if (ch == '\f') {
break;
} else if (ch == 033) {
in_esc = true;
} else if (in_esc && ch == 'w') {
read_block();
} else if (in_esc && (ch >= 'A' && ch <= 'Z')) {
in_esc = false;
}
}
return !page.empty();
}
void write_pnm(FILE *f) {
size_t height = page.size();
size_t width = 0;
for (auto &l : page) {
width = std::max(width, l.size());
}
fprintf(f, "P4 %zd %zd\n", width * 8, height);
std::vector<uint8_t> empty(width);
for (auto &l : page) {
fwrite(l.data(), 1, l.size(), f);
fwrite(empty.data(), 1, width - l.size(), f);
}
}
} // namespace
int main(int argc, char *argv[]) {
const char *in_filename;
std::string out_prefix;
if (argc > 2) {
in_filename = argv[1];
out_prefix = argv[2];
} else if (argc > 1) {
in_filename = argv[1];
out_prefix = argv[1];
} else {
in_filename = nullptr;
out_prefix = "page";
}
if (in_filename) {
in_file = fopen(in_filename, "rb");
if (!in_file) {
fprintf(stderr, "Can't open file \"%s\"\n", in_filename);
return 1;
}
} else {
in_file = stdin;
if (isatty(0)) {
fprintf(stderr, "No filename given and no input on stdin\n");
return 1;
}
}
try {
int page_num = 1;
while (read_page()) {
std::string out_filename = out_prefix
+ "-" + std::to_string(page_num) + ".pbm";
FILE *out_file = fopen(out_filename.c_str(), "wb");
if (!out_file) {
fprintf(stderr, "Can't write file \"%s\"\n", out_filename.c_str());
return 1;
}
write_pnm(out_file);
fclose(out_file);
fprintf(stderr, "%s\n", out_filename.c_str());
++page_num;
}
} catch (std::exception &e) {
fprintf(stderr, "%s\n", e.what());
return 1;
}
return 0;
}

View File

@@ -0,0 +1,107 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2013 Peter De Wachter
//
// brlaser is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// brlaser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include "debug.h"
#include <iostream>
#include <typeinfo>
namespace {
template <typename T>
void dump(const char *name, const T &value) {
std::cerr << "DEBUG: " PACKAGE ": page header: " << name << " = " << value << '\n';
}
template <typename T, int N>
void dump(const char *name, const T (&value)[N]) {
std::cerr << "DEBUG: " PACKAGE ": page header: " << name << " =";
for (int i = 0; i < N; ++i) {
std::cerr << ' ' << value[i];
}
std::cerr << '\n';
}
void dump(const char *name, const char *value) {
std::cerr << "DEBUG: " PACKAGE ": page header: " << name << " = \"" << value << "\"\n";
}
template <int N, int M>
void dump(const char *name, const char (&value)[N][M]) {
std::cerr << "DEBUG: " PACKAGE ": page header: " << name << " =";
for (int i = 0; i < N; ++i) {
std::cerr << " \"" << value[i] << '"';
}
std::cerr << '\n';
}
} // namespace
void dump_page_header(const cups_page_header2_t &h) {
#define d(f) dump(#f, h.f)
d(MediaClass);
d(MediaColor);
d(MediaType);
d(OutputType);
d(AdvanceDistance);
d(AdvanceMedia);
d(Collate);
d(CutMedia);
d(Duplex);
d(HWResolution);
d(ImagingBoundingBox);
d(InsertSheet);
d(Jog);
d(LeadingEdge);
d(Margins);
d(ManualFeed);
d(MediaPosition);
d(MediaWeight);
d(MirrorPrint);
d(NegativePrint);
d(NumCopies);
d(Orientation);
d(OutputFaceUp);
d(PageSize);
d(Separations);
d(TraySwitch);
d(Tumble);
d(cupsWidth);
d(cupsHeight);
d(cupsMediaType);
d(cupsBitsPerColor);
d(cupsBitsPerPixel);
d(cupsBytesPerLine);
d(cupsColorOrder);
d(cupsColorSpace);
d(cupsCompression);
d(cupsRowCount);
d(cupsRowFeed);
d(cupsRowStep);
d(cupsNumColors);
d(cupsBorderlessScalingFactor);
d(cupsPageSize);
d(cupsImagingBBox);
d(cupsInteger);
d(cupsReal);
d(cupsString);
d(cupsMarkerType);
d(cupsRenderingIntent);
d(cupsPageSizeName);
#undef d
}

View File

@@ -0,0 +1,25 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2013 Peter De Wachter
//
// brlaser is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// brlaser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
#ifndef DEBUG_H
#define DEBUG_H
#include <cups/raster.h>
void dump_page_header(const cups_page_header2_t &h);
#endif

View File

@@ -0,0 +1,118 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2013 Peter De Wachter
//
// brlaser is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// brlaser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
#include "job.h"
#include <assert.h>
#include <algorithm>
#include <vector>
#include "line.h"
#include "block.h"
job::job(FILE *out, const std::string &job_name)
: out_(out),
job_name_(job_name),
page_params_() {
// Delete dubious characters from job name
std::replace_if(job_name_.begin(), job_name_.end(), [](char c) {
return c < 32 || c >= 127 || c == '"' || c == '\\';
}, ' ');
begin_job();
}
job::~job() {
end_job();
}
void job::begin_job() {
for (int i = 0; i < 128; ++i) {
putc(0, out_);
}
fprintf(out_, "\033%%-12345X@PJL\n");
fprintf(out_, "@PJL JOB NAME=\"%s\"\n", job_name_.c_str());
}
void job::end_job() {
fprintf(out_, "\033%%-12345X@PJL\n");
fprintf(out_, "@PJL EOJ NAME=\"%s\"\n", job_name_.c_str());
fprintf(out_, "\033%%-12345X\n");
}
void job::write_page_header() {
fprintf(out_, "\033%%-12345X@PJL\n");
if (page_params_.resolution != 1200) {
fprintf(out_, "@PJL SET RAS1200MODE = FALSE\n");
fprintf(out_, "@PJL SET RESOLUTION = %d\n", page_params_.resolution);
} else {
fprintf(out_, "@PJL SET RAS1200MODE = TRUE\n");
fprintf(out_, "@PJL SET RESOLUTION = 600\n");
}
fprintf(out_, "@PJL SET ECONOMODE = %s\n",
page_params_.economode ? "ON" : "OFF");
fprintf(out_, "@PJL SET SOURCETRAY = %s\n",
page_params_.sourcetray.c_str());
fprintf(out_, "@PJL SET MEDIATYPE = %s\n",
page_params_.mediatype.c_str());
fprintf(out_, "@PJL SET PAPER = %s\n",
page_params_.papersize.c_str());
fprintf(out_, "@PJL SET PAGEPROTECT = AUTO\n");
fprintf(out_, "@PJL SET ORIENTATION = PORTRAIT\n");
fprintf(out_, "@PJL ENTER LANGUAGE = PCL\n");
fputs("\033E", out_);
fprintf(out_, "\033&l%dX", std::max(1, page_params_.num_copies));
if (page_params_.duplex) {
fputs("\033&l2S", out_);
}
}
void job::encode_page(const page_params &page_params,
int lines,
int linesize,
nextline_fn nextline) {
if (!(page_params_ == page_params)) {
page_params_ = page_params;
write_page_header();
}
std::vector<uint8_t> line(linesize);
std::vector<uint8_t> reference(linesize);
block block;
if (!nextline(line)) {
return;
}
block.add_line(encode_line(line));
std::swap(line, reference);
fputs("\033*b1030m", out_);
for (int i = 1; i < lines && nextline(line); ++i) {
std::vector<uint8_t> encoded = encode_line(line, reference);
if (!block.line_fits(encoded.size())) {
block.flush(out_);
}
block.add_line(std::move(encoded));
std::swap(line, reference);
}
block.flush(out_);
fputs("1030M\f", out_);
fflush(out_);
}

View File

@@ -0,0 +1,68 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2013 Peter De Wachter
//
// brlaser is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// brlaser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
#ifndef JOB_H
#define JOB_H
#include <stdint.h>
#include <stdio.h>
#include <string>
#include <vector>
struct page_params {
int num_copies;
int resolution;
bool duplex;
bool economode;
std::string sourcetray;
std::string mediatype;
std::string papersize;
bool operator==(const page_params &o) const {
return num_copies == o.num_copies
&& resolution == o.resolution
&& duplex == o.duplex
&& economode == o.economode
&& sourcetray == o.sourcetray
&& mediatype == o.mediatype
&& papersize == o.papersize;
}
};
class job {
public:
typedef bool (*nextline_fn)(std::vector<uint8_t> &buf);
explicit job(FILE *out, const std::string &job_name);
~job();
void encode_page(const page_params &params,
int lines,
int linesize,
nextline_fn nextline);
private:
void begin_job();
void end_job();
void write_page_header();
FILE *out_;
std::string job_name_;
page_params page_params_;
};
#endif // JOB_H

View File

@@ -0,0 +1,191 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2013 Peter De Wachter
//
// brlaser is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// brlaser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
#include "line.h"
#include <assert.h>
#include <algorithm>
using std::vector;
namespace {
void write_overflow(int value, vector<uint8_t> *out) {
if (value >= 0) {
if (value < 255) {
out->push_back(value);
} else {
out->insert(out->end(), value / 255, 255);
out->push_back(value % 255);
}
}
}
template <typename Iterator>
void write_substitute(int offset,
Iterator first,
Iterator last,
vector<uint8_t> *out) {
assert(offset >= 0);
assert(offset < 10000);
assert(first != last);
const int offset_max = 15;
const int count_max = 7;
int count = std::distance(first, last) - 1;
int offset_low = std::min(offset, offset_max);
int count_low = std::min(count, count_max);
out->push_back((offset_low << 3) | count_low);
write_overflow(offset - offset_max, out);
write_overflow(count - count_max, out);
out->insert(out->end(), first, last);
}
void write_repeat(int offset, int count, int value, vector<uint8_t> *out) {
assert(offset >= 0);
assert(offset < 10000);
assert(count >= 2);
assert(count < 10000);
const int offset_max = 3;
const int count_max = 31;
count -= 2;
int offset_low = std::min(offset, offset_max);
int count_low = std::min(count, count_max);
out->push_back(128 | (offset_low << 5) | count_low);
write_overflow(offset - offset_max, out);
write_overflow(count - count_max, out);
out->push_back(value);
}
bool all_zeros(const vector<uint8_t> &buf) {
return std::none_of(buf.begin(), buf.end(), [](uint8_t b) { return b; });
}
template <typename Iterator1, typename Iterator2>
int skip_to_next_mismatch(Iterator1 *first1,
Iterator1 last1,
Iterator2 *first2) {
auto mismatch_it = std::mismatch(*first1, last1, *first2);
int skipped = std::distance(*first1, mismatch_it.first);
*first1 = mismatch_it.first;
*first2 = mismatch_it.second;
return skipped;
}
template <typename Iterator>
int repeat_length(Iterator first, Iterator last) {
if (first != last) {
auto k = *first;
auto mismatch = std::find_if(std::next(first), last,
[=](decltype(k) x) { return x != k; });
return std::distance(first, mismatch);
}
return 0;
}
template <typename Iterator1, typename Iterator2>
int substitute_length(Iterator1 first1, Iterator1 last1, Iterator2 first2) {
if (first1 != last1) {
Iterator1 it1 = first1;
Iterator2 it2 = first2;
Iterator1 next1 = std::next(first1);
Iterator2 next2 = std::next(first2);
Iterator1 prev1 = first1;
while (next1 != last1) {
if ((*it1 == *it2 && *next1 == *next2)) {
return std::distance(first1, it1);
}
if (*it1 == *next1 && *it1 == *prev1) {
return std::distance(first1, prev1);
}
prev1 = it1;
it1 = next1; it2 = next2;
++next1; ++next2;
}
}
return std::distance(first1, last1);
}
size_t reserve_size(const vector<uint8_t> &line) {
// Big enough to store the line uncompressed together with an Substitute
// command with many overflow bytes.
return line.size() + 16;
}
} // namespace
vector<uint8_t> encode_line(const vector<uint8_t> &line,
const vector<uint8_t> &reference) {
assert(line.size() == reference.size());
if (all_zeros(line)) {
return vector<uint8_t>(1, 0xFF);
}
vector<uint8_t> output;
output.reserve(reserve_size(line));
output.push_back(0); // first byte is the edit count
const uint8_t max_edits = 254;
int num_edits = 0;
auto line_it = line.begin();
auto ref_it = reference.begin();
while (1) {
int offset = skip_to_next_mismatch(&line_it, line.end(), &ref_it);
if (line_it == line.end()) {
// No more differences, we're done.
break;
}
if (++num_edits == max_edits) {
// We've run out of edits. Just output the rest of the line in a big
// substitute command.
write_substitute(offset, line_it, line.end(), &output);
break;
}
int s = substitute_length(line_it, line.end(), ref_it);
if (s > 0) {
write_substitute(offset, line_it, std::next(line_it, s), &output);
line_it += s;
ref_it += s;
} else {
int r = repeat_length(line_it, line.end());
assert(r >= 2);
write_repeat(offset, r, *line_it, &output);
line_it += r;
ref_it += r;
}
}
assert(num_edits <= max_edits);
output[0] = num_edits;
return output;
}
vector<uint8_t> encode_line(const vector<uint8_t> &line) {
if (all_zeros(line)) {
return vector<uint8_t>(1, 0xFF);
}
vector<uint8_t> buf;
buf.reserve(reserve_size(line));
buf.push_back(1);
write_substitute(0, line.begin(), line.end(), &buf);
return buf;
}

View File

@@ -0,0 +1,31 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2013 Peter De Wachter
//
// brlaser is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// brlaser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
#ifndef LINE_H
#define LINE_H
#include <stdint.h>
#include <vector>
std::vector<uint8_t> encode_line(
const std::vector<uint8_t> &line,
const std::vector<uint8_t> &reference);
std::vector<uint8_t> encode_line(
const std::vector<uint8_t> &line);
#endif // LINE_H

View File

@@ -0,0 +1,205 @@
// This file is part of the brlaser printer driver.
//
// Copyright 2013 Peter De Wachter
//
// brlaser is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// brlaser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <cups/raster.h>
#include <algorithm>
#include <functional>
#include <string>
#include <array>
#include <map>
#include "config.h"
#include "job.h"
#include "debug.h"
namespace {
cups_raster_t *ras;
volatile sig_atomic_t interrupted = 0;
void sigterm_handler(int sig) {
interrupted = 1;
}
bool next_line(std::vector<uint8_t> &buf) {
if (interrupted) {
return false;
}
return cupsRasterReadPixels(ras, buf.data(), buf.size()) == buf.size();
}
bool plain_ascii_string(const char *str) {
bool result = true;
for (; result && *str; str++) {
result = *str >= 32 && *str <= 126;
}
return result;
}
std::string ascii_job_name(const char *job_id, const char *job_user, const char *job_name) {
std::array<const char *, 3> parts = {{
job_id,
job_user,
job_name
}};
std::string result;
for (const char *part : parts) {
if (*part && plain_ascii_string(part)) {
if (!result.empty()) {
result += '/';
}
result += part;
}
}
if (result.empty()) {
result = "brlaser";
}
const int max_size = 79;
if (result.size() > max_size) {
result.resize(max_size);
}
return result;
}
page_params build_page_params(const cups_page_header2_t &header) {
static const std::array<std::string, 6> sources = {{
"AUTO", "T1", "T2", "T3", "MP", "MANUAL"
}};
static const std::map<std::string, std::string> sizes = {
{ "A4", "A4" },
{ "A5", "A5" },
{ "A6", "A6" },
{ "B5", "B5" },
{ "B6", "B6" },
{ "EnvC5", "C5" },
{ "EnvMonarch", "MONARCH" },
{ "EnvPRC5", "DL" },
{ "EnvDL", "DL" },
{ "Executive", "EXECUTIVE" },
{ "Legal", "LEGAL" },
{ "Letter", "LETTER" }
};
page_params p = { };
p.num_copies = header.NumCopies;
p.resolution = header.HWResolution[0];
p.economode = header.cupsInteger[10];
p.mediatype = header.MediaType;
p.duplex = header.Duplex;
if (header.MediaPosition < sources.size())
p.sourcetray = sources[header.MediaPosition];
else
p.sourcetray = sources[0];
auto size_it = sizes.find(header.cupsPageSizeName);
if (size_it != sizes.end())
p.papersize = size_it->second;
else
p.papersize = "A4";
return p;
}
} // namespace
int main(int argc, char *argv[]) {
fprintf(stderr, "INFO: %s version %s\n", PACKAGE, VERSION);
if (argc != 6 && argc != 7) {
fprintf(stderr, "ERROR: rastertobrlaser job-id user title copies options [file]\n");
fprintf(stderr, "INFO: This program is a CUPS filter. It is not intended to be run manually.\n");
return 1;
}
const char *job_id = argv[1];
const char *job_user = argv[2];
const char *job_name = argv[3];
// const int job_copies = atoi(argv[4]);
// const char *job_options = argv[5];
const char *job_filename = argv[6];
// const char *job_charset = getenv("CHARSET");
signal(SIGTERM, sigterm_handler);
signal(SIGPIPE, SIG_IGN);
int fd = STDIN_FILENO;
if (job_filename) {
fd = open(job_filename, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "ERROR: " PACKAGE ": Unable to open raster file\n");
return 1;
}
}
#ifdef __OpenBSD__
if (pledge("stdio", nullptr) != 0) {
fprintf(stderr, "ERROR: " PACKAGE ": pledge failed\n");
return 1;
}
#endif
ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
if (!ras) {
fprintf(stderr, "DEBUG: " PACKAGE ": Cannot read raster data. Most likely an earlier filter in the pipeline failed.\n");
return 1;
}
int pages = 0;
{
job job(stdout, ascii_job_name(job_id, job_user, job_name));
cups_page_header2_t header;
while (!interrupted && cupsRasterReadHeader2(ras, &header)) {
if (header.cupsBitsPerPixel != 1
|| header.cupsBitsPerColor != 1
|| header.cupsNumColors != 1
|| header.cupsBytesPerLine > 10000) {
fprintf(stderr, "ERROR: " PACKAGE ": Page %d: Bogus raster data.\n", pages + 1);
dump_page_header(header);
return 1;
}
if (pages == 0) {
fprintf(stderr, "DEBUG: " PACKAGE ": Page header of first page\n");
dump_page_header(header);
}
job.encode_page(build_page_params(header),
header.cupsHeight,
header.cupsBytesPerLine,
next_line);
fprintf(stderr, "PAGE: %d %d\n", ++pages, header.NumCopies);
}
}
if (pages == 0) {
fprintf(stderr, "ERROR: " PACKAGE ": No pages were found.\n");
return 1;
}
fflush(stdout);
if (ferror(stdout)) {
fprintf(stderr, "DEBUG: " PACKAGE ": Could not write print data. Most likely the CUPS backend failed.\n");
return 1;
}
return 0;
}