tiff.h100444 423 0 34333 5642652530 10611 0ustar luigiwheel/* $Header: /usr/people/sam/tiff/libtiff/RCS/tiff.h,v 1.44 1994/09/17 23:22:37 sam Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994 Sam Leffler * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #ifndef _TIFF_ #define _TIFF_ /* * Tag Image File Format (TIFF) * * Based on Rev 6.0 from: * Developer's Desk * Aldus Corporation * 411 First Ave. South * Suite 200 * Seattle, WA 98104 * 206-622-5500 */ #define TIFF_VERSION 42 #define TIFF_BIGENDIAN 0x4d4d #define TIFF_LITTLEENDIAN 0x4949 /* * Intrinsic data types required by the file format: * * 8-bit quantities char/unsigned char * 16-bit quantities int16/uint16 * 32-bit quantities int32/uint32 * strings unsigned char* */ typedef short int16; typedef unsigned short uint16; /* sizeof (uint16) must == 2 */ #if defined(__alpha) || _MIPS_SZLONG == 64 typedef int int32; typedef unsigned int uint32; /* sizeof (uint32) must == 4 */ #else typedef long int32; typedef unsigned long uint32; /* sizeof (uint32) must == 4 */ #endif typedef struct { uint16 tiff_magic; /* magic number (defines byte order) */ uint16 tiff_version; /* TIFF version number */ uint32 tiff_diroff; /* byte offset to first directory */ } TIFFHeader; /* * TIFF Image File Directories are comprised of * a table of field descriptors of the form shown * below. The table is sorted in ascending order * by tag. The values associated with each entry * are disjoint and may appear anywhere in the file * (so long as they are placed on a word boundary). * * If the value is 4 bytes or less, then it is placed * in the offset field to save space. If the value * is less than 4 bytes, it is left-justified in the * offset field. */ typedef struct { uint16 tdir_tag; /* see below */ uint16 tdir_type; /* data type; see below */ uint32 tdir_count; /* number of items; length in spec */ uint32 tdir_offset; /* byte offset to field data */ } TIFFDirEntry; /* * NB: In the comments below, * - items marked with a + are obsoleted by revision 5.0, * - items marked with a ! are introduced in revision 6.0. * - items marked with a $ are obsoleted by revision 6.0. */ /* * Tag data type information. * * Note: RATIONALs are the ratio of two 32-bit integer values. */ typedef enum { TIFF_NOTYPE = 0, /* placeholder */ TIFF_BYTE = 1, /* 8-bit unsigned integer */ TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */ TIFF_SHORT = 3, /* 16-bit unsigned integer */ TIFF_LONG = 4, /* 32-bit unsigned integer */ TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */ TIFF_SBYTE = 6, /* !8-bit signed integer */ TIFF_UNDEFINED = 7, /* !8-bit untyped data */ TIFF_SSHORT = 8, /* !16-bit signed integer */ TIFF_SLONG = 9, /* !32-bit signed integer */ TIFF_SRATIONAL = 10, /* !64-bit signed fraction */ TIFF_FLOAT = 11, /* !32-bit IEEE floating point */ TIFF_DOUBLE = 12 /* !64-bit IEEE floating point */ } TIFFDataType; /* * TIFF Tag Definitions. */ #define TIFFTAG_SUBFILETYPE 254 /* subfile data descriptor */ #define FILETYPE_REDUCEDIMAGE 0x1 /* reduced resolution version */ #define FILETYPE_PAGE 0x2 /* one page of many */ #define FILETYPE_MASK 0x4 /* transparency mask */ #define TIFFTAG_OSUBFILETYPE 255 /* +kind of data in subfile */ #define OFILETYPE_IMAGE 1 /* full resolution image data */ #define OFILETYPE_REDUCEDIMAGE 2 /* reduced size image data */ #define OFILETYPE_PAGE 3 /* one page of many */ #define TIFFTAG_IMAGEWIDTH 256 /* image width in pixels */ #define TIFFTAG_IMAGELENGTH 257 /* image height in pixels */ #define TIFFTAG_BITSPERSAMPLE 258 /* bits per channel (sample) */ #define TIFFTAG_COMPRESSION 259 /* data compression technique */ #define COMPRESSION_NONE 1 /* dump mode */ #define COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */ #define COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */ #define COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */ #define COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */ #define COMPRESSION_JPEG 6 /* !JPEG compression */ #define COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */ #define COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */ #define COMPRESSION_PACKBITS 32773 /* Macintosh RLE */ #define COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */ /* compression codes 32908-32911 are reserved for Pixar */ #define COMPRESSION_PIXARFILM 32908 /* Pixar companded 10bit LZW */ #define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ #define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ #define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ #define PHOTOMETRIC_RGB 2 /* RGB color model */ #define PHOTOMETRIC_PALETTE 3 /* color map indexed */ #define PHOTOMETRIC_MASK 4 /* $holdout mask */ #define PHOTOMETRIC_SEPARATED 5 /* !color separations */ #define PHOTOMETRIC_YCBCR 6 /* !CCIR 601 */ #define PHOTOMETRIC_CIELAB 8 /* !1976 CIE L*a*b* */ #define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */ #define THRESHHOLD_BILEVEL 1 /* b&w art scan */ #define THRESHHOLD_HALFTONE 2 /* or dithered scan */ #define THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */ #define TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */ #define TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */ #define TIFFTAG_FILLORDER 266 /* data order within a byte */ #define FILLORDER_MSB2LSB 1 /* most significant -> least */ #define FILLORDER_LSB2MSB 2 /* least significant -> most */ #define TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */ #define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */ #define TIFFTAG_MAKE 271 /* scanner manufacturer name */ #define TIFFTAG_MODEL 272 /* scanner model name/number */ #define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */ #define TIFFTAG_ORIENTATION 274 /* +image orientation */ #define ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */ #define ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */ #define ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */ #define ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */ #define ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */ #define ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */ #define ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */ #define ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */ #define TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */ #define TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */ #define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */ #define TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */ #define TIFFTAG_MAXSAMPLEVALUE 281 /* +maximum sample value */ #define TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */ #define TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */ #define TIFFTAG_PLANARCONFIG 284 /* storage organization */ #define PLANARCONFIG_CONTIG 1 /* single image plane */ #define PLANARCONFIG_SEPARATE 2 /* separate planes of data */ #define TIFFTAG_PAGENAME 285 /* page name image is from */ #define TIFFTAG_XPOSITION 286 /* x page offset of image lhs */ #define TIFFTAG_YPOSITION 287 /* y page offset of image lhs */ #define TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */ #define TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */ #define TIFFTAG_GRAYRESPONSEUNIT 290 /* $gray scale curve accuracy */ #define GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */ #define GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */ #define GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */ #define GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ #define GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */ #define TIFFTAG_GRAYRESPONSECURVE 291 /* $gray scale response curve */ #define TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */ #define GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */ #define GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */ #define GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */ #define TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */ #define GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */ #define TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */ #define RESUNIT_NONE 1 /* no meaningful units */ #define RESUNIT_INCH 2 /* english */ #define RESUNIT_CENTIMETER 3 /* metric */ #define TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */ #define TIFFTAG_COLORRESPONSEUNIT 300 /* $color curve accuracy */ #define COLORRESPONSEUNIT_10S 1 /* tenths of a unit */ #define COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */ #define COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */ #define COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ #define COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */ #define TIFFTAG_TRANSFERFUNCTION 301 /* !colorimetry info */ #define TIFFTAG_SOFTWARE 305 /* name & release */ #define TIFFTAG_DATETIME 306 /* creation date and time */ #define TIFFTAG_ARTIST 315 /* creator of image */ #define TIFFTAG_HOSTCOMPUTER 316 /* machine where created */ #define TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */ #define TIFFTAG_WHITEPOINT 318 /* image white point */ #define TIFFTAG_PRIMARYCHROMATICITIES 319 /* !primary chromaticities */ #define TIFFTAG_COLORMAP 320 /* RGB map for pallette image */ #define TIFFTAG_HALFTONEHINTS 321 /* !highlight+shadow info */ #define TIFFTAG_TILEWIDTH 322 /* !rows/data tile */ #define TIFFTAG_TILELENGTH 323 /* !cols/data tile */ #define TIFFTAG_TILEOFFSETS 324 /* !offsets to data tiles */ #define TIFFTAG_TILEBYTECOUNTS 325 /* !byte counts for tiles */ #define TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */ #define TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */ #define CLEANFAXDATA_CLEAN 0 /* no errors detected */ #define CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */ #define CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */ #define TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */ #define TIFFTAG_SUBIFD 330 /* subimage descriptors */ #define TIFFTAG_INKSET 332 /* !inks in separated image */ #define INKSET_CMYK 1 /* !cyan-magenta-yellow-black */ #define TIFFTAG_INKNAMES 333 /* !ascii names of inks */ #define TIFFTAG_DOTRANGE 336 /* !0% and 100% dot codes */ #define TIFFTAG_TARGETPRINTER 337 /* !separation target */ #define TIFFTAG_EXTRASAMPLES 338 /* !info about extra samples */ #define EXTRASAMPLE_UNSPECIFIED 0 /* !unspecified data */ #define EXTRASAMPLE_ASSOCALPHA 1 /* !associated alpha data */ #define EXTRASAMPLE_UNASSALPHA 2 /* !unassociated alpha data */ #define TIFFTAG_SAMPLEFORMAT 339 /* !data sample format */ #define SAMPLEFORMAT_UINT 1 /* !unsigned integer data */ #define SAMPLEFORMAT_INT 2 /* !signed integer data */ #define SAMPLEFORMAT_IEEEFP 3 /* !IEEE floating point data */ #define SAMPLEFORMAT_VOID 4 /* !untyped data */ #define TIFFTAG_SMINSAMPLEVALUE 340 /* !variable MinSampleValue */ #define TIFFTAG_SMAXSAMPLEVALUE 341 /* !variable MaxSampleValue */ #define TIFFTAG_JPEGPROC 512 /* !JPEG processing algorithm */ #define JPEGPROC_BASELINE 1 /* !baseline sequential */ #define JPEGPROC_LOSSLESS 14 /* !Huffman coded lossless */ #define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */ #define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */ #define TIFFTAG_JPEGRESTARTINTERVAL 515 /* !restart interval length */ #define TIFFTAG_JPEGLOSSLESSPREDICTORS 517 /* !lossless proc predictor */ #define TIFFTAG_JPEGPOINTTRANSFORM 518 /* !lossless point transform */ #define TIFFTAG_JPEGQTABLES 519 /* !Q matrice offsets */ #define TIFFTAG_JPEGDCTABLES 520 /* !DCT table offsets */ #define TIFFTAG_JPEGACTABLES 521 /* !AC coefficient offsets */ #define TIFFTAG_YCBCRCOEFFICIENTS 529 /* !RGB -> YCbCr transform */ #define TIFFTAG_YCBCRSUBSAMPLING 530 /* !YCbCr subsampling factors */ #define TIFFTAG_YCBCRPOSITIONING 531 /* !subsample positioning */ #define YCBCRPOSITION_CENTERED 1 /* !as in PostScript Level 2 */ #define YCBCRPOSITION_COSITED 2 /* !as in CCIR 601-1 */ #define TIFFTAG_REFERENCEBLACKWHITE 532 /* !colorimetry info */ /* tags 32952-32956 are private tags registered to Island Graphics */ #define TIFFTAG_REFPTS 32953 /* image reference points */ #define TIFFTAG_REGIONTACKPOINT 32954 /* region-xform tack point */ #define TIFFTAG_REGIONWARPCORNERS 32955 /* warp quadrilateral */ #define TIFFTAG_REGIONAFFINE 32956 /* affine transformation mat */ /* tags 32995-32999 are private tags registered to SGI */ #define TIFFTAG_MATTEING 32995 /* $use ExtraSamples */ #define TIFFTAG_DATATYPE 32996 /* $use SampleFormat */ #define TIFFTAG_IMAGEDEPTH 32997 /* z depth of image */ #define TIFFTAG_TILEDEPTH 32998 /* z depth/data tile */ /* tags 33300-33309 are private tags registered to Pixar */ /* * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH * are set when an image has been cropped out of a larger image. * They reflect the size of the original uncropped image. * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used * to determine the position of the smaller image in the larger one. */ #define TIFFTAG_PIXAR_IMAGEFULLWIDTH 33300 /* full image size in x */ #define TIFFTAG_PIXAR_IMAGEFULLLENGTH 33301 /* full image size in y */ #endif /* _TIFF_ */ rs.h100644 423 0 3464 6243646065 10274 0ustar luigiwheel/* Global definitions for Reed-Solomon encoder/decoder * Phil Karn KA9Q, September 1996 * * The parameters MM and KK specify the Reed-Solomon code parameters. * * Set MM to be the size of each code symbol in bits. The Reed-Solomon * block size will then be NN = 2**M - 1 symbols. Supported values are * defined in rs.c. * * Set KK to be the number of data symbols in each block, which must be * less than the block size. The code will then be able to correct up * to NN-KK erasures or (NN-KK)/2 errors, or combinations thereof with * each error counting as two erasures. */ #ifdef MSDOS #define inline /* broken MSC 5.0 */ #endif #define MM 8 /* RS code over GF(2**MM) - change to suit */ #define KK 192 /* 223 */ /* KK = number of information symbols */ #define NN ((1 << MM) - 1) #if (MM <= 8) typedef unsigned char dtype; #else typedef unsigned int dtype; #endif /* Initialization function */ void init_rs(void); /* These two functions *must* be called in this order (e.g., * by init_rs()) before any encoding/decoding */ void generate_gf(void); /* Generate Galois Field */ void gen_poly(void); /* Generate generator polynomial */ /* Reed-Solomon encoding * data[] is the input block, parity symbols are placed in bb[] * bb[] may lie past the end of the data, e.g., for (255,223): * encode_rs(&data[0],&data[223]); */ int encode_rs(dtype data[], dtype bb[]); /* Reed-Solomon erasures-and-errors decoding * The received block goes into data[], and a list of zero-origin * erasure positions, if any, goes in eras_pos[] with a count in no_eras. * * The decoder corrects the symbols in place, if possible and returns * the number of corrected symbols. If the codeword is illegal or * uncorrectible, the data array is unchanged and -1 is returned */ int eras_dec_rs(dtype data[], int eras_pos[], int no_eras); rs.c100644 423 0 34763 6222701347 10305 0ustar luigiwheel/* * Reed-Solomon coding and decoding * Phil Karn (karn@ka9q.ampr.org) September 1996 * * This file is derived from the program "new_rs_erasures.c" by Robert * Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy * (harit@spectra.eng.hawaii.edu), Aug 1995 * * I've made changes to improve performance, clean up the code and make it * easier to follow. Data is now passed to the encoding and decoding functions * through arguments rather than in global arrays. The decode function returns * the number of corrected symbols, or -1 if the word is uncorrectable. * * This code supports a symbol size from 2 bits up to 16 bits, * implying a block size of 3 2-bit symbols (6 bits) up to 65535 * 16-bit symbols (1,048,560 bits). The code parameters are set in rs.h. * * Note that if symbols larger than 8 bits are used, the type of each * data array element switches from unsigned char to unsigned int. The * caller must ensure that elements larger than the symbol range are * not passed to the encoder or decoder. * */ #include #include "rs.h" #if (KK >= NN) #error "KK must be less than 2**MM - 1" #endif /* This defines the type used to store an element of the Galois Field * used by the code. Make sure this is something larger than a char if * if anything larger than GF(256) is used. * * Note: unsigned char will work up to GF(256) but int seems to run * faster on the Pentium. */ typedef int gf; /* Primitive polynomials - see Lin & Costello, Appendix A, * and Lee & Messerschmitt, p. 453. */ #if(MM == 2)/* Admittedly silly */ int Pp[MM+1] = { 1, 1, 1 }; #elif(MM == 3) /* 1 + x + x^3 */ int Pp[MM+1] = { 1, 1, 0, 1 }; #elif(MM == 4) /* 1 + x + x^4 */ int Pp[MM+1] = { 1, 1, 0, 0, 1 }; #elif(MM == 5) /* 1 + x^2 + x^5 */ int Pp[MM+1] = { 1, 0, 1, 0, 0, 1 }; #elif(MM == 6) /* 1 + x + x^6 */ int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1 }; #elif(MM == 7) /* 1 + x^3 + x^7 */ int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 1 }; #elif(MM == 8) /* 1+x^2+x^3+x^4+x^8 */ int Pp[MM+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1 }; #elif(MM == 9) /* 1+x^4+x^9 */ int Pp[MM+1] = { 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; #elif(MM == 10) /* 1+x^3+x^10 */ int Pp[MM+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; #elif(MM == 11) /* 1+x^2+x^11 */ int Pp[MM+1] = { 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; #elif(MM == 12) /* 1+x+x^4+x^6+x^12 */ int Pp[MM+1] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1 }; #elif(MM == 13) /* 1+x+x^3+x^4+x^13 */ int Pp[MM+1] = { 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; #elif(MM == 14) /* 1+x+x^6+x^10+x^14 */ int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }; #elif(MM == 15) /* 1+x+x^15 */ int Pp[MM+1] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; #elif(MM == 16) /* 1+x+x^3+x^12+x^16 */ int Pp[MM+1] = { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 }; #else #error "MM must be in range 2-16" #endif /* Alpha exponent for the first root of the generator polynomial */ #define B0 1 /* index->polynomial form conversion table */ gf Alpha_to[NN + 1]; /* Polynomial->index form conversion table */ gf Index_of[NN + 1]; /* No legal value in index form represents zero, so * we need a special value for this purpose */ #define A0 (NN) /* Generator polynomial g(x) * Degree of g(x) = 2*TT * has roots @**B0, @**(B0+1), ... ,@^(B0+2*TT-1) */ gf Gg[NN - KK + 1]; /* Compute x % NN, where NN is 2**MM - 1, * without a slow divide */ static inline gf modnn(int x) { while (x >= NN) { x -= NN; x = (x >> MM) + (x & NN); } return x; } #define min(a,b) ((a) < (b) ? (a) : (b)) #define CLEAR(a,n) {\ int ci;\ for(ci=(n)-1;ci >=0;ci--)\ (a)[ci] = 0;\ } #define COPY(a,b,n) {\ int ci;\ for(ci=(n)-1;ci >=0;ci--)\ (a)[ci] = (b)[ci];\ } #define COPYDOWN(a,b,n) {\ int ci;\ for(ci=(n)-1;ci >=0;ci--)\ (a)[ci] = (b)[ci];\ } void init_rs(void) { generate_gf(); gen_poly(); } /* generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] lookup tables: index->polynomial form alpha_to[] contains j=alpha**i; polynomial form -> index form index_of[j=alpha**i] = i alpha=2 is the primitive element of GF(2**m) HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows: Let @ represent the primitive element commonly called "alpha" that is the root of the primitive polynomial p(x). Then in GF(2^m), for any 0 <= i <= 2^m-2, @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for example the polynomial representation of @^5 would be given by the binary representation of the integer "alpha_to[5]". Similarily, index_of[] can be used as follows: As above, let @ represent the primitive element of GF(2^m) that is the root of the primitive polynomial p(x). In order to find the power of @ (alpha) that has the polynomial representation a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) we consider the integer "i" whose binary representation with a(0) being LSB and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry "index_of[i]". Now, @^index_of[i] is that element whose polynomial representation is (a(0),a(1),a(2),...,a(m-1)). NOTE: The element alpha_to[2^m-1] = 0 always signifying that the representation of "@^infinity" = 0 is (0,0,0,...,0). Similarily, the element index_of[0] = A0 always signifying that the power of alpha which has the polynomial representation (0,0,...,0) is "infinity". */ void generate_gf(void) { register int i, mask; mask = 1; Alpha_to[MM] = 0; for (i = 0; i < MM; i++) { Alpha_to[i] = mask; Index_of[Alpha_to[i]] = i; /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */ if (Pp[i] != 0) Alpha_to[MM] ^= mask; /* Bit-wise EXOR operation */ mask <<= 1; /* single left-shift */ } Index_of[Alpha_to[MM]] = MM; /* * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by * poly-repr of @^i shifted left one-bit and accounting for any @^MM * term that may occur when poly-repr of @^i is shifted. */ mask >>= 1; for (i = MM + 1; i < NN; i++) { if (Alpha_to[i - 1] >= mask) Alpha_to[i] = Alpha_to[MM] ^ ((Alpha_to[i - 1] ^ mask) << 1); else Alpha_to[i] = Alpha_to[i - 1] << 1; Index_of[Alpha_to[i]] = i; } Index_of[0] = A0; Alpha_to[NN] = 0; } /* * Obtain the generator polynomial of the TT-error correcting, length * NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0, * ... ,(2*TT-1) * * Examples: * * If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2. * g(x) = (x+@) (x+@**2) * * If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4. * g(x) = (x+1) (x+@) (x+@**2) (x+@**3) */ void gen_poly(void) { register int i, j; Gg[0] = Alpha_to[B0]; Gg[1] = 1; /* g(x) = (X+@**B0) initially */ for (i = 2; i <= NN - KK; i++) { Gg[i] = 1; /* * Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by * (@**(B0+i-1) + x) */ for (j = i - 1; j > 0; j--) if (Gg[j] != 0) Gg[j] = Gg[j - 1] ^ Alpha_to[modnn((Index_of[Gg[j]]) + B0 + i - 1)]; else Gg[j] = Gg[j - 1]; /* Gg[0] can never be zero */ Gg[0] = Alpha_to[modnn((Index_of[Gg[0]]) + B0 + i - 1)]; } /* convert Gg[] to index form for quicker encoding */ for (i = 0; i <= NN - KK; i++) Gg[i] = Index_of[Gg[i]]; } /* * take the string of symbols in data[i], i=0..(k-1) and encode * systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[] * is input and bb[] is output in polynomial form. Encoding is done by using * a feedback shift register with appropriate connections specified by the * elements of Gg[], which was generated above. Codeword is c(X) = * data(X)*X**(NN-KK)+ b(X) */ int encode_rs(dtype data[KK], dtype bb[NN-KK]) { register int i, j; gf feedback; CLEAR(bb,NN-KK); for (i = KK - 1; i >= 0; i--) { #if (MM != 8) if(data[i] > NN) return -1; /* Illegal symbol */ #endif feedback = Index_of[data[i] ^ bb[NN - KK - 1]]; if (feedback != A0) { /* feedback term is non-zero */ for (j = NN - KK - 1; j > 0; j--) if (Gg[j] != A0) bb[j] = bb[j - 1] ^ Alpha_to[modnn(Gg[j] + feedback)]; else bb[j] = bb[j - 1]; bb[0] = Alpha_to[modnn(Gg[0] + feedback)]; } else { /* feedback term is zero. encoder becomes a * single-byte shifter */ for (j = NN - KK - 1; j > 0; j--) bb[j] = bb[j - 1]; bb[0] = 0; } } return 0; } /* * Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful, * writes the codeword into data[] itself. Otherwise data[] is unaltered. * * Return number of symbols corrected, or -1 if codeword is illegal * or uncorrectable. * * First "no_eras" erasures are declared by the calling program. Then, the * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). * If the number of channel errors is not greater than "t_after_eras" the * transmitted codeword will be recovered. Details of algorithm can be found * in R. Blahut's "Theory ... of Error-Correcting Codes". */ int eras_dec_rs(dtype data[NN], int eras_pos[NN-KK], int no_eras) { int deg_lambda, el, deg_omega; int i, j, r; gf u,q,tmp,num1,num2,den,discr_r; gf recd[NN]; gf lambda[NN-KK + 1], s[NN-KK + 1]; /* Err+Eras Locator poly * and syndrome poly */ gf b[NN-KK + 1], t[NN-KK + 1], omega[NN-KK + 1]; gf root[NN-KK], reg[NN-KK + 1], loc[NN-KK]; int syn_error, count; /* data[] is in polynomial form, copy and convert to index form */ for (i = NN-1; i >= 0; i--){ #if (MM != 8) if(data[i] > NN) return -1; /* Illegal symbol */ #endif recd[i] = Index_of[data[i]]; } /* first form the syndromes; i.e., evaluate recd(x) at roots of g(x) * namely @**(B0+i), i = 0, ... ,(NN-KK-1) */ syn_error = 0; for (i = 1; i <= NN-KK; i++) { tmp = 0; for (j = 0; j < NN; j++) if (recd[j] != A0) /* recd[j] in index form */ tmp ^= Alpha_to[modnn(recd[j] + (B0+i-1)*j)]; syn_error |= tmp; /* set flag if non-zero syndrome => * error */ /* store syndrome in index form */ s[i] = Index_of[tmp]; } if (!syn_error) { /* * if syndrome is zero, data[] is a codeword and there are no * errors to correct. So return data[] unmodified */ return 0; } CLEAR(&lambda[1],NN-KK); lambda[0] = 1; if (no_eras > 0) { /* Init lambda to be the erasure locator polynomial */ lambda[1] = Alpha_to[eras_pos[0]]; for (i = 1; i < no_eras; i++) { u = eras_pos[i]; for (j = i+1; j > 0; j--) { tmp = Index_of[lambda[j - 1]]; if(tmp != A0) lambda[j] ^= Alpha_to[modnn(u + tmp)]; } } #ifdef ERASURE_DEBUG /* find roots of the erasure location polynomial */ for(i=1;i<=no_eras;i++) reg[i] = Index_of[lambda[i]]; count = 0; for (i = 1; i <= NN; i++) { q = 1; for (j = 1; j <= no_eras; j++) if (reg[j] != A0) { reg[j] = modnn(reg[j] + j); q ^= Alpha_to[reg[j]]; } if (!q) { /* store root and error location * number indices */ root[count] = i; loc[count] = NN - i; count++; } } if (count != no_eras) { printf("\n lambda(x) is WRONG\n"); return -1; } #ifndef NO_PRINT printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); for (i = 0; i < count; i++) printf("%d ", loc[i]); printf("\n"); #endif #endif } for(i=0;i 0; j--) if (reg[j] != A0) { reg[j] = modnn(reg[j] + j); q ^= Alpha_to[reg[j]]; } if (!q) { /* store root (index-form) and error location number */ root[count] = i; loc[count] = NN - i; count++; } } #ifdef DEBUG printf("\n Final error positions:\t"); for (i = 0; i < count; i++) printf("%d ", loc[i]); printf("\n"); #endif if (deg_lambda != count) { /* * deg(lambda) unequal to number of roots => uncorrectable * error detected */ return -1; } /* * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo * x**(NN-KK)). in index form. Also find deg(omega). */ deg_omega = 0; for (i = 0; i < NN-KK;i++){ tmp = 0; j = (deg_lambda < i) ? deg_lambda : i; for(;j >= 0; j--){ if ((s[i + 1 - j] != A0) && (lambda[j] != A0)) tmp ^= Alpha_to[modnn(s[i + 1 - j] + lambda[j])]; } if(tmp != 0) deg_omega = i; omega[i] = Index_of[tmp]; } omega[NN-KK] = A0; /* * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form */ for (j = count-1; j >=0; j--) { num1 = 0; for (i = deg_omega; i >= 0; i--) { if (omega[i] != A0) num1 ^= Alpha_to[modnn(omega[i] + i * root[j])]; } num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; den = 0; /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { if(lambda[i+1] != A0) den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])]; } if (den == 0) { #ifdef DEBUG printf("\n ERROR: denominator = 0\n"); #endif return -1; } /* Apply error to data */ if (num1 != 0) { data[loc[j]] ^= Alpha_to[modnn(Index_of[num1] + Index_of[num2] + NN - Index_of[den])]; } } return count; } g3net.c100644 423 0 103231 6246312575 10713 0ustar luigiwheel/*** *** File: g3net.c *** *** Transport data over a faxmodem connection. ***/ char copyright[] = " * Copyright (c) 1996 * Luigi Rizzo (luigi@iet.unipi.it). All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * and other contributors. * 4. Neither the name of the Author nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * "; /*** *** Reed-Solomon encoding courtesy of Phil Karn. *** TIFF header files come from the "libtiff" package by Sam Leffler *** "getopt" comes from the BSD sources. ***/ #include #include #include #include #include /* bzero and friends */ #include /* read/write */ #include "rs.h" #ifndef O_BINARY #define O_BINARY 0 /* dos compatibility hack */ #endif #ifndef min #define min(a,b) ( (a) < (b) ? (a) : (b) ) #endif #define P(x) fprintf x #define Pv(x) if (verbose) fprintf x #define P2(x) if (verbose>1) fprintf x #define P3(x) if (verbose>2) fprintf x #define P4(x) if (verbose>3) fprintf x #define P1(x) #define SRC_WIDTH (64) /*** a g3 line is actually preceded by 2 bytes (line #) */ #define G3_WIDTH (SRC_WIDTH+2) #define SRCLINES KK #define ECCLINES 255 /* for RS codes */ #define SRC_BLKSIZE (SRC_WIDTH * SRCLINES) #define ECC_BLKSIZE (SRC_WIDTH * ECCLINES) #define u_char unsigned char #define u_long unsigned long int verbose=0; #ifdef MSDOS #define MSDOS_ON 1 #define UNIX_ON 0 #else #define MSDOS_ON 0 #define UNIX_ON 1 #endif int reverse=MSDOS_ON; int add_tiff=MSDOS_ON; u_long tot_lines = 0; /* reset once per output file */ #ifdef MISSING_BZERO /* and other systems missing some functions */ /* these are only here to make the program compile, and work * slowly. If you can, use/write better replacement functions. */ void bzero(char *b, long len) { for (; len ; len--) *b++ = 0; /* slow but who cares! */ } void bcopy(char *src, char *dst, long len) { for (; len ; len--) *dst++ = *src++ ; } void srandom(unsigned seed) { } long random(void) { static long prev=1; prev = ( prev * 17 ); return (prev); } char *__progname="g3net"; #endif char usage[] = "%s [-e] [-d] [-r] [-t] [-v] [-f] [inputfile] [-o] [outputfile]\n" " -d decode input file (containing g3 data) -- default\n" " -e encode input file into g3 data\n" " -r [toggle] reverse input bits (default on MSDOS)\n" " -t [toggle] produce a TIFF file instead of a g3 file\n" " -v be verbose\n" " -f optional prefix for input file\n" " -o optional prefix for output file\n" "local defaults: decode, " #ifdef MSDOS "reverse bits, tiff, " #endif "input from stdin, output to stdout\n"; /*** *** some info on data layout *** ENCODING Source data consists of a block of bytes, whose first 2 bytes (little endian) indicate the length of the block. The max (source) blocksize is SRCLINES * SRC_WIDTH - 2. The block is copied to eccbuf[], where each row of KK bytes is copied to a vector of size ECCLINES (the additional space is used for ecc codes, the last line is padded to an integer multiple of SRCLINES. Data in eccbuf[] is then encoded using RS codes, then transposes (column by column, in a temporary buffer), rotated, and encoded as g3 data. Before g3-encoding, each line is prepended with 2 copies of its index. The encoding process saves data to an array and the associated len. The array includes the leading and tailing EOL codes. DECODING The decoding process is passed a pointer to the received g3 data and the length of the block. Data is first g3-decoded, saving each line to a temporary buffer, and its length into the length[] vector. Then, the first 2 bytes of the temporary buffer are tested. If they match, we have a valid line, possibly partial, which is then transposed and copied to eccbuf[] keeping length information. Unused positions are zero-filled (but they are considered erasures by the RS decoding process). After g3-decoding, row by row we compute the erasures and invoke the RS decoder. *** ***/ u_char * g3_encode_byte(u_char data, u_char *dst, int cmd); #define TESTING #ifdef TESTING /*** *** These functions are only used to test the encoder/decoder ***/ /*** *** add_noise is used for testing purposes, it corrupts g3 data *** to test the robustness of the decoding algorithm. ***/ int add_noise(u_char *data, int datalen, int errors) { /*** *** add errors percent of errors, including scrambled bytes *** and shortened/missing lines ***/ int i, d; errors = (datalen / 100 ) * errors / 100 ; for (i=0; i < errors/2; i++) { d = random() % datalen; P4((stderr, "scrambling byte at g3 offset %d\n", d)); data[d] = 0x5a; } for (i=0; i < errors/2; i++) { int j; d = random() % datalen; P4((stderr, "removing byte at g3 offset %d\n", d)); for (j=d; j < datalen-1 ; j++) data[j] = data[j+1]; datalen-- ; } return datalen; } int test_errs(u_char *src, u_char *dst, int len) { int i, errs=0; for (i=0; i< len ; i++) { if (src[i] != dst[i]) { errs++; Pv((stderr,"error at pos %d - should be 0x%02x - 0x%02x\n", i, src[i], dst[i])); } } if (errs) P((stderr,"%d decoding errors\n",errs)); return 0; } #endif /* TESTING */ int copy_blk(u_char *src, long srclen, u_char *buf, long buflen) { /*** *** copy input data to the buffer, including the two length bytes *** at the beginning, and rs-encode. We use a (190,255) code, and *** exactly 64 columns. Hence, the source is first partitioned in *** 64 blocks, and lines are zero-padded up to position 190. *** ***/ int w = 0, i ; int in_blks = (srclen + SRC_WIDTH - 1) / SRC_WIDTH ; bzero(buf, buflen); for (i=0, w=0 ; i < srclen; ) { buf[w++] = src[i++] ; if ( w == in_blks || i == srclen ) { /* end of line */ P3((stderr, "encoding block %d\n", in_blks)); encode_rs( buf, buf + SRCLINES ); w = 0 ; buf += ECCLINES ; } } return in_blks; } u_char eccbuf[SRC_WIDTH][ECCLINES]; /* buffer for ECC data */ /*** eccbuf is shared by encode and decode functions ***/ /*** *** g3_encode encodes a block of max SRC_BLKSIZE bytes. The length of the *** encoded block is returned, or -1 if an error occurs. The only possible *** error at this point is passing invalid parameters. *** *** src: pointer to the data block. *** srclen: block size. srclen=0 means that an end of block *** is produced. *** NOTE NOTE NOTE: the first two bytes of the block are *** overwritten with the length of the block, so they should *** not contain user data. *** dst: pointer to the output block. Sufficient size is assumed, *** the block expands roughly by a factor of 2. ***/ int g3_encode(u_char *src, int srclen, u_char *dst) { int i, n1, n_ecc; u_char *dst0 = dst; if (srclen < 0 || srclen > SRC_BLKSIZE) { P((stderr,"invalid srclen %d\n", srclen)); return -1; } if (srclen == 0) { /*** final padding of page ***/ for (i=0; i<8 ; i++) dst = g3_encode_byte(0, dst, 3); /* EOL, padded */ return dst - dst0; } src[0] = srclen & 0xff; src[1] = (srclen >>8) & 0xff; n1 = copy_blk( src, srclen, &eccbuf[0][0], sizeof(eccbuf) ); n_ecc = min (ECCLINES-SRCLINES, (n1+1)/2 ); Pv((stderr, "*** Encoding %d bytes (%d data blocks, %d ecc lines)\n", srclen, n1, n_ecc)); n_ecc += SRCLINES ; /* easier for comparisons */ /*** *** at this point have blks rows, each containing 255 bytes of *** ECC data. Must now scramble and g3-encode. *** To protect from transmission errors, each line is also error- *** protected with a N,N+1 RS code. ***/ dst = g3_encode_byte(0, dst, 0); /* reset encoder */ for (i=0; i<2 ; i++) dst = g3_encode_byte(0, dst, 3); /* initial EOL, padded */ for (i=0; i= n1 && i < SRCLINES) || i >= n_ecc) { P3((stderr,"skipping line %d\n",i)); continue; } /*** *** send only non-zero data lines (say N1). *** Fully-zero lines between N1 and SRCLINES are assumed *** as correctly received and default to all-zeroes. *** *** send at most max( ECCLINES-SRCLINES, (N1*2)/5) ECC lines, *** others default as erasures. ***/ /*** *** here we provide the g3 encoding for the line ***/ P3((stderr, "g3-encoding line %d, size %d starts with " "0x%02x 0x%02x 0x%02x 0x%02x\n",i, G3_WIDTH, eccbuf[rot][i], eccbuf[(rot+1)%SRC_WIDTH][i], eccbuf[(rot+2)%SRC_WIDTH][i], eccbuf[(rot+3)%SRC_WIDTH][i] )); dst = g3_encode_byte((u_char)i, dst, 1); /* index */ dst = g3_encode_byte((u_char)i, dst, 1); /* index */ for (j=0; j < SRC_WIDTH ; j++) { dst = g3_encode_byte(eccbuf[rot++][i], dst, 1); /* data */ if (rot == SRC_WIDTH) rot = 0; } dst = g3_encode_byte(0, dst, 2); /* final EOL */ } dst = g3_encode_byte(0, dst, 4); /* black line and one more EOL, padded */ #if 0 for (i=0; i<6 ; i++) dst = g3_encode_byte(0, dst, 3); /* final EOL */ #endif Pv((stderr, "--- encoding process returns %d bytes\n", dst - dst0)); return (dst - dst0); } /*** *** these are the g3 codes used to encode bits. ***/ u_char w_len[16] = { /* length of g3 white codes */ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6 }; u_char w_code[16] = { /* g3 white codes */ 0x0e, 0x01, 0x0d, 0x03, 0x07, 0x0f, /* length 4 */ 0x19, 0x05, 0x1c, 0x02, /* length 5 */ 0x04, 0x30, 0x0b, 0x2b, 0x15, 0x35 /* length 6 */ }; u_char w_g3_len[16] = { /* corresponding segment lengths in pixels */ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }; u_char b_len[4] = { 2, 2, 3, 3 }; u_char b_code[4] = { 0x3, 0x1, 0x2, 0x6 }; u_char b_g3_len[4] = { 2, 3, 1, 4 }; /*********************************************************************** *** *** these are the 'white' codes which are used to fill-up a line to *** its standard width (1728), so the file is a compliant g3 file. *** ***********************************************************************/ /* termina codes white, start 0, step 1, len 64 */ struct g3code { u_short code; u_short len ; } ; struct g3code t_white[64] = { { 0x0ac, 8 }, { 0x038, 6 }, { 0x00e, 4 }, { 0x001, 4 }, { 0x00d, 4 }, { 0x003, 4 }, { 0x007, 4 }, { 0x00f, 4 }, { 0x019, 5 }, { 0x005, 5 }, { 0x01c, 5 }, { 0x002, 5 }, { 0x004, 6 }, { 0x030, 6 }, { 0x00b, 6 }, { 0x02b, 6 }, { 0x015, 6 }, { 0x035, 6 }, { 0x072, 7 }, { 0x018, 7 }, { 0x008, 7 }, { 0x074, 7 }, { 0x060, 7 }, { 0x010, 7 }, { 0x00a, 7 }, { 0x06a, 7 }, { 0x064, 7 }, { 0x012, 7 }, { 0x00c, 7 }, { 0x040, 8 }, { 0x0c0, 8 }, { 0x058, 8 }, { 0x0d8, 8 }, { 0x048, 8 }, { 0x0c8, 8 }, { 0x028, 8 }, { 0x0a8, 8 }, { 0x068, 8 }, { 0x0e8, 8 }, { 0x014, 8 }, { 0x094, 8 }, { 0x054, 8 }, { 0x0d4, 8 }, { 0x034, 8 }, { 0x0b4, 8 }, { 0x020, 8 }, { 0x0a0, 8 }, { 0x050, 8 }, { 0x0d0, 8 }, { 0x04a, 8 }, { 0x0ca, 8 }, { 0x02a, 8 }, { 0x0aa, 8 }, { 0x024, 8 }, { 0x0a4, 8 }, { 0x01a, 8 }, { 0x09a, 8 }, { 0x05a, 8 }, { 0x0da, 8 }, { 0x052, 8 }, { 0x0d2, 8 }, { 0x04c, 8 }, { 0x0cc, 8 }, { 0x02c, 8 }, }; /* make-up codes white start 64, step 64, len 27 */ struct g3code m_white[27] = { { 0x01b, 5 }, { 0x009, 5 }, { 0x03a, 6 }, { 0x076, 7 }, { 0x06c, 8 }, { 0x0ec, 8 }, { 0x026, 8 }, { 0x0a6, 8 }, { 0x016, 8 }, { 0x0e6, 8 }, { 0x066, 9 }, { 0x166, 9 }, { 0x096, 9 }, { 0x196, 9 }, { 0x056, 9 }, { 0x156, 9 }, { 0x0d6, 9 }, { 0x1d6, 9 }, { 0x036, 9 }, { 0x136, 9 }, { 0x0b6, 9 }, { 0x1b6, 9 }, { 0x032, 9 }, { 0x132, 9 }, { 0x0b2, 9 }, { 0x006, 6 }, { 0x1b2, 9 }, }; /*** *** encodes one byte. Returns the new value of the pointer, *** possibly advanced during the encoding process. *** *** cmd specifies the actual action, i.e: *** *** 0 : reset encoder, dst unused *** 1 : encode single byte *** 2 : finish line, no padding *** 3 : finish line, padding ***/ static u_char brev[256]; /* bit reversal */ void init_brev() { int i; if (reverse) for (i=0; i<256; i++) brev[i]=i; else for (i=0; i<256; i++) brev[i] = ( ((i & 0x01) << 7) | ((i & 0x02) << 5) | ((i & 0x04) << 3) | ((i & 0x08) << 1) | ((i & 0x10) >> 1) | ((i & 0x20) >> 3) | ((i & 0x40) >> 5) | ((i & 0x80) >> 7) ); } u_char * g3_encode_byte(u_char data, u_char *dst, int cmd) { #define C_WHITE 4 #define C_BLACK 2 #define C_EOL 0 static int c = C_WHITE; /* start with white */ static int in_bits =0, out_bits = 0 ; static u_long in_buf = 0, out_buf = 0 ; static u_char *dst0; static int this_line_len = 0; static long this_bytes = 0; if (cmd == 0) { P4((stderr,"g3_encode_byte: execute cmd 0 dst 0x%08lx\n", (u_long)dst)); c = C_WHITE; in_bits = out_bits = 0; in_buf = out_buf = 0; this_bytes = 0; this_line_len = 0; dst0 = dst; return dst; } if (dst == NULL || cmd < 1 || cmd > 4) return NULL; if (cmd == 1) { /* encode byte */ data &= 0xff ; in_buf |= (data << in_bits); in_bits += 8; this_bytes++; for (; in_bits >= c;) { u_long d = in_buf & ( (1<< c) - 1 ) ; in_bits -= c; in_buf >>= c; if (c == C_WHITE) { out_buf |= (w_code[d] << out_bits ) ; out_bits += w_len[d] ; this_line_len += w_g3_len[d]; c = C_BLACK; } else { out_buf |= (b_code[d] << out_bits ) ; out_bits += b_len[d] ; this_line_len += b_g3_len[d]; c = C_WHITE; } } } else { /* close line */ P4((stderr,"g3_encode_byte: execute cmd %d off %d\n",cmd,dst-dst0)); if (in_bits != 0) { /* is an error */ P((stderr,"g3_encode_byte: error, have %d bits after %ld bytes\n", in_bits, this_bytes)); this_bytes = 0; return NULL; } { /* pad line */ int delta = 1728 - this_line_len; int m = delta/64 - 1 ; int t = delta & 63 ; P4((stderr,"line len %d, pad with %d, %d\n", this_line_len, m , t)); if (m>=0) { out_buf |= (m_white[m].code << out_bits); out_bits += m_white[m].len ; } out_buf |= (t_white[t].code << out_bits); out_bits += t_white[t].len ; this_line_len = 0; while (out_bits >= 8) { P4((stderr,"emitting 0x%02x\n", (u_char)(out_buf & 0xff))); *dst++ = brev[ (u_char)(out_buf & 0xff) ]; out_buf >>= 8; out_bits -= 8; } } tot_lines ++; /* count of total lines */ this_bytes = 0; if (cmd == 4) { #if 1 /* crude hack to add a black line */ static int black[] = { /* code/length */ #if 0 0x800, 12, /* code/len */ 0xAC, 8, /* white segment */ 0xa40, 13, /* black span */ 0x6, 3, /* black fillup */ 0x800, 12, /* code/len */ 0xAC, 8, /* white segment */ 0xa40, 13, /* black span */ 0x6, 3, /* black fillup */ 0x800, 12, /* code/len */ 0xAC, 8, /* white segment */ 0xa40, 13, /* black span */ 0x6, 3, /* black fillup */ #endif 0x0, 0 }; /* terminator */ int *ip = black; u_long code, data; tot_lines --; /* XXX */ for (;;) { while (out_bits >= 8) { P4((stderr,"emitting 0x%02x\n", (u_char)(out_buf & 0xff))); *dst++ = brev[ (u_char)(out_buf & 0xff) ]; out_buf >>= 8; out_bits -= 8; } code = *ip++; data = *ip++; if (data == 0) break; code &= (1< 4) out_bits = 12 ; else if (out_bits > 0) out_bits = 4; } /* now is simply eol */ out_buf |= ( 0x800 << out_bits ); /* add eol code */ out_bits += 12; /* max 24 now */ } while (out_bits >= 8) { P4((stderr,"emitting 0x%02x\n", (u_char)(out_buf & 0xff))); *dst++ = brev[ (u_char)(out_buf & 0xff) ]; out_buf >>= 8; out_bits -= 8; } return dst; } void repack(u_char *data) { int i, len, blk; u_char * s, *d; len = data[0] + data[1]*256 ; blk = (len + SRC_WIDTH - 1)/SRC_WIDTH; Pv((stderr,"repacking in %d rows\n",blk)); if (blk == SRCLINES || len==0) return; /* no need! */ /*** fist line is ok ***/ s = data + SRCLINES ; d = data + blk; for (i=1; i= 8) { if (pos < G3_WIDTH + 2 /* index */) { u_char d = out_buf & 0xff; g3buf[pos++] = d ; out_buf >>= 8; out_bits -= 8; if (pos < 10) P4((stderr,"emitting byte 0x%02x (pos %d)\n", d, pos -1)); } else { /*** *** should not happen, unless the line is too long ***/ Pv((stderr,"g3 line too long (%d), maybe not a g3net file\n", pos)); goto g3_error; } } if (s >= srclen) break; /*** *** if needed, read one more byte from the input stream ***/ if (in_bits < 12) { in_buf |= brev[ src[s] ] << in_bits ; in_bits += 8; if (pos < 10 || in_buf & 0xfff == 0x800) P4((stderr,"state %d read 0x%02x --> 0x%08lx / %d\n", c, src[s], in_buf, in_bits)); s++ ; } /*** *** run the state machine. Either wait for EOL, WHITE or BLACK ***/ switch (c) { case C_EOL: /*** *** wait for eol, ignoring garbage. Does not start a new line. ***/ while (in_bits >= 12) { if ( (in_buf & 0xfff) == 0x800 ) { /*** found EOL ***/ prev_eol = curr_eol; curr_eol = s; if (skipped_bits) P4((stderr,"found eol, line %d real %d " "g3 offset %d skipped %ld bits\n", line, real_line, s, skipped_bits)); in_buf >>= 12; in_bits -= 12; this_bits = 0; skipped_bits = 0; c = C_WHITE; /*** next, wait for WHITE ***/ goto again; } else { /*** not found, shift and repeat ***/ P4((stderr,"not found eol, in_bits %d, shift by 1\n", in_bits)); in_buf >>= 1; in_bits--; skipped_bits ++; } } /*** need more data ***/ break; case C_WHITE: /*** *** white codes can be 4..6 bits long ***/ if (in_bits < 4) break; lim = min(in_bits,6); for (len = 4; len <= lim; len++) { u_char d = ( in_buf & ( (1 << len) - 1) ); int i; for (i = 0; i < 16; i++) { if (w_len[i] == len && w_code[i] == d) { /* found */ this_bits += 4; out_buf |= ( i << out_bits ); out_bits += 4 ; in_bits -= len ; in_buf >>= len ; if (pos < 10) P4((stderr,"C_WHITE: 0x%1x/4 encoded as " "0x%02x/%d (0x%08lx), total %ld/%ld\n", i, d, len, out_buf, this_bits, this_bits/8)); c = C_BLACK ; goto again; } } } g3_error: /*** *** if we get here, there is an error or an EOL. *** For us the rest of the line does not contain anything. *** need at least 2 bytes for a valid line ***/ if (pos != G3_WIDTH) { /*** *** In case of error, try to skip corrupt bits. ***/ pos = pos - 2; /* XXX */ } if (pos >= 2 && g3buf[0] == g3buf[1] && g3buf[0] >= real_line) { int rot ; line++; if (g3buf[0] >= SRCLINES && real_line < SRCLINES) { int l; for (l = real_line+1; l < SRCLINES; l++) { int j; P3((stderr,"rebuilding line %d\n",l)); for (j=0; j < SRC_WIDTH; j++) eccbuf[j][l] = 0; length[l] = SRC_WIDTH; } } real_line = g3buf[0] ; length[real_line] = pos - 2; /*** skip first 2 bytes ***/ rot = (31*real_line) % (SRC_WIDTH); P2((stderr, "g3-line %d (%d), size %d starts with " "0x%02x 0x%02x 0x%02x 0x%02x\n", real_line, line, pos, g3buf[2], g3buf[3], g3buf[4], g3buf[5] )); /*** *** transpose ***/ for (i = 2; i < pos ; i++) { eccbuf[rot][real_line] = g3buf[i] ; if ( ++rot == SRC_WIDTH ) rot = 0; } if (real_line == ECCLINES - 1) { prev_eol = curr_eol = s; goto end_of_block; /* no need to check further */ } } else { /*** maybe it is the beginning of a new block ? ***/ if (pos >= 2 && g3buf[0] == g3buf[1] && g3buf[0] < real_line && real_line >= SRCLINES) { goto end_of_block; /* no need to check further */ } if (pos > 1) P3((stderr,"line not found, pos %d g3_ofs %d ix " "0x%02x 0x%02x in_buf 0x%08lx/%d\n", pos, s, g3buf[0], g3buf[1], in_buf, in_bits)); g3buf[0] = g3buf[1] = 0xff; } out_bits = 0; out_buf = 0; pos = 0; c = C_EOL; break; case C_BLACK: /*** *** black codes are 2 or 3 bits ***/ if (in_bits < 2) break; lim = min(in_bits,3); for (len = 2; len <= lim; len++) { u_char d = ( in_buf & ( (1 << len) - 1) ); int i; for (i = 0; i < 4; i++) { if (b_len[i] == len && b_code[i] == d) { this_bits += 2; out_buf |= ( i << out_bits ); out_bits += 2 ; in_bits -= len ; in_buf >>= len ; if (pos < 10) P4((stderr,"C_BLACK: 0x%1x/4 encoded as " "0x%02x/%d (0x%08lx), total %ld/%ld\n", i, d, len, out_buf, this_bits, this_bits/8)); c = C_WHITE ; goto again; } } } goto g3_error; } /* switch */ } /* outside for cycle */ } /*** end of g3 decoder block ***/ end_of_block: /*** *** now eccbuf[][] has the source data with erasures. *** Do RS decoding on each of the SRC_WIDTH lines ***/ if (line ==0 ) { Pv((stderr,"no data found, consuming %d bytes\n", srclen)); return srclen; } P2(( stderr, "starting RS decoding on %d lines\n", line )); if (1) { int broken = 0; int missing = 0; for (i=0; i< ECCLINES; i++) { if (length[i] != SRC_WIDTH && length[i] > 0 && i < SRCLINES) { broken++; missing += SRC_WIDTH - length[i] ; Pv((stderr,"*** line %3d width %3d\n", i, length[i])); } } if (broken || missing) Pv((stderr,"%d corrupt lines, %d missing bytes\n", broken, missing)); } for (i=0; i < SRC_WIDTH ; i++) { int eras_pos[ECCLINES]; int eras = 0; int risu; int j; int first = 0; /*** *** compute erasures ***/ for (j = 0; j < ECCLINES ; j++) { long last = (first + length[j]) ; int err = 0; if ( length[j] == 0 /* empty line */ ) err = 1; else if ( last <= SRC_WIDTH ) { if (i < first || i >= last) err = 1; } else { last = last - SRC_WIDTH ; if ( i >= last && i < first ) err = 1; } if (err) { eras_pos[eras++] = j; P2((stderr,"warning, erasure %d at pos %d in line %d\n", eras, j, i)); } if (++first == SRC_WIDTH) first = 0; } if (0 && eras) { char b[ECCLINES+1]; memset(b, '*', eras); b[eras]='\0'; P((stderr,"line %3d erasures %3d %s\n",i, eras, b)); } risu = eras_dec_rs(eccbuf[i], eras_pos, eras); if (risu == -1 ) { Pv((stderr,"Too many errors decoding block %d (%d eras)\n", i, eras)); fail++; } if (dst + SRCLINES - dst0 > dstlen) { P((stderr,"ouch! would overflow buffer (%d vs %d)\n", dst + SRCLINES - dst0, dstlen)); exit(0); } bcopy( eccbuf[i], dst, SRCLINES); dst += SRCLINES; } repack(dst0); if (fail) P((stderr,"%d blocks with decoding errors\n", fail)); return fail ? -1 : prev_eol; /* this many chars were used */ } /*** *** routines to prepend a TIFF header to the file ***/ #include "tiff.h" static u_char tiffdir[512]; static u_char *tiffdirp; uint16 *tiffdircount; /*** *** tde writes a stripped-down directory entry, with only 1 element *** which is <= 4bytes in size. ***/ void tde(u_short tag, u_short type, u_long val) { TIFFDirEntry tde; tde.tdir_tag = tag; tde.tdir_type = type; tde.tdir_count = 1; tde.tdir_offset = val; (*tiffdircount)++; bcopy ((void *)&tde, (void *)tiffdirp, sizeof(tde)); tiffdirp += sizeof(tde); } void make_hdr(int out_file, unsigned length) { TIFFHeader th; u_long cur_pos; Pv((stderr, "%d total lines \n", length)); cur_pos = (u_long)lseek(out_file, 0, SEEK_CUR); /* mark current file position */ if (cur_pos & 1) { write(out_file, "\0", 1); /* pad... */ cur_pos++; } th.tiff_magic = TIFF_LITTLEENDIAN ; th.tiff_version = TIFF_VERSION; th.tiff_diroff = (unsigned long)cur_pos; /* filled in later */ tiffdirp = tiffdir + 2; tiffdircount = (uint16 *)tiffdir; *tiffdircount = 0; /*** now make tiff tags ***/ tde(TIFFTAG_IMAGEWIDTH, TIFF_SHORT, 1728); tde(TIFFTAG_IMAGELENGTH, TIFF_SHORT, length); tde(TIFFTAG_BITSPERSAMPLE, TIFF_SHORT, 1); tde(TIFFTAG_COMPRESSION, TIFF_SHORT, COMPRESSION_CCITTFAX3); tde(TIFFTAG_PHOTOMETRIC, TIFF_SHORT, PHOTOMETRIC_MINISWHITE); tde(TIFFTAG_FILLORDER, TIFF_SHORT, reverse ? FILLORDER_LSB2MSB : FILLORDER_MSB2LSB); /*XXX*/ tde(TIFFTAG_STRIPOFFSETS, TIFF_LONG, 8); tde(TIFFTAG_ORIENTATION, TIFF_SHORT, ORIENTATION_TOPLEFT); tde(TIFFTAG_SAMPLESPERPIXEL, TIFF_SHORT, 1);/*XXX */ tde(TIFFTAG_ROWSPERSTRIP, TIFF_SHORT, length);/*XXX */ tde(TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG, cur_pos-8); tde(TIFFTAG_PLANARCONFIG, TIFF_SHORT, PLANARCONFIG_CONTIG);/*XXX */ bzero(tiffdirp, 4); /* trailing zero required */ tiffdirp += 4; write(out_file, tiffdir, tiffdirp - tiffdir); lseek(out_file, 0, 0); write(out_file, &th, sizeof(th)); } /*** *** end of tiff routines ***/ u_char my_g3buf[ECC_BLKSIZE * 2]; /* oversized! */ u_char srcbuf[SRC_BLKSIZE]; /* buffer for test data */ /*** *** open_out is used to open an output file. If the *** pathname has changed, the old handle is closed (if *** existed) and the new one is opened. *** *** A NULL filename is translated to stdout. *** Existing files are not overwritten. ***/ int open_out(char *outfn) { static char oldfn_buf[256]; static char *oldfn=NULL; static int handle = -1; if (outfn==NULL) outfn="-"; if (oldfn==NULL || strcmp(outfn, oldfn)) { /*** close old handle, open a new one ***/ if (handle > 2 ) { /*** do not close std files ***/ close(handle); handle = -1; } strncpy(oldfn_buf, outfn, sizeof(oldfn_buf) -1 ); oldfn = oldfn_buf; if (!strcmp(outfn,"-")) handle = 1; else handle = open (oldfn, O_BINARY|O_EXCL|O_CREAT|O_WRONLY, 0777); if (handle < 0 ) { P((stderr, "cannot create file %s\n",oldfn)); } } return handle; } /*** *** decode an input file. A NULL outfn is assumed as a will to *** use the original filename. Otherwise, "-" means outoput *** to stdout, and a name ending with a "/" is prepended to *** the original filename. ***/ u_long decode_file(int in_file, char *outfn) { static char outfile[256]; int out_file; u_long written=0; int len, g3len, delta = 0, ofs = 0; int data_offset; int isadir=0; if (in_file < 0) return 1; /* error */ strcpy(outfile,""); if (outfn != NULL) { isadir = (outfn[strlen(outfn)-1] == '/' ); strncpy(outfile, outfn, sizeof(outfile)); } for (;;) { /*** *** read one block from the input file ***/ again: g3len = read(in_file, my_g3buf + delta, sizeof(my_g3buf) - delta); if (g3len < 0) return 0; delta += g3len; /* add previous bytes */ if (delta < sizeof(my_g3buf) && g3len > 0) goto again; g3len = delta; /*** *** try to decode the block ***/ bzero(srcbuf, sizeof(srcbuf)); ofs = g3_decode(my_g3buf, g3len, srcbuf, sizeof(srcbuf) ); if (ofs < 0) { P((stderr,"decode failure! \n")); exit(1); /* decode failure ? */ } /*** *** compute length, offset and possibly file name of data ***/ len = srcbuf[0] + 256*srcbuf[1]; data_offset = srcbuf[2] ; if (len < 3 ) return written ; /* error in decoding */ if (data_offset > 3) { if (outfn == NULL) strncpy(outfile, srcbuf+3, sizeof(outfile)); else if (isadir) sprintf(outfile,"%s%s",outfn,srcbuf+3); P((stderr,"original file name %s, saving to file %s\n", srcbuf+3, outfile)); } else { data_offset = 3; } out_file = open_out(outfile); if (out_file > 0) { written += write(out_file, srcbuf+data_offset, len - data_offset); Pv((stderr,"*** decode done, in %d (%d) g3 bytes, " "out %d data bytes ***\n", g3len, ofs, len - data_offset)); } else { written++; /* to make the program silent */ } delta = g3len - ofs ; if (delta == 0) return written; /* ok */ bcopy(my_g3buf+ofs, my_g3buf, delta) ; } } int encode_file(int in_file, int out_file, char *in_fn, int nerrors) { int test_len, g3len; int delta = 0; int first_block = 1; static u_char inbuf[SRC_BLKSIZE]; /* buffer in encode_file */ if (out_file < 0) return 0; if (add_tiff) write(out_file, inbuf, 8); /* room for tiff header */ for(;;) { int data_ofs = 3; delta = 0; if (first_block) { first_block = 0 ; if (in_fn != NULL && strlen(in_fn) < 60) { strcpy(inbuf+data_ofs, in_fn); data_ofs += strlen(in_fn) + 1; } } again: test_len = read(in_file, inbuf+data_ofs + delta, SRC_BLKSIZE - data_ofs - delta); if (test_len <0 || (test_len+delta == 0)) break; delta += test_len; if (delta < SRC_BLKSIZE - data_ofs && test_len > 0) goto again; test_len = delta + data_ofs; inbuf[0] = test_len & 0xff; inbuf[1] = (test_len >> 8) & 0xff; inbuf[2] = data_ofs ; g3len = g3_encode(inbuf, test_len, my_g3buf); write(out_file, my_g3buf, g3len); if (verbose==0) P((stderr,".")); Pv((stderr,"*** encode done, in %d data bytes," " out %d g3 bytes ***\n", test_len - data_ofs, g3len)); #ifdef TESTING g3len = add_noise(my_g3buf, g3len, nerrors); g3_decode(my_g3buf, g3len, srcbuf, sizeof(srcbuf)); g3len = srcbuf[0] + 256*srcbuf[1]; if (g3len != test_len) P((stderr,"+++ Length mismatch: source %d bytes, got %d\n", test_len, g3len)); else test_errs(inbuf, srcbuf, g3len); #endif /* TESTING */ } g3len = g3_encode(inbuf, 0, my_g3buf); /*** eof page ***/ write(out_file, my_g3buf, g3len); if (add_tiff) make_hdr(out_file, tot_lines); return 0; } int main(int argc,char *argv[]) { char *outfn = NULL; int in_file = 0; /* default: stdin */ int out_file = -1; char *in_file_name="-"; int decode = 1; int i; long t; long nerrors = 0; long written = 0; extern char *optarg; verbose = 0; while ((i = getopt(argc,argv,"ergdtE:vo:")) != EOF) { switch(i){ case 'g': /* raw g3 data */ add_tiff = 0 ; break; case 't': /* add TIFF header */ add_tiff = 1 ; break; case 'r': /* reverse data bits */ reverse = ! reverse ; break; case 'o': /* output file */ outfn = optarg; break; case 'e': /* encode */ decode = 0; break; case 'd': /* Decode */ decode = 1; break; #ifdef TESTING case 'E': /* Number of errors per block */ nerrors = atoi(optarg); break; #endif case 'v': /* Be verbose */ verbose++ ; break; default: P((stderr,usage, argv[0])); exit(1); } } argc -= optind; argv += optind; P1((stderr, "Reed-Solomon code is (%d,%d) over GF(%d)\n", NN,KK,NN+1)); time(&t); srandom(t); init_rs(); init_brev(); /*** *** remaining arguments are assumed to be filenames ***/ if (decode == 0) { out_file = open_out(outfn) ; if (out_file < 0) exit(1); }; while (in_file_name || argc>0) { written = 0; if (argc > 0 ) { in_file_name = argv[0]; argc--; argv++; } P((stderr, "File %s ",in_file_name)); if (!strcmp(in_file_name,"-")) { in_file = 0; /* stdin */ } else in_file = open(in_file_name, O_BINARY | O_RDONLY); if (in_file < 0) { P((stderr,"Cannot open input file %s\n",argv[0])); } if (decode) { written = decode_file(in_file, outfn); if (written == 0) { P((stderr,"Warning, no data written. " "Try again with '-r' flag\n")); } } else { encode_file(in_file, out_file, in_file_name, nerrors); } P((stderr, " done\n")); in_file_name = NULL; } return 0; } Makefile100644 423 0 540 6246244271 11103 0ustar luigiwheelCC=gcc CFLAGS=-O -Wall SRCS= tiff.h rs.h rs.c g3net.c Makefile getopt.c DOCS= notes.txt README.rs g3net.1 README faxspool.diffs ALLSRCS= $(SRCS) $(DOCS) g3net: g3net.o rs.o $(CC) -o g3net g3net.o rs.o g3net.o: g3net.c rs.h tiff.h Makefile rs.o: rs.c rs.h Makefile clean: - rm *.core *.o g3net g3net.tgz: $(ALLSRCS) tar cvzf g3net.tgz $(ALLSRCS) getopt.c100644 423 0 7447 5571276715 11156 0ustar luigiwheel/* * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)getopt.c 8.2 (Berkeley) 4/2/94"; #endif /* LIBC_SCCS and not lint */ #include #include #include int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt, /* character checked for validity */ optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { extern char *__progname; static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (EOF); } if (place[1] && *++place == '-') { /* found "--" */ ++optind; place = EMSG; return (EOF); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means EOF. */ if (optopt == (int)'-') return (EOF); if (!*place) ++optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "%s: illegal option -- %c\n", __progname, optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (opterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __progname, optopt); return (BADCH); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ } notes.txt100664 423 0 5234 6242644636 11370 0ustar luigiwheelNotes on how to transport data over fax transmissions G3 documents are sent as a number of lines. Each line contains codes representing alternating black/white segments. A line is terminates with 11 '0' bits (EOL). 3 or more EOL indicate end of page (?) A line begins with a black segment. In the following data are indicated in transmission order. Black codes have 2 2-bit and 2 3-bit codes, which can be used to represent 2 bits of information, with an average of 1.25 bits/bit. The maximum segment length corresponding to these codes is 3 pixels. White codes have 6 4-bit, 4 5-bit and 7 6-bit codes, which can be used to represent 4 bits of information, with an average of 1.25 bits/bit (actually, slightly lower since there is an unused code which can be used for other purposes). The maximum segment length corresponding to these codes is 16 pixels (17 considering the unused code). Following the above encoding, a 6-bit string takes up to 19 (20) pixels. Since a G3 line can have a maximum width of 1728 pixels, we can encode up to 540 bits/line corresponding to an average length of 686 bits (including the EOL), an average of 1.27 bits/bit. Common sense suggests to keep lines shorter and make them an integral number of bytes, e.g. 64 bytes -> 512 bits. Vertically, a lowres fax can contain 98 dpi resulting in approximately 1000 lines per page. Since one or more lines can get lost, some form of interleaving and redundant encoding must be used, to protect the receiver from losses. A simple encoding could use a Reed-Solomon code where elements of each block are sent one per line, and possibly rotated at each line to achieve a better error correction. Possible structure: ENCODING: 1) pad data to an integral multiple of 128 bytes; 2) for each block build a 255,128 RS code; 3) interleave the code: the source for each line is made of one byte per block, rotated according to the line's number. Each line is additionally prepended by its number (modulo 255). 4) the source data is encoded according to g3 codes. The shortest message is made of 255 lines, each containing a line number and the EOL. Line numbers take on average 10 bits, for a total of 21 bits/line, or 5 Kbit overhead (1/2 second). Data are then expanded by roughly a factor of 2 (depending on the encoding chosen; a (255,160) RS code makes this exactly 2. DECODING: 1) fully missing lines are treated as erasures, partially received ones can be dealt with as errors/erasures. 2) lines are aligned and interleaving removed. 3) blocks are rs-decoded; 4) if errors are present, then this can only be a fax 5) if no errors are present, parse the decoded text for a valid signature. If not found, this is a fax. README.rs100644 423 0 13576 6222705140 11012 0ustar luigiwheelReed-Solomon coding/decoding package v1.0 Phil Karn, KA9Q, September 1996 This package implements general purpose Reed-Solomon encoding and decoding for a wide range of code parameters. It is a rewrite of code by Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy (harit@spectra.eng.hawaii.edu), which was in turn based on an earlier program by Simon Rockliff (simon@augean.ua.oz.au). This package would not exist without the excellent work of these earlier authors. This package includes the following files: readme - this file rs.h - include in user programs. Code params are defined here. rs.c - the initialization, encoder and decoder routines rstest.c - test program makefile - makefile for the test program and encoder/decoder Any good coding theory textbook will describe the error-correcting properties of Reed-Solomon codes in far more detail than can be included here. Here is a brief summary of the properties of the standard (nonextended) Reed-Solomon codes implemented in this package: MM - the code symbol size in bits KK - the number of data symbols per block, KK < NN NN - the block size in symbols, which is always (2**MM - 1) The integer parameters MM and KK are specified by the user. The code currently supports values of MM ranging from 2 to 16, which is almost certainly a wider range than is really useful. Note that Reed-Solomon codes are non-binary. Each RS "symbol" is actually a group of MM bits. Just one bit error anywhere in a given symbol spoils the whole symbol. That's why RS codes are often called "burst-error-correcting" codes; if you're going to have bit errors, you'd like to concentrate them into as few RS symbols as possible. In the literature you will often see RS code parameters given in the form "(255,223) over GF(2**8)". The first number inside the parentheses is the block length NN, and the second number is KK. The number inside the GF() gives the size of each code symbol, written either in exponential form e.g., GF(2**8), or as an integer that is a power of 2, e.g., GF(256). Both indicate an 8-bit symbol. Note that many RS codes in use are "shortened", i.e., the block size is smaller than the symbol size would indicate. Examples include the (32,28) and (28,24) RS codes over GF(256) in the Compact Disc and the (204,188) RS code used in digital video broadcasting. This package does not directly support shortened codes, but they can be implemented by simply padding the data array with zeros before encoding, omitting them for transmission and then reinserting them locally before decoding. A future version of this code will probably support a more efficient implementation of shortened RS codes. The error-correcting ability of a Reed-Solomon code depends on NN-KK, the number of parity symbols in the block. In the pure error- correcting mode (no erasures indicated by the calling function), the decoder can correct up to (NN-KK)/2 symbol errors per block and no more. The decoder can correct more than (NN-KK)/2 errors if the calling program can say where at least some of the errors are. These known error locations are called "erasures". (Note that knowing where the errors are isn't enough by itself to correct them because the code is non-binary -- we don't know *which* bits in the symbol are in error.) If all the error locations are known in advance, the decoder can correct as many as NN-KK errors, the number of parity symbols in the code block. (Note that when this many erasures is specified, there is no redundancy left to detect additional uncorrectable errors so the decoder may yield uncorrected errors.) In the most general case there are both errors and erasures. Each error counts as two erasures, i.e., the number of erasures plus twice the number of non-erased errors cannot exceed NN-KK. For example, a (255,223) RS code operating on 8-bit symbols can handle up to 16 errors OR 32 erasures OR various combinations such as 8 errors and 16 erasures. The three user-callable functions in rs.c are as follows: 1. void init_rs(void); Initializes the internal tables used by the encoder and decoder using the code parameters compiled in from rs.h. This function *must* be called before the encoder or decoder are used for the first time. 2. int encode_rs(dtype data[KK],dtype bb[NN-KK]); Encodes a block in the Reed-Solomon code. The first argument contains the KK symbols of user data to be encoded, and the second argument contains the array into which the encoder will place the NN-KK parity symbols. The data argument is unchanged. For user convenience, the data and bb arrays may be part of a single contiguous array of NN elements, e.g., for a (255,223) code: encode_rs(&data[0],&data[223]); The encode_rs() function returns 0 on success, -1 on error. (The only possible error is an illegal (i.e., too large) symbol in the user data array. Note that the typedef for the "dtype" type depends on the value of MM specified in rs.h. For MM <= 8, dtype is equivalent to "unsigned char"; for larger values, dtype is equivalent to "unsigned int". 3. int eras_dec_rs(dtype data[NN], int eras_pos[NN-KK], int no_eras); Decodes a encoded block with errors and/or erasures. The first argument contains the NN symbols of the received codeword, the first KK of which are the user data and the latter NN-KK are the parity symbols. Caller-specified erasures, if any, are passed in the second argument as an array of integers with the third argument giving the number of entries. E.g., to specify that symbols 10 and 20 (counting from 0) are to be treated as erasures the caller would say eras_pos[0] = 10; eras_pos[1] = 20; eras_dec_rs(data,eras_pos,2); The return value from eras_dec_rs() will give the number of errors (including erasures) corrected by the decoder. If the codeword could not be corrected due to excessive errors, -1 will be returned. The decoder will also return -1 if the data array contains an illegal symbol, i.e., one exceeding the defined symbol size. g3net.1100644 423 0 10636 6246632062 10613 0ustar luigiwheel.\" @(#)g3net.1 8.1 (Rizzo) 11/18/96 .\" $Id: g3net.1,v 1.1 1996/11/18 14:10:00 luigi Exp $ .\" .Dd November 20, 1996 .Dt g3net 1 .Os DEIT .Sh NAME .Nm g3net .Nd decode/encode g3 files into data files .Sh SYNOPSIS .Nm g3net .Op Fl degrotv .Ar [ files ... ] .Sh DESCRIPTION The .Nm g3net utility is used to convert files between g3 format and binary formats. It is intended as an utility to exchange arbitrary files using fax-modems and the associated controlling programs. .Pp In .Ar encoding mode, the input files are converted into a proprietary format (described by the source code) suitable to be transmitted to a faxmodem. In .Ar decoding mode, the reverse process is applied, recovering the original data. The encoded format uses a Reed-Solomon Forward Error Correction code to recover from the large losses (up to 30%) which can occur over noisy phone lines. .Pp Multiple files can be sent in a single ``fax'', and file names are recovered during the decoding process. The program does never overwrite an existing file. .Pp The options are as follows: .Bl -tag -width Ds .It Fl d decoding mode. This is the default. .It Fl e encoding mode. .It Fl r reverse bit order in g3 file. There is no standard bit order for g3 files produced by faxmodems; if the decoding/encoding process is not successful you can add this flags to adapt to the conventions used by your fax-handling program. .It Fl t produce a TIFF file (default on MSDOS) .It Fl g produce raw g3 data (default on Unix). .It Fl v be verbose. Multiple instances of this option increase the level of verbosity (up to unacceptable levels). .It Fl o Ar outputfile output file. In encoding mode, this is simply the file containing fax data. Stdout is used if no file is specified. .Pp In decoding mode, the original names are used if no output file is specified. A filename (or "-" for stdout) indicates where the output goes (multiple files are concatenated together). Finally, specifying a directory name (ending with a "/" as the output file, causes files to be saved with the original names in the specified directory. .Pp The .Nm g3net utility exits 0 on success, and >0 if an error occurs. .Sh APPLICATIONS .Nm has been developed for three main applications: .Ss Shorten fax transmission times .\" .Bl -tag -width 4n -offset indent -compact The size of a fax page is anywhere between 20 and 100Kb, depending on its complexity. However, often faxes are generated electronically, and the source (or even the Postscript encoding) is much smaller, perhaps by a factor of 10. Exchanging document sources instead of the rendered versions can give rise to significant savings in communication times (20-30 seconds/page on average), with significant savings on long-distance communications. .Ss Better use of received documents It is generally hard to reuse the information contained in received faxes, other than to print them. Documents sent using .Nm are more tolerant to transmission errors since an FEC technique is used. Also, the document can be easily manipulated by the receiver. .Ss Tranfer arbitrary data over faxmodems Most owner of a fax modem do not have the ability, possibility, desire or will to set up a proper connection to transport arbitrary data. Rather, they use the fax-handling programs which are supplied with their modems to send/receive faxes. .Nm can be used to overcome these limitations. The program is completely independent from the operating system and fax-handling programs (well, almost -- see BUGS), thus allowing people on different systems to exchange data transparently. .Sh BUGS The program produces a single-page output containing only g3 data. .Pp Because various fax-handling programs prepend different headers to incoming/outgoing faxes, the program might have a hard time in adapting to the various different formats. This is a minor problem in decoding faxes, since the error-correcting features of the encoding make the program able to discard header information. .Pp As for most programs, the code could be much more efficient. .Sh SEE ALSO .Xr pbmtog3 1 .Xr g3topbm 1 .Rs .\".%A Rob Pike .\".%T "UNIX Style, or cat -v Considered Harmful" .\".%J "USENIX Summer Conference Proceedings" .\".%D 1983 .\".Re .Sh AUTHORS .Nm is Copyright (C) 1996 by Luigi Rizzo . The Reed-Solomon code has been written by Phil Karn. .Sh HISTORY The .Nm program was developed as a companion program to mgetty+sendfax. Although meant as a proof of concept only, it has evolved to an usable program. README100664 423 0 20451 6247005123 10360 0ustar luigiwheelThis is g3net, an utility to send arbitrary files as attachments to a fax. This is extremely useful to exchange data with people which are only able to send/receive faxes with a faxmodem, and cannot set up a proper data connection (uucp, kermit, slip/ppp, etc.). Since most people would wonder "Why should I use such a thing!", the section ``MOTIVATION'' will explain why. Please take off your "computer guru" hat when reading that. ================ USE ============================================= g3net has two operating modes: * in ENCODING mode, it takes a set of input files and encodes them producing a TIFF-G3 file. Such a file can be easily handled by any (well, most) fax-handling packages and transmitted to the remote end as if it were a plain fax. No special software is required to send/receive this file. * in DECODING mode, it takes a received fax document (usually containing G3 data) and decodes it. If the ``fax'' was produced by g3net, the files which are part of the archive are extracted. Note that the ``fax'' includes a lot of redundancy, so that even if up to 30% of fax lines are lost/corrupted, it is possible to reconstruct the original document. Transferring files with g3net is extremely simple: 1) the sender encodes files with g3net, producing a TIFF file 2) the TIFF file is transmitted as a fax, using a standard fax-handling software. 3) the TIFF file is received as a fax, using a standard fax-handling software. 4) the received fax is decoded using g3net in decode mode. Since this is the default operating mode, under Windows it suffices to drag the received document over g3net to extract the attachments. ================ MOTIVATION ====================================== Q: Why should one use this complex encoding, when there are better ways to transfer data across two modems, i.e.: - run UUCP - run PPP/SLIP - use some package like kermit, rzsz or the like. A: Consider the typical uses of a fax: 1. sending a facsimile of an existing paper document; 2. send a short note (an order for a product, or a message, etc.) 3. send a relatively long document (e.g. some product information, or a listing, or an article); 4. exchange a document (e.g. a form to be filled in with proper data, or a document which is being edited/revised by different people); A paper FAX is very well suited to situation 1. However, cases 2..4 probably account for the vast majority of faxes exchanged nowadays. In all these cases, the receiver would greatly benefit from having the document sent in some easy-to-process form, e.g. a file containing the desired data. This is what modems and data network have been designed for, you would say ... Unfortunately, most people who own a faxmodem, and use it for cases 2..4, cannot set up a proper data interconnection. They happily run their faxmodems connected to a Windows/Macintosh box with the fax-handling package which comes with the modem. To them, UUCP, PPP, RZSZ are just obscure names. The usefulness of an easy-to-use data-exchanging utility is so strong that several producers try to support it. First of all, the G3 standard includes a ``Binary File Transfer'' capability. None of the Class2 faxmodem that I have tried support this option (maybe they do in Class1 mode, this I don't know). Some FAX-handling packages (e.g. WinFax PRO, Microsoft FAX in Win95) claim to support transfer of binary files using Class1 modems and probably use a proprietary standard to interpret information. Requiring special capabilities for the hardware (or driving it in a special way) and using proprietary protocols is the best way to: a) push the market to use your product, or b) make a feature totally useless At least now, b) seems to be true for data transfers across faxmodems, although big software companies are known to be able to drive the market wherever they want. g3net tries to overcome these limitations in two ways: 1) allows data transfer without requiring special capabilities for the sender/receiver. A plain fax modem will suffice (actually, files encoded with g3net will be received happily by your paper fax, although you'll have a hard time in using them other than for a nice background); 2) uses a non-proprietary data format (in the sense that full sources of the decoder/encoder are freely available), making it possible to exchange files between different architectures. As a side effect, this feature also makes data forwarding possible. Error correction is an important feature of g3net. Transfers across faxmodems are subject to errors due to noisy lines, or slow receiving programs which cannot handle incoming data properly, and it is generally time-consuming to request the retransmission of missing data. Hence, files encoded with g3net include enough redundant information (through the use of (192,255) Reed-Solomon codes and various forms of interleaving) to be able to reconstruct the original document even if 30% of fax lines are not received (or some of them are received incorrectly). ================ APPLICATIONS =================================== There are several applications for g3net: CUTTING PHONE BILL COSTS Typically fax messages include mostly textual information. The ``rendered'' version of these messages have a size of 30..100KB per page, whereas the corresponding ASCII (or RTF, or DOC... ) files are 1-2KB at most. Hence, transmission times can be cut by 15..40 sec/page, with corresponding savings, especially on long distance calls and long documents. SENDING REUSABLE DATA Data sent with g3net can be easily reused at the receiver, since they are in binary format. This is extremely useful for people willing to exchange documents without having to set up some kind of ``networking'' DATA PROTECTION Since g3net enables users to transfer arbitrary files, sensitive data can be sent as encrypted files, with the decryption key transferred separately. E.g. you can send reserved info to somebody's fax server without worrying that indiscrete eyes can watch at them, only the authorized people can read the information. DEVELOPING NEW APPLICATIONS The ability to transfer binary files in a transparent way enables a number of new applications. We mention only a few of them: + COLOR FAX (transfer images encoded with g3net; a JPEG image is not much bigger than a comparable-size fax page, and can be transferred easily); + DATA OVER FAX (use g3net and a fax connection as a transport for email for places which cannot setup a proper UUCP connection); + DATA ON DEMAND (include g3net-encoded files, e.g. drivers, pictures, among those server by a fax-on-demand system; this is trivial and does not require any change whatsoever to the existing setup); + DATA COLLECTION (a factory, store, or other site can receive reports from remote sites using the same line used for incoming faxes); Sources compile fine with gcc (djgpp under DOS), and are written to be as platform-independant as possible. It is likely that it can even compile on Apple systems. =============== ACKNOWLEDGEMENTS ================================ This program could not have been written without the availability of a Reed-Solomon implementation ("rs.c") by Phil Karn, Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy (harit@spectra.eng.hawaii.edu). The file "tiff.h" and some details on the structure of TIFF files come from the "libtiff" package by Sam Leffler. The "getopt" implementation comes from the BSD sources. Finally, this program can compile easily under MSDOS thank to the DJGPP compiler (a port of GNU's gcc to MSDOS) by D.J. Delorie. The proper Copyright messages appear in each file which has not been written originally by me. For this package as a whole, the Copyright conditions are specified in "g3net.c". It is basically a BSD-style copyright. Luigi Rizzo (luigi@iet.unipi.it) ==================================================================== Luigi Rizzo Dip. di Ingegneria dell'Informazione email: luigi@iet.unipi.it Universita' di Pisa tel: +39-50-568533 via Diotisalvi 2, 56126 PISA (Italy) fax: +39-50-568522 http://www.iet.unipi.it/~luigi/ ==================================================================== faxspool.diffs100664 423 0 2712 6244312266 12336 0ustar luigiwheel--- faxspool.orig Sun Nov 17 00:01:14 1996 +++ faxspool.new Tue Nov 19 09:26:55 1996 @@ -117,6 +117,12 @@ g3cat $1 >$2.1 } +# "convert" raw file +# +fs_cvt_raw() +{ + (cat /usr/local/lib/mgetty+sendfax/header.g3net; g3net -e $1 ) | g3cat - >$2.1 +} # # convert a X11 xwd file - scaled to fill the whole page width # since we do not know whether it's colour or grey or what, we have @@ -316,6 +322,7 @@ poll_req="" verbose_to="" normal_res="" +rawformat="" TIME="" # @@ -341,6 +348,9 @@ # enable polling -p) poll_req=true ; shift ;; +# raw format + -r) rawformat="1" ; shift + ;; # use normal resolution (as opposed to fine resolution) -n) normal_res="-n" ; shift ;; @@ -622,6 +632,8 @@ # # try to determine file type by extention (won't work for print spooler!) # + if [ -z "$rawformat" ] + then case $file in *.g3) format="g3" ; base=`basename $file .g3` ;; *.ps) format="ps" ; base=`basename $file .ps` ;; @@ -640,6 +652,9 @@ *.tif) format="tif"; base=`basename $file .tif`;; *.tiff) format="tif"; base=`basename $file .tiff`;; esac + else + format="raw"; base="rawfile"; + fi # if we don't know the file type now, let's try something more esoteric @@ -721,7 +736,7 @@ if case $format in - ps | ascii | pbm | pgm | ppm |\ + raw | ps | ascii | pbm | pgm | ppm |\ g3 | dvi | lj | xwd | gif | tif ) fs_cvt_$format $file $target $normal_res ;;