Browse Source

Added -f flag (not yet used). Added README.md. Misc changes

master
suhrke 3 years ago
parent
commit
6a66d5d280
4 changed files with 191 additions and 204 deletions
  1. 51
    0
      README.md
  2. 2
    1
      src/Decoder.cpp
  3. 0
    1
      src/Fileproc.cpp
  4. 138
    202
      src/main.cpp

+ 51
- 0
README.md View File

@@ -0,0 +1,51 @@
#paperback-cli
Paperback-cli is the crossplatform, backwards-compatible, command line version of Oleh Yuschuk's [PaperBack](http://www.ollydbg.de/Paperbak/index.html). Originally designed to print encoded data directly to paper, it has been simplified to focus on encoding and decoding bitmaps that can be saved printed to any printable media via whatever printing mechanism is available to your system. Recommended for small files such as cryptocurrency wallets, key revocation certificates, password databases, and any other data of a few megabytes or less. While the capacity is small compared to conventional storage media, this program encodes or decodes non-electronic backups characteristically resilient to or unaffected by electromagnetic disturbance, water, and heat.

####Build Requirements
* No external dependencies

####Building:
```bash
git submodule update --init --recursive
make
```


####Encode arbitrary data to bitmap (Compression and encryption recommended):
```bash
./paperback-cli --encode -i [input] -o [output].bmp
```

####Decode encoded bitmap
```bash
./paperback-cli --decode -i scanned.bmp -o original.gpg
```


####List all arguments and settings:
```bash
./paperback-cli --help
```


####Compiler(s)
* mingw-w64, GCC 6.3.0 under msys2
* gcc version 7.1.1 20170630


####What has changed from 1.1?
Decryption and decompression has been ported for backwards compatibility with existing backups but more appropriate tools, such as gpg, tar, and bzip2, should be used to preprocess the data before encoding. Printing has been removed entirely for cross-platform compatibility.


####What settings should I use?
Settings depend on the target printer, scanner, and the abuse you expect the printed medium to endure. Inkjet printers are substantially less precise, requiring low DPI settings to be readable (200 by default). The recommended DPI for laser printers is half of your scanner DPI (600 dpi printing possible with scans of 1200 DPI). Oleh recommends a dot size of 70% (default) to ensure adequate white space. Redundancy guards against partially damaged data (default of 5 is 1 block of redundant data per 5 blocks), so higher settings increase chances of recovery after damage. Header and footer prints page and file information (on by default) but has not yet been implemented in this version. Border prints a black border around the data (disabled by default to save ink).

####Similar projects:
Several QR code-based paper backup programs have been written since Oleh released PaperBack 1.1, each with their own advantages. Intra2net ([paperbackup](https://github.com/intra2net/paperbackup)) explains that the ubiquity of QR codes allows his solution several high-quality encoder/decoders. With good density, excellent error-correction, and several alternatives if one decoder should fail, QR codes are an excellent choice. PaperBack also detects and repairs damaged data but the advantage of PaperBack is signifcantly higher density, due to the layout of data. Every cell of a QR code sacrifices space for alignment blocks, whereas PaperBack uses the grid itself for this information. The disadvantage is, should PaperBack fail to decode, there are no alternatives except previous versions of PaperBack. Twibright's [Optar](http://ronja.twibright.com/optar/) is very similar to PaperBack, but, according to Oleh's claims, PaperBack stores 500kB per page while Twibright claims to store 200kB. Comparision testing to follow as time allows.

__________________

Forked from [Oleh Yuschuk's PaperBack](http://www.ollydbg.de/Paperbak/index.html)

Paperback-cli 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.


+ 2
- 1
src/Decoder.cpp View File

@@ -828,7 +828,8 @@ static void Decodenextblock(t_procdata *pdata) {
}
percent=(pdata->posy*pdata->nposx+pdata->posx)*100/
(pdata->nposx*pdata->nposy);
Message(s,percent);
if (percent % 10 == 0)
Message(s,percent);
// Decode block.
answer=Decodeblock(pdata,pdata->posx,pdata->posy,&result);
// If we are unable to locate block, probably we are outside the raster.

+ 0
- 1
src/Fileproc.cpp View File

@@ -274,7 +274,6 @@ int Finishpage(int slot,int ngood,int nbad,uint32_t nrestored) {
if (pf->ndata==pf->nblock) {
if (::pb_autosave==0) {
Message("File restored.",0);
Saverestoredfile(slot,0);
}
else {
Message("File complete",0);

+ 138
- 202
src/main.cpp View File

@@ -16,151 +16,16 @@
* =====================================================================================
*/
#include <stdlib.h>
#include <iostream>
#include <string>
#include <getopt.h>
#include <stdbool.h>

#include "paperbak.h"
#include "Resource.h"
#include <getopt.h>
using namespace std;

#define VERSIONHI 1
#define VERSIONLO 2

#ifdef CXXSCRAP
#include "cxxopts.hpp"

inline bool isSwitchValid(int value) {
return ( value < 0 || value > 1 );
}

// redundancy 1 to 10
// dot size 50 to 100
// dpi 40 to 300
bool validate(cxxopts::Options &o) {
bool is_ok = true;
if ((o["mode"].as<string>().compare("encode") != 0) &&
o["mode"].as<string>().compare("decode") != 0) {
cerr << "error: invalid mode given" << endl;
is_ok = false;
}
if (o["i"].as<string>().empty()) {
cerr << "error: no input file given" << endl;
is_ok = false;
}
if (o["o"].as<string>().empty()) {
cerr << "error: no output file given" << endl;
is_ok = false;
}
if (o["s"].as<int>() < 50 || o["s"].as<int>() > 100) {
cerr << "error: invalid value for dot size" << endl;
is_ok = false;
}
if (o["d"].as<int>() < 40 || o["d"].as<int>() > 300) {
cerr << "error: invalid value for dpi" << endl;
is_ok = false;
}
if (o["r"].as<int>() < 2 || o["r"].as<int>() > 10) {
cerr << "error: invalid value for redundancy" << endl;
is_ok = false;
}
if ( isSwitchValid(o["no-header"].as<int>()) ) {
cerr << "error: invalid value given for no-header switch" << endl;
is_ok = false;
}
if ( isSwitchValid(o["border"].as<int>()) ) {
cerr << "error: invalid value given for border switch" << endl;
is_ok = false;
}

return is_ok;
}

cxxopts::Options arguments(int ac, char **av) {
cxxopts::Options o(av[0],
"Encodes or decodes high-density printable file backups.");
vector<string> parg = {"mode", "input", "output"};
o.add_options()
("h,help", "displays help")
("v,version", "Display version and information relevant to that version")
("mode",
"encode or decode, operation on input and output",
cxxopts::value<string>())
("i,input",
"file to encode to or decode from",
cxxopts::value<string>(),
"FILE")
("o,output",
"file as a result of program",
cxxopts::value<string>(),
"FILE")
("d,dpi",
"dots per inch of input or output bitmap, between 40 and 300",
cxxopts::value<int>() -> default_value("200"))
("s,dotsize",
"size of the dots in bitmap as percentage of maximum dot size in pixels, between 50 and 100",
cxxopts::value<int>() -> default_value("70"))
("r,redundancy",
"data redundancy ratio of input or output bitmap as a reciprocal, between 2 and 10",
cxxopts::value<int>() -> default_value("5"))
("n,no-header",
"disable printing of file name, last modify date and time, file size, and page number as a header",
cxxopts::value<int>() -> default_value("0")-> implicit_value("1"))
("b,border",
"print a black border around the block",
cxxopts::value<int>() -> default_value("0")-> implicit_value("1"))
;
o.parse_positional(parg);
o.parse(ac, av);
if (o.count("help")) {
cout << o.help() << endl;
exit(EXIT_SUCCESS);
}else if (o.count("version")) {
cout << "\nPaperBack v" << VERSIONHI << "." << VERSIONLO << endl
<< "Copyright © 2007 Oleh Yuschuk" << endl << endl
<< "----- THIS SOFTWARE IS FREE -----" << endl
<< "Released under GNU Public License (GPL 3+)" << endl
<< "Full sources available" << endl << endl
<< "Reed-Solomon ECC:" << endl
<< "Copyright © 2002 Phil Karn (GPL)" << endl << endl;
}else if (!validate(o)) {
exit(EXIT_FAILURE);
}
return o;
}

bool setglobals(cxxopts::Options &options) {
bool isEncode;
try {
// set arguments to extern (global) variables
::pb_dpi = options["dpi"].as<int>();
::pb_dotpercent = options["dotsize"].as<int>();
::pb_redundancy = options["redundancy"].as<int>();
::pb_printheader = ( ! options["no-header"].as<int>() );
::pb_printborder = options["border"].as<int>();
// decode = !encode
isEncode = options["mode"].as<string>().compare("encode") == 0;

// externs (also have matching values in printdata and/or procdata)
std::string infile = options["input"].as<string>();
std::string outfile = options["output"].as<string>();
strcpy (::pb_infile, infile.c_str());
strcpy (::pb_outbmp, outfile.c_str());
strcpy (::pb_outfile, outfile.c_str());
}
catch (const cxxopts::OptionException& e) {
cerr << "error parsing options: " << e.what() << endl;
exit(1);
}
catch (const std::exception& e) {
cerr << "An unexpected error occurred: " << e.what() << endl;
exit(1);
}
return isEncode;
}
#endif


// Global forward declarations
t_fproc pb_fproc[NFILE]; // Processed file
@@ -189,37 +54,129 @@ int pb_marginright; // Right printer page margin
int pb_margintop; // Top printer page margin
int pb_marginbottom; // Bottom printer page margin

void dhelp() {
printf("placeholder - help");

// Function prototypes
void dhelp (const char *exe);
void dversion();
int arguments (int ac, char **av);




int main(int argc, char ** argv) {
// set values needed for cli version
::pb_autosave = 1;
// set default values for vars affected by arg parsing
::pb_infile[0] = '\0';
::pb_outfile[0] = '\0';
::pb_outbmp[0] = '\0';
::pb_dpi = 200;
::pb_dotpercent = 70;
::pb_redundancy = 5;
::pb_printheader = 0;
::pb_printborder = 0;

bool isEncode = arguments(argc, argv);
if (isEncode) {
printf ("Encoding %s to create %s\n"
"DPI: %d\n"
"Dot percent: %d\n"
"Redundancy: 1:%d\n"
"Print header/footer: %d\n"
"Print border: %d\n",
::pb_infile, ::pb_outbmp,
::pb_dpi, ::pb_dotpercent, ::pb_redundancy,
::pb_printheader, ::pb_printborder);

Printfile (::pb_infile, ::pb_outbmp);
while (::pb_printdata.step != 0) {
Nextdataprintingstep (&::pb_printdata);
}
}
else {
printf ("Decoding %s into %s\n", ::pb_infile, ::pb_outfile);
Decodebitmap (::pb_infile);
while (::pb_procdata.step != 0) {
Nextdataprocessingstep (&::pb_procdata);
}
}

return 0;
}

void dversion() {
printf("placeholder - version");


inline void dhelp (const char *exe) {
printf("%s\n\n"
"Usage:\n"
"\t%s --encode -i [infile] -o [out].bmp [OPTION...]\n"
"\t%s --decode -i [in].bmp -o [outfile]\n"
"\t%s --decode -f [inputfolder] -o [outfile]\n\n"
"\t--encode Create a bitmap from the input file\n"
"\t--decode Decode an encoded bitmap/folder of bitmaps\n"
"\t-i, --input File to encode to or decode from\n"
"\t-o, --output Newly encoded bitmap or decoded file\n"
"\t-f, --inputfolder Directory of bitmaps to decode into a single file\n"
"\t-d, --dpi Dots per inch of the output bitmap (40 to 600)\n"
"\t-s, --dotsize Size of the dots in bitmap as percentage of maximum dot\n"
"\t size in pixels, (50 to 100)\n"
"\t-r, --redundancy Data redundancy ratio of input or output bitmap as a\n"
"\t reciprocal, (2 to 10)\n"
"\t-n, --no-header Disable printing of file name, last modify date and time,\n"
"\t file size, and page number\n"
"\t-b, --border Print a black border around the page\n"
"\t-v, --version Display version and information relevant to that version\n"
"\t-h, --help Display all arguments and program description\n\n",
"\nEncodes or decodes high-density printable file backups.",
exe,
exe,
exe);
}



inline void dversion() {
printf("\nPaperBack v%d.%d\n"
"Copyright © 2007 Oleh Yuschuk\n\n"
"----- THIS SOFTWARE IS FREE -----\n"
"Released under GNU Public License (GPL 3+)\n"
"Full sources available\n\n"
"Reed-Solomon ECC:\n"
"Copyright © 2002 Phil Karn (GPL)\n\n"
"Bzip2 data compression:\n"
"Copyright © 1996-2005 Julian R. Seward (see sources)\n\n"
"FIPS-197 compliant AES encryption:\n"
"Copyright © 2001-2004 Christophe Devine (GPL 2+)\n\n",
VERSIONHI, VERSIONLO);
}

int arguments(int ac, char **av) {


int arguments (int ac, char **av) {
bool is_ok = true;
int displayhelp = 0, displayversion = 0, isencode;
struct option long_options[] = {
// options that set flags
{"help", no_argument, &displayhelp, 1},
{"version", no_argument, &displayversion, 1},
{"encode", no_argument, &isencode, 1},
{"decode", no_argument, &isencode, 0},
{"encode", no_argument, &isencode, 1},
{"decode", no_argument, &isencode, 0},
// options that assign values in switch
{"input", required_argument, NULL, 'i'},
{"output", required_argument, NULL, 'o'},
{"dpi", required_argument, NULL, 'd'},
{"dotsize", required_argument, NULL, 's'},
{"redundancy", required_argument, NULL, 'r'},
{"no-header", no_argument, NULL, 'n'},
{"border", no_argument, NULL, 'b'},
{"input", required_argument, NULL, 'i'},
{"output", required_argument, NULL, 'o'},
{"inputfolder", required_argument, NULL, 'f'},
{"dpi", required_argument, NULL, 'd'},
{"dotsize", required_argument, NULL, 's'},
{"redundancy", required_argument, NULL, 'r'},
{"no-header", no_argument, NULL, 'n'},
{"border", no_argument, NULL, 'b'},
{"version", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{0, 0, 0, 0}
};
int c;
while(is_ok) {
int options_index = 0;
c = getopt_long(ac, av, "i:o:d:s:r:bn", long_options, &options_index);
c = getopt_long (ac, av, "i:o:f:d:s:r:nbvh", long_options, &options_index);
if (c == -1) {
break;
}
@@ -236,13 +193,21 @@ int arguments(int ac, char **av) {
break;
case 'o':
if (optarg == NULL) {
fprintf(stderr, "error: arg is null \n");
fprintf(stderr, "error: outfile arg is null \n");
is_ok = false;
} else {
strcpy (::pb_outfile, optarg);
strcpy (::pb_outbmp, optarg);
}
break;
case 'f':
if (optarg == NULL) {
fprintf(stderr, "error: inputfolder arg is null \n");
is_ok = false;
} else {
strcpy (::pb_infile, optarg);
}
break;
case 'd':
::pb_dpi = atoi(optarg);
break;
@@ -258,85 +223,56 @@ int arguments(int ac, char **av) {
case 'b':
::pb_printborder = atoi(optarg);
break;
case 'v':
displayversion = true;
break;
case 'h':
displayhelp = true;
break;
default:
exit(EXIT_FAILURE);
exit (EXIT_FAILURE);
}
}
if (displayhelp) {
dhelp();
dhelp (av[0]);
exit(EXIT_SUCCESS);
}
if (displayversion) {
dversion();
exit(EXIT_SUCCESS);
}
if (strlen(::pb_infile) == 0) {
fprintf(stderr, "error: no input file given\n");
if (strlen (::pb_infile) == 0) {
fprintf (stderr, "error: no input file given\n");
is_ok = false;
}
if (strlen(::pb_outfile) == 0) {
fprintf(stderr, "error: no output file given\n");
if (strlen (::pb_outfile) == 0) {
fprintf (stderr, "error: no output file given\n");
is_ok = false;
}
if (::pb_dotpercent < 50 || ::pb_dotpercent > 100) {
fprintf(stderr, "error: invalid dotsize given\n");
fprintf (stderr, "error: invalid dotsize given\n");
is_ok = false;
}
if (::pb_dpi < 40 || ::pb_dpi > 300) {
fprintf(stderr, "error: invalid dotsize given\n");
if (::pb_dpi < 40 || ::pb_dpi > 600) {
fprintf (stderr, "error: invalid DPI given\n");
is_ok = false;
}
if (::pb_redundancy < 2 || ::pb_redundancy > 10) {
fprintf(stderr, "error: invalid dotsize given\n");
fprintf (stderr, "error: invalid redundancy given\n");
is_ok = false;
}
if (::pb_printheader < 0 || ::pb_printheader > 1) {
fprintf(stderr, "error: invalid dotsize given\n");
fprintf (stderr, "error: invalid header setting given\n");
is_ok = false;
}
if (::pb_printborder < 0 || ::pb_printborder > 1) {
fprintf(stderr, "error: invalid dotsize given\n");
fprintf (stderr, "error: invalid border setting given\n");
is_ok = false;
}
if (!is_ok) {
if ( ! is_ok) {
exit(EXIT_FAILURE);
}
if (isencode) {
printf("program is set to encode.\n");
} else {
printf("program is set to decode.\n");
}
return isencode;
}


int main(int argc, char ** argv) {
// set default values for vars affected by arg. parsing.
::pb_infile[0] = 0;
::pb_outfile[0] = 0;
::pb_dpi = 200;
::pb_dotpercent = 70;
::pb_redundancy = 5;
::pb_printheader = 0;
::pb_printborder = 0;

bool isEncode = arguments(argc, argv);
if (isEncode) {
Printfile(::pb_infile, ::pb_outbmp);
// begin the process to write the bitmap
while (::pb_printdata.step != 0) {
//cout << "Step: " << ::pb_printdata.step << endl;
Nextdataprintingstep (&::pb_printdata);
}
}
else {
Decodebitmap (::pb_infile);
while (::pb_procdata.step != 0) {
//cout << "Step: " << ::pb_procdata.step << endl;
Nextdataprocessingstep (&::pb_procdata);
}
}

return 0;
}


Loading…
Cancel
Save