0707070035351137021006640007620000050000010260220476773366500001100000001573Bfeats.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* Bfeats.h - typedef, constants, and function declarations for Bfeats. INCLUDES Requires prior #include "BMask.h" */ typedef struct Bfeats { BMask bm; /* bitmask (1 for each feature) */ unsigned short mny; /* number of feature indices in fa[] */ unsigned short *fa; /* fa[mny] of feature (ss) nos, no dups (malloc) */ } Bfeats; #define Init_Bfeats {Init_BMask,0,NULL} #if MAIN Bfeats empty_Bfeats = Init_Bfeats; #else extern Bfeats empty_Bfeats; #endif Bfeats *alloc_bfeats(); free_bfeats(); char *bfeats_toa(); Bfeats *dup_bfeats(); 0707070035351137031006640007620000050000010260240476773366500001100000470007Bitmap.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* Bitmap.h: 2-D fixed-sized bitmaps */ /* BITMAP TEMPLATES: potentially MACHINE-DEPENDENT bit-packing */ #define Bm_h 54 /* height (no. bits) */ #define Bm_il 3 /* width (no. ints) */ #define Bm_ex_h 5 /* extra pixels allowed, top/bottom */ #define Bm_ex_w 16 /* extra pixels allowed, left/right */ #define Bm_wi ((int)(8*sizeof(int))) /* width of an int in bits; sizeof() is unsigned: must coerce to signed so can compare correctly with negative ints */ typedef unsigned int Bm_l[Bm_il]; /* bitmap line */ #define Bm_w (Bm_wi*Bm_il) /* width of bitmap (<= # bits in a Bm_l) */ #define Bm_w_ok (Bm_w+2*Bm_ex_w) /* OK width (sides truncated to fit) */ #define Bm_h_ok (Bm_h+2*Bm_ex_h) /* OK height (top/bot truncated to fit) */ #define Bm_area (Bm_w*Bm_h) /* area of bitmap */ #define Bm_ni (Bm_il*Bm_h) /* no. ints in bitmap area */ #define Bm_ns (2*Bm_ni) /* no. of shorts in bitmap area */ typedef union Bm { /* the rectangular array of bits */ Bm_l l[Bm_h]; int unsigned i[Bm_ni]; short unsigned s[Bm_ns]; } Bm; typedef struct Bm_consts { unsigned int mask_all; /* all bitmap bits set */ unsigned int mask[Bm_wi]; /* constant mask bits (in int) */ unsigned char Rbits[256]; /* Bytes with bits reversed */ unsigned char Nbits[65536]; /* Nbits[i] = no. bits set in (unsigned short) i */ } Bm_consts; /* The following 2076 lines are a static initialization for Bm_consts; it is written by program `mkbmc' which runs function `fwra_bm_consts' */ #if MAIN Bm_consts bm_consts = { 0xffffffff, { 0x1,0x2,0x4,0x8, 0x10,0x20,0x40,0x80, 0x100,0x200,0x400,0x800, 0x1000,0x2000,0x4000,0x8000, 0x10000,0x20000,0x40000,0x80000, 0x100000,0x200000,0x400000,0x800000, 0x1000000,0x2000000,0x4000000,0x8000000, 0x10000000,0x20000000,0x40000000,0x80000000 }, { 00,0200,0100,0300,040,0240,0140,0340,020,0220,0120,0320,060,0260,0160,0360, 010,0210,0110,0310,050,0250,0150,0350,030,0230,0130,0330,070,0270,0170,0370, 04,0204,0104,0304,044,0244,0144,0344,024,0224,0124,0324,064,0264,0164,0364, 014,0214,0114,0314,054,0254,0154,0354,034,0234,0134,0334,074,0274,0174,0374, 02,0202,0102,0302,042,0242,0142,0342,022,0222,0122,0322,062,0262,0162,0362, 012,0212,0112,0312,052,0252,0152,0352,032,0232,0132,0332,072,0272,0172,0372, 06,0206,0106,0306,046,0246,0146,0346,026,0226,0126,0326,066,0266,0166,0366, 016,0216,0116,0316,056,0256,0156,0356,036,0236,0136,0336,076,0276,0176,0376, 01,0201,0101,0301,041,0241,0141,0341,021,0221,0121,0321,061,0261,0161,0361, 011,0211,0111,0311,051,0251,0151,0351,031,0231,0131,0331,071,0271,0171,0371, 05,0205,0105,0305,045,0245,0145,0345,025,0225,0125,0325,065,0265,0165,0365, 015,0215,0115,0315,055,0255,0155,0355,035,0235,0135,0335,075,0275,0175,0375, 03,0203,0103,0303,043,0243,0143,0343,023,0223,0123,0323,063,0263,0163,0363, 013,0213,0113,0313,053,0253,0153,0353,033,0233,0133,0333,073,0273,0173,0373, 07,0207,0107,0307,047,0247,0147,0347,027,0227,0127,0327,067,0267,0167,0367, 017,0217,0117,0317,057,0257,0157,0357,037,0237,0137,0337,077,0277,0177,0377 }, { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15,12,13,13,14,13,14,14,15,13,14,14,15,14,15,15,16 } }; #else extern Bm_consts bm_consts; #endif double Bm_match(); char *BM_toa(); 0707070035351137041006640007620000050000010260520476773366600001000000207047CCITT.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* CCITT.c - functions for CCITT compression/decompression of binary images. The following discussion is a summary of CCITT Recommendations T.4 and T.6 on facsimile coding schemes and coding control functions for Group 3 and Group 4 facsimile apparatus (drafted at Malaga-Torremolinos, 1984). They describe algorithms for invertible (lossless) compression and decompression of bilevel (black-and-white, not grey) 2D rectangular images of arbitrary height and width. By convention the images are processed top-down, one horizontal scan line at a time. It is not strictly necessary to know the height of an image before starting compression or decompression. Width, however, must be known in advance in some cases (discussed below), and must remain constant for the whole image in all cases. There are three distinct but intimately related standards: Group 3 1-dimensional, Group 3 2-dimensional, and Group 4. VLSI hardware implementations always include all three. The Group 3 encodings are used in the vast installed base of FAX machines. Group 4 is not used in today's FAX machines, but seems to be the default standard in document image archiving applications. The CCITT Group 3 FAX standard permits either 1-D or 2-D encoding. It is not easy to tell from an encoding which was used. Both 1-D and 2-D assume fixed scanline length (in pixels), which must be known at encoding time. Group 3 1-D (g31) code uses fixed ``modified Huffman'' codes for run-lengths, with two different code tables for black and white runs. Each line is assumed to begin with a (possibly 0-length) white run. Of course, the colors strictly alternate. An empty (all-white) line is supposed to be spelled out with a full pixel count, although some decoders won't complain if just a 0-length count is used. There are provisions for fill bits at the end of lines to allow slow receiving equipment to keep up. Each line ends with an EOL code on which it may be possible to synchronize after transmission error. Group 3 2-D (g32) encoding tries to exploit the slowly-changing nature of artwork from line to line. It is a mixture of 1-D-coded lines and ``2-D''-coded lines describing small local changes relative to the immediately prior ``reference'' line. 1-D coding recurs every few (`k') lines, so that resynchronization is frequently possible. K is usually 2 or 4, but the standard permits any number, even infinity, since the coding method used on a line is specified by which of two special EOLx codes is used to end the prior line. CCITT Group 4 (g4) is like Group 3 2-D, but optimized to take advantage of a lossless communications channel or reliable storage medium (such as computer memory), where resynchronization is unnecessary. Thus the first line is 2-D encoded referenced to an imaginary initial blank line, k is always infinity, and EOL's are not used at all. It essential that the line-length be known in advance of both encoding and decoding, so that line-breaks can be triggered when that length is exceeded. End of FAX buffer (end of page) is signaled by a special EOFB code. On images of printed text and sparse line-graphics, g4-compressed files are often 15-40X smaller than bitmap (packed bits), 5X than bitfile(9.5), 2X than g31, and 2X than rle | pack. PERFORMANCE On 10 printed A4 pages (business letters, technical reports, etc), at a resolution of 400 dpi: binary: 2020 Kbytes CPU secs (to compress binary) pack: 200 - 380 17 bitfile(9.5): 150 - 360 ? rle: 100 - 230 7.5 compress: 90 - 155 14 g31: 85 - 190 13 g32: 55 - 110 13 g4: 30 - 70 13 G4-compressed files are 15-40X smaller than binary, 5X than bitfile(9.5), 3.5X than rle, 2X than g31, and 2X than rle | pack. */ #include <stdio.h> #include <string.h> #include <ctype.h> #include "CPU.h" #include "stdocr.h" #include "rle.h" #include "bitio.h" #include "CCITT.h" #define DEBUG 0 /* 0 disables compilation of all debugging code; 1 compiles, but must enable particular parts below */ #define NEW_TRAIL 1 /* enable new trailing-0 counts (has passed early tests) */ #define dbg_trail 0 DST_table *ccitt_table() { DST_context cx; if((cx.t = (DST_table *)malloc(sizeof(DST_table)))==NULL) abort("CCITT.c: build_tbl: can't alloc cx.t"); /* All tables have e[DST_white], e[DST_black], & e[DST_2d] entries */ cx.t->mny=3; if((cx.t->e=(DST_entry *)malloc(cx.t->mny*sizeof(DST_entry)))==NULL) abort("CCITT.c: build_tbl: can't alloc cx.t->e[%d]",cx.t->mny); cx.s = cx.c = DST_white; cx.l = 0; cx.t->e[cx.s].p[0] = '\0'; cx.t->e[cx.s].l = 0; cx.t->e[cx.s].z = 0; build_transits(cx); cx.s = cx.c = DST_black; cx.l = 0; cx.t->e[cx.s].p[0] = '\0'; cx.t->e[cx.s].l = 0; cx.t->e[cx.s].z = 0; build_transits(cx); cx.s = cx.c = DST_2d; cx.l = 0; cx.t->e[cx.s].p[0] = '\0'; cx.t->e[cx.s].l = 0; cx.t->e[cx.s].z = 0; build_transits(cx); #if DEBUG if(F) ccitt_err_tbl(cx.t); #endif return(cx.t); } DST_state new_state(t) DST_table *t; { t->mny++; if((t->e=(DST_entry *)realloc(t->e,t->mny*sizeof(DST_entry)))==NULL) abort("can't realloc t->[%d]",t->mny); return(t->mny-1); } /* The entry described by `cx' exists in the table, and its prefix `p' is setup; create its transitions, and their next entries, recursively. */ build_transits(cx) DST_context cx; #define entry cx.t->e[cx.s] #define transit entry.t[col] { DST_color col; DST_entry ne; /* next entry */ DST_context ncx; /* next Context */ char **s,**ss; /* for searching code */ short *c,*cs; int si,matching,longer; char svch,col_str[2]; switch(cx.c) { case DST_white: ss=codewht; cs=bitcwht; break; case DST_black: ss=codeblk; cs=bitcblk; break; case DST_2d: ss=code2d; cs=bitc2d; break; }; for(col=0;col<=1;col++) { sprintf(col_str,"%1d",col); ncx = cx; ncx.l++; /* build a transition */ strcpy(ne.p,entry.p); strcat(ne.p,col_str); ne.l = ncx.l; if(col==0) ne.z = entry.z+1; else ne.z = 0; /* count those that match new prefix */ longer=matching=0; for(s=ss,c=cs,si=0; (*s)!=NULL; s++,c++,si++) { if(*c==ncx.l) { if(strcmp(*s,ne.p)==0) { matching++; switch(cx.c) { case DST_white: case DST_black: transit.a = itor(si); break; case DST_2d: transit.a = si; break; }; }; } else if(*c>ncx.l) { svch=(*s)[ncx.l]; (*s)[ncx.l] = '\0'; if(strcmp(*s,ne.p)==0) { longer++; }; (*s)[ncx.l]=svch; }; }; /* analyze results */ if(matching==0&&longer>0) { /* no match yet; go deeper */ transit.a = DST_action_NULL; ncx.s = transit.s = new_state(cx.t); strcpy(cx.t->e[ncx.s].p,ne.p); cx.t->e[ncx.s].l = ne.l; cx.t->e[ncx.s].z = ne.z; build_transits(ncx); } else if(matching==1&&longer==0) { /* unique leaf: good */ /* picked up action earlier */ switch(cx.c) { case DST_white: case DST_black: if(transit.a<=63) /* termination code */ transit.s = flip_color(cx.c); else /* makeup code */ transit.s = cx.c; break; case DST_2d: /* legal end of code */ transit.s = DST_state_NULL; break; }; } else { /* illegal transition */ transit.a = DST_action_ERROR; transit.s = DST_state_NULL; }; }; } ccitt_err_tbl(t) DST_table *t; { int d; ccitt_err_state(DST_white,t); ccitt_err_state(DST_black,t); ccitt_err_state(DST_2d,t); } ccitt_err_state(s,t) DST_state s; DST_table *t; { err("%03d %s %2d %2d%*s %d %03d,%-4d %d %03d,%-4d", s,t->e[s].p,t->e[s].l,t->e[s].z,14-strlen(t->e[s].p)," ", 0,t->e[s].t[0].s,t->e[s].t[0].a, 1,t->e[s].t[1].s,t->e[s].t[1].a ); if(t->e[s].t[0].s>1) ccitt_err_state(t->e[s].t[0].s,t); if(t->e[s].t[1].s>1) ccitt_err_state(t->e[s].t[1].s,t); } /* Translate a stream of bits in CCITT FAX Group 3 (1-D) compression format into a sequence of RLE_Lines. Returns one (RLE_Line *) on each call (or NULL if EOF or error). The first pixel (black or white) in each g31 line is assigned run index 0. */ RLE_Line *g31_to_rlel(t,f,bof) DST_table *t; BITFILE *f; boolean bof; /* beginning of file */ #define dbg_g31r_r (0) /* trace each run/EOL/ERR_SYN */ #define dbg_g31r_c (0) /* trace each Huffman code (or, fill+EOL)*/ #define dbg_g31r_t (0) /* trace each state-transition */ { static DST_context cx; static RLE_Line rl; static RLE_Run *r; /* prior, current runs */ int run,biti,sync,si,bitv; boolean fill; /* color of 1st run in each line */ #define g31_first_color DST_white /* reverse Black/White in output image */ #define g31_negative 0 if(bof){if(T) { /* sync by skipping initial FILL & EOL code */ sync=0; while((bitv=getb(f))==0) sync++; if(bitv!=1||sync<11) { #if DEBUG if(dbg_g31r_c) { fprintf(stderr,"BOF_ERR "); for(si=0;si<sync;si++) fprintf(stderr,"0"); if(bitv==1) fprintf(stderr,"1\n"); else fprintf(stderr,"?\n"); }; #endif return(NULL); } #if DEBUG else if(dbg_g31r_c){ fprintf(stderr,"BOF_EOL "); for(si=0;si<sync;si++) fprintf(stderr,"0"); fprintf(stderr,"1\n"); }; #endif }; /* start file expecting a run-code of a fixed color */ cx.s = cx.c = g31_first_color; rl.y = -1; /* assume first line is y==0 */ }; rl.y++; rl.runs=0; r = rl.r; biti=run=0; while(T) switch(getb(f)) { case 0 : /* next bit is 0 */ switch(t->e[cx.s].t[0].a) { case DST_action_ERROR: /* bad code: try to resynchronize */ #if DEBUG if(dbg_g31r_t){ fprintf(stderr,"%s %04d %s0?...\n", (cx.c==DST_white)? "W": "B", t->e[cx.s].t[0].s, t->e[cx.s].p); }; #endif /* count trailing 0's so far (should be in table) */ #if !NEW_TRAIL sync=1; si=strlen(t->e[cx.s].p)-1; while(si>=0&&t->e[cx.s].p[si]=='0') {sync++; si--;}; fill = (si<0); /* all 0's: may be fill bits */ #else sync=t->e[cx.s].z+1; fill = (sync>t->e[cx.s].l); /* all 0's: maybe fill bits */ #endif #if DEBUG if(dbg_trail) err("sync %d fill %d",sync,fill); if(dbg_g31r_c)fprintf(stderr,"ERR_SYN %s0?",t->e[cx.s].p); #endif while(sync<11) { switch(bitv=getb(f)) { case 0: sync++; #if DEBUG if(dbg_g31r_c) fprintf(stderr,"0"); #endif break; case 1: sync=0; fill=F; #if DEBUG if(dbg_g31r_c) fprintf(stderr,"1"); #endif break; case EOF: #if DEBUG if(dbg_g31r_c) fprintf(stderr,"<EOF>\n"); #endif return(NULL); break; }; }; /* next `1' will synchronize */ do { switch(bitv=getb(f)) { case 0: #if DEBUG if(dbg_g31r_c) fprintf(stderr,"0"); #endif break; case 1: #if DEBUG if(dbg_g31r_c) fprintf(stderr,"1"); #endif break; case EOF: #if DEBUG if(dbg_g31r_c) fprintf(stderr,"<EOF>\n"); #endif return(NULL); break; }; } while(bitv!=1); #if DEBUG if(dbg_g31r_c) fprintf(stderr,"\n"); if(dbg_g31r_r) { if(fill) fprintf(stderr,"FILL_EOL\n"); else fprintf(stderr,"ERR_SYN_EOL\n"); }; #endif /* start next line expecting a run-code of a fixed color */ cx.s = cx.c = g31_first_color; return(&rl); break; case DST_action_NULL: #if DEBUG if(dbg_g31r_t)fprintf(stderr,"%s %04d %s0\n", (cx.c==DST_white)? "W": "B", t->e[cx.s].t[0].s, t->e[cx.s].p); #endif cx.s = t->e[cx.s].t[0].s; break; case DST_EOL: #if DEBUG if(dbg_g31r_c)fprintf(stderr,"EOL %s0\n", t->e[cx.s].p); if(dbg_g31r_r)fprintf(stderr,"EOL\n"); #endif /* start next line expecting a run-code of a fixed color */ cx.s = cx.c = g31_first_color; return(&rl); break; default: #if DEBUG if(dbg_g31r_c)fprintf(stderr,"%s%6d %s0\n", (cx.c==DST_white)? "W": "B", t->e[cx.s].t[0].a, t->e[cx.s].p); #endif if(t->e[cx.s].t[0].a<=63) { run += t->e[cx.s].t[0].a; #if DEBUG if(dbg_g31r_r)fprintf(stderr,"%s%6d\n", (cx.c==DST_white)? "W": "B", run); #endif biti += run; if(cx.c==DST_black^g31_negative) { /* end of black run */ r->xe = biti-1; r++; rl.runs++; } else { /* end of white run */ r->xs = biti; }; cx.c = flip_color(cx.c); run = 0; } else run += t->e[cx.s].t[0].a; cx.s = t->e[cx.s].t[0].s; break; }; break; case 1: /* next bit is 1 */ switch(t->e[cx.s].t[1].a) { case DST_action_ERROR: /* bad code: try to resynchronize */ #if DEBUG if(dbg_g31r_t){ fprintf(stderr,"%s %04d %s1?...\n", (cx.c==DST_white)? "W": "B", t->e[cx.s].t[1].s, t->e[cx.s].p); }; if(dbg_g31r_c)fprintf(stderr,"ERR_SYN %s1?",t->e[cx.s].p); #endif /* no trailing 0's; can't be fill bits */ sync=0; while(sync<11) { switch(bitv=getb(f)) { case 0: sync++; #if DEBUG if(dbg_g31r_c) fprintf(stderr,"0"); #endif break; case 1: sync=0; #if DEBUG if(dbg_g31r_c) fprintf(stderr,"1"); #endif break; case EOF: #if DEBUG if(dbg_g31r_c) fprintf(stderr,"<EOF>\n"); #endif return(NULL); break; }; }; /* next `1' will synchronize */ do { switch(bitv=getb(f)) { case 0: #if DEBUG if(dbg_g31r_c) fprintf(stderr,"0"); #endif break; case 1: #if DEBUG if(dbg_g31r_c) fprintf(stderr,"1"); #endif break; case EOF: #if DEBUG if(dbg_g31r_c) fprintf(stderr,"<EOF>\n"); #endif return(NULL); break; }; } while(bitv!=1); #if DEBUG if(dbg_g31r_c) fprintf(stderr,"\n"); if(dbg_g31r_r) fprintf(stderr,"ERR_SYN_EOL\n"); #endif /* start next line expecting a run-code of a fixed color */ cx.s = cx.c = g31_first_color; return(&rl); break; case DST_action_NULL: #if DEBUG if(dbg_g31r_t)fprintf(stderr,"%s %04d %s1\n", (cx.c==DST_white)? "W": "B", t->e[cx.s].t[1].s, t->e[cx.s].p); #endif cx.s = t->e[cx.s].t[1].s; break; case DST_EOL: #if DEBUG if(dbg_g31r_c)fprintf(stderr,"EOL %s1\n", t->e[cx.s].p); if(dbg_g31r_r)fprintf(stderr,"EOL\n"); #endif /* start next line expecting a run-code of a fixed color */ cx.s = cx.c = g31_first_color; return(&rl); break; default: #if DEBUG if(dbg_g31r_c)fprintf(stderr,"%s%6d %s1\n", (cx.c==DST_white)? "W": "B", t->e[cx.s].t[1].a, t->e[cx.s].p); #endif if(t->e[cx.s].t[1].a<=63) { run += t->e[cx.s].t[1].a; #if DEBUG if(dbg_g31r_r)fprintf(stderr,"%s%6d\n", (cx.c==DST_white)? "W": "B", run); #endif biti += run; if(cx.c==DST_black^g31_negative) { /* end of black run */ r->xe = biti-1; r++; rl.runs++; } else { /* end of white run */ r->xs = biti; }; cx.c = flip_color(cx.c); run = 0; } else run += t->e[cx.s].t[1].a; cx.s = t->e[cx.s].t[1].s; break; }; break; case EOF: return(NULL); break; default: return(NULL); break; }; /* never come here: return() variously from cases above */ } /* Translate a sequence of RLE_Line's (describing a binary image) into a file (a stream of bits) in CCITT FAX Group 3 (1-D) compression format. BOF_to_g31() must be called first; then call rlel_to_g31() for each line (including blank lines); finally, EOF_to_g31() must be called. Each line's EOL and the RTC's first EOL are padded so they end on a byte boundary. */ /* debugging flags: trace to stderr */ #define dbg_rg31_e (0) /* entry */ #define dbg_rg31_r (0) /* runs */ #define dbg_rg31_s (0) /* bitstrings */ #if DEBUG #define bits_g31(bits) { \ cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \ if(dbg_rg31_s) fprintf(stderr,"%s",(bits)); \ if(dbg_rg31_r) fprintf(stderr," "); \ } #define EOL_g31 { \ if(dbg_rg31_r) fprintf(stderr,"EOL "); \ bits_g31(EOLSTRING); \ if(dbg_rg31_r) fprintf(stderr,"\n"); \ } #else #define bits_g31(bits) { \ cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \ } #define EOL_g31 { \ bits_g31(EOLSTRING); \ } #endif BOF_to_g31(f) BITFILE *f; /* state of output bitfile */ { char *cs; EOL_g31; } rlel_to_g31(rl,wid,f) RLE_Line *rl; /* line of runs: if NULL, then blank */ int wid; /* width of an output line in pixels */ BITFILE *f; /* state of output bitfile */ { int pi; /* input pixel index on line */ RLE_Run *rp,*pp,*sp; int runl,codi; char *cs,*p01; #if DEBUG #define Wrun_g31(rn) { \ runl=(rn); \ if(dbg_rg31_r) fprintf(stderr,"W %5d ",runl); \ while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \ p01=codewht[codi=rtoi(runl)]; bits_g31(p01); \ if(codi>=64) {p01=codewht[runl%64]; bits_g31(p01);}; \ if(dbg_rg31_r) fprintf(stderr,"\n"); \ } #else #define Wrun_g31(rn) { \ runl=(rn); \ while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \ p01=codewht[codi=rtoi(runl)]; bits_g31(p01); \ if(codi>=64) {p01=codewht[runl%64]; bits_g31(p01);}; \ } #endif #if DEBUG #define Brun_g31(rn) { \ runl=(rn); \ if(dbg_rg31_r) fprintf(stderr,"B %5d ",runl); \ while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \ p01=codeblk[codi=rtoi(runl)]; bits_g31(p01); \ if(codi>=64) {p01=codeblk[runl%64]; bits_g31(p01);}; \ if(dbg_rg31_r) fprintf(stderr,"\n"); \ } #else #define Brun_g31(rn) { \ runl=(rn); \ while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \ p01=codeblk[codi=rtoi(runl)]; bits_g31(p01); \ if(codi>=64) {p01=codeblk[runl%64]; bits_g31(p01);}; \ } #endif #if DEBUG if(dbg_rg31_e) err("rlel_to_g31(rl[y%d,r%d])",rl->y,rl->runs); #endif if(rl!=NULL&&rl->runs>0) { pi=0; /* bit to write next */ #if DEBUG if(dbg_rg31_e) err("rlel_to_g31(rl[y%d,r%d])",rl->y,rl->runs); #endif for(sp=(rp=rl->r)+rl->runs; rp<sp; rp++) { Wrun_g31(rp->xs-pi); pi=rp->xs; Brun_g31(rp->xe-pi+1); pi=rp->xe+1; }; if((--rp)->xe+1<wid) Wrun_g31(wid-rp->xe-1); } else { #if DEBUG if(dbg_rg31_e) err("rlel_to_g31(rl[y?,r0])"); #endif Wrun_g31(wid); /* blank (all-white) scanline */ }; /* fill so that EOL ends on byte boundary */ padb(f,0,8,EOLLENGTH); #if DEBUG if(dbg_rg31_s) fprintf(stderr,"+0?"); #endif EOL_g31; } EOF_to_g31(f) BITFILE *f; { char *cs; /* fill so that EOL ends on byte boundary */ padb(f,0,8,EOLLENGTH); #if DEBUG if(dbg_rg31_s) fprintf(stderr,"+0?"); #endif /* write RTC */ EOL_g31; EOL_g31; EOL_g31; EOL_g31; EOL_g31; EOL_g31; } /* Macro for use within g32_to_rlel, to read one 1-D Modified Huffman coded run-length of a given color, placing the result in a given variable. Exceptionally, goto trap_eol, trap_eof, or trap_code_err. */ #if DEBUG #define g32_1d_run(C,V) { \ run = 0; \ do { cx.tr.s = (C); \ do { px = cx; \ switch(bitv=getb(f)) { \ case 0 : cx.tr=t->e[cx.tr.s].t[0]; break; \ case 1 : cx.tr=t->e[cx.tr.s].t[1]; break; \ case EOF : goto trap_eof; break; \ }; \ } \ while(cx.tr.a==DST_action_NULL); \ switch(cx.tr.a) { \ case DST_EOL : \ if(dbg_g32r_c)fprintf(stderr,"EOL %s\n",EOLSTRING); \ goto trap_eol; \ break; \ case DST_action_ERROR : goto trap_code_err; break; \ default : \ if(dbg_g32r_c)fprintf(stderr,"%s%6d %s%d\n", \ ((C)==DST_white)? "W": "B", \ cx.tr.a, \ t->e[px.tr.s].p, \ bitv); \ run += cx.tr.a; \ break; \ }; \ } \ while(cx.tr.a>63); \ (V) = run; \ } #else #define g32_1d_run(C,V) { \ run = 0; \ do { cx.tr.s = (C); \ do { px = cx; \ switch(bitv=getb(f)) { \ case 0 : cx.tr=t->e[cx.tr.s].t[0]; break; \ case 1 : cx.tr=t->e[cx.tr.s].t[1]; break; \ case EOF : goto trap_eof; break; \ }; \ } \ while(cx.tr.a==DST_action_NULL); \ switch(cx.tr.a) { \ case DST_EOL : \ goto trap_eol; \ break; \ case DST_action_ERROR : goto trap_code_err; break; \ default : \ run += cx.tr.a; \ break; \ }; \ } \ while(cx.tr.a>63); \ (V) = run; \ } #endif /* Translate a stream of bits in CCITT FAX Group 3 (2-D) compression format into a sequence of RLE_Lines. Returns one (RLE_Line *) on each call (or NULL if EOF or error). The first pixel (black or white) in each g32 line is assigned run index 0. */ RLE_Line *g32_to_rlel(t,f,bof) DST_table *t; BITFILE *f; boolean bof; /* beginning of file */ #define dbg_g32r_e (0) /* entry/exit */ #define dbg_g32r_r (0) /* trace each run/EOL/ERR_SYN */ #define dbg_g32r_c (0) /* trace each Huffman code (or, fill+EOL)*/ #define dbg_g32r_t (0) /* trace each state-transition */ #define g32r_strict (1) /* 1 is CORRECT: explicitly code the last black pel */ { static RLE_Line rl0,rl1,*prl,*crl; /* prior, current run-lines */ RLE_Line *swrl; int bitv; /* the last-read bit value */ DST_context cx,px; /* the current/prior decoding context */ RLE_Run *cr,*pr,*pre; /* into current/prior rle lines */ RLE_Run *pra0; /* rightmost in prior line with xe<=a0 (if none: prl->r) */ int run,sync,si,rtc_eols; boolean fill; /* pixel indices (0,1,...): current-line a*; prior-line b*. a0 is the index of the most recently completely encoded bit */ int a0,a1,a2,b1,b2; DST_color a0_color; /* a0's color: same as a2 & b2, opposite of a1 & b1 */ int a01,a12; /* lengths of runs a0-a1 & a1-a2 */ #define g32_first_color DST_white /* color of 1st run in each line */ #define g32_negative (0) /* if 1, invert Black/White on output */ #define swap_rl(f,b) {swrl=(f); (f)=(b); (b)=swrl;} /* detect b1 & b2: sensitive to a0, a0_color, and prior runs *pr *(pr+1) */ #define g32r_find_Bb1Wb2 { \ /* find 1st black changing pel>a0 */ \ /* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \ while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \ /* look beyond pra0 */ \ pr=pra0; while(pr<pre && (b1=pr->xs)<=a0) pr++; \ /* move b2 to 1st changing white pel > b1 */ \ if(pr<pre) b2=pr->xe+1; \ else b1=b2=prl->len; \ } #define g32r_find_Wb1Bb2 { \ /* find 1st white changing pel>a0 */ \ /* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \ while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \ /* look beyond pra0 */ \ pr=pra0; while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \ /* move b2 to 1st changing black pel > b1 */ \ if(pr<pre) { \ if((pr+1)<pre) b2=(pr+1)->xs; \ else b2=prl->len; \ } \ else b1=b2=prl->len; \ } #define g32r_find_b1b2 {if(a0_color==DST_white) g32r_find_Bb1Wb2 else g32r_find_Wb1Bb2;} #if DEBUG if(dbg_g32r_e) fprintf(stderr,"g32_to_rlel(t,bf,bof%d)\n",bof); #endif if(bof){crl= &rl0; crl->y= -1; crl->len=0; crl->runs=0; prl= &rl1; prl->y= -1; prl->len=0; prl->runs=0; /* sync by skipping initial FILL & EOL code */ sync=0; while((bitv=getb(f))==0) sync++; if(bitv!=1||sync<11) { #if DEBUG if(dbg_g32r_c) { fprintf(stderr,"BOF_ERR "); for(si=0;si<sync;si++) fprintf(stderr,"0"); if(bitv==1) fprintf(stderr,"1\n"); else fprintf(stderr,"?\n"); }; #endif return(NULL); } #if DEBUG else if(dbg_g32r_c){ fprintf(stderr,"BOF_EOL "); for(si=0;si<sync;si++) fprintf(stderr,"0"); fprintf(stderr,"1\n"); }; #else ; #endif prl->y = -1; crl->y = 0; } else crl->y = prl->y + 1; pre = (pra0=pr=prl->r) + prl->runs; /* prior line */ crl->runs=0; cr=crl->r-1; /* current line */ /* start on an imaginary white pixel just to left of margin */ a0= -1; a0_color = DST_white; /* check 1-D / 2-D bit immediately after prior EOL */ switch(bitv=getb(f)) { case 0 : /* 2-dimensionally encoded line */ #if DEBUG if(dbg_g32r_c) fprintf(stderr,"2D_LINE 0\n"); #endif /* start b1/b2 on prior line's first black pixel, etc; if none, then place off end of line */ if(pr<pre) {b1=pr->xs; b2=pr->xe+1;} else b1=b2=prl->len; /* parse a sequence of 2D codes... */ while(T/* exited only via goto trap_* and return */) { cx.tr.s = DST_2d; cx.tr.a = DST_action_NULL; #if DEBUG if(dbg_g32r_t)fprintf(stderr,"(%d,%d)\n",cx.tr.s,cx.tr.a); #endif do { switch(bitv=getb(f)) { case 0 : case 1 : cx.tr=t->e[cx.tr.s].t[bitv]; break; case EOF: goto trap_eof; break; }; #if DEBUG if(dbg_g32r_t)fprintf(stderr,"%d->(%d,%d)\n", bitv,cx.tr.s,cx.tr.a); #endif } while(cx.tr.a==DST_action_NULL); #if DEBUG if(dbg_g32r_t)fprintf(stderr,"%s %04d %s0\n", (cx.c==DST_white)? "W": "B", cx.tr.s, t->e[cx.tr.s].p); #endif switch(cx.tr.a) { case i2D_V0: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"V0 %s\n",code2d[cx.tr.a]); #endif a1=b1; /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if g32r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g32r_find_b1b2; break; case i2D_VR1: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"VR1 %s\n",code2d[cx.tr.a]); #endif a1=b1+1; /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g32r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g32r_find_b1b2; break; case i2D_VR2: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"VR2 %s\n",code2d[cx.tr.a]); #endif a1=b1+2; /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g32r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g32r_find_b1b2; break; case i2D_VR3: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"VR3 %s\n",code2d[cx.tr.a]); #endif a1=b1+3; /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g32r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g32r_find_b1b2; break; case i2D_VL1: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"VL1 %s\n",code2d[cx.tr.a]); #endif if((a1=b1-1)<0) err("g32_to_rlel: VL1 backs up to %d",a1); /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g32_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g32r_find_b1b2; break; case i2D_VL2: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"VL2 %s\n",code2d[cx.tr.a]); #endif if((a1=b1-2)<0) err("g32_to_rlel: VL2 backs up to %d",a1); /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g32r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g32r_find_b1b2; break; case i2D_VL3: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"VL3 %s\n",code2d[cx.tr.a]); #endif if((a1=b1-3)<0) err("g32_to_rlel: VL3 backs up to %d",a1); /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g32r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g32r_find_b1b2; break; case i2D_PASS: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"PASS %s\n",code2d[cx.tr.a]); #endif /* move a0 to b2; no change of color */ a0=b2; if(a0>=prl->len) goto trap_expecting_eol; if(a0_color==DST_black) cr->xe = a0; #if !g32r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g32r_find_b1b2; break; case i2D_HORIZ: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"HORIZ %s\n",code2d[cx.tr.a]); #endif if(a0_color==DST_white) { if(a0<0) a0=0; /* first run in line starts at 0 */ g32_1d_run(DST_white,a01); a1 = a0 + a01; g32_1d_run(DST_black,a12); a2 = a1 + a12; if(a12>0) /* Black run of >0 length */ { crl->runs++; (++cr)->xs = a1; cr->xe = a2-1; }; a0 = a2; /* still white */ if(a0>=prl->len) goto trap_expecting_eol; /* encode a0 */ #if !g32r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g32r_find_Bb1Wb2; } else { g32_1d_run(DST_black,a01); a1 = a0 + a01; g32_1d_run(DST_white,a12); a2 = a1 + a12; if(a01>0) /* Black run of >0 length */ { cr->xe = a1 - 1; } else { /* 0-length: very peculiar: ignore */ fprintf(stderr, "g32_to_rlel: HORIZ B%d! W%d - ignore\n", a01,a12); cr--; crl->runs--; }; a0 = a2; /* still black */ if(a0>=prl->len) goto trap_expecting_eol; /* encode a0 */ crl->runs++; (++cr)->xs = a0; #if !g32r_strict if(a0==prl->len-1) { cr->xe = a0; a0++; goto trap_expecting_eol; }; #endif g32r_find_Wb1Bb2; }; break; case i2D_EOL: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"EOL %s\n",code2d[cx.tr.a]); #endif goto trap_eol; break; case DST_action_ERROR: goto trap_code_err; break; }; }; break; case 1 : /* 1-dimensionally encoded line */ #if DEBUG if(dbg_g32r_c) fprintf(stderr,"1D_LINE 1\n"); #endif /* read a sequence of 1-D runcodes... */ while(T/* exit only via goto trap_X */) { g32_1d_run(a0_color,a01); a1 = ((a0>=0)? a0 : 0) + a01; if(a01>0) { /* encode a0 through a1-1 */ if(a0_color==DST_black^g32_negative) { /* output-black run */ crl->runs++; (++cr)->xs=((a0>=0)? a0 : 0); cr->xe=a1-1; }; }; a0=a1; a0_color=flip_color(a0_color); if(prl->len>0 && a0>=prl->len) goto trap_expecting_eol; }; break; case EOF : goto trap_eof; break; }; /* come here via goto's: all these traps return() */ trap_expecting_eol: /* come here expecting to see EOL or FILL+EOL */ sync=0; while((bitv=getb(f))==0) sync++; switch(bitv) { case 1: if(sync==11) { #if DEBUG if(dbg_g32r_c){ fprintf(stderr,"EOL %s\n",EOLSTRING); }; #endif goto trap_eol; } else if(sync>11) { #if DEBUG if(dbg_g32r_c){ fprintf(stderr,"FILLEOL "); for(si=0;si<sync-11;si++) fprintf(stderr,"0"); fprintf(stderr,"+"); fprintf(stderr,"%s\n",EOLSTRING); }; #endif goto trap_eol; } else { #if DEBUG if(dbg_g32r_c){ fprintf(stderr,"NOT EOL "); for(si=0;si<sync;si++) fprintf(stderr,"0"); fprintf(stderr,"1?"); }; #endif sync=0; goto trap_eol_err; }; break; case EOF: goto trap_eof; break; }; goto trap_eol; trap_code_err: /* unexpected coding sequence: 'px' holds last decoding context & 'bitv' latest bit value; will attempt to resynchronize on next EOL */ #if DEBUG if(dbg_g32r_c)fprintf(stderr,"CODERR %s%d?", t->e[px.tr.s].p,bitv); #endif /* count trailing 0's so far (should be in table) */ #if !NEW_TRAIL if(bitv==0) sync=1; else sync=0; si=strlen(t->e[px.tr.s].p)-1; while(si>=0&&t->e[px.tr.s].p[si]=='0') {sync++; si--;}; fill = (si<0); /* all 0's: may be fill bits */ #else if(bitv==0) sync=t->e[px.tr.s].z+1; else sync=t->e[px.tr.s].z; fill = (sync>t->e[px.tr.s].l); /* all 0's: maybe fill bits */ #endif #if DEBUG if(dbg_trail)err("sync %d fill %d",sync,fill); #endif trap_eol_err: while(sync<11) { switch(bitv=getb(f)) { case 0: sync++; #if DEBUG if(dbg_g32r_c) fprintf(stderr,"0"); #endif break; case 1: sync=0; #if DEBUG if(dbg_g32r_c) fprintf(stderr,"1"); #endif break; case EOF: goto trap_eof; break; }; }; /* next `1' will synchronize */ do { switch(bitv=getb(f)) { case 0: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"0"); #endif break; case 1: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"1"); #endif break; case EOF: goto trap_eof; break; }; } while(bitv!=1); #if DEBUG if(dbg_g32r_c) fprintf(stderr," EOL\n"); #endif goto trap_eol; trap_eol: /* come here having seen (and reported) EOL */ /* learn/check line-length */ if(a0>=0) crl->len=a0; else crl->len=0; if(crl->len==0) { /* no pixels coded -- may be the 1st of 6 RTC EOLs */ /* check suffix 1 bit */ if((bitv=getb(f))!=1) goto trap_eol_err; rtc_eols=1; #if DEBUG if(dbg_g32r_c)fprintf(stderr,"RTC_EOL +1 (%d)\n",rtc_eols); #endif do { sync=0; while((bitv=getb(f))==0) sync++; switch(bitv) { case 1: if(sync<11) { #if DEBUG if(dbg_g32r_c){ fprintf(stderr,"NOT RTC "); for(si=0;si<sync;si++) fprintf(stderr,"0"); fprintf(stderr,"1?\n"); }; #endif sync=0; goto trap_eol_err; }; break; case EOF: goto trap_eof; break; }; /* check suffix 1 bit */ if((bitv=getb(f))!=1) goto trap_eol_err; rtc_eols++; #if DEBUG if(dbg_g32r_c) { fprintf(stderr,"RTC_EOL "); for(si=0;si<sync;si++) fprintf(stderr,"0"); fprintf(stderr,"1+1 (%d)\n",rtc_eols); }; #endif } while(rtc_eols<6); /* normal RTC */ #if DEBUG if(dbg_g32r_c)fprintf(stderr,"RTC\n"); #endif return(NULL); } else if(prl->len==0) { #if DEBUG if(dbg_g32r_c)fprintf(stderr,"LINELEN %d\n",crl->len); #endif } else if(crl->len!=prl->len) { err("g32_to_rlel: y%d: LINELEN changes c%d != p%d ? (force to %d)", crl->y,crl->len,prl->len,prl->len); crl->len = prl->len; }; swap_rl(crl,prl); return(prl); trap_eof: #if DEBUG if(dbg_g32r_c) fprintf(stderr,"<EOF>\n"); #endif return(NULL); } /* Translate a sequence of RLE_Line's (describing a binary image) into a file (a stream of bits) in CCITT FAX Group 3 (2-D) compression format. BOF_to_g32() must be called first; then call rlel_to_g32() for each line (including blank lines); finally, EOF_to_g32() must be called. Each line's EOL and the RTC's first EOL will be padded so they end on a byte boundary. */ /* debugging flags: trace to stderr */ #define dbg_rg32_e (0) /* entry */ #define dbg_rg32_r (0) /* runs */ #define dbg_rg32_s (0) /* bitstrings */ #define rg32_strict (1) /* 1 is CORRECT: explicitly code the last black pel */ #if DEBUG #define bits_g32(bits) { \ cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \ if(dbg_rg32_s) fprintf(stderr,"%s",(bits)); \ if(dbg_rg32_r) fprintf(stderr," "); \ } #else #define bits_g32(bits) { \ cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \ } #endif #if DEBUG #define EOL_g32 { \ if(dbg_rg32_r) fprintf(stderr,"EOL "); \ bits_g32(EOLSTRING); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define EOL_g32 { \ bits_g32(EOLSTRING); \ } #endif BOF_to_g32(f) BITFILE *f; { char *cs; /* a NOP: no header for Group 3 (2-D) */ #if DEBUG if(dbg_rg32_e) fprintf(stderr,"BOF\n"); #endif }; rlel_to_g32(pl,cl,wid,f) RLE_Line *pl; /* prior "reference" line: if NULL, use 1-D coding on cl */ RLE_Line *cl; /* current "coding" line: if NULL, is blank (all white) */ int wid; /* width of an output line in pixels */ BITFILE *f; { int runl,codi; char *cs,*p01; #if DEBUG #define Wrun_g32(rn) { \ runl=(rn); \ if(dbg_rg32_r) fprintf(stderr,"W %5d ",runl); \ while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \ p01=codewht[codi=rtoi(runl)]; bits_g32(p01); \ if(codi>=64) {p01=codewht[runl%64]; bits_g32(p01);}; \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define Wrun_g32(rn) { \ runl=(rn); \ while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \ p01=codewht[codi=rtoi(runl)]; bits_g32(p01); \ if(codi>=64) {p01=codewht[runl%64]; bits_g32(p01);}; \ } #endif #if DEBUG #define Brun_g32(rn) { \ runl=(rn); \ if(dbg_rg32_r) fprintf(stderr,"B %5d ",runl); \ while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \ p01=codeblk[codi=rtoi(runl)]; bits_g32(p01); \ if(codi>=64) {p01=codeblk[runl%64]; bits_g32(p01);}; \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define Brun_g32(rn) { \ runl=(rn); \ while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \ p01=codeblk[codi=rtoi(runl)]; bits_g32(p01); \ if(codi>=64) {p01=codeblk[runl%64]; bits_g32(p01);}; \ } #endif #if DEBUG #define V0_g32 { \ if(dbg_rg32_r) fprintf(stderr,"V0 "); \ bits_g32(code2d[i2D_V0]); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define V0_g32 { \ bits_g32(code2d[i2D_V0]); \ } #endif #if DEBUG #define VR1_g32 { \ if(dbg_rg32_r) fprintf(stderr,"VR1 "); \ bits_g32(code2d[i2D_VR1]); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define VR1_g32 { \ bits_g32(code2d[i2D_VR1]); \ } #endif #if DEBUG #define VR2_g32 { \ if(dbg_rg32_r) fprintf(stderr,"VR2 "); \ bits_g32(code2d[i2D_VR2]); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define VR2_g32 { \ bits_g32(code2d[i2D_VR2]); \ } #endif #if DEBUG #define VR3_g32 { \ if(dbg_rg32_r) fprintf(stderr,"VR3 "); \ bits_g32(code2d[i2D_VR3]); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define VR3_g32 { \ bits_g32(code2d[i2D_VR3]); \ } #endif #if DEBUG #define VL1_g32 { \ if(dbg_rg32_r) fprintf(stderr,"VL1 "); \ bits_g32(code2d[i2D_VL1]); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define VL1_g32 { \ bits_g32(code2d[i2D_VL1]); \ } #endif #if DEBUG #define VL2_g32 { \ if(dbg_rg32_r) fprintf(stderr,"VL2 "); \ bits_g32(code2d[i2D_VL2]); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define VL2_g32 { \ bits_g32(code2d[i2D_VL2]); \ } #endif #if DEBUG #define VL3_g32 { \ if(dbg_rg32_r) fprintf(stderr,"VL3 "); \ bits_g32(code2d[i2D_VL3]); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define VL3_g32 { \ bits_g32(code2d[i2D_VL3]); \ } #endif #if DEBUG #define PASS_g32 { \ if(dbg_rg32_r) fprintf(stderr,"PASS "); \ bits_g32(code2d[i2D_PASS]); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define PASS_g32 { \ bits_g32(code2d[i2D_PASS]); \ } #endif #if DEBUG #define HORIZ_g32 { \ if(dbg_rg32_r) fprintf(stderr,"HORIZ "); \ bits_g32(code2d[i2D_HORIZ]); \ if(dbg_rg32_r) fprintf(stderr,"\n"); \ } #else #define HORIZ_g32 { \ bits_g32(code2d[i2D_HORIZ]); \ } #endif #define detect_a1a2_BW { \ /* find leftmost black changing pel > a0 */ \ /* advance cra as far as possible s.t. cra->xe<=a0 */ \ while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \ /* look beyond cra, until cr->xs>a0 */ \ cr=cra; while(cr<cre && (a1=cr->xs)<=a0) cr++; \ if(cr<cre) a2=cr->xe+1; \ else a1=a2=wid; \ } #define detect_a1a2_WB { \ /* find leftmost white changing pel > a0 */ \ /* advance cra as far as possible s.t. cra->xe<=a0 */ \ while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \ /* look beyond cra, until cr->xe+1>a0 */ \ cr=cra; while(cr<cre && (a1=cr->xe+1)<=a0) cr++; \ if(cr<cre) { \ if((cr+1)<cre) a2=(cr+1)->xs; \ else a2=wid; \ } \ else a1=a2=wid; \ } #define detect_a1a2 {if(a0_color==DST_white) detect_a1a2_BW else detect_a1a2_WB;} #define detect_b1b2_BW {\ /* find leftmost black changing pel > a0 */ \ /* advance pra as far as possible s.t. pra->xe<=a0 */ \ while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \ /* look beyond pra */ \ pr=pra; while(pr<pre && (b1=pr->xs)<=a0) pr++; \ /* move b2 to 1st changing white pel > b1 */ \ if(pr<pre) b2=pr->xe+1; \ else b1=b2=wid; \ } #define detect_b1b2_WB {\ /* find leftmost white changing pel > a0 */ \ /* advance pra as far as possible s.t. pra->xe<=a0 */ \ while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \ /* look beyond pra */ \ pr=pra; while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \ /* move b2 to 1st changing black pel > b1 */ \ if(pr<pre) { \ if((pr+1)<pre) b2=(pr+1)->xs; \ else b2=wid; \ } \ else b1=b2=wid; \ } #define detect_b1b2 {if(a0_color==DST_white) detect_b1b2_BW else detect_b1b2_WB;} #if DEBUG if(dbg_rg32_e) err("rlel_to_g32(pl[%d],cl[%d],w%d)", (pl==NULL)? -1: pl->runs, (cl==NULL)? -1: cl->runs, wid); #endif /* fill so that EOL ends on byte boundary */ padb(f,0,8,EOLLENGTH); #if DEBUG if(dbg_rg32_s) fprintf(stderr,"FILL +0?"); #endif EOL_g32; /* begin with EOL (sic) */ if(pl==NULL) /* use 1-D coding for *cl */ { int pi; /* input pixel index on line */ RLE_Run *rp,*pp,*sp; putb(1,f); #if DEBUG if(dbg_rg32_r) fprintf(stderr,"1D_LINE 1\n"); #endif if(cl!=NULL&&cl->runs>0) { pi=0; /* bit to write next */ for(sp=(rp=cl->r)+cl->runs; rp<sp; rp++) { Wrun_g32(rp->xs-pi); pi=rp->xs; Brun_g32(rp->xe-pi+1); pi=rp->xe+1; }; if((--rp)->xe+1<wid) Wrun_g32(wid-rp->xe-1); } else Wrun_g32(wid); /* blank scanline */ } else /* use 2-D coding for *cl */ { RLE_Run *cr,*cre,*pr,*pre; /* into current/prior rle lines */ int a0,a1,a2,b1,b2; /* indices {0,1,...} of pixels */ DST_color a0_color; /* a0's color: same as a2 & b2, opp of a1 & b1 */ RLE_Run *cra; /* rightmost in current st xe<=a0 (none: ==cl->r) */ RLE_Run *pra; /* rightmost in prior st xe<=a0 (none: ==pl->r) */ int a01,a12,a1b1; /* lengths of runs a0-a1 a1-a2 a1-b1 */ putb(0,f); #if DEBUG if(dbg_rg32_r) fprintf(stderr,"2D_LINE 0\n"); #endif /* start on an imaginary white pixel just to left of margin */ a0= -1; a0_color = DST_white; pre = (pra=pl->r) + pl->runs; /* prior line's runs */ /* start b1/b2 on prior line's first black pixel, etc; if none, then place off end of line */ if(pra<pre) {b1=pra->xs; b2=pra->xe+1;} else b1=b2=wid; if(cl!=NULL&&cl->runs>0) { cre = (cra=cl->r) + cl->runs; a1=cra->xs; a2=cra->xe+1; #if rg32_strict while(a0 < wid) { #else while(a0 < wid-1) { #endif /* a0, a1, a2, b1, b2 are as in CCITT Rec T.4 */ #if DEBUG if(dbg_rg32_r) fprintf(stderr,"f%d(%d,%d,%d) b%d(%d,%d)\n", cra-(cl->r),a0,a1,a2,pra-(pl->r),b1,b2); #endif if(b2<a1) /* PASS mode */ { PASS_g32; a0=b2; /* a0-color, a1, & a2 are unchanged */ detect_b1b2; } else if((a1b1=(a1-b1))<=3 && a1b1>= -3) { /* VERTICAL mode */ switch(a1b1) { case -3: VL3_g32; break; case -2: VL2_g32; break; case -1: VL1_g32; break; case 0: V0_g32; break; case 1: VR1_g32; break; case 2: VR2_g32; break; case 3: VR3_g32; break; }; a0=a1; a0_color=flip_color(a0_color); detect_a1a2; detect_b1b2; } else { /* HORIZONTAL mode */ HORIZ_g32; a01=a1-a0; if(a0== -1) a01--; a12=a2-a1; if(a0_color==DST_white) { Wrun_g32(a01); Brun_g32(a12); } else { Brun_g32(a01); Wrun_g32(a12); }; a0=a2; /* a0_color is unchanged */ detect_a1a2; detect_b1b2; }; }; } else /* current line is blank */ { a1=a2=wid; #if rg32_strict while(a0 < wid) { #else while(a0 < wid-1) { #endif /* a0, a1, a2, b1, b2 are as in CCITT Rec. T.4 */ #if DEBUG if(dbg_rg32_r) fprintf(stderr,"f(%d,%d,%d) b%d(%d,%d)\n", a0,a1,a2,pra-(pl->r),b1,b2); #endif if(b2<a1) /* PASS mode */ { PASS_g32; a0=b2; /* a0-color, a1, & a2 are unchanged */ detect_b1b2; } else if((a1b1=a1-b1)<=3 && a1b1>= -3) { /* VERTICAL mode */ switch(a1b1) { case -3: VL3_g32; break; case -2: VL2_g32; break; case -1: VL1_g32; break; case 0: V0_g32; break; case 1: VR1_g32; break; case 2: VR2_g32; break; case 3: VR3_g32; break; }; a0=a1; a0_color=flip_color(a0_color); /* a1, & a2 are unchanged */ detect_b1b2; } else { /* HORIZONTAL mode */ HORIZ_g32; a01=a1-a0; if(a0== -1) a01--; a12=a2-a1; if(a0_color==DST_white) { Wrun_g32(a01); Brun_g32(a12); } else { Brun_g32(a01); Wrun_g32(a12); }; a0=a2; /* a0_color, a1, & a2 are unchanged */ detect_b1b2; }; }; }; }; } EOF_to_g32(f) BITFILE *f; { char *cs; padb(f,0,8,EOLLENGTH); /* fill so that EOL ends on byte boundary */ #if DEBUG if(dbg_rg32_s) fprintf(stderr,"FILL +0?"); #endif /* write RTC */ EOL_g32; EOL_g32; EOL_g32; EOL_g32; EOL_g32; EOL_g32; #if DEBUG if(dbg_rg32_e) fprintf(stderr,"EOF\n"); #endif } /* Macro for use within g4_to_rlel, to read one 1-D Modified Huffman coded run-length of color C, placing the result in variable V. Exceptionally, goto trap_eol, trap_eof, or trap_code_err. */ #if DEBUG #define g4_1d_run(C,V) { \ run = 0; \ do { cx.tr.s = (C); \ do { px = cx; \ switch(bitv=getb(f)) { \ case 0 : cx.tr=t->e[cx.tr.s].t[0]; break; \ case 1 : cx.tr=t->e[cx.tr.s].t[1]; break; \ case EOF : goto trap_eof; break; \ }; \ } \ while(cx.tr.a==DST_action_NULL); \ switch(cx.tr.a) { \ case DST_EOL : \ if(dbg_g4r_c)fprintf(stderr,"EOL %s\n",EOLSTRING); \ goto trap_eol; \ break; \ case DST_action_ERROR : goto trap_code_err; break; \ default : \ if(dbg_g4r_c)fprintf(stderr,"%s%6d %s%d\n", \ ((C)==DST_white)? "W": "B", \ cx.tr.a, \ t->e[px.tr.s].p, \ bitv); \ run += cx.tr.a; \ break; \ }; \ } \ while(cx.tr.a>63); \ (V) = run; \ } #else #define g4_1d_run(C,V) { \ run = 0; \ do { cx.tr.s = (C); \ do { px = cx; \ switch(bitv=getb(f)) { \ case 0 : cx.tr=t->e[cx.tr.s].t[0]; break; \ case 1 : cx.tr=t->e[cx.tr.s].t[1]; break; \ case EOF : goto trap_eof; break; \ }; \ } \ while(cx.tr.a==DST_action_NULL); \ switch(cx.tr.a) { \ case DST_EOL : \ goto trap_eol; \ break; \ case DST_action_ERROR : goto trap_code_err; break; \ default : \ run += cx.tr.a; \ break; \ }; \ } \ while(cx.tr.a>63); \ (V) = run; \ } #endif /* Translate a stream of bits in CCITT FAX Group 4 compression format, of known fixed line-length, into a sequence of RLE_Lines. Returns one (RLE_Line *) on each call (or NULL if EOF or error). The first pixel (black or white) in each g4 line is assigned run index 0. WARNING: the RLE_Line returned must NOT be modified by the caller, since it is used to decode the next line. */ RLE_Line *g4_to_rlel(t,f,bof,len) DST_table *t; BITFILE *f; boolean bof; /* beginning of file */ int len; /* line-length in pixels (used only on bof) */ #define dbg_g4r_e (0) /* trace entry-to / exit-from function */ #define dbg_g4r_r (0) /* trace each run/EOL/ERR_SYN */ #define dbg_g4r_c (0) /* trace each Huffman code (or, fill+EOL)*/ #define dbg_g4r_t (0) /* trace each state-transition */ #define g4r_strict (1) /* 1 is CORRECT: explicitly code the last black pel */ { static RLE_Line rl0,rl1,*prl,*crl; /* prior, current run-lines */ RLE_Line *swrl; int bitv; /* the last-read bit value */ DST_context cx,px; /* the current/prior decoding context */ RLE_Run *cr,*pr,*pre; /* into current/prior rle lines */ RLE_Run *pra0; /* rightmost in prior line with xe<=a0 (if none: prl->r) */ int run,sync,si,rtc_eols; /* pixel indices (0,1,...): current-line a*; prior-line b*. a0 is the index of the most recently completely encoded bit */ int a0,a1,a2,b1,b2; DST_color a0_color; /* a0's color: same as a2 & b2, opposite of a1 & b1 */ int a01,a12; /* lengths of runs a0-a1 & a1-a2 */ #define g4_first_color (DST_white) /* color of 1st run in each line */ #define g4_negative (0) /* if 1, invert Black/White on output */ #define swap_rl(f,b) {swrl=(f); (f)=(b); (b)=swrl;} /* detect b1 & b2: sensitive to a0, a0_color, and prior runs *pr *(pr+1) */ #define g4r_find_Bb1Wb2 { \ /* find 1st black changing pel>a0 */ \ /* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \ while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \ /* look beyond pra0 */ \ pr=pra0; while(pr<pre && (b1=pr->xs)<=a0) pr++; \ /* move b2 to 1st changing white pel > b1 */ \ if(pr<pre) b2=pr->xe+1; \ else b1=b2=prl->len; \ } #define g4r_find_Wb1Bb2 { \ /* find 1st white changing pel>a0 */ \ /* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \ while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \ /* look beyond pra0 */ \ pr=pra0; while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \ /* move b2 to 1st changing black pel > b1 */ \ if(pr<pre) { \ if((pr+1)<pre) b2=(pr+1)->xs; \ else b2=prl->len; \ } \ else b1=b2=prl->len; \ } #define g4r_find_b1b2 { \ if(a0_color==DST_white) g4r_find_Bb1Wb2 else g4r_find_Wb1Bb2; \ if(b1<=a0) err("g4_to_rlel: y%d: b1 %d <= a0 %d ?",crl->y,a0,b1); \ } if(bof){/* initial reference line is all white, of known length */ prl= &rl0; prl->y= -1; prl->len=len; prl->runs=0; /* initial coding line has y-coordinate 0 */ crl= &rl1; crl->y=0; crl->len=0; crl->runs=0; } else crl->y = prl->y + 1; #if DEBUG if(dbg_g4r_e) fprintf(stderr, "g4_to_rlel(t,f,bof%d,len%d) y%d,l%d\n", bof,len,prl->y,prl->len); #endif pre = (pra0=pr=prl->r) + prl->runs; /* prior line */ crl->runs=0; cr=crl->r-1; /* current line */ /* start on an imaginary white pixel just to left of margin */ a0= -1; a0_color = DST_white; #if DEBUG a1=a2=b1=b2=0; /* immaterial; looks better when debugging */ #endif /* start b1/b2 on prior line's first black pixel, etc; if none, then place off end of line */ if(pr<pre) {b1=pr->xs; b2=pr->xe+1;} else b1=b2=prl->len; /* parse a sequence of 2D codes... */ while(T/* exit only via 'goto trap_X' */) { /* a0, a1, a2, b1, b2 are as defined in CCITT Rec. T.6 */ #if DEBUG if(dbg_g4r_r) fprintf(stderr,"a(%d,%d,%d) b(%d,%d)\n",a0,a1,a2,b1,b2); #endif cx.tr.s = DST_2d; cx.tr.a = DST_action_NULL; #if DEBUG if(dbg_g4r_t)fprintf(stderr,"(%d,%d)\n",cx.tr.s,cx.tr.a); #endif do { switch(bitv=getb(f)) { case 0 : case 1 : cx.tr=t->e[cx.tr.s].t[bitv]; break; case EOF: goto trap_eof; break; }; #if DEBUG if(dbg_g4r_t)fprintf(stderr,"%d->(%d,%d)\n", bitv,cx.tr.s,cx.tr.a); #endif } while(cx.tr.a==DST_action_NULL); #if DEBUG if(dbg_g4r_t)fprintf(stderr,"%s %04d %s0\n", (cx.c==DST_white)? "W": "B", cx.tr.s, t->e[cx.tr.s].p); #endif switch(cx.tr.a) { case i2D_V0: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"V0 %s\n",code2d[cx.tr.a]); #endif a1=b1; /* interpret (a0,a1-1] */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* interpret a0 */ if(a0_color==DST_black) { if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0) err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?", crl->y,crl->runs,cr->xs,cr->xe); crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g4r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g4r_find_b1b2; break; case i2D_VR1: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"VR1 %s\n",code2d[cx.tr.a]); #endif a1=b1+1; /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0) err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?", crl->y,crl->runs,cr->xs,cr->xe); crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g4r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g4r_find_b1b2; break; case i2D_VR2: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"VR2 %s\n",code2d[cx.tr.a]); #endif a1=b1+2; /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0) err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?", crl->y,crl->runs,cr->xs,cr->xe); crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g4r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g4r_find_b1b2; break; case i2D_VR3: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"VR3 %s\n",code2d[cx.tr.a]); #endif a1=b1+3; /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0) err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?", crl->y,crl->runs,cr->xs,cr->xe); crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g4r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g4r_find_b1b2; break; case i2D_VL1: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"VL1 %s\n",code2d[cx.tr.a]); #endif if((a1=b1-1)<=a0) err("g4_to_rlel: y%d: VL1 a1 %d <= a0 %d ?", crl->y,a1,a0); /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0) err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?", crl->y,crl->runs,cr->xs,cr->xe); crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g4r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g4r_find_b1b2; break; case i2D_VL2: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"VL2 %s\n",code2d[cx.tr.a]); #endif if((a1=b1-2)<=a0) err("g4_to_rlel: y%d: VL2 a1 %d <= a0 %d ?", crl->y,a1,a0); /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0) err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?", crl->y,crl->runs,cr->xs,cr->xe); crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g4r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g4r_find_b1b2; break; case i2D_VL3: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"VL3 %s\n",code2d[cx.tr.a]); #endif if((a1=b1-3)<=a0) err("g4_to_rlel: y%d: VL3 a1 %d <= a0 %d ?", crl->y,a1,a0); /* encode a0 to a1-1 */ if(a0_color==DST_black) cr->xe=a1-1; /* move a0 to a1 */ a0=a1; if(a0>=prl->len) goto trap_expecting_eol; a0_color = flip_color(a0_color); /* encode a0 */ if(a0_color==DST_black) { if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0) err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?", crl->y,crl->runs,cr->xs,cr->xe); crl->runs++; (++cr)->xs = a0; cr->xe = a0; }; #if !g4r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g4r_find_b1b2; break; case i2D_PASS: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"PASS %s\n",code2d[cx.tr.a]); #endif /* move a0 to b2; no change of color */ a0=b2; if(a0>=prl->len) goto trap_expecting_eol; if(a0_color==DST_black) cr->xe = a0; #if !g4r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g4r_find_b1b2; break; case i2D_HORIZ: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"HORIZ %s\n",code2d[cx.tr.a]); #endif if(a0_color==DST_white) { if(a0<0) a0=0; /* first run in line starts at 0 */ g4_1d_run(DST_white,a01); a1 = a0 + a01; g4_1d_run(DST_black,a12); a2 = a1 + a12; if(a12>0) /* Black run of >0 length */ { if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0) err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?", crl->y,crl->runs,cr->xs,cr->xe); crl->runs++; (++cr)->xs = a1; cr->xe = a2-1; }; a0 = a2; /* still white */ if(a0>=prl->len) goto trap_expecting_eol; /* encode a0 */ #if !g4r_strict if(a0==prl->len-1) { a0++; goto trap_expecting_eol; }; #endif g4r_find_Bb1Wb2; } else { g4_1d_run(DST_black,a01); a1 = a0 + a01; g4_1d_run(DST_white,a12); a2 = a1 + a12; if(a01>0) /* Black run of >0 length */ { cr->xe = a1 - 1; } else { /* 0-length: very peculiar: ignore */ fprintf(stderr, "g4_to_rlel: HORIZ B%d! W%d - ignore\n", a01,a12); cr--; crl->runs--; }; a0 = a2; /* still black */ if(a0>=prl->len) goto trap_expecting_eol; /* encode a0 */ crl->runs++; (++cr)->xs = a0; #if !g4r_strict if(a0==prl->len-1) { cr->xe = a0; a0++; goto trap_expecting_eol; }; #endif g4r_find_Wb1Bb2; }; break; case i2D_EOL: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"EOL %s\n",code2d[cx.tr.a]); #endif goto trap_eol; break; case DST_action_ERROR: goto trap_code_err; break; }; }; /* come here via goto's: all these traps return() */ trap_expecting_eol: /* come here having detected (computed) end-of-line */ /* learn/check/correct line-length */ crl->len = (a0>0)? a0 : 0; if(crl->len!=prl->len) { err("g4_to_rlel: y%d: LINELEN changes c%d != p%d ? (force to %d)", crl->y,crl->len,prl->len,prl->len); crl->len = prl->len; }; swap_rl(crl,prl); #if DEBUG if(dbg_g4r_e) fprintf(stderr, "exit g4_to_rlel: expg_eol y%d,l%d\n", prl->y,prl->len); #endif return(prl); trap_eol: /* come here having seen an EOL code (rare in Group 4) */ /* It must be the first of two EOL codes making up the EOB signal */ /* look for 2nd EOL */ sync=0; while((bitv=getb(f))==0) sync++; switch(bitv) { case 1: if(sync==11) { #if DEBUG if(dbg_g4r_c) { fprintf(stderr,"EOB_EOL %s\n",EOLSTRING); fprintf(stderr,"EOB\n"); }; #endif } else { #if DEBUG if(dbg_g4r_c){ fprintf(stderr,"NOT EOB "); for(si=0;si<sync;si++) fprintf(stderr,"0"); fprintf(stderr,"1?\n"); fprintf(stderr,"ABORT\n"); }; #endif }; break; case EOF: goto trap_eof; break; }; #if DEBUG if(dbg_g4r_e) fprintf(stderr,"exit g4_to_rlel: eol\n"); #endif return(NULL); trap_code_err: /* unexpected coding sequence: 'px' holds last decoding context & 'bitv' latest bit value; will attempt to resynchronize on next EOL */ #if DEBUG if(dbg_g4r_c)fprintf(stderr,"CODERR %s%d? (px.tr.s=%d)\n", t->e[px.tr.s].p,bitv,px.tr.s); #endif err("g4_to_rlel: code error"); #if DEBUG if(dbg_g4r_e) fprintf(stderr,"exit g4_to_rlel: code_err\n"); #endif return(NULL); trap_eof: #if DEBUG if(dbg_g4r_c) fprintf(stderr,"<EOF>\n"); if(dbg_g4r_e) fprintf(stderr,"exit g4_to_rlel: eof\n"); #endif return(NULL); } /* Translate a sequence of RLE_Line's (describing a binary image) into a file (a stream of bits) in CCITT FAX Group 4 compression format. BOF_to_g4() must be called first; then call rlel_to_g4() for each line (including blank lines); finally, EOF_to_g4() must be called. The EOFB is padded (suffixed) with 0's to a byte boundary if necessary; no other filling or padding is performed. */ /* debugging flags: trace to stderr */ #define dbg_rg4_e (0) /* entry */ #define dbg_rg4_r (0) /* runs */ #define dbg_rg4_c (0) /* codes (bitstrings) */ #define rg4_strict (1) /* 1 is CORRECT: explicitly code the last black pel */ #if DEBUG #define bits_g4(bits) { \ cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \ if(dbg_rg4_c) fprintf(stderr,"%s",(bits)); \ if(dbg_rg4_r) fprintf(stderr," "); \ } #else #define bits_g4(bits) { \ cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;}; \ } #endif #if DEBUG #define EOFB_g4 { \ if(dbg_rg4_r) fprintf(stderr,"EOFB "); \ bits_g4(EOFB); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define EOFB_g4 { \ bits_g4(EOFB); \ } #endif BOF_to_g4(f) BITFILE *f; { char *cs; /* a NOP: no header for Group 4 */ #if DEBUG if(dbg_rg4_e) fprintf(stderr,"BOF\n"); #endif }; rlel_to_g4(pl,cl,wid,f) RLE_Line *pl; /* prior "reference" line */ RLE_Line *cl; /* current "coding" line: if NULL, is blank (all white) */ int wid; /* width of an output line in pixels */ BITFILE *f; { int runl,codi; char *cs,*p01; #if DEBUG #define Wrun_g4(rn) { \ runl=(rn); \ if(dbg_rg4_r) fprintf(stderr,"W %5d ",runl); \ while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \ p01=codewht[codi=rtoi(runl)]; bits_g4(p01); \ if(codi>=64) {p01=codewht[runl%64]; bits_g4(p01);}; \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define Wrun_g4(rn) { \ runl=(rn); \ while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \ p01=codewht[codi=rtoi(runl)]; bits_g4(p01); \ if(codi>=64) {p01=codewht[runl%64]; bits_g4(p01);}; \ } #endif #if DEBUG #define Brun_g4(rn) { \ runl=(rn); \ if(dbg_rg4_r) fprintf(stderr,"B %5d ",runl); \ while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \ p01=codeblk[codi=rtoi(runl)]; bits_g4(p01); \ if(codi>=64) {p01=codeblk[runl%64]; bits_g4(p01);}; \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define Brun_g4(rn) { \ runl=(rn); \ while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \ p01=codeblk[codi=rtoi(runl)]; bits_g4(p01); \ if(codi>=64) {p01=codeblk[runl%64]; bits_g4(p01);}; \ } #endif #if DEBUG #define V0_g4 { \ if(dbg_rg4_r) fprintf(stderr,"V0 "); \ bits_g4(code2d[i2D_V0]); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define V0_g4 { \ bits_g4(code2d[i2D_V0]); \ } #endif #if DEBUG #define VR1_g4 { \ if(dbg_rg4_r) fprintf(stderr,"VR1 "); \ bits_g4(code2d[i2D_VR1]); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define VR1_g4 { \ bits_g4(code2d[i2D_VR1]); \ } #endif #if DEBUG #define VR2_g4 { \ if(dbg_rg4_r) fprintf(stderr,"VR2 "); \ bits_g4(code2d[i2D_VR2]); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define VR2_g4 { \ bits_g4(code2d[i2D_VR2]); \ } #endif #if DEBUG #define VR3_g4 { \ if(dbg_rg4_r) fprintf(stderr,"VR3 "); \ bits_g4(code2d[i2D_VR3]); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define VR3_g4 { \ bits_g4(code2d[i2D_VR3]); \ } #endif #if DEBUG #define VL1_g4 { \ if(dbg_rg4_r) fprintf(stderr,"VL1 "); \ bits_g4(code2d[i2D_VL1]); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define VL1_g4 { \ bits_g4(code2d[i2D_VL1]); \ } #endif #if DEBUG #define VL2_g4 { \ if(dbg_rg4_r) fprintf(stderr,"VL2 "); \ bits_g4(code2d[i2D_VL2]); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define VL2_g4 { \ bits_g4(code2d[i2D_VL2]); \ } #endif #if DEBUG #define VL3_g4 { \ if(dbg_rg4_r) fprintf(stderr,"VL3 "); \ bits_g4(code2d[i2D_VL3]); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define VL3_g4 { \ bits_g4(code2d[i2D_VL3]); \ } #endif #if DEBUG #define PASS_g4 { \ if(dbg_rg4_r) fprintf(stderr,"PASS "); \ bits_g4(code2d[i2D_PASS]); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define PASS_g4 { \ bits_g4(code2d[i2D_PASS]); \ } #endif #if DEBUG #define HORIZ_g4 { \ if(dbg_rg4_r) fprintf(stderr,"HORIZ "); \ bits_g4(code2d[i2D_HORIZ]); \ if(dbg_rg4_r) fprintf(stderr,"\n"); \ } #else #define HORIZ_g4 { \ bits_g4(code2d[i2D_HORIZ]); \ } #endif #define detect_a1a2_BW { \ /* find leftmost black changing pel > a0 */ \ /* advance cra as far as possible s.t. cra->xe<=a0 */ \ while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \ /* look beyond cra, until cr->xs>a0 */ \ cr=cra; while(cr<cre && (a1=cr->xs)<=a0) cr++; \ if(cr<cre) a2=cr->xe+1; \ else a1=a2=wid; \ } #define detect_a1a2_WB { \ /* find leftmost white changing pel > a0 */ \ /* advance cra as far as possible s.t. cra->xe<=a0 */ \ while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \ /* look beyond cra, until cr->xe+1>a0 */ \ cr=cra; while(cr<cre && (a1=cr->xe+1)<=a0) cr++; \ if(cr<cre) { \ if((cr+1)<cre) a2=(cr+1)->xs; \ else a2=wid; \ } \ else a1=a2=wid; \ } #define detect_a1a2 {if(a0_color==DST_white) detect_a1a2_BW else detect_a1a2_WB;} #define detect_b1b2_BW {\ /* find leftmost black changing pel > a0 */ \ /* advance pra as far as possible s.t. pra->xe<=a0 */ \ while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \ /* look beyond pra */ \ pr=pra; while(pr<pre && (b1=pr->xs)<=a0) pr++; \ /* move b2 to 1st changing white pel > b1 */ \ if(pr<pre) b2=pr->xe+1; \ else b1=b2=wid; \ } #define detect_b1b2_WB {\ /* find leftmost white changing pel > a0 */ \ /* advance pra as far as possible s.t. pra->xe<=a0 */ \ while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \ /* look beyond pra */ \ pr=pra; while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \ /* move b2 to 1st changing black pel > b1 */ \ if(pr<pre) { \ if((pr+1)<pre) b2=(pr+1)->xs; \ else b2=wid; \ } \ else b1=b2=wid; \ } #define detect_b1b2 {if(a0_color==DST_white) detect_b1b2_BW else detect_b1b2_WB;} RLE_Run *cr,*cre,*pr,*pre; /* into current/prior rle lines */ int a0,a1,a2,b1,b2; /* indices {0,1,...} of pixels */ DST_color a0_color; /* a0's color: same as a2 & b2, opp of a1 & b1 */ RLE_Run *cra; /* rightmost in current st xe<=a0 (none: ==cl->r) */ RLE_Run *pra; /* rightmost in prior st xe<=a0 (none: ==pl->r) */ int a01,a12,a1b1; /* lengths of runs a0-a1 a1-a2 a1-b1 */ #if DEBUG if(dbg_rg4_e) err("rlel_to_g4(pl[%d],cl[%d],w%d)", (pl==NULL)? -1: pl->runs, (cl==NULL)? -1: cl->runs, wid); #endif /* start on an imaginary white pixel just to left of margin */ a0= -1; a0_color = DST_white; pre = (pra=pl->r) + pl->runs; /* prior line's runs */ /* start b1/b2 on prior line's first black pixel, etc; if none, then place off end of line */ if(pra<pre) {b1=pra->xs; b2=pra->xe+1;} else b1=b2=wid; if(cl!=NULL&&cl->runs>0) { cre = (cra=cl->r) + cl->runs; a1=cra->xs; a2=cra->xe+1; #if rg4_strict while( a0 < wid ) { #else while( a0 < wid-1 ) { #endif /* a0, a1, a2, b1, b2 are as defined in CCITT Rec. T.6 */ #if DEBUG if(dbg_rg4_r) fprintf(stderr,"f%d(%d,%d,%d) b%d(%d,%d)\n", cra-(cl->r),a0,a1,a2,pra-(pl->r),b1,b2); #endif if(b2<a1) /* PASS mode */ { PASS_g4; a0=b2; /* a0-color, a1, & a2 are unchanged */ detect_b1b2; } else if((a1b1=(a1-b1))<=3 && a1b1>= -3) { /* VERTICAL mode */ switch(a1b1) { case -3: VL3_g4; break; case -2: VL2_g4; break; case -1: VL1_g4; break; case 0: V0_g4; break; case 1: VR1_g4; break; case 2: VR2_g4; break; case 3: VR3_g4; break; }; a0=a1; a0_color=flip_color(a0_color); detect_a1a2; detect_b1b2; } else { /* HORIZONTAL mode */ HORIZ_g4; a01=a1-a0; if(a0== -1) a01--; a12=a2-a1; if(a0_color==DST_white) { Wrun_g4(a01); Brun_g4(a12); } else { Brun_g4(a01); Wrun_g4(a12); }; a0=a2; /* a0_color is unchanged */ detect_a1a2; detect_b1b2; }; }; } else /* current line is blank */ { a1=a2=wid; #if rg4_strict while( a0 < wid ) { #else while( a0 < wid-1 ) { #endif /* a0, a1, a2, b1, b2 are as defined in CCITT Rec. T.6 */ #if DEBUG if(dbg_rg4_r) fprintf(stderr,"f(%d,%d,%d) b%d(%d,%d)\n", a0,a1,a2,pra-(pl->r),b1,b2); #endif if(b2<a1) /* PASS mode */ { PASS_g4; a0=b2; /* a0-color, a1, & a2 are unchanged */ detect_b1b2; } else if((a1b1=a1-b1)<=3 && a1b1>= -3) { /* VERTICAL mode */ switch(a1b1) { case -3: VL3_g4; break; case -2: VL2_g4; break; case -1: VL1_g4; break; case 0: V0_g4; break; case 1: VR1_g4; break; case 2: VR2_g4; break; case 3: VR3_g4; break; }; a0=a1; a0_color=flip_color(a0_color); /* a1, & a2 are unchanged */ detect_b1b2; } else { /* HORIZONTAL mode */ HORIZ_g4; a01=a1-a0; if(a0== -1) a01--; a12=a2-a1; if(a0_color==DST_white) { Wrun_g4(a01); Brun_g4(a12); } else { Brun_g4(a01); Wrun_g4(a12); }; a0=a2; /* a0_color, a1, & a2 are unchanged */ detect_b1b2; }; }; }; } EOF_to_g4(f) BITFILE *f; { char *cs; /* write EOFB */ EOFB_g4; #if DEBUG if(dbg_rg4_e) fprintf(stderr,"EOF\n"); #endif } 0707070035351137051006640007620000050000010261160476773366600001000000024315CCITT.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* CCITT Group 3 FAX compression codes */ #define EOLSTRING "000000000001" #define EOLLENGTH 12 /* length of EOLSTRING */ #define MAXCODELEN 24 #define DST_EOL -3 /* translate a runlength value <=2560 to an index into the Huffman code table; if the index is >=64, then must repeat for (r%64) */ #define rtoi(r) (((r)<64)? (r): 64+((r)/64)) /* translate an index into the Huffman code table to a runlength value */ #define itor(i) (((i)<64)? (i): (((i)>64)? (((i)-64)*64): DST_EOL)) /* Black run code table */ static char *codeblk[] = { /* code run-length value */ "0000110111", /* 0, */ "010", /* 1, */ "11", /* 2, */ "10", /* 3, */ "011", /* 4, */ "0011", /* 5, */ "0010", /* 6, */ "00011", /* 7, */ "000101", /* 8, */ "000100", /* 9, */ "0000100", /* 10, */ "0000101", /* 11, */ "0000111", /* 12, */ "00000100", /* 13, */ "00000111", /* 14, */ "000011000", /* 15, */ "0000010111", /* 16, */ "0000011000", /* 17, */ "0000001000", /* 18, */ "00001100111", /* 19, */ "00001101000", /* 20, */ "00001101100", /* 21, */ "00000110111", /* 22, */ "00000101000", /* 23, */ "00000010111", /* 24, */ "00000011000", /* 25, */ "000011001010", /* 26, */ "000011001011", /* 27, */ "000011001100", /* 28, */ "000011001101", /* 29, */ "000001101000", /* 30, */ "000001101001", /* 31, */ "000001101010", /* 32, */ "000001101011", /* 33, */ "000011010010", /* 34, */ "000011010011", /* 35, */ "000011010100", /* 36, */ "000011010101", /* 37, */ "000011010110", /* 38, */ "000011010111", /* 39, */ "000001101100", /* 40, */ "000001101101", /* 41, */ "000011011010", /* 42, */ "000011011011", /* 43, */ "000001010100", /* 44, */ "000001010101", /* 45, */ "000001010110", /* 46, */ "000001010111", /* 47, */ "000001100100", /* 48, */ "000001100101", /* 49, */ "000001010010", /* 50, */ "000001010011", /* 51, */ "000000100100", /* 52, */ "000000110111", /* 53, */ "000000111000", /* 54, */ "000000100111", /* 55, */ "000000101000", /* 56, */ "000001011000", /* 57, */ "000001011001", /* 58, */ "000000101011", /* 59, */ "000000101100", /* 60, */ "000001011010", /* 61, */ "000001100110", /* 62, */ "000001100111", /* 63 */ EOLSTRING, /* EOL */ "0000001111", /* 64, */ "000011001000", /* 128, */ "000011001001", /* 192, */ "000001011011", /* 256, */ "000000110011", /* 320, */ "000000110100", /* 384, */ "000000110101", /* 448, */ "0000001101100", /* 512, */ "0000001101101", /* 576, */ "0000001001010", /* 640, */ "0000001001011", /* 704, */ "0000001001100", /* 768, */ "0000001001101", /* 832, */ "0000001110010", /* 896, */ "0000001110011", /* 960, */ "0000001110100", /* 1024, */ "0000001110101", /* 1088, */ "0000001110110", /* 1152, */ "0000001110111", /* 1216, */ "0000001010010", /* 1280, */ "0000001010011", /* 1344, */ "0000001010100", /* 1408, */ "0000001010101", /* 1472, */ "0000001011010", /* 1536, */ "0000001011011", /* 1600, */ "0000001100100", /* 1664, */ "0000001100101", /* 1728 */ /* extended length: */ "00000001000", /* 1792, */ "00000001100", /* 1856, */ "00000001101", /* 1920, */ "000000010010", /* 1984, */ "000000010011", /* 2048, */ "000000010100", /* 2112, */ "000000010101", /* 2176, */ "000000010110", /* 2240, */ "000000010111", /* 2304, */ "000000011100", /* 2368, */ "000000011101", /* 2432, */ "000000011110", /* 2496, */ "000000011111", /* 2560 */ NULL /* are there codes beyond 2560? */ }; /* No. bits in the codes in the above table */ static short bitcblk[] = { 10,3,2,2,3,4,4,5,6,6, /* 0 - 9 */ 7,7,7,8,8,9,10,10,10,11, /* 10 - 19 */ 11,11,11,11,11,11,12,12,12,12, /* 20 - 29 */ 12,12,12,12,12,12,12,12,12,12, /* 30 - 39 */ 12,12,12,12,12,12,12,12,12,12, /* 40 - 49 */ 12,12,12,12,12,12,12,12,12,12, /* 50 - 59 */ 12,12,12,12, /* 60 - 63 */ 12, /* EOL */ 10, /* 64 */ 12,12,12,12,12,12, /* 128 - 448 */ 13,13,13,13,13,13,13,13,13, /* 512 - */ 13,13,13,13,13,13,13,13,13, 13,13, /* - 1728 */ 11,11,11, /* 1792 - 1920 */ 12,12,12,12,12,12,12,12,12,12, /* 1984 - 2560 */ /* for codes over 2560 */ 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, -1 }; /* White run code table */ static char *codewht[] = { /* code run-length value */ "00110101", /* 0, */ "000111", /* 1, */ "0111", /* 2, */ "1000", /* 3, */ "1011", /* 4, */ "1100", /* 5, */ "1110", /* 6, */ "1111", /* 7, */ "10011", /* 8, */ "10100", /* 9, */ "00111", /* 10, */ "01000", /* 11, */ "001000", /* 12, */ "000011", /* 13, */ "110100", /* 14, */ "110101", /* 15, */ "101010", /* 16, */ "101011", /* 17, */ "0100111", /* 18, */ "0001100", /* 19, */ "0001000", /* 20, */ "0010111", /* 21, */ "0000011", /* 22, */ "0000100", /* 23, */ "0101000", /* 24, */ "0101011", /* 25, */ "0010011", /* 26, */ "0100100", /* 27, */ "0011000", /* 28, */ "00000010", /* 29, */ "00000011", /* 30, */ "00011010", /* 31, */ "00011011", /* 32, */ "00010010", /* 33, */ "00010011", /* 34, */ "00010100", /* 35, */ "00010101", /* 36, */ "00010110", /* 37, */ "00010111", /* 38, */ "00101000", /* 39, */ "00101001", /* 40, */ "00101010", /* 41, */ "00101011", /* 42, */ "00101100", /* 43, */ "00101101", /* 44, */ "00000100", /* 45, */ "00000101", /* 46, */ "00001010", /* 47, */ "00001011", /* 48, */ "01010010", /* 49, */ "01010011", /* 50, */ "01010100", /* 51, */ "01010101", /* 52, */ "00100100", /* 53, */ "00100101", /* 54, */ "01011000", /* 55, */ "01011001", /* 56, */ "01011010", /* 57, */ "01011011", /* 58, */ "01001010", /* 59, */ "01001011", /* 60, */ "00110010", /* 61, */ "00110011", /* 62, */ "00110100", /* 63 */ EOLSTRING, /* EOL */ "11011", /* 64, */ "10010", /* 128, */ "010111", /* 192, */ "0110111", /* 256, */ "00110110", /* 320, */ "00110111", /* 384, */ "01100100", /* 448, */ "01100101", /* 512, */ "01101000", /* 576, */ "01100111", /* 640, */ "011001100", /* 704, */ "011001101", /* 768, */ "011010010", /* 832, */ "011010011", /* 896, */ "011010100", /* 960, */ "011010101", /* 1024, */ "011010110", /* 1088, */ "011010111", /* 1152, */ "011011000", /* 1216, */ "011011001", /* 1280, */ "011011010", /* 1344, */ "011011011", /* 1408, */ "010011000", /* 1472, */ "010011001", /* 1536, */ "010011010", /* 1600, */ "011000", /* 1664, */ "010011011", /* 1728 */ /* extended length: */ "00000001000", /* 1792, */ "00000001100", /* 1856, */ "00000001101", /* 1920, */ "000000010010", /* 1984, */ "000000010011", /* 2048, */ "000000010100", /* 2112, */ "000000010101", /* 2176, */ "000000010110", /* 2240, */ "000000010111", /* 2304, */ "000000011100", /* 2368, */ "000000011101", /* 2432, */ "000000011110", /* 2496, */ "000000011111", /* 2560 */ NULL /* are there codes beyond 2560? */ }; /* no. bits in the codes in the above table */ static short bitcwht[] = { 8,6,4,4,4,4,4,4,5,5, /* 0 - 9 */ 5,5,6,6,6,6,6,6,7,7, /* 10 - 19 */ 7,7,7,7,7,7,7,7,7,8, /* 20 - 29 */ 8,8,8,8,8,8,8,8,8,8, /* 30 - 39 */ 8,8,8,8,8,8,8,8,8,8, /* 40 - 49 */ 8,8,8,8,8,8,8,8,8,8, /* 50 - 59 */ 8,8,8,8, /* 60 - 63 */ 12, /* EOL */ 5,5, /* 64,128 */ 6, /* 192 */ 7, /* 256 */ 8,8,8,8,8,8, /* 320 - 640 */ 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, /* 704 - 1600 */ 6, /* 1664 */ 9, /* 1728 */ 11,11,11, /* 1792,1856,1920 */ 12,12,12,12,12,12,12,12,12,12, /* 1984 - 2560 */ /* for codes over 2560 */ 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, -1 }; /* 2-D codes (indices into code2d[] table) */ #define i2D_V0 0 #define i2D_VR1 1 #define i2D_VR2 2 #define i2D_VR3 3 #define i2D_VL1 4 #define i2D_VL2 5 #define i2D_VL3 6 #define i2D_PASS 7 #define i2D_HORIZ 8 #define i2D_EOL 9 static char *code2d[] = { "1", /* V0 */ "011", /* VR1 */ "000011", /* VR2 */ "0000011", /* VR3 */ "010", /* VL1 */ "000010", /* VL2 */ "0000010", /* VL3 */ "0001", /* PASS */ "001", /* HORIZ */ EOLSTRING, /* EOL */ NULL }; static short bitc2d[] = { 1,3,6,7,3,6,7,4,3,12 }; #define EOL0STRING "0000000000010" #define EOL1STRING "0000000000011" #define EOFB "000000000001000000000001" static char *spare1d[] = { "000000001", /* 0, */ "0000000001", /* 0, */ "00000000001", /* 0 */ NULL }; static char *spare2d[] = { "0000001", /* 0, */ "00000001", /* 0, */ "000000001", /* 0, */ "0000000001", /* 0, */ "00000000001", /* 0 */ NULL }; /* State-transition table for decoding CCITT G3-1 */ /* bit colors; also, starting index in table of 1-D codes*/ #define DST_color short #define DST_white 0 #define DST_black 1 #define flip_color(c) ((c)? 0: 1) #define DST_2d 2 /* starting index in table of 2-D codes */ #define DST_state short /* state-id: index into DST_tbl.e[] */ #define DST_state_NULL (-1) #define DST_state_ERROR (-2) #define DST_action int #define DST_action_NULL (-1) #define DST_action_ERROR (-2) /* transition in finite-state machine */ typedef struct DST_transit { DST_action a; /* action to perform */ DST_state s; /* next state */ } DST_transit; typedef struct DST_entry { char p[MAXCODELEN+1]; /* code prefix so far (in ASCII) */ short l; /* strlen(.p) */ short z; /* no. of trailing "0"'s in .p */ DST_transit t[2]; /* two transitions: on 0 & 1 */ } DST_entry; typedef struct DST_table { int mny; /* no. entries so far */ DST_entry *e; /* array in malloc space: e[DST_white] starts white 1-D codes; e[DST_black] starts black 1-D codes; e[DST_2d] starts 2-D codes */ } DST_table; typedef struct DST_context { DST_color c; /* current run-color */ int l; /* length of current code in bits: 0..(len-1) */ DST_table *t; /* table */ DST_state s; /* current state */ DST_transit tr; /* current state/action */ } DST_context; DST_table *ccitt_table(); RLE_Line *g31_to_rlel(); int rlel_to_g31(); RLE_Line *g32_to_rlel(); int rlel_to_g32(); RLE_Line *g4_to_rlel(); int rlel_to_g4(); 0707070035351137061006640007620000050000010261170476773366600000600000010272CPU.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* T. Thompson - ATT-BL HO - portable versions */ /* C. Macey - ATT-DSG LZ - portable versions */ /* Specify the environment: CPU, OS, graphics, etc. This is an attempt to maintain a single master source tailorable at compile time, while encapsulating as many as possible of the required #if's and #ifdef's in this one file. OS-dependent #includes are triggered by these prior statements: #define LIBC_INCL 1 -- strcpy(), etc #define VALUES_INCL 1 -- math constants (PI etc) #define FILE_TREE_INCL 1 -- UNIX file-tree walking */ /* CPUs with some support: */ #define VAX 0 #define CRAY 1 #define SUN 2 /* including SPARC */ #define ATT3B 3 #define I386 4 #define MIPS 5 /* including SGI */ /*** Select CPU here: */ #define CPU VAX /* Operating systems with some support: */ #define V9_OS 1 /* ATT-BL research UNIX, 9th edition */ #define SV_OS 2 /* ATT UNIX System V */ #define SUN_OS 3 /* Sun OS 4.x */ /*** Select OS here: */ #define OS V9_OS /* Graphics display environments with some support: */ #define NO_GRAPHICS 0 /* defeat all graphics */ #define Y_GRAPHICS 1 /* the Y graphics interface (used in 1127 for Metheus) */ #define SUN_GRAPHICS 2 /* Tim Thompson's Sun interface */ #define X_GRAPHICS 3 /* Mark Tuomenoksa's X interface */ /*** Select graphics environment here: */ #define GRAPHICS Y_GRAPHICS /* OCR installation directory */ #ifndef OCRDIR #define OCRDIR "/usr/ocr" #endif /*** Miscellaneous arcane options: best left alone **/ #define FILE_TREE (1) /* set to zero to defeat UNIX file tree code */ /*** END OF SELECTIONS ** The rest of this file merely implements their effects */ /* define byte ordering in CPU */ #if CPU == SUN || CPU == MIPS #define BIG_ENDIAN 1 #endif /* deal with compilers that don't like (void *) */ #if CPU == MIPS #define VOID char #else #define VOID void #endif /* include libc functions defs, if necessary */ #if LIBC_INCL #if OS == V9_OS || CPU == CRAY #include <libc.h> #else #if OS == SV_OS || OS == SUN_OS || CPU == MIPS #include <string.h> #endif #endif #endif /* include values */ #if VALUES_INCL #include <values.h> #endif /* UNIX file-tree-walk includes */ #if FILE_TREE_INCL #if CPU==VAX || CPU==CRAY || CPU==MIPS #include <sys/types.h> #include <sys/stat.h> #include <ftw.h> #else #if CPU==SUN || CPU==I386 #include <sys/types.h> #include <sys/stat.h> #include "myftw.h" /* T. Thompson's version */ #endif #endif #endif #if CPU==SUN||CPU==ATT3B||CPU==MIPS||CPU==I386 #define sgn(V) (((V)>0)? 1: (((V)<0)? -1: 0)) #endif #if CPU==SUN||CPU==ATT3B||CPU==MIPS /* These are all big-endian machines */ #define swapshortin(x) (((x)<<8)&0xff00)|(((x)>>8)&0xff) #define swapintin(x) \ ((((x)<<24)&0xff000000)| \ (((x)<<8) &0x00ff0000)| \ (((x)>>8) &0x0000ff00)| \ (((x)>>24)&0x000000ff)) /* The order of bytes in an int */ #define INDEX0 3 #define INDEX1 2 #define INDEX2 1 #define INDEX3 0 /* disable fast trick for picking out a short from an int */ #define USESHIFT /* cf. skewlib.c */ #else #define swapshortin(x) (x) #define swapintin(x) (x) #define INDEX0 0 #define INDEX1 1 #define INDEX2 2 #define INDEX3 3 #endif /* global max no. classes -- gradually being made dynamic everywhere */ #if CPU==SUN #define MAX_CL 128 #else #define MAX_CL 3200 /* adequate for JIS Level 1 */ #endif /* include char types (is this really necessary?) */ #if CTYPE_INCL #if CPU == SUN #include <string.h> #else #include <ctype.h> #endif #endif /* includes for atan2 special configurations */ #if ATAN_INCL #if CPU == CRAY #define use_fast_atan2 F #include "CRAY.h" #else #define use_fast_atan2 T #endif #endif /* regular expression includes (fix to use standard regexp?) */ #if REGEXP_INCL #if OS == V9_OS #include <regexp.h> #else #include "regexp.h" #endif #endif /* Use of the graphics display */ #if CPU != CRAY #define SHOW_GRAPHICS 1 #endif #ifndef PI #define PI 3.14159265358979323846 #endif 0707070035351137071006640007620000050000010261230476773366600001000000027244Coord.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* T. J. Thompson - ATT-BL HO - improvements */ /* Coord.c - function bodies for basic Coordinate geometry. See Coord.h for associated defines, typedefs, etc. */ #include <stdio.h> #include <math.h> #include <string.h> #define ATAN_INCL 1 #include "CPU.h" #include "boole.h" #include "Units.h" #include "Coord.h" /* Added by Tim Thompson ... */ int Readvax = 0; VOID setreadvax() { char *getenv(); char *p = getenv("READVAX"); /* any non-null value of READVAX will set it */ if ( p!=NULL && strlen(p)>0 ) Readvax = 1; } /* ... */ /* Convert a real value, a units specification, and a resolution into a value in scanner coordinates. */ int vto_scoor(v,u,r) double v; /* value in special units */ char u; /* units: one of UNITS (see ric.h) */ int r; /* resolution in pixels/inch */ { int c; switch(u) { case 'i': /* inches */ c = (int)(v*r + 0.5); break; case 'c': /* cm */ c = (int)((v*r/2.54) + 0.5); break; case 'p': /* points */ c = (int)((v*INCHES_PER_POINT*r) + 0.5); break; case 'P': /* picas */ c = (int)((v*12.0*INCHES_PER_POINT*r) + 0.5); break; case 's': /* scanner pixel (Scoor) */ case 'u': /* basic unit */ c = (int)(v + 0.5); break; default: c = (int)(v + 0.5); break; }; return(c); } /* Return pointer to empty Sp from malloc space */ Sp *alloc_sp() { Sp *spp; if((spp=(Sp *)malloc(sizeof(Sp)))==NULL) abort("alloc_sp: can't"); *spp = zero_Sp; return(spp); } /* Free Sp from malloc space */ free_sp(spp) Sp *spp; { free(spp); } Sp *ato_sp(s) char *s; { char *d; static Sp p; char *p_x,*p_y; #define SP_DELIM "(), " d = strdup(s); p_x = strtok(d,SP_DELIM); p_y = strtok((char *)0,SP_DELIM); if(p_x==NULL||p_y==NULL) {free(d); return(NULL);}; p.x = atoi(p_x); p.y = atoi(p_y); free(d); return(&p); } char *sp_toa(sp) Sp *sp; #define sp_toa_distinct (5) { static char s[sp_toa_distinct][40]; static int sp_toa_cur = -1; sp_toa_cur = (sp_toa_cur+1)%sp_toa_distinct; sprintf(s[sp_toa_cur],"(%d,%d)",sp->x,sp->y); return(s[sp_toa_cur]); } /* Read a list of Sp's (in ascii) from file *fp, into set *spsp */ frda_sps(fp,spsp) FILE *fp; Sps *spsp; #define MAX_SPS_LINE (80) { Sp *spp,**bb; long seek; char line[MAX_SPS_LINE+1]; *spsp = empty_Sps; seek = ftell(fp); /* count all points quickly, in advance */ while(!feof(fp)) { line[0] = '\0'; fgets(line,MAX_SPS_LINE,fp); if(strlen(line)>0) { spsp->mny++; }; }; if((spsp->pa=(Sp **)malloc((spsp->mny+1)*sizeof(Sp *)))==NULL) abort("frda_sps: can't alloc spsp->pa[%d]",spsp->mny+1); /* next, reread points */ fseek(fp,(long)seek,0); bb=spsp->pa; while(!feof(fp)) { line[0] = '\0'; fgets(line,MAX_SPS_LINE,fp); if(strlen(line)>0) { *(spp = alloc_sp()) = *ato_sp(line); *(bb++) = spp; }; }; *bb = NULL; } err_sps(p) Sps *p; { int i; Sp **s; fprintf(stderr,"Sps: %d points: ",p->mny); if(p->mny>0) for(s=p->pa; (*s)!=NULL; s++) { fprintf(stderr,"%s ",sp_toa(*s)); }; fprintf(stderr,"\n"); } Sp *append_sp_sps(sp,sps) Sp *sp; Sps *sps; { if(sps->mny>0) { if((sps->pa=(Sp **)realloc(sps->pa,(sps->mny+2)*sizeof(Sp *)))==NULL) abort("append_sp_sps: can't realloc sps->pa[%d]",sps->mny+2); } else { sps->mny=0; if((sps->pa=(Sp **)malloc((sps->mny+2)*sizeof(Sp *)))==NULL) abort("append_sp_sps: can't alloc sps->pa[%d]",sps->mny+2); }; sps->pa[sps->mny++] = sp; sps->pa[sps->mny] = NULL; } /* Return pointer to local static Sps which holds a duplicate of the given Sps (all contents are freshly malloc'ed) */ Sps *dup_sps(old) Sps *old; { static Sps new; Sp **o,**n; if(old->mny>0) { new.mny = old->mny; if((new.pa=(Sp **)malloc((new.mny+1)*sizeof(Sp *)))==NULL) abort("dup_sps: can't alloc new.pa[%d]",new.mny+1); for(o=old->pa,n=new.pa; *o!=NULL; o++,n++) { *(*n = alloc_sp()) = **o; }; *n = NULL; } else new = empty_Sps; return(&new); } free_sps(p) Sps *p; { if(p->pa!=NULL) free(p->pa); *p = empty_Sps; } Sp *append_sp_spa(sp,spa) Sp *sp; Spa *spa; { if(spa->mny>0) { if((spa->a=(Sp *)realloc(spa->a,(spa->mny+1)*sizeof(Sp)))==NULL) abort("append_sp_spa: can't alloc spa->a[%d]",spa->mny+1); } else { spa->mny=0; if((spa->a=(Sp *)malloc((spa->mny+1)*sizeof(Sp)))==NULL) abort("append_sp_spa: can't alloc spa->a[%d]",spa->mny+1); }; spa->a[spa->mny++] = *sp; } err_spa(p) Spa *p; { int i; Sp *sp; fprintf(stderr,"Spa: %d points: ",p->mny); for(i=0,sp=p->a;i<p->mny;i++,sp++) { fprintf(stderr,"%s ",sp_toa(sp)); }; fprintf(stderr,"\n"); } free_spa(p) Spa *p; { if(p->a!=NULL) free(p->a); *p = empty_Spa; } /* Rotate the Scanner point `(x,y') about origin `*orp' by angle `ang', and return pointer to the result. This is slow, but no matter. */ Sp *rotate_Sp(ang,orp,x,y) double ang; Sp *orp; int x,y; { static Sp res; Sp of; of.x = x - orp->x; of.y = y - orp->y; res.x = (short)(((cos(ang)*of.x - sin(ang)*of.y)) + orp->x + 0.5); res.y = (short)(((sin(ang)*of.x + cos(ang)*of.y)) + orp->y + 0.5); return(&res); } /* Horizontally shear the Scanner point `(x,y') about origin `*orp' by shear angle `ang', and return pointer to the result. `Ang' is close to 90 degrees. This is slow, but no matter. */ Sp *hshear_Sp(ang,orp,x,y) double ang; Sp *orp; int x,y; { static Sp res; Scoor of_y,tr_x; res.x = (short)(orp->x - (y - orp->y)*tan(ang-(90.0*DtoR)) + 0.5); res.y = orp->y; return(&res); } /* Return pointer to initialized Edge from malloc space */ Edge *alloc_edge() { Edge *ep; if((ep=(Edge *)malloc(sizeof(Edge)))==NULL) abort("alloc_edge: can't"); *ep = empty_Edge; return(ep); } /* Free Edge from malloc space */ free_edge(ep) Edge *ep; { free(ep); } char *edge_toa(ep) Edge *ep; { static char s[40]; strcpy(s,sp_toa(&(ep->a))); strcat(s,"-"); strcat(s,sp_toa(&(ep->b))); return(s); } Edge *ato_edge(s) char *s; { char *d; static Edge e; char *a_x,*a_y,*b_x,*b_y; #define EDGE_DELIM "(),- " d = strdup(s); a_x = strtok(d,EDGE_DELIM); a_y = strtok((char *)0,EDGE_DELIM); b_x = strtok((char *)0,EDGE_DELIM); b_y = strtok((char *)0,EDGE_DELIM); if(a_x==NULL||a_y==NULL||b_x==NULL||b_y==NULL) {free(d); return(NULL);}; e.a.x = atoi(a_x); e.a.y = atoi(a_y); e.b.x = atoi(b_x); e.b.y = atoi(b_y); free(d); return(&e); } /* Return pointer to empty Bbx from malloc space */ Bbx *alloc_bbx() { Bbx *bxp; if((bxp=(Bbx *)malloc(sizeof(Bbx)))==NULL) abort("alloc_bbx: can't"); *bxp = empty_Bbx; return(bxp); } /* Free Bbx from malloc space */ free_bbx(bxp) Bbx *bxp; { free(bxp); } char *bbx_toa(bxp) Bbx *bxp; { static char s[40]; strcpy(s,sp_toa(&(bxp->a))); strcat(s,sp_toa(&(bxp->b))); return(s); } Bbx *ato_bbx(s) char *s; { char *d; static Bbx bx; char *a_x,*a_y,*b_x,*b_y; #define BBX_DELIM "(), " d = strdup(s); a_x = strtok(d,BBX_DELIM); a_y = strtok((char *)0,BBX_DELIM); b_x = strtok((char *)0,BBX_DELIM); b_y = strtok((char *)0,BBX_DELIM); if(a_x==NULL||a_y==NULL||b_x==NULL||b_y==NULL) {free(d); return(NULL);}; bx.a.x = atoi(a_x); bx.a.y = atoi(a_y); bx.b.x = atoi(b_x); bx.b.y = atoi(b_y); free(d); return(&bx); } Bbx *expand_bbx(bxp,X) Bbx *bxp; int X; /* expansion code */ { static Bbx xbx; xbx = *bxp; switch(X) { case -3: xbx.a.x += 2; xbx.a.y += 2; xbx.b.x -= 1; xbx.b.y -= 1; break; case -2: xbx.a.x += 1; xbx.a.y += 1; xbx.b.x -= 1; xbx.b.y -= 1; break; case -1: xbx.a.x += 1; xbx.a.y += 1; break; case 0: break; case 1: xbx.b.x += 1; xbx.b.y += 1; break; case 2: xbx.a.x -= 1; xbx.a.y -= 1; xbx.b.x += 1; xbx.b.y += 1; break; case 3: xbx.a.x -= 1; xbx.a.y -= 1; xbx.b.x += 2; xbx.b.y += 2; break; default: break; }; return(&xbx); } /* Predicate: Is most of Bbx 1 inside Bbx 2? ``Most'' is defined as more than half of the first Bbx's area inside BBx 2.*/ boolean bbx_inside_most(b1,b2) Bbx *b1,*b2; { struct { /* overlap between blob box and selection box */ Bbx bx; /* Bbx of intersection */ Sp sd; /* side-lengths of overlap box, >=0 */ long area; /* area is square pixels, >=0 */ } ov; if(!bbx_inside_any(b1,b2)) return(F); else if(bbx_inside_all(b1,b2)) return(T); else { /* compute overlap box */ ov.bx.a.x = ((b1)->a.x>(b2)->a.x)? (b1)->a.x: (b2)->a.x; ov.bx.a.y = ((b1)->a.y>(b2)->a.y)? (b1)->a.y: (b2)->a.y; ov.bx.b.x = ((b1)->b.x<(b2)->b.x)? (b1)->b.x: (b2)->b.x; ov.bx.b.y = ((b1)->b.y<(b2)->b.y)? (b1)->b.y: (b2)->b.y; ov.sd.x = bbx_wid(&ov.bx); if(ov.sd.x<0) ov.sd.x=0; ov.sd.y = bbx_hgt(&ov.bx); if(ov.sd.y<0) ov.sd.y=0; ov.area = ov.sd.x*ov.sd.y; return( (ov.area>0) && ( 2*ov.area > bbx_area(b1) ) ); }; } Bbx *translate_bbx(bxp,off) Bbx *bxp; Sp off; { static Bbx res; res.a.x = bxp->a.x + off.x; res.a.y = bxp->a.y + off.y; res.b.x = bxp->b.x + off.x; res.b.y = bxp->b.y + off.y; return(&res); } /* Free Bbxs (but not the contents) */ free_bbxs(bxsp) Bbxs *bxsp; { Bbx **b; if(bxsp->mny>0) { if(bxsp->pa!=NULL) free(bxsp->pa); }; *bxsp = empty_Bbxs; } /* Free Bbxs (and the individually-malloc'ed contents) */ free_bbxs_etc(bxsp) Bbxs *bxsp; { Bbx **b; if(bxsp->mny>0) { for(b=bxsp->pa; (*b)!=NULL; b++) free(*b); if(bxsp->pa!=NULL) free(bxsp->pa); }; *bxsp = empty_Bbxs; } /* Return pointer to local static Bbxs which holds a duplicate of the given Bbxs (all contents are freshly malloc'ed) */ Bbxs *dup_bbxs(old) Bbxs *old; { static Bbxs new; Bbx **o,**n; if(old->mny>0) { new.mny = old->mny; new.alloc = old->alloc; new.incr = old->incr; if((new.pa=(Bbx **)malloc((new.alloc)*sizeof(Bbx *)))==NULL) abort("dup_bbxs: can't alloc new.pa[%d]",new.alloc); for(o=old->pa,n=new.pa; *o!=NULL; o++,n++) { *(*n = alloc_bbx()) = **o; }; *n = NULL; } else new = empty_Bbxs; return(&new); } Bbx *append_bbx(bxp,bxsp) Bbx *bxp; Bbxs *bxsp; { if(bxsp->mny>0) { if((bxsp->mny+2)>bxsp->alloc) { bxsp->alloc += bxsp->incr; if( ( bxsp->pa = (Bbx **)realloc(bxsp->pa,bxsp->alloc*sizeof(Bbx *)) ) ==NULL ) abort("append_bbx: can't alloc bxsp->pa[%d]",bxsp->alloc); }; } else { bxsp->mny=0; if(bxsp->pa!=NULL) free(bxsp->pa); bxsp->alloc=0; while((bxsp->mny+2)>bxsp->alloc) bxsp->alloc += bxsp->incr; if((bxsp->pa=(Bbx **)malloc(bxsp->alloc*sizeof(Bbx *)))==NULL) abort("append_bbx: can't alloc bxsp->a[%d]",bxsp->alloc); }; bxsp->pa[bxsp->mny++] = bxp; bxsp->pa[bxsp->mny] = NULL; } frda_bbxs(fp,bxsp) FILE *fp; Bbxs *bxsp; #define MAX_BBX_LINE (80) { Bbx *bxp,**bb; long seek; char line[MAX_BBX_LINE+1]; *bxsp = empty_Bbxs; seek = ftell(fp); /* count all boxes quickly, in advance */ while(!feof(fp)) { line[0] = '\0'; fgets(line,MAX_BBX_LINE,fp); if(strlen(line)>0) { bxsp->mny++; }; }; if((bxsp->pa=(Bbx **)malloc((bxsp->mny+1)*sizeof(Bbx *)))==NULL) abort("frda_bbxs: can't alloc bxsp->pa[%d]",bxsp->mny+1); bxsp->alloc = bxsp->mny+1; /* next, reread boxes */ fseek(fp,(long)seek,0); bb=bxsp->pa; while(!feof(fp)) { line[0] = '\0'; fgets(line,MAX_BBX_LINE,fp); if(strlen(line)>0) { *(bxp = alloc_bbx()) = *ato_bbx(line); *(bb++) = bxp; }; }; *bb = NULL; } fwra_bbxs(fp,bxsp) FILE *fp; Bbxs *bxsp; { Bbx **b; if(bxsp->mny>0) for(b=bxsp->pa; *b!=NULL; b++) { fputs(bbx_toa(*b),fp); fputs("\n",fp); }; fflush(fp); } 0707070035351137101006640007620000050000010261240476773366600001000000017772Coord.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* Coord.h - defines, typedefs, Inits, empties, and function declarations for basic Coordinate geometry data items. See Coord.c for associated functions. */ /* Round signed floating-pt no. F: (a) ROUND - to nearest integer; (b) ROUND_UP - up to next int; (c) ROUND_DN - down to prior int. Evaluates the argument exactly once. */ static double _round,_round_up,_round_dn; #define ROUND(F) ((int)(((_round=(F))>=0.0)? _round+0.5: _round-0.5)) #define ROUND_UP(F) ((int)(((_round_up=(F))>=0.0)? _round_up+0.999999: _round_up)) #define ROUND_DN(F) ((int)(((_round_dn=(F))>=0.0)? _round_dn: _round_dn-0.999999)) /* The basic unit is the scanner pixel, located in the X,Y plane. As in many graphics coordinate systems, X increases left-to-right, while Y increases top-down. Pixel coordinates are usually integer values. The physical extent of integer coordinate `x' along the real X-axis is the half-open interval [x,x+1), and similarly for Y. The actual digitizing resolution (e.g. pixels/inch) represented can vary from document to document, and is almost always known to the algorithms. X & Y resolution can be different, though for simplicity of discussion we will usually assume that they are equal, i.e. that pixels are square. Thus pixel (x,y) may be thought of as the region [x,x+1)X[y,y+1) in the real plane. Half-pixel resolution is also supported, with its own data types for clarity. However, to avoid distracting struggles with the type system, they are for the most part #defined to be identical to ordinary coordinates. The principle effect is that the limits of scanner coordinates have been halved to allow for safe use of half-pixels everywhere. (This still permits images 80 inches square at 400 pixels/inch, assuming `short' is at least 16-bit 2's complement.) Half-pixel coordinates can also be used to describe boundaries of regions, as a set of ideal point locations at the corners and edge midpoints of pixels. The half-pixel data type is used; boundary points are identified by flags in the Bdy "boundary" structure, and may be displayed differently. */ #define Scoor short /* Scanner pixel coordinate value */ #define Hcoor Scoor /* Half-pixel coordinate value */ #define Bcoor Hcoor /* Half-pixel boundary coordinate value */ /* Each Scoor value `v' is associated of course with two Hcoor values `a' < `b'. Conventionally, the physical extent of the `a' half-coordinate is the real interval [v,v+0.5), and `b' is [v+0.5,v+1). */ #define StoHa(S) ((S)*2) #define StoHb(S) ((S)*2+1) #define HtoS(H) ((H)/2) /* The 3 half-pixel boundary points of a pixel coordinate `C' are: */ #define StoBa(S) (StoHa((S))) /* minimum of interval */ #define StoBb(S) (StoHb((S))) /* midpoint of interval */ #define StoBc(S) (StoHa((S)+1)) /* maximum of interval */ #define Scoor_MIN (SHRT_MIN/2) /* minimum possible value */ #define Scoor_MAX (SHRT_MAX/2) /* maximum possible value */ #define Hcoor_MIN (SHRT_MIN) /* minimum possible value */ #define Hcoor_MAX (SHRT_MAX) /* maximum possible value */ #define fwri_Scoor(F,V) fwri_int2((F),(V)) #define frdi_Scoor(F) frdi_int2(F) #define fwri_Hcoor(F,V) fwri_int2((F),(V)) #define frdi_Hcoor(F) frdi_int2(F) #define fwri_Bcoor(F,V) fwri_int2((F),(V)) #define frdi_Bcoor(F) frdi_int2(F) typedef struct Sp { /* point: pixel address */ Scoor x; /* increases left-to-right: Scoor_MIN is left of image */ Scoor y; /* increases down: Scoor_MIN is top of image */ } Sp; #define Hp Sp /* Half-pixel point */ #define Init_Zero_Sp {0,0} #define Init_Min_Sp {Scoor_MIN,Scoor_MIN} #define Init_Max_Sp {Scoor_MAX,Scoor_MAX} #if MAIN Sp zero_Sp = Init_Zero_Sp; #else extern Sp zero_Sp; #endif #define fwri_Sp(F,P) { fwri_Scoor((F),(P)->x); fwri_Scoor((F),(P)->y); } #define frdi_Sp(F,P) (feof(F)? 0: ( \ (P)->x=frdi_Scoor(F), \ (P)->y=frdi_Scoor(F), \ (ferror(F)? -errno: 1) ) ) /* Is Sp *p1 exactly equal to Sp *p2? */ #define sp_eq(p1,p2) ( \ ((p1)->x == (p2)->x) \ && ((p1)->y == (p2)->y) \ ) typedef struct Sps { /* Set of Points */ int mny; /* no. points (mny==0 ==> pa==NULL) */ Sp **pa; /* NULL-terminated Sp *pa[mny+1] (malloc space)*/ } Sps; #define Init_Sps {0,NULL} #if MAIN Sps empty_Sps = Init_Sps; #else extern Sps empty_Sps; #endif typedef struct Spa { /* array of Points */ int mny; /* no. points in array */ Sp *a; /* Sp a[mny] (malloc space)*/ } Spa; /** #define Pointa Spa **/ /* OBSOLESCENT */ #define Init_Spa {0,NULL} #if MAIN Spa empty_Spa = Init_Spa; #else extern Spa empty_Spa; #endif /* An edge is an ordered pair of vertices. */ typedef struct Edge { Sp a,b; /* endpoints */ } Edge; #define Init_Edge {Init_Zero_Sp,Init_Zero_Sp} #if MAIN Edge empty_Edge = Init_Edge; #else extern Edge empty_Edge; #endif #define fwri_Edge(F,P) { fwri_Sp((F),&((P)->a)); fwri_Sp((F),&((P)->b)); } #define frdi_Edge(F,P) ( feof(F)? 0: ( \ frdi_Sp(F,&((P)->a)), \ frdi_Sp(F,&((P)->b)), \ (ferror(F)? -errno: 1) ) ) /* A bounding box is a rectangle */ typedef struct { /* bounding box: inclusive of boundary values */ Sp a; /* top-left corner */ Sp b; /* bottom-right corner */ } Bbx; typedef struct DSp { /* point: pixel address */ double x; /* increases down the page, MinScoor at top */ double y; /* increases across the page, MinScoor at left */ } DSp; #define Init_Bbx {Init_Max_Sp,Init_Min_Sp} #define Init_Max_Bbx {Init_Min_Sp,Init_Max_Sp} #if MAIN Bbx empty_Bbx = Init_Bbx; Bbx max_Bbx = Init_Max_Bbx; #else extern Bbx empty_Bbx; extern Bbx max_Bbx; #endif #define fwri_Bbx(F,P) { fwri_Sp((F),&((P)->a)); fwri_Sp((F),&((P)->b)); } #define frdi_Bbx(F,P) ( feof(F)? 0: ( \ frdi_Sp(F,&((P)->a)), \ frdi_Sp(F,&((P)->b)), \ (ferror(F)? -errno: 1) ) ) /* OBSOLESCENT: */ #if MAIN Bbx null_Bbx = {Init_Max_Sp,Init_Min_Sp}; #else extern Bbx null_Bbx; #endif /* height, width, area of Bbx in pixels */ #define bbx_hgt(bxp) ((bxp)->b.y-(bxp)->a.y+1) #define bbx_wid(bxp) ((bxp)->b.x-(bxp)->a.x+1) #define bbx_area(bxp) (bbx_hgt((bxp))*bbx_wid((bxp))) /* Is Bbx *b1 exactly equal to Bbx *b2? */ #define bbx_eq(b1,b2) ( \ ((b1)->a.x == (b2)->a.x) \ && ((b1)->a.y == (b2)->a.y) \ && ((b1)->b.x == (b2)->b.x) \ && ((b1)->b.y == (b2)->b.y) \ ) /* Is Bbx *b1 wholly inside Bbx *b2? */ #define bbx_inside_all(b1,b2) ( \ ((b1)->a.x >= (b2)->a.x) \ && ((b1)->a.y >= (b2)->a.y) \ && ((b1)->b.x <= (b2)->b.x) \ && ((b1)->b.y <= (b2)->b.y) \ ) /* Is any of Bbx *b1 inside Bbx *b2? */ #define bbx_inside_any(b1,b2) ( \ ((b1)->a.x <= (b2)->b.x) \ && ((b1)->a.y <= (b2)->b.y) \ && ((b1)->b.x >= (b2)->a.x) \ && ((b1)->b.y >= (b2)->a.y) \ ) typedef struct Bbxs { /* A set of Bbxs */ int mny; /* if mny==0, then pa==NULL */ Bbx **pa; /* NULL-terminated array (in malloc space) of `mny+1' pointers to Bbxs (in malloc space) */ int alloc; /* no. slots in pa[] actually allocated (>=mny+1) */ int incr; /* no. slots in pa[] to reallocate at a time */ } Bbxs; #define Init_Bbxs {0,NULL,0,512} #if MAIN Bbxs empty_Bbxs = Init_Bbxs; #else extern Bbxs empty_Bbxs; #endif Sp *alloc_sp(); free_sp(); char *sp_toa(); /* Sp to ascii printable string */ Sp *ato_sp(); /* Sp from ascii printable string */ frda_sps(); Sps *dup_sps(); Sp *append_sp_sps(); Sp *append_sp_spa(); Sp *rotate_Sp(); /* rotate Sp about given fixed-point */ Sp *hshear_Sp(); /* horiz-shear Sp about given fixed-point */ Edge *alloc_edge(); free_edge(); char *edge_toa(); /* Edge to ascii printable string */ Edge *ato_edge(); /* Edge from ascii printable string */ Bbx *alloc_bbx(); Bbx *append_bbx(); Bbxs *dup_bbxs(); char *bbx_toa(); /* Bbx to ascii printable string */ Bbx *ato_bbx(); /* Bbx from ascii printable string */ Bbx *translate_bbx(); boolean bbx_inside_most(); /* Is Bbx 1 mostly inside Bbx 2? */ Bbx *expand_bbx(); 0707070035351137111006640007620000050000010261300476773366600000700000016417Path.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* Path.c - Path functions */ #include <errno.h> #include <stdio.h> #include <string.h> #define FILE_TREE_INCL 1 #include "CPU.h" #include "Path.h" #define dbg_FTW (0) /* Return full path string in Path *pp, starting at level `sl'; if the level is too deep or the name at level `sl' is null, return null string. */ char *path_toa(pp,sl) Path *pp; int sl; /* starting level: 0 is first */ { int len,lvl; static char s[MAX_PATH_DEPTH*(32)]; s[0] = '\0'; if( sl<=pp->level && pp->name[sl]!=NULL && pp->name[sl][0]!='\0' ) { for(lvl=sl; lvl<=pp->level; lvl++) { strcat(s,pp->name[lvl]); strcat(s,"/"); }; }; if((len=strlen(s))>0) s[len-1] = '\0'; return(s); } /* no. slashes in a name */ int slashes(n) char *n; { register int res; register char *c; res=0; c=n; while(*c!='\0') { if(*c=='/') res++; c++; }; return(res); } /* basename */ char *bname(n) char *n; { register char *res,*c; res=n-1; c=n; while(*c!='\0') { if(*c=='/') res=c; c++; }; return(res+1); } #if CPU==VAX || CPU==CRAY int process_file_tree_node(n,s,code,S) char *n; struct stat *s; int code; struct FTW *S; /* Uses global `path_process' structure */ { char *out_n; int persist; struct stat sbuf; switch(code) { case FTW_F: if(dbg_FTW)err("visit file %s %s %d",n,n+(S->base),S->level); if(S->level>0) { if(path_process.path.name[S->level]!=NULL) free(path_process.path.name[S->level]); path_process.path.name[S->level]=strdup(n+(S->base)); }; path_process.path.level = S->level; out_n = strdup(path_toa(&path_process.path,0)); if(dbg_FTW)err("file: %s ==> %s",n,out_n); (*path_process.process)(n,out_n,path_process.arg); if(out_n!=NULL) free(out_n); break; case FTW_SL: if(dbg_FTW)err("visit link %s %s %d",n,n+(S->base),S->level); S->quit = FTW_FOLLOW; /* follow symbolic link */ break; case FTW_D: /* pre-visit of directory */ if(dbg_FTW)err("visit dir %s %s %d",n,n+(S->base),S->level); if(S->level>0) { if(path_process.path.name[S->level]!=NULL) free(path_process.path.name[S->level]); path_process.path.name[S->level]=strdup(n+(S->base)); }; path_process.path.level = S->level; out_n = path_toa(&path_process.path,0); if(dbg_FTW)err("dir: %s --> %s",n,out_n); if(out_n[0]=='\0') /* no output name */ break; /* ensure directory named out_n exists */ if(stat(out_n,&sbuf)==0) { /* file exists */ if(!(sbuf.st_mode&S_IFDIR)) { /* not a directory - try to remove */ if(unlink(out_n)==0) { if(mkdir(out_n,0777)!=0) { /* irrecoverable mkdir */ abort("can't mkdir %s", out_n); }; } else { /* irrecoverable unlink */ abort("can't unlink %s",out_n); }; }; } else if(errno==ENOENT) { /* file doesn't exist */ if(mkdir(out_n,0777)!=0) { /* irrecoverable mkdir */ abort("can't mkdir %s",out_n); }; } else { /* irrecoverable stat */ abort("can't stat %s",out_n); }; break; case FTW_DP: /* post-visit of directory: ignore it*/ break; case FTW_DNR: err("can't read dir %s (FTW_DNR) - ignore it",n); break; case FTW_NS: err("can't stat %s (FTW_NS) - ignore it",n); break; case FTW_NSL: if(0) /* happens if file is missing */ err("can't stat symbolic link %s (FTW_NSL) - ignore it",n); break; default: err("unexpected FTW code %d - ignore it",code); break; }; return(0); } #else #if CPU==MIPS int process_file_tree_node(n,s,code) char *n; /* name of the object */ struct stat *s; /* info. about object */ int code; /* Uses global `path_process' structure */ #define lvl path_process.path.level { char *out_n; int persist; struct stat sbuf; char *bn; lvl = slashes(n) - path_process.sl0; bn = bname(n); switch(code) { case FTW_F: if(dbg_FTW) err("visit file %s, bn %s, lvl %d",n,bn,lvl); if(lvl>0) { if(path_process.path.name[lvl]!=NULL) free(path_process.path.name[lvl]); path_process.path.name[lvl]=strdup(bn); }; out_n = strdup(path_toa(&path_process.path,0)); if(dbg_FTW)err("file: %s ==> %s",n,out_n); (*path_process.process)(n,out_n,path_process.arg); if(out_n!=NULL) free(out_n); break; case FTW_D: /* pre-visit of directory */ if(dbg_FTW) err("visit dir %s, bn %s, lvl %d",n,bn,lvl); if(lvl>0) { if(path_process.path.name[lvl]!=NULL) free(path_process.path.name[lvl]); path_process.path.name[lvl]=strdup(bn); }; out_n = path_toa(&path_process.path,0); if(dbg_FTW)err("dir: %s --> %s",n,out_n); if(out_n[0]=='\0') /* no output name */ break; /* ensure directory named out_n exists */ if(stat(out_n,&sbuf)==0) { /* file exists */ if(!(sbuf.st_mode&S_IFDIR)) { /* not a directory - try to remove */ if(unlink(out_n)==0) { if(mkdir(out_n,0777)!=0) { /* irrecoverable mkdir */ abort("can't mkdir %s", out_n); }; } else { /* irrecoverable unlink */ abort("can't unlink %s",out_n); }; }; } else if(errno==ENOENT) { /* file doesn't exist */ if(mkdir(out_n,0777)!=0) { /* irrecoverable mkdir */ abort("can't mkdir %s",out_n); }; } else { /* irrecoverable stat */ abort("can't stat %s",out_n); }; break; case FTW_DNR: err("can't read dir %s (FTW_DNR) - ignore it",n); break; case FTW_NS: err("can't stat %s (FTW_NS) - ignore it",n); break; default: err("unexpected FTW code %d - ignore it",code); break; }; return(0); } #endif #endif /* Process every leaf file (non-directory) in the file-tree rooted at `in_ftn'. If `in_ftn' is itself a leaf, then only it is processed. If it is a directory, then a corresponding file-tree is built, rooted at `out_ftn', and paths to its leaves created by `mkdir's as required; for each pair of corresponding leaf filenames, `process' is called. The filenames have not yet been opened. If `out_ftn' is the empty string, then no output file-tree will be generated and the corresponding output filenames will all be null. If `in_ftn' is the empty string, then `process' is called only once, with the input filename empty. Pass 'arg' to 'process' as third argument. */ process_file_trees(process,in_ftn,out_ftn,arg) VOID (*process)(); char *in_ftn; /* may be empty */ char *out_ftn; /* may be empty */ VOID *arg; /* passed to '(*process)()' as 3rd argument */ /* Uses global `path_process' structure */ { int level; if(in_ftn[0]=='\0') (*process)(in_ftn,out_ftn,arg); else { if(dbg_FTW) err("process_file_trees(%s,%s)",in_ftn,out_ftn); path_process.path.level = 0; path_process.path.name[0] = out_ftn; path_process.sl0 = slashes(in_ftn); for(level=1; level<MAX_PATH_DEPTH; level++) path_process.path.name[level] = NULL; path_process.process = process; path_process.arg = arg; if(ftw(in_ftn,process_file_tree_node,MAX_PATH_DEPTH)<0) err("ftw error: errno %d",errno); }; } 0707070035351137121006640007620000050000010261310476773366700000700000001611Path.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* Path.h - Path names */ #define MAX_PATH_DEPTH (16) /* maximum expected names in path */ typedef struct Path { int level; /* current level */ char *name[MAX_PATH_DEPTH]; /* name[0] is output root name; the rest are basenames (both input and output) */ } Path; typedef struct Path_process { int sl0; /* no. slashes in input root name */ Path path; VOID (*process)(); VOID *arg; /* passed as 3rd arg to (*process)() */ } Path_process; Path_process path_process; /* controls file-tree processing */ char *path_toa(); /* see Path.c */ 0707070035351137131006640007620000050000010261330476773367000000700000404335Text.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* Text.c - functions for Document-image file ("dim" file) handling General Introduction -------------------- Dim files describe a document as a collection of records of these types: Page full page Block block (often a column) of text Txtln line of text Word word Char character, isolated symbol, `graph' Interp interpretation of a character (result of classification) Sfeats scalar features of a character Shapes local shape features of a character Bfeats binary indicator features of a character Blob connected component (maximal subset of 8-connected black pixels) Lag line-adjacency graph of runs Run horizontal run of black pixels Pixel bilevel (black/white) picture element (symbols are expected to be black against a white background); usually square They may be organized hierarchically -- a Page may own : Blocks, Txtlns, Words, Chars, & Blobs a Block may own : Blocks, Txtlns, Words, Chars, & Blobs a Txtln may own : Txtlns, Words, Chars, & Blobs a Word may own : Words, Chars & Blobs a Char may own : Blobs, Interps, Sfeats, Shapes, & Bfeats a Blob may own : Runs (variously represented) a Run owns : black Pixels Note that the hierarchy is strict except that Blocks, Txtlns, & Words may own records of their own type. This serves several functions: -- a Block may own other Blocks, conventionally nested within it, to represent a physical or logical page layout decomposition; -- a Txtln may have alternative interpretations & segmentations into Words; -- a Word may have alternative segmentations into Chars. For each record type R, there should exist these data-structures: R struct Init_R #define'd initialization string empty_R an extern ``empty'' (initialized) instance of R Also there are library functions (in which _R is spelled in lower-case): R *alloc_R() allocate memory and initialize to ``empty'' free_R(R *) free memory (only of record R, not what it owns) free_R_etc(R *,ids) free R and what it owns (as specified by `ids') R *dup_R(R *) return distinct copy, with duplicated contents R *dup_R_etc(R *,ids) return distinct copy, duplicated contents & parts char *R_toa(R *) convert to printable ASCII string frdb_R(FILE *, R *) fread R (binary) from file thru pointer frdb_R_etc(",",ids) fread R (binary) and what it owns (as specified) fwrb_R(FILE *, R *) fwrite R (binary) to file thru pointer fwrb_R_etc(",",ids) fwrite R (binary) and what it owns (as specified) (some of these may be unimplemented if they haven't yet been needed) I/O conventions: -- frd?_... return one of: 1 normal & successful 0 EOF <0 I/O errors Quite a few functions don't obey this rule yet. Many intermediate fns that don't directly perform I/O don't bother passing back status from fns they call. Those that perform I/O directly often complain to stderr and exit(2). The situation is fairly chaotic, and has already caused bugs. Generally: -- An `etc' argument is a set of Ident bits specifying a set of record types; it is passed along unchanged in calls to other _etc functions. -- `fwrb_R_etc' fns obey the `etc' instructions carefully, writing only those record types specified -- `frdb_R_etc' fns mostly ignore `etc', blindly reading everything they see (since they aren't clever enough to skip past yet); however, the Blob-reading fns look at the Runs_?? bits to select a main memory format for Runs -- `frdb_R_etc' uses alloc_Y to allocate all new Y -- `fwrb_R_etc', however, does NOT free anything: this must be done explicitly afterwards. Ownership of a set of records is implemented by two fields in the owner record: (1) a count of the number of members, and (2) either a ``set'' or a ``list'' pointer: set: to a NULL-terminated array of pointers to records list: to the first in a singly-linked, NULL-terminated, chain sets are used for sets of Blocks, Txtlns, Words, Chars, and Blobs lists are used for Interpl, and for Blobs owned by Chars, since they tend to be fewer Blobs and Runs are treated more elaborately than other records. Blobs are collected in lists when owned by Chars, but in sets otherwise -- the motivation was that the Char lists are usually very short, and the malloc overhead of creating them might be unpleasant -- however, maintaining two kinds of sets has caused other headaches; it might be good someday to abolish lists in favor of sets throughout. Runs can often be compressed to about half the usual size by using char fields instead of shorts, and this is done automatically when writing to files. There is both a set and a list form of Run. The peripheral file format is: - deliberately decoupled from the internal (main memory) format: i.e. the main memory structs can be (and are) changed frequently for purposes of experimentation without forcing frequent reformatting of the (by now large) backlog of archived files (particularly the character image databases). To bring such files up-to-date, the program `renew' should be used: it must be edited to reflect changes since the last overhaul of the file format. - designed to be ``scannable'': that is, one can skip rapidly from record to record (using the Ident headers) without minding the hierarchy. This is most useful for the graphics editor "met", where it permits quick response at the outset. It is also used widely in the off-line training programs, where main memory is at a premium. - machine-independent: floating-point representations are forced to fixed point and scaled to integer; all integer representations are written as a sequence of bytes in a fixed order, via putc()/getc(). fwrite()/fread() are never used for binary I/O. This seems to work on virtually all UNIX machines. See fioi.h. CCITT Group 4 encodings have been implemented and are available as a peripheral file format for Blobs. They offer a large compression factor (x8) over RunF and RunFS records, and the CPU overhead is not excessive. It turns out that the connectivity information represented explicitly in Run records but lost in ccitt-g4 can be recovered in linear time and space (see fix_lag()); in practice the extra recovery time is negligible and the extra space is 0. This is possible because Blobs are known to be connected: if not, then (I suspect that) superlinear time is required in general to recover the lag. */ #include <stdio.h> #include <math.h> #define LIBC_INCL 1 #include "CPU.h" #include "stdocr.h" #include "rle.h" #include "Text.h" #include "bitio.h" #include "CCITT.h" long fseek(),lseek(); #define dbg_fwrb T /* failsafe consistency checking */ #define dbg_frdb T /* failsafe consistency checking */ #define dbg_fwrb_runs F /* announce no. bytes used to write each Blob's Runs */ #define dbg_frdb_runs F /* announce no. bytes used to write each Blob's Runs */ /* return ASCII string describing ident bits */ char *ident_toa(id) Ident id; { static char s[80]; s[0]='\0'; if((id&IsALL)==IsALL) strcat(s,"ALL"); else { if(id&IsPage) { strcat(s,"PG"); if(id&(Page_label)) { strcat(s,"."); if(id&Page_label) strcat(s,"l"); }; } if(id&IsBlock) { strcat(s,"BK"); if(id&(Block_wst|Block_label)) { strcat(s,"."); if(id&Block_wst) strcat(s,"w"); if(id&Block_label) strcat(s,"l"); }; }; if(id&IsTxtln) { strcat(s,"TL"); if(id&(Txtln_basl|Txtln_size|Txtln_label)) { strcat(s,"."); if(id&Txtln_basl) strcat(s,"b"); if(id&Txtln_size) strcat(s,"s"); if(id&Txtln_label) strcat(s,"l"); }; }; if(id&IsWord) { strcat(s,"WD"); if(id&(Word_spelled|Word_label)) { strcat(s,"."); if(id&Word_spelled) strcat(s,"s"); if(id&Word_label) strcat(s,"l"); }; }; if(id&IsWordInterp) { strcat(s,"WI"); if(id&(Word_spelled|Word_numeric|Word_initcap|Word_allcaps|Word_hyphens|Word_slashes|Word_termhyp|Word_endsent)) { strcat(s,"."); if(id&Word_spelled) strcat(s,"s"); if(id&Word_numeric) strcat(s,"n"); if(id&Word_initcap) strcat(s,"i"); if(id&Word_allcaps) strcat(s,"a"); if(id&Word_hyphens) strcat(s,"-"); if(id&Word_slashes) strcat(s,"/"); if(id&Word_termhyp) strcat(s,"h"); if(id&Word_endsent) strcat(s,"."); }; }; if(id&IsChar) { strcat(s,"CH"); if(id&(Char_spelled|Char_confused|Char_termhyp|Char_omit|Char_label|Char_ranparms)) { strcat(s,"."); if(id&Char_spelled) strcat(s,"s"); if(id&Char_confused) strcat(s,"c"); if(id&Char_termhyp) strcat(s,"h"); if(id&Char_omit) strcat(s,"o"); if(id&Char_label) strcat(s,"l"); if(id&Char_ranparms) strcat(s,"r"); if(id&Char_split) strcat(s,"S"); if(id&Char_merged) strcat(s,"M"); }; }; if(id&IsInterp) { strcat(s,"IN"); if(id&Interp_spelled) { strcat(s,".s"); }; }; if(id&IsBlob) { strcat(s,"BB"); if( id&(Blob_lm|Blob_rm|Blob_tm|Blob_bm |Blob_chopt|Blob_chopb|Blob_chopl|Blob_chopr |Blob_small|Blob_local) ) { strcat(s,"."); if(id&(Blob_tm|Blob_bm|Blob_lm|Blob_rm)) { if(id&Blob_lm) strcat(s,"l"); if(id&Blob_rm) strcat(s,"r"); if(id&Blob_tm) strcat(s,"t"); if(id&Blob_bm) strcat(s,"b"); }; if(id&(Blob_chopt|Blob_chopb|Blob_chopl|Blob_chopr)) { if(id&Blob_chopl) strcat(s,"L"); if(id&Blob_chopr) strcat(s,"R"); if(id&Blob_chopt) strcat(s,"T"); if(id&Blob_chopb) strcat(s,"B"); }; if(id&Blob_small) strcat(s,"s"); if(id&Blob_local) strcat(s,"o"); }; } }; return(s); } /* convert a conventional character-code to a record type */ Ident cto_ident(c) char c; { Ident type; switch(c) { case 'b': type=IsBlob; break; case 'B': case 'k': type=IsBlock; break; case 'c': type=IsChar; break; case 'i': type=IsInterp; break; case 'p': case 'P': type=IsPage; break; case 'r': type=IsRun; break; case 't': case 'l': type=IsTxtln; break; case 'w': type=IsWord; break; case 'y': type=IsBdy; break; }; return(type); } Ident cto_flag(c,type) char c; Ident type; { Ident flag; flag = IsNONE; if(type&IsPage) { switch(c) { case 'l': flag |= Page_label; break; }; } else if(type&IsBlock) { switch(c) { case 'w': flag |= Block_wst; break; case 'l': flag |= Block_label; break; }; } else if(type&IsTxtln) { switch(c) { case 'b': flag |= Txtln_basl; break; case 's': flag |= Txtln_size; break; case 'l': flag |= Txtln_label; break; }; } else if(type&IsWord) { switch(c) { case 's': flag |= Word_spelled; break; case 'n': flag |= Word_numeric; break; case 'i': flag |= Word_initcap; break; case 'a': flag |= Word_allcaps; break; case '-': flag |= Word_hyphens; break; case '/': flag |= Word_slashes; break; case 'h': flag |= Word_termhyp; break; case '.': flag |= Word_endsent; break; case 'l': flag |= Word_label; break; }; } else if(type&IsChar) { switch(c) { case 's': flag |= Char_spelled; break; case 'c': flag |= Char_confused; break; case 'h': flag |= Char_termhyp; break; case 'o': flag |= Char_omit; break; case 'l': flag |= Char_label; break; case 'r': flag |= Char_ranparms; break; case 'S': flag |= Char_split; break; case 'M': flag |= Char_merged; break; }; } else if(type&IsBlob) { switch(c) { case 'B': flag |= Blob_chopb; break; case 'L': flag |= Blob_chopl; break; case 'R': flag |= Blob_chopr; break; case 'T': flag |= Blob_chopt; break; case 'b': flag |= Blob_bm; break; case 'l': flag |= Blob_lm; break; case 'o': flag |= Blob_local; break; case 'r': flag |= Blob_rm; break; case 's': flag |= Blob_small; break; case 't': flag |= Blob_tm; break; }; } else if(type&IsInterp) { switch(c) { case 's': flag |= Interp_spelled; break; }; }; return(flag); } #if FRDI /* read only the Ident of the next record; if EOF, return 0 */ Ident frdb_ident(fp) FILE *fp; { Ident ident; ident = frdi_Ident(fp); #if dbg_frdb_toa err("frdb_ident: %s",ident_toa(ident)); #endif if(feof(fp)) return(0); else return(ident); } #else /* read only the Ident of the next record; return 0 iff EOF */ Ident frdb_ident(fp) FILE *fp; { Ident ident; int stat; if((stat=fread(&ident,sizeof(Ident),1,fp))!=1) { if(stat==0) return(0); else abort("frdb_ident: can't fread, status %d",stat); }; if( Readvax ) ident = swapintin(ident); #if dbg_frdb_toa err("frdb_ident: %s",ident_toa(ident)); #endif if(feof(fp)) return(0); else return(ident); } #endif #if FRDI /* read label into malloc space */ char *frdb_label(f) FILE *f; { register char *res; res=frdi_str(f); #if dbg_frdb_toa err("frdb_label: \"%s\"",res); #endif return(res); } #else /* read label into malloc space */ char *frdb_label(fp) FILE *fp; { static char s[MAX_LABEL_LEN]; char *c,*ce,*l; int ch; ce=(c=s)+MAX_LABEL_LEN-1; while((c<ce)&&((ch=getc(fp))!=EOF)&&(ch!='\0')) *(c++) = ch; *c='\0'; if(c==ce) { /* label is truncated; find end of it */ while(((ch=getc(fp))!=EOF)&&(ch!='\0')) ; }; if((l=strdup(s))==NULL) abort("frdb_label: can't dup char *s[%d]",strlen(s)); #if dbg_frdb_toa err("frdb_label: \"%s\"",l); #endif return(l); } #endif /* skip label */ fskb_label(fp) FILE *fp; { int ch; while(((ch=getc(fp))!=EOF)&&(ch!='\0')&&(ch!='\n')) ; if(ch==EOF) return(0); else return(1); } /* Skip the REST of this record (the Ident is assumed to have been read), and return the Ident of the next record in the file; else return: 0 EOF -1 I/O error -2 not one of: Page, Block, Txtln, Char, Interp */ char *pp_toa(ppp) Pp *ppp; { static char s[30]; sprintf(s,"(%0.2f,%0.2f)",ppp->x,ppp->y); return(s); } /* return integer string in the range 00-99 */ char *merit_toa(m) Merit m; { static char s[3]; int im; im = (int)(m * 100); if(im>99) im=99; else if(im<0) im=0; if(im<10) { s[0] = '0'; sprintf(s+1,"%d",im); } else sprintf(s,"%2d",im); s[3] = '\0'; return(s); } char *pts_toa(p) Pts p; { static char s[10]; sprintf(s,"%g",((int)((p*10.0)+0.5))/10.0); return(s); } Bdy *alloc_bdy() { Bdy *p; if((p=(Bdy *)malloc(sizeof(Bdy)))==NULL) abort("alloc_bdy: can't malloc"); else { *p = empty_Bdy; return(p); }; } Bdys *alloc_bdys() { Bdys *p; if((p=(Bdys *)malloc(sizeof(Bdys)))==NULL) abort("alloc_bdys: can't malloc"); else { *p = empty_Bdys; return(p); }; } char *bdyedge_toa(bep) BdyEdge *bep; { static char s[80]; char aps[20]; strcpy(aps,sp_toa(bep->ap)); sprintf(s,"%s,%s p%d c%s a%0.2f", aps, sp_toa(bep->bp), bep->per, pp_toa(&(bep->ctr)), (bep->ang/PI)*180.0); return(s); } free_bdyedges(besp) BdyEdges *besp; { register BdyEdge *bep,**bepp; if(besp->pa!=NULL) { if(besp->mny>0) { for(bep= *(bepp=besp->pa); bep!=NULL; bep= *(++bepp)) free(bep); }; free(besp->pa); }; *besp = empty_BdyEdges; } /* Skip past the "TYPE=document-image\n\n" (or "TYPE=dim\n\n") ASCII header from file *fp, read and check the Doc record, and, if all's well, return 1. If an immediate EOF, return 0. If not EOF, and no "TYPE=" header, leave fp as it was, and return -1. If a malformed "TYPE=" header, leave fp as it was, and return -2. */ int skip_type(fp) FILE *fp; { int ich,stat; long seek; #define MAX_TYPE_HDR_LEN (100) char type_eq[MAX_TYPE_HDR_LEN+1]; register char *pcp,*ccp,*ecp; int version; seek = ftell(fp); /* test for EOF */ if(feof(fp) || (ich=getc(fp))==EOF) /* premature EOF*/ return(0); if((type_eq[0]=ich)!='T') { /* no "TYPE=" header */ ungetc(ich,fp); /* fast, guaranteed push-back */ return(-1); }; /* try to read the rest of "TYPE=" */ for(ecp=(ccp=type_eq+1)+4; ccp<ecp; ccp++) { if(feof(fp) || (ich=getc(fp))==EOF) { /* no "TYPE=" header */ fseek(fp,seek,0); return(-1); } else *ccp=ich; } *ccp='\0'; /* check for "TYPE=" so far */ if(strcmp(type_eq,"TYPE=")==0) { /* read rest of ASCII header */ ccp=(pcp=type_eq+3)+1; ecp=type_eq+MAX_TYPE_HDR_LEN; do { ccp++; pcp++; if((ich=getc(fp))==EOF) { /* malformed "TYPE=" header */ fseek(fp,seek,0); return(-2); } else *ccp=ich; } while(ccp<ecp && (*ccp!='\n'||*pcp!='\n')); if(ccp==ecp) { /* malformed "TYPE=" header */ fseek(fp,seek,0); return(-2); }; *pcp='\0'; /* check that it is "TYPE=document-image\n\n" or "TYPE=dim\n\n" */ if(strcmp(type_eq,"TYPE=document-image")!=0 && strcmp(type_eq,"TYPE=dim")!=0) { /* malformed "TYPE=" header */ fseek(fp,seek,0); return(-2); }; #if dbg_frdb_toa err("skip_type: \"%s\\n\\n\"",type_eq); #endif return(1); /* normal and successful TYPE= header */ } else { /* no "TYPE=" header */ fseek(fp,seek,0); return(-1); }; } Doc *alloc_doc() { Doc *p; if((p=(Doc *)malloc(sizeof(Doc)))==NULL) abort("alloc_doc: can't malloc"); else { *p = empty_Doc; return(p); }; } char *doc_toa(p) Doc *p; { static char s[80]; sprintf(s,"Doc v%d p%d l%s", p->version, p->ps.mny, (p->l!=NULL)? p->l: ""); return(s); } #if FWRI /* write the given doc (record only) */ fwrb_doc(f,p) FILE *f; Doc *p; { int stat; fwri_uint1(f,p->version); fwri_uint2(f,p->ps.mny); #if dbg_fwrb_toa err("fwrb_doc: %s",doc_toa(p)); #endif if(p->l!=NULL) { fwri_ch(f,'l'); fwrb_label(f,p->l); } else fwri_ch(f,'\0'); } #else fwrb_doc(f,p) FILE *f; Doc *p; {} #endif #if FRDI /* read a Doc record (only) - it must be next in the file; don't immediately read its parts; return 0 iff immediate EOF. Check for correct version no: if fails, abort. */ int frdb_doc(f,p) FILE *f; Doc *p; { char qlabel; *p = empty_Doc; if(feof(f)) return(0); p->version=frdi_uint1(f); p->ps.mny=frdi_uint2(f); if((qlabel=frdi_ch(f))=='l') p->l=frdb_label(f); #if dbg_frdb_toa err("frdb_doc: %s",doc_toa(p)); #endif if(ferror(f)) return(-errno); else return(1); } #else int frdb_doc(f,p) FILE *f; Doc *p; { return(1); } #endif #if FWRI /* Write the initial Doc record */ put_doc(f) FILE *f; { Doc doc; doc = empty_Doc; doc.version = DIM_VERSION; doc.ps.mny = 1; fwrb_doc(f,&doc); } #else put_doc(f) FILE *f; {} #endif #if FRDI /* read, check, discard, and skip past the Doc record */ int skip_doc(f) FILE *f; { Doc doc; frdb_doc(f,&doc); if(doc.version!=DIM_VERSION) abort("skip_doc: version %d != DIM_VERSION %d", doc.version,DIM_VERSION); if(doc.l!=NULL) free(doc.l); return(1); } #else int skip_doc(f) FILE *f; { Doc doc; return(1); } #endif Page *alloc_page() { Page *p; if((p=(Page *)malloc(sizeof(Page)))==NULL) abort("alloc_page: can't malloc"); alloc_census(Page,1); *p = empty_Page; return(p); } char *page_toa(p) Page *p; { static char s[80]; sprintf(s,"%s bx%s res%d,%d sk%0.2f,sh%0.2f bk%d l%d c%d b%d", ident_toa(p->ident), bbx_toa(&(p->bx)), p->res_x,p->res_y, (p->skew/PI)*180.0, (p->shear/PI)*180.0, p->bks.mny,p->ls.mny,p->cs.mny,p->bs.mny, (p->l!=NULL)? p->l: ""); return(s); } #if FWRI /* write the given page (record only) */ fwrb_page(f,p) FILE *f; Page *p; { int stat; #if dbg_fwrb if(f==stdout||f==stderr||ftell(f)<=0L) { fprintf(f,"TYPE=dim\n\n"); #if dbg_fwrb_toa err("fwrb_page: \"TYPE=dim\\n\\n\""); #endif put_doc(f); }; if((!(p->ident&IsPage))||(p->ident&(IsALL&(~IsPage)))) err("fwrb_page: %s",page_toa(p)); if(p->ident&Page_label && p->l==NULL) { err("fwrb_page: Page_label set but .l==NULL"); p->ident &= ~Page_label; }; #endif fwri_Ident(f,p->ident); fwri_Bbx(f,&(p->bx)); fwri_int2(f,p->res_x); fwri_int2(f,p->res_y); fwri_Radians(f,p->skew); fwri_Radians(f,p->shear); fwri_uint2(f,p->bks.mny); fwri_uint2(f,p->ls.mny); fwri_uint2(f,p->ws.mny); fwri_uint2(f,p->cs.mny); fwri_uint3(f,p->bs.mny); #if dbg_fwrb_toa err("fwrb_page: %s",page_toa(p)); #endif if(p->ident&Page_label) fwrb_label(f,p->l); } #else /* write the given page (record only) */ fwrb_page(fp,pp) FILE *fp; Page *pp; { PageF pf; int stat; #if dbg_fwrb if((!(pp->ident&IsPage))||(pp->ident&(IsALL&(~IsPage)))) err("fwrb_page: %s",page_toa(pp)); #endif memset(&pf,'\0',sizeof(pf)); pf.ident = pp->ident; pf.res_x=pp->res_x; pf.res_y=pp->res_y; pf.bx=pp->bx; pf.skew=pp->skew; pf.shear=pp->shear; pf.bkmny=pp->bks.mny; pf.lmny=pp->ls.mny; pf.wmny=pp->ws.mny; pf.cmny=pp->cs.mny; pf.bmny=pp->bs.mny; if(fp==stdout||fp==stderr||ftell(fp)<=0L) { fprintf(fp,"TYPE=document-image\n\n"); #if dbg_fwrb_toa err("fwrb_page: \"TYPE=document-image\\n\\n\""); #endif }; if((stat=fwrite(&pf,sizeof(PageF),1,fp))!=1) abort("fwrb_page: can't fwrite - status %d",stat); #if dbg_fwrb_toa err("fwrb_page: %s",page_toa(pp)); #endif if(pf.ident&Page_label) fwrb_label(fp,pp->l); } #endif /* write a page and its specified parts */ fwrb_page_etc(fp,pp,etc) FILE *fp; Page *pp; Ident etc; { static Ident parts = (IsBlock|IsTxtln|IsWord|IsChar|IsBlob); Page pg; if((etc&parts)!=parts) /* write selected parts */ { pg = *pp; if(!(etc&IsBlock)) pg.bks.mny=0; if(!(etc&IsTxtln)) pg.ls.mny=0; if(!(etc&IsWord)) pg.ws.mny=0; if(!(etc&IsChar)) pg.cs.mny=0; if(!(etc&IsBlob)) pg.bs.mny=0; pp = &pg; /* write modified record */ }; fwrb_page(fp,pp); fwrb_blocks_etc(fp,pp->bks,etc); fwrb_txtlns_etc(fp,pp->ls,etc); fwrb_words_etc(fp,pp->ws,etc); fwrb_chars_etc(fp,pp->cs,etc); fwrb_blobs_etc(fp,pp->bs,etc); } /* write a page and its specified parts, ASCII (INCOMPLETE) */ fwra_page_etc(fp,pp,etc) FILE *fp; Page *pp; Ident etc; { static Ident parts = (IsBlock|IsTxtln|IsWord|IsChar|IsBlob); Page pg; if((etc&parts)!=parts) /* write selected parts */ { pg = *pp; if(!(etc&IsBlock)) pg.bks.mny=0; if(!(etc&IsTxtln)) pg.ls.mny=0; if(!(etc&IsWord)) pg.ws.mny=0; if(!(etc&IsChar)) pg.cs.mny=0; if(!(etc&IsBlob)) pg.bs.mny=0; pp = &pg; /* write modified record */ }; if(etc&IsPage) fwrb_page(fp,pp); fwrb_blocks_etc(fp,pp->bks,etc); fwrb_txtlns_etc(fp,pp->ls,etc); fwrb_words_etc(fp,pp->ws,etc); fwrb_chars_etc(fp,pp->cs,etc); fwrb_blobs_etc(fp,pp->bs,etc); } #if FRDI /* read a Page record (only) - it must be next in the file; don't immediately read its parts; return 0 iff immediate EOF */ int frdb_page(f,p) FILE *f; Page *p; { char *pfc; /* for debugging */ int stat; switch(skip_type(f)) { case 1: /* "TYPE=" header */ skip_doc(f); break; case 0: /* immediate EOF */ return(0); break; case -1: /* no "TYPE=" header */ break; case -2: /* garbled "TYPE=" header */ abort("frdb_page: garbled \"TYPE=\" header"); break; }; *p = empty_Page; if(feof(f)) return(0); p->ident=frdi_Ident(f); frdi_Bbx(f,&(p->bx)); p->res_x=frdi_int2(f); p->res_y=frdi_int2(f); p->skew=frdi_Radians(f); p->shear=frdi_Radians(f); p->bks.mny=frdi_uint2(f); p->ls.mny=frdi_uint2(f); p->ws.mny=frdi_uint2(f); p->cs.mny=frdi_uint2(f); p->bs.mny=frdi_uint3(f); #if dbg_frdb if((!(p->ident&IsPage))||(p->ident&(IsALL&(~IsPage)))) err("frdb_page: %s",page_toa(p)); #endif #if dbg_frdb_toa err("frdb_page: %s",page_toa(p)); #endif if(p->ident&Page_label) p->l = frdb_label(f); if(ferror(f)) return(-errno); else return(1); } #else /* read a Page record (only) - it must be next in the file; don't immediately read its parts; return T iff not early EOF */ int frdb_page(fp,pp) FILE *fp; Page *pp; { PageF pf; char *pfc; /* for debugging */ int stat; if((stat=skip_type(fp))!=1 /* "TYPE=" header */ && stat!=-1 /* no "TYPE=" header */ ) { /* premature EOF or error */ return(stat); }; if((stat=fread(&pf,sizeof(PageF),1,fp))!=1) /* premature EOF*/ return(stat); pfc = (char *)&pf; *pp = empty_Page; pp->ident=pf.ident; pp->res_x=pf.res_x; pp->res_y=pf.res_y; pp->bx=pf.bx; pp->skew=pf.skew; pp->shear=pf.shear; pp->bks.mny = pf.bkmny; pp->bks.bpa=NULL; pp->ls.mny = pf.lmny; pp->ls.lpa=NULL; pp->ws.mny = pf.wmny; pp->ws.wpa=NULL; pp->cs.mny = pf.cmny; pp->cs.cpa=NULL; pp->bs.mny = pf.bmny; pp->bs.bpa=NULL; #if dbg_frdb_toa err("frdb_page: %s",page_toa(pp)); #endif if(pp->ident&Page_label) pp->l = frdb_label(fp); #if dbg_frdb if((!(pp->ident&IsPage))||(pp->ident&(IsALL&(~IsPage)))) err("frdb_page: %s",page_toa(pp)); #endif return(stat); } #endif /* Read a page and selected parts */ int frdb_page_etc(fp,pp,etc) FILE *fp; Page *pp; Ident etc; { int stat; if((etc&IsALL)==IsALL) { long here; /* In order to minimize malloc time to read an often huge file, malloc and then free storage roughly equal to what's needed */ if( /* DEFEATED */ F && (here=ftell(fp))>=0 && fseek(fp,0,2)>=0 ) { /* *fp is connected to a file, not a pipe */ free(malloc(ftell(fp))); fseek(fp,here,0); }; }; if((stat=frdb_page(fp,pp))!=1) return(stat); if(etc&IsBlock && pp->bks.mny>0) frdb_blocks_etc(fp,&(pp->bks),etc); else pp->bks = empty_Blocks; if(etc&IsTxtln && pp->ls.mny>0) frdb_txtlns_etc(fp,&(pp->ls),etc); else pp->ls = empty_Txtlns; if(etc&IsWord && pp->ws.mny>0) frdb_words_etc(fp,&(pp->ws),etc); else pp->ws = empty_Words; if(etc&IsChar && pp->cs.mny>0) frdb_chars_etc(fp,&(pp->cs),etc); else pp->cs = empty_Chars; if(etc&IsBlob && pp->bs.mny>0) frdb_blobs_etc(fp,&(pp->bs),etc); else pp->bs = empty_Blobs; return(1/*normal return*/); } free_page_etc(p,etc) Page *p; Ident etc; { free_blocks_etc(&(p->bks),etc); free_txtlns_etc(&(p->ls),etc); free_words_etc(&(p->ws),etc); free_chars_etc(&(p->cs),etc); free_blobs_etc(&(p->bs),etc); if(p->ident&Page_label && p->l!=NULL) { free(p->l); p->l=NULL; p->ident &= ~Page_label; }; if(etc&IsPage) { free(p); free_census(Page,1); }; } /* return a pointer to a distinct and duplicate copy of record Page *p, created out of malloc space */ Page *dup_page(p) Page *p; { Page *dup; dup=alloc_page(); *dup = *p; return(dup); } /* Return a pointer to a distinct and duplicate copy of Page *p, and its parts as specified by `etc', created out of malloc space. */ Page *dup_page_etc(p,etc) Page *p; Ident etc; { Page *dup; dup = dup_page(p); if(etc&IsBlob&&dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(p->bs),etc); else dup->bs = empty_Blobs; if(etc&IsChar&&dup->cs.mny>0) dup->cs = *dup_chars_etc(&(p->cs),etc); else dup->cs = empty_Chars; if(etc&IsWord&&dup->ws.mny>0) dup->ws = *dup_words_etc(&(p->ws),etc); else dup->ws = empty_Words; if(etc&IsTxtln&&dup->ls.mny>0) dup->ls = *dup_txtlns_etc(&(p->ls),etc); else dup->ls = empty_Txtlns; if(etc&IsBlock&&dup->bks.mny>0) dup->bks = *dup_blocks_etc(&(p->bks),etc); else dup->bks = empty_Blocks; return(dup); } Block *alloc_block() { Block *p; if((p=(Block *)malloc(sizeof(Block)))==NULL) abort("alloc_block: can't malloc"); alloc_census(Block,1); *p = empty_Block; return(p); } char *block_toa(p) Block *p; { static char s[80]; sprintf(s,"%s bx%s sk%0.2f,sh%0.2f wst%0.2f m%s bk%d l%d w%d c%d b%d", ident_toa(p->ident), bbx_toa(&(p->bx)), p->skew/DtoR, p->shear/DtoR, p->wst, merit_toa(p->m), p->bks.mny,p->ls.mny,p->ws.mny,p->cs.mny,p->bs.mny, (p->l!=NULL)? p->l: ""); return(s); } #if FWRI fwrb_block(f,p) FILE *f; Block *p; { int stat; #if dbg_fwrb if((!(p->ident&IsBlock))||(p->ident&(IsALL&(~IsBlock)))) err("fwrb_block: %s",block_toa(p)); if(p->ident&Block_label && p->l==NULL) { err("fwrb_page: Block_label set but .l==NULL"); p->ident &= ~Block_label; }; #endif fwri_Ident(f,p->ident); fwri_Bbx(f,&(p->bx)); fwri_Radians(f,p->skew); fwri_Radians(f,p->shear); fwri_Ems(f,p->wst); fwri_Merit(f,p->m); fwri_uint2(f,p->bks.mny); fwri_uint2(f,p->ls.mny); fwri_uint2(f,p->ws.mny); fwri_uint2(f,p->cs.mny); fwri_uint3(f,p->bs.mny); #if dbg_fwrb_toa err("fwrb_block: %s",block_toa(p)); #endif if(p->ident&Block_label) fwrb_label(f,p->l); } #else fwrb_block(fp,bkp) FILE *fp; Block *bkp; { BlockF bf; int stat; #if dbg_fwrb if((!(bkp->ident&IsBlock))||(bkp->ident&(IsALL&(~IsBlock)))) err("fwrb_block: %s",block_toa(bkp)); #endif memset(&bf,'\0',sizeof(bf)); bf.ident = bkp->ident; bf.bx = bkp->bx; bf.wst = bkp->wst; bf.skew = bkp->skew; bf.shear = bkp->shear; bf.lmny = bkp->ls.mny; bf.wmny = bkp->ws.mny; bf.cmny = bkp->cs.mny; bf.bmny = bkp->bs.mny; #if dbg_fwrb_toa err("fwrb_block: %s",block_toa(bkp)); #endif if((stat=fwrite(&bf,sizeof(BlockF),1,fp))!=1) abort("fwrb_block: can't fwrite - status %d",stat); } #endif fwrb_blocks_etc(fp,bks,etc) FILE *fp; Blocks bks; Ident etc; { register Block *bkp,**bkpp; if(bks.mny>0) for(bkp= *(bkpp=bks.bpa); bkp!=NULL; bkp= *(++bkpp)) fwrb_block_etc(fp,bkp,etc); } fwrb_block_etc(fp,bkp,etc) FILE *fp; Block *bkp; Ident etc; { static Ident parts = (IsTxtln|IsWord|IsChar|IsBlob); Block bk; if((etc&parts)!=parts) /* write selected parts */ { bk = *bkp; if(!(etc&IsTxtln)) bk.ls.mny=0; if(!(etc&IsWord)) bk.ws.mny=0; if(!(etc&IsChar)) bk.cs.mny=0; if(!(etc&IsBlob)) bk.bs.mny=0; bkp = &bk; /* write modified record */ }; fwrb_block(fp,bkp); fwrb_txtlns_etc(fp,bkp->ls,etc); fwrb_words_etc(fp,bkp->ws,etc); fwrb_chars_etc(fp,bkp->cs,etc); fwrb_blobs_etc(fp,bkp->bs,etc); } #if FRDI int frdb_block(f,p) FILE *f; Block *p; { *p = empty_Block; if(feof(f)) return(0); p->ident=frdi_Ident(f); frdi_Bbx(f,&(p->bx)); p->skew=frdi_Radians(f); p->shear=frdi_Radians(f); p->wst=frdi_Ems(f); p->m=frdi_Merit(f); p->bks.mny=frdi_uint2(f); p->ls.mny=frdi_uint2(f); p->ws.mny=frdi_uint2(f); p->cs.mny=frdi_uint2(f); p->bs.mny=frdi_uint3(f); #if dbg_frdb_toa err("frdb_block: %s",block_toa(p)); #endif #if dbg_frdb if((!(p->ident&IsBlock))||(p->ident&(IsALL&(~IsBlock)))) err("frdb_block: %s",block_toa(p)); #endif if(p->ident&Block_label) p->l = frdb_label(f); if(ferror(f)) return(-errno); else return(1); } #else int frdb_block(fp,bkp) FILE *fp; Block *bkp; { BlockF bf; int stat; if((stat=fread(&bf,sizeof(BlockF),1,fp))!=1) abort("frdb_block: can't fread - status %d",stat); *bkp = empty_Block; bkp->ident = bf.ident; bkp->bx = bf.bx; bkp->skew = bf.skew; bkp->shear = bf.shear; bkp->wst = bf.wst; bkp->ls.mny = bf.lmny; bkp->ws.mny = bf.wmny; bkp->cs.mny = bf.cmny; bkp->bs.mny = bf.bmny; #if dbg_frdb if((!(bkp->ident&IsBlock))||(bkp->ident&(IsALL&(~IsBlock)))) err("frdb_block: %s",block_toa(bkp)); #endif #if dbg_frdb_toa err("frdb_block: %s",block_toa(bkp)); #endif if(bkp->ident&Block_label) bkp->l = frdb_label(fp); if(ferror(fp)) return(-errno); else return(1); } #endif frdb_block_etc(fp,bkp,etc) FILE *fp; Block *bkp; Ident etc; { BlockF bf; int stat; frdb_block(fp,bkp); if(etc&IsTxtln && bkp->ls.mny>0) frdb_txtlns_etc(fp,&(bkp->ls),etc); else bkp->ls = empty_Txtlns; if(etc&IsWord && bkp->ws.mny>0) frdb_words_etc(fp,&(bkp->ws),etc); else bkp->ws = empty_Words; if(etc&IsChar && bkp->cs.mny>0) frdb_chars_etc(fp,&(bkp->cs),etc); else bkp->cs = empty_Chars; if(etc&IsBlob && bkp->bs.mny>0) frdb_blobs_etc(fp,&(bkp->bs),etc); else bkp->bs = empty_Blobs; if(ferror(fp)) return(-errno); else return(1); } /* read number of blocks, and their parts */ frdb_blocks_etc(fp,bksp,etc) FILE *fp; Blocks *bksp; Ident etc; { int bi; register Block *bkp,**bkpp; if(bksp->mny<=0) { *bksp = empty_Blocks; return(1); }; if((bkpp=bksp->bpa=(Block **)malloc((bksp->mny+1)*sizeof(Block *)))==NULL) abort("can't alloc Blocks.bpa array"); for(bi=0; bi<bksp->mny; bi++) { *(bkpp++) = bkp = alloc_block(); frdb_block_etc(fp,bkp,etc); }; *bkpp = NULL; if(ferror(fp)) return(-errno); else return(1); } free_block_etc(p,etc) Block *p; Ident etc; { free_txtlns_etc(&(p->ls),etc); free_words_etc(&(p->ws),etc); free_chars_etc(&(p->cs),etc); free_blobs_etc(&(p->bs),etc); if(p->ident&Block_label && p->l!=NULL) { free(p->l); p->l=NULL; p->ident &= ~Block_label; }; if(etc&IsBlock) { free(p); free_census(Block,1); }; } /* Unconditionally free the malloc-space array of pointers, and empty the set. Don't free the records that it owned. */ free_blocks(p) Blocks *p; { if(p->bpa!=NULL) { free(p->bpa); p->bpa = NULL; } p->mny = 0; } free_blocks_etc(p,etc) Blocks *p; Ident etc; { register Block *bkp,**bkpp; if(p->mny>0&&(etc&IsBlock)) for(bkp= *(bkpp=p->bpa); bkp!=NULL; bkp= *(++bkpp)) free_block_etc(bkp,etc); free_blocks(p); } /* return a pointer to a distinct and duplicate copy of *bkp, created out of malloc space */ Block *dup_block(bkp) Block *bkp; { Block *dup; dup=alloc_block(); *dup = *bkp; return(dup); } /* Return a pointer to a distinct and duplicate copy of *bkp, and its parts as specified by `etc', created out of malloc space. */ Block *dup_block_etc(bkp,etc) Block *bkp; Ident etc; { Block *dup; dup = dup_block(bkp); if(etc&IsBlob&&dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(bkp->bs),etc); else dup->bs = empty_Blobs; if(etc&IsChar&&dup->cs.mny>0) dup->cs = *dup_chars_etc(&(bkp->cs),etc); else dup->cs = empty_Chars; if(etc&IsWord&&dup->ws.mny>0) dup->ws = *dup_words_etc(&(bkp->ws),etc); else dup->ws = empty_Words; if(etc&IsTxtln&&dup->ls.mny>0) dup->ls = *dup_txtlns_etc(&(bkp->ls),etc); else dup->ls = empty_Txtlns; return(dup); } /* Return a pointer to a distinct local static duplicate of non-empty *bksp. Its bkpa array is created newly out of malloc space. If etc&IsBlock, all its Blocks are also duplicated, else the contents of bkpa point to the old unduplicated Blocks. */ Blocks *dup_blocks_etc(bksp,etc) Blocks *bksp; Ident etc; /* parts to duplicate */ { static Blocks dup; register Block **bkpp,**dpp; if((dup.mny = bksp->mny)<=0) dup = empty_Blocks; else { if((dup.bpa=(Block **)malloc((dup.mny+1)*sizeof(Block *)))==NULL) abort("can't dup bks.bpa"); for(bkpp=bksp->bpa,dpp=dup.bpa; *bkpp!=NULL; bkpp++,dpp++) { if(etc&IsBlock) *dpp = dup_block_etc(*bkpp,etc); else *dpp = *bkpp; }; *dpp = NULL; }; return(&dup); } /* Append a block to the end of a blocks set. Return appended Block *. */ Block *append_block(bkp,bksp) Block *bkp; Blocks *bksp; { register Block *rp,**rpp,**npp; if(bksp->mny==0) { if((bksp->bpa=(Block **)malloc(2*sizeof(Block *)))==NULL) abort("append_block: can't malloc bksp->bpa"); } else { if((bksp->bpa=(Block **)realloc( bksp->bpa, (bksp->mny+2)*sizeof(Block *)) )==NULL) abort("append_block: can't realloc bksp->bpa"); }; bksp->bpa[bksp->mny] = bkp; bksp->bpa[++bksp->mny] = NULL; return(bkp); } /* remove a block from a blocks set */ remove_block(bkp,bksp) Block *bkp; Blocks *bksp; { register Block *rp,**rpp,**npp; if(bksp->mny==0) err("can't remove Block - Blocks empty"); else { for(rp= *(rpp=bksp->bpa); rp!=NULL; rp= *(++rpp)) if(rp==bkp) break; if(rp==NULL) err("can't remove Block - not found"); else { /* move later entries up */ npp=rpp+1; do *(rpp++)= *(npp++); while ((*rpp)!=NULL); if((--(bksp->mny))==0) {free(bksp->bpa); bksp->bpa=NULL;}; /* don't bother to realloc downwards */ }; }; } ConstPitch *alloc_constpitch() { ConstPitch *p; if((p=(ConstPitch *)malloc(sizeof(ConstPitch)))==NULL) abort("can't alloc ConstPitch"); else { *p = empty_ConstPitch; return(p); }; } char *constpitch_toa(p) ConstPitch *p; { static char s[80]; sprintf(s,"{w%.3f,o%d,r%.1f}", p->w,p->o,p->r); return(s); } free_constpitch(p) ConstPitch *p; { free(p); } Txtln *alloc_txtln() { Txtln *p; if((p=(Txtln *)malloc(sizeof(Txtln)))==NULL) abort("can't alloc Txtln"); alloc_census(Txtln,1); *p = empty_Txtln; return(p); } char *txtln_toa(p) Txtln *p; { static char s[80]; sprintf(s,"%s bx%s sz%s ba%d cw%s m%s l%d w%d c%d b%d %s", ident_toa(p->ident), bbx_toa(&(p->bx)), pts_toa(p->size), p->basl, /** proj omitted **/ ((p->cp!=NULL)? constpitch_toa(p->cp): "0"), merit_toa(p->m), p->ls.mny,p->ws.mny,p->cs.mny,p->bs.mny, (p->l!=NULL)? p->l: ""); return(s); } #if FWRI fwrb_txtln(f,p) FILE *f; Txtln *p; { #if dbg_fwrb if((!(p->ident&IsTxtln))||(p->ident&(IsALL&(~IsTxtln)))) err("fwrb_txtln: %s",txtln_toa(p)); if(p->ident&Txtln_label && p->l==NULL) { err("fwrb_page: Txtln_label set but .l==NULL"); p->ident &= ~Txtln_label; }; #endif fwri_Ident(f,p->ident); fwri_Bbx(f,&(p->bx)); fwri_Pts(f,p->size); fwri_Scoor(f,p->basl); /* fwri_?(f,p->proj); */ /* fwri_ConstPitch(f,p->cp); */ fwri_Merit(f,p->m); fwri_uint2(f,p->ls.mny); fwri_uint2(f,p->ws.mny); fwri_uint2(f,p->cs.mny); fwri_uint3(f,p->bs.mny); #if dbg_fwrb_toa err("fwrb_txtln: %s",txtln_toa(p)); #endif if(p->ident&Txtln_label) fwrb_label(f,p->l); } #else fwrb_txtln(fp,lp) FILE *fp; Txtln *lp; { TxtlnF lf; int stat; #if dbg_fwrb if((!(lp->ident&IsTxtln))||(lp->ident&(IsALL&(~IsTxtln)))) err("fwrb_txtln: %s",txtln_toa(lp)); #endif memset(&lf,'\0',sizeof(lf)); lf.ident = lp->ident; lf.bx = lp->bx; lf.basl = lp->basl; lf.size = lp->size; if(lp->proj!=NULL) lf.pmny = lp->bx.b.y - lp->bx.a.y + 1; else lf.pmny = 0; /* ignore lp->cp for now */ lf.wmny = lp->ws.mny; lf.cmny = lp->cs.mny; lf.bmny = lp->bs.mny; if((stat=fwrite(&lf,sizeof(TxtlnF),1,fp))!=1) abort("can't write TxtlnF, status %d",stat); #if dbg_fwrb_toa err("fwrb_txtln: %s",txtln_toa(lp)); #endif if(lf.ident&Txtln_label) fwrb_label(fp,lp->l); } #endif fwrb_txtlns_etc(fp,ls,etc) FILE *fp; Txtlns ls; Ident etc; { register Txtln *lp,**lpp; if(ls.mny>0) for(lp= *(lpp=ls.lpa); lp!=NULL; lp= *(++lpp)) fwrb_txtln_etc(fp,lp,etc); } fwrb_txtln_etc(fp,lp,etc) FILE *fp; Txtln *lp; Ident etc; { static Ident parts = (IsWord|IsChar|IsBlob); Txtln tl; if((etc&parts)!=parts) /* write selected parts */ { tl = *lp; if(!(etc&IsWord)) tl.ws.mny=0; if(!(etc&IsChar)) tl.cs.mny=0; if(!(etc&IsBlob)) tl.bs.mny=0; lp = &tl; /* write modified record */ }; fwrb_txtln(fp,lp); if(lp->proj!=NULL) {/* write projection array someday */}; fwrb_words_etc(fp,lp->ws,etc); fwrb_chars_etc(fp,lp->cs,etc); fwrb_blobs_etc(fp,lp->bs,etc); } #if FRDI int frdb_txtln(f,p) FILE *f; Txtln *p; { *p = empty_Txtln; if(feof(f)) return(0); p->ident=frdi_Ident(f); frdi_Bbx(f,&(p->bx)); p->size=frdi_Pts(f); p->basl=frdi_Scoor(f); /* p->proj=frdi_?(f); */ /* p->cp=frdi_ConstPitch(f); */ p->m=frdi_Merit(f); p->ls.mny=frdi_uint2(f); p->ws.mny=frdi_uint2(f); p->cs.mny=frdi_uint2(f); p->bs.mny=frdi_uint3(f); #if dbg_frdb if((!(p->ident&IsTxtln))||(p->ident&(IsALL&(~IsTxtln)))) err("frdb_txtln: %s",txtln_toa(p)); #endif #if dbg_frdb_toa err("frdb_txtln: %s",txtln_toa(p)); #endif if(p->ident&Txtln_label) p->l = frdb_label(f); if(ferror(f)) return(-errno); else return(1); } #else int frdb_txtln(fp,lp) FILE *fp; Txtln *lp; { TxtlnF lf; int stat; if((stat=fread(&lf,sizeof(TxtlnF),1,fp))!=1) abort("can't read TxtlnF, status %d",stat); *lp = empty_Txtln; lp->ident = lf.ident; lp->bx = lf.bx; lp->basl = lf.basl; lp->size = lf.size; if(lf.pmny>0) lp->proj=(short *)malloc(lf.pmny); else lp->proj = NULL; lp->cp = NULL; lp->ws.mny = lf.wmny; lp->cs.mny = lf.cmny; lp->bs.mny = lf.bmny; #if dbg_frdb if((!(lp->ident&IsTxtln))||(lp->ident&(IsALL&(~IsTxtln)))) err("frdb_txtln: %s",txtln_toa(lp)); #endif #if dbg_frdb_toa err("frdb_txtln: %s",txtln_toa(lp)); #endif if(lp->ident&Txtln_label) lp->l = frdb_label(fp); if(ferror(fp)) return(-errno); else return(1); } #endif frdb_txtln_etc(fp,lp,etc) FILE *fp; Txtln *lp; Ident etc; { TxtlnF lf; int stat; frdb_txtln(fp,lp); if(lp->proj!=NULL) {/* read projection array someday */}; if(etc&IsWord && lp->ws.mny>0) frdb_words_etc(fp,&(lp->ws),etc); else lp->ws = empty_Words; if(etc&IsChar && lp->cs.mny>0) frdb_chars_etc(fp,&(lp->cs),etc); else lp->cs = empty_Chars; if(etc&IsBlob && lp->bs.mny>0) frdb_blobs_etc(fp,&(lp->bs),etc); else lp->bs = empty_Blobs; if(ferror(fp)) return(-errno); else return(1); } /* read number of txtlns, and parts */ frdb_txtlns_etc(fp,lsp,etc) FILE *fp; Txtlns *lsp; Ident etc; { int li; register Txtln *lp,**lpp; if(lsp->mny<=0) { *lsp = empty_Txtlns; return(1); }; if((lpp=lsp->lpa=(Txtln **)malloc((lsp->mny+1)*sizeof(Txtln *)))==NULL) abort("can't alloc Txtlns.lpa array"); for(li=0; li<lsp->mny; li++) { *(lpp++) = lp = alloc_txtln(); frdb_txtln_etc(fp,lp,etc); }; *lpp = NULL; if(ferror(fp)) return(-errno); else return(1); } /* Append a txtln to the end of a txtlns set. Do NOT maintain Txtlns in order sorted ascending on Txtln.bx.a.y. Return appended Txtln *. */ Txtln *append_txtln(lp,lsp) Txtln *lp; Txtlns *lsp; { register Txtln *rp,**rpp,**npp; if(lsp->mny==0) { if((lsp->lpa=(Txtln **)malloc(2*sizeof(Txtln *)))==NULL) abort("append_txtln: can't malloc lsp->lpa"); } else { if((lsp->lpa=(Txtln **)realloc( lsp->lpa, (lsp->mny+2)*sizeof(Txtln *)) )==NULL) abort("append_txtln: can't realloc lsp->lpa"); }; lsp->lpa[lsp->mny] = lp; lsp->lpa[++lsp->mny] = NULL; return(lp); } /* remove a txtln from a txtlns set */ remove_txtln(lp,lsp) Txtln *lp; Txtlns *lsp; { register Txtln *rp,**rpp,**npp; if(lsp->mny==0) err("can't remove Txtln - Txtlns empty"); else { for(rp= *(rpp=lsp->lpa); rp!=NULL; rp= *(++rpp)) if(rp==lp) break; if(rp==NULL) err("can't remove Txtln - not found"); else { /* move later entries up */ npp=rpp+1; do *(rpp++)= *(npp++); while ((*rpp)!=NULL); if((--(lsp->mny))==0) {free(lsp->lpa); lsp->lpa=NULL;}; /* don't bother to realloc downwards */ }; }; } free_txtln_etc(p,etc) Txtln *p; Ident etc; { free_words_etc(&(p->ws),etc); free_chars_etc(&(p->cs),etc); free_blobs_etc(&(p->bs),etc); if(p->ident&Txtln_label && p->l!=NULL) { free(p->l); p->l=NULL; p->ident &= ~Txtln_label; }; if(etc&IsTxtln) { if(p->l!=NULL) free(p->l); free(p); free_census(Txtln,1); }; } /* Unconditionally free the malloc-space array of pointers, and empty the set. Don't free the records that it owned. */ free_txtlns(lsp) Txtlns *lsp; { if(lsp->lpa!=NULL) { free(lsp->lpa); lsp->lpa = NULL; } lsp->mny = 0; } free_txtlns_etc(lsp,etc) Txtlns *lsp; Ident etc; { register Txtln *lp,**lpp; if(lsp->mny>0&&(etc&IsTxtln)) for(lp= *(lpp=lsp->lpa); lp!=NULL; lp= *(++lpp)) free_txtln_etc(lp,etc); free_txtlns(lsp); } /* return a pointer to a distinct and duplicate copy of *lp, created out of malloc space */ Txtln *dup_txtln(lp) Txtln *lp; { Txtln *dup; if((dup=(Txtln *)malloc(sizeof(Txtln)))==NULL) abort("can't dup Txtln"); alloc_census(Txtln,1); *dup = *lp; return(dup); } /* Return a pointer to a distinct and duplicate copy of *lp, and its parts as specified by `etc', created out of malloc space. */ Txtln *dup_txtln_etc(lp,etc) Txtln *lp; Ident etc; { Txtln *dup; dup = dup_txtln(lp); if(etc&IsBlob&&dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(lp->bs),etc); else dup->bs = empty_Blobs; if(etc&IsChar&&dup->cs.mny>0) dup->cs = *dup_chars_etc(&(lp->cs),etc); else dup->cs = empty_Chars; if(etc&IsWord&&dup->ws.mny>0) dup->ws = *dup_words_etc(&(lp->ws),etc); else dup->ws = empty_Words; return(dup); } /* Return a pointer to a distinct local static duplicate of non-empty *lsp. Its lpa array is created newly out of malloc space. If etc&IsTxtln, all its Txtlns are also duplicated, else the contents of lpa point to the old unduplicated Txtlns. */ Txtlns *dup_txtlns_etc(lsp,etc) Txtlns *lsp; Ident etc; /* parts to duplicate */ { static Txtlns dup; register Txtln **lpp,**dpp; if((dup.mny = lsp->mny)<=0) dup = empty_Txtlns; else { if((dup.lpa=(Txtln **)malloc((dup.mny+1)*sizeof(Txtln *)))==NULL) abort("can't dup ls.lpa"); for(lpp=lsp->lpa,dpp=dup.lpa; *lpp!=NULL; lpp++,dpp++) { if(etc&IsTxtln) *dpp = dup_txtln_etc(*lpp,etc); else *dpp = *lpp; }; *dpp = NULL; }; return(&dup); } Word *alloc_word() { Word *p; if((p=(Word *)malloc(sizeof(Word)))==NULL) abort("can't alloc Word"); alloc_census(Word,1); *p = empty_Word; return(p); } char *word_toa(p) Word *p; { static char s[80]; sprintf(s,"%s bx%s ws%0.2f c%d b%d m%s w%d", ident_toa(p->ident), bbx_toa(&(p->bx)), p->wsp, p->cs.mny,p->bs.mny,merit_toa(p->m),p->ws.mny); return(s); } /* Are two Words identical? A not quite exhaustively-detailed test. */ boolean eq_word(w1,w2) Word *w1,*w2; { register Char **c1,**c2; if(w1->cs.mny!=w2->cs.mny) return(F); for(c1=w1->cs.cpa,c2=w2->cs.cpa; *c1!=NULL; c1++,c2++) { if((*c1)->area!=(*c2)->area) return(F); if(!bbx_eq(&((*c1)->bx),&((*c2)->bx))) return(F); if((*c1)->bmny!=(*c2)->bmny) return(F); }; /* don't bother to compare Blob lists in detail (they aren't in any particular order). */ return(T); } /* Compute a hash key for this Word that is likely to indicate whether or not it is geometrically identical to another Word. */ int hash_word(w) Word *w; { register int k; register Char **c; if(w->cs.mny==0) return(0); k = w->bx.a.x * w->bx.a.y * w->bx.b.x * w->bx.b.y; for(c=w->cs.cpa; (*c)!=NULL; c++) { k += (*c)->bx.a.x * (*c)->bx.a.y * (*c)->bx.b.x * (*c)->bx.b.y * (*c)->bmny * (*c)->area; }; return(k); } #if FWRI fwrb_word(f,p) FILE *f; Word *p; { #if dbg_fwrb if((!(p->ident&IsWord))||(p->ident&(IsALL&(~IsWord)))) err("fwrb_word: %s",word_toa(p)); if(p->ident&Word_label && p->l==NULL) { err("fwrb_page: Word_label set but .l==NULL"); p->ident &= ~Word_label; }; #endif fwri_Ident(f,p->ident); fwri_Bbx(f,&(p->bx)); fwri_int2(f,p->wsp*UCHAR_MAX); fwri_Merit(f,p->m); fwri_Prob(f,p->p); fwri_uint2(f,p->ws.mny); fwri_uint2(f,p->cs.mny); fwri_uint3(f,p->bs.mny); /* fwri_int4(f,p->hash); */ #if dbg_fwrb_toa err("fwrb_word: %s",word_toa(p)); #endif if(p->ident&Word_label) fwrb_label(f,p->l); } #else fwrb_word(fp,wp) FILE *fp; Word *wp; { WordF wf; int stat; #if dbg_fwrb if((!(wp->ident&IsWord))||(wp->ident&(IsALL&(~IsWord)))) err("fwrb_word: %s",word_toa(wp)); #endif memset(&wf,'\0',sizeof(wf)); wf.ident = wp->ident; wf.bx = wp->bx; wf.wsp = wp->wsp; wf.m = wp->m; wf.wmny = wp->ws.mny; wf.cmny = wp->cs.mny; wf.bmny = wp->bs.mny; if((stat=fwrite(&wf,sizeof(WordF),1,fp))!=1) abort("can't write WordF, status %d",stat); #if dbg_fwrb_toa err("fwrb_word: %s",word_toa(wp)); #endif if(wf.ident&Word_label) fwrb_label(fp,wp->l); } #endif fwrb_words_etc(fp,ws,etc) FILE *fp; Words ws; Ident etc; { register Word *wp,**wpp; if(ws.mny>0) for(wp= *(wpp=ws.wpa); wp!=NULL; wp= *(++wpp)) fwrb_word_etc(fp,wp,etc); } fwrb_word_etc(fp,wp,etc) FILE *fp; Word *wp; Ident etc; { static Ident parts = (IsWord|IsChar|IsBlob); Word wd; if((etc&parts)!=parts) /* write selected parts */ { wd = *wp; if(!(etc&IsWord)) wd.ws.mny=0; if(!(etc&IsChar)) wd.cs.mny=0; if(!(etc&IsBlob)) wd.bs.mny=0; wp = &wd; /* write modified record */ }; fwrb_word(fp,wp); if(etc&IsWord) fwrb_words_etc(fp,wp->ws,IsALL); fwrb_chars_etc(fp,wp->cs,etc); fwrb_blobs_etc(fp,wp->bs,etc); } #if FRDI int frdb_word(f,p) FILE *f; Word *p; { *p = empty_Word; if(feof(f)) return(0); p->ident=frdi_Ident(f); frdi_Bbx(f,&(p->bx)); p->wsp=frdi_int2(f)/(float)UCHAR_MAX; p->m=frdi_Merit(f); p->p=frdi_Prob(f); p->ws.mny=frdi_uint2(f); p->cs.mny=frdi_uint2(f); p->bs.mny=frdi_uint3(f); /* p->hash=frdi_int4(f); */ #if dbg_frdb if((!(p->ident&IsWord))||(p->ident&(IsALL&(~IsWord)))) err("frdb_word: %s",word_toa(p)); #endif #if dbg_frdb_toa err("frdb_word: %s",word_toa(p)); #endif if(p->ident&Word_label) p->l = frdb_label(f); if(ferror(f)) return(-errno); else return(1); } #else int frdb_word(fp,wp) FILE *fp; Word *wp; { WordF wf; int stat; if((stat=fread(&wf,sizeof(WordF),1,fp))!=1) abort("can't read WordF, status %d",stat); *wp = empty_Word; wp->ident = wf.ident; wp->bx = wf.bx; wp->wsp = wf.wsp; wp->m = wf.m; wp->ws.mny = wf.wmny; wp->cs.mny = wf.cmny; wp->bs.mny = wf.bmny; #if dbg_frdb if((!(wp->ident&IsWord))||(wp->ident&(IsALL&(~IsWord)))) err("frdb_word: %s",word_toa(wp)); #endif #if dbg_frdb_toa err("frdb_word: %s",word_toa(wp)); #endif if(wp->ident&Word_label) wp->l = frdb_label(fp); if(ferror(fp)) return(-errno); else return(1); } #endif frdb_word_etc(fp,wp,etc) FILE *fp; Word *wp; Ident etc; { WordF cf; int stat; frdb_word(fp,wp); frdb_words_etc(fp,&(wp->ws),IsALL); /* rd alternatives entirely, if any */ if(etc&IsChar && wp->cs.mny>0) frdb_chars_etc(fp,&(wp->cs),etc); else wp->cs = empty_Chars; if(etc&IsBlob && wp->bs.mny>0) frdb_blobs_etc(fp,&(wp->bs),etc); else wp->bs = empty_Blobs; if(ferror(fp)) return(-errno); else return(1); } /* read words, and their parts */ frdb_words_etc(fp,wsp,etc) FILE *fp; Words *wsp; Ident etc; { int wi; register Word *wp,**wpp; if(wsp->mny<=0) { *wsp = empty_Words; return(1); }; if((wpp=wsp->wpa=(Word **)malloc((wsp->mny+1)*sizeof(Word *)))==NULL) abort("can't alloc Words.wpa array"); for(wi=0; wi<wsp->mny; wi++) { *(wpp++) = wp = alloc_word(); frdb_word_etc(fp,wp,etc); }; *wpp = NULL; if(ferror(fp)) return(-errno); else return(1); } /* remove a word from a words set */ remove_word(wp,wsp) Word *wp; Words *wsp; { register Word *rp,**rpp,**npp; if(wsp->mny==0) err("can't remove Word - Words empty"); else { for(rp= *(rpp=wsp->wpa); rp!=NULL; rp= *(++rpp)) if(rp==wp) break; if(rp==NULL) err("can't remove Word - not found"); else { /* move later entries up */ npp=rpp+1; do *(rpp++)= *(npp++); while ((*rpp)!=NULL); if((--(wsp->mny))==0) {free(wsp->wpa); wsp->wpa=NULL;}; /* don't bother to realloc downwards */ }; }; } /* Remove a Word from a Txtln's Words set. Shrink the Txtln's Bbx if the Word abuts it on the left or right. Ensure that the first Word in the line has wsp==0.0 BUG: doesn't update wsp of trailing Word */ remove_word_txtln(wp,lp) Word *wp; Txtln *lp; { register Word *cwp,**wpp; remove_word(wp,&(lp->ws)); if(lp->ws.mny>0) { if(wp->bx.a.x==lp->bx.a.x || wp->bx.b.x==lp->bx.b.x) { /* recompute possibly shrunken bx */ lp->bx=empty_Bbx; for(cwp= *(wpp=lp->ws.wpa); cwp!=NULL; cwp= *(++wpp)) merge_bbx(&(cwp->bx),&(lp->bx)); }; (lp->ws.wpa[0])->wsp=0.0; }; } /* Append a word to the end of a words set. Do NOT maintain set in order ascending on Word.bx.a.x. Return the appended Word. */ Word *append_word(wp,wsp) Word *wp; Words *wsp; { if(wsp->mny==0) { if((wsp->wpa=(Word **)malloc(2*sizeof(Word *)))==NULL) abort("append_word: can't malloc wsp->wpa"); } else { if((wsp->wpa=(Word **)realloc( wsp->wpa, (wsp->mny+2)*sizeof(Word *)) )==NULL) abort("append_word: can't realloc wsp->wpa"); }; wsp->wpa[wsp->mny++] = wp; wsp->wpa[wsp->mny] = NULL; return(wp); } /* Insert a Word into a Words set. Words is assumed to be sorted ascending on Word.bx.a.x, and this order is maintained. Words with equal Word.bx.a.x are stored in the order that they were inserted: so that the first one inserted remains the first among equals (this feature is important for certain WordSet applications). Return inserted (Word *) */ Word *insert_word(wp,wsp) Word *wp; Words *wsp; { register Word **wpp,*nwp,*pwp; if(wsp->mny==0) { if((wsp->wpa=(Word **)malloc(2*sizeof(Word *)))==NULL) abort("insert_word: can't malloc wsp->wpa"); wsp->wpa[wsp->mny] = wp; } else { if((wpp=wsp->wpa=(Word **)realloc( wsp->wpa, (wsp->mny+2)*sizeof(Word *)) )==NULL) abort("insert_word: can't realloc wsp->wpa"); while(((*wpp)!=NULL)&&(*wpp)->bx.a.x<=wp->bx.a.x) wpp++; /* **wpp is now 1st entry > *wp in sorted order; insert new word just before it */ pwp=wp; do { nwp= *wpp; *(wpp++)=pwp; pwp=nwp; } while(pwp!=NULL); }; wsp->wpa[++wsp->mny] = NULL; return(wp); } /* Insert a Word into the Words owned by a given Txtln, maintaining the Txtln's Bbx and sorted order in the Words set. Return the inserted Word * */ Word *insert_word_txtln(wp,lp) Word *wp; Txtln *lp; { merge_bbx(&(wp->bx),&(lp->bx)); return(insert_word(wp,&(lp->ws))); } /* Free wordinterp and its parts as specified in etc. Always free its strings (if any). If etc&IsWordInterp, free the record itself also. */ free_wordinterp_etc(p,etc) WordInterp *p; Ident etc; { if(p->s!=NULL) { free(p->s); p->s=NULL; }; if(p->pp!=NULL) { free(p->pp); p->pp=NULL; }; if(p->by!=NULL) { free(p->by); p->by=NULL; }; if(p->po!=NULL) { free(p->po); p->po=NULL; }; if(p->ps!=NULL) { free(p->ps); p->ps=NULL; }; if(etc&IsWordInterp) free(p); } /* Duplicate (return ptr to local static copy of) a WordInterp. Always free its strings (if any). 'etc' is ignored. */ WordInterp *dup_wordinterp_etc(p,etc) WordInterp *p; Ident etc; { static WordInterp d; d = *p; if(p->s!=NULL) d.s = strdup(p->s); if(p->pp!=NULL) d.pp = strdup(p->pp); if(p->by!=NULL) d.by = strdup(p->by); if(p->po!=NULL) d.po = strdup(p->po); if(p->ps!=NULL) d.ps = strdup(p->ps); return(&d); } /* Unconditionally free the malloc-space array of pointers, and empty the set. Don't free the records that it owned. */ free_words(wsp) Words *wsp; { if(wsp->wpa!=NULL) { free(wsp->wpa); wsp->wpa = NULL; } wsp->mny = 0; } free_words_etc(wsp,etc) Words *wsp; Ident etc; { register Word *wp,**wpp; int wi; if(wsp->mny>0&&(etc&IsWord)) for(wp= *(wpp=wsp->wpa); wp!=NULL; wp= *(++wpp)) free_word_etc(wp,etc); free_words(wsp); } /* return a pointer to a distinct and duplicate copy of *wp, created out of malloc space */ Word *dup_word(wp) Word *wp; { Word *dup; if((dup=(Word *)malloc(sizeof(Word)))==NULL) abort("can't dup Word"); alloc_census(Word,1); *dup = *wp; return(dup); } /* Return a pointer to a distinct and duplicate copy of *wp, and ALL it owns, created out of malloc space. (HOW they are duplicated is controlled by flags in etc.) */ Word *dup_word_etc(wp,etc) Word *wp; Ident etc; { Word *dup; dup = dup_word(wp); if(dup->ws.mny>0) dup->ws = *dup_words_etc(&(wp->ws),etc); else dup->ws = empty_Words; if(dup->cs.mny>0) dup->cs = *dup_chars_etc(&(wp->cs),etc); else dup->cs = empty_Chars; if(dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(wp->bs),etc); else dup->bs = empty_Blobs; return(dup); } /* Return a pointer to a distinct local static duplicate of non-empty *wsp. Its wpa array is created newly out of malloc space. If etc&IsWord, all its Words are also duplicated, else the contents of wpa point to the old unduplicated Words. */ Words *dup_words_etc(wsp,etc) Words *wsp; Ident etc; /* parts to duplicate */ { static Words dup; register Word **wpp,**dpp; if((dup.mny=wsp->mny)<=0) dup = empty_Words; else { if((dup.wpa=(Word **)malloc((dup.mny+1)*sizeof(Word *)))==NULL) abort("can't dup ws.wpa"); for(wpp=wsp->wpa,dpp=dup.wpa; *wpp!=NULL; wpp++,dpp++) { if(etc&IsWord) *dpp = dup_word_etc(*wpp,etc); else *dpp = *wpp; }; *dpp = NULL; }; return(&dup); } WordInterp *alloc_wordinterp() { WordInterp *p; if((p=(WordInterp *)malloc(sizeof(WordInterp)))==NULL) abort("can't alloc WordInterp"); else { *p = empty_WordInterp; return(p); }; } char *wordinterp_toa(p) WordInterp *p; { static char s[80]; sprintf(s,"%s %s %s|%s|%s|%s", ident_toa(p->ident), ((p->s!=NULL)? p->s: ""), ((p->pp!=NULL)? p->pp: ""), ((p->by!=NULL)? p->by: ""), ((p->po!=NULL)? p->po: ""), ((p->ps!=NULL)? p->ps: "") ); return(s); } /* Free Word and its parts, as specified by etc. Always free the pointer-arrays of ws, cs & bs. If etc&IsWord, free all Words in ws also. If etc&IsChar, free all Chars in cs also. If etc&IsBlob, free all Blobs in bs also. */ free_word_etc(p,etc) Word *p; Ident etc; #define dbg_fwe (F) { if(dbg_fwe) { err("free_word_etc: %s",word_toa(p)); err("free_word_etc: %s",ident_toa(etc)); err_census_all; }; free_words_etc(&(p->ws),IsALL); free_chars_etc(&(p->cs),etc); free_blobs_etc(&(p->bs),etc); if(p->ident&Word_label && p->l!=NULL) { free(p->l); p->l=NULL; p->ident &= ~Word_label; }; if(etc&IsWord) free_word(p); if(dbg_fwe) err_census_all; } free_word(wp) Word *wp; { free(wp); free_census(Word,1); } fwrb_sfeats(fp,sfv) FILE *fp; SFv sfv; { register Pval *vp,*vq; for(vq=(vp=sfv)+SF_MNY; vp<vq; vp++) fwri_int3(fp,USHRT_MAX*(*vp)+0.5); #if dbg_fwrb_toa /** err("fwrb_sfeats: %s",sfeats_toa(sfv)); **/ #endif } int frdb_sfeats(fp,sfv) FILE *fp; SFv sfv; { register Pval *vp,*vq; for(vq=(vp=sfv)+SF_MNY; vp<vq; vp++) *vp = frdi_int3(fp)/((Pval)USHRT_MAX); #if dbg_frdb_toa /** err("frdb_sfeats: %s",sfeats_toa(sfv)); **/ #endif } /* return ptr to local static copy of Shapes of given size */ Shapes *alloc_shapes(mny) int mny; { static Shapes shs; shs.mny = shs.alloc = mny; if((shs.sa=(Nb_s *)malloc(shs.alloc*sizeof(Nb_s)))==NULL) abort("can't alloc Shapes.sa[%d]",shs.alloc); return(&shs); } fwrb_shapes(fp,p) FILE *fp; Shapes *p; /* on entry, p->mny has already been written */ { int dim; register Nb_s *sp,*sq; register Pval *vp; if(p->mny>0&&p->sa!=NULL) { for(sq=(sp=p->sa)+p->mny; sp<sq; sp++) { dim=Sh_dim[sp->t&(~Sh_tiny)]; fwri_uint1(fp,(sp->t&0x7F)|((sp->t&Sh_tiny)?0x80:0x00)); fwri_int2(fp,(*(vp=sp->p))*SHRT_MAX); if(dim>1) { fwri_int2(fp,(*(++vp))*SHRT_MAX); if(dim>2) { fwri_int2(fp,(*(++vp))*SHRT_MAX); if(dim>3) { fwri_int2(fp,(*(++vp))*SHRT_MAX); } } }; }; }; #if dbg_fwrb_toa /** err("fwrb_shapes: %s",shapes_toa(p)); **/ #endif } int frdb_shapes(fp,p) FILE *fp; Shapes *p; /* on entry, p->mny has already been read */ { register Nb_s *sp,*sq; register Pval *vp; uint1 ui1; int dim; if(p->mny>0) { *p = *alloc_shapes(p->mny); for(sq=(sp=p->sa)+p->mny; sp<sq; sp++) { ui1 = frdi_uint1(fp); sp->t = ui1&0x7F|((ui1&0x80)?Sh_tiny:0); dim=Sh_dim[sp->t&(~Sh_tiny)]; *(vp=sp->p) = ((float)frdi_int2(fp))/SHRT_MAX; if(dim>1) { *(++vp) = ((float)frdi_int2(fp))/SHRT_MAX; if(dim>2) { *(++vp) = ((float)frdi_int2(fp))/SHRT_MAX; if(dim>3) { *(++vp) = ((float)frdi_int2(fp))/SHRT_MAX; } } }; }; } else { p->alloc = 0; if(p->sa!=NULL) free(p->sa); p->sa = NULL; }; #if dbg_frdb_toa /** err("frdb_shapes: %s",shapes_toa(p)); **/ #endif } fwra_shapes_etc(fp,p,t) FILE *fp; Shapes *p; char *t; /* string of shape types (empty => all) */ { Nb_s *s; int i,j; char a[80],f[10]; for(i=0,s=p->sa; i<p->mny; i++,s++) { if(t[0]=='\0'||strchr(t,Sh_nam[s->t&(~Sh_tiny)])!=NULL) { sprintf(a,"%c%c ", Sh_nam[s->t&(~Sh_tiny)], (s->t&Sh_tiny)?'\'':' ' ); for(j=0;j<Sh_dim[s->t&(~Sh_tiny)];j++) { sprintf(f," %0.3f",s->p[j]); strcat(a,f); }; fprintf(fp,"%s\n",a); }; }; } err_shapes(shp) Shapes *shp; { int si,di; Nb_s *sp; fprintf(stderr,"shapes %d:\n",shp->mny); for(si=0,sp=shp->sa; si<shp->mny; si++,sp++) { fprintf(stderr," %c",Sh_nam[sp->t]); for(di=0; di<Sh_dim[sp->t]; di++) fprintf(stderr," %6.3f",sp->p[di]); fprintf(stderr,"\n"); }; } /* Unconditionally free the malloc-space array of pointers, and empty the set. Don't free the records that it owned. */ free_shapes(shp) Shapes *shp; { if(shp->sa!=NULL) { if(shp->alloc<=0) abort("can't free unalloc'ed shapes"); else { free(shp->sa); shp->sa=NULL; }; }; shp->mny = shp->alloc = 0; } /* functions for RanParms */ RanParms *alloc_ranparms() { RanParms *rp; if((rp=(RanParms *)malloc(sizeof(RanParms)))==NULL) abort("alloc_ranparms: can't alloc"); *rp = empty_RanParms; return(rp); } free_ranparms(ran) RanParms *ran; { free(ran); } RanParms *dup_ranparms(p) RanParms *p; { RanParms *dup; dup = alloc_ranparms(); *dup = *p; return(dup); } char *ranparms_toa(ran,select) RanParms *ran; char *select; /* a string, subset of: "*rpabejkstxy" if "*" or "" ALL */ { static char s[200]; char p[20]; char *cp; static char select_all[] = "abejkprstxy"; s[0]='\0'; if(select[0]=='*'||select[0]=='\0') select=select_all; for(cp=select; *cp!='\0'; cp++) { switch(*cp) { case 'a': sprintf(p,"a%0.3f ",ran->skew/DtoR); strcat(s,p); break; case 'b': sprintf(p,"b%0.3f ",ran->bhgt); strcat(s,p); break; case 'e': sprintf(p,"e%0.3f ",ran->blur); strcat(s,p); break; case 'j': sprintf(p,"j%0.3f ",ran->jitter); strcat(s,p); break; case 'k': sprintf(p,"k%0.3f ",ran->kern); strcat(s,p); break; case 'p': sprintf(p,"p%g ",ran->size); strcat(s,p); break; case 'r': sprintf(p,"r%d,%d ",ran->res_x,ran->res_y); strcat(s,p); break; case 's': sprintf(p,"s%0.4f ",ran->speckle); strcat(s,p); break; case 't': sprintf(p,"t%0.3f ",ran->thresh); strcat(s,p); break; case 'x': sprintf(p,"x%0.3f ",ran->xscale); strcat(s,p); break; case 'y': sprintf(p,"y%0.3f ",ran->yscale); strcat(s,p); break; }; }; return(s); } RanParms *ato_ranparms(s) char *s; { static RanParms ran; char *f,n,*v; #define TOKEN_SEP "=, \n" f=strtok(s,TOKEN_SEP); while(f!=NULL&&strlen(f)>0) { n=f[0]; v=f+1; switch(n) { case 'r': /* res */ ran.res_x = atoi(v); v=strtok((char *)0,TOKEN_SEP); ran.res_y = atoi(v); break; case 'p': ran.size = atof(v); break; case 'a': ran.skew = atof(v)*DtoR; break; case 'b': ran.bhgt = atof(v); break; case 'e': ran.blur = atof(v); break; case 'j': ran.jitter = atof(v); break; case 'k': ran.kern = atof(v); break; case 's': ran.speckle = atof(v); break; case 't': ran.thresh = atof(v); break; case 'x': ran.xscale = atof(v); break; case 'y': ran.yscale = atof(v); break; }; f=strtok((char *)0,TOKEN_SEP); }; return(&ran); } #if FWRI fwrb_ranparms(f,p) FILE *f; RanParms *p; { fwri_int2(f,p->res_x); fwri_int2(f,p->res_y); fwri_Pts(f,p->size); fwri_Radians(f,p->skew); fwri_Ems(f,p->bhgt); fwri_int3(f,p->blur*10000.0); fwri_int3(f,p->jitter*10000.0); fwri_int3(f,p->kern*10000.0); fwri_int3(f,p->speckle*10000.0); fwri_int3(f,p->thresh*10000.0); fwri_int3(f,p->xscale*10000.0); fwri_int3(f,p->yscale*10000.0); #if dbg_fwrb_toa err("fwrb_ranparms: %s",ranparms_toa(p)); #endif } #else fwrb_ranparms(f,p) FILE *f; RanParms *p; { if((fwrite(p,sizeof(RanParms),1,f))!=1) return(0); #if dbg_fwrb_toa err("fwrb_ranparms: %s",ranparms_toa(p)); #endif } #endif #if FRDI int frdb_ranparms(f,p) FILE *f; RanParms *p; { *p = empty_RanParms; if(feof(f)) return(0); p->res_x=frdi_int2(f); p->res_y=frdi_int2(f); p->size=frdi_Pts(f); p->skew=frdi_Radians(f); p->bhgt=frdi_Ems(f); p->blur=frdi_int3(f)/10000.0; p->jitter=frdi_int3(f)/10000.0; p->kern=frdi_int3(f)/10000.0; p->speckle=frdi_int3(f)/10000.0; p->thresh=frdi_int3(f)/10000.0; p->xscale=frdi_int3(f)/10000.0; p->yscale=frdi_int3(f)/10000.0; #if dbg_frdb_toa err("frdb_ranparms: %s",ranparms_toa(p)); #endif if(ferror(f)) return(-errno); else return(1); } #else int frdb_ranparms(fp,ran) FILE *fp; RanParms *ran; { if((fread(ran,sizeof(RanParms),1,fp))<1) return(0); #if dbg_frdb_toa err("frdb_ranparms: %s",ranparms_toa(ran)); #endif } #endif Char *alloc_char() { Char *p; if((p=(Char *)malloc(sizeof(Char)))==NULL) abort("can't alloc Char"); alloc_census(Char,1); *p = empty_Char; return(p); } char *char_toa(cp) Char *cp; { static char s[100],bfs[24]; if(cp->bfsp==NULL) strcpy(bfs,"0"); else if(cp->bfsp->bm.n==0) strcpy(bfs,"0"); else if(cp->bfsp->bm.mny==0) sprintf(bfs,"%d",cp->bfsp->bm.n); else sprintf(bfs,"%d,%d",cp->bfsp->bm.n,cp->bfsp->bm.mny); sprintf(s,"%s bx%s w%d,h%d cs%d bl%d ar%d pe%d sf%d sh%d bf%s i%d", ident_toa(cp->ident), bbx_toa(&(cp->bx)), bbx_wid(&cp->bx),bbx_hgt(&cp->bx), cp->csp, cp->bmny, cp->area,cp->per, (cp->sfv==NULL)? 0: 1, cp->sh.mny, bfs, cp->il.mny ); return(s); } /* compute the centroid of the Char (offset from bx.a) */ Pp *char_centroid(cp) Char *cp; { static Pp c; Pp *bc; /* blob centroid */ Blob *bp; int bi; c.x = c.y = 0.0; for(bi=0, bp=cp->fi; bi<cp->bmny; bi++, bp=bp->n) { bc = blob_centroid(bp); c.x += bp->area * (bc->x + (cp->bx.a.x - cp->bx.a.x)); c.y += bp->area * (bc->y + (cp->bx.a.y - cp->bx.a.y)); }; c.x /= cp->area; c.y /= cp->area; return(&c); } #if FWRI fwrb_char(f,p) FILE *f; Char *p; { #if dbg_fwrb if((!(p->ident&IsChar))||(p->ident&(IsALL&(~IsChar)))) err("fwrb_char: %s",char_toa(p)); if(p->ident&Char_label && p->l==NULL) { err("fwrb_page: Char_label set but .l==NULL"); p->ident &= ~Char_label; }; if(p->ident&Char_ranparms && p->rp==NULL) { err("fwrb_page: Char_ranparms set but .rp==NULL"); p->ident &= ~Char_ranparms; }; #endif fwri_Ident(f,p->ident); fwri_Bbx(f,&(p->bx)); fwri_Scoor(f,p->csp); fwri_uint4(f,p->area); fwri_uint4(f,p->per); fwri_Scoor(f,p->basl); fwri_uint3(f,p->bmny); fwri_uint2(f,p->il.mny); fwri_uint1(f,(p->sfv!=NULL)?SF_MNY:0); fwri_uint2(f,p->sh.mny); fwri_uint2(f,(p->bfsp!=NULL)?p->bfsp->bm.n:0); #if dbg_fwrb_toa err("fwrb_char: %s",char_toa(p)); #endif if(p->ident&Char_label) fwrb_label(f,p->l); if(p->ident&Char_ranparms) fwrb_ranparms(f,p->rp); } #else fwrb_char(fp,cp) FILE *fp; Char *cp; { CharF cf; int stat; #if dbg_fwrb if((!(cp->ident&IsChar))||(cp->ident&(IsALL&(~IsChar)))) err("fwrb_char: %s",char_toa(cp)); #endif memset(&cf,'\0',sizeof(cf)); if(cp->ident&Char_ranparms && cp->rp==NULL) cp->ident &= ~Char_ranparms; cf.ident = cp->ident | IsChar; cf.bx = cp->bx; cf.csp = cp->csp; cf.area = cp->area; cf.per = cp->per; /* basl omitted */ cf.bmny = cp->bmny; cf.imny = cp->il.mny; cf.sfmny = (cp->sfv!=NULL)?SF_MNY:0; cf.shmny = cp->sh.mny; if(cp->bfsp!=NULL) cf.bfmny = cp->bfsp->bm.n; else cf.bfmny=0; if((stat=fwrite(&cf,sizeof(CharF),1,fp))!=1) abort("can't write CharF, status %d",stat); #if dbg_fwrb_toa err("fwrb_char: %s",char_toa(cp)); #endif if(cf.ident&Char_ranparms) fwrb_ranparms(fp,cp->rp); if(cf.ident&Char_label) fwrb_label(fp,cp->l); } #endif fwrb_chars_etc(fp,cs,etc) FILE *fp; Chars cs; Ident etc; { register Char *cp,**cpp; if(cs.mny>0) for(cp= *(cpp=cs.cpa); cp!=NULL; cp= *(++cpp)) fwrb_char_etc(fp,cp,etc); } fwrb_char_etc(fp,cp,etc) FILE *fp; Char *cp; Ident etc; { static Ident parts = (IsInterp|IsBlob|IsShapes|IsBfeats|IsSfeats); Char ch; if((etc&parts)!=parts) /* write selected parts */ { ch = *cp; if(!(etc&IsInterp)) ch.il.mny=0; if(!(etc&IsBlob)) ch.bmny=0; if(!(etc&IsSfeats)) ch.sfv = NULL; if(!(etc&IsShapes)) ch.sh = empty_Shapes; if(!(etc&IsBfeats)) ch.bfsp = NULL; cp = &ch; /* write modified record */ }; fwrb_char(fp,cp); if(cp->sfv!=NULL) fwrb_sfeats(fp,cp->sfv); if(cp->sh.mny>0) fwrb_shapes(fp,&(cp->sh)); #if CPU!=CRAY if(cp->bfsp!=NULL) fwrb_bfeats(fp,cp->bfsp); #endif fwrb_interpl_etc(fp,cp->il,etc); if(cp->bmny>0) fwrb_blobl_etc(fp,cp->bmny,cp->fi,etc); } #if FRDI int frdb_char(f,p) FILE *f; Char *p; { int sf_mny,bf_mny; *p = empty_Char; if(feof(f)) return(0); p->ident=frdi_Ident(f); frdi_Bbx(f,&(p->bx)); p->csp=frdi_Scoor(f); p->area=frdi_uint4(f); p->per=frdi_uint4(f); p->basl=frdi_Scoor(f); p->bmny=frdi_uint3(f); p->il.mny=frdi_uint2(f); if((sf_mny=frdi_uint1(f))>0) { if((p->sfv=(Pval *)malloc(sf_mny*sizeof(Pval)))==NULL) abort("frdb_char: can't alloc p->sfv[%d]",sf_mny); memset(p->sfv,'\0',sf_mny*sizeof(Pval)); }; p->sh.mny=frdi_uint2(f); if((bf_mny=frdi_uint2(f))>0) { p->bfsp = alloc_bfeats(bf_mny,0); }; #if dbg_frdb if((!(p->ident&IsChar))||(p->ident&(IsALL&(~IsChar)))) err("frdb_char: %s",char_toa(p)); #endif #if dbg_frdb_toa err("frdb_char: %s",char_toa(p)); #endif if(p->ident&Char_label) p->l = frdb_label(f); if(p->ident&Char_ranparms) { p->rp = alloc_ranparms(); frdb_ranparms(f,p->rp); }; if(ferror(f)) return(-errno); else return(1); } #else int frdb_char(fp,cp) FILE *fp; Char *cp; { CharF cf; int stat; if((stat=fread(&cf,sizeof(CharF),1,fp))!=1) abort("frdb_char: can't read CharF, status %d",stat); *cp = empty_Char; cp->ident = cf.ident; cp->bx = cf.bx; cp->csp = cf.csp; cp->area = cf.area; cp->per = cf.per; cp->basl = 0; cp->bmny = cf.bmny; cp->il.mny = cf.imny; if(cf.sfmny>0) { if((cp->sfv=(Pval *)malloc(SF_MNY*sizeof(Pval)))==NULL) abort("frdb_char: can't alloc cp->sfv[%d]",SF_MNY); memset(cp->sfv,'\0',SF_MNY*sizeof(Pval)); } else cp->sfv = NULL; cp->sh.mny = cf.shmny; #if CPU!=CRAY #if dbg_frdb if((!(cp->ident&IsChar))||(cp->ident&(IsALL&(~IsChar)))) err("frdb_char: %s",char_toa(cp)); #endif #endif #if dbg_frdb_toa err("frdb_char: %s",char_toa(cp)); #endif if(cp->ident&Char_ranparms) { cp->rp = alloc_ranparms(); frdb_ranparms(fp,cp->rp); }; if(cp->ident&Char_label) cp->l = frdb_label(fp); #if CPU!=CRAY if(cf.bfmny>0) cp->bfsp = alloc_bfeats(cf.bfmny,0); else #endif cp->bfsp = NULL; if(ferror(fp)) return(-errno); else return(1); } #endif frdb_char_etc(fp,cp,etc) FILE *fp; Char *cp; Ident etc; { frdb_char(fp,cp); if(cp->sfv!=NULL) frdb_sfeats(fp,cp->sfv); if(cp->sh.mny>0) frdb_shapes(fp,&(cp->sh)); #if CPU!=CRAY if(cp->bfsp!=NULL) { frdb_bfeats(fp,cp->bfsp); }; #endif if(cp->il.mny>0) { frdb_interpl_etc(fp,&(cp->il),etc); /**if(!(etc&IsInterp)) free_interpl_etc(&(cp->il),IsALL);**/ }; if(etc&IsBlob && cp->bmny>0) frdb_blobl_etc(fp,cp->bmny,&(cp->fi),etc); else { cp->bmny = 0; cp->fi = NULL; }; if(ferror(fp)) return(-errno); else return(1); } /* read a set of chars, and parts */ frdb_chars_etc(fp,csp,etc) FILE *fp; Chars *csp; Ident etc; { int ci; register Char *cp,**cpp; if(csp->mny<=0) { *csp = empty_Chars; return(1); }; if((cpp=csp->cpa=(Char **)malloc((csp->mny+1)*sizeof(Char *)))==NULL) abort("frdb_chars_etc: can't alloc Chars.cpa array"); for(ci=0; ci<csp->mny; ci++) { *(cpp++) = cp = alloc_char(); frdb_char_etc(fp,cp,etc); }; *cpp = NULL; if(ferror(fp)) return(-errno); else return(1); } /* return a pointer to a distinct and duplicate copy of *cp; it is created out of malloc space. RanParms & label are treated as an integral part of the Char. */ Char *dup_char(cp) Char *cp; { Char *dup; if((dup=(Char *)malloc(sizeof(Char)))==NULL) abort("can't dup Char"); alloc_census(Char,1); *dup = *cp; if(dup->ident&Char_label && dup->l!=NULL) dup->l = strdup(cp->l); else {dup->ident &= ~Char_label; dup->l = NULL;}; if(dup->ident&Char_ranparms && dup->rp!=NULL) dup->rp = dup_ranparms(cp->rp); else {dup->ident &= ~Char_ranparms; dup->rp = NULL;}; return(dup); } /* return a pointer to a distinct and duplicate copy of *cp and those of its lists as specified by etc. (Does not conform to practice for dup_word_etc.) */ Char *dup_char_etc(cp,etc) Char *cp; Ident etc; { Char *dup; dup = dup_char(cp); if(dup->bmny>0&&etc&IsBlob) dup->fi = dup_blobl_etc(cp->fi,etc); else {dup->bmny=0; dup->fi=NULL;}; if(dup->il.mny>0&&etc&IsInterp) dup->il = *dup_interpl_etc(&(cp->il),etc); else dup->il = empty_Interpl; /** if(dup->sfv!=NULL>0&&etc&IsSfeats) dup->sfv = dup_sfeats(cp->sfv); else dup->sfv = NULL; if(dup->sh.mny>0&&etc&IsShapes) dup->sh = *dup_shapes(&cp->sh); else dup->sh = empty_Shapes; **/ #if CPU!=CRAY if(dup->bfsp!=NULL>0&&etc&IsBfeats) dup->bfsp = dup_bfeats(cp->bfsp); else #endif dup->bfsp = NULL; return(dup); } /* Return a pointer to a local static duplicate of non-empty *csp. Its cpa array is new, created out of malloc space. If etc&IsChar, all its Characters are also duplicated, else the contents of cpa point to the old unduplicated Chars. */ Chars *dup_chars_etc(csp,etc) Chars *csp; Ident etc; /* parts to duplicate */ { static Chars dup; register Char **cpp,**dpp; if((dup.mny=csp->mny)<=0) dup = empty_Chars; else { if((dup.cpa=(Char **)malloc((dup.mny+1)*sizeof(Char *)))==NULL) abort("can't dup cs.cpa"); for(cpp=csp->cpa,dpp=dup.cpa; (*cpp)!=NULL; cpp++,dpp++) { if(etc&IsChar) *dpp = dup_char_etc(*cpp,etc); else *dpp = *cpp; }; *dpp = NULL; }; return(&dup); } err_chars(p) Chars *p; { register Char **cpp; fprintf(stderr,"Chars %d: ",p->mny); if(p->mny>0) for(cpp=p->cpa; (*cpp)!=NULL; cpp++) fprintf(stderr,"%X ",*cpp); fprintf(stderr,"\n"); } /* Make a Char out of a single Blob. Return a freshly-allocated Char that owns the given Blob as is (not duplicated, copied or freed). The Blob's next pointer is set to NULL. */ Char *char_of_blob(b) Blob *b; { Char *c; c=alloc_char(); c->bx = b->bx; c->area = b->area; c->per = b->per; c->bmny = 1; c->fi = b; b->n = NULL; return(c); } Interp *alloc_interp() { Interp *new; if((new=(Interp *)malloc(sizeof(Interp)))==NULL) abort("alloc_interp: can't malloc"); alloc_census(Interp,1); *new = empty_Interp; return(new); } Interp *dup_interp(ip) Interp *ip; { Interp *dup; if((dup=(Interp *)malloc(sizeof(Interp)))==NULL) abort("dup_interp: can't malloc"); alloc_census(Interp,1); *dup = *ip; return(dup); } /* Print the interpl */ fwra_interpl(fp,ilp) FILE *fp; Interpl *ilp; { register Interp *cp; fprintf(fp,"Interpl[%d] ",ilp->mny); for(cp=ilp->fi; cp!=NULL; cp=cp->n) { fprintf(fp," %s --",interp_toa(cp)); }; fprintf(fp,"\n"); } /* Print the interpl very briefly */ fwra_interpl_brief(fp,ilp) FILE *fp; Interpl *ilp; { register Interp *ip; for(ip=ilp->fi; ip!=NULL; ip=ip->n) { fprintf(fp,"%s %s ",ip->ci.c,merit_toa(ip->m)); }; fprintf(fp,"\n"); } err_interpl(ilp) Interpl *ilp; { fwra_interpl(stderr,ilp); } /* return the address of a local static copy of the given Interpl, for which each Interp is a duplicate of those in the given list */ Interpl *dup_interpl_etc(ilp,etc) Interpl *ilp; Ident etc; { static Interpl lis; register Interp *cp,*pp,*dp; lis = *ilp; if(ilp->fi==NULL) return(NULL); for(pp=NULL,cp=ilp->fi; cp!=NULL; pp=dp,cp=cp->n) { dp=dup_interp(cp); if(pp==NULL) lis.fi = dp; else pp->n = dp; }; pp->n=NULL; return(&lis); } /* Return a pointer to a local static duplicate of *isp. Its pa array is new, created out of malloc space. If etc&IsInterp, all its Interps are also duplicated, else the contents of pa point to the old unduplicated Interps. */ Interps *dup_interps_etc(isp,etc) Interps *isp; Ident etc; /* parts to duplicate */ { static Interps dup; register Interp **ipp,**dpp; dup = *isp; if(dup.mny<=0) dup = empty_Interps; else { if((dup.pa=(Interp **)malloc((dup.mny+1)*sizeof(Interp *)))==NULL) abort("can't dup (Interp *)is.pa[%d]",(dup.mny+1)); for(ipp=isp->pa,dpp=dup.pa; *ipp!=NULL; ipp++,dpp++) { if(etc&IsInterp) *dpp = dup_interp(*ipp); else *dpp = *ipp; }; *dpp = NULL; }; return(&dup); } free_interps_etc(isp,etc) Interps *isp; Ident etc; /* parts to free */ { register Interp **ipp,**dpp; if(etc&IsInterp) { /* free contents */ for(ipp=isp->pa; *ipp!=NULL; ipp++) free_interp(*ipp); }; if(isp->pa!=NULL) { free(isp->pa); isp->pa = NULL; }; isp->mny = 0; } /* remove a char from a chars set */ remove_char(cp,csp) Char *cp; Chars *csp; { register Char *rp,**rpp,**npp; if(csp->mny==0) err("remove_char: can't - Chars empty"); else { for(rp= *(rpp=csp->cpa); rp!=NULL; rp= *(++rpp)) if(rp==cp) break; if(rp==NULL) err("remove_char: can't - not found"); else { /* move later entries up */ npp=rpp+1; do *(rpp++)= *(npp++); while ((*rpp)!=NULL); if((--(csp->mny))==0) {free(csp->cpa); csp->cpa=NULL;}; /* don't bother to realloc downwards */ }; }; } /* Append a char to the end of a chars set. Do NOT attempt to maintain Chars in order sorted ascending on Char.bx.a.x. Return appended Char *. */ Char *append_char(cp,csp) Char *cp; Chars *csp; { register Char *rp,**rpp,**npp; if(csp->mny==0) { if((csp->cpa=(Char **)malloc(2*sizeof(Char *)))==NULL) abort("append_char: can't malloc csp->cpa[%d]",2); } else { if((csp->cpa=(Char **)realloc( csp->cpa, (csp->mny+2)*sizeof(Char *)) )==NULL) abort("append_char: can't realloc csp->cpa[%d]", (csp->mny+2)); }; csp->cpa[csp->mny] = cp; csp->cpa[++csp->mny] = NULL; return(cp); } /* Insert a Char into a Chars set. Chars is assumed to be sorted ascending on on Char.bx.a.x, and this order is maintained. Return inserted Char * */ Char *insert_char(cp,csp) Char *cp; Chars *csp; { register Char **cpp,*ncp,*pcp; if(csp->mny==0) { if((csp->cpa=(Char **)malloc(2*sizeof(Char *)))==NULL) abort("insert_char: can't malloc csp->cpa[%d]",2); csp->cpa[csp->mny] = cp; } else { if((cpp=csp->cpa=(Char **)realloc( csp->cpa, (csp->mny+2)*sizeof(Char *)) )==NULL) abort("insert_char: can't realloc csp->cpa[%d]",csp->mny+2); while(((*cpp)!=NULL)&&(*cpp)->bx.a.x<cp->bx.a.x) cpp++; /* **cpp is now 1st entry >= *cp in sorted order */ pcp=cp; do { ncp= *cpp; *(cpp++)=pcp; pcp=ncp; } while(pcp!=NULL); }; csp->cpa[++csp->mny] = NULL; return(cp); } /* Append the contents of a "source" chars set to a "destination" chars set. Merely copy (Char *) pointers: don't duplicate Chars. Do NOT attempt to maintain Chars in order sorted ascending on Char.bx.a.x. Return destination (Chars *). */ Chars *append_chars(s,d) Chars *s; /* source */ Chars *d; /* destination */ { register Char *rp,**rpp,**npp; if(s->mny==0) return(d); if(d->mny==0) { if((d->cpa=(Char **)malloc((s->mny+1)*sizeof(Char *)))==NULL) abort("append_chars: can't malloc d->cpa[%d]",2); } else { if((d->cpa=(Char **)realloc( d->cpa, (d->mny+s->mny+1)*sizeof(Char *)) )==NULL) abort("append_chars: can't realloc d->cpa[%d]", (d->mny+s->mny+1)); }; memcpy(d->cpa+d->mny,s->cpa,(s->mny+1)*sizeof(Char *)); d->mny += s->mny; return(d); } /* Insert a Char into the Chars owned by a given Word, maintaining order in set, and updating the Word's bx */ Char *insert_char_word(cp,wp) Char *cp; Word *wp; { merge_bbx(&(cp->bx),&(wp->bx)); return(insert_char(cp,&(wp->cs))); } free_char_etc(p,etc) Char *p; /* !=NULL */ Ident etc; { if(etc&IsBlob) free_blobl_etc(&(p->bmny),&(p->fi),etc); if(etc&IsInterp) free_interpl(&(p->il)); if(etc&IsSfeats && p->sfv!=NULL) { free(p->sfv); p->sfv=NULL; }; if(etc&IsShapes) free_shapes(&(p->sh)); #if CPU!=CRAY if(etc&IsBfeats && p->bfsp!=NULL) { free_bfeats(p->bfsp); p->bfsp=NULL; }; #endif if(etc&IsChar) { if(p->ident&Char_label && p->l!=NULL) { free(p->l); p->l=NULL; p->ident &= ~Char_label; }; if(p->ident&Char_ranparms && p->rp!=NULL) { free_ranparms(p->rp); p->rp=NULL; p->ident &= ~Char_ranparms; }; free(p); free_census(Char,1); }; } /* Unconditionally free the malloc-space array of pointers, and empty the set. Don't free the records that it owned. */ free_chars(csp) Chars *csp; { if(csp->cpa!=NULL) { free(csp->cpa); csp->cpa = NULL; } csp->mny = 0; } free_chars_etc(csp,etc) Chars *csp; Ident etc; { register Char *cp,**cpp; if(csp->mny>0&&(etc&IsChar)) for(cp= *(cpp=csp->cpa); cp!=NULL; cp= *(++cpp)) free_char_etc(cp,etc); free_chars(csp); } /** Blob handling: alloc_blob_pool(sz,debug) - create pool of free blob records free_blob_pool() - free the pool Blob *alloc_blob() - allocate a new blob (in pool) free_blob(bp) - free a specified blob free_blob_runs(bp) - free a blob & the runs in its blob set free_blobl_etc(int *,Blob **,etc) - free blobs etc in char's blob list out_blob(bp) - print (ascii) to stdout fwrb_blob(fp,bp) - write binary Blob (only) to fp fwrb_blob_etc(fp,bp,etc) - write binary Blob & specified parts to fp frdb_blob_etc(fp,bp,etc) - read binary Blob & parts in specified form frdb_runfs(fp,bp,max) - read *bp's (binary) RunF's from fp err_blob(s,bp) - print (ascii) to stderr err_blob_runs(s,bp) - print Blob & its Runs (ascii) to stderr err_blob_runfs(s,bp) - print Blob & its RunFs (ascii) to stderr err_blob_briefly(s,bp) - print (ascii) to stderr err_blobf(s,bp) - print file-format blob (ascii) to stderr err_blob_stats() - report blob statistics blob_small(bp) - test whether its runs' data can be compressed to chars BUGS most fread/fwrite/fseek should be read/write/lseek, for speed -- but how to choose? **/ /* make (empty) pool of `size' Blobs (return F if can't allocate) */ boolean alloc_blob_pool(size,dbg) int size; boolean dbg; { register Blob *cbp, *cbq, *pbp; blob_max=size; if((blob_pool=(Blob *)malloc(blob_max*sizeof(Blob)))==NULL) return(F); blob_debug = dbg; pbp= &blob_fr; /* link up all blobs into free list using only first-ptrs */ for(cbq=(cbp=blob_pool)+blob_max; cbp<cbq; cbp++) { pbp->n = cbp; pbp = cbp; }; pbp->n = NULL; /* marks end of free list */ blob_fr_mny = blob_max; blob_hi=0; blob_chopped = 0; hi_blob_no = 0; return(T); } free_blob_pool() { free(blob_pool); } Blob *alloc_blob() { Blob *p; if((p=(Blob *)malloc(sizeof(Blob)))==NULL) abort("alloc_blob: can't"); alloc_census(Blob,1); *p = empty_Blob; return(p); } /* Unconditionally free this Blob record. */ free_blob(bp) Blob *bp; { free(bp); free_census(Blob,1); } /* Allocate new Blob record and assign to it the next blob no */ Blob *alloc_pool_blob() { register Blob *bp; if((bp = blob_fr.n)==NULL) { err("too many alloc_blob() calls - aborting:"); #ifdef STATS err_blob_stats(); #endif exit(1); }; blob_fr.n = bp->n; #ifdef STATS blob_fr_mny--; if(blob_hi<(blob_max-blob_fr_mny)) blob_hi = blob_max-blob_fr_mny; #endif bp->no = hi_blob_no++; return(bp); } free_pool_blob(bp) Blob *bp; { if(blob_debug&&bp==NULL) abort("free_pool_blob: can't free a NULL Blob"); #ifdef STATS blob_fr_mny++; if(blob_debug&&(blob_fr_mny>blob_max)) { err("free_pool_blob: too many free_blob() calls - aborting:"); #ifdef STATS err_blob_stats(); #endif exit(1); }; #endif bp->n = blob_fr.n; blob_fr.n = bp; } /* free the runs belonging to this blob */ free_runs(bp) Blob *bp; { register Run *crp,*nrp; if(bp->ident&Runs_ff) { if(bp->r.ff!=NULL) free(bp->r.ff); bp->r.ff=NULL; } else if(bp->ident&Runs_f) { for(crp=bp->r.f; crp!=NULL; crp=nrp) { nrp=crp->n; free_run(crp); }; } else if(bp->ident&Runs_seek) /* none to free */ ; } /* free blob *bp and those parts (runs) specified */ free_blob_etc(bp,etc) Blob *bp; Ident etc; { if(etc&IsRun) free_runs(bp); if(etc&IsBlob) free_blob(bp); } /* return a pointer to a distinct and duplicate copy of *bp; it is created out of malloc space */ Blob *dup_blob(bp) Blob *bp; { Blob *dup; if((dup=(Blob *)malloc(sizeof(Blob)))==NULL) abort("dup_blob: can't malloc"); alloc_census(Blob,1); *dup = *bp; return(dup); } /* return a pointer to a distinct and duplicate copy of *bp and what it owns, as described by etc; created out of malloc space */ Blob *dup_blob_etc(bp,etc) Blob *bp; Ident etc; { Blob *dup; dup = dup_blob(bp); if(bp->runs>0) { if(bp->ident&Runs_ff) { int ri; RunF *rp,*drp; if((dup->r.ff= (RunF *)malloc(bp->runs*sizeof(RunF)))==NULL) abort("dup_blob_etc: can't malloc RunF[%d]", bp->runs); for(ri=0,rp=bp->r.ff,drp=dup->r.ff; ri<bp->runs; ri++) *(drp++) = *(rp++); } else abort("dup_blob_etc: only Runs_ff implemented"); }; return(dup); } /* Return a pointer to a local static duplicate of non-empty *bsp. Its bpa array is created newly out of malloc space. If etc&IsBlob, all its Blobs are also fresh duplicates, else the contents of bpa point to the old unduplicated Blobs. */ Blobs *dup_blobs_etc(bsp,etc) Blobs *bsp; Ident etc; /* parts to duplicate */ { static Blobs dup; register Blob **bpp,**dpp; if((dup.mny = bsp->mny)<=0) dup = empty_Blobs; else { if((dup.bpa=(Blob **)malloc((dup.mny+1)*sizeof(Blob *)))==NULL) abort("dup_blobs_etc: can't malloc bs.bpa[%d]",dup.mny+1); for(bpp=bsp->bpa,dpp=dup.bpa; *bpp!=NULL; bpp++,dpp++) { if(etc&IsBlob) *dpp = dup_blob_etc(*bpp,etc); else *dpp = *bpp; }; *dpp = NULL; }; return(&dup); } /* Split the given Blobs into two, *b0 & *b1, according to the value 0 or !0 respectively returned by the function s(b,a) applied to each Blob *b and blind argument *a. s() will be evaluated exactly once for each Blob, and the Blob's will be assigned in the order found in the original Blobs. Only pointers to Blob's are created; the Blob's themselves are not duplicated. The original Blobs record is unchanged. */ split_blobs(b,s,a,b0,b1) Blobs *b; int (*s)(); VOID *a; /* passed transparently to s() */ Blobs *b0,*b1; { char *sel,*sp; register Blob *bp,**bpp; Blob **b0pp; Blob **b1pp; *b0 = *b1 = empty_Blobs; if(b->mny<=0) return; if((sel=(char *)malloc(b->mny))==NULL) abort("split_blobs: can't malloc sel[%d]",b->mny); for(bp= *(bpp=b->bpa),sp=sel; bp!=NULL; bp= *(++bpp),sp++) if(*sp = s(bp,a)) b1->mny++; else b0->mny++; if(b0->mny>0) if((b0->bpa=(Blob **)malloc((b0->mny+1)*sizeof(Blob *)))==NULL) abort("split_blobs: can't malloc b0->bpa[%d]",b0->mny+1); if(b1->mny>0) if((b1->bpa=(Blob **)malloc((b1->mny+1)*sizeof(Blob *)))==NULL) abort("split_blobs: can't malloc b1->bpa[%d]",b1->mny+1); b0pp=b0->bpa; b1pp=b1->bpa; for(bp= *(bpp=b->bpa),sp=sel; bp!=NULL; bp= *(++bpp),sp++) if(*sp) *(b1pp++)=bp; else *(b0pp++)=bp; if(b0->mny>0) *b0pp=NULL; if(b1->mny>0) *b1pp=NULL; free(sel); } /* Return the address of the first in a list of Blobs, duplicated from the given list. */ Blob *dup_blobl_etc(bp,etc) Blob *bp; Ident etc; { Blob *fi,*cp,*pp,*dp; if(bp==NULL) return(NULL); for(pp=NULL,cp=bp; cp!=NULL; pp=dp,cp=cp->n) { dp=dup_blob_etc(cp,etc); if(pp==NULL) fi = dp; else pp->n = dp; }; pp->n=NULL; return(fi); } /* Prepend this blob to the given Char's bloblist; update Char's bx, area, & per. Inverse of `remove_blobl()'. */ Blob *insert_blobl(bp,cp) Blob *bp; Char *cp; { register Blob *pbp,*nbp; if(cp->bmny>0) bp->n = cp->fi; else bp->n = NULL; cp->fi = bp; cp->bmny++; merge_bbx(&(bp->bx),&(cp->bx)); cp->area += bp->area; cp->per += bp->per; return(bp); } /* Remove this blob from a char's bloblist; update Char's bx, area, per. Inverse of `insert_blobl()'. */ remove_blobl(bp,cp) Blob *bp; Char *cp; { Blob *rp,*pp; Bbx bx; /* Char's new Bbx */ if(cp->bmny==1) { /* frequent case */ cp->fi=NULL; cp->bmny=0; } else if(cp->bmny>1){ bx=empty_Bbx; pp=NULL; for(rp=cp->fi; rp!=NULL; pp=rp,rp=rp->n) { if(rp==bp) break; else { if(bx.a.x > rp->bx.a.x) bx.a.x = rp->bx.a.x; if(bx.a.y > rp->bx.a.y) bx.a.y = rp->bx.a.y; if(bx.b.x < rp->bx.b.x) bx.b.x = rp->bx.b.x; if(bx.b.y < rp->bx.b.y) bx.b.y = rp->bx.b.y; }; }; if(rp!=NULL) { /* remove from list */ if(pp==NULL) cp->fi=bp->n; else pp->n=bp->n; cp->bmny--; for(rp=bp->n; rp!=NULL; rp=rp->n) { if(bx.a.x > rp->bx.a.x) bx.a.x = rp->bx.a.x; if(bx.a.y > rp->bx.a.y) bx.a.y = rp->bx.a.y; if(bx.b.x < rp->bx.b.x) bx.b.x = rp->bx.b.x; if(bx.b.y < rp->bx.b.y) bx.b.y = rp->bx.b.y; }; cp->bx = bx; } else err("remove_blobl: can't - not found"); } else err("remove_blobl: can't - Blobl empty"); cp->area -= bp->area; cp->per -= bp->per; } /* prepend this blob to the given Blob list */ Blob *prepend_blobl(bp,blp) Blob *bp; Blobl *blp; { register Blob *pbp,*nbp; if(blp->mny>0) bp->n = blp->fi; else { bp->n = NULL; blp->la = bp; }; blp->fi = bp; blp->mny++; return(bp); } /* append this blob to the given Blob list */ Blob *append_blobl(bp,blp) Blob *bp; Blobl *blp; { register Blob *pbp,*nbp; if(blp->mny==0) blp->fi = bp; else blp->la->n = bp; blp->la = bp; bp->n = NULL; blp->mny++; return(bp); } /* remove a blob from a blobs set */ remove_blob(bp,bsp) Blob *bp; Blobs *bsp; { register Blob *rp,**rpp,**npp; if(bsp->mny==0) err("remove_blob: can't - Blobs empty"); else { for(rp= *(rpp=bsp->bpa); rp!=NULL; rp= *(++rpp)) if(rp==bp) break; if(rp==NULL) err("remove_blob: can't - not found"); else { /* move later entries up */ npp=rpp+1; do *(rpp++)= *(npp++); while ((*rpp)!=NULL); if((--(bsp->mny))==0) {free(bsp->bpa); bsp->bpa=NULL;}; /* don't bother to realloc downwards */ }; }; } /* Append a blob to the end of a blobs set. Return appended Blob *. */ Blob *append_blob(p,sp) Blob *p; Blobs *sp; { register Blob *rp,**rpp,**npp; if(sp->mny==0) { if((sp->bpa=(Blob **)malloc(2*sizeof(Blob *)))==NULL) abort("append_blob: can't malloc sp->bpa[2]"); } else { if((sp->bpa=(Blob **)realloc( sp->bpa, (sp->mny+2)*sizeof(Blob *)) )==NULL) abort("append_blob: can't realloc sp->bpa[%d]",sp->mny+2); }; sp->bpa[sp->mny] = p; sp->bpa[++sp->mny] = NULL; return(p); } /* Append Blobs *p1 to Blobs *p2. On return, *p1 is unchanged, *p2 is in general longer, and all the Blob's owned by *p1 are now also owned by *p2. */ append_blobs_blobs(p1,p2) Blobs *p1,*p2; { int mny; register Blob **pp1,**pp2; if(p1->mny==0) return; if(p2->mny==0) { *p2 = *dup_blobs_etc(p1,IsNONE); return; }; mny = p2->mny + p1->mny; if((p2->bpa=(Blob **)realloc(p2->bpa,(mny+1)*sizeof(Blob *)))==NULL) abort("append_blobs_blobs: can't realloc p2->bpa[%d]",mny+1); pp1=p1->bpa; pp2=p2->bpa+p2->mny; while(*pp1!=NULL) *(pp2++) = *(pp1++); *pp2 = NULL; p2->mny = mny; } free_blobl_etc(mnyp,fip,etc) int *mnyp; Blob **fip; Ident etc; { register Blob *bp,*nbp; if(*mnyp>0) { for(bp= *fip; bp != NULL; bp=nbp) { nbp=bp->n; free_blob_etc(bp,etc); }; }; *mnyp=0; *fip=NULL; } /* Unconditionally free the malloc-space array of pointers, and empty the set. Don't free the records that it owned. */ free_blobs(bsp) Blobs *bsp; { if(bsp->bpa!=NULL) { free(bsp->bpa); bsp->bpa=NULL; }; bsp->mny = 0; } free_blobs_etc(bsp,etc) Blobs *bsp; Ident etc; { register Blob *bp, **bpp; if(bsp->mny>0&&(etc&IsBlob)) for(bp= *(bpp=bsp->bpa); bp!=NULL; bp= *(++bpp)) free_blob_etc(bp,etc); free_blobs(bsp); } Blobs *blobl_to_blobs(blp) Blobl *blp; { static Blobs bs; register Blob *bp,**bpp; bs = empty_Blobs; bs.mny = blp->mny; if(bs.mny>0) { if((bs.bpa=(Blob **)malloc((bs.mny+1)*sizeof(Blob *)))==NULL) abort("blobl_to_blobs: can't malloc Blobs.bpa[%d]",bs.mny+1); for(bp=blp->fi,bpp=bs.bpa; bp!=NULL; bp=bp->n,bpp++) *bpp = bp; *bpp = NULL; }; return(&bs); } int bp_tod(bp) Blob *bp; { if(bp==NULL) return(-2); else return(bp-blob_pool); } /* test whether for this Blob, each runs's data fields could all be compressed from a short to a char */ boolean blob_small(bp) Blob *bp; { if(bp->runs>255) return(F); if(bbx_wid(&bp->bx)>255) return(F); if(bbx_hgt(&bp->bx)>255) return(F); return(T); } char *blob_toa(bp) Blob *bp; { char s1[80]; static char s[80]; Scoor hgt,wid; if(bp==NULL) strcpy(s,"NULL"); else { hgt = bp->bx.b.y - bp->bx.a.y + 1; wid = bp->bx.b.x - bp->bx.a.x + 1; sprintf(s1,"%s bx%s w%d,h%d ar%d pe%d r.", ident_toa(bp->ident), bbx_toa(&(bp->bx)), wid, hgt, bp->area, bp->per ); if(bp->ident&Runs_f) strcat(s1,"f"); else if(bp->ident&Runs_ff) strcat(s1,"ff"); else if(bp->ident&Runs_seek) strcat(s1,"sk"); else if(bp->ident&Runs_g4) strcat(s1,"g"); else strcat(s1,"?"); sprintf(s,"%s%d",s1,bp->runs); }; return(s); } /* compute the centroid of the Blob, w.r.t bx.a */ Pp *blob_centroid(bp) Blob *bp; { static Pp c; RunF *rfp; int ri,area; c.x = c.y = 0.0; if(bp->ident&Runs_ff) { for(ri=0, rfp=bp->r.ff; ri<bp->runs; ri++, rfp++) { c.x += (area=(rfp->xe-rfp->xs+1)) * (rfp->xe+rfp->xs); c.y += area * rfp->y; }; c.x /= 2.0*bp->area; c.y /= bp->area; } else abort("blob_centroid: only Runs_ff supported"); return(&c); } /* write (printably) to stdout */ out_blob(bp) Blob *bp; { Run *crp; static char pad[] = " "; short y; if(bp==NULL) fprintf(stderr,"Bb NULL.\n"); else fprintf(stdout,"%s\n",blob_toa(bp)); fprintf(stdout,"%sy%d:",pad,bp->bx.a.y); for(crp=bp->r.f,y=crp->y; crp!=NULL; crp=crp->n) { if(crp->y!=y) { fprintf(stdout,"\n%sy%d:",pad,crp->y); y=crp->y; }; fprintf(stdout," [%d,%d]",crp->xs,crp->xe); }; fprintf(stdout,"\n"); } #if FWRI /* Write blob record (only) to FILE *f. Check whether Blob is ``small'' and label *p accordingly. */ fwrb_blob(f,p) FILE *f; Blob *p; { #if dbg_fwrb if((!(p->ident&IsBlob))||(p->ident&(IsALL&(~IsBlob)))) err("fwrb_blob: %s",blob_toa(p)); #endif if(blob_small(p)) p->ident |= Blob_small; else p->ident &= ~Blob_small; fwri_Ident(f,p->ident); /* fwri_Seq(f,p->no); */ fwri_Bbx(f,&(p->bx)); fwri_uint4(f,p->area); fwri_uint4(f,p->per); /* don't write .n */ fwri_Merit(f,p->m); fwri_uint3(f,p->runs); fwri_uint2(f,((p->bdsp==NULL)? 0: p->bdsp->mny)); #if dbg_fwrb_toa err("fwrb_blob: %s",blob_toa(p)); #endif } #else /* Write blob record (only) to FILE *fp. Check whether Blob is ``small'' and label *bp accordingly. */ fwrb_blob(fp,bp) FILE *fp; Blob *bp; { BlobF bf; #if dbg_fwrb if((!(bp->ident&IsBlob))||(bp->ident&(IsALL&(~IsBlob)))) err("fwrb_blob: %s",blob_toa(bp)); #endif memset(&bf,'\0',sizeof(bf)); if(blob_small(bp)) bp->ident |= Blob_small; else bp->ident &= ~Blob_small; bf.ident = bp->ident; bf.bx=bp->bx; bf.area=bp->area; bf.per=bp->per; bf.runs=bp->runs; if(bp->bdsp==NULL) bf.bdys=0; else bf.bdys=bp->bdsp->mny; if(blob_debug) err_blobf("",&bf); if(fwrite(&bf,sizeof(BlobF),1,fp)!=1) abort("fwrb_blob: can't fwrite"); #if dbg_fwrb_toa err("fwrb_blob: %s",blob_toa(bp)); #endif } #endif /* Write detailed description of Runs to stderr. */ Blob *err_runs(name,bp) char *name; Blob *bp; { Run *rp; RunF *rfp,*rfe; int ri; if(bp->ident&Runs_f) { fprintf(stderr,"%s Runs_f[%d] in %s:\n", name,bp->runs,bbx_toa(&bp->bx)); for(rp=bp->r.f,ri=0; rp!=NULL; rp=rp->n,ri++) { fprintf(stderr," %2d: %d[%d,%d]\n", ri,rp->y,rp->xs,rp->xe); }; } else if(bp->ident&Runs_ff) { fprintf(stderr,"%s Runs_ff[%d] in %s: ", name,bp->runs,bbx_toa(&(bp->bx))); for(rfe=(rfp=bp->r.ff)+bp->runs,ri=0; rfp<rfe; rfp++,ri++) { fprintf(stderr," %d:%d[%d,%d]", ri,rfp->y,rfp->xs,rfp->xe); }; fprintf(stderr,"\n"); } else if(bp->ident&Runs_seek) { goto unsupported; } else { goto unsupported; }; return; unsupported: abort("err_runs: %s unsupported",ident_toa(bp->ident)); } /* Convert the type of Runs in *bp to the type specified by id. Supported: only bp->ident&Runs_f to id&Runs_ff. Return pointer to local static duplicate of *bp. */ Blob *runs_to_runs(bp,id) Blob *bp; Ident id; { static Blob b; register Run *rp; RunF *rfp; b = *bp; if(bp->ident&Runs_f) { if(id&Runs_ff) { b.ident &= ~(Runs_f|Blob_small); b.ident |= Runs_ff; if(blob_small(bp)) b.ident |= Blob_small; if((b.r.ff=(RunF *)malloc(b.runs*sizeof(RunF)))==NULL) abort("runs_to_runs: can't malloc Blob.r.ff[%d]", b.runs); for(rp=bp->r.f,rfp=b.r.ff; rp!=NULL; rp=rp->n,rfp++) { /* y, xs, xe will be relative to Blob.bx.a */ rfp->y = rp->y - bp->bx.a.y; rfp->xs = rp->xs - bp->bx.a.x; rfp->xe = rp->xe - bp->bx.a.x; /* above,below connecting indices are relative to the sequence no. of this run (ac>0 & bc>0) */ if((rfp->ad = rp->ad)!=0) rfp->ac = rp->u.no - rp->ac->u.no; else rfp->ac = 0; if((rfp->bd = rp->bd)!=0) rfp->bc = rp->bc->u.no - rp->u.no; else rfp->bc = 0; if(0) err_runf(" ",rfp); }; } else { goto unsupported; }; } else if(bp->ident&Runs_ff) { if(bp->ident&Blob_small) { goto unsupported; } else { goto unsupported; }; } else if(bp->ident&Runs_seek) { goto unsupported; } else { goto unsupported; }; return(&b); unsupported: abort("runs_to_runs: %s --> %s unsupported", ident_toa(bp->ident),ident_toa(id)); } #if CPU!=CRAY /* Write these RunFs to FILE *fp in CCITT Group 4 format. BUG: uses bitio to one end of a pipe, just to store the entire byte-stream so it can be counted; then, it is copied to *fp. This fails on large bitmaps since the space available for pipe buffering is limited by system constraints and can run out at any time (symptom: the user process hangs in I state). Also, since it relies so heavily on streams, it may not prove to be very portable. Should be rewritten with an expandable byte-buffer of some kind, which requires that the `putting' function in bitio be user-selectable. */ fwrb_runfs_g4(fp,bxp,runs,ff) FILE *fp; Bbx *bxp; int runs; RunF *ff; #define dbg_fwrb_runfs_g4_detail F { RLE_Line l0,l1; RLE_Line *cl,*pl,*swap; /* current/prior/swap line */ int wid,hgt; /* width,height of rectangular box of pixels */ BITFILE *bf; int iri; RunF *irp; RLE_Run *crp; static int pipe_fd[2] = {-1,-1}; static FILE *pipe_fp[2] = {NULL,NULL}; unsigned long bytes,bi; int och; /* buffer g4 code in a pipe in order to count it */ if(pipe_fd[0]==-1) { pipe(pipe_fd); if((pipe_fp[0] = fdopen(pipe_fd[0],"r"))==NULL) abort("fwrb_runfs_g4: can't open pipe \"r\", fd=%d", pipe_fd[0]); if((pipe_fp[1] = fdopen(pipe_fd[1],"w"))==NULL) abort("fwrb_runfs_g4: can't open pipe \"w\", fd=%d", pipe_fd[1]); /* leave this pipe open for the duration of the process */ }; /* treat pipe_fp[1] as a sequence of bits */ if((bf=bopen(pipe_fp[1],"w"))==NULL) abort("fwrb_runfs_g4: can't open bitfile"); wid = bbx_wid(bxp); hgt=bbx_hgt(bxp); BOF_to_g4(bf); cl= &l0; pl= &l1; cl->len = pl->len = wid; cl->y=0; pl->runs=0; iri=0; irp=ff; do { /* build current RLE_Line */ crp=cl->r; while(iri<runs&&irp->y==cl->y) { crp->xs=irp->xs; crp->xe=irp->xe; if(dbg_fwrb_runfs_g4_detail) err("i%d: y%d x[%d,%d]", iri,cl->y,crp->xs,crp->xe); iri++; irp++; crp++; }; cl->runs = crp-cl->r; /* write current RLE_line to file */ rlel_to_g4(pl,cl,wid,bf); /* save current line as prior */ swap=pl; pl=cl; cl=swap; cl->runs=0; cl->y=pl->y+1; } while(cl->y<hgt); /** By policy, don't append EOFB (i.e. omit EOF_to_g4(bf)) **/ bytes = bclose(bf); if(dbg_fwrb_runs) err("fwrb_runfs_g4: %d bytes",bytes); #if FWRI fwri_uint4(fp,bytes); #else fwrite(&bytes,sizeof(bytes),1,fp); #endif /* copy contents in pipe to fp */ fflush(pipe_fp[1]); for(bi=0;bi<bytes;bi++) { putc(och=getc(pipe_fp[0]),fp); #if dbg_fwrb_runs fprintf(stderr,"%02x",(unsigned char)och); #endif }; if(dbg_fwrb_runs) fprintf(stderr,"\n"); } #else fwrb_runfs_g4(fp,bxp,runs,ff) FILE *fp; Bbx *bxp; int runs; RunF *ff; { abort("fwrb_runfs_g4: unimplemented on Cray"); } #endif #if CPU != CRAY /* Read a connected group of Runs in CCITT Group 4 format, into an array of RunFs. Return: 1 if normal & successful, 0 if EOF, and -1 if error. */ int frdb_g4_runfs(fp,bxp,runs,ff) FILE *fp; Bbx *bxp; /* their bounding box, shrink-wrapped to fit exactly */ int runs; /* expect exactly this number of runs */ RunF *ff; /* space for `runs' RunFs */ #define dbg_frdb_g4_runfs_detail F { RLE_Line *cl; /* current line */ int wid,hgt; /* width,height of rectangular box of pixels */ int y; /* height of current line */ boolean bof; BITFILE *bf; static DST_table *tbl = NULL; int iri; RLE_Run *irp; int ori; RunF *orp; unsigned long bytes,g4_bytes; #if FRDI bytes=frdi_uint4(fp); #else fread(&bytes,sizeof(bytes),1,fp); #endif if(dbg_frdb_runs) err("frdb_g4_runfs: %d bytes",bytes); /* read FILE *fp as a sequence of bits */ if((bf=bopen(fp,"r"))==NULL) abort("frdb_g4_runfs: can't open bitfile"); if(tbl==NULL) { tbl=ccitt_table(); if(dbg_frdb_g4_runfs_detail) ccitt_err_tbl(tbl); }; wid=bbx_wid(bxp); hgt=bbx_hgt(bxp); y=0; bof=T; ori=0; orp=ff; while((y<hgt)&&(cl=g4_to_rlel(tbl,bf,bof,wid))!=NULL) { /* copy runs to RunF ff[] */ for(iri=0,irp=cl->r; iri<cl->runs; iri++,irp++) { if(dbg_frdb_g4_runfs_detail) err("o%d i%d: y%d x[%d,%d]", ori,iri,y,irp->xs,irp->xe); if(ori<runs) { orp->y = y; orp->xs = irp->xs; orp->xe = irp->xe; orp++; } else err("frdb_g4_runfs: too many runs: ori%d >= runs%d", ori,runs); ori++; }; y++; bof=F; }; if(cl==NULL) { err("frdb_g4_runfs: unexpected EOF"); return(0); }; /* recover connectivity among runs, on the assumption that they are still in increasing lexicographic order on (y,xs) */ fix_lag(orp-ff,(char *)ff,Runs_ff); if(ori!=runs) { err("frdb_g4_runfs: expected %d runs, but read %d",runs,ori); return(-1); }; if((g4_bytes=bclose(bf))!=bytes) { err("frdb_g4_runfs: expected %d bytes, but read %d", bytes,g4_bytes); return(-1); }; if(ferror(fp)) return(-errno); else return(1); } #else int frdb_g4_runfs(fp,bxp,runs,ff) FILE *fp; Bbx *bxp; /* exact bounding box, shrink-wrapped to fit */ int runs; /* expect exactly this number of runs */ RunF *ff; /* space for `runs' RunFs */ { abort("frdb_g4_runfs: unimplemented on Cray"); } #endif /* Write blob, etc to FILE *fp in binary format. If !(etc&IsBlob), then do nothing. else write Blob record and: If etc&IsRun, then also try to write Runs: If Blob.runs==0, write no runs. else if etc&Runs_g4, write in CCITT G4 format compact but needs large streams; may not port well; else write in Runs_ff format if blob is small enough, use compressed RunFS form on output. */ fwrb_blob_etc(fp,bp,etc) FILE *fp; Blob *bp; Ident etc; { Ident sv_ident; int sv_runs; Run *rp; RunF rf; register RunF *rfp, *rfq; RunFS *rsp; #if FWRI RunFS rfs; #else static RunFS rfsa[256]; #endif int ri; if(!(etc&IsBlob)) return; sv_ident = bp->ident; sv_runs = bp->runs; if(etc&IsRun) { /* decide which Runs_* bits should be set on output */ bp->ident &= ~(Runs_f|Runs_ff|Runs_seek|Runs_g4); if(etc&Runs_g4) { bp->ident |= Runs_g4; } else { /* assume Runs_ff is wanted */ bp->ident |= Runs_ff; }; } else { bp->ident &= ~(IsRun|Runs_f|Runs_ff|Runs_seek|Runs_g4); bp->runs = 0; }; fwrb_blob(fp,bp); bp->ident = sv_ident; bp->runs = sv_runs; if(bp->runs==0) return; if(etc&Runs_g4) { /* write CCITT Group 4 encoding for Runs */ if(bp->ident&Runs_ff) { fwrb_runfs_g4(fp,&(bp->bx),bp->runs,bp->r.ff); } else abort("fwrb_blob_etc: etc&Runs_g4 but !(id&Runs_ff)"); } else { /* Assume Runs_ff format is desired */ if(bp->ident&Runs_f) { rp=bp->r.f; if(bp->ident&Blob_small) { /* use compressed Run records */ if(blob_debug) err("small"); /* can use small local static array */ #if FWRI rsp= &rfs; #else rsp=rfsa; #endif while(rp!=NULL) { /* y, xs, xe will be relative to Blob.bx.a */ rsp->y = rp->y - bp->bx.a.y; rsp->xs = rp->xs - bp->bx.a.x; rsp->xe = rp->xe - bp->bx.a.x; /* above,below connecting run indices are relative to the sequence no. of this run (ac>0 & bc>0) */ if((rsp->ad = rp->ad)!=0) rsp->ac = rp->u.no - rp->ac->u.no; else rsp->ac = 0; if((rsp->bd = rp->bd)!=0) rsp->bc = rp->bc->u.no - rp->u.no; else rsp->bc = 0; if(blob_debug) err_runfs(" ",rsp); rp=rp->n; #if FWRI fwri_RunFS(fp,rsp); #else rsp++; #endif }; #if !FWRI if(fwrite(rfsa,sizeof(RunFS),bp->runs,fp)!=bp->runs) abort("fwrb_blob_etc: can't fwrite RunFS[%d]",bp->runs); if(dbg_fwrb_runs) err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunFS)); #endif } else { if(blob_debug) err("large"); while(rp!=NULL) { /* y, xs, xe will be relative to Blob.bx.a */ rf.y = rp->y - bp->bx.a.y; rf.xs = rp->xs - bp->bx.a.x; rf.xe = rp->xe - bp->bx.a.x; /* above,below connecting run indices are relative to the sequence no. of this run (ac>0 & bc>0) */ if((rf.ad = rp->ad)!=0) rf.ac = rp->u.no - rp->ac->u.no; else rf.ac = 0; if((rf.bd = rp->bd)!=0) rf.bc = rp->bc->u.no - rp->u.no; else rf.bc = 0; if(blob_debug) err_runf(" ",&rf); /* since there may be many, won't use a local array */ #if FWRI fwri_RunF(fp,&rf); #else if(fwrite(&rf,sizeof(RunF),1,fp)!=1) abort("fwrb_blob_etc: can't fwrite RunF"); #endif rp=rp->n; }; if(dbg_fwrb_runs) err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunF)); }; } else if(bp->ident&Runs_ff) { if(bp->ident&Blob_small) { /* use compressed Run records */ if(blob_debug) err("small"); /* can use small local static array */ #if FWRI rsp= &rfs; #else rsp=rfsa; #endif for(rfp=bp->r.ff,ri=0; ri<bp->runs; rfp++,ri++) { rsp->y = rfp->y; rsp->xs = rfp->xs; rsp->xe = rfp->xe; rsp->ad = rfp->ad; rsp->bd = rfp->bd; rsp->ac = rfp->ac; rsp->bc = rfp->bc; #if FWRI fwri_RunFS(fp,rsp); #else rsp++; #endif }; #if !FWRI if(fwrite(rfsa,sizeof(RunFS),bp->runs,fp)!=bp->runs) abort("fwrb_blob_etc: can't fwrite RunFS[%d]",bp->runs); if(dbg_fwrb_runs) err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunFS)); #endif } else { if(blob_debug) err("large"); #if FWRI for(rfq=(rfp=bp->r.ff)+bp->runs; rfp<rfq; rfp++) { fwri_RunF(fp,rfp); }; #else if(fwrite(bp->r.ff,sizeof(RunF),bp->runs,fp)!=bp->runs) abort("fwrb_blob_etc: can't fwrite RunF[%d]",bp->runs); if(dbg_fwrb_runs) err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunF)); #endif }; }; }; } /* Read a given Blob's RunF's (binary) from FILE *fp; return F on EOF. If bp->runs<=max, read the RunF's into bp->r.ff, and set Runs_ff bit. otherwise ignore them all and set bp->r.ff==NULL. */ int frdb_runfs(fp,bp,max) FILE *fp; Blob *bp; /* *bp's fields already set up */ int max; /* maximum no. RunF records expected */ { register RunFS *rsp,*rsq; static RunFS rfsa[256]; register RunF *rfp,*rfq; if(bp->r.ff!=NULL && bp->runs <= max) { bp->ident |= Runs_ff; bp->ident &= ~(Runs_f|Runs_seek); if(bp->ident&Blob_small) { if(blob_debug) err("small"); #if FRDI for(rsq=(rsp=rfsa)+bp->runs; rsp<rsq; rsp++) { frdi_RunFS(fp,rsp); }; #else if(fread(rfsa,sizeof(RunFS),bp->runs,fp) < bp->runs) return(0); #endif /* copy compressed RunFS's into RunF's */ for(rsq=(rsp=rfsa)+bp->runs,rfp=bp->r.ff; rsp<rsq; rsp++,rfp++) { /* beware sign extension from unsigned chars */ if(blob_debug) err_runfs(" ",rsp); rfp->y = 0377&rsp->y; rfp->xs = 0377&rsp->xs; rfp->xe = 0377&rsp->xe; rfp->ad = 0377&rsp->ad; rfp->bd = 0377&rsp->bd; rfp->ac = 0377&rsp->ac; rfp->bc = 0377&rsp->bc; }; } else { if(blob_debug) err("large"); #if FRDI for(rfq=(rfp=bp->r.ff)+bp->runs; rfp<rfq; rfp++) frdi_RunF(fp,rfp); #else if(fread(bp->r.ff,sizeof(RunF),bp->runs,fp) != bp->runs) return(F); #endif }; } else { bp->ident &= ~(Runs_ff|Runs_f); bp->ident |= Runs_seek; bp->r.seek=ftell(fp); /* skip past excessive no. of runs */ /** What if FRDI?? **/ if(bp->ident&Blob_small) fseek(fp,(long)((bp->runs)*sizeof(RunFS)),1); else fseek(fp,(long)((bp->runs)*sizeof(RunF)),1); }; if(ferror(fp)) return(-errno); else return(1); } #if FRDI /* read a Blob record (only) into *p */ int frdb_blob(f,p) FILE *f; Blob *p; { int bdy_mny; *p = empty_Blob; if(feof(f)) return(0); p->ident=frdi_Ident(f); /* p->no=frdi_Seq(f); */ frdi_Bbx(f,&(p->bx)); p->area=frdi_uint4(f); p->per=frdi_uint4(f); /* don't read .n */ p->m=frdi_Merit(f); p->runs=frdi_uint3(f); if((bdy_mny=frdi_uint2(f))>0) { p->bdsp = alloc_bdys(); p->bdsp->mny = bdy_mny; }; #if dbg_frdb if((!(p->ident&IsBlob))||(p->ident&(IsALL&(~IsBlob)))) err("frdb_blob: %s",blob_toa(p)); #endif #if dbg_frdb_toa err("frdb_blob: %s",blob_toa(p)); #endif if(ferror(f)) return(-errno); else return(1); } #else /* read a Blob record (only) into *bp; return F if EOF */ int frdb_blob(fp,bp) FILE *fp; Blob *bp; { BlobF bf; if(fread(&bf,sizeof(BlobF),1,fp)!=1) return(0); if(blob_debug) err_blobf("bf",&bf); bp->ident=bf.ident; bp->no = 0; bp->bx=bf.bx; bp->area=bf.area; /*bp->per=bf.per;*/ bp->runs=bf.runs; /*bp->bdys=bf.bdys;*/ bp->n = NULL; bp->r.f = NULL; bp->bdsp = NULL; #if dbg_frdb if((!(bp->ident&IsBlob))||(bp->ident&(IsALL&(~IsBlob)))) err("frdb_blob: %s",blob_toa(bp)); #endif #if dbg_frdb_toa err("frdb_blob: %s",blob_toa(bp)); #endif if(ferror(fp)) return(-errno); else return(1); } #endif err_blob(s,bp) char *s; Blob *bp; { fprintf(stderr,"%s ",s); if(bp==NULL) fprintf(stderr,"Blob NULL.\n"); else fprintf(stderr, "Blob %d: x[%d,%d],y[%d,%d] ar%d ft%s r(#%d f%d)\n", bp->no,bp->bx.a.x,bp->bx.b.x,bp->bx.a.y,bp->bx.b.y, bp->area,ident_toa(bp->ident),bp->runs,rp_tod(bp->r.f)); } err_blob_runs(s,bp) char *s; Blob *bp; { Run *crp; char cs[20]; fprintf(stderr,"%s ",s); err_blob(s,bp); if(bp!=NULL&&bp->runs>0&&bp->r.f!=NULL) { sprintf(cs,"%*s",strlen(s)+2," "); for(crp=bp->r.f; crp!=NULL; crp=crp->n) err_run(cs,crp); }; } err_blob_runfs(s,bp) char *s; Blob *bp; { RunF *crp; int ri; char cs[20]; fprintf(stderr,"%s ",s); err_blob_briefly("",bp); if(bp!=NULL&&bp->runs>0&&bp->r.ff!=NULL) { sprintf(cs,"%*s",strlen(s)+2," "); for(crp=bp->r.ff,ri=0; ri<bp->runs; crp++,ri++) err_runf(cs,crp); }; } err_blobf(s,bp) char *s; BlobF *bp; { Run *crp; char cs[20]; fprintf(stderr,"%s ",s); if(bp==NULL) fprintf(stderr,"BlobF NULL.\n"); else fprintf(stderr, "BlobF: x[%d,%d],y[%d,%d] ar%d ft%s #r%d\n", bp->bx.a.x,bp->bx.b.x,bp->bx.a.y,bp->bx.b.y, bp->area,ident_toa(bp->ident),bp->runs); } err_blob_briefly(s,bp) char s[]; Blob *bp; { Run *crp; if(bp==NULL) err("%s Blob NULL.",s); else { fprintf(stderr, "%s Blob #%d: bx(%d,%d),(%d,%d) ar%d f%s runs%d ", s, bp->no, bp->bx.a.x,bp->bx.a.y,bp->bx.b.x,bp->bx.b.y, bp->area, ident_toa(bp->ident), bp->runs); fprintf(stderr,"\n"); }; } err_blob_stats() { err("Blob stats: %d now, %d total, %d hi-water\n", blob_max-blob_fr_mny,hi_blob_no+1,blob_hi); } /* write blob list starting at fi */ fwrb_blobl_etc(fp,mny,fi,etc) FILE *fp; int mny; Blob *fi; Ident etc; { int bi; Blob *bp; if(mny>0) for(bi=0,bp=fi; bi<mny; bi++,bp=bp->n) { if(bp!=NULL) fwrb_blob_etc(fp,bp,etc); else { err("fwrb_blobl_etc: bmny==%d but %dth (Blob *) is NULL", mny,bi); break; }; }; } fwrb_blobs_etc(fp,bs,etc) FILE *fp; Blobs bs; Ident etc; { register Blob *bp,**bpp; if(bs.mny==0) return; for(bp= *(bpp=bs.bpa); bp!=NULL; bp= *(++bpp)) fwrb_blob_etc(fp,bp,etc); } /* read a set of blobs, and their parts */ frdb_blobs_etc(fp,bsp,etc) FILE *fp; Blobs *bsp; Ident etc; /* read only the parts indicated */ { int bi; register Blob *bp,**bpp; if(bsp->mny<=0) { *bsp = empty_Blobs; return(1); }; if((bpp=bsp->bpa=(Blob **)malloc((bsp->mny+1)*sizeof(Blob *)))==NULL) abort("frdb_blobs_etc: can't alloc Blobs.bpa[%d]",bsp->mny+1); for(bi=0; bi<bsp->mny; bi++) { *(bpp++) = bp = alloc_blob(); if(!frdb_blob_etc(fp,bp,etc)) abort("frdb_blobs_etc: unexpected EOF"); }; *bpp = NULL; if(ferror(fp)) return(-errno); else return(1); } /* Read a blob record into *bp, and then read its parts as specified by etc. If there aren't any runs, return normally. If etc&IsRun is false, then set Runs_seek and proceed as described below. If etc&Runs_ff, then the contents of r.ff is examined: if NULL, then space is allocated here for `runs' RunF's; if non-NULL, then on the assumption that it points to space for at least `runs' many, they are read into it. If etc&Runs_seek, then the ftell value is placed in r.seek, and the runs are simply skipped over. The Runs_f (list) option is unimplemented. The Blob is marked with the appropriate Runs_X bit. Return: 1 if normal & successful, 0 if EOF, and -1 if error. */ int frdb_blob_etc(fp,bp,etc) FILE *fp; Blob *bp; Ident etc; { int stat; if((stat=frdb_blob(fp,bp))!=1) return(stat); if(bp->runs<=0) { bp->runs = 0; bp->r.ff = NULL; bp->ident &= ~(Runs_f|Runs_seek|Runs_g4); bp->ident |= Runs_ff; return(1); }; if(!(etc&IsRun)) { etc |= IsRun|Runs_seek; etc &= ~(Runs_f|Runs_ff|Runs_g4); }; if (!(etc&(Runs_f|Runs_ff|Runs_g4|Runs_seek)) || etc&Runs_ff) { /* Want to deliver Runs in Runf ff[] format */ if(bp->r.ff==NULL) { if( (bp->r.ff= (RunF *)malloc(bp->runs*sizeof(RunF)))==NULL) abort("frdb_blob_etc: can't alloc r.ff[%d]",bp->runs); }; if(bp->ident&Runs_g4) { /* Runs are in CCITT Group 4 format */ stat=frdb_g4_runfs(fp,&(bp->bx),bp->runs,bp->r.ff); } else { /* Runs are in RunF or RunFS format */ stat=frdb_runfs(fp,bp,bp->runs); }; bp->ident |= Runs_ff; bp->ident &= ~(Runs_f|Runs_seek|Runs_g4); return(stat); } else if(etc&Runs_seek) { bp->ident |= Runs_seek; bp->ident &= ~(Runs_ff|Runs_f); bp->r.seek=ftell(fp); /* save seek addr */ /* skip past runs */ if(bp->ident&Blob_small) fseek(fp,(long)((bp->runs)*sizeof(RunFS)),1); else fseek(fp,(long)((bp->runs)*sizeof(RunF)),1); } else /* (etc&Runs_f) || (etc&Runs_g4) */ { abort("frdb_blob_etc: Runs_f & Runs_g4 etc option unimplemented"); }; if(ferror(fp)) return(-errno); else return(1); } /* read a number of blobs, and their parts, into linked-list (mny, *fi); return T iff not EOF */ boolean frdb_blobl_etc(fp,bmny,fip,etc) FILE *fp; int bmny; Blob **fip; Ident etc; { int bi; register Blob *bp,**bpp; RunF *rp; int stat; if(bmny<=0) return(1); bi=0; bpp=fip; do { bp=alloc_blob(); if((stat=frdb_blob_etc(fp,bp,etc))!=1) return(stat); *bpp=bp; bpp= &(bp->n); } while((++bi)<bmny); *bpp=NULL; if(ferror(fp)) return(-errno); else return(1); } char *interp_toa(ip) Interp *ip; { static char s[80]; char ms[3],shs[3],szs[3],hts[3],prs[3]; strcpy(ms,merit_toa(ip->m)); strcpy(shs,merit_toa(ip->mshap)); strcpy(szs,merit_toa(ip->msize)); strcpy(hts,merit_toa(ip->mbhgt)); strcpy(prs,merit_toa(ip->p)); sprintf(s,"%s %s sz%s ba%d m%s (sh%s sz%s ht%s) p%s", ident_toa(ip->ident), #if CPU!=CRAY classid_toa(&(ip->ci)), #else ip->ci.c, #endif pts_toa(ip->size), ip->basl, ms,shs,szs,hts,prs); return(s); } frdb_interpl_etc(fp,ilp,etc) FILE *fp; Interpl *ilp; Ident etc; { int ii,stat; Interp *ip,*pp; if(ilp->mny<=0) { *ilp = empty_Interpl; return(1); }; for(ii=0; ii<ilp->mny; ii++) { ip=alloc_interp(); if(ii==0) ilp->fi = ip; else pp->n = ip; if((stat=frdb_interp(fp,ip))!=1) return(stat); pp=ip; }; ip->n = NULL; if(ferror(fp)) return(-errno); else return(1); } #if FRDI int frdb_interp(f,p) FILE *f; Interp *p; { int stat; *p = empty_Interp; if(feof(f)) return(0); p->ident=frdi_Ident(f); frdi_ClassId(f,&(p->ci)); p->mshap=frdi_Merit(f); p->size=frdi_Pts(f); p->msize=frdi_Merit(f); p->basl=frdi_Scoor(f); p->mbhgt=frdi_Merit(f); p->m=frdi_Merit(f); p->p=frdi_Prob(f); #if dbg_frdb if((!(p->ident&IsInterp))||(p->ident&(IsALL&(~IsInterp)))) err("frdb_interp: %s",interp_toa(p)); #endif if(ferror(f)) return(-errno); else return(1); } #else int frdb_interp(fp,ip) FILE *fp; Interp *ip; { InterpF inf; int stat; if((stat=fread(&inf,sizeof(InterpF),1,fp))!=1) { err("can't fread InterpF, status %d",stat); return(stat); }; *ip = empty_Interp; ip->ident = inf.ident; ip->ci = inf.ci; ip->clp = NULL; ip->clsp = NULL; ip->mshap = inf.mshap; ip->size = inf.size; ip->msize = inf.msize; ip->basl = inf.basl; ip->mbhgt = inf.mbhgt; ip->m = inf.m; #if dbg_frdb if((!(ip->ident&IsInterp))||(ip->ident&(IsALL&(~IsInterp)))) err("frdb_interp: %s",interp_toa(ip)); #endif if(ferror(fp)) return(-errno); else return(1); } #endif free_interpl(ilp) Interpl *ilp; { int ii; Interp *ip,*np; if(ilp->mny>0) { for(ip=ilp->fi; ip!=NULL; ip=np) { np=ip->n; free_interp(ip); } ilp->mny=0; }; ilp->fi=NULL; }; fwrb_interpl_etc(fp,is,etc) FILE *fp; Interpl is; Ident etc; { Interp *ip; int ii; if(is.mny>0) for(ii=0,ip=is.fi; ii<is.mny; ii++,ip=ip->n) fwrb_interp_etc(fp,ip,etc); } /* remove this Interp from the Interp-list */ remove_interpl(ip,ilp) Interp *ip; Interpl *ilp; { Interp *rp,*pp; if(ilp->mny==1) { /* frequent case */ ilp->fi=NULL; ilp->mny=0; } else if(ilp->mny>1){ pp=NULL; for(rp=ilp->fi; rp!=ip&&rp!=NULL; pp=rp,rp=rp->n) ; if(rp!=NULL) { /* remove from list */ if(pp==NULL) ilp->fi=ip->n; else pp->n=ip->n; ilp->mny--; } else err("remove_interpl: can't - not found"); } else err("remove_interpl: can't - Interpl empty"); } /* prepend this Interp to the Interp-list */ prepend_interpl(ip,ilp) Interp *ip; Interpl *ilp; { Interp *rp,*pp; ip->n = ilp->fi; ilp->fi = ip; ilp->mny++; } fwrb_interp_etc(fp,ip,etc) FILE *fp; Interp *ip; Ident etc; { fwrb_interp(fp,ip); } #if FWRI fwrb_interp(f,p) FILE *f; Interp *p; { InterpF inf; int stat; #if dbg_fwrb if((!(p->ident&IsInterp))||(p->ident&(IsALL&(~IsInterp)))) err("fwrb_interp: %s",interp_toa(p)); #endif fwri_Ident(f,p->ident); fwri_ClassId(f,&(p->ci)); fwri_Merit(f,p->mshap); fwri_Pts(f,p->size); fwri_Merit(f,p->msize); fwri_Scoor(f,p->basl); fwri_Merit(f,p->mbhgt); fwri_Merit(f,p->m); fwri_Prob(f,p->p); #if dbg_fwrb_toa err("fwrb_interp: %s",interp_toa(p)); #endif } #else fwrb_interp(fp,ip) FILE *fp; Interp *ip; { InterpF inf; int stat; #if dbg_fwrb if((!(ip->ident&IsInterp))||(ip->ident&(IsALL&(~IsInterp)))) err("fwrb_interp: %s",interp_toa(ip)); #endif memset(&inf,'\0',sizeof(inf)); inf.ident = ip->ident; inf.ci = ip->ci; inf.mshap = ip->mshap; inf.size = ip->size; inf.msize = ip->msize; inf.basl = ip->basl; inf.mbhgt = ip->mbhgt; inf.m = ip->m; if((stat=fwrite(&inf,sizeof(InterpF),1,fp))!=1) abort("fwrb_interp: can't fwrite, status %d",stat); #if dbg_fwrb_toa err("fwrb_interp: %s",interp_toa(ip)); #endif } #endif /** Run handling: alloc_run_pool -create pool of free run records free_run_pool - free entire pool alloc_run - allocate a new run from pool free_run - free a specified run (into pool) err_run - print Run (ascii) to stderr err_runb - print Run (ascii) to stderr (after added to blob set) err_runf - print RunF (ascii) to stderr (after added to blob set) err_runfs - print RunFS (ascii) to stderr (after added to blob set) err_run_stats - report statistics to stderr **/ /* RunPool functions: variable-size pool, speed-optimized alloc/free */ /* Initialize pool of Runs with increment `incr' (return F if can't allocate) */ boolean alloc_run_pool(incr,dbg) int incr; boolean dbg; /* trace actions on Runs */ { register Run *crp, *prp; register int i; _RunPool.incr = incr; _RunPool.pools = 1; if((_RunPool.pool=(Run **)malloc(_RunPool.pools*sizeof(Run *)))==NULL) return(F); if((_RunPool.pool[_RunPool.pools-1] = (Run *)malloc(_RunPool.incr*sizeof(Run)))==NULL) { free(_RunPool.pool); return(F); }; _RunPool.next = 0; _RunPool.free = NULL; #if STATS _RunPool.total = 0; #endif _RunPool.dbg = dbg; if(_RunPool.dbg) err("alloc_run_pool: incr%d",_RunPool.incr); return(T); } free_run_pool() { register int i; for(i=0; i<_RunPool.pools; i++) free(_RunPool.pool[i]); free(_RunPool.pool); } /* The ``hard'' case of allocating runs from RunPool: can't be inline */ Run *hard_alloc_run() { _RunPool.pools++; if((_RunPool.pool= (Run **)realloc(_RunPool.pool,_RunPool.pools*sizeof(Run *)))==NULL) abort("alloc_Run: can't realloc"); if((_RunPool.cur=_RunPool.pool[_RunPool.pools-1] = (Run *)malloc(_RunPool.incr*sizeof(Run)))==NULL) abort("alloc_Run: can't malloc"); _RunPool.next=1; *(_RunPool.cur) = empty_Run; return(_RunPool.cur); } int rp_tod(rp) Run *rp; { return((int)rp); } char *runf_toa(rp) RunF *rp; { static char s[80]; char s1[80]; strcpy(s,"RunF "); if(rp==NULL) strcat(s,"NULL"); else { sprintf(s1, "y%d,x[%d,%d] lag(ad%d,bd%d ac%d,bc%d)", rp->y,rp->xs,rp->xe, rp->ad,rp->bd, rp->ac,rp->bc ); strcat(s,s1); }; return(s); } char *runfs_toa(rp) RunFS *rp; { static char s[80]; char s1[80]; strcpy(s,"RunFS "); if(rp==NULL) strcat(s,"NULL"); else { sprintf(s1, "y%d,x[%d,%d] lag(ad%d,bd%d ac%d,bc%d)", rp->y,rp->xs,rp->xe, rp->ad,rp->bd, rp->ac,rp->bc ); strcat(s,s1); }; return(s); } err_run(s,rp) char *s; Run *rp; { fprintf(stderr,"%s ",s); if(rp==NULL) fprintf(stderr,"Run NULL.\n"); else fprintf(stderr, "Run %d: y%d,x[%d,%d] l(n%d) t(o%x ad%d,bd%d ac%d,bc%d)\n", rp_tod(rp), rp->y,rp->xs,rp->xe, rp_tod(rp->n), #if CPU!=CRAY (int)rp->u.o, #else 0, #endif rp->ad,rp->bd, rp_tod(rp->ac), rp_tod(rp->bc) ); } /* print Run after it has been added to Blob set */ err_runb(s,rp) char *s; Run *rp; { fprintf(stderr,"%s ",s); if(rp==NULL) fprintf(stderr,"Run NULL.\n"); else fprintf(stderr, "Run %d: y%d,x[%d,%d] l(n%d) t(no%d ad%d,bd%d ac%d,bc%d)\n", rp_tod(rp), rp->y,rp->xs,rp->xe, rp_tod(rp->n), rp->u.no, rp->ad,rp->bd, rp_tod(rp->ac),rp_tod(rp->bc) ); } err_runf(s,rp) char *s; RunF *rp; { fprintf(stderr,"%s ",s); if(rp==NULL) fprintf(stderr,"RunF NULL.\n"); else fprintf(stderr, "RunF: y%d,x[%d,%d] t(ad%d,bd%d ac%d,bc%d)\n", rp->y,rp->xs,rp->xe, rp->ad,rp->bd, rp->ac,rp->bc ); } err_runfs(s,rp) char *s; RunFS *rp; { RunF rf; rf.y = 0377&rp->y; rf.xs = 0377&rp->xs; rf.xe = 0377&rp->xe; rf.ad = 0377&rp->ad; rf.bd = 0377&rp->bd; rf.ac = 0377&rp->ac; rf.bc = 0377&rp->bc; err_runf(s,&rf); } int runs_of_blob(p,ra,max) Blob *p; RLE_Yrun *ra; int max; { int runs,ri; RunF *rfp; runs = p->runs; if(runs>max) { err("runs_of_blob: max exceeded - skip this blob"); runs = 0; } else if(runs>0) { if(p->ident&Runs_ff) { for(ri=0,rfp=p->r.ff; ri<runs; ri++,rfp++) { ra->y = p->bx.a.y + rfp->y; ra->xs = p->bx.a.x + rfp->xs; ra->xe = p->bx.a.x + rfp->xe; ra++; }; } else { err("runs_of_blob: handle only Runs_ff - skip this blob"); runs = 0; }; }; return(runs); } int no_runs_of_blobl(p) Blobl *p; { int runs; Blob *pp; runs = 0; if(p->mny>0) for(pp=p->fi; pp!=NULL; pp=pp->n) runs += pp->runs; return(runs); } int runs_of_blobl(p,ra,max) Blobl *p; RLE_Yrun *ra; int max; { int runs; Blob *pp; runs = 0; if(p->mny>0) for(pp=p->fi; pp!=NULL; pp=pp->n) runs += runs_of_blob(pp,ra+runs,max-runs); return(runs); } int no_runs_of_char(p) Char *p; { int runs; Blobl bl; runs = 0; bl.mny = p->bmny; bl.fi = p->fi; runs += no_runs_of_blobl(&bl); return(runs); } int runs_of_char(p,ra,max) Char *p; RLE_Yrun *ra; int max; { int runs; Blobl bl; runs = 0; bl.mny = p->bmny; bl.fi = p->fi; runs += runs_of_blobl(&bl,ra,max); return(runs); } /* ascending lexicographic order on y,xs */ int rn_asc(r1,r2) RLE_Yrun *r1,*r2; { if(r1->y < r2->y) return(-1); else if(r1->y==r2->y) { if(r1->xs < r2->xs) return(-1); else if (r1->xs == r2->xs) return(0); else return(1); } else return(1); } RLE_Lines *rlines_of_char(chp) Char *chp; { static RLE_Lines rls; int no_runs,cy,ri; RLE_Run *lr; RLE_Yrun *ra,*cr; RLE_Line *cl; /* count runs */ no_runs = no_runs_of_char(chp); /* allocate runs array */ if((ra=(RLE_Yrun *)malloc(no_runs*sizeof(RLE_Yrun)))==NULL) abort("rlines_of_char: can't malloc ra[%d]",no_runs); runs_of_char(chp,ra,no_runs); /* sort runs ascending on (y,xs) */ qsort(ra,no_runs,sizeof(RLE_Yrun),rn_asc); /* count RLE_lines.mny */ rls.mny = 0; cy=Scoor_MIN; for(ri=0,cr=ra; ri<no_runs; ri++,cr++) if(cr->y!=cy) { rls.mny++; cy = cr->y; }; /* allocate RLE_lines */ if((rls.rla=(RLE_Line *)malloc(rls.mny*sizeof(RLE_Line)))==NULL) abort("rlines_of_page: can't malloc rls.rla[%d]",rls.mny); /* fill in RLE_lines */ cy=Scoor_MIN; cl=rls.rla-1; for(ri=0,cr=ra; ri<no_runs; ri++,cr++) { if(cr->y!=cy) { cl++; cl->y = cy = cr->y; cl->runs = 0; lr = cl->r; }; lr->xs = cr->xs; lr->xe = cr->xe; lr++; cl->runs++; }; free(ra); return(&rls); } int asc_merit(m1,m2) Merit *m1,*m2; { if(*m1 < *m2) return(-1); else if(*m1 > *m2) return(1); else return(0); } /* Word merit is computed as a function of the merit of its Chars. No Chars forces merit to 0.0. The result is dominated by the weakest merit in the Word, slightly improved by the others. */ Merit wordmerit(w) Word *w; { register Char *cp,**cpp; static int m_alloc = 0; static Merit *ma; /* ma[m_alloc] */ int mi; Merit m; double wgt,sumwgt; if(w->cs.mny<=0) return(0.0); if(w->cs.mny>m_alloc) { if(m_alloc==0) { m_alloc=w->cs.mny; if((ma=(Merit *)malloc(m_alloc*sizeof(Merit)))==NULL) abort("wordmerit: can't malloc ma[%d]",m_alloc); } else { m_alloc=w->cs.mny; if((ma=(Merit *)realloc(ma,m_alloc*sizeof(Merit)))==NULL) abort("wordmerit: can't realloc ma[%d]",m_alloc); }; }; for(cp= *(cpp=w->cs.cpa),mi=0; cp!=NULL; cp= *(++cpp),mi++) { if(cp->area==0 || cp->il.mny==0) ma[mi]=0.0; else ma[mi] = cp->il.fi->m; }; qsort(ma,w->cs.mny,sizeof(Merit),asc_merit); #define DOM (5.0) /* The worst merit is DOM times more significant than second worst, which is DOM times more significant than the third worst, and so on. */ m=ma[0]; sumwgt=wgt=1.0; for(mi=1; mi<w->cs.mny; mi++) { m += ma[mi]*(wgt /= DOM); sumwgt += wgt; }; m /= sumwgt; return(m); } WordSet *alloc_wordset(top,cut,cap) double top; /* initial maximum merit (is never reduced) */ double cut; /* cut ratio: don't keep merit < cut*top */ int cap; /* capacity: maximum no. at a time (0 ==> no limit) */ { WordSet *res; if((res=(WordSet *)malloc(sizeof(WordSet)))==NULL) abort("alloc_wordset: can't"); *res = empty_WordSet; res->top = top; res->cut = cut; if((res->cap = cap)==0) res->cap=INT_MAX; return(res); } int free_wordset_etc(s,etc) WordSet *s; Ident etc; { int high; free_words_etc(&(s->ws),etc); high = s->high; free(s); return(high); } /* Find the maximum-merit word in the set; among ties, pick the first seen. */ Word *find_max_wordset(s) WordSet *s; { register Word *max,**wpp; max=NULL; if(s->ws.mny>0) for(wpp=s->ws.wpa; *wpp!=NULL; wpp++) { if(max==NULL || max->m < (*wpp)->m) max=(*wpp); }; return(max); } /* Find the maximum-merit word in the set; among ties, pick the last seen. */ Word *find_min_wordset(s) WordSet *s; { register Word *min,**wpp; min=NULL; if(s->ws.mny>0) for(wpp=s->ws.wpa; *wpp!=NULL; wpp++) { if(min==NULL || min->m >= (*wpp)->m) min=(*wpp); }; return(min); } /* Insert a Word (without duplicating it). Update top, min, max, & high. If the new word's merit is equal to the current maximum, it does not become become the new maximum. If the new word's merit is equal to the current minimum, it becomes the new minimum. */ put_wordset(w,s) Word *w; /* must have w->m set up */ WordSet *s; { insert_word(w,&(s->ws)); if(max_wordset(s)==NULL || max_wordset(s)->m < w->m) { max_wordset(s) = w; if(s->top < max_wordmerit(s)) s->top = max_wordmerit(s); }; if(min_wordset(s)==NULL || min_wordset(s)->m >= w->m) min_wordset(s) = w; if(s->high < s->ws.mny) s->high = s->ws.mny; } /* Remove a Word (without freeing it). Maintain min/max, but don't prune items. Also, don't lower top or high. */ Word *get_wordset(w,s) Word *w; WordSet *s; { if(w==NULL || s->ws.mny==0) return(NULL); remove_word(w,&s->ws); if(s->ws.mny==0) { max_wordset(s) = NULL; min_wordset(s) = NULL; } else { if(w==max_wordset(s)) max_wordset(s) = find_max_wordset(s); if(w==min_wordset(s)) min_wordset(s) = find_min_wordset(s); }; return(w); } /* Remove a Word (without freeing it). Maintain min/max. Don't lower top. */ Word *remove_wordset(w,s,n) Word *w; WordSet *s; char *n; { register Word *gw; #if dbg_ws if(w!=NULL) err("remove_wordset: %X %s",w,word_toa(w)); else err("remove_wordset: NULL"); #endif gw=get_wordset(w,s); #if dbg_ws err_wordset(s,n); #endif return(gw); } /* Check whether a given Word is identical to any already in a given set. Word *w must have its hash key set up. */ boolean member_wordset(w,s) Word *w; WordSet *s; { register Word **ww; if(s->ws.mny>0) { for(ww=s->ws.wpa; (*ww)!=NULL; ww++) { if(w->hash==(*ww)->hash && eq_word(w,(*ww))) return(T); }; }; return(F); } /* Insert a Word into a set, maintaining uniqueness, a ``range'' property, and a maximum capacity. Uniqueness is maintained by refusing to insert words that are identical (eq_word()) to a word already in the set (or in set `u'). The range property is that every word in the set must have merit no less than `s->cut' times the lifetime maximum for the set `s->top'. Maximum capacity is maintained as follows: if insertion would mean more members than `cap', then either (a) the insertion is refused (if its merit is less than the current `min', or (b) the current `min' is deleted (and silently freed in its entirety), and the insertion occurs. The inserted Word is not duplicated. If, as a result of an insertion, some of its words no longer satisfy the range property, they are silently removed (and freed in their entirety). Return T iff the Word is actually inserted. */ boolean insert_wordset(w,s,n,u) Word *w; WordSet *s; char *n; /* name of set `s' */ WordSet *u; /* if !=NULL, also check uniqueness here */ { Word *fr; #if dbg_ws err("insert_wordset: %X %s",w,word_toa(w)); #endif if((w->m = wordmerit(w)) >= (s->cut * s->top)) { w->hash = hash_word(w); if(member_wordset(w,s) || (u!=NULL&&member_wordset(w,u))) /* don't insert */ return(F); if(s->ws.mny==s->cap) /* at capacity */ { if(w->m <= min_wordmerit(s)) /* too poor */ return(F); else { fr = remove_wordset(min_wordset(s),s); free_word_etc(fr,IsALL); }; }; put_wordset( w, s ); if(max_wordset(s)==w) /* this has become the new maximum */ { while(min_wordmerit(s) < (s->cut * s->top)) { fr = remove_wordset(min_wordset(s),s); free_word_etc(fr,IsALL); }; }; #if dbg_ws err_wordset(s,n); #endif return(T); } else { #if dbg_ws err_wordset(s,n); #endif return(F); }; } err_wordset(s,n) WordSet *s; char *n; /* name of set */ { char m1[10],m2[10]; register Word *wp,**wpp; fprintf( stderr,"WordSet %s: t%g c%g [%s/%X,%s/%X] m%d h%d: ", n, s->top,s->cut, strcpy(m1,merit_toa(max_wordmerit(s))),max_wordset(s), strcpy(m2,merit_toa(min_wordmerit(s))),min_wordset(s), s->ws.mny,s->high ); if(s->ws.mny>0) for(wp= *(wpp=s->ws.wpa); wp!=NULL; wp= *(++wpp)) fprintf(stderr,"%X/%s/%d ",wp,merit_toa(wp->m),wp->cs.mny); fprintf(stderr,"\n"); } translate_txtln(lp,off) Txtln *lp; Sp off; { lp->bx = *translate_bbx(&lp->bx,off); lp->basl += off.y; translate_chars(lp->cs,off); } translate_chars(csp,off) Chars *csp; Sp off; { register Char *cp,**cpp; for(cp= *(cpp=csp->cpa); cp!=NULL; cp= *(++cpp)) translate_char(cp,off); } translate_char(cp,off) Char *cp; Sp off; { cp->bx = *translate_bbx(&cp->bx,off); translate_blobl(cp,off); } translate_blobs(b,off) Blobs *b; Sp off; { register Blob *bp,**bpp; if(b->mny>0) for ( bp= *(bpp=b->bpa); bp!=NULL; bp= *(++bpp) ) translate_blob(bp,off); } translate_blobl(cp,off) Char *cp; Sp off; { int bi; register Blob *bp; for(bi=0,bp=cp->fi; bi<cp->bmny&&bp!=NULL; bi++,bp=bp->n) translate_blob(bp,off); } translate_blob(bp,off) Blob *bp; Sp off; { bp->bx = *translate_bbx(&bp->bx,off); } 0707070035351137141006640007620000050000010262240476773367000000700000107063Text.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* Text.h - typedefs, constants, and function declarations for document-images (see Text.c for companion functions.) INCLUDES requires prior: #include "stdocr.h" */ #define dbg_fwrb_toa (F) /* err("%s",R_toa()) for each record written */ #define dbg_frdb_toa (F) /* err("%s",R_toa()) for each record read */ #define DIM_VERSION (0) /* current version no. of Dim-file format */ #include "Bfeats.h" #define Ident int /* identification bits [MUST BE >=32 bits] */ #define fwri_Ident(F,V) fwri_uint4((F),(V)) #define frdi_Ident(F) frdi_uint4(F) /* Ident bits */ /* identifies external file record type(s) */ #define IsPage 04000000000 #define IsBlock 02000000000 #define IsTxtln 01000000000 #define IsWord 00020000000 #define IsChar 00400000000 #define IsBlob 00200000000 #define IsRun 00100000000 /* should be IsRuns or IsLag */ #define IsRuns (IsRun) #define IsInterp 00040000000 /* Char interpretation */ #define IsBdy 00010000000 #define IsShapes 00004000000 #define IsLag 00002000000 #define IsBfeats 00001000000 #define IsSfeats 00000400000 #define IsWordInterp 00000200000 /* Runs: set in Blob records' ids. At most one of these may be set in main memory. Only Runs_ff or Runs_g4 may be set in peripheral file format. */ #define Runs_f 00000010000 /* Runs are in list, starting *.r.f */ #define Runs_ff 00000020000 /* RunFs are in array, at *.r.ff */ #define Runs_seek 00000040000 /* Runs are still in file, at *.seek */ #define Runs_g4 00000100000 /* Runs are in CCITT Group 4 format */ /* CCITT Group 4 format in peripheral files consists of (a) an unsigned long count, then (b) that many bytes of Group 4 encoding exactly as in CCITT Recommendation T.6, except that no EOFB code is appended, since the end of the bitmap can be detected using the bounding box of the owning Blob. Instead, the last scan line of the bitmap is merely padded to the nearest full byte with '0' bits. This compresses the representation by about a factor of 8 on average, compared to RunF/RunFS encoding. */ #define IsALL (IsPage|IsBlock|IsTxtln|IsWord|IsChar|IsBlob|IsRun|IsBdy|IsInterp|IsShapes|IsLag|IsBfeats|IsSfeats|IsWordInterp) #define IsNONE 0 /* Enable optional debugging-support code to maintain a count of selected record types that are allocated using alloc_* free_* and dup_* functions. The counts are in units of records, not bytes. By design, has no effect at all on correctness. */ #define ALLOC_CENSUS (0) #if ALLOC_CENSUS typedef struct Census { int Page_mny; int Block_mny; int Txtln_mny; int Word_mny; int Char_mny; int Blob_mny; int Run_mny; int Interp_mny; int Bfeats_mny; int BMask_mny; } Census; #define Init_Census {0,0,0,0,0,0,0,0,0,0} #if MAIN Census empty_Census = Init_Census; Census _CENSUS = Init_Census; #else extern Census empty_Census; extern Census _CENSUS; #endif #define alloc_census(id,n) _CENSUS./**/id/**/_mny += (n) #define free_census(id,n) _CENSUS./**/id/**/_mny -= (n) #define err_census(S,C) err("%s P%d B%d l%d w%d c%d b%d r%d i%d bf%d bm%d",\ S,(C)->Page_mny,(C)->Block_mny,(C)->Txtln_mny,(C)->Word_mny,\ (C)->Char_mny,(C)->Blob_mny,(C)->Run_mny,(C)->Interp_mny,\ (C)->Bfeats_mny,(C)->BMask_mny ) #define err_census_all err_census("allocated: ",&(_CENSUS)) #define err_census_rec(rp) { \ Census *cs; cs = (Census *)census_rec((rp)); \ err_census(ident_toa((rp)->ident),cs); \ } #else #define alloc_census(i,n) #define free_census(i,n) #define err_census(s,c) #define err_census_all #define err_census_rec(r) #endif /* Most record types can own an ASCII label, which is simply a '\0'-terminated string. Its uses are varied. */ #define MAX_LABEL_LEN 128 /* maximum no. characters in a label string */ #if FWRI #if dbg_fwrb_toa #define fwrb_label(F,L) { \ fwri_str((F),(L)); \ err("fwrb_label: \"%s\"",(L)); \ } #else #define fwrb_label(F,L) { \ fwri_str((F),(L)); \ } #endif #else #if dbg_fwrb_toa #define fwrb_label(F,L) { \ fputs((L),(F)); \ fputc('\0',(F)); \ err("fwrb_label: \"%s\"",(L)); \ } #else #define fwrb_label(F,L) { \ fputs((L),(F)); \ fputc('\0',(F)); \ } #endif #endif char *frdb_label(); /* A boundary is an ordered list of vertices. In some uses, it is assumed to close: in this case, the first point is not repeated at the end. `vn' counts the no. vertices. bdy_trace omits consecutive duplicates and compresses horizontal and vertical runs. `per' counts the no. of pixels on the 8-connected boundary. An attempt has been made not to count consecutive duplicate pixels, but this may be buggy. `ren' counts the number of run-ends touched. Each run contributes two ends, even if it is one pixel long. The sum of ren-counts among all bdys for a blob should equal exactly twice the no. runs. Note that vn<=per and vn<=2*ren, and (probably) ren<=per. A ``smoothed'' version (courtesy of John Hobby) may be given in s[], expressed in fractional pixels. */ typedef struct Bdy { Ident ident; /* shows type of boundary */ Bbx bx; /* bounding box (usually relative to blob's bx.a) */ long per; /* no. pixels in 8-connected perimeter */ int ren; /* no. run-ends touched */ int vn; /* no. distinct vertices in v[] */ Sp *v; /* array of vn+1 vertices, v[0]==v[vn] (malloc space) */ short fr; /* fraction of pixels used in smoothed outline */ int sn; /* no. distinct smoothed vertices in s[] */ Sp *s; /* array of sn+1 vertices, s[0]==s[sn] (malloc space) */ int an; /* no. vertices in polygonal approximation */ Sp **ap; /* approx'n: array of an ptrs into v[] (in malloc space) */ float err; /* error tolerance used for approximation */ int hn; /* no. vertices in convex hull of polygonal approx'n */ Sp ***hpp; /* convex hull: array of hn ptrs into ap[] (malloc) */ struct Bdy *n; /* for use when a member of a linked-list */ } Bdy; #define Init_Bdy {IsBdy,Init_Bbx,0,0,0,NULL,1,0,NULL,0,NULL,0.0,0,NULL,NULL} #if MAIN Bdy empty_Bdy = Init_Bdy; #else extern Bdy empty_Bdy; #endif #define Bdy_verts 00000000001 /* vertices */ #define Bdy_approx 00000000002 /* polygonal approx'n */ #define Bdy_hull 00000000004 /* convex hull */ #define Bdy_ALL (Bdy_verts|Bdy_approx|Bdy_hull) #define Bdy_ccw 00000000100 /* winding order is counter-clockwise*/ #define Bdy_half 00000000200 /* uses half-pixel boundary points */ /* A boundaries-set is an ordered list of boundaries. In some uses, they are used to enclose a connected region: in this case, all are closed, and the first is conventionally the exterior and the others are interior boundaries. The interior is then always to the left of the boundary: that is, the exterior boundary is oriented counter- clockwise, and the interior boundaries clockwise */ typedef struct Bdys { int mny; /* no. boundaries */ long per; /* perimeter of all bdys */ Bdy *b; /* array of boundaries (malloc space) (sometimes first) */ } Bdys; #define Init_Bdys {0,0,NULL} #if MAIN Bdys empty_Bdys = Init_Bdys; #else extern Bdys empty_Bdys; #endif /* A boundary edge is an ordered pair of vertices along a boundary. It implicitly describes an 8-connected sequence of pixels from a to b, inclusive. Also used for straight-line approximations to the set of pixels, and the convex hull of such an approximation. */ typedef struct BdyEdge { Bdy *byp; /* boundary to which it belongs */ Sp *ap,*bp; /* ptrs into byp->v */ long per; /* perimeter: no. 8-connected pixels */ Pp ctr; /* centroid */ Radians ang; /* ls-fitted angle (directed roughly from a to b) */ Pp a; /* endpoints a & b (with sub-pixel precision) */ Pp b; } BdyEdge; #define Init_BdyEdge {NULL,NULL,NULL,0,Init_Zero_Pp,0.0,Init_Zero_Pp,Init_Zero_Pp} #if MAIN BdyEdge empty_BdyEdge = Init_BdyEdge; #else extern BdyEdge empty_BdyEdge; #endif /* Ordered set of BdyEdges */ typedef struct BdyEdges { int mny; BdyEdge **pa; /* NULL-terminated array of pointers to BdyEdges */ } BdyEdges; #define Init_BdyEdges {0,NULL} #if MAIN BdyEdges empty_BdyEdges = Init_BdyEdges; #else extern BdyEdges empty_BdyEdges; #endif /* Moments of a region (or boundary-list) of pixels */ typedef struct Moments { /* 0th moment */ int M00; /* area: sum of 1 */ /* 1st moments */ int M10; /* sum of xi */ int M01; /* sum of yi */ Pp c; /* centroid: M10/M00, M01/M00 */ /* 2nd moments (relative to centroid) */ float M20; /* sum of rxi*rxi */ float M11; /* sum of rxi*ryi */ float M02; /* sum of ryi*ryi */ Radians a; /* orientation angle, in [-PI/2,PI/2) (radians) */ Pp d; /* directional vector of principal axis */ } Moments; #define Init_Moments {0,0,0,{0.0,0.0},0.0,0.0,0.0,0.0,{0.0,0.0}} #if MAIN Moments zero_Moments = Init_Moments; #else extern Moments zero_Moments; #endif /* functions in Text.c */ Bdy *alloc_bdy(); Bdys *alloc_bdys(); /* functions in Bdy.c */ Bdys *dup_bdys_etc(); Bdy *dup_bdy_etc(); Bdys *boundaries(); char *moments_toa(); Moments *bdy_moments(); boolean fit_bdyedge(); BdyEdge *dup_bdyedge(); BdyEdge *append_bdyedge(); remove_bdyedge(); free_bdyedges(); BdyEdges *dup_bdyedges(); /* Each Run is initially inserted into a `line set', owned by its scan Line. Later, as connections are discovered, it joins a `tree set'. When the forest of trees of which it is a part is finally complete, the Run is removed from its `line set', and added to a `blob set'. */ typedef struct Run { /* internal (main memory) record */ Scoor y, xs, xe; /* coordinates of black interval (y,[xs,xe]) */ struct Run *n; /* line & blob sets: next Run */ unsigned short ad, bd; /* tree set: above,below degrees (no. conn'd)*/ struct Run *ac, *bc; /* tree set: above,below leftmost connections */ union { struct Tree *o; /* tree set: owner Tree */ int no; /* blob set: sequence no. 0,1,... in set */ } u; /* (overlain fields) */ } Run; #define Init_Run {0,0,0,NULL,0,0,NULL,NULL} #if MAIN Run empty_Run = Init_Run; #else extern Run empty_Run; #endif /* Peripheral file format. `ac' and `bc' are relative to the position of this run in the canonical run order. */ typedef struct RunF { /* external (peripheral file) record (full size) */ Scoor y, xs, xe; /* coordinates of black interval (y,[xs,xe]) */ unsigned short ad, bd; /* above,below degrees */ unsigned short ac, bc; /* above,below leftmost connections (indices) */ } RunF; #define Init_RunF {0,0,0,0,0,0,0} #if MAIN RunF empty_RunF = Init_RunF; #else extern RunF empty_RunF; #endif #define fwri_RunF(F,P) { \ fwri_Scoor((F),(P)->y); \ fwri_Scoor((F),(P)->xs); \ fwri_Scoor((F),(P)->xe); \ fwri_uint2((F),(P)->ad); \ fwri_uint2((F),(P)->bd); \ fwri_uint2((F),(P)->ac); \ fwri_uint2((F),(P)->bc); \ } #define frdi_RunF(F,P) ( feof(F)? 0 : ( \ (P)->y=frdi_Scoor(F), \ (P)->xs=frdi_Scoor(F), \ (P)->xe=frdi_Scoor(F), \ (P)->ad=frdi_uint2(F), \ (P)->bd=frdi_uint2(F), \ (P)->ac=frdi_uint2(F), \ (P)->bc=frdi_uint2(F), \ (ferror(F)? -errno: 1) ) ) /* In `well-behaved' text, the overwhelming majority of Blobs are small enough that all their Runs can be encoded using character data fields, a factor of two saving, which is important since a dense IEEE proceedings page blob file would otherwise require 2.3Mbytes */ typedef struct RunFS { /* external (peripheral file) record (small size) */ unsigned char y, xs, xe;/* coordinates of black interval (y,[xs,xe]) */ unsigned char ad, bd; /* above,below degrees */ unsigned char ac, bc; /* above,below leftmost connections (indices) */ } RunFS; #define Init_RunFS {0,0,0,0,0,0,0} #if MAIN RunFS empty_RunFS = Init_RunFS; #else extern RunFS empty_RunFS; #endif #define fwri_RunFS(F,P) { \ fwri_uint1((F),(P)->y); \ fwri_uint1((F),(P)->xs); \ fwri_uint1((F),(P)->xe); \ fwri_uint1((F),(P)->ad); \ fwri_uint1((F),(P)->bd); \ fwri_uint1((F),(P)->ac); \ fwri_uint1((F),(P)->bc); \ } #define frdi_RunFS(F,P) ( feof(F)? 0: ( \ (P)->y=frdi_uint1(F), \ (P)->xs=frdi_uint1(F), \ (P)->xe=frdi_uint1(F), \ (P)->ad=frdi_uint1(F), \ (P)->bd=frdi_uint1(F), \ (P)->ac=frdi_uint1(F), \ (P)->bc=frdi_uint1(F), \ (ferror(F)? -errno: 1) ) ) /* Set of runs. PROPOSED NEW FORMAT. Not yet incorporated widely. */ typedef struct Runs { Ident ident; /* IsRuns & Runs_fi, Runs_ff, Runs_fs, or Runs_sk flags */ int mny; /* no. runs */ union { /* access to runs */ struct Run *fi; /* first run of singly-linked list */ struct RunF *ff; /* top of RunF[mny] array */ struct RunFS *fs; /* top of RunFS[mny] array */ long sk; /* seek(F,seek,0) will find them in file F */ } r; } Runs; #define Init_Runs {IsRuns,0} /* NOTE: can't initialize union */ #if MAIN Runs empty_Runs = Init_Runs; #else extern Runs empty_Runs; #endif /* INTERNAL management */ #if !MAIN extern #endif struct { int incr; /* size of each pool[i] */ int pools; /* no. of pools allocated */ Run **pool; /* malloc space Run pool[pools][0..incr-1] */ int next; /* the next avail Run is: pool[pools-1][next] */ Run *free; /* head of free lifo list (NULL if none) */ Run *cur; /* most-recently allocated Run */ int total; /* total no. ever allocated */ boolean dbg; } _RunPool #if MAIN = {0,0,NULL,0,NULL,NULL,0,F} #endif ; /* Run management routines (Text.c) */ boolean alloc_run_pool(); free_run_pool(); Run *hard_alloc_run(); err_run(); err_runb(); err_runf(); err_runfs(); err_run_stats(); /* Allocate a Run from the RunPool (returns (Run *)) -- mostly inline */ #define alloc_run() ( _RunPool.total++, (_RunPool.free!=NULL)? \ (_RunPool.cur=_RunPool.free,_RunPool.free=_RunPool.cur->n, \ *(_RunPool.cur)=empty_Run,_RunPool.cur): \ ( (_RunPool.next<_RunPool.incr)? \ (_RunPool.cur=_RunPool.pool[_RunPool.pools-1]+(_RunPool.next++), \ *(_RunPool.cur)=empty_Run,_RunPool.cur): \ hard_alloc_run() ) ) /* Free a Run back into the RunPool -- entirely inline */ #define free_run(rp) { (rp)->n = _RunPool.free; _RunPool.free = (rp); } /* EXTERNAL file format: If BlobF.runs is zero, then conventionally the Runs have simply been omitted. The RunF.y, RunF.xs, & RunF.xe coordinates are offsets from BlobF.bx.a (their blob's left-top corner). RunF.ac & RunF.bc index into an array of only those RunF records belonging to the current BlobF, in ascending lexicographic order on (RunF.y,RunF.xs) -- so that they are in the range [0,BlobF.runs-1]. IMPROVEMENTS: */ /* some subroutines are too lazy to handle indefinitely large blobs */ #define Runs_Max 10000 /* A Blob is (formally) a maximal 8-connected set of black pixels. The connectivity algorithm finds them in strictly increasing order on (y,xe) of its Run with highest (y,xe). */ typedef struct Blob { /* internal (main memory) record */ Ident ident; /* identification bits */ Seq no; /* blob sequence no */ Bbx bx; long area; long per; struct Blob *n; /* free set: next blob */ Merit m; /* Only used locally (not for peripheral file) */ Runs *rsp; /* runs (not yet used) */ Bdys *bdsp; /* boundaries (in malloc space); NULL if none */ /* presently in use (but planned to be replaced by Runs) */ int runs; union { /* to find runs */ struct Run *f; /* blob set: first run */ struct RunF *ff; /* top of RunF array */ long seek; /* seek(f,seek,0) will find them */ } r; } Blob; #define Init_Blob {IsBlob,0,Init_Bbx,0,0,NULL,0.0,NULL,NULL,0,} #if MAIN Blob empty_Blob = Init_Blob; #else extern Blob empty_Blob; #endif typedef struct Blobs { /* Blob set */ int mny; /* the number of pointers in set */ Blob **bpa; /* pts to NULL-terminated array[mny+1] of pointers */ } Blobs; #define Init_Blobs {0,NULL} #if MAIN Blobs empty_Blobs = Init_Blobs; #else extern Blobs empty_Blobs; #endif /* Singly-linked list of Blobs. Only forward `next' links Blob.n are used. */ typedef struct Blobl { /* Blob list */ int mny; /* the number in set */ Blob *fi; /* to first */ Blob *la; /* to last */ } Blobl; #define Init_Blobl {0,NULL,NULL} #if MAIN Blobl empty_Blobl = Init_Blobl; #else extern Blobl empty_Blobl; #endif typedef struct BlobF { /* external file format */ Ident ident; /* identification bits: IsBlob must be set */ Bbx bx; long area; long per; int runs; /* no. runs to follow */ short bdys; /* no. bdys to follow */ } BlobF; /* Blob identification bits */ #define Blob_lm 00000000001 /* touches left margin */ #define Blob_rm 00000000002 /* touches right margin */ #define Blob_tm 00000000004 /* touches top margin */ #define Blob_bm 00000000010 /* touches bottom margin */ #define Blob_chopt 00000000020 /* chopped (at the top) */ #define Blob_chopb 00000000040 /* chopped (at the bottom) */ #define Blob_chopl 00000002000 /* chopped (at the left) */ #define Blob_chopr 00000004000 /* chopped (at the right) */ #define Blob_small 00000000200 /* its runs (can be) compressed x2 */ #define Blob_local 00000000400 /* unassigned: avail for local pgm use */ /* INTERNAL management: */ int hi_blob_no; /* current highest blob no */ /* Blobs are allocated from a pool of free ones */ int blob_max; Blob *blob_pool; Blob blob_fr; /* head of list of free blobs */ int blob_fr_mny; int blob_hi; /* high-water mark in blob pool */ int blob_chopped; /* total no. of blobs that were chopped */ boolean blob_debug; /* debug traces? */ /* EXTERNAL file format: A Blob file consists of an arbitrary number of: BlobF record, followed by BlobF.runs instances of: RunF record If BlobF.runs is zero, then conventionally the Runs have simply been omitted. The RunF.y, RunF.xs, & RunF.xe coordinates are relative offsets from BlobF.bx.a (their blob's left-top corner). RunF.ac & RunF.bc index into an array of only those RunF records belonging to the current BlobF, in ascending lexicographic order on (RunF.y,RunF.xs) -- so that they are in the range [0,BlobF.runs-1]. If ad(or, bd)==0, the ac(or, bc) is undefined (conn sets them conventionally to 0). */ /* Blob management routines (conBlob.c) */ Blob *alloc_blob(); free_blob(); boolean alloc_blob_pool(); free_blob_pool(); Blob *alloc_pool_blob(); free_pool_blob(); out_blob(); fwrb_blob_etc(); boolean frdb_blob_etc(); boolean frdb_runfs(); err_blob(); err_blob_runs(); err_blob_runfs(); err_blob_briefly(); err_blobf(); err_blob_stats(); boolean blob_small(); /* Compute height-above-baseline in ems of Char *cp w.r.t. Txtln *lp, on a page of y-resolution res. The txtln's `basl' & `size' must be set up. */ #define char_bhgt(cp,lp,res) \ ((((cp)->bx.b.y - (lp)->basl)/(double)(res)*INS_PER_PT*(lp)->size)) /* an Interpretation of a Char */ typedef struct Interp { Ident ident; struct Cl *clp; struct Class *clsp; ClassId ci; /* class id (font, size, name, variant) */ Merit mshap; /* shape merit in [0,1] */ Pts size; /* implied text size */ Merit msize; /* size merit in [0,1] */ Scoor basl; /* implied absolute baseline location */ Merit mbhgt; /* height-above-baseline merit in [0,1] */ Merit m; /* match merit (due to mshap, msize, & mbhgt) */ Prob p; /* approximate probability */ struct Interp *n; /* next in singly-linked list */ } Interp; #define Init_Interp {IsInterp,NULL,NULL,Init_ClassId,0.0,0.0,0.0,0,0.0,0.0,0.0,NULL} #if MAIN Interp empty_Interp = Init_Interp; #else extern Interp empty_Interp; #endif /* Interp.ident flags: */ #define Interp_spelled 00000000001 /* has passed a spelling check */ #define free_interp(i) {free((i)); free_census(Interp,1); } typedef struct InterpF { Ident ident; ClassId ci; /* class id (font, size, name, variant) */ Merit mshap; /* shape merit */ Pts size; /* implied text size (in points) */ Merit msize; /* size merit */ Scoor basl; /* implied baseline location */ Merit mbhgt; /* height-above-baseline merit */ Merit m; /* match merit (due to shp, siz, hgt) */ } InterpF; /* a list of interpretations */ typedef struct Interpl { short mny; /* no. in list */ struct Interp *fi; /* first in list (mny==0 -> fi==NULL) */ } Interpl; #define Init_Interpl {0,NULL} #if MAIN Interpl empty_Interpl = Init_Interpl; #else extern Interpl empty_Interpl; #endif /* a set of interpretations */ typedef struct Interps { short mny; /* no. in set */ struct Interp **pa; /* NULL-terminated array of ptrs (malloc spc) */ Merit m; /* combined merit (normalized product) */ } Interps; #define Init_Interps {0,NULL,0.0} #if MAIN Interps empty_Interps = Init_Interps; #else extern Interps empty_Interps; #endif typedef struct Shapes { short mny; /* no. items in set */ short alloc; /* no. items that can fit in array (alloc>=mny) */ Nb_s *sa; /* ptr to contiguous array (malloc space) */ } Shapes; #define Init_Shapes {0,0,NULL} #if MAIN Shapes empty_Shapes = Init_Shapes; #else extern Shapes empty_Shapes; #endif #define SH_INCR (20) /* Shapes are allocated by this increment */ #define init_sh(sh) { \ (sh)->alloc = SH_INCR; \ if(((sh)->sa=(Nb_s *)malloc((sh)->alloc*sizeof(Nb_s)))==NULL) \ abort("can't alloc sh->sa[%d]",(sh)->alloc); \ (sh)->mny = 0; \ } #define add_sh(s,sh) { \ if((sh)->mny==(sh)->alloc) { \ (sh)->alloc += SH_INCR; \ if(((sh)->sa=(Nb_s *)realloc((sh)->sa,(sh)->alloc*sizeof(Nb_s)))==NULL) \ abort("can't alloc (sh)->sa[%d]",(sh)->alloc); \ }; \ (sh)->sa[(sh)->mny++] = *(s); \ } /* Parameters governing the pseudo-random generation of a Char image using a 1st-order statistical model of imaging. */ typedef struct RanParms { short res_x; /* -r resolution (scanner pels/inch) */ short res_y; /* (for now, equal to res_x) */ Pts size; /* -p size of text */ Radians skew; /* -a skew angle */ Ems bhgt; /* -b height above baseline */ float blur; /* -e blurring std err (scanner pels) */ float jitter; /* -j jitter std err (scanner pels) */ float kern; /* -k kerning std err (scanner pels) */ float speckle; /* -s pel-wise additive noise std err (scanner pels) */ float thresh; /* -t threshold for binarization */ float xscale; /* -x horizontal scaling (dimensionless) */ float yscale; /* -y vertical scaling (dimensionless) */ } RanParms; #define Init_RanParms {0,0,0.0,0.0,0.0,0.7,0.0,0.0,0.125,0.25,1.0,1.0} #if MAIN RanParms empty_RanParms = Init_RanParms; #else extern RanParms empty_RanParms; #endif RanParms *alloc_ranparms(); RanParms *dup_ranparms(); char *ranparms_toa(); RanParms *ato_ranparms(); fwrb_ranparms(); int frdb_ranparms(); /* Char - a character: isolated, elementary symbol of the writing system; linguists might call this a `graph' */ typedef struct Char { Ident ident; /* feature bits */ Bbx bx; Scoor csp; /* space before character in Txtln (abs. coords) */ long area; /* no. pixels */ long per; /* perimeter (all bdys) */ Scoor basl; /* baseline (absolute coordinates, local copy) */ /* next should be Blobl */ int bmny; /* no. blobs in Char */ struct Blob *fi; /* 1st in list (p.n ptrs) (bmny==0 -> fi==NULL) */ Pval *sfv; /* scalar-features (SFv) */ Shapes sh; /* set of shapes (size- & loc'n-invariant) */ Bfeats *bfsp; /* binary features */ RanParms *rp; /* randomizing parameters */ Interpl il; /* interpretations */ char *l; /* label (ASCII string in malloc space) */ } Char; #define Init_Char {IsChar,Init_Bbx,0,0L,0L,Scoor_MIN,0,NULL,NULL,Init_Shapes,NULL,NULL,Init_Interpl,NULL} #if MAIN Char empty_Char = Init_Char; #else extern Char empty_Char; #endif /* Char.ident flags: */ #define Char_spelled 00000000001 /* Its 1st Interp is in correct spelling */ #define Char_confused 00000000002 /* The classifier may have confused this */ #define Char_termhyp 00000000004 /* a terminal hyphen of its Word */ #define Char_omit 00000000010 /* can be omitted */ #define Char_label 00000000020 /* has an ASCII string label */ #define Char_ranparms 00000000040 /* has RanParms */ #define Char_split 00000000100 /* resulted from splitting a Char */ #define Char_merged 00000000200 /* resulted from merging Chars */ typedef struct Chars { int mny; /* mny==0 -> cpa==NULL */ Char **cpa; /* pts to NULL-term'd array of ptrs (in malloc space) */ } Chars; #define Init_Chars {0,NULL} #if MAIN Chars empty_Chars = Init_Chars; #else extern Chars empty_Chars; #endif /* CharF - Char external file format */ typedef struct CharF { Ident ident; /* feature bits: IsChar must be set */ Bbx bx; Scoor csp; /* space before character in Txtln (abs. coords) */ long area; long per; short bmny; /* no. blobs to follow */ short imny; /* no. interpretations (follows immediately) */ short sfmny; /* no. scalar features (follows immediately) */ short shmny; /* no. shape features (follows immediately) */ short bfmny; /* no. binary features (follows immediately) */ /* if ident&Char_ranparms, RanParms follows CharF */ /* if ident&Char_label, label follows CharF ('\0'-terminated string) */ } CharF; Char *alloc_char(); /* in Text.c */ Char *append_char(); Char *insert_char(); Char *insert_char_word(); Char *dup_char(); Char *dup_char_etc(); Chars *append_chars(); Chars *dup_chars_etc(); typedef struct Words { int mny; /* mny==0 -> wpa==NULL */ struct Word **wpa; /* pts to NULL-term'd array of ptrs */ } Words; #define Init_Words {0,NULL} #if MAIN Words empty_Words = Init_Words; #else extern Words empty_Words; #endif /* Word - one or more Chars lying in a textline close together. wsp (word space) is always >=0 and is scaled by xheight (of Txtln) */ typedef struct Word { Ident ident; /* feature bits */ Bbx bx; float wsp; /* space before word (multiple of wst*em) */ Merit m; /* Word merit (function of its Char's merits) */ Prob p; /* probability */ Words ws; /* set of alternative segmentations */ Chars cs; Blobs bs; char *l; /* label (ASCII string in malloc space) */ int hash; /* hash key for fast equality checking */ } Word; #define Init_Word {IsWord,Init_Bbx,0.0,0.0,0.0,Init_Words,Init_Chars,Init_Blobs,NULL,0} #if MAIN Word empty_Word = Init_Word; #else extern Word empty_Word; #endif /* Word-interpretation (as printable ASCII string). All string fields must point to malloc-space strings. */ typedef struct WordInterp { Ident ident; /* identifies word type */ char *s; /* entire string = pp+by+po+ps */ char *pp; /* punctuation prefix */ char *by; /* body of word */ char *po; /* possessive ('s 'S) or negative (n't N'T) suffix */ char *ps; /* punctuation suffix */ } WordInterp; #define Init_WordInterp {IsWordInterp,NULL,NULL,NULL,NULL,NULL} #if MAIN WordInterp empty_WordInterp = Init_WordInterp; #else extern WordInterp empty_WordInterp; #endif WordInterp *dup_wordinterp_etc(); /* Word.ident & WordInterp.ident flags: */ #define Word_spelled 00000000001 /* by spells correctly */ #define Word_wf 00000000002 /* s is well-formed */ #define Word_ok 00000000004 /* s is ok ("acceptable") */ #define Word_numeric 00000000010 /* by is numeric */ #define Word_initcap 00000000020 /* by has initial capital */ #define Word_allcaps 00000000040 /* by is all caps */ #define Word_hyphens 00000000100 /* by has imbedded hyphens */ #define Word_slashes 00000000200 /* by has imbedded slashes */ #define Word_endsent 00000000400 /* end of sentence: ps has .!? */ #define Word_termhyp 00000001000 /* some interpretation ends with hyphen */ #define Word_label 00000002000 /* has an ASCII string label */ #define Word_allalp 00000004000 /* s is all alphabetic */ #define Word_bodalp 00000010000 /* by is all alphabetic */ /* WordF - Word external file format */ typedef struct WordF { Ident ident; /* feature bits: IsWord must be set */ Bbx bx; float wsp; /* space before word (multiple of thr) */ float m; /* merit */ short wmny; /* no. Words (in Word.ws) to follow this Word */ short cmny; /* no. Chars to follow this Word */ short bmny; /* no. Blobs to follow this Word */ /* if ident&Word_label, label follows WordF ('\0'-terminated string) */ } WordF; /* constant pitch model for a Txtln */ typedef struct ConstPitch { Ems w; /* Character pitch */ Scoor o; /* origin (one of the character break points) */ float r; /* max/min autocorrelation ratio - the larger the better */ } ConstPitch; #define Init_ConstPitch {0.0,0,0.0} #if MAIN ConstPitch empty_ConstPitch = Init_ConstPitch; #else extern ConstPitch empty_ConstPitch; #endif typedef struct Txtlns { short mny; struct Txtln **lpa; /* to array of Txtln's (if mny==0, lpa==NULL) */ } Txtlns; #define Init_Txtlns {0,NULL} #if MAIN Txtlns empty_Txtlns = Init_Txtlns; #else extern Txtlns empty_Txtlns; #endif /* Text Line */ #define Txtln_label 00000000004 /* has an ASCII string label */ #define Txtln_size 00000000002 /* dominant text size chosen */ #define Txtln_basl 00000000001 /* dominant baseline chosen */ typedef struct Txtln { Ident ident; Bbx bx; Pts size; /* dominant text size (0 means unknown) */ Scoor basl; /* dominant baseline (absolute y coordinate) */ short *proj; /* ptr to malloc space projection array */ ConstPitch *cp; /* ptr to malloc space constant-pitch model */ Merit m; /* merit */ Txtlns ls; /* alternative Txtln segmentations */ Words ws; /* sorted asc. on x */ Chars cs; /* sorted asc. on bx.a.x */ Blobs bs; /* misc. non-char blobs */ char *l; /* label (ASCII string in malloc space) */ } Txtln; #define Init_Txtln {IsTxtln,Init_Bbx,0.0,0,NULL,NULL,0.0,Init_Txtlns,Init_Words,Init_Chars,Init_Blobs,NULL} #if MAIN Txtln empty_Txtln = Init_Txtln; #else extern Txtln empty_Txtln; #endif /* Text Line */ typedef struct TxtlnF { Ident ident; /* IsTxtln must be set */ Bbx bx; Scoor basl; /* baseline (absolute y coordinate) */ Pts size; /* text size (<=0.0 means none is known) */ short pmny; /* no. shorts in projection array to follow */ float m; /* merit */ short lmny; /* no. alternative txtlns to follow */ short wmny; /* no. words to follow */ short cmny; /* no. chars to follow */ int bmny; /* no. blobs to follow */ /* if ident&Txtln_label, label follows TxtlnF ('\0'-terminated string) */ } TxtlnF; /* blocks of text */ typedef struct Blocks { short mny; /* if mny==0, bpa==NULL */ struct Block **bpa; /* to NULL-term'd array of ptrs */ } Blocks; #define Init_Blocks {0,NULL} #if MAIN Blocks empty_Blocks = Init_Blocks; #else extern Blocks empty_Blocks; #endif /* block of text */ typedef struct Block { Ident ident; Bbx bx; /* bounding box of block */ Radians skew; /* skew angle (as correction to Page.skew) */ Radians shear; /* shear angle (as correction to Page.shear) */ Ems wst; /* word-space threshhold */ Merit m; /* merit */ Blocks bks; /* Blocks nested within this one */ Txtlns ls; Words ws; Chars cs; Blobs bs; char *l; /* label (ASCII string in malloc space) */ } Block; #define Init_Block {IsBlock,Init_Bbx,0.0,0.0,0.0,0.0,Init_Blocks,Init_Txtlns,Init_Words,Init_Chars,Init_Blobs,NULL} #if MAIN Block empty_Block = Init_Block; #else extern Block empty_Block; #endif /* Ident bits for Blocks */ #define Block_wst 00000000001 /* word-space-thresh set up */ #define Block_label 00000000002 /* has an ASCII string label */ #define Block_mb (1) /* block of text */ typedef struct BlockF { Ident ident; /* IsBlock must be set */ Bbx bx; Ems wst; /* word-space threshold */ float skew; float shear; #if Block_mb float m; short bkmny; #endif short lmny; short wmny; int cmny; int bmny; /* if ident&Block_label, label follows BlockF ('\0'-terminated string) */ } BlockF; /* page */ typedef struct Page { Ident ident; Bbx bx; /* extreme indices in pixels */ short res_x; /* resolution in pixels/inch: x & y */ short res_y; Radians skew; /* skew angle */ Radians shear; /* shear correction */ Blocks bks; /* blocks */ Txtlns ls; /* textlines (those not in any block) */ Words ws; /* words (not in any textline) */ Chars cs; /* chars (not in any word) */ Blobs bs; /* blobs (not in any char) */ char *l; /* label (ASCII string in malloc space) */ } Page; #define Init_Page {IsPage,Init_Bbx,0,0,0.0,0.0,Init_Blocks,Init_Txtlns,Init_Words,Init_Chars,Init_Blobs,NULL} #if MAIN Page empty_Page = Init_Page; #else extern Page empty_Page; #endif #define Page_label 00000000001 /* has a label */ /* Pages of text */ typedef struct Pages { unsigned short mny; /* if mny==0, pa==NULL */ struct Page **pa; /* to NULL-term'd array of ptrs */ } Pages; #define Init_Pages {0,NULL} #if MAIN Pages empty_Pages = Init_Pages; #else extern Pages empty_Pages; #endif typedef struct PageF { Ident ident; /* IsPage bit must be set */ short res_x,res_y; /* resolution in pixels/inch: x & y */ Bbx bx; /* extreme indices in pixels */ float skew; /* original page skew angle, radians */ float shear; /* original page shear angle, radians */ short bkmny; /* no. blocks */ short lmny; /* no. textlines (not in any block) */ short wmny; /* no. words (not in any textline) */ int cmny; /* no. chars (not in any word) */ int bmny; /* no. blobs (not in any char)) */ /* if ident&Page_label, label follows PageF ('\0'-terminated string) */ } PageF; #define Page_new 00000000001 /* Page is in ``new'' format */ /* Each Dim-file begins with a Doc record */ typedef struct Doc { unsigned short version; /* file format version number */ Pages ps; char *l; /* ASCII label */ } Doc; #define Init_Doc {0,Init_Pages,NULL} #if MAIN Doc empty_Doc = Init_Doc; #else extern Doc empty_Doc; #endif char *ident_toa(); Ident cto_ident(); Ident cto_flag(); char *merit_toa(); Page *alloc_page(); char *page_toa(); Page *dup_page(); Page *dup_page_etc(); Block *alloc_block(); char *block_toa(); Block *dup_block(); Block *dup_block_etc(); Block *append_block(); Blocks *dup_blocks_etc(); ConstPitch *alloc_constpitch(); char *constpitch_toa(); Txtln *alloc_txtln(); char *txtln_toa(); Word *alloc_word(); char *word_toa(); boolean eq_word(); int hash_word(); Char *alloc_char(); char *char_toa(); Pp *char_centroid(); Char *char_of_blob(); char *interp_toa(); char *blob_toa(); Pp *blob_centroid(); char *runf_toa(); char *runfs_toa(); char *pp_toa(); char *bdyedge_toa(); Blob *dup_blob(); Blob *dup_blob_etc(); Blob *dup_blobl_etc(); Blob *runs_to_runs(); Blobs *dup_blobs_etc(); Blobs *blobl_to_blobs(); Interp *alloc_interp(); Interp *dup_interp(); Interpl *dup_interpl_etc(); Interps *dup_interps_etc(); Word *append_word(); Word *insert_word(); Word *insert_word_txtln(); Word *dup_word(); Word *dup_word_etc(); Words *dup_words_etc(); Txtln *dup_txtln(); Txtln *dup_txtln_etc(); Txtlns *dup_txtlns_etc(); Block *dup_block(); Block *dup_block_etc(); Radians add_ang(); Radians subtract_ang(); /* in-line macroes */ /* Merge the `source' Bbx into the `destination' Bbx, expanding the dest Bbx as required. The source Bbx is unmodified. Usage: merge_bbx(s,d) Bbx *s,*d; */ #define merge_bbx(s,d) { \ if((s)->a.x < (d)->a.x) (d)->a.x = (s)->a.x; \ if((s)->a.y < (d)->a.y) (d)->a.y = (s)->a.y; \ if((s)->b.x > (d)->b.x) (d)->b.x = (s)->b.x; \ if((s)->b.y > (d)->b.y) (d)->b.y = (s)->b.y; \ } /* Experimental implementation of a data structure for maintaining a set of distinct Words whose merit falls within a dynamically-varying range. This implementation is worst-case quadratic time. BUGS: insert_wordset shouldn't duplicate the word. */ #define dbg_ws (0) /* if !=0, enable WordSet debugging tracing */ typedef struct WordSet { double cut; /* cut-fraction */ int cap; /* capacity: maximum number permitted at any time */ double top; /* maximum merit seen since allocation */ Words ws; /* sorted by top-choice merit */ Word *max,*min; /* maximum/minimum entries currently in ws */ int high; /* high-water: max. no. entries in history */ } WordSet; #define Init_WordSet {1.0,INT_MAX,0.0,Init_Words,NULL,NULL,0} #if MAIN WordSet empty_WordSet = Init_WordSet; #else extern WordSet empty_WordSet; #endif #define size_wordset(s) ((s)->ws.mny) #define top_wordset(s) ((s)->top) #define max_wordset(s) ((s)->max) #define min_wordset(s) ((s)->min) #define max_wordmerit(s) ((max_wordset((s))!=NULL)? (max_wordset((s)))->m: 0.0) #define min_wordmerit(s) ((min_wordset((s))!=NULL)? (min_wordset((s)))->m: 0.0) Merit wordmerit(); WordSet *alloc_wordset(); boolean insert_wordset(); Word *remove_wordset(); int free_wordset_etc(); err_wordset(); 0707070035351137151006640007620000050000010263160476773367000001000000001554Units.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ #define UNITS "icpPsu" /* units notation for: inches, cm, points, picas, scanner pixel (Scoor), and basic unit (also Scoor) */ #define INCHES_PER_POINT (0.0138) /* cf. Chicago Manual of Style */ #define RADIANS_PER_DEGREE (PI/180.0) #define DtoR (RADIANS_PER_DEGREE) /* degrees * DtoR = radians */ #define Radians double /* angle in radians */ /* machine-independent I/O has a resolution of 0.1 second of arc */ #define fwri_Radians(F,V) fwri_int3((F),(V)*2062648.1) #define frdi_Radians(F) (frdi_int3(F)/(Radians)2062648.1) 0707070035351137161006640007620000050000010263200476773367000001000000012421abort.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* abort.h - three terse message, warning, and abort functions. out(s,a,...) print message to stdout err(s,a,...) print warning to stderr abort(s,a,...) complain to stderr and exit abnormally. The 's' argument is a printf string, and the 'a',... are (up to 15) arguments matching %-fields. These routines prefix the program name and append `\n' to the printf string, then write to: `out': stdout `err' & `abort': stderr Abort also says " - abort", and exits abnormally. This #include should be preceded by `#define CMDNAME "xxx"' so that `xxx:' will be prefixed to msg and abort strings. */ #ifndef CMDNAME #define CMDNAME "hsb" #endif #define MSGMAX 120 #ifndef boolean #define boolean int #define T 1 #define F 0 #endif /* WARNING: these function-call versions do not port well: e.g. floating-point arguments are botched on MIPS and SGI machines */ out(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) char *s; { static char m[MSGMAX]; strcpy(m,CMDNAME); strcat(m,": "); strcat(m,s); strcat(m,"\n"); fprintf(stdout,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15); } err(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) char *s; { char m[MSGMAX]; strcpy(m,CMDNAME); strcat(m,": "); strcat(m,s); strcat(m,"\n"); fprintf(stderr,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15); } abort(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) char *s; { static char m[MSGMAX]; strcpy(m,s); strcat(m," - abort"); err(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15); exit(1); } /* These hybrid macro/function forms ports well, but are awkward to use... */ char *_F(s) char *s; { static char m[MSGMAX]; strcpy(m,CMDNAME); strcat(m,": "); strcat(m,s); strcat(m,"\n"); return(m); } #define out0(Z) fprintf(stdout,_F(Z)) #define out1(Z,A) fprintf(stdout,_F(Z),A) #define out2(Z,A,B) fprintf(stdout,_F(Z),A,B) #define out3(Z,A,B,C) fprintf(stdout,_F(Z),A,B,C) #define out4(Z,A,B,C,D) fprintf(stdout,_F(Z),A,B,C,D) #define out5(Z,A,B,C,D,E) fprintf(stdout,_F(Z),A,B,C,D,E) #define out6(Z,A,B,C,D,E,F) fprintf(stdout,_F(Z),A,B,C,D,E,F) #define out7(Z,A,B,C,D,E,F,G) fprintf(stdout,_F(Z),A,B,C,D,E,F,G) #define out8(Z,A,B,C,D,E,F,G,H) fprintf(stdout,_F(Z),A,B,C,D,E,F,G,H) #define out9(Z,A,B,C,D,E,F,G,H,I) fprintf(stdout,_F(Z),A,B,C,D,E,F,G,H,I) #define out10(Z,A,B,C,D,E,F,G,H,I,J) fprintf(stdout,_F(Z),A,B,C,D,E,F,G,H,I,J) #define out11(Z,A,B,C,D,E,F,G,H,I,J,K) fprintf(stdout,_F(Z),A,B,C,D,E,F,G,H,I,J,K) #define err0(Z) fprintf(stderr,_F(Z)) #define err1(Z,A) fprintf(stderr,_F(Z),A) #define err2(Z,A,B) fprintf(stderr,_F(Z),A,B) #define err3(Z,A,B,C) fprintf(stderr,_F(Z),A,B,C) #define err4(Z,A,B,C,D) fprintf(stderr,_F(Z),A,B,C,D) #define err5(Z,A,B,C,D,E) fprintf(stderr,_F(Z),A,B,C,D,E) #define err6(Z,A,B,C,D,E,F) fprintf(stderr,_F(Z),A,B,C,D,E,F) #define err7(Z,A,B,C,D,E,F,G) fprintf(stderr,_F(Z),A,B,C,D,E,F,G) #define err8(Z,A,B,C,D,E,F,G,H) fprintf(stderr,_F(Z),A,B,C,D,E,F,G,H) #define err9(Z,A,B,C,D,E,F,G,H,I) fprintf(stderr,_F(Z),A,B,C,D,E,F,G,H,I) #define err10(Z,A,B,C,D,E,F,G,H,I,J) fprintf(stderr,_F(Z),A,B,C,D,E,F,G,H,I,J) #define err11(Z,A,B,C,D,E,F,G,H,I,J,K) fprintf(stderr,_F(Z),A,B,C,D,E,F,G,H,I,J,K) char *_G(s) char *s; { static char m[MSGMAX]; strcpy(m,CMDNAME); strcat(m,": "); strcat(m,s); strcat(m," - abort\n"); return(m); } #define abort0(Z) fprintf(stderr,_G(Z)) #define abort1(Z,A) fprintf(stderr,_G(Z),A) #define abort2(Z,A,B) fprintf(stderr,_G(Z),A,B) #define abort3(Z,A,B,C) fprintf(stderr,_G(Z),A,B,C) #define abort4(Z,A,B,C,D) fprintf(stderr,_G(Z),A,B,C,D) #define abort5(Z,A,B,C,D,E) fprintf(stderr,_G(Z),A,B,C,D,E) #define abort6(Z,A,B,C,D,E,F) fprintf(stderr,_G(Z),A,B,C,D,E,F) #define abort7(Z,A,B,C,D,E,F,G) fprintf(stderr,_G(Z),A,B,C,D,E,F,G) #define abort8(Z,A,B,C,D,E,F,G,H) fprintf(stderr,_G(Z),A,B,C,D,E,F,G,H) #define abort9(Z,A,B,C,D,E,F,G,H,I) fprintf(stderr,_G(Z),A,B,C,D,E,F,G,H,I) #define abort10(Z,A,B,C,D,E,F,G,H,I,J) fprintf(stderr,_G(Z),A,B,C,D,E,F,G,H,I,J) #define abort11(Z,A,B,C,D,E,F,G,H,I,J,K) fprintf(stderr,_G(Z),A,B,C,D,E,F,G,H,I,J,K) boolean ask_more() { FILE *tty; char reply[20]; static int skip = 0; if(skip<=0) { fputs("MORE? ",(tty=fopen("/dev/tty","w"))); fclose(tty); fgets(reply,20,(tty=fopen("/dev/tty","r"))); fclose(tty); switch (reply[0]) { case '\0': case 'y': case 'Y': return(T); case 'n': case 'N': case 'q': case 'Q': return(F); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': skip = atoi(reply); return(T); case '*': skip = INT_MAX; return(T); default: skip = 0; return(T); }; } else skip--; return(T); } boolean ask_quit() { FILE *tty; char reply[20]; fputs("QUIT? ",(tty=fopen("/dev/tty","w"))); fclose(tty); fgets(reply,20,(tty=fopen("/dev/tty","r"))); fclose(tty); switch (reply[0]) { case 'y': case 'Y': return(F); case 'n': case 'N': case 'q': case 'Q': return(T); }; return(F); } 0707070035351137171006640007620000050000010263220476773367100000600000171751bcp.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* T. J. ThompsonT - ATT-BL HO - extensions */ /* bcp.c - translate among binary image file formats, optionally trimming, shifting, scaling, and rotating the image on the fly. Scaling is by arbitrary real factors, separately in X & Y. Rotation is still crude and slow. USAGE: bcp [options...] [I [O]] I/O: If O is omitted, all output is concatenated to stdout. If I is also omitted, all input is read from stdin. If I is a filename, it is the sole input; but, if it is a directory name, then every leaf of its file tree is processed in turn; and, in this case, if O also is specified, it is forced to become the root directory of an isomorphic tree of output files (this use of Unix file trees may be defeated using compile-time option FILE_TREE). [PROPOSED: An input file may be a catenation of pages. These may vary in TYPE and other parameters. They will all be translated to the same output type, and catenated to one file, each with a complete translated header. Generally, a complete picfile header must be repeated at the top of each page: exceptions include TYPE=cdf, which packs pages in its own peculiar way.] OPTIONS: NOTE: lengths, distances, and pixel indices are assumed to be in units of pixels (scanner units), unless one of "icpPs" is appended, meaning inches, cm, points, picas, or (explicitly) scanner pixels. This applies to option: -w (seems buggy). -B[io] read/write bitfile(9.5) format (doesn't use TYPE= header). [doesn't run-length encode yet: may be bulky.] -M write TYPE=bitmap format. -P write Postscript format (only on Suns; by Tim Thompson, ATT-BL HO) -Rx[,y] force output resolutions to x,y (overrides -xX[,Y]) (pixels/inch). Requires a RES=X Y line in the header. -R= Force the output resolution to be equal to the greater of the input resolutions. -S write Sun rasterfile format (only on Suns; by Tim Thompson, ATT-BL HO) -Tt when reading TYPE=dump, binarize the image by thresholding each pixel value as follows: (pixel<t)? black: white. (default: -T128) -Ww shrink-wrap output around black artwork, surrounding it with equal margins of width w (pixels), then translate so that the left-top corner of the margin box is at 0,0 (works only with TYPE=document- image input). (w must be >= 0) -Zx[,y] set input resolution to RES=x y (overriding existing RES, if any) -b write binary format (TYPE=binary) -d? trace to stderr: -dR comment on any change in resolution -dc point out oddities in cdf files which are, by default, silently corrected -dh file headers (a good first debugging step) -dm margins -dr runs (exhaustive, voluminous) -ds status and summary statistics (brief) -g31 write CCITT FAX Group 3 1-dim encoding -31 ditto -g32 write CCITT FAX Group 3 2-dim encoding (see also -k option) -32 ditto -g4 write CCITT FAX Group 4 encoding (the default output format) -4 ditto -kK set the 'k' for g32 encoding on output (default: -k4) -oX,Y offset the result by X,Y (merely shift the bounding box) -p write TYPE=dump NCHAN=1 format; input binary pixels are mapped to grey as follows: (pixel==white)? 255: 0. -r write rle format (this is Pavlidis' obsolescent OCR format) -t[lrbN] top of the page is really at the left/right/bottom; after all other transformations are carried out, the image will be rotated to bring the real top of page to the top. By arbitrary convention, the top-left corner of the rotated image will be equal to the top-left corner of the image resulting from all the other transformations. [UNFINISHED, UNDER DEVELOPMENT: -tr & -tb; -tN, where N is a numeric string, is interpreted as a counterclockwise rotation by N degrees: for now, only handle +/-20 degrees. The present code for -tN is slow and subject to aliasing.] -v reverse video: swap black and white -wL,T,R,B specify window to select: (L,T) is the left-top (origin) and (R,B) the OPEN right-bottom corner (i.e. the corner coordinates are not included.) A '%' argument defaults to the input window parameter. [NOTE: since non-zero L,T windows are still not everywhere well supported (by pcp, met, etc), it might be best to shift the new L,T to 0,0 on output -- but this is not done now.] -xX[,Y] expansion factor(s), horizontally and vertically; if only one is specified, they are assumed equal (default: -x1.0,1.0) May be overridden by -Rx[,y]. Requires a RES=X Y line in the header. DESCRIPTION This translates among these formats of binary images: ccitt-g31, ccitt-g32, ccitt-g4, picture (TYPE=dump NCHAN=1), binary, rle, bitfile(9.5), cdf, Sun rasterfile (TYPE=bitmap), and Postscript. All require a TYPE= header in picfile format (see below), except bitfile(9.5) (as a result, to read these, must use special option: -Bi). Most require WINDOW=ox oy cx cy and RES=x y header lines also. Optionally, the image may be modified on the fly by the following operations performed in this order: trimming - a subset of the input image is selected (-w option) shifting - the origin is shifted (-o) scaling - real scaling factors are applied, in X & Y separately (-x, -R) rotation - by 90, 180, 270 degrees - UNDER DEVELOPMENT (-t option) reverse-video - swap black and white (-v option) Note that scaling changes the effective digitizing resolution by arbitrary real factors (expansion or contraction), in X and Y separately. Presently, this is accomplished naively by replication or deletion of pixels. If it is ever desired to apply more interesting image-processing techniques (such as smoothing and resampling), the required changes may be safely confined to functions transform_rlels() (in bcp.c) & transform_rlel() (in rlelib.c). Accepts TYPE=document-image (or TYPE=dim), flattening its hierarchy, and writes it out as a single page image. PICFILE FORMAT (briefly summarized; see picture(5)) Each picture file comprises an ASCII header followed by binary data. The header is terminated by two newlines (an empty line). A typical header is: TYPE=ccitt-g4 WINDOW=0 0 640 480 RES=300 300 (note the final empty line) TYPE must come first. The other lines may come in any order. WINDOW gives the x,y coordinates of the upper left corner (inclusive) and lower right corners (exclusive). Typically, an image of WxH pixels will be described by WINDOW=0 0 W H. RES=X Y gives the digitizing resolution horizontally and vertically, in integral pixels/inch. Supported TYPEs include: dump A two-dimensional array of pixel structures. NCHAN=1 is required: one byte per pixel. On input, the grey pixel values are thresholded to binary (see option -T). On output, black is 0 and white is 255. bitmap One bit/pixel, packed into bytes high-order bit first. Black is `1'. Each horizontal row is padded to a 16-bit boundary with `0'. (This is identical to Sun rasterfile format, except for the ASCII header.) ccitt-g4 CCITT FAX Group 4 compressed image. Similarly, ccitt-g31 means Group 3/1-D and ccitt-g32 means Group 3/2-D. (Obsolescent 112 formats: rle A run-length coding, better for binary images (see rle.h). binary 1 bit/pixel, packed into bytes low-order bit first. Black is `1'. Each horizontal row is padded to a full byte with `0'.) NOTE: bitfile(9.5) doesn't use an ASCII header. (Odd formats in use outside 112, sometimes very heavily: cdf supported on input only, and only the first page of several. tiff not yet supported.) IMPLEMENTATION STATUS CCITT FAX ``uncompressed'' (or, ``transparent'') mode is not implemented, either while encoding or decoding. Cdf is an input-only option; Sun rasterfile and Postscript are output-only options. Postscript output is useful only for very small images. Rotations are only partially implemented, and are slow. KNOWN BUGS (30 May 89) WINDOW=OX OY CX CY where OX or OY are non-zero is not handled correctly for every combination of file types. Unit gets passed wrongly to vto_scoor(). Rle can't be both inout and output (design flaw: they share a buffer). Beware off-by-one errors (top or bottom line omitted); has not been carefully checked for all file type combinations. AUTHORS Dec 1988 - Henry S. Baird (AT&T Bell Labs MH) - first working draft Mar 1989 - Tim Thompson (BL HO) - extensions for SunOS, bug fixes, etc */ #include <stdio.h> #include <string.h> #include <ctype.h> #include "CPU.h" #define MAIN 1 #include "stdocr.h" #include "rle.h" #include "pic.h" #include "Text.h" /* Ugly stubs just to prevent Text.h dragging in many other *.h & *.o files */ Bfeats *alloc_bfeats(){}; free_bfeats(){}; Bfeats *dup_bfeats(){}; fwrb_bfeats(){}; frdb_bfeats(){}; fix_lag(){}; char *classid_toa(){}; #include "Bitmap.h" #include "CCITT.h" #include "bitio.h" #if FILE_TREE #include "Path.h" #endif #define CMDNAME "bcp" #include "abort.h" double atof(),sin(),cos(); char *strchr(); /* Runtime options values */ static struct { boolean from_bitfile; /* -Bi */ boolean to_bitfile; /* -Bo */ boolean to_bitmap; /* -M */ boolean to_g31; /* -g31 or -31 */ boolean to_g32; /* -g32 or -32 */ boolean to_g4; /* -g4 or -4 */ boolean to_rle; /* -r */ boolean to_bin; /* -b */ boolean to_pic; /* -p */ boolean to_post; /* -P */ boolean to_rast; /* -S */ boolean omit_hdr; /* -O */ Sp out_res; /* -R (-1 = unspecified; -2 = force-equal) */ Scoor shrinkwrap; /* -W (-1 = unspecified) */ Sp in_res; /* -Z (SHRT_MIN,SHRT_MIN = unspecified) */ int g32_k; /* -k */ int metheus; /* -m */ Sp offset; /* -o */ boolean dbg_any; boolean dbg_R; /* -dR */ boolean dbg_c; /* -dc */ boolean dbg_h; /* -dh */ boolean dbg_m; /* -dm */ boolean dbg_r; /* -dr */ boolean dbg_s; /* -ds */ boolean show; /* -s */ char top; /* -tT takes on values: 't', 'l', 'r', 'b', 'a' */ float top_angle; /* -t angular value (set if top=='a') (Radians) */ int thresh; /* -Tt */ boolean reverse; /* -v */ char *optarg_l; /* -w?,,, */ char *optarg_t; /* -w,?,, */ char *optarg_r; /* -w,,?, */ char *optarg_b; /* -w,,,? */ Bbx trim; /* output margins resulting from -w */ Pp expand; /* -x */ char *in_fn; char *out_fn; } _O = { F, F, F, F, F, T, F, F, F, F, F, F, {-1,-1}, -1, {SHRT_MIN,SHRT_MIN}, 4, -1, Init_Zero_Sp, F, F, F, F, F, F, F, F, 't',0.0, 128, F, NULL, NULL, NULL, NULL, Init_Max_Bbx, {1.0,1.0}, NULL, NULL }; parse_args(arc,arv) int arc; char **arv; { /* getopt support */ int optch; extern int optind; extern char *optarg; char *metheus_ev,metheus_digit; char *fs; /* default metheus number */ if((metheus_ev=(char *)getenv("FB"))!=NULL) { metheus_digit = metheus_ev[(int)strlen(metheus_ev)-1]; if((int)isdigit(metheus_digit)) { _O.metheus = (metheus_digit - '0'); }; }; while((optch=getopt(arc,arv,"B:MOPR:ST:W:Z:3:4bd:g:k:m:o:prst:vw:x:"))!=EOF) switch(optch) { case 'B': switch(*optarg) { case 'o': _O.to_bitfile = T; _O.to_g4 = F; break; case 'i': _O.from_bitfile = T; break; default: abort("option -B%s is illegal",optarg); break; }; break; case 'M': _O.to_bitmap = T; _O.to_g4 = F; break; case 'O': _O.omit_hdr = T; break; case 'P': #if CPU==SUN _O.to_post = T; _O.to_g4 = F; #else abort("-P option available only on Suns"); #endif break; case 'R': if(*optarg=='=') { _O.out_res.x = _O.out_res.y = -2; fs=NULL; } else if((fs=strtok(optarg,","))!=NULL) { if(strcmp(fs,"%")!=0) { _O.out_res.x = atoi(fs); }; }; if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) { if(strcmp(fs,"%")!=0) { _O.out_res.y = atoi(fs); }; } else _O.out_res.y = _O.out_res.x; break; case 'S': #if CPU==SUN _O.to_rast = T; _O.to_g4 = F; #else abort("-S option available only on Suns"); #endif break; case 'T': _O.thresh=atoi(optarg); break; case 'W': _O.shrinkwrap=atoi(optarg); if(_O.shrinkwrap<0) { err("-W%d must be >=0; force to -W0", _O.shrinkwrap); _O.shrinkwrap=0; }; break; case 'Z': if((fs=strtok(optarg,","))!=NULL) { if(strcmp(fs,"%")!=0) { _O.in_res.x = atoi(fs); }; }; if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) { if(strcmp(fs,"%")!=0) { _O.in_res.y = atoi(fs); }; } else _O.in_res.y = _O.in_res.x; break; case '3': switch (*optarg) { case '1': _O.to_g31=T; _O.to_g4=F; break; case '2': _O.to_g32=T; _O.to_g4=F; break; default: abort("bad option: -g3%s",optarg); break; }; break; case '4': _O.to_g4=T; break; case 'b': _O.to_bin=T; _O.to_g4=F; break; case 'd': _O.dbg_any=T; switch(*optarg) { case 'R': _O.dbg_R = T; break; case 'c': _O.dbg_c = T; break; case 'h': _O.dbg_h = T; break; case 'm': _O.dbg_m = T; break; case 'r': _O.dbg_r = T; break; case 's': _O.dbg_s = T; break; }; break; case 'g': switch (optarg[0]) { case '3': switch (optarg[1]) { case '1': _O.to_g31=T; _O.to_g4=F; break; case '2': _O.to_g32=T; _O.to_g4=F; break; default: abort("bad option: -g%s",optarg); break; }; break; case '4': _O.to_g4=T; break; default: abort("bad option: -g%s",optarg); break; }; break; case 'k': _O.g32_k = atoi(optarg); break; case 'm': _O.metheus = atoi(optarg); break; case 'o': if((fs=strtok(optarg,","))!=NULL) { if(strcmp(fs,"%")!=0) _O.offset.x = atoi(fs); }; if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) { if(strcmp(fs,"%")!=0) _O.offset.y = atoi(fs); }; break; case 'p': _O.to_pic=T; _O.to_g4=F; break; case 'r': _O.to_rle = T; _O.to_g4 = F; break; case 's': _O.show = T; break; case 't': _O.top = *optarg; if(strchr("0123456789.+-",_O.top)!=NULL) { _O.top = 'a'; /* angular value */ _O.top_angle = atof(optarg)*DtoR; }; break; case 'v': _O.reverse = T; break; case 'w': if( (fs=strtok(optarg,","))!=NULL && strlen(fs)>0 && strcmp(fs,"%")!=0 ) _O.optarg_l = strdup(fs); if( fs!=NULL && (fs=strtok((char *)0,","))!=NULL && strlen(fs)>0 && strcmp(fs,"%")!=0 ) _O.optarg_t = strdup(fs); if( fs!=NULL && (fs=strtok((char *)0,","))!=NULL && strlen(fs)>0 && strcmp(fs,"%")!=0 ) _O.optarg_r = strdup(fs); if( fs!=NULL && (fs=strtok((char *)0,","))!=NULL && strlen(fs)>0 && strcmp(fs,"%")!=0 ) _O.optarg_b = strdup(fs); break; case 'x': if((fs=strtok(optarg,","))!=NULL) { if(strcmp(fs,"%")!=0) { if(*fs=='/') _O.expand.x = 1.0/atof(fs+1); else _O.expand.x = atof(fs); if(_O.expand.x<=0.0) _O.expand.x=1.0; }; }; if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) { if(strcmp(fs,"%")!=0) { if(*fs=='/') _O.expand.y = 1.0/atof(fs+1); else _O.expand.y = atof(fs); if(_O.expand.y<=0.0) _O.expand.y=1.0; }; } else _O.expand.y = _O.expand.x; break; default: break; }; switch(arc-optind) { case 2: _O.out_fn = strdup(arv[optind+1]); case 1: _O.in_fn = strdup(arv[optind]); case 0: break; default: abort("<= two filenames expected"); break; }; if(_O.show&&_O.metheus==-1) { err("FB=/dev/omM not specified, using /dev/om0"); _O.metheus = 0; }; } unimplemented() { abort("unimplemented"); } typedef struct Copy_arg { boolean bop; /* beginning of page */ PIC_hdr *ph; int wid; /* bbx_wid(&(ph->bx)) (for speed) */ BITFILE *bf; DST_table *tbl; /* for CCITT input */ int k; /* CCITT Group 3 2-D k */ int thresh; /* for input pic files */ RLE_Lines rles; /* for TYPE=document-image or TYPE=dim */ } Copy_arg; #define Init_Copy_arg {T,NULL,INT_MIN,NULL,NULL,4,128,Init_RLE_Lines} #if MAIN Copy_arg empty_Copy_arg = Init_Copy_arg; #else extern Copy_arg empty_Copy_arg; #endif /* SOURCES: return the next RLE_Line from the given file type, with run indices shifted to lie within [ a->ph->bx.a.x, a->ph->bx.b.x ]. **** BUGS: not all handle non-zero a->ph->bx.a.x yet. */ /* Handles non-zero a->ph->bx.a.x. */ RLE_Line *cdf_mrlc_source(a) Copy_arg *a; #define dbg_cdf (0) { static RLE_Line rl; int n; /* no. pixels decoded */ int col; /* color: 0=white, 1=black */ int byte; /* input byte */ int nb; /* no. bytes read for this line */ int ni; /* nibble index: 0=1st (low-order), 1=2nd(high-order) */ int nib; /* current nibble */ int mult; /* multiplier for current nibble */ int run; /* no. pixels in current run */ RLE_Run *rp; #define toggle_color() {if(col) col=0; else col=1;} /* get next byte into `byte' */ #define getbyte() { \ if((byte=getc(a->ph->fp))==EOF) goto eof; nb++; \ if(dbg_cdf) err("byte0x%x",byte); \ } /* get next nibble into `nib' */ #define getnib() { \ if(ni) { getbyte(); ni=0; nib=byte&0x0F; } \ else { ni=1; nib=(byte>>4); } \ if(dbg_cdf) err("nib0x%x byte0x%x ni%d",nib,byte,ni); \ } /* get next run into `run' */ #define getrun() { \ run=0; mult=1; \ do {getnib(); run += mult * (nib&0x07); mult *= 8;} while(nib&0x08); \ if(dbg_cdf) err("run%d %c",run,((col)? 'B': 'W')); \ } a->bop = F; n=0; col=0; ni=1; nb=0; rp=rl.r; do { getrun(); if(col) {/* black run */ if(run>0) { /* ... of >0 length */ rp->xs = a->ph->bx.a.x + n+1; rp->xe = a->ph->bx.a.x + (n+=run); if((rp-rl.r)>0 && ((rp-1)->xe >= rp->xs-1) ) { if(_O.dbg_c) err("cdf_mrlc_source: abutting black runs [%d,%d] & [%d,%d] - merged", (rp-1)->xs,(rp-1)->xe, rp->xs,rp->xe ); /* merge with prior black run */ (rp-1)->xe = rp->xe; } else rp++; } else { /* zero-length black run */ if( _O.dbg_c && (rp-rl.r)>0 ) err("cdf_mrlc_source: zero-length black run [%d,%d] in middle of line - ignored", n,n); }; } else { /* white run */ n+=run; }; toggle_color(); } while(n<a->wid); /* read 2 EOL nibbles */ getnib(); getnib(); rl.runs = rp - rl.r; rl.len = a->wid; if(rl.runs>0 && rl.r[rl.runs-1].xe>=a->wid) { if(_O.dbg_c) err("cdf_mrlc_source: run [%d,%d] in line of length %d - truncated", rl.r[rl.runs-1].xs,rl.r[rl.runs-1].xe,a->wid); rl.r[rl.runs-1].xe = a->wid-1; if(rl.r[rl.runs-1].xs>rl.r[rl.runs-1].xe) { rl.runs--; }; }; rl.y = a->ph->cy++; if(_O.dbg_r) nerr_RLE_Line("cdf_source: ",&rl); return(&rl); eof: if(dbg_cdf) err("cdf_mrlc_source: unexpected EOF, input line %d",a->ph->cy); return(NULL); } int no_runs_of_page(p) Page *p; { int runs; runs = 0; runs += no_runs_of_blocks(&p->bks); runs += no_runs_of_txtlns(&p->ls); runs += no_runs_of_words(&p->ws); runs += no_runs_of_chars(&p->cs); runs += no_runs_of_blobs(&p->bs); return(runs); } int runs_of_page(p,ra,max) Page *p; RLE_Yrun *ra; int max; { int runs; runs = 0; runs += runs_of_blocks(&p->bks,ra,max); runs += runs_of_txtlns(&p->ls,ra+runs,max-runs); runs += runs_of_words(&p->ws,ra+runs,max-runs); runs += runs_of_chars(&p->cs,ra+runs,max-runs); runs += runs_of_blobs(&p->bs,ra+runs,max-runs); return(runs); } int no_runs_of_blocks(p) Blocks *p; { int runs; Block *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp)) runs += no_runs_of_block(pp); return(runs); } int runs_of_blocks(p,ra,max) Blocks *p; RLE_Yrun *ra; int max; { int runs; Block *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp)) runs += runs_of_block(pp,ra+runs,max-runs); return(runs); } int no_runs_of_block(p) Block *p; { int runs; runs = 0; runs += no_runs_of_txtlns(&p->ls); runs += no_runs_of_words(&p->ws); runs += no_runs_of_chars(&p->cs); runs += no_runs_of_blobs(&p->bs); return(runs); } int runs_of_block(p,ra,max) Block *p; RLE_Yrun *ra; int max; { int runs; runs = 0; runs += runs_of_txtlns(&p->ls,ra+runs,max-runs); runs += runs_of_words(&p->ws,ra+runs,max-runs); runs += runs_of_chars(&p->cs,ra+runs,max-runs); runs += runs_of_blobs(&p->bs,ra+runs,max-runs); return(runs); } int no_runs_of_txtlns(p) Txtlns *p; { int runs; Txtln *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->lpa); pp!=NULL; pp= *(++ppp)) runs += no_runs_of_txtln(pp); return(runs); } int runs_of_txtlns(p,ra,max) Txtlns *p; RLE_Yrun *ra; int max; { int runs; Txtln *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->lpa); pp!=NULL; pp= *(++ppp)) runs += runs_of_txtln(pp,ra+runs,max-runs); return(runs); } int no_runs_of_txtln(p) Txtln *p; { int runs; runs = 0; runs += no_runs_of_words(&p->ws); runs += no_runs_of_chars(&p->cs); runs += no_runs_of_blobs(&p->bs); return(runs); } int runs_of_txtln(p,ra,max) Txtln *p; RLE_Yrun *ra; int max; { int runs; runs = 0; runs += runs_of_words(&p->ws,ra+runs,max-runs); runs += runs_of_chars(&p->cs,ra+runs,max-runs); runs += runs_of_blobs(&p->bs,ra+runs,max-runs); return(runs); } int no_runs_of_words(p) Words *p; { int runs; Word *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->wpa); pp!=NULL; pp= *(++ppp)) runs += no_runs_of_word(pp); return(runs); } int runs_of_words(p,ra,max) Words *p; RLE_Yrun *ra; int max; { int runs; Word *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->wpa); pp!=NULL; pp= *(++ppp)) runs += runs_of_word(pp,ra+runs,max-runs); return(runs); } int no_runs_of_word(p) Word *p; { int runs; runs = 0; runs += no_runs_of_chars(&p->cs); runs += no_runs_of_blobs(&p->bs); return(runs); } int runs_of_word(p,ra,max) Word *p; RLE_Yrun *ra; int max; { int runs; runs = 0; runs += runs_of_chars(&p->cs,ra+runs,max-runs); runs += runs_of_blobs(&p->bs,ra+runs,max-runs); return(runs); } int no_runs_of_chars(p) Chars *p; { int runs; Char *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->cpa); pp!=NULL; pp= *(++ppp)) runs += no_runs_of_char(pp); return(runs); } int runs_of_chars(p,ra,max) Chars *p; RLE_Yrun *ra; int max; { int runs; Char *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->cpa); pp!=NULL; pp= *(++ppp)) runs += runs_of_char(pp,ra+runs,max-runs); return(runs); } int no_runs_of_blobs(p) Blobs *p; { int runs; Blob *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp)) runs += pp->runs; return(runs); } int runs_of_blobs(p,ra,max) Blobs *p; RLE_Yrun *ra; int max; { int runs; Blob *pp,**ppp; runs = 0; if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp)) runs += runs_of_blob(pp,ra+runs,max-runs); return(runs); } /* ascending lexicographic order on y,xs */ int local_rn_asc(r1,r2) RLE_Yrun *r1,*r2; { if(r1->y < r2->y) return(-1); else if(r1->y==r2->y) { if(r1->xs < r2->xs) return(-1); else if (r1->xs == r2->xs) return(0); else return(1); } else return(1); } RLE_Lines *rle_lines_of_page(pgp) Page *pgp; { static RLE_Lines rls; int no_runs,cy,ri; RLE_Yrun *ra,*cr; RLE_Run *lr; RLE_Line *cl; /* count runs */ no_runs = no_runs_of_page(pgp); if(_O.dbg_r) err("no_runs %d",no_runs); /* allocate runs array */ if((ra=(RLE_Yrun *)malloc(no_runs*sizeof(RLE_Yrun)))==NULL) abort("rle_lines_of_page: can't malloc ra[%d]",no_runs); runs_of_page(pgp,ra,no_runs); /* sort runs ascending on (y,xs) */ qsort(ra,no_runs,sizeof(RLE_Yrun),local_rn_asc); /* count RLE_lines.mny */ rls.mny = 0; cy=INT_MIN; for(ri=0,cr=ra; ri<no_runs; ri++,cr++) if(cr->y!=cy) { rls.mny++; cy = cr->y; }; /* allocate RLE_lines */ if((rls.rla=(RLE_Line *)malloc(rls.mny*sizeof(RLE_Line)))==NULL) abort("rle_lines_of_page: can't malloc rls.rla[%d]",rls.mny); /* fill in RLE_lines */ cy=INT_MIN; cl=rls.rla-1; for(ri=0,cr=ra; ri<no_runs; ri++,cr++) { if(cr->y!=cy) { cl++; cl->y = cy = cr->y; cl->runs = 0; lr = cl->r; }; lr->xs = cr->xs; lr->xe = cr->xe; lr++; cl->runs++; }; free(ra); return(&rls); } Bbx *bbx_of_rle_lines(rlsp) RLE_Lines *rlsp; { static Bbx res; Bbx r; int li,ri; RLE_Line *lp; RLE_Run *rp; res = empty_Bbx; for(li=0,lp=rlsp->rla; li<rlsp->mny; li++,lp++) { r.a.y = r.b.y = lp->y; for(ri=0,rp=lp->r; ri<lp->runs; ri++,rp++) { r.a.x = rp->xs; r.b.x = rp->xe; merge_bbx(&r,&res); }; }; return(&res); } translate_rle_lines(r,p) RLE_Lines *r; Sp p; { int li,ri; RLE_Line *lp; RLE_Run *rp; for(li=0,lp=r->rla; li<r->mny; li++,lp++) { lp->y += p.y; for(ri=0,rp=lp->r; ri<lp->runs; ri++,rp++) { rp->xs += p.x; rp->xe += p.x; }; }; } RLE_Line *binary_source(a) Copy_arg *a; { static RLE_Line rl; unsigned char *inline; a->bop = F; if(PIC_rline(a->ph,&inline)==1) { rl.runs = rlbr(inline,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,rl.r); rl.y = a->ph->cy; rl.len = a->wid; if(_O.dbg_r) nerr_RLE_Line("binary_source: ",&rl); return(&rl); } else { if(_O.dbg_r) nerr_RLE_Line("binary_source: ",NULL); return(NULL); }; } RLE_Line *bitmap_source(a) Copy_arg *a; { static RLE_Line rl; unsigned char *inline; register unsigned char *cp,*ep,*rb; a->bop = F; if(PIC_rline(a->ph,&inline)==1) { /* reverse bit order in each byte */ rb=bm_consts.Rbits; ep=(cp=inline)+a->ph->bpl; while(cp<ep) { *cp = rb[*cp]; cp++; }; rl.runs = rlbr(inline,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,rl.r); rl.y = a->ph->cy; rl.len = a->wid; if(_O.dbg_r) nerr_RLE_Line("bitmap_source: ",&rl); return(&rl); } else { if(_O.dbg_r) nerr_RLE_Line("binary_source: ",NULL); return(NULL); }; } RLE_Line *bitfile_source(a) Copy_arg *a; #define dbg_Bi (F) { static RLE_Line rl; unsigned char *cp,*ep,*pp; int ch,ci; a->bop = F; /* copy current line to prior */ memcpy(a->ph->pline,a->ph->line,a->ph->bpl); /* read one binary raster line */ ep=(cp=a->ph->line)+a->ph->bpl; while(cp<ep) { if((ch=getc(a->ph->fp))!=EOF) { if(ch<127) { if(dbg_Bi) err("cb: %o",ch); if((fread(cp,1,2*ch,a->ph->fp))==2*ch) { cp += 2*ch; } else return(NULL); } else { ch &= 0x7F; if(dbg_Bi) err("cb: 0200+%o",ch); if((fread(cp,1,2,a->ph->fp))==2) { cp += 2; for(ci=0;ci<ch-1;ci++,cp+=2) { *cp = *(cp-2); *(cp+1) = *(cp-1); }; } else return(NULL); }; } else return(NULL); }; /* reverse bit-order, & xor with prior line */ for(ep=(cp=a->ph->line)+a->ph->bpl,pp=a->ph->pline; cp<ep; cp++,pp++) { *cp = bm_consts.Rbits[*cp] ^ *pp; if(dbg_Bi) err("db: %o = ?? ^ %o",*cp,*pp); }; rl.runs = rlbr(a->ph->line,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,rl.r); rl.y = ++a->ph->cy; rl.len = a->wid; if(_O.dbg_r) nerr_RLE_Line("bitfile_source: ",&rl); return(&rl); } RLE_Line *dim_source(a) Copy_arg *a; { static RLE_Line *rlp,*rlq,rl; if(a->bop) { a->ph->cy = a->ph->bx.a.y-1; rlq=(rlp=a->rles.rla)+a->rles.mny; }; if(_O.dbg_r) { err("dim_source: a->bop %d a->ph->cy %d",a->bop,a->ph->cy); nerr_RLE_Line("*rlp",rlp); }; a->bop = F; a->ph->cy++; if(rlp<rlq) { if(a->ph->cy < rlp->y) { rl.y = a->ph->cy; rl.runs = 0; rl.len = a->wid; if(_O.dbg_r) nerr_RLE_Line("dim_source: ",&rl); return(&rl); } else if(a->ph->cy == rlp->y) { rlp->len = a->wid; rlp++; if(_O.dbg_r) nerr_RLE_Line("dim_source: ",rlp-1); return(rlp-1); } else { while(rlp<rlq && a->ph->cy>rlp->y) rlp++; if(rlp>=rlq) { if(_O.dbg_r) nerr_RLE_Line("dim_source: NULL"); return(NULL); } else { rlp->len = a->wid; rlp++; if(_O.dbg_r) nerr_RLE_Line("dim_source: ",rlp-1); return(rlp-1); }; }; } else { if(_O.dbg_r) nerr_RLE_Line("dim_source: NULL"); return(NULL); }; } RLE_Line *rle_source(a) Copy_arg *a; { static RLE_Line *rl; a->bop = F; if((rl=RLE_get_Line(a->ph->bx.a.x,a->ph->bx.b.x))!=NULL) { a->ph->cy = rl->y; rl->len = a->wid; if(_O.dbg_r) nerr_RLE_Line("rle_source: ",rl); return(rl); } else { if(_O.dbg_r) nerr_RLE_Line("rle_source: ",NULL); return(NULL); }; } /* Read next line of runs from pic file, with runs shifted to lie in the range [ a->ph->bx.a.x, a->ph->bx.b.x ]. */ RLE_Line *pic_source(a) Copy_arg *a; { static RLE_Line rl; unsigned char *inline; a->bop = F; if(PIC_rline(a->ph,&inline)==1) { rl.runs = trcr(inline, 0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x, a->thresh,rl.r); rl.y = a->ph->cy; rl.len = a->wid; if(_O.dbg_r) nerr_RLE_Line("pic_source: ",&rl); return(&rl); } else { if(_O.dbg_r) nerr_RLE_Line("pic_source: ",NULL); return(NULL); }; } /* Read next line of runs from g31 file, with runs shifted to lie in the range [ a->ph->bx.a.x, a->ph->bx.b.x ]. */ RLE_Line *g31_source(a) Copy_arg *a; { static RLE_Line *rlp,rl; RLE_Run *rp,*ep,*np; if((rlp=g31_to_rlel(a->tbl,a->bf,a->bop))!=NULL) { a->bop = F; rlp->y = ++a->ph->cy; rlp->len = a->wid; if(a->ph->bx.a.x!=0) { /* must shift run indices */ rl.y = rlp->y; rl.len = rlp->len; if((rl.runs=rlp->runs)>0) { for(ep=(rp=rlp->r)+rlp->runs,np=rl.r; rp<ep; rp++,np++ ) { np->xs = rp->xs + a->ph->bx.a.x; np->xe = rp->xe + a->ph->bx.a.x; }; }; if(_O.dbg_r) nerr_RLE_Line("g31_source: ",&rl); return(&rl); } else { if(_O.dbg_r) nerr_RLE_Line("g31_source: ",rlp); return(rlp); }; } else { if(_O.dbg_r) nerr_RLE_Line("g31_source: ",NULL); return(NULL); }; } /* Read next line of runs from g32 file, with runs shifted to lie in the range [ a->ph->bx.a.x, a->ph->bx.b.x ]. */ RLE_Line *g32_source(a) Copy_arg *a; { static RLE_Line *rlp,rl; RLE_Run *rp,*ep,*np; if((rlp=g32_to_rlel(a->tbl,a->bf,a->bop))!=NULL) { a->bop = F; rlp->y = ++a->ph->cy; rlp->len = a->wid; if(a->ph->bx.a.x!=0) { /* must shift run indices */ if(_O.dbg_r) err("g32_source: shift +%d",a->ph->bx.a.x); rl.y = rlp->y; rl.len = rlp->len; if((rl.runs=rlp->runs)>0) { for(ep=(rp=rlp->r)+rlp->runs,np=rl.r; rp<ep; rp++,np++ ) { np->xs = rp->xs + a->ph->bx.a.x; np->xe = rp->xe + a->ph->bx.a.x; }; }; if(_O.dbg_r) nerr_RLE_Line("g32_source: ",&rl); return(&rl); } else { if(_O.dbg_r) nerr_RLE_Line("g32_source: ",rlp); return(rlp); }; } else { if(_O.dbg_r) nerr_RLE_Line("g32_source: ",NULL); return(NULL); }; } /* Read next line of runs from g4 file, after shifting runs to lie in the range [ a->ph->bx.a.x, a->ph->bx.b.x ]. */ RLE_Line *g4_source(a) Copy_arg *a; { static RLE_Line *rlp,rl; RLE_Run *rp,*ep,*np; if((rlp=g4_to_rlel(a->tbl,a->bf,a->bop,a->wid))!=NULL) { a->bop = F; rlp->y = ++a->ph->cy; rlp->len = a->wid; if(a->ph->bx.a.x!=0) { /* shift runs */ rl.y = rlp->y; rl.len = rlp->len; if((rl.runs=rlp->runs)>0) { for(ep=(rp=rlp->r)+rlp->runs,np=rl.r; rp<ep; rp++,np++ ) { np->xs = rp->xs + a->ph->bx.a.x; np->xe = rp->xe + a->ph->bx.a.x; }; }; if(_O.dbg_r) nerr_RLE_Line("g4_source: ",&rl); return(&rl); } else { if(_O.dbg_r) nerr_RLE_Line("g4_source: ",rlp); return(rlp); }; } else { a->bop = F; if(_O.dbg_r) nerr_RLE_Line("g4_source: ",NULL); return(NULL); }; } binary_sink(rl,a) RLE_Line *rl; Copy_arg *a; { int stat; if(_O.dbg_r) nerr_RLE_Line("binary_sink: ",rl); if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; } if(rl!=NULL) { memset(a->ph->line,'\0',a->ph->bpl); if(rl->runs>0) { /* convert *rl to binary, using ``little-endian'' bit-order */ brrl(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line); }; if((stat=PIC_wline(a->ph,a->ph->line))!=1) abort("binary_sink: can't write: stat %d",stat); }; return(1); } bitmap_sink(rl,a) RLE_Line *rl; Copy_arg *a; { int stat; if(_O.dbg_r) nerr_RLE_Line("bitmap_sink: ",rl); if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; } if(rl!=NULL) { memset(a->ph->line,'\0',a->ph->bpl); if(rl->runs>0) { /* convert *rl to binary, using ``big-endian'' bit-order */ brrlb(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line); }; if((stat=PIC_wline(a->ph,a->ph->line))!=1) abort("bitmap_sink: can't write: stat %d",stat); }; return(1); } /* Write bitfile(9.5) format */ bitfile_sink(rl,a) RLE_Line *rl; Copy_arg *a; #define dbg_Bo (F) { int stat; int ci,towrite; register unsigned char uc,*cp,*pp,*ep; if(_O.dbg_r||dbg_Bo) nerr_RLE_Line("bitfile_sink: ",rl); if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; } if(rl!=NULL) { /* copy current to prior */ memcpy(a->ph->pline,a->ph->line,a->ph->bpl); memset(a->ph->line,'\0',a->ph->bpl); if(rl->runs>0) { /* convert *rl to binary, using ``big-endian'' bit-order */ brrlb(rl->runs,rl->r, a->ph->bx.a.x,a->ph->bx.b.x, 0,a->ph->line); if(dbg_Bo) { unsigned char *cb,*eb; fprintf(stderr,"a->ph->line: "); for(eb=(cb=a->ph->line)+a->ph->bpl;cb<eb;cb++) fprintf(stderr,"%02X",*cb); fprintf(stderr,"\n"); }; }; /* break up output into blocks of 2*126 bytes; SHOULD also try run-length coding */ ci=0; while((towrite=a->ph->bpl-ci) > 0) { if(towrite >= 2*127) towrite=2*126; /* write control byte for block */ uc = towrite/2; if(dbg_Bo) err("cb: %02X",uc); putc(uc,a->ph->fp); for(ep=(cp=a->ph->line+ci)+towrite,pp=a->ph->pline+ci; cp<ep; cp++,pp++) { /* write XOR byte */ uc = *cp ^ *pp; if(dbg_Bo) err("db %d: %02X = c%02X ^ p%02X",cp-a->ph->line,uc,*cp,*pp); putc(uc,a->ph->fp); }; ci += towrite; }; } else { free(a->ph->line); a->ph->line=NULL; free(a->ph->pline); a->ph->pline=NULL; fflush(a->ph->fp); }; } rle_sink(rl,a) RLE_Line *rl; Copy_arg *a; { if(_O.dbg_r) nerr_RLE_Line("rle_sink: ",rl); if(a->bop) { RIC_hdr rh; rh.bx = a->ph->bx; rh.res_x = a->ph->res_x; rh.res_y = a->ph->res_y; RLE_put_hdr(fileno(a->ph->fp),&rh,1); a->ph->cy = a->ph->bx.a.y-1; a->bop=F; }; if(rl!=NULL) { if(rl->runs>0) RLE_put_Line(fileno(a->ph->fp),rl); a->ph->cy++; } else RLE_close(fileno(a->ph->fp)); return(1); } /* Write next line of runs to g31 file, after shifting runs to lie in the range [ 0, a->ph->bx.b.x - a->ph->bx.a.x ]. */ g31_sink(rl,a) RLE_Line *rl; Copy_arg *a; { int stat; RLE_Line crl; RLE_Run *rp,*ep,*np; if(_O.dbg_r) nerr_RLE_Line("g31_sink: ",rl); if(a->bop) { PIC_put_hdr(a->ph); /* treat FILE *a->ph->fp as a sequence of bits */ if((a->bf=bopen(a->ph->fp,"w"))==NULL) abort("g31_sink: can't open bitfile"); BOF_to_g31(a->bf); a->bop=F; }; if(rl!=NULL) { /* check that rl->len is consistent with a->ph */ if(rl->len != a->ph->bx.b.x - a->ph->bx.a.x + 1) { err("g31_sink: rl->len %d != wid(a->ph.bx) %d", rl->len, a->ph->bx.b.x - a->ph->bx.a.x + 1); rl->len = a->ph->bx.b.x - a->ph->bx.a.x + 1; }; if(rl->runs>0) { if(a->ph->bx.a.x!=0) { /* shift runs */ crl.y = rl->y; crl.len = rl->len; crl.runs = rl->runs; for(ep=(rp=rl->r)+rl->runs,np=crl.r; rp<ep; rp++,np++) { np->xs = rp->xs - a->ph->bx.a.x; np->xe = rp->xe - a->ph->bx.a.x; }; rlel_to_g31(&crl,crl.len,a->bf); } else rlel_to_g31(rl,rl->len,a->bf); } else rlel_to_g31(NULL,rl->len,a->bf); a->ph->cy++; } else { EOF_to_g31(a->bf); bclose(a->bf); }; return(1); } /* Write next line of runs to g32 file, after shifting runs to lie in the range [ 0, a->ph->bx.b.x - a->ph->bx.a.x ]. */ g32_sink(rl,a) RLE_Line *rl; Copy_arg *a; { static RLE_Line prl; RLE_Line *pl; RLE_Line crl; RLE_Run *rp,*ep,*np; if(_O.dbg_r) nerr_RLE_Line("g32_sink: ",rl); if(a->bop) { PIC_put_hdr(a->ph); /* treat FILE *a->ph->fp as a sequence of bits */ if((a->bf=bopen(a->ph->fp,"w"))==NULL) abort("can't open bitfile"); BOF_to_g32(a->bf); a->bop=F; prl.runs = 0; }; if(rl!=NULL) { /* check that rl->len is consistent with a->ph */ if(rl->len != a->ph->bx.b.x - a->ph->bx.a.x + 1) { err("g32_sink: rl->len %d != wid(a->ph.bx) %d", rl->len, a->ph->bx.b.x - a->ph->bx.a.x + 1); rl->len = a->ph->bx.b.x - a->ph->bx.a.x + 1; }; prl.len = rl->len; prl.y = rl->y - 1; if(((a->ph->cy+1-a->ph->bx.a.y)%a->k)==0) pl=NULL; else pl=&prl; if(rl->runs>0) { if(a->ph->bx.a.x!=0) { /* shift runs */ crl.y = rl->y; crl.len = rl->len; crl.runs = rl->runs; for(ep=(rp=rl->r)+rl->runs,np=crl.r; rp<ep; rp++,np++) { np->xs = rp->xs - a->ph->bx.a.x; np->xe = rp->xe - a->ph->bx.a.x; }; rlel_to_g32(pl,&crl,crl.len,a->bf); prl.y=crl.y; prl.len=crl.len; prl.runs=crl.runs; memcpy(prl.r,crl.r,2*prl.runs*sizeof(short)); } else { rlel_to_g32(pl,rl,rl->len,a->bf); prl.y=rl->y; prl.len=rl->len; prl.runs=rl->runs; memcpy(prl.r,rl->r,2*prl.runs*sizeof(short)); }; } else { rlel_to_g32(pl,NULL,rl->len,a->bf); prl.y=rl->y; prl.len=rl->len; prl.runs=0; } a->ph->cy++; } else { EOF_to_g32(a->bf); bclose(a->bf); prl.runs = 0; }; return(1); } /* Write next line of runs to g4 file, after shifting runs to lie in the range [ 0, a->ph->bx.b.x - a->ph->bx.a.x ]. */ g4_sink(rl,a) RLE_Line *rl; Copy_arg *a; { static RLE_Line prl; RLE_Line crl; RLE_Run *rp,*ep,*np; if(_O.dbg_r) nerr_RLE_Line("g4_sink: ",rl); if(a->bop) { PIC_put_hdr(a->ph); /* treat FILE *a->ph->fp as a sequence of bits */ if((a->bf=bopen(a->ph->fp,"w"))==NULL) abort("can't open bitfile"); BOF_to_g4(a->bf); a->bop=F; prl.runs = 0; }; if(rl!=NULL) { /* check that rl->len is consistent with a->ph */ if(rl->len != a->ph->bx.b.x - a->ph->bx.a.x + 1) { err("g4_sink: rl->len %d != wid(a->ph.bx) %d", rl->len, a->ph->bx.b.x - a->ph->bx.a.x + 1); rl->len = a->ph->bx.b.x - a->ph->bx.a.x + 1; }; if(rl->runs>0) { if(a->ph->bx.a.x!=0) { /* shift runs */ crl.y = rl->y; crl.len = rl->len; crl.runs = rl->runs; for(ep=(rp=rl->r)+rl->runs,np=crl.r; rp<ep; rp++,np++) { np->xs = rp->xs - a->ph->bx.a.x; np->xe = rp->xe - a->ph->bx.a.x; }; rlel_to_g4(&prl,&crl,crl.len,a->bf); prl.y=crl.y; prl.len=crl.len; prl.runs=crl.runs; memcpy(prl.r,crl.r,2*prl.runs*sizeof(short)); } else { rlel_to_g4(&prl,rl,rl->len,a->bf); prl.y=rl->y; prl.len=rl->len; prl.runs=rl->runs; memcpy(prl.r,rl->r,2*prl.runs*sizeof(short)); }; } else { rlel_to_g4(&prl,NULL,rl->len,a->bf); prl.runs=0; } a->ph->cy++; } else { EOF_to_g4(a->bf); bclose(a->bf); prl.runs = 0; }; return(1); } pic_sink(rl,a) RLE_Line *rl; Copy_arg *a; { int stat; if(_O.dbg_r) nerr_RLE_Line("pic_sink: ",rl); if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; }; if(rl!=NULL) { crrl(rl->runs,rl->r,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->line); if((stat=PIC_wline(a->ph,a->ph->line))!=1) abort("pic_sink: can't write: stat %d",stat); }; return(1); } #if CPU==SUN post_sink(rl,a) RLE_Line *rl; Copy_arg *a; { int stat; if(_O.dbg_r) nerr_RLE_Line("post_sink: ",rl); if (a->bop) { PIC_put_hdr(a->ph); /* needed for allocation of h->line? */ POST_start(a->ph); a->bop = F; }; if(rl!=NULL) { memset(a->ph->line,'\0',a->ph->bpl); if(rl->runs>0) { /* convert *rl to binary, using ``little-endian'' bit-order */ brrl(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line); }; if((stat=POST_wline(a->ph,a->ph->line))!=1) abort("post_sink: can't write: stat %d",stat); } else { POST_end(); }; return(1); } #else post_sink() {abort("-P postscript output unimplemented");}; #endif #if CPU==SUN rast_sink(rl,a) RLE_Line *rl; Copy_arg *a; { int stat; if(_O.dbg_r) nerr_RLE_Line("rast_sink: ",rl); if (a->bop) { PIC_put_hdr(a->ph); /* needed for allocation of h->line? */ RAST_start(a->ph); a->bop = F; }; if(rl!=NULL) { memset(a->ph->line,'\0',a->ph->bpl); if(rl->runs>0) { /* convert *rl to binary, using ``little-endian'' bit-order */ brrl(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line); }; if((stat=RAST_wline(a->ph,a->ph->line))!=1) abort("rast_sink: can't write: stat %d",stat); } else { RAST_end(); }; return(1); } #else rast_sink() {abort("-S sunraster output unimplemented");}; #endif /* Save RLE_Line *rl in buffer, as packed binary, using ``little-endian'' bit-packing order, rounding each line to the nearest int for speed. If a->bop, malloc a complete, contiguous buffer holding the entire page, and initialize its contents to zeroes. On each call with rl!=NULL, convert the given line to binary & save in buffer. When called with rl==NULL but a!=NULL, signalling end-of-page, do nothing. Normally, return kludgey (unsigned int *)1, like other sink functions. When called with rl==NULL && a==NULL, return pointer to buffer. It is the responsibility of the calling code to free the buffer. */ unsigned int *binary_buffer(rl,a) RLE_Line *rl; Copy_arg *a; { static unsigned int *buf = NULL; static int ipl = 0; /* ints/line */ int bufsz; /* (bytes) */ unsigned int *result; #define BITS_PER_INT (8*sizeof(int)) if(a!=NULL && a->bop) { /* round up to int boundary */ ipl = (bbx_wid(&(a->ph->bx))+BITS_PER_INT-1)/BITS_PER_INT; bufsz = sizeof(int)*ipl*bbx_hgt(&(a->ph->bx)); if((buf=(unsigned int *)malloc(bufsz))==NULL) abort("binary_buffer: can't alloc int buf[%d]",bufsz/sizeof(int)); memset(buf,'\0',bufsz); a->bop=F; }; if(rl!=NULL) { /* convert *rl to binary, using ``little-endian'' bit-order */ if(rl->runs>0) { /* *rl --> binary, with ``little-endian'' bit-order */ #if BIG_ENDIAN brrlb( rl->runs, rl->r, a->ph->bx.a.x, a->ph->bx.b.x, 0, buf+(ipl*(rl->y-a->ph->bx.a.y)) ); #else brrl( rl->runs, rl->r, a->ph->bx.a.x, a->ph->bx.b.x, 0, buf+(ipl*(rl->y-a->ph->bx.a.y)) ); #endif }; return((unsigned int *)1); } else { if(a!=NULL) return((unsigned int *)1); else { result = buf; buf = NULL; ipl = 0; return(result); }; }; } /* Rotate binary buffer *buf (whose shape is specified by a->ph->bx), through angle tra->rot, and write the resulting stream of RLE_Line's to sink() one at a time, along with a rotated version of *a as the 2nd argument. Only PI/2 is supported; UNDER DEVELOPMENT: other multiples of PI/2 and small arbitrary angles. */ rotate_binary_buffer(buf,tra,sink,a) unsigned int *buf; Transform_rlel_arg *tra; int (*sink)(); /* takes args: (RLE_Line *), and int */ Copy_arg *a; { register int ipl; /* ints/line in binary buffer */ Copy_arg ra; /* rotated */ RLE_Line rl; #define TINY_ANG (PI/1000) /* round up to int boundary */ ipl = (bbx_wid(&(a->ph->bx))+BITS_PER_INT-1)/BITS_PER_INT; ra = *a; ra.bop=T; if((ra.ph = (PIC_hdr *)malloc(sizeof(PIC_hdr)))==NULL) abort("rotate_binary_buffer: can't malloc ra.ph"); *(ra.ph) = *(a->ph); /* by arbitrary convention, rotated bx.a will coincide with input bx.a */ if(tra->rot <= PI/2+TINY_ANG && tra->rot >= PI/2-TINY_ANG) { int ey,ii; register RLE_Run *rp; register unsigned int *cb,*eb,bm,obm; register short rx; ra.ph->bx.b.x = a->ph->bx.a.x + bbx_hgt(&(a->ph->bx)) - 1; ra.ph->bx.b.y = a->ph->bx.a.y + bbx_wid(&(a->ph->bx)) - 1; rl.len = ra.wid = bbx_wid(&(ra.ph->bx)); rl.y = ra.ph->bx.a.y; ey=ra.ph->bx.b.y; ii=0; bm=01; do { obm=0; /* assume 0 left of margin */ rp=rl.r-1; rx=ra.ph->bx.a.x; cb=(eb=buf+ii)+((rl.len-1)*ipl); do { if((*cb & bm)!=obm) { if(obm) { rp->xe=rx-1; obm=0; } else { (++rp)->xs=rx; obm=bm; }; }; rx++; } while( (cb -= ipl) >= eb ); if(obm) rp->xe=rx-1; rl.runs = rp - rl.r + 1; sink(&rl,&ra); if((bm<<=1)==0) {ii++; bm=01;}; } while((++rl.y)<=ey); } else if(tra->rot <= PI+TINY_ANG && tra->rot >= PI-TINY_ANG) { rl.len = ra.wid; abort("rotate_binary_buffer: tra->rot==%g deg unimplemented", tra->rot/DtoR); } else if(tra->rot <= 3*PI/2+TINY_ANG && tra->rot >= 3*PI/2-TINY_ANG) { ra.ph->bx.b.x = a->ph->bx.a.x + bbx_hgt(&(a->ph->bx)) - 1; ra.ph->bx.b.y = a->ph->bx.a.y + bbx_wid(&(a->ph->bx)) - 1; rl.len = ra.wid = bbx_wid(&(ra.ph->bx)); abort("rotate_binary_buffer: tra->rot==%g deg unimplemented", tra->rot/DtoR); } else if(tra->rot <= 20.0*DtoR && tra->rot >= -20.0*DtoR) { /* rotation by ``small'' angle */ Sp ce; /* center of image to be rotated */ double rcos,rsin; /* real rotation vector (cos,sin) */ double irx,iry; /* current rotated pixel location */ register int sx,sy,ex,ey,rx,ry; register RLE_Run *rp; register int pel,opel; register int orx,ory; if(0) err("rotate_binary_buffer: tra->rot==%g deg under development", tra->rot/DtoR); /* conventionally, keep the same window as the input image, while rotating about its midpoint */ rl.len = ra.wid = bbx_wid(&(ra.ph->bx)); sx = ra.ph->bx.a.x; ex = ra.ph->bx.b.x; sy = ra.ph->bx.a.y; ey = ra.ph->bx.b.y; ce.x = sx + bbx_wid(&(ra.ph->bx))/2; ce.y = sy + bbx_hgt(&(ra.ph->bx))/2; rcos = cos(tra->rot); rsin = sin(tra->rot); for(ory=sy; ory<=ey; ory++) { opel=0; /* left of output margin: assume pel==0 */ rp=rl.r-1; irx = ((rcos*(sx - ce.x) - rsin*(ory - ce.y))) + ce.x; iry = ((rsin*(sx - ce.x) + rcos*(ory - ce.y))) + ce.y; for(orx=sx; orx<=ex; orx++) { rx = (int)(irx + 0.5); ry = (int)(iry + 0.5); if(rx<sx || rx>ex || ry<sy || ry>ey) /* outside input image: assume pel==0 */ pel=0; else /* look at bit within input image */ { int ix,iy,bx; iy = (ry-sy)*ipl; ix = rx/BITS_PER_INT; bx = rx%BITS_PER_INT; #if BIG_ENDIAN pel = (buf[ iy + ix ] & (01<<(BITS_PER_INT-bx-1))) ? 1 : 0; #else pel = (buf[ iy + ix ] & (01<<bx)) ? 1 : 0; #endif }; if(pel!=opel) { if(opel) { rp->xe=orx-1; opel=0; } else { (++rp)->xs=orx; opel=pel; }; }; /* step one pel to the right in output image */ irx += rcos; iry += rsin; }; if(opel) rp->xe=orx-1; rl.runs = rp - rl.r + 1; rl.y = ory; sink(&rl,&ra); }; } else { abort("rotate_binary_buffer: tra->rot==%g deg unimplemented", tra->rot/DtoR); }; sink(NULL,&ra); /* signal end-of-page */ } /* Copy a source of RLE_Lines to a sink of RLE_Lines, transforming them by trimming, shifting, scaling, truncation, and rotation. The source is function ir(), which returns non-empty lines only, or NULL on end of page. It is passed `bop=T' on beginning of page. On return from ir(), ia->ph->cy holds the index of the line, whose height is guaranteed to lie in the range [ia->ph->bx.a.y,ia->ph->bx.b.y]. All input runs are guaranteed to lie in [ia->ph->bx.a.x,ia->ph->bx.b.x]. The maximum length (in pels) of each source line is ia->wid. The sink function or() takes two arguments: RLE_Line *rl; ==NULL on end-of-page Copy_arg *a; The lines sent to the sink must be in unbroken ascending integer sequence of rl->y (thus blank lines must be explicitly sent). At all times, oa->ph->cy is the line last written. After the first call to or(), oa->ph->cy lies in the range [oa->ph->bx.a.y,oa->ph->bx.b.y]. Trimming, shifting, scaling, and truncation are performed either here or in function transform_rlel(). Rotation is handled specially: the complete output image (after all other transformations have been performed) is saved in an intermediate buffer (as packed binary), then rotated. Rotation is much slower than the other operations, mainly due to the necessity of touching every pixel. (Manhattan rotations might be faster if the buffer held RLE_lines, but then it would be next-to-impossible to extend to arbitrary rotations someday.) */ transform_rlels(ir,ia,or,oa,tra) RLE_Line *(*ir)(); /* return next RLE_Line */ Copy_arg *ia; /* used here (bop & wid) & passed to ir() */ int (*or)(); /* write next RLE_Line */ Copy_arg *oa; /* used here (bop && ph->bx.*.y) & passed to or() */ Transform_rlel_arg *tra; { RLE_Line *irl,*orl; static RLE_Line rl0 = Init_RLE_Line; /* empty line */ int tr_y; /* transformed y */ int (*sv_or)(); if(tra->rot!=0.0) { /* if must rotate the image, first buffer the entire set of output RLE_Lines */ sv_or = or; or = (int (*)())binary_buffer; }; /* signal beginning of page; reset in source() & sink() functions */ ia->bop=oa->bop=T; /* set first output line number to write */ tra->dy = (tra->sy = oa->ph->bx.a.y); while((irl=ir(ia))!=NULL) { if(F&&_O.dbg_r) nerr_RLE_Line("trans.i: ",irl); /* trim input lines' Y */ if(irl->y < tra->tr.a.y) continue; if(irl->y > tra->tr.b.y) break; /* compute the output Y that is equal to the last of the group of transformed equivalent Y's */ tr_y = (int)((irl->y + tra->off.y + 1)*tra->scl.y) - 1; /* truncate if necessary */ if(tr_y>oa->ph->bx.b.y) tr_y = oa->ph->bx.b.y; /* supply implicit blank line(s) of the same length */ while(tra->sy < tr_y) { rl0.len = ia->wid; transform_rlel(&rl0,tra,or,oa); }; irl->len = ia->wid; transform_rlel(irl,tra,or,oa); }; /* supply terminating blank line(s) of the same length */ while(tra->sy < oa->ph->bx.b.y) { rl0.len = ia->wid; transform_rlel(&rl0,tra,or,oa); }; transform_rlel(NULL,tra,or,oa); /* signal end of page */ /* read input until end of page occurs; this is required to support catenated pages */ while(irl!=NULL) irl=ir(ia); if(tra->rot!=0.0) { unsigned int *buf; buf = binary_buffer(NULL,NULL); if(buf!=NULL) { rotate_binary_buffer(buf,tra,sv_or,oa); free(buf); }; }; } process_page(i,o) Copy_arg *i,*o; { RLE_Line *(*source)(); int (*sink)(); char unit,*up,cpy[40]; /* units character */ Transform_rlel_arg tra; i->wid = bbx_wid(&(i->ph->bx)); _O.trim = max_Bbx; /* start by trimming nothing */ /* translate units in option arguments */ if(_O.optarg_l!=NULL) { strcpy(cpy,_O.optarg_l); if((up=strpbrk(cpy,UNITS))!=NULL) { unit= *up; *up='\0'; _O.trim.a.x=vto_scoor(atof(cpy),unit,i->ph->res_x); } else /* assume scanner coordinates */ _O.trim.a.x=atoi(cpy); }; if(_O.optarg_r!=NULL) { strcpy(cpy,_O.optarg_r); if((up=strpbrk(cpy,UNITS))!=NULL) { unit= *up; *up='\0'; _O.trim.b.x=vto_scoor(atof(cpy),unit,i->ph->res_x); } else /* assume scanner coordinates */ _O.trim.b.x=atoi(cpy); _O.trim.b.x--; /* -w coordinate is open, Bbx is closed */ }; if(_O.optarg_t!=NULL) { strcpy(cpy,_O.optarg_t); if((up=strpbrk(cpy,UNITS))!=NULL) { unit= *up; *up='\0'; _O.trim.a.y=vto_scoor(atof(cpy),unit,i->ph->res_y); } else /* assume scanner coordinates */ _O.trim.a.y=atoi(cpy); }; if(_O.optarg_b!=NULL) { strcpy(cpy,_O.optarg_b); if((up=strpbrk(cpy,UNITS))!=NULL) { unit= *up; *up='\0'; _O.trim.b.y=vto_scoor(atof(cpy),unit,i->ph->res_y); } else /* assume scanner coordinates */ _O.trim.b.y=atoi(cpy); _O.trim.b.y--; /* -w coordinate is open, Bbx is closed */ }; /* Modified output margins may lie OUTSIDE the input window as well as within it. */ if(_O.trim.a.x==Scoor_MIN) _O.trim.a.x=i->ph->bx.a.x; if(_O.trim.b.x==Scoor_MAX) _O.trim.b.x=i->ph->bx.b.x; if(_O.trim.a.y==Scoor_MIN) _O.trim.a.y=i->ph->bx.a.y; if(_O.trim.b.y==Scoor_MAX) _O.trim.b.y=i->ph->bx.b.y; if(_O.dbg_m) err("trim: %s",bbx_toa(&(_O.trim))); if(strcmp(i->ph->type,"binary")==0) { source = binary_source; } else if(strcmp(i->ph->type,"bitmap")==0) { source = bitmap_source; } else if(strcmp(i->ph->type,"bitfile")==0) { source = bitfile_source; } else if(strcmp(i->ph->type,"document-image")==0) { source = dim_source; } else if(strcmp(i->ph->type,"dim")==0) { source = dim_source; } else if(strcmp(i->ph->type,"rle")==0) { RIC_hdr rh; /* reopen RLE file to use system I/O (awkward, obsolescent) */ lseek(fileno(i->ph->fp),0L,0); RLE_open(fileno(i->ph->fp),&rh); i->ph->cy = i->ph->bx.a.y-1; source = rle_source; } else if(strcmp(i->ph->type,"pico")==0 ||strcmp(i->ph->type,"dump")==0) { i->thresh = _O.thresh; source = pic_source; } else if(strcmp(i->ph->type,"ccitt-g31")==0) { if((i->bf=bopen(i->ph->fp,"r"))==NULL) abort("can't open bitfile"); i->tbl = ccitt_table(); source = g31_source; } else if(strcmp(i->ph->type,"ccitt-g32")==0) { if((i->bf=bopen(i->ph->fp,"r"))==NULL) abort("can't open bitfile"); i->tbl = ccitt_table(); source = g32_source; } else if(strcmp(i->ph->type,"ccitt-g4")==0) { if((i->bf=bopen(i->ph->fp,"r"))==NULL) abort("can't open bitfile"); i->tbl = ccitt_table(); source = g4_source; } else if(strcmp(i->ph->type,"cdf-mrlc")==0) { source = cdf_mrlc_source; } else abort("Input file TYPE=%s unsupported",i->ph->type); if(_O.dbg_h) err("In %s",PIC_hdr_toa(i->ph)); /* Adjudicate -R and -x options */ if(_O.out_res.x==-2) { /* -R= specified: force resolutions to be equal to the greater */ if(i->ph->res_x < i->ph->res_y) { _O.out_res.x = _O.out_res.y = i->ph->res_y; } else if(i->ph->res_y < i->ph->res_x) { _O.out_res.x = _O.out_res.y = i->ph->res_x; } else _O.out_res.x = _O.out_res.y = i->ph->res_x; }; if(_O.out_res.x!=-1) { /* -Rx specified; override -xX */ _O.expand.x = ((double)_O.out_res.x)/i->ph->res_x; if(_O.dbg_R && _O.expand.x!=1.0) err("horizontal resolution changed: x%g (%d -> %d)", _O.expand.x,i->ph->res_x,_O.out_res.x); }; if(_O.out_res.y!=-1) { /* -R,y specified; override -x,Y */ _O.expand.y = ((double)_O.out_res.y)/i->ph->res_y; if(_O.dbg_R && _O.expand.y!=1.0) err("vertical resolution changed: x%g (%d -> %d)", _O.expand.y,i->ph->res_y,_O.out_res.y); }; /* Setup image transformation parameters */ tra = empty_Transform_rlel_arg; tra.tr = _O.trim; tra.off = _O.offset; tra.scl = _O.expand; tra.wh.x = bbx_wid(&(tra.tr)); tra.wh.y = bbx_hgt(&(tra.tr)); tra.rev = _O.reverse; if(tra.scl.x!=1.0) { tra.wh.x = (int)(tra.wh.x*tra.scl.x+0.5); }; if(tra.scl.y!=1.0) { tra.wh.y = (int)(tra.wh.y*tra.scl.y+0.5); }; switch(_O.top) { case 't': /* default */ break; case 'l': /* top is really at left */ tra.rot = (Radians)(PI/2); break; case 'b': /* top is really at bottom */ tra.rot = (Radians)(PI); break; case 'r': /* top is really at right */ tra.rot = (Radians)((3*PI)/2); break; case 'a': /* rotation angle given */ tra.rot = _O.top_angle; break; }; /* is the transform the identity? (speed-optimized special case) */ tra.ident = ( (bbx_eq(&(tra.tr),&(i->ph->bx))) && (tra.scl.x==1.0) && (tra.scl.y==1.0) && (tra.off.x==0) && (tra.off.y==0) && (tra.rot==0.0) ); /* compute transformed output box & resolution; don't rotate here (see transform_rlels()) */ if(tra.ident) { o->ph->bx = i->ph->bx; o->ph->res_x = i->ph->res_x; o->ph->res_y = i->ph->res_y; } else { o->ph->bx = tra.tr; o->ph->bx.a.x += tra.off.x; o->ph->bx.b.x += tra.off.x; o->ph->bx.a.y += tra.off.y; o->ph->bx.b.y += tra.off.y; if(tra.scl.x!=1.0) { o->ph->bx.a.x = tra.scl.x*o->ph->bx.a.x; o->ph->bx.b.x = o->ph->bx.a.x + tra.wh.x-1; }; if(tra.scl.y!=1.0) { o->ph->bx.a.y = tra.scl.y*o->ph->bx.a.y; o->ph->bx.b.y = o->ph->bx.a.y + tra.wh.y-1; }; o->ph->res_x = (i->ph->res_x*tra.scl.x + 0.5); o->ph->res_y = (i->ph->res_y*tra.scl.y + 0.5); }; if(_O.to_bin) { strcpy(o->ph->type,"binary"); sink = binary_sink; } else if(_O.to_bitfile) { strcpy(o->ph->type,"bitfile"); sink = bitfile_sink; } else if(_O.to_bitmap) { strcpy(o->ph->type,"bitmap"); sink = bitmap_sink; } else if (_O.to_rle) { if(strcmp(i->ph->type,"rle")==0) abort("can't both read and write TYPE=rle - sorry"); strcpy(o->ph->type,"rle"); sink = rle_sink; } else if(_O.to_g31) { strcpy(o->ph->type,"ccitt-g31"); sink = g31_sink; } else if(_O.to_g32) { strcpy(o->ph->type,"ccitt-g32"); o->k = _O.g32_k; sink = g32_sink; } else if(_O.to_g4) { strcpy(o->ph->type,"ccitt-g4"); sink = g4_sink; } else if(_O.to_pic) { strcpy(o->ph->type,"dump"); sink = pic_sink; } #if CPU==SUN else if(_O.to_post) { strcpy(o->ph->type,"postscript"); sink = post_sink; } #endif #if CPU==SUN else if(_O.to_rast) { strcpy(o->ph->type,"sunraster"); sink = rast_sink; } #endif if(i->ph->misc!=NULL) { o->ph->misc = i->ph->misc; i->ph->misc = NULL; }; if(_O.dbg_h) err("Out %s",PIC_hdr_toa(o->ph)); transform_rlels(source,i,sink,o,&tra); /* Synchronize filedes pointer with stream pointer */ lseek(fileno(o->ph->fp),o->ph->seek = ftell(o->ph->fp),0); } /* A file may be a catenation of pages. */ process_fps(i,o) FILE *i,*o; { Copy_arg ia,oa; int stat; ia = oa = empty_Copy_arg; ia.ph = alloc_PIC_hdr(i); oa.ph = alloc_PIC_hdr(o); stat=PIC_get_hdr(ia.ph); if(_O.dbg_h && stat!=1) err("PIC_get_hdr() returns status %d",stat); /* enforce bitfile(9) I/O restrictions */ if(_O.from_bitfile && strcmp(ia.ph->type,"bitfile")!=0) abort("-Bi requires input to be bitfile(9.5) format"); if(!_O.from_bitfile && strcmp(ia.ph->type,"bitfile")==0) { /* TYPE= is missing, erroneously: refuse to recognize it */ abort("TYPE=... header is missing"); }; if(strcmp(ia.ph->type,"document-image")==0 || strcmp(ia.ph->type,"dim")==0) { Page pg; skip_doc(i); if(frdb_page_etc(i,&pg,IsALL)==1) { ia.ph->bx = pg.bx; ia.ph->res_x = pg.res_x; ia.ph->res_y = pg.res_y; ia.rles = *rle_lines_of_page(&pg); if(_O.shrinkwrap!=-1) { Sp trans; ia.ph->bx = *bbx_of_rle_lines(&ia.rles); ia.ph->bx.a.x -= _O.shrinkwrap; ia.ph->bx.a.y -= _O.shrinkwrap; ia.ph->bx.b.x += _O.shrinkwrap; ia.ph->bx.b.y += _O.shrinkwrap; if(bbx_area(&(ia.ph->bx))<=0) abort("-W%d shrinks to nothing",_O.shrinkwrap); trans.x = -ia.ph->bx.a.x; trans.y = -ia.ph->bx.a.y; translate_rle_lines(&ia.rles,trans); ia.ph->bx.b.x = bbx_wid(&ia.ph->bx)-1; ia.ph->bx.b.y = bbx_hgt(&ia.ph->bx)-1; ia.ph->bx.a.x = ia.ph->bx.a.y = 0; }; free_page_etc(&pg,IsALL&(~IsPage)); } else { free_page_etc(&pg,IsALL&(~IsPage)); abort("can't read document-image file"); }; }; if(_O.in_res.x!=SHRT_MIN&&_O.in_res.y!=SHRT_MIN) { /* force input RES to given values */ if(ia.ph->res_x!=0 || ia.ph->res_y!=0) { err("input: RES=%d %d overridden by -Z%d,%d\n", ia.ph->res_x,ia.ph->res_y,_O.in_res.x,_O.in_res.y); }; ia.ph->res_x = _O.in_res.x; ia.ph->res_y = _O.in_res.y; }; if(ia.ph->res_x<=0 || ia.ph->res_y<=0) err("input: RES=%d %d may cause problems (set using -Zx,y)", ia.ph->res_x,ia.ph->res_y); while(strlen(ia.ph->type)>0 && stat==1 && !feof(i) && !ferror(i) && !ferror(o)) { process_page(&ia,&oa); if( strcmp(ia.ph->type,"cdf")==0 || strcmp(ia.ph->type,"cdf-mrlc")==0 ) { stat=CDF_next_page(ia.ph); } else { if((stat=PIC_get_hdr(ia.ph))==1) { /* enforce bitfile(9) I/O restrictions */ if(_O.from_bitfile && strcmp(ia.ph->type,"bitfile")!=0) abort("-Bi means input must be picfile"); if(!_O.from_bitfile && strcmp(ia.ph->type,"bitfile")==0) { /* TYPE= is missing, erroneously: silently quit */ if(_O.dbg_h) err("strange input before normal EOF - ignored"); strcpy(ia.ph->type,""); }; }; }; if(_O.dbg_h && stat!=1) err("PIC_get_hdr() returns status %d",stat); }; /* EOF or error */ free_PIC_hdr(ia.ph); free_PIC_hdr(oa.ph); } #if FILE_TREE /* Process filenames: if NULL, use stdin/stdout; if files, read them; if directories, create a parallel file tree and process the leaves pairwise. */ process_fns(i,o) char *i; /* may be NULL; not yet fopened for read */ char *o; /* may be NULL; not yet fopened for write */ #define dbg_ft (F) { FILE *i_fp; FILE *o_fp; char *branch; if(dbg_ft) err("processs(\"%s\",\"%s\")",i,o); branch=path_toa(&path_process.path,1); if(dbg_ft&&branch[0]!='\0') err("%s",branch); if(i==NULL||i[0]=='\0') i_fp=stdin; else if( (i_fp=fopen(i,"r"))==NULL ) { err("can't open input file %s - skip it",i); return; }; if(o==NULL||o[0]=='\0') o_fp=stdout; else if( (o_fp=fopen(o,"w"))==NULL ) { err("can't open output file %s - skip it",o); return; }; process_fps(i_fp,o_fp); if(i_fp!=stdin) fclose(i_fp); if(o_fp!=stdout) fclose(o_fp); else fflush(o_fp); }; #else /* Process filenames: if NULL, use stdin/stdout; if files, open and process them. */ process_fns(i_fn,o_fn) char *i_fn; /* may be NULL; not yet fopened for read */ char *o_fn; /* may be NULL; not yet fopened for write */ { FILE *i_fp; FILE *o_fp; if(i_fn==NULL||strlen(i_fn)==0) i_fp = stdin; else { if((i_fp=fopen(i_fn,"r"))==NULL) abort("can't open input file %s",i_fn); }; if(o_fn==NULL||strlen(o_fn)==0) o_fp = stdout; else { if((o_fp=fopen(o_fn,"w"))==NULL) abort("can't open output file %s",o_fn); }; process_fps(i_fp,o_fp); if(i_fp!=stdin) fclose(i_fp); if(o_fp!=stdout) fclose(o_fp); else fflush(o_fp); }; #endif main(arc,arv) int arc; char **arv; { parse_args(arc,arv); #if FILE_TREE process_file_trees(process_fns,_O.in_fn,_O.out_fn); #else process_fns(_O.in_fn,_O.out_fn); #endif } nerr_RLE_Line(s,rl) char *s; RLE_Line *rl; { RLE_Run *r; int ri; if(rl==NULL) fprintf(stderr,"%15s RLEL NULL.\n",s); else { fprintf(stderr,"%15s RLEL y%d r%d l%d: ",s,rl->y,rl->runs,rl->len); for(ri=0,r=rl->r; ri<rl->runs; ri++,r++) fprintf(stderr,"[%d,%d] ",r->xs,r->xe); fprintf(stderr,"\n"); }; } 0707070035351137201006640007620000050000010263350476773367100001000000030702bitio.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* bitio.h - view a stream file as a sequence of binary values, hiding the bit- and byte-packing format of the file. The format of input and output files may differ. Reading and writing are performed by macroes for speed; the price for this is that the file formats must be fixed at compile time. SYNOPSIS #include <stdio.h> #include "bitio.h" BITFILE *bopen(stream,type); FILE *stream; char *type; int getb(bitfile); BITFILE *bitfile; putb(bit,bitfile); int bit; padb(bitfile,bit,bdy,len); int bit,bdy,len; char *bbuffer(bitfile); unsigned long bsize(bitfile); unsigned long bflush(bitfile); unsigned long bclose(bitfile); COMPILER DEPENDENCIES The compiler's data types must include: unsigned char: 8 bits each unsigned short: 2 unsigned chars each unsigned int: 2 unsigned shorts each DESCRIPTION Bopen views the named stream file as a bit file to be read (if type is "r") or written (if type is "w" or "wb"). The stream file must already have been fopen(3)ed, and the first bit to be read/written will be the first bit in its next byte in getc(3)/putc(3) order. Bopen returns a pointer which identifies the bitfile to the other functions. System or stream I/O to/from the associated stream should not be used until after bclose is called. If bopen's type is "wb", then the entire output stream will be buffered in main memory until bflush or bclose are called. At any time, bbuffer returns this buffer's address and bsize its length in bytes. Getb returns the next bit from the named bitfile. It returns EOF on end of file or read error. EOF may occur on a byte, short, or int boundary, depending on file format. Putb appends the given bit to the named bitfile. Padb writes 'bit' enough times (possibly 0) so that if a bitstring of length 'len' were written next it would end on a 'bdy'-bit boundary (may do the wrong thing if 'bdy' doesn't divide UINT_MAX). Bflush ensures that all written bits have been written to the stream via putc(3). The output is padded with 0 bits to a byte, short, or int boundary, depending on file format. It returns the number of bytes (not bits) written since bopen or the last bflush. The bitfile remains open. It does not fflush(3) the associated stream. Bclose causes a bflush and frees all buffers. It returns the total number of bytes (not bits) read/written since bopen. It fflush(3)'es, but does not fclose(3) the associated stream. Bitfile formats are selected at compile time: see `FORMAT:' at the end of this file. The formats for input and output may differ. Formats include: a each bit is an ASCII character: '0' or '1', in putc(3) order; not padded. 0 the low-order (0001) bit in each byte is first ("little-endian"), and bytes are in putc(3) order; EOF and padding at a byte boundary. 1 the high-order (0200) bit in each byte is first ("big-endian"), and bytes are in putc(3) order; EOF and padding at a byte boundary. 10 the low-order (0001) bit in each byte is first ("little-endian"), but bytes are reversed (in each pair) from putc(3) order; EOF and padding at a short boundary. 11 the high-order (0200) bit in each byte is first ("big-endian"), but bytes are reversed (in each pair) from putc(3) order; EOF and padding at a short boundary. Planned (data structures are in place; code will be implemented if needed): 100 the low-order (0001) bit in each byte is first ("little-endian"), and bytes (in each pair) are in putc(3) order; but shorts (in each pair) are reversed from putc(3) order; EOF and padding at an int boundary. 101, 110, 111 - by obvious analogy BUGS Putting to an input bitfile or getting from an output bitfile is erroneous, but is not checked for. */ #define BUFFERED (T) /* enable buffering of output */ typedef struct BITFILE { FILE *fp; /* associated stream */ char type; /* one of 'r','w' */ int ic; /* byte just read */ unsigned long nb; /* no. bytes read/written since bopen */ unsigned long alloc; /* no. bytes allocated in buffer */ char *buf; /* buffer (in malloc space) */ char *cp; /* next char in buffer */ unsigned int n; /* no. bits written so far (mod UINT_MAX) */ unsigned char cm; /* single-bit mask */ unsigned short sm; /* single-bit mask */ unsigned int im; /* single-bit mask */ union { struct { /* used to reorder char & short order */ union { struct { unsigned char c0; unsigned char c1; } cc; unsigned short s; } s0; union { struct { unsigned char c0; unsigned char c1; } cc; unsigned short s; } s1; } ss; unsigned int i; } i; } BITFILE; #define Init_BITFILE {NULL,'\0',0,0L,0L,NULL,NULL,0,0,0} #if MAIN BITFILE empty_BITFILE = Init_BITFILE; #else extern BITFILE empty_BITFILE; #endif /* Code common to all formats: */ #if MAIN BITFILE *bopen_rw(s,t) FILE *s; char *t; { BITFILE *f; if((f=(BITFILE *)malloc(sizeof(BITFILE)))==NULL) { err("bopen: can't alloc"); return(NULL); }; *f = empty_BITFILE; f->fp = s; f->type = *t; return(f); } #else BITFILE *bopen_rw(); #endif #define bbuffer(f) ((f)->buf) #define bsize(f) ((bbuffer(f)!=NULL)? ((f)->cp - (f)->buf): 0L) #if !BUFFERED #define bputc(c,f) putc((c),(f)->fp) #define bbflush(f) (0L) #else #define BITFILE_incr (512) /* buffer allocations are in these increments */ #if MAIN brealloc(f) BITFILE *f; { int nbuf; /* no. bytes in buffer */ nbuf = bsize(f); f->alloc += BITFILE_incr; if((f->buf=(char *)realloc(f->buf,f->alloc))==NULL) abort(""); f->cp = f->buf + nbuf; } #endif #define bputc(c,f) { \ if((f)->buf==NULL) putc((c),(f)->fp); \ else { if(bsize(f)==(f)->alloc) brealloc(f); \ *(++((f)->cp))=(c); \ } \ } #if MAIN unsigned long bbflush(f) BITFILE *f; /* f->buf!=NULL && bsize(f)>0 */ { register char *cp,*cq; unsigned long nbuf; nbuf = bsize(f); for(cq=(cp=f->buf)+nbuf; cp<cq; cp++) putc(*cp,f->fp); f->cp=f->buf; return(nbuf); } #else unsigned long bbflush(); #endif #endif /* Code particular to each format: */ /* Format a: ASCII file, one printable char ('0' or '1') per bit: */ #define bopen_r_a(s) bopen_rw((s),"r") #define bopen_w_a(s) bopen_rw((s),"w") #define getb_a(f) ( (((f)->ic=getc((f)->fp))!=EOF)? \ ((f)->nb++, \ ((f)->ic=='0')? \ 0: \ (((f)->ic=='1')? 1: EOF)): \ EOF ) #define putb_a(b,f) { if((b)) bputc('1',f); else bputc('0',f); (f)->nb++; } #define bflush_a(f) ( (bsize(f)>0)? bbflush(f): (0L) ) /* Format 0: the low-order bit (0001) in each byte is first ("little-endian"), and bytes are in putc(3) order; */ #if MAIN BITFILE *bopen_r_0(s) FILE *s; { BITFILE *f; if((f=bopen_rw(s,"r"))!=NULL) { f->cm=0000; }; return(f); } #else BITFILE *bopen_r_0(); #endif #if MAIN BITFILE *bopen_w_0(s) FILE *s; { BITFILE *f; if((f=bopen_rw(s,"w"))!=NULL) { f->i.ss.s0.cc.c0=0000; f->cm=0001; }; return(f); } #else BITFILE *bopen_w_0(); #endif #define getb_0(f) ( ((f)->cm)? \ ( ((f)->cm&(f)->ic)? \ ((f)->cm<<=1,1): \ ((f)->cm<<=1,0) ): \ ( (((f)->ic=getc((f)->fp))==EOF)? \ EOF: \ ( (f)->nb++, \ (f)->cm=0001, \ ((f)->cm&(f)->ic)? \ ((f)->cm<<=1,1): \ ((f)->cm<<=1,0) ) ) ) #define putb_0(b,f) { \ if((b)) (f)->i.ss.s0.cc.c0 |= (f)->cm; \ if( !((f)->cm<<=1) ) { \ bputc((f)->i.ss.s0.cc.c0,f); \ (f)->nb++; \ (f)->i.ss.s0.cc.c0=0000; (f)->cm=0001; \ }; \ (f)->n++; \ } #define bflush_0(f) (padb((f),0,8,0), (bsize(f)>0)? bbflush(f): 0L) /* Format 1: the high-order bit (0200) in each byte is first ("big-endian"), and bytes are in putc(3) order; */ #if MAIN BITFILE *bopen_r_1(s) FILE *s; { BITFILE *f; if((f=bopen_rw(s,"r"))!=NULL) { f->cm=0000; }; return(f); } #else BITFILE *bopen_r_1(); #endif #if MAIN BITFILE *bopen_w_1(s) FILE *s; { BITFILE *f; if((f=bopen_rw(s,"w"))!=NULL) { f->i.ss.s0.cc.c0=0000; f->cm=0200; }; return(f); } #else BITFILE *bopen_w_1(); #endif #define getb_1(f) ( ((f)->cm)? \ ( ((f)->cm&(f)->ic)? \ ((f)->cm>>=1,1): \ ((f)->cm>>=1,0) ): \ ( (((f)->ic=getc((f)->fp))==EOF)? \ EOF: \ ( (f)->nb++, \ (f)->cm=0200, \ ((f)->cm&(f)->ic)? \ ((f)->cm>>=1,1): \ ((f)->cm>>=1,0) ) ) ) #define putb_1(b,f) { \ if((b)) (f)->i.ss.s0.cc.c0 |= (f)->cm; \ if( !((f)->cm>>=1) ) { \ bputc((f)->i.ss.s0.cc.c0,f); \ (f)->nb++; \ (f)->i.ss.s0.cc.c0=0000; (f)->cm=0200; \ }; \ (f)->n++; \ } #define bflush_1(f) (padb((f),0,8,0), (bsize(f)>0)? bbflush(f): 0L) /* Format 10: the low-order (0001) bit in each byte is first ("little-endian"), and bytes are reversed (in each pair) from putc(3) order; */ #if MAIN BITFILE *bopen_r_10(s) FILE *s; { BITFILE *f; if((f=bopen_rw(s,"r"))!=NULL) { f->sm=0000000; }; return(f); } #else BITFILE *bopen_r_10(); #endif #if MAIN BITFILE *bopen_w_10(s) FILE *s; { BITFILE *f; if((f=bopen_rw(s,"w"))!=NULL) { f->i.ss.s0.s=0000000; f->sm=0000001; }; return(f); } #else BITFILE *bopen_w_10(); #endif #define getb_10(f) ( ((f)->sm)? \ ( ((f)->sm&(f)->i.ss.s0.s)? \ ((f)->sm<<=1,1): \ ((f)->sm<<=1,0) ): \ ( (((f)->ic=getc((f)->fp))==EOF)? \ EOF: \ ( (f)->nb++, \ (f)->i.ss.s0.cc.c1=(f)->ic&0377, \ ( (((f)->ic=getc((f)->fp))==EOF)? \ EOF: \ ( (f)->nb++, \ (f)->i.ss.s0.cc.c0=(f)->ic&0377, \ (f)->sm=0000001, \ ((f)->sm&(f)->i.ss.s0.s)? \ ((f)->sm<<=1,1): \ ((f)->sm<<=1,0) ) ) ) ) ) #define putb_10(b,f) { \ if((b)) (f)->i.ss.s0.s |= (f)->sm; \ if( !((f)->sm<<=1) ) { \ bputc((f)->i.ss.s0.cc.c1,f); \ (f)->nb++; \ bputc((f)->i.ss.s0.cc.c0,f); \ (f)->nb++; \ (f)->i.ss.s0.s=0000000; (f)->sm=0000001; \ }; \ (f)->n++; \ } #define bflush_10(f) (padb((f),0,16,0), (bsize(f)>0)? bbflush(f): 0L) /* Format 11: the high-order (0200) bit in each byte is first ("little-endian"), and bytes are reversed (in each pair) from putc(3) order. */ #if MAIN BITFILE *bopen_r_11(s) FILE *s; { BITFILE *f; if((f=bopen_rw(s,"r"))!=NULL) { f->sm=0000000; }; return(f); } #else BITFILE *bopen_r_11(); #endif #if MAIN BITFILE *bopen_w_11(s) FILE *s; { BITFILE *f; if((f=bopen_rw(s,"w"))!=NULL) { f->i.ss.s0.s=0000000; f->sm=0100000; }; return(f); } #else BITFILE *bopen_w_11(); #endif #define getb_11(f) ( ((f)->sm)? \ ( ((f)->sm&(f)->i.ss.s0.s)? \ ((f)->sm>>=1,1): \ ((f)->sm>>=1,0) ): \ ( (((f)->ic=getc((f)->fp))==EOF)? \ EOF: \ ( (f)->nb++, \ (f)->i.ss.s0.cc.c0=(f)->ic&0377, \ ( (((f)->ic=getc((f)->fp))==EOF)? \ EOF: \ ( (f)->nb++, \ (f)->i.ss.s0.cc.c1=(f)->ic&0377, \ (f)->sm=0100000, \ ((f)->sm&(f)->i.ss.s0.s)? \ ((f)->sm>>=1,1): \ ((f)->sm>>=1,0) ) ) ) ) ) #define putb_11(b,f) { \ if((b)) (f)->i.ss.s0.s |= (f)->sm; \ if( !((f)->sm>>=1) ) { \ bputc((f)->i.ss.s0.cc.c0,f); \ (f)->nb++; \ bputc((f)->i.ss.s0.cc.c1,f); \ (f)->nb++; \ (f)->i.ss.s0.s=0000000; (f)->sm=0100000; \ }; \ (f)->n++; \ } #define bflush_11(f) (padb((f),0,16,0), (bsize(f)>0)? bbflush(f): 0L) /**************************************************************/ /* FORMAT: may be selected here (input and output may differ) */ /* Input: */ #define bopen_r(s) bopen_r_0((s)) #define getb(f) getb_0(f) /* Output: */ #define bopen_w(s) bopen_w_0((s)) #define putb(b,f) putb_0((b),(f)) #define bflush(f) bflush_0(f) /**************************************************************/ /* Code common to all formats: */ #if MAIN BITFILE *bopen(s,t) FILE *s; char *t; { BITFILE *res; if(*(t)=='r') res=bopen_r(s); else if(*(t)=='w') { res=bopen_w(s); #if BUFFERED if(*(t+1)=='b') { res->alloc = BITFILE_incr; if((res->buf=(char *)malloc(res->alloc))==NULL) abort("bopen: can't alloc buffer"); res->cp = res->buf; }; #endif } else abort("bopen: bad type: \"%s\"",t); return(res); } #else BITFILE *bopen(); #endif #if MAIN padb(f,b,B,l) BITFILE *f; char b; int l,B; { while(((f)->n+(l))%(B)) putb((b),(f)); } #endif #if MAIN unsigned long bclose(f) BITFILE *f; { unsigned long nb,nbuf; if(f->type=='w') { nbuf=bflush(f); fflush(f->fp); #if BUFFERED if(f->buf!=NULL) { free(f->buf); f->buf=NULL; } #endif }; nb=f->nb; free(f); return(nb); } #else unsigned long bclose(); #endif 0707070035350557131006640007620000050000010263430476773367100001000000000615boole.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* boole.h */ #define boolean int #define T 1 #define F 0 0707070035350321011006640007620000050000010263450476773367100000700000020537fioi.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* fioi.h - buffered I/O of machine-, OS-, and compiler-independent binary values. Machine-, OS-, and compiler-independence of 'fioi' functions require that: 1) chars are exactly 8 bits and their contents are invariant under I/O; 2) the order of chars, as written by putc() and read by getc(), is also invariant, across all machines, OS, and compilers. Both of these requirements are customarily met by UNIX OS & tools. All values are written/read as a stream of char's, ultimately using putc() & getc() macroes. To maximize speed, macroes are used wherever possible: - the first argument F of each macro is a stream (FILE *). - write macroes have the form fwri_TYPE(F,value); `value' is assigned to a variable of type TYPE before it is written (so compiler-dependent type coercions may apply). - read macroes have the form frdi_TYPE(F), returning a value of type TYPE. Arguments to these macroes are evaluated exactly once. */ /** MACHINE-DEPENDENT CUSTOMIZATION OF TYPES **/ /* For each machine, all these types must be supported in the sense that some roughly-equivalent machine-supported type exists. If an exact equivalent doesn't exist, pick the shortest that is at least as long (in no. bytes), if possible. If there is no machine representation at least as long as specified, the only penalty will be the inevitable one: when a value is read, it may be truncated to the maximum value that can be represented. */ #define int1 char /* 8-bit signed 2's complement integer */ #define int2 short /* 16-bit signed 2's complement integer */ #define int3 int /* 24-bit signed 2's complement integer */ #define int4 int /* 32-bit signed 2's complement integer */ #define int8 long /* 64-bit signed 2's complement integer */ #define uint1 unsigned char /* 8-bit unsigned integer */ #define uint2 unsigned short /* 16-bit unsigned integer */ #define uint3 unsigned int /* 24-bit unsigned integer */ #define uint4 unsigned int /* 32-bit unsigned integer */ #define uint8 unsigned long /* 64-bit unsigned integer */ /* IEEE 64-bit floating point format */ typedef struct Ieeed { int8 l; int8 h; } Ieeed; /* Cope with unsigned chars on 3B2 & compensate for bug on MIPS */ #if CPU!=ATT3B && CPU!=MIPS #define toint1(c) (int1)(c) #else #if MAIN int toint1(c) register int c; { if ( ((1<<7)&c) !=0 ) return(c-256); else return c; } #else extern int toint1(); #endif #endif /** THE REST OF THIS FILE IS MACHINE-, OS-, and COMPILER-INDEPENDENT **/ typedef struct Fioi { int1 i1; int2 i2; int3 i3; int4 i4; int8 i8; uint1 ui1; uint2 ui2; uint3 ui3; uint4 ui4; uint8 ui8; char str[100]; } Fioi; #define Init_Fioi {0,0,0,0,0,0,0,0,0,0,""} #if MAIN Fioi _Fioi = Init_Fioi; #else extern Fioi _Fioi; #endif /* Characters */ #define fwri_ch(F,V) putc((V),(F)) #define frdi_ch(F) getc((F)) #if T /* TRANSITIONAL: used to read: "#if FWRI" */ /* Strings are '\0'-terminated both in main memory & in peripheral files. */ #define fwri_str(F,S) { fputs((S),(F)); putc('\0',(F)); } #else /* Strings are '\0'-terminated in the variable and '\n'-terminated in the file. BAD, OBSOLESCENT POLICY: both should use '\0'-termination */ #define fwri_str(F,S) { fputs((S),(F)); putc('\n',(F)); } #endif #define MAX_FIO_STRLEN (128) #if T /* TRANSITIONAL: used to read: "#if FRDI" */ /* Strings are '\0'-terminated both in main memory & in peripheral files. */ /*** TRANSITIONAL PATCH: accept '\n' as a terminator also; this will be disabled as soon as all classifier tables have been recreated with FWRI==T. ***/ /* Read string of maximum length MAX_FIO_STRLEN; return pointer to malloc space */ #if MAIN char *frdi_str(f) FILE *f; { static char s[MAX_FIO_STRLEN+1]; register int ch; register char *c,*ce; char *res; ce=(c=s)+MAX_FIO_STRLEN; while((c<ce)&&((ch=getc(f))!=EOF)&&(ch!='\0')&&(ch!='\n')) *(c++) = ch; *c='\0'; if(c==ce) /* label is truncated; find end of it */ { while(((ch=getc(f))!=EOF)&&(ch!='\0')&&(ch!='\n')) ; }; if((res=(char *)strdup(s))==NULL) abort("frdi_str: can't dup char *s[%d]",strlen(s)); return(res); } #else char *frdi_str(); #endif /* 's' is an already-allocated buffer of known length >=N (including '\0') */ #if MAIN int frdi_strn(f,s,n) FILE *f; char s[]; int n; { register int ch; register char *c,*ce; ce=(c=s)+n-1; while((c<ce)&&((ch=getc(f))!=EOF)&&(ch!='\0')&&(ch!='\n')) *(c++) = ch; *c='\0'; if(c==ce) /* label is truncated; find end of it */ { while(((ch=getc(f))!=EOF)&&(ch!='\0')&&(ch!='\n')) ; }; if(ch==EOF) return(0); else if(ferror(f)) return(-errno); else return(1); } #else int frdi_strn(); #endif #else /* Strings are '\0'-terminated in the variable and '\n'-terminated in the file. BAD, OBSOLESCENT POLICY: both should use '\0'-termination */ /* Read string of maximum length MAX_FIO_STRLEN; return pointer to malloc space */ #if MAIN char *frdi_str(f) FILE *f; { static char s[MAX_FIO_STRLEN+1]; register int ch; register char *c,*ce; char *res; ce=(c=s)+MAX_FIO_STRLEN; while((c<ce)&&((ch=getc(f))!=EOF)&&(ch!='\n')) *(c++) = ch; *c='\0'; if(c==ce) /* label is truncated; find end of it */ { while(((ch=getc(f))!=EOF)&&(ch!='\n')) ; }; if((res=(char *)strdup(s))==NULL) abort("frdi_str: can't dup char *s[%d]",strlen(s)); return(res); } #else char *frdi_str(); #endif /* S is an already-allocated buffer of known length >=N (including '\0') */ #define frdi_strn(F,S,N) ( feof(F)? 0 : ( \ fgets((S),(N),(F)), \ ( (((S)[strlen((S))-1])=='\n')? (S)[strlen((S))-1]='\0': 1 ), \ (ferror(F)? -errno: 1) ) ) #endif /* Integers (unsigned and signed) are written low-order byte first. */ #define fwri_uint1(F,V) fwri_ch((F),(uint1)(V)) #define frdi_uint1(F) ((uint1)frdi_ch((F))) #define fwri_uint2(F,V) { fwri_uint1((F),_Fioi.ui2=(V)); \ fwri_uint1((F),_Fioi.ui2>>8); } #define frdi_uint2(F) ((uint2)( _Fioi.ui2=frdi_uint1((F)), \ (frdi_uint1((F))<<8)|_Fioi.ui2 )) #define fwri_uint3(F,V) { fwri_uint2((F),_Fioi.ui3=(V)); \ fwri_uint1((F),_Fioi.ui3>>16); } #define frdi_uint3(F) ((uint3)( _Fioi.ui3=frdi_uint2((F)), \ (frdi_uint1((F))<<16)|_Fioi.ui3 )) #define fwri_uint4(F,V) { fwri_uint2((F),_Fioi.ui4=(V)); \ fwri_uint2((F),_Fioi.ui4>>16); } #define frdi_uint4(F) ((uint4)( _Fioi.ui4=frdi_uint2((F)), \ (frdi_uint2((F))<<16)|_Fioi.ui4 )) #define fwri_uint8(F,V) { fwri_uint4((F),_Fioi.ui8=(V)); \ fwri_uint4((F),_Fioi.ui8>>32); } #define frdi_uint8(F) ((uint8)( _Fioi.ui8=frdi_uint4((F)), \ (frdi_uint4((F))<<32)|_Fioi.ui8 )) /* Signed integers are assumed to be 2's complement. Note the suppression of inappropriate sign-extensions using judicious unsigned reads. */ #define fwri_int1(F,V) fwri_ch((F),_Fioi.i1=(V)) #define frdi_int1(F) (toint1(frdi_ch((F)))) #define fwri_int2(F,V) { fwri_int1((F),_Fioi.i2=(V)); \ fwri_int1((F),_Fioi.i2>>8); } #define frdi_int2(F) ((int2)( _Fioi.i2=frdi_uint1((F)), \ (frdi_int1((F))<<8)|_Fioi.i2 )) #define fwri_int3(F,V) { fwri_int2((F),_Fioi.i3=(V)); \ fwri_int1((F),_Fioi.i3>>16); } #define frdi_int3(F) ((int3)( _Fioi.i3=frdi_uint2((F)), \ (frdi_int1((F))<<16)|_Fioi.i3 )) #define fwri_int4(F,V) { fwri_int2((F),_Fioi.i4=(V)); \ fwri_int2((F),_Fioi.i4>>16); } #define frdi_int4(F) ((int4)( _Fioi.i4=frdi_uint2((F)), \ (frdi_int2((F))<<16)|_Fioi.i4 )) #define fwri_int8(F,V) { fwri_int4((F),_Fioi.i8=(V)); \ fwri_int4((F),_Fioi.i8>>32); } #define frdi_int8(F) ((int8)( _Fioi.i8=frdi_uint4((F)), \ (frdi_int4((F))<<32)|_Fioi.i8 )) /* Floating point */ #if MAIN /* See Marsha Grabow & George Gilmer & KT */ void dtoieeed(ieee,native) Ieeed *ieee; double native; { double fr, ho, f; int iexp; if(native < 0) { dtoieeed(ieee, -native); ieee->h |= 0x80000000L; return; } if(native == 0) { ieee->l = 0; ieee->h = 0; return; } fr = frexp(native, &iexp); f = 2097152L; /* shouldnt use fp constants here */ fr = modf(fr*f, &ho); ieee->h = ho; ieee->h &= 0xfffffL; ieee->h |= (iexp+1022L) << 20; f = 65536L; fr = modf(fr*f, &ho); ieee->l = ho; ieee->l <<= 16; ieee->l |= (long)(fr*f); } #else void dtoieeed(); #endif 0707070035350321111006640007620000050000010263500476773367100000700000002300font.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* font.h - typedefs, etc for font-characteristic functions: The baseline is defined by the locus of bottoms of all characters that have no descenders and are not punctuation. The top is the top of characters without risers (negative). The `rise' is the (negative) height of risers (above baseline), and `descent' is the positive) distance below baseline. */ /* font attributes, in absolute scanner coordinates */ typedef struct FontAttr { Scoor body; /* point size */ Scoor xhgt; /* x-height */ Scoor ascd; /* height of ascenders (above xheight, >0) */ Scoor caph; /* capital height (above baseline, >0) */ Scoor desc; /* height of descenders (below baseline, >0) */ Scoor doth; /* height of punctuation dots */ } FontAttr; #ifdef MAIN FontAttr *ps_to_attr(); /* pointsize, digit'n resol'n --> attributes */ xhgt_to_ps(); caph_to_ps(); #endif 0707070035350320471006640007620000050000010263510476773367200000700000124016jslr.c /* AT&T PROPRIETARY: Developed at AT&T Expense */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* rlbr - run-length encode a binary raster line `rasp' is a raster line of bits. rasp[0] is the leftmost byte in the line and the 001 bit is the leftmost bit in each byte ("little-endian"). Analyzes the line into a series of runs of `1's, placing them into array `runs'. Observes margins: starts at `lm' bit and continues through `rm'; bits outside margins are assumed 0. A `run' is two shorts (the starting & ending indices of the run of `1's, inclusive). The indices are shifted so that the index of `lm' becomes `olm'. Returns the number of runs. NOTES: The contents of the raster-line are restored to their orginal state on return. The user must ensure that: (1) margins fall within `rasp'; (2) `rasp' has one extra byte at the end for use by this routine; and (3) `runs' is big enough to hold the worst-case no. of runs that could result, which is (rm-lm)/2+1. */ int rlbr(rasp,lm,rm,olm,runp) char unsigned rasp[]; /* binary raster line (with 1 extra byte at end) */ int lm,rm; /* left,right margin bit indices within raster */ int olm; /* on output, `lm' index has become `olm' */ short runp[]; /* array of run-segments [xs,xe] (pairs of short) */ { register char unsigned *bp,*ep; /* byte pointers into raster line */ register short cb; /* x_coordinate of 1st bit of current byte */ register short *xp; /* ptr to x-coordinate in run-length array */ register short prior; /* prior bit, coded 0400 or 0000 */ char unsigned *lbp,*rbp; /* ptrs to margin bytes */ int lo,ro; /* `offset' of margin bits in bytes */ char unsigned svlb,svrb,svrrb; /* unmodified copies of margin bytes */ if(lm>rm) return(0); /* compute margins' bytes, save copies, set bits outside margins to 0 */ lbp=rasp+(lm/8); svlb= *lbp; /* force bits left of lm to 0 */ lo=lm%8; if(lo>0) *lbp &= (0377<<lo); rbp=rasp+(rm/8); svrb= *rbp; /* force bits right of rm to 0 */ ro=rm%8; if(ro<7) *rbp &= (0377>>(7-ro)); /* place a 0000 byte to right of margin byte, to force good termination */ svrrb= *(rbp+1); *(rbp+1)='\0'; /* MAIN LOOP */ prior=0000; /* act as if there's a 0 byte to left of margin byte */ xp=runp; bp=lbp; ep=rbp+2; cb=(-lo+olm); do { switch( prior | *(bp++) ) { /* contents of rlbr.c1 come below here */ case 00: break; case 01: *(xp++)=cb; *(xp++)=cb; break; case 02: *(xp++)=cb+1; *(xp++)=cb+1; break; case 03: *(xp++)=cb; *(xp++)=cb+1; break; case 04: *(xp++)=cb+2; *(xp++)=cb+2; break; case 05: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; break; case 06: *(xp++)=cb+1; *(xp++)=cb+2; break; case 07: *(xp++)=cb; *(xp++)=cb+2; break; case 010: *(xp++)=cb+3; *(xp++)=cb+3; break; case 011: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; break; case 012: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; break; case 013: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; break; case 014: *(xp++)=cb+2; *(xp++)=cb+3; break; case 015: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; break; case 016: *(xp++)=cb+1; *(xp++)=cb+3; break; case 017: *(xp++)=cb; *(xp++)=cb+3; break; case 020: *(xp++)=cb+4; *(xp++)=cb+4; break; case 021: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; break; case 022: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; break; case 023: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; break; case 024: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; break; case 025: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; break; case 026: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; break; case 027: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; break; case 030: *(xp++)=cb+3; *(xp++)=cb+4; break; case 031: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; break; case 032: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; break; case 033: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; break; case 034: *(xp++)=cb+2; *(xp++)=cb+4; break; case 035: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; break; case 036: *(xp++)=cb+1; *(xp++)=cb+4; break; case 037: *(xp++)=cb; *(xp++)=cb+4; break; case 040: *(xp++)=cb+5; *(xp++)=cb+5; break; case 041: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+5; break; case 042: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; break; case 043: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; break; case 044: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; break; case 045: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; break; case 046: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; break; case 047: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; break; case 050: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break; case 051: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break; case 052: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break; case 053: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break; case 054: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break; case 055: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break; case 056: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break; case 057: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break; case 060: *(xp++)=cb+4; *(xp++)=cb+5; break; case 061: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+5; break; case 062: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; break; case 063: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; break; case 064: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; break; case 065: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; break; case 066: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; break; case 067: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; break; case 070: *(xp++)=cb+3; *(xp++)=cb+5; break; case 071: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; break; case 072: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; break; case 073: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; break; case 074: *(xp++)=cb+2; *(xp++)=cb+5; break; case 075: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; break; case 076: *(xp++)=cb+1; *(xp++)=cb+5; break; case 077: *(xp++)=cb; *(xp++)=cb+5; break; case 0100: *(xp++)=cb+6; *(xp++)=cb+6; break; case 0101: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0102: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0103: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0104: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0105: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0106: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0107: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0110: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0111: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0112: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0113: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0114: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0115: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0116: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0117: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0120: *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0121: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0122: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0123: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0124: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0125: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0126: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0127: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0130: *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0131: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0132: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0133: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0134: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0135: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0136: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0137: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break; case 0140: *(xp++)=cb+5; *(xp++)=cb+6; break; case 0141: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0142: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0143: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0144: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0145: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0146: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0147: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0150: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0151: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0152: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0153: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0154: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0155: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0156: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0157: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break; case 0160: *(xp++)=cb+4; *(xp++)=cb+6; break; case 0161: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0162: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0163: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0164: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0165: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0166: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0167: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0170: *(xp++)=cb+3; *(xp++)=cb+6; break; case 0171: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0172: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0173: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0174: *(xp++)=cb+2; *(xp++)=cb+6; break; case 0175: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+6; break; case 0176: *(xp++)=cb+1; *(xp++)=cb+6; break; case 0177: *(xp++)=cb; *(xp++)=cb+6; break; case 0200: *(xp++)=cb+7; prior=0400; break; case 0201: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+7; prior=0400; break; case 0202: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+7; prior=0400; break; case 0203: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+7; prior=0400; break; case 0204: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+7; prior=0400; break; case 0205: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+7; prior=0400; break; case 0206: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+7; prior=0400; break; case 0207: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+7; prior=0400; break; case 0210: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break; case 0211: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break; case 0212: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break; case 0213: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break; case 0214: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break; case 0215: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break; case 0216: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break; case 0217: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break; case 0220: *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0221: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0222: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0223: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0224: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0225: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0226: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0227: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0230: *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0231: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0232: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0233: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0234: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0235: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0236: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0237: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break; case 0240: *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0241: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0242: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0243: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0244: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0245: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0246: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0247: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0250: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0251: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0252: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0253: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0254: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0255: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0256: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0257: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0260: *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0261: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0262: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0263: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0264: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0265: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0266: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0267: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0270: *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0271: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0272: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0273: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0274: *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0275: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0276: *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0277: *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break; case 0300: *(xp++)=cb+6; prior=0400; break; case 0301: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+6; prior=0400; break; case 0302: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+6; prior=0400; break; case 0303: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+6; prior=0400; break; case 0304: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; prior=0400; break; case 0305: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; prior=0400; break; case 0306: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+6; prior=0400; break; case 0307: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+6; prior=0400; break; case 0310: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break; case 0311: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break; case 0312: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break; case 0313: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break; case 0314: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break; case 0315: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break; case 0316: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break; case 0317: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break; case 0320: *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0321: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0322: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0323: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0324: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0325: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0326: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0327: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0330: *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0331: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0332: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0333: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0334: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0335: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0336: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0337: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break; case 0340: *(xp++)=cb+5; prior=0400; break; case 0341: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+5; prior=0400; break; case 0342: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; prior=0400; break; case 0343: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+5; prior=0400; break; case 0344: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; prior=0400; break; case 0345: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; prior=0400; break; case 0346: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; prior=0400; break; case 0347: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; prior=0400; break; case 0350: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break; case 0351: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break; case 0352: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break; case 0353: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break; case 0354: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break; case 0355: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break; case 0356: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break; case 0357: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break; case 0360: *(xp++)=cb+4; prior=0400; break; case 0361: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; prior=0400; break; case 0362: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; prior=0400; break; case 0363: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; prior=0400; break; case 0364: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; prior=0400; break; case 0365: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; prior=0400; break; case 0366: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; prior=0400; break; case 0367: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; prior=0400; break; case 0370: *(xp++)=cb+3; prior=0400; break; case 0371: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; prior=0400; break; case 0372: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; prior=0400; break; case 0373: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; prior=0400; break; case 0374: *(xp++)=cb+2; prior=0400; break; case 0375: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; prior=0400; break; case 0376: *(xp++)=cb+1; prior=0400; break; case 0377: *(xp++)=cb; prior=0400; break; case 0400: *(xp++)=cb-1; prior=0000; break; case 0401: *(xp++)=cb; prior=0000; break; case 0402: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; prior=0000; break; case 0403: *(xp++)=cb+1; prior=0000; break; case 0404: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; prior=0000; break; case 0405: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; prior=0000; break; case 0406: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; prior=0000; break; case 0407: *(xp++)=cb+2; prior=0000; break; case 0410: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; prior=0000; break; case 0411: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; prior=0000; break; case 0412: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; prior=0000; break; case 0413: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; prior=0000; break; case 0414: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; prior=0000; break; case 0415: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; prior=0000; break; case 0416: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; prior=0000; break; case 0417: *(xp++)=cb+3; prior=0000; break; case 0420: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break; case 0421: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break; case 0422: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break; case 0423: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break; case 0424: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break; case 0425: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break; case 0426: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break; case 0427: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break; case 0430: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+4; prior=0000; break; case 0431: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; prior=0000; break; case 0432: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; prior=0000; break; case 0433: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; prior=0000; break; case 0434: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+4; prior=0000; break; case 0435: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; prior=0000; break; case 0436: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+4; prior=0000; break; case 0437: *(xp++)=cb+4; prior=0000; break; case 0440: *(xp++)=cb-1; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0441: *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0442: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0443: *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0444: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0445: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0446: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0447: *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0450: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0451: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0452: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0453: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0454: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0455: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0456: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0457: *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break; case 0460: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break; case 0461: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break; case 0462: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break; case 0463: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break; case 0464: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break; case 0465: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break; case 0466: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break; case 0467: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break; case 0470: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+5; prior=0000; break; case 0471: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; prior=0000; break; case 0472: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; prior=0000; break; case 0473: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; prior=0000; break; case 0474: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+5; prior=0000; break; case 0475: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; prior=0000; break; case 0476: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+5; prior=0000; break; case 0477: *(xp++)=cb+5; prior=0000; break; case 0500: *(xp++)=cb-1; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0501: *(xp++)=cb; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0502: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0503: *(xp++)=cb+1; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0504: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0505: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0506: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0507: *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0510: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0511: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0512: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0513: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0514: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0515: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0516: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0517: *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0520: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0521: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0522: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0523: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0524: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0525: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0526: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0527: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0530: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0531: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0532: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0533: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0534: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0535: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0536: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0537: *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break; case 0540: *(xp++)=cb-1; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0541: *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0542: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0543: *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0544: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0545: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0546: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0547: *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0550: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0551: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0552: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0553: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0554: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0555: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0556: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0557: *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break; case 0560: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break; case 0561: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break; case 0562: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break; case 0563: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break; case 0564: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break; case 0565: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break; case 0566: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break; case 0567: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break; case 0570: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+6; prior=0000; break; case 0571: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+6; prior=0000; break; case 0572: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; prior=0000; break; case 0573: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; prior=0000; break; case 0574: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+6; prior=0000; break; case 0575: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+6; prior=0000; break; case 0576: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+6; prior=0000; break; case 0577: *(xp++)=cb+6; prior=0000; break; case 0600: *(xp++)=cb-1; *(xp++)=cb+7; break; case 0601: *(xp++)=cb; *(xp++)=cb+7; break; case 0602: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+7; break; case 0603: *(xp++)=cb+1; *(xp++)=cb+7; break; case 0604: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+7; break; case 0605: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+7; break; case 0606: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+7; break; case 0607: *(xp++)=cb+2; *(xp++)=cb+7; break; case 0610: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; break; case 0611: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; break; case 0612: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; break; case 0613: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; break; case 0614: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+7; break; case 0615: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+7; break; case 0616: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+7; break; case 0617: *(xp++)=cb+3; *(xp++)=cb+7; break; case 0620: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0621: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0622: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0623: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0624: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0625: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0626: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0627: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0630: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0631: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0632: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0633: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0634: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0635: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0636: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+7; break; case 0637: *(xp++)=cb+4; *(xp++)=cb+7; break; case 0640: *(xp++)=cb-1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0641: *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0642: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0643: *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0644: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0645: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0646: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0647: *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0650: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0651: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0652: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0653: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0654: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0655: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0656: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0657: *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0660: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0661: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0662: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0663: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0664: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0665: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0666: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0667: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0670: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0671: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0672: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0673: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0674: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0675: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0676: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+7; break; case 0677: *(xp++)=cb+5; *(xp++)=cb+7; break; case 0700: *(xp++)=cb-1; *(xp++)=cb+6; break; case 0701: *(xp++)=cb; *(xp++)=cb+6; break; case 0702: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+6; break; case 0703: *(xp++)=cb+1; *(xp++)=cb+6; break; case 0704: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; break; case 0705: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; break; case 0706: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+6; break; case 0707: *(xp++)=cb+2; *(xp++)=cb+6; break; case 0710: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0711: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0712: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0713: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0714: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0715: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0716: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; break; case 0717: *(xp++)=cb+3; *(xp++)=cb+6; break; case 0720: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0721: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0722: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0723: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0724: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0725: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0726: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0727: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0730: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0731: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0732: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0733: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0734: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0735: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0736: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; break; case 0737: *(xp++)=cb+4; *(xp++)=cb+6; break; case 0740: *(xp++)=cb-1; *(xp++)=cb+5; break; case 0741: *(xp++)=cb; *(xp++)=cb+5; break; case 0742: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; break; case 0743: *(xp++)=cb+1; *(xp++)=cb+5; break; case 0744: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; break; case 0745: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; break; case 0746: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; break; case 0747: *(xp++)=cb+2; *(xp++)=cb+5; break; case 0750: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; break; case 0751: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; break; case 0752: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; break; case 0753: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; break; case 0754: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; break; case 0755: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; break; case 0756: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; break; case 0757: *(xp++)=cb+3; *(xp++)=cb+5; break; case 0760: *(xp++)=cb-1; *(xp++)=cb+4; break; case 0761: *(xp++)=cb; *(xp++)=cb+4; break; case 0762: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; break; case 0763: *(xp++)=cb+1; *(xp++)=cb+4; break; case 0764: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; break; case 0765: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; break; case 0766: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; break; case 0767: *(xp++)=cb+2; *(xp++)=cb+4; break; case 0770: *(xp++)=cb-1; *(xp++)=cb+3; break; case 0771: *(xp++)=cb; *(xp++)=cb+3; break; case 0772: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; break; case 0773: *(xp++)=cb+1; *(xp++)=cb+3; break; case 0774: *(xp++)=cb-1; *(xp++)=cb+2; break; case 0775: *(xp++)=cb; *(xp++)=cb+2; break; case 0776: *(xp++)=cb-1; *(xp++)=cb+1; break; case 0777: break; /* contents of jslr.c1 come above here */ }; cb += 8; } while(bp<ep); /* restore margin bytes */ *lbp = svlb; *rbp = svrb; *(rbp+1) = svrrb; return((xp-runp)/2); }; 0707070035350320511006640007620000050000010263540476773367200001100000001652limits.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* Extreme values of integral types (conforms to Oct 1, 86 draft ANSI C std) */ #define CHAR_BIT 8 #define SCHAR_MIN -128 #define SCHAR_MAX 127 #define UCHAR_MIN 0 #define UCHAR_MAX 255 #define CHAR_MIN SCHAR_MIN /* type char sign-extends */ #define CHAR_MAX SCHAR_MAX /* type char sign-extends */ #define SHRT_MIN -32768 #define SHRT_MAX 32767 #define USHRT_MIN 0 #define USHRT_MAX 65535 #define INT_MIN -2147483648 #define INT_MAX 2147483647 #define UINT_MIN 0 #define UINT_MAX 4294967295 #define LONG_MIN -2147483648 #define LONG_MAX 2147483647 #define ULONG_MIN 0 #define ULONG_MAX 4294967295 0707070035351106241006640007620000050000010263560476773367300001000000025436myftw.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* * ftw - file tree walk * * int ftw (path, fn, depth) char *path; int (*fn)(); int depth; * * Given a path name, ftw starts from the file given by that path * name and visits each file and directory in the tree beneath * that file. If a single file has multiple links within the * structure, it will be visited once for each such link. * For each object visited, fn is called with four arguments. * The fourth can often be ignored; it is a pointer, say S, * declared "struct FTW *S", discussed in more detail below. * The first contains the path name of the object, the second * contains a pointer to a stat buffer which will usually hold * appropriate information for the object and the third contains * an integer value giving additional information about the * object, as follows: * * FTW_F The object is a file for which stat was * successful. It does not guarantee that the * file can actually be read. * * FTW_D The object is a directory for which stat and * open for read were both successful. This is * a preorder visit -- objects in the directory * are yet to be visited. * * FTW_DNR The object is a directory for which stat * succeeded, but which cannot be read. Because * the directory cannot be read, fn will not be * called for any descendants of this directory. * * FTW_DP The object is a directory for which stat and * open for read were both successful. This is * a postorder visit -- everything in the directory * has already been visited. * * FTW_NS Lstat failed on the object. If errno is EACCES, * then the failure stems from lack of * appropriate permission. This indication will * be given, for example, for each file in a directory * with read but no execute permission. Whenever * stat fails, it is not possible to determine * whether this object is a file or a directory. * The stat buffer passed to fn will contain garbage. * * FTW_SL The object is a symbolic link. Set S->quit * (a component of the structure pointed to by * the fourth parameter to fn) to FTW_FOLLOW to * have the link followed and the object to which * it points visited. * * FTW_NSL Lstat succeeded, but stat failed on the object. * This is only possible when following a symbolic * link. * * Among the components of the structure to which the fourth * parameter, S, to fn points is S->quit. If the caller sets * S->quit to FTW_SKR, then no more files in the current directory * will be visited. (The current directory is the one containing * the object being visited.) If the third parameter to fn is * FTW_D and the caller sets S->quit to FTW_SKD, then this directory * (the one named in the first parameter to fn) will be skipped. * * Other components pointed to by the fourth parameter S are * the current recursion level S->level (top level = 0) and * the offset S->base in the pathname of the current object * (the first parameter to fn) of the object's base name. * By expanding the definition of struct FTW given below and * including the files included below, one can arrange for * S to point to a larger structure, components of which can * be initialized (for example) on calls to fn with third * parameter FTW_D. * * If fn returns nonzero, ftw stops and returns the same value * to its caller. Ftw only initiates a nonzero return if malloc * fails; in this case ftw sets errno to ENOMEM and returns -1. * * The third argument to ftw does not limit the depth to which * ftw will go. Rather, it limits the depth to which ftw will * go before it starts recycling file descriptors. In general, * it is necessary to use a file descriptor for each level of the * tree, but they can be recycled for deep trees by saving the position, * closing, re-opening, and seeking. It is possible to start * recycling file descriptors by sensing when we have run out, but * in general this will not be terribly useful if fn expects to be * able to open files. We could also figure out how many file descriptors * are available and guarantee a certain number to fn, but we would not * know how many to guarantee, and we do not want to impose the extra * overhead on a caller who knows how many are available without * having to figure it out. * * It is possible for ftw to die with a memory fault in the event * of a file system so deeply nested that the stack overflows. */ #include <sys/types.h> #include <sys/stat.h> #include "myftw.h" /* not <ftw.h>, for portability to Suns */ /* * Struct FTW (whose definition starts at the end of ftw.h) must * must include at least the integers quit, base, and level. */ #define FTW_PATHLEN0 1000 #define FTW_PATHINC 1000 #ifndef S_IFLNK #define lstat stat #endif #ifdef S_IFSOCK #include <sys/dir.h> #else #include "ndir.h" #endif #ifndef ENOMEM #include <errno.h> #endif extern int errno; /* * Each generation of ftw1 (the real ftw) allocates one copy, R, of the * following structure; it passes a pointer to this structure when it * recursively invokes itself. These structures are chained together, * so that if it becomes necessary to recycle file descriptors, then * the oldest descriptor (the one at the shallowest depth still open) * can be recycled. */ struct FTW_rec { struct FTW_rec *prev; long here; /* seek to here when reopening at this level */ DIR *fd; /* file descriptor at this level */ }; /* * One instance, T, of the following structure is allocated by ftw; a * pointer to it is passed to all generations of ftw1 (the real ftw). * T could often be a global variable, but this way the parameter fn * can invoke ftw for an independent tree walk. * Component T->path points to storage for the object path-names; * this storage may be relocated by realloc if T->path needs to be * more than T->pathlast characters long. * T->path[T->pathnext] is the next free character in the pathnames. * T->depth = parameter depth to ftw. T->lastout is the deepest level at * which a file descriptor has been recycled. */ struct FTW_top { int (*fn)(); char *path; unsigned pathlast, pathnext; int lastout; int depth; }; static ftw_1_(); int ftw (path, fn, depth) char *path; int (*fn)(); int depth; { struct FTW_top T; struct FTW_rec R; struct FTW S; int rc; char *malloc(), *strcpy(); T.depth = depth; T.lastout = -1; T.fn = fn; S.quit = 0; S.level = -1; /* initialize S.base, T.pathnext... */ { register char c, *p, *q; for (p = q = path; c = *p; p++) if (c == '/') q = p + 1; S.base = q - path; T.pathnext = p - path; } T.pathlast = T.pathnext + FTW_PATHLEN0; T.path = malloc(T.pathlast); if (!T.path) { errno = ENOMEM; return -1; } strcpy(T.path, path); rc = ftw_1_(&R, &T, 0, &S); free(T.path); return rc; } int static ftw_1_ (R, T, level, S1) register struct FTW_rec *R; register struct FTW_top *T; int level; struct FTW *S1; { int rc, n; DIR *fd; struct direct *dirp; char *component, *path; struct stat sb; struct FTW_rec mr; unsigned nextsave; struct FTW S; char *realloc(); long lseek(); mr.prev = R; path = T->path; S.level = level; S.quit = 0; S.base = S1->base; /* Try to get file status. If unsuccessful, errno will say why. */ if (lstat(path, &sb) < 0) { rc = (*T->fn) (path, &sb, FTW_NS, &S); S1->quit = S.quit; return rc; }; /* * The stat succeeded, so we know the object exists. * If not a directory, call the user function and return. */ #ifdef S_IFLNK if ((sb.st_mode & S_IFMT) == S_IFLNK) { rc = (*T->fn) (path, &sb, FTW_SL, &S); S1->quit = S.quit; if (rc || S.quit == FTW_SKR) return rc; if (S.quit != FTW_FOLLOW) return 0; S1->quit = S.quit = 0; if (stat(path, &sb) < 0) { rc = (*T->fn) (path, &sb, FTW_NSL, &S); S1->quit = S.quit; return rc; }; } #endif if ((sb.st_mode & S_IFMT) != S_IFDIR) { rc = (*T->fn) (path, &sb, FTW_F, &S); S1->quit = S.quit; return rc; } /* * The object was a directory. * * Open a file to read the directory */ mr.fd = fd = opendir(path); /* * Call the user function, telling it whether * the directory can be read. If it can't be read * call the user function or indicate an error, * depending on the reason it couldn't be read. */ if (!fd) { rc = (*T->fn) (path, &sb, FTW_DNR, &S); S1->quit = S.quit; return rc; } /* We could read the directory. Call user function. */ rc = (*T->fn) (path, &sb, FTW_D, &S); if (rc != 0) goto rtrn; if (S.quit == FTW_SKD) goto rtrn; if (S.quit == FTW_SKR) {S1->quit = FTW_SKR; goto rtrn;} /* Make sure path is big enough to hold generated pathnames. */ n = nextsave = T->pathnext; if (n + MAXNAMLEN + 1 >= T->pathlast) { T->pathlast += FTW_PATHINC; path = T->path = realloc(T->path, T->pathlast); if (!path) { errno = ENOMEM; rc = -1; goto rtrn; } } /* Create a prefix to which we will append component names */ if (n > 0 && path[n-1] != '/') path[n++] = '/'; component = path + n; /* * Read the directory one component at a time. * We must ignore "." and "..", but other than that, * just create a path name and call self to check it out. */ while (dirp = readdir(fd)) { if (dirp->d_ino != 0 && strcmp (dirp->d_name, ".") != 0 && strcmp (dirp->d_name, "..") != 0) { int i; struct FTW_rec *pr; /* Append the component name to the working path */ strcpy(component, dirp->d_name); T->pathnext = n + strlen(dirp->d_name); /* * If we are about to exceed our depth, * remember where we are and close the file. */ if (level - T->lastout >= T->depth) { pr = &mr; i = T->lastout++; while (++i < level) pr = pr->prev; pr->here = telldir(pr->fd); closedir(pr->fd); } /* * Do a recursive call to process the file. */ S.quit = 0; S.base = n; rc = ftw_1_(&mr, T, level+1, &S); if (rc != 0 || S.quit == FTW_SKR) { if (level > T->lastout) closedir(fd); T->pathnext = nextsave; return rc; } /* * If we closed the file, try to reopen it. */ if (level <= T->lastout) { char c = path[nextsave]; path[nextsave] = 0; T->lastout = level - 1; mr.fd = fd = opendir(path); if (!fd) { rc = (*T->fn) (path, &sb, FTW_DNR, &S); S1->quit = S.quit; T->pathnext = nextsave; return rc; } path[nextsave] = c; seekdir(fd, mr.here); } } } T->pathnext = nextsave; path[nextsave] = 0; /* * We got out of the subdirectory loop. Call the user * function again at the end and clean up. */ rc = (*T->fn) (path, &sb, FTW_DP, &S); S1->quit = S.quit; rtrn: closedir(fd); return rc; } 0707070035350320551006640007620000050000010263640476773367300001000000002137myftw.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* * Codes for the third argument to the user-supplied function * which is passed as the second argument to ftw... */ #define FTW_F 0 /* file */ #define FTW_D 1 /* directory */ #define FTW_DNR 2 /* directory without read permission */ #define FTW_NS 3 /* unknown type, stat failed */ #define FTW_DP 4 /* directory, postorder visit */ #define FTW_SL 5 /* symbolic link */ #define FTW_NSL 6 /* stat failed (errno = ENOENT) on symbolic link */ /* Values the user-supplied function may wish to assign to component quit of struct FTW... */ #define FTW_SKD 1 /* skip this directory (2nd par = FTW_D) */ #define FTW_SKR 2 /* skip rest of current directory */ #define FTW_FOLLOW 3 /* follow symbolic link */ struct FTW { int quit, base, level; #ifndef FTW_more_to_come }; #endif 0707070035350320571006640007620000050000010263660476773367300000600000003730pic.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* pic.h - picture files. See man page for picfile(5). They have an ascii header, terminated by \n\n; see PIC_hdr for its data fields. The rest is binary scanner data. Each `PIC_hdr.bpl' bytes holds one scan-line's pixels, 1 bit/pixel. A `1' bit means black. The order of the bytes in a line is left-to-right across the page. The low-order bit in a byte is the left-most. Conventionally, X-coordinates start at 0, at the left of the page, and increase to the right. Y-coordinates start at 0 at the top of the page, and increase down. NOTE: must be preceded by #include "Coord.h" */ typedef struct PIC_hdr { /* Contents of picfile ASCII header (or other structure) */ char type[40]; /* "rle" "dump" "binary" "ccitt-g4" "imdir" etc */ Bbx bx; /* WINDOW (bounding box) */ short res_x; /* resolution in pixels/inch (x,y may differ) */ short res_y; char *parms; /* PARMS= string */ char *misc; /* all other unexpected header lines, catenated */ /* the following are used by I/O routines */ FILE *fp; long seek; /* current seek address */ int bpl; /* bytes per line (in file) */ unsigned char *line; /* one line of picture (malloc space) */ unsigned char *pline; /* prior line of picture (malloc space) */ Scoor cy; /* index no. of *line */ } PIC_hdr; #define Init_PIC_hdr {"",Init_Bbx,0,0,NULL,NULL,NULL,0L,0,NULL,NULL,0} #if MAIN PIC_hdr empty_PIC_hdr = Init_PIC_hdr; #else extern PIC_hdr empty_PIC_hdr; #endif /* these functions are in /usr/hsb/ocr/piclib.c */ PIC_hdr *alloc_PIC_hdr(); int PIC_get_hdr(); PIC_put_hdr(); err_PIC_line(); PIC_skip(); int PIC_rline(); int PIC_wline(); char *PIC_hdr_toa(); 0707070035350320561006640007620000050000010263700476773367300001100000044413piclib.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* piclib.c - picture-file public functions. alloc_PIC_hdr() - allocate initialized PIC_hdr, associate with FILE * free_PIC_hdr() - free PIC_hdr & all malloc'ed fields PIC_get_hdr() - get picture-file header PIC_rline() - read one line of picture data PIC_put_hdr() - get picture-file header PIC_wline() - write one line of picture data err_PIC_Line() - print line on stderr PIC_hdr_toa() - PIC_hdr to ascii printable string (PIC_* functions use system I/O, for speed) */ #include <stdio.h> #include <math.h> #include <string.h> #include "boole.h" #include "limits.h" /* numeric extreme values */ #include "Units.h" #include "Coord.h" #include "pic.h" #define PIC_debug (0) double atof(); PIC_hdr *alloc_PIC_hdr( fp ) FILE *fp; /* already-open file descr */ { PIC_hdr *h; if((h=(PIC_hdr *)malloc(sizeof(PIC_hdr)))==NULL) abort("piclib: alloc_PIC_hdr: can't alloc"); *h = empty_PIC_hdr; h->fp = fp; return(h); } free_PIC_hdr( h ) PIC_hdr *h; { if(h->parms!=NULL) free(h->parms); if(h->line!=NULL) free(h->line); if(h->pline!=NULL) free(h->pline); if(h->misc!=NULL) free(h->misc); free(h); } /* system I/O variation on fgets(3), except it replaces \n with \0, and returns the number of chars read (including \0) */ int PIC_fgets(bf,max,fd) char *bf; int max; int fd; { char *cp; int stat,mny; cp=bf; mny=0; while(((stat=read(fd,cp,1))==1)&&(++mny<max)&&((*cp)!='\n')) cp++; if(stat!=1) return(stat); else if(mny>=max) return(-1); *cp='\0'; return(mny); } /* Read picture file header from file descr fileno(h->fp), set up the rest of the header, and return status: 1 OK, 0 EOF, <0 error */ int PIC_get_hdr( h ) PIC_hdr *h; #define HL_MAX 300 #define HTERM "=, \n" /* terminations for header words: "=,<sp><tab>" */ { char *cp,*parm,hline[HL_MAX],oline[HL_MAX],*hl; int status,nrd,ch,mny; /* synchronize FILE * ptr with file descr ptr */ fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0); hline[0]='\0'; if((mny=read(fileno(h->fp),hline,5))!=5) return(0); if(!(hline[0]=='T' && hline[1]=='Y' && hline[2]=='P' && hline[3]=='E' && hline[4]=='=')) { /* no "TYPE=" header; don't accept */ if(0) /* don't accept */ { if(PIC_debug) err("PIC_get_hdr: can't find TYPE=... header"); return(-1); } else /* accept as bitfile format (OBSOLESCENT) */ { strcpy(h->type,"bitfile"); h->res_x = h->res_y = 0; fseek(h->fp,h->seek+2L,0); /* back up to byte no. 2 */ /* read window */ if((ch=getc(h->fp))!=EOF) { h->bx.a.x = ch; if((ch=getc(h->fp))!=EOF) { h->bx.a.x += (ch<<8); if((ch=getc(h->fp))!=EOF) { h->bx.a.y = ch; if((ch=getc(h->fp))!=EOF) { h->bx.a.y += (ch<<8); if((ch=getc(h->fp))!=EOF) { h->bx.b.x = ch; if((ch=getc(h->fp))!=EOF) { h->bx.b.x += (ch<<8); if((ch=getc(h->fp))!=EOF) { h->bx.b.y = ch; if((ch=getc(h->fp))!=EOF) { h->bx.b.y += (ch<<8); }}}}}}}} else return(0/*EOF*/); h->bx.b.x--; h->bx.b.y--; /* synchronize file descr ptr with FILE * ptr */ lseek(fileno(h->fp),h->seek = ftell(h->fp),0); }; } else { if((status=PIC_fgets(hline+5,HL_MAX-5,fileno(h->fp)))<=0) return(status); strcpy(oline,hline); hl=hline; while(*hl==' ') hl++; /* strip initial blanks */ while(strlen(hl)>1) { if(PIC_debug) err("PIC_get_hdr: hl \"%s\"",hl); parm=strtok(hl,HTERM); if(parm!=NULL&&strcmp(parm,"TYPE")==0) { if((parm=strtok(0,HTERM))!=NULL) { strcpy(h->type,parm); if( (strcmp(h->type,"dump")==0) || (strcmp(h->type,"pico")==0) || (strcmp(h->type,"rle")==0) || (strcmp(h->type,"binary")==0) || (strcmp(h->type,"bitmap")==0) || (strcmp(h->type,"dim")==0) || (strcmp(h->type,"document-image")==0) || (strcmp(h->type,"ccitt-g31")==0) || (strcmp(h->type,"ccitt-g32")==0) || (strcmp(h->type,"ccitt-g4")==0) || (strcmp(h->type,"cdf")==0) || (strcmp(h->type,"tiff")==0) ) /* these types are expected */ { if(PIC_debug) err("PIC_get_hdr: good TYPE=\"%s\"",h->type); } else { if(PIC_debug) err("PIC_get_hdr: unexpected TYPE=\"%s\"",h->type); return(-1); }; } else { if(PIC_debug) err("PIC_get_hdr: 1st line must be TYPE=..."); return(-1); }; } else if(parm!=NULL&&strcmp(parm,"WINDOW")==0) { if((parm=strtok(0,HTERM))!=NULL) h->bx.a.x=atoi(parm); else return(-1); if((parm=strtok(0,HTERM))!=NULL) h->bx.a.y=atoi(parm); else return(-1); if((parm=strtok(0,HTERM))!=NULL) h->bx.b.x=atoi(parm)-1; else return(-1); if((parm=strtok(0,HTERM))!=NULL) h->bx.b.y=atoi(parm)-1; else return(-1); } else if(parm!=NULL&&strcmp(parm,"RES")==0) { if((parm=strtok(0,HTERM))!=NULL) h->res_x=(int)(atof(parm)+0.5); else return(-1); if((parm=strtok(0,HTERM))!=NULL) h->res_y=(int)(atof(parm)+0.5); else return(-1); } else if(parm!=NULL&&strcmp(parm,"NCHAN")==0) { int nchan; if((parm=strtok(0,HTERM))!=NULL) nchan=atoi(parm); else return(-1); if(nchan!=1) { err("PIC_get_hdr: NCHAN=%d illegal: must be 1",nchan); return(-1); }; } else if(parm!=NULL&&strcmp(parm,"PARMS")==0) { int nchan; if((parm=strtok(0,"\n"))!=NULL) { h->parms = strdup(parm); } else return(-1); } else if(parm!=NULL) { char *cat; /* save all header lines with unexpected keywords */ if(h->misc==NULL) h->misc=(char *)malloc(strlen(oline)+2); else { cat=(char *)malloc(strlen(h->misc)+strlen(oline)+2); strcpy(cat,h->misc); free(h->misc); h->misc=cat; }; strcat(h->misc,oline); strcat(h->misc,"\n"); } else return(-1); if((status=PIC_fgets(hline,HL_MAX,fileno(h->fp)))<=0) return(status); strcpy(oline,hline); hl=hline; while(*hl==' ') hl++; /* strip initial blanks */ }; }; if(strcmp(h->type,"cdf")==0) { int stat; /* Compund Document Format has binary header */ /* synchronize FILE * ptr with file descr ptr */ fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0); if((stat=CDF_get_hdr(h)) != 1) return(stat); }; if(strcmp(h->type,"tiff")==0) { int stat; /* Tagged Image File Format has abinary header */ /* synchronize FILE * ptr with file descr ptr */ fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0); if((stat=TIFF_get_hdr(h)) != 1) return(stat); }; /* may want to allocate a line buffer here */ h->bpl = bbx_wid(&(h->bx)); if(strcmp(h->type,"binary")==0) h->bpl = (h->bpl+7)/8; /* round up to byte boundary */ else if(strcmp(h->type,"bitfile")==0) h->bpl = 2*((h->bpl+15)/16); /* round up to 2-byte boundary */ else if(strcmp(h->type,"bitmap")==0) h->bpl = 2*((h->bpl+15)/16); /* round up to 2-byte boundary */ else if( strcmp(h->type,"rle")==0 || strcmp(h->type,"dim")==0 || strcmp(h->type,"document-image")==0 || strcmp(h->type,"cdf")==0 || strcmp(h->type,"cdf-mrlc")==0 || strcmp(h->type,"cdf-g31")==0 || strcmp(h->type,"cdf-g32")==0 || strcmp(h->type,"cdf-g4")==0 || strcmp(h->type,"tiff")==0 ) h->bpl = 0; if(h->bpl==0) h->line = NULL; else { /* allocate one extra byte in line buffer as a favor to RLE */ if((h->line = (unsigned char *) malloc(h->bpl+1))==NULL) { fprintf(stderr, "piclib: PIC_get_hdr: can't alloc h->line (%d bytes) - abort\n", h->bpl+1); return(-1); }; memset(h->line,'\0',h->bpl); if(strcmp(h->type,"bitfile")==0) { if((h->pline = (unsigned char *) malloc(h->bpl+1))==NULL) { fprintf(stderr, "piclib: PIC_get_hdr: can't alloc h->pline (%d bytes) - abort\n", h->bpl+1); return(-1); }; }; }; h->cy = h->bx.a.y-1; /* just prior to 1st line */ /* synchronize FILE * ptr with file descr ptr */ fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0); return(1); } /* Read next page from AT&T Image Director file header from file descr fileno(h->fp), set up the rest of the header, and return status: 1 OK, 0 EOF, <0 error */ int CDF_next_page( h ) PIC_hdr *h; { return(-1); /* unimplemented */ } #define HASHEADER(h) ((strcmp((h)->type,"postscript")!=0&&strcmp((h)->type,"sunraster")!=0)) /* Read AT&T Image Director file header from file descr fileno(h->fp), set up the rest of the header, and return status: 1 OK, 0 EOF, <0 error */ int CDF_get_hdr( h ) PIC_hdr *h; { char *cp,*parm,hline[HL_MAX]; int status,nrd,ch,mny; #define dbg_cdf (0) typedef struct CDF_file { unsigned char raw[16]; unsigned char op,np,at; unsigned int l1,l2,len; } CDF_file; typedef struct CDF_page { unsigned char raw[16]; unsigned char op,pn,at; unsigned char f1,f2,f3,f4; unsigned int ptr; } CDF_page; typedef struct CDF_recd { unsigned char raw[16]; unsigned char op,a1,a2,a3; unsigned int len; Bbx bx; } CDF_recd; CDF_file fh; CDF_page ph; CDF_recd rh; if(dbg_cdf) err("CDF_get_hdr: enter %s",PIC_hdr_toa(h)); /* synchronize FILE * ptr with file descr ptr */ fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0); strcpy(h->type,"cdf"); /* Read CDF File header */ if(fread(fh.raw,1,16,h->fp)!=16) return(0); fh.op = fh.raw[0]; fh.np = fh.raw[1]; fh.at = fh.raw[2]; fh.l1 = fh.raw[4]+256*fh.raw[5]; fh.l2 = fh.raw[6]+256*fh.raw[7]; fh.len = fh.raw[12]+256*(fh.raw[13]+256*(fh.raw[14]+256*fh.raw[15])); if(dbg_cdf) err("CDF_get_hdr: file hdr: op0x%x p%d at0x%x lim1:%u lim2:%u len%u", fh.op,fh.np,fh.at,fh.l1,fh.l2,fh.len); if(fh.op!=0xA0&&fh.op!=0xAF) abort("CDF_get_hdr: file must be CDF type"); if(fh.np!=1) err("CDF_get_hdr: file has %d pages - ignore all but 1st",fh.np); switch(fh.at>>4) { case 0: h->res_x = h->res_y = 100; break; case 1: h->res_x = h->res_y = 200; break; case 2: h->res_x = h->res_y = 300; break; default: err("CDF_get_hdr: file has unknown resolution nibble 0x%x -- assume 400 dpi",fh.at>>4); h->res_x = h->res_y = 400; break; }; h->bx.a.x = h->bx.a.y = 0; h->bx.b.x = fh.l1; h->bx.b.y = fh.l2; if(fh.op==0xAF) { abort("CDF_get_hdr: file has continuation header"); }; /* Read 1st page table entry */ if(fread(ph.raw,1,16,h->fp)!=16) return(0); ph.op = ph.raw[0]; ph.pn = ph.raw[1]; ph.at = ph.raw[2]; ph.ptr = ph.raw[12]+256*(ph.raw[13]+256*(ph.raw[14]+256*ph.raw[15])); if(dbg_cdf) err("CDF_get_hdr: page hdr: op0x%x p%d at0x%x ptr%u", ph.op,ph.pn,ph.at,ph.ptr); if(ph.op!=0x80&&ph.op!=0x8F) abort("CDF_get_hdr: page opcode 0x%x is peculiar",ph.op); if(ph.pn!=1) err("CDF_get_hdr: page %d out of order - read anyway",ph.pn); switch(ph.at&0x0F) { /* low nibble */ case 0: /* portrait */ break; case 1: /* landscape */ default: err("CDF_get_hdr: page has peculiar format nibble 0x%x -- assume 40portrait",ph.at&0x0F); break; }; switch(ph.at>>4) { /* high nibble */ case 0xF: /* background is white */ break; default: err("CDF_get_hdr: page has peculiar color nibble 0x%x -- assume white",ph.at>>4); break; }; /* seek top of Page */ fseek(h->fp,h->seek+=ph.ptr,0); /* Read CDF Record header */ if(fread(rh.raw,1,16,h->fp)!=16) return(0); rh.op = rh.raw[0]; rh.a1 = rh.raw[1]; rh.a2 = rh.raw[2]; rh.a3 = rh.raw[3]; rh.len = rh.raw[4]+256*rh.raw[5]; rh.bx.a.x = rh.raw[8]+256*rh.raw[9]; rh.bx.a.y = rh.raw[10]+256*rh.raw[11]; rh.bx.b.x = rh.raw[12]+256*rh.raw[13]; rh.bx.b.y = rh.raw[14]+256*rh.raw[15]; if(dbg_cdf) err("CDF_get_hdr: record hdr: op0x%x a0x%x,0x%x,0x%x len%u bx%s", rh.op,rh.a1,rh.a2,rh.a3,rh.len,bbx_toa(&rh.bx)); switch(rh.op) { case 0x20: /* Image */ break; case 0x01: /* End of Page */ case 0x10: /* Text */ case 0x1F: /* Text + cont. */ case 0x50: /* Text Document */ case 0x5F: /* Text Document + cont. */ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: /* Graphics */ default: abort("CDF_get_hdr: record not Image"); }; if(rh.a2!=0x01) err("CDF_get_hdr: record not opaque - assume opaque"); switch(rh.a3&0x0F) { /* compression algorithm */ case 1: /* modified run-length code */ strcat(h->type,"-mrlc"); break; case 0: /* raw */ abort("CDF_get_hdr: record compression 0x%x is legal but unsupported",rh.a3&0x0F); break; case 2: /* ccitt_g31 */ strcat(h->type,"-g31"); abort("CDF_get_hdr: record compression 0x%x is legal but unsupported",rh.a3&0x0F); break; case 3: /* ccitt_g32 or ccitt_g4 */ strcat(h->type,"-g32"); abort("CDF_get_hdr: record compression 0x%x is legal but unsupported",rh.a3&0x0F); break; default: abort("CDF_get_hdr: record compression 0x%x is peculiar",rh.a3&0x0F); break; }; switch(rh.a3>>4) { /* resolution */ case 0: h->res_y = 100; break; case 1: h->res_y = 200; break; case 2: h->res_y = 300; break; default: err("CDF_get_hdr: record vert resolution peculiar 0x%x - assume 200 dpi", rh.a3>>4); h->res_y = 200; break; }; /* synchronize file descr ptr with FILE * ptr */ lseek(fileno(h->fp),h->seek = ftell(h->fp),0); if(dbg_cdf) err("CDF_get_hdr: normal exit %s",PIC_hdr_toa(h)); return(1); } /* Read Tagged Image Format File (TIFF) header, from file descr fileno(h->fp), set up the rest of the PIC header, and return status: 1 OK, 0 EOF, <0 error */ int TIFF_get_hdr( h ) PIC_hdr *h; { err("TIFF not yet supported"); return(-1); } /* Write header to picture file, to file descriptor fileno(h->fp), and initialize line buffer and cy. */ PIC_put_hdr( h ) PIC_hdr *h; { char *cp,*parm,hline[HL_MAX]; int status,nrd; unsigned short s; #define put_ushort(S) { s=(S); putc(s&0377,h->fp); putc(s>>8,h->fp); } /* write type header */ if( strcmp(h->type,"bitfile")==0 ) { /* bitfile header */ put_ushort(0); } else if(HASHEADER(h)) { sprintf(hline,"TYPE=%s\n",h->type); write(fileno(h->fp),hline,strlen(hline)); }; if(strcmp(h->type,"pico")==0 || strcmp(h->type,"dump")==0) { sprintf(hline,"NCHAN=1\n"); write(fileno(h->fp),hline,strlen(hline)); }; /* write window */ h->bpl = bbx_wid(&(h->bx)); if(strcmp(h->type,"binary")!=0 && strcmp(h->type,"bitfile")!=0 && strcmp(h->type,"bitmap")!=0 && HASHEADER(h)) { sprintf(hline,"WINDOW=%d %d %d %d\n", h->bx.a.x,h->bx.a.y,h->bx.b.x+1,h->bx.b.y+1); write(fileno(h->fp),hline,strlen(hline)); } else if(strcmp(h->type,"binary")==0) { h->bpl = (h->bpl+7)/8; /* round up to byte boundary */ sprintf(hline,"WINDOW=%d %d %d %d\n", h->bx.a.x,h->bx.a.y,h->bx.b.x+1,h->bx.b.y+1); write(fileno(h->fp),hline,strlen(hline)); } else if(strcmp(h->type,"bitmap")==0) { h->bpl = 2*((h->bpl+15)/16); /* round up to 2-byte boundary */ sprintf(hline,"WINDOW=%d %d %d %d\n", h->bx.a.x,h->bx.a.y,h->bx.b.x+1,h->bx.b.y+1); write(fileno(h->fp),hline,strlen(hline)); } else if(strcmp(h->type,"sunraster")!=0 ) { /* bitfile window */ h->bpl = 2*((h->bpl+15)/16); /* round up to 2-byte boundary */ put_ushort(h->bx.a.x); put_ushort(h->bx.a.y); put_ushort(h->bx.b.x+1); put_ushort(h->bx.b.y+1); fflush(h->fp); }; if( ((h->res_x!=0||h->res_y!=0)) && (HASHEADER(h)) && strcmp(h->type,"bitfile")!=0 ) { sprintf(hline,"RES=%d %d\n",h->res_x,h->res_y); write(fileno(h->fp),hline,strlen(hline)); }; if(h->parms!=NULL && strlen(h->parms)>0 && strcmp(h->type,"bitfile")!=0 ) { sprintf(hline,"PARMS=%s\n",h->parms); write(fileno(h->fp),hline,strlen(hline)); }; if(h->misc!=NULL && strlen(h->misc)>0 && strcmp(h->type,"bitfile")!=0 ) { write(fileno(h->fp),h->misc,strlen(h->misc)); }; /* terminating blank line */ if( HASHEADER(h) && strcmp(h->type,"bitfile")!=0 ) { hline[0] = '\n'; write(fileno(h->fp),hline,1); }; if(strcmp(h->type,"rle")==0) { h->bpl = 0; h->line = NULL; } else { /* allocate one extra byte in line buffer as a favor to RLE */ if((h->line = (unsigned char *) malloc(h->bpl+1))==NULL) { fprintf(stderr, "piclib: PIC_put_hdr: can't alloc h->line (%d bytes) - abort\n", h->bpl+1); return(-1); }; if(strcmp(h->type,"bitfile")==0) { memset(h->line,'\0',h->bpl); if((h->pline = (unsigned char *) malloc(h->bpl+1))==NULL) { fprintf(stderr, "piclib: PIC_put_hdr: can't alloc h->pline (%d bytes) - abort\n", h->bpl+1); return(-1); }; }; }; h->cy = h->bx.a.y-1; /* just prior to 1st line */ /* synchronize FILE * ptr with file descr ptr */ fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0); } err_PIC_line(h,sl) PIC_hdr *h; char *sl; #define BPL 20 /* bytes to display per line */ { char *cp,*ep; int bpl; /* bytes per display line */ bpl=0; for(cp=sl,ep=sl+h->bpl; cp!=ep; cp++) { fprintf(stderr,"%o ",0377&(*cp)); if((++bpl)%BPL==0) fprintf(stderr,"\n "); }; if((bpl)%BPL!=0)fprintf(stderr,"\n"); } /* Skip `y' lines of PIC file */ PIC_skip(h,y) PIC_hdr *h; int y; { lseek(fileno(h->fp),(long)(y*h->bpl),1); h->seek += y*h->bpl; h->cy += y; } /* Read next full line of picture data, and if OK update line & cy; return status: 1 OK, 0 EOF, -1 ERR. Free buffer in header on EOF. */ int PIC_rline(h,lbpp) PIC_hdr *h; unsigned char **lbpp; { int stat; if( (stat=read(fileno(h->fp),h->line,h->bpl)) == h->bpl) { *lbpp=h->line; h->seek += h->bpl; h->cy++; if(PIC_debug) err("read %d bytes from fileno(h->fp) - OK",stat); return(1); } else { /* EOF or ERR */ *lbpp=NULL; free(h->line); h->line = NULL; if(PIC_debug) err("read from fileno(h->fp) stat%d",stat); if((stat>=0)&&(stat<h->bpl)) return(0 /*EOF*/); else return(-1); }; } /* write a full line of picture data, returning status: 1 OK, 0 EOF, -1 ERR */ int PIC_wline(h,line) PIC_hdr *h; unsigned char *line; { int stat; if( (stat=write(fileno(h->fp),line,h->bpl)) == h->bpl) { h->seek += h->bpl; h->cy++; if(PIC_debug) err("wrote %d bytes to fd%d - OK",stat,fileno(h->fp)); return(1); } else { /* ERR */ err("write to fd%d stat%d",fileno(h->fp),stat); if((stat>=0)&&(stat<h->bpl)) return(0 /*EOF*/); else return(-1); }; } char *PIC_hdr_toa(h) PIC_hdr *h; { static char s[120]; sprintf(s,"{type=%s bx%s res%d,%d bpl%d cy%d sk%d}", h->type, bbx_toa(&(h->bx)), h->res_x,h->res_y, h->bpl, h->cy, h->seek ); return(s); } 0707070035351135641006640007620000050000010264030476773367300001200000032256postlib.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* T. Thompson - ATT-BL HO - first versions */ /* Routines for generating PostScript from RLE. */ /* The routines at the bottom of this file, which */ /* do the actual conversion to postscript, were */ /* hacked out of 'sun2ps'. The original header */ /* giving credit to its authors is there. */ /* The 'binary' version of the output is collected in a */ /* temporary file, which is then fed back to the routines */ /* that generate postscript in a run-length-encoded form. */ /* Ideally it should just convert the original run-length */ /* encoding directly, but the REAL bottleneck is the */ /* PostScript printer, of course. Printing an 800 by 800 */ /* pixel image takes 5 minutes. */ #include <stdio.h> #include <math.h> #include <string.h> #include "CPU.h" #include "boole.h" #include "limits.h" /* numeric extreme values */ #include "Units.h" #include "Coord.h" #include "pic.h" FILE *Fp, *tmpfile(); int Raswidth; int Raslength; int Rasbytes; /* bytes per row */ int Inv = 0; int Aspect = 1; /* if non-zero, retain original aspect ratio */ int Land = 0; /* if non-zero, print in landscape mode */ char Revbyte[256]; /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ char Revnib[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; void POST_start(h) PIC_hdr *h; { int n, v; /* build a table of reversed bytes */ for ( n=0; n<256; n++ ) Revbyte[n] = Revnib[(n>>4)&0xf] | Revnib[n&0xf]<<4; h->bpl = (h->bpl+7)/8; Rasbytes = h->bpl; Raslength = h->bpl * h->bx.b.y; Raswidth = h->bx.b.x; postmain(1,NULL,Raswidth,h->bx.b.y); #if CPU==SUN Fp = tmpfile(); #else Fp = fopen("tmp.postlib.0","rw"); #endif } void POST_end() { int c; rewind(Fp); (VOID) Encode(Raslength, Inv); PrintPostScriptClosing(); fclose(Fp); } /* write a full line of picture data, returning status: 1 OK, 0 EOF, -1 ERR */ int POST_wline(h,line) PIC_hdr *h; unsigned char *line; { int stat; if( (stat=fwrite(line,1,h->bpl,Fp)) == h->bpl) { h->seek += h->bpl; h->cy++; return(1); } else { /* ERR */ err("write to fd%d stat%d",fileno(h->fp),stat); if((stat>=0)&&(stat<h->bpl)) return(0 /*EOF*/); else return(-1); }; } /****************************************************************************** * * * File: sun2ps.c * * Author: Glenn Boysko * * Organization: Case Western Reserve University * * EMail: {decvax, sun}!mandrill!boysko * * boysko@mandrill.cwru.edu * * Created: Wed Mar 23 9:25pm * * Contents: Sun Rasterfile to PostScript image (using a run-length * * encoding scheme.) * * * * (Adapted from "postimage" filter by J. R. Bammi.) * * * * @(#)sun2ps.c 1.8 ******************************************************************************/ /* * Usage: * sun2ps [-s sizex sizey] [-t transx transy] [-r rot] [-l] [-i] [-a] file ... * * -s sizex sizey = size of postscript image - default 7.5 x 10 inches. * -t transx transy = translate image - default 0.5 0.5 inches * -r rotate = rotate image - default 0 degress * -l = landscape (overrides *all* settings.) * -i = inverse image - default no inverse * (Inverse enabled implies white on black.) * -a = maintain correct aspect ratio - default none. * */ /* Sun standard raster file format (as obtained by screendump(1)). * * Header (8 16-bit quantities) * Color Map * Image * */ /* Header Format: * * ras_magic (int) Raster Magic number 0x59a66a95 * ras_width (int) Width of image in pixels. * ras_height (int) Height of image in pixels. * ras_depth (int) Bits per pixel. Either 1 or 8 bits. * ras_length (int) Length of image in bytes. * ras_type (int) Type of file. Assumed to be RT_STANDARD (1) if * produced by a screendump command. * ras_maptype (int) Type of color map. * ras_maplength (int) Length of color map in bytes. * */ /* Ras_maplength bytes of Color map data. */ /* Ras_length bytes of Image data. */ /* Buffer and Input Modes... */ #define LITERAL 0 #define COPY 1 #define IGNORE 2 /* Transmission Variables. */ int BufCount; unsigned char Buffer[128], CurrByte, NextByte, *BufferP = Buffer; /* Diagnostic Variables. */ int DiagNLongRuns = 0, DiagMaxRunLength = 0, DiagNumRuns = 0; double DiagSumRunLength = 0; postmain(argc,argv,width,height) int argc; char **argv; int width, height; { char *filename; double sizex, sizey, transx, transy, rotate; extern double atof(); filename = "STDIN"; sizex = 7.5; sizey = 10.0; transx = transy = 0.5; rotate = 0.0; while(--argc > 0) { ++argv; if((*argv)[0] == '-') { switch((*argv)[1]) { case 'l': case 'L': Land = 1; break; case 's': case 'S': sizex = atof(*++argv); sizey = atof(*++argv); argc -= 2; break; case 't': case 'T': transx = atof(*++argv); transy = atof(*++argv); argc -= 2; break; case 'r': case 'R': rotate = atof(*++argv); argc--; break; case 'I': case 'i': Inv = 1; break; case 'A': case 'a': Aspect = 1; break; default: fprintf(stderr,"Illegal switch %c - ignored\n", (*argv)[1]); } } } if (Land) { transx = 8.0; transy = 0.5; sizex = 10.0; sizey = 7.5; rotate = 90.0; } if (Aspect) { if ((sizex / width) < (sizey / height)) { sizey = sizex * (height * 1.0 / width); } else { sizex = sizey * (width * 1.0 / height); } } PrintPostScriptRoutines(height, width, 1 /*depth*/ , transx, transy, sizex, sizey, rotate); } /****************************************************************************** * I/O Routines. * ******************************************************************************/ int gb() /* Get a byte from Fp. */ { int byte; if (!feof(Fp)) byte = getc(Fp); else Error("Premature EOF.\n"); if (ferror(Fp)) Error("I/O Error.\n"); return(Revbyte[byte]); } SendHex(Byte) /* Send a Hex char to Stdout. */ unsigned char Byte; { static int LineCount = 0; printf("%02x", 0xff & Byte); if (++LineCount == Rasbytes) { putchar('\n'); LineCount = 0; } } int SendBuffer(Inv) /* Send a buffer to Stdout. Return BytesSent. */ int Inv; { int i, BytesSent; if (BufferMode() == LITERAL) { SendHex( (unsigned char) 0xff & BufCount ); for (i = 0; i < BufCount+1; i++) { SendHex( (Inv) ? Buffer[i] : ~Buffer[i]); } BytesSent = BufCount+2; } else if (BufferMode() == COPY) { SendHex( (unsigned char) 0xff & (0x100 + BufCount) ); SendHex( (Inv) ? Buffer[0] : ~Buffer[0]); BytesSent = 2; DiagRecLRun(mag(BufCount)+1); } return(BytesSent); } /****************************************************************************** * Utility Routines. * ******************************************************************************/ int mag(Byte) /* Magitude of a signed char. */ int Byte; { if (Byte & 0x80) { /* Signed */ Byte = ~(--Byte); } return( 0xff & Byte ); } /****************************************************************************** * Buffer Management Routines. * ******************************************************************************/ int InputMode() { if (CurrByte == NextByte) return(COPY); return(LITERAL); } int BufferMode() { if (BufCount >= 0 && BufCount <= 127) return(LITERAL); else if (BufCount >= -127 && BufCount <= -1) return(COPY); return(IGNORE); } InitLitMode(NBytes, Inv) int *NBytes, Inv; { BufferP = Buffer; BufCount = -1; ContLitMode(NBytes, Inv); } ContLitMode(NBytes, Inv) int *NBytes, Inv; { if (BufCount == 127) { SendBuffer(Inv); BufferP = Buffer; BufCount = -1; } *BufferP++ = CurrByte; BufCount++; CurrByte = NextByte; NextByte = (unsigned char) gb(); (*NBytes)--; } InitCopyMode(NBytes, Inv) int *NBytes, Inv; { BufferP = Buffer; *BufferP++ = CurrByte; BufCount = -1; CurrByte = (unsigned char) gb(); NextByte = (unsigned char) gb(); *NBytes -= 2; } ContCopyMode(NBytes, Inv) int *NBytes, Inv; { if (BufCount == -127) { SendBuffer(Inv); InitCopyMode(NBytes, Inv); DiagNLongRuns++; } BufCount--; CurrByte = NextByte; NextByte = gb(); (*NBytes)--; } /****************************************************************************** * Encoding Algorithm. * ******************************************************************************/ int Encode(NBytes, Inv) int NBytes, Inv; { int BytesSent = 0; /* Initialize Buffer, BufCount, NextByte, CurrByte */ CurrByte = (unsigned char) gb(); NextByte = (unsigned char) gb(); if (InputMode() == LITERAL) { InitLitMode(&NBytes, Inv); } else { InitCopyMode(&NBytes, Inv); } while (NBytes > 3) { switch(BufferMode()) { case LITERAL: if (InputMode() == COPY) { BytesSent += SendBuffer(Inv); InitCopyMode(&NBytes, Inv); } else { ContLitMode(&NBytes, Inv); } break; case COPY: if (CurrByte == Buffer[0]) { ContCopyMode(&NBytes, Inv); } else { BytesSent += SendBuffer(Inv); if (InputMode() == COPY) { InitCopyMode(&NBytes, Inv); } else { InitLitMode(&NBytes, Inv); } } break; default: Error("Bad Buffer Mode... Sorry\n"); break; } } BytesSent += SendBuffer(Inv); /* Send out rem'g 2-3 bytes in LITERAL mode. */ Buffer[0] = CurrByte; Buffer[1] = NextByte; if (NBytes == 3) Buffer[2] = gb(); BufCount = NBytes-1; BytesSent += SendBuffer(Inv); return(BytesSent); } /****************************************************************************** * Diagnostic Routines. * ******************************************************************************/ DiagRecLRun(Rlength) int Rlength; { #ifdef DIAGS if (Rlength > DiagMaxRunLength) DiagMaxRunLength = Rlength; DiagSumRunLength += Rlength; DiagNumRuns++; #endif } Diags() { #ifdef DIAGS fprintf(stderr, "Longest Run (<= 128) = %d\n", DiagMaxRunLength); fprintf(stderr, "Number of Runs over 128 = %d\n", DiagNLongRuns); fprintf(stderr, "Average Run Length of %d. (%d Runs)\n", (int) DiagSumRunLength / DiagNumRuns, DiagNumRuns); #endif } /****************************************************************************** * PostScript Output Routines. * ******************************************************************************/ PrintPostScriptRoutines(ras_h, ras_w, ras_d, tx, ty, sx, sy, rot) int ras_h, ras_w, ras_d; double tx, ty, sx, sy, rot; { printf("%%!\n/inch {72 mul} def\n"); printf("/bpp %d def\n", ras_d); printf("/scanlines %d def\n", ras_h); printf("/scansize %d def\n", ras_w); printf("/bitmapx\n{"); printf(" %d %d %d [%d 0 0 %d 0 %d] ", ras_w, ras_h, ras_d, ras_w, -ras_h, ras_h); printf("{currentfile readrlehexstring pop } image\n} def\n"); printf("gsave\n"); printf("%f inch %f inch translate\n",tx, ty); printf("%f rotate\n", rot ); printf("%f inch %f inch scale\n", sx, sy); printf("/readrlehexstring\t%% rle_file => decoded_string boolean\n"); printf("{\n\t/fileptr exch def\n\tfileptr 1 string readhexstring {"); printf("\n\t\t0 get dup 128 and 0 eq\n"); printf("\t\t{ 1 add /Buffer exch string def\n"); printf("\t\t\tfileptr Buffer readhexstring\n\t\t}\n\t\t{"); printf(" 256 exch sub /BufCount exch def\n"); printf("\t\t\t/Buffer BufCount 1 add string def\n"); printf("\t\t\t/RunInt fileptr 1 string readhexstring"); printf(" pop 0 get def\n"); printf("\t\t\t0 1 BufCount { RunInt Buffer 3 1 roll put } for\n"); printf("\t\t\tBuffer true\n\t\t} ifelse\n\t}\n\t{ false } ifelse\n"); printf("} def\n"); printf("/clipathx\n{\tnewpath\n\t0 0 moveto\n\t%f inch 0", sx); printf(" lineto\n\t%f inch %f inch lineto\n\t0 %f inch lineto\n", sx, sy, sy); printf("\tclosepath\n} def\nclipathx clip\n"); printf("bitmapx\n"); } PrintPostScriptClosing() { printf("\ngrestore\n"); printf("showpage\n"); } /****************************************************************************** * Error Routine. * ******************************************************************************/ Error(S1, S2, S3) char *S1, *S2, *S3; { fprintf(stderr, S1, S2, S3); exit(-1); } 0707070035351136011006640007620000050000010264130476773367300001200000005002rastlib.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* T. Thompson - ATT-BL HO - first version */ /* Routines for generating PostScript from RLE. */ /* The routines at the bottom of this file, which */ /* do the actual conversion to postscript, were */ /* take from 'sun2ps'. The original header */ /* giving credit to its authors is there. */ /* The 'binary' version of the output is collected in a */ /* temporary file, which is then fed back to the routines */ /* that generate postscript in a run-length-encoded form. */ /* Ideally it should just convert the original run-length */ /* encoding directly, but this is just a hack. The REAL */ /* bottleneck is the PostScript printer, of course. */ /* Printing an 800 by 800 pixel image takes 5 minutes. */ #include <stdio.h> #include <math.h> #include <string.h> #include "CPU.h" #include "boole.h" #include "limits.h" /* numeric extreme values */ #include "Units.h" #include "Coord.h" #include "pic.h" #include <sys/types.h> #include <suntool/sunview.h> #include <pixrect/pixrect.h> #include <pixrect/pr_io.h> int Raswidth; int Raslength; extern char Revbyte[256]; extern char Revnib[16]; static FILE *fout; void RAST_start(h) PIC_hdr *h; { int n, v; struct rasterfile rh; /* build a table of reversed bytes */ for ( n=0; n<256; n++ ) Revbyte[n] = Revnib[(n>>4)&0xf] | Revnib[n&0xf]<<4; fout = h->fp; h->bpl = (h->bpl+7)/8; Raslength = h->bpl * h->bx.b.y; Raswidth = h->bx.b.x; rh.ras_magic = RAS_MAGIC; rh.ras_width = h->bx.b.x; rh.ras_height = h->bx.b.y; rh.ras_depth = 1; rh.ras_length = Raslength; rh.ras_type = RT_STANDARD; rh.ras_maptype = RMT_NONE; rh.ras_maplength = 0; pr_dump_header(fout,&rh,(colormap_t*)0); } void RAST_end() { } /* write a full line of picture data, returning status: 1 OK, 0 EOF, -1 ERR */ int RAST_wline(h,line) PIC_hdr *h; unsigned char *line; { int stat; int n; for ( n=h->bpl; n>0; n-- ) { if ( putc(Revbyte[*line++],fout) == EOF ) break; } if ( n == 0 ) { h->seek += h->bpl; h->cy++; return(1); } else { /* ERR */ err("write to fd%d stat%d",fileno(h->fp),stat); if((stat>=0)&&(stat<h->bpl)) return(0 /*EOF*/); else return(-1); }; } 0707070035351135651006640007620000050000010264150476773367300000600000003030ric.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* ric.h - Ricoh IS-30 scanner constants, typedefs, function declarations The scanner program `rscan' creates a file (typically >1Mbyte). It has an ascii header, terminated by \n\n -- see RIC_hdr for its data fields. The rest is binary scanner data. Each `RIC_hdr.bpl' bytes holds one scan-line's pixels, 1 bit/pixel. A `1' bit means black. The order of the bytes in a line is left-to-right across the page. The low-order bit in a byte is the left-most. Conventionally, X-coordinates start at 0, at the left of the page, and increase to the right. Y-coordinates start at 0 at the top of the page, and increase down. REQUIRES: prior #include "Coord.h" */ typedef struct { /* Scanner file header */ short res_x,res_y; /* resolution in pixels/inch (x,y may differ) */ short bpl; /* bytes per scan line */ Bbx bx; /* bounding box (pixel indices 0,1,...) */ } RIC_hdr; /* these routines are found in /usr/hsb/ricoh/riclib.c */ int RIC_get_hdr(); /* args: fd, (RIC_hdr *); returns: 1==OK, 0==EOF, -1=ERR */ int RIC_line(); /* arg: (char **); returns: 1==OK, 0==EOF, -1==ERR */ RIC_skip(); /* arg: int no. lines to skip */ char *S_hdr_toa(); /* RIC_hdr in printable-string form */ 0707070035351135321006640007620000050000010264160476773367300001100000011466riclib.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* riclib.c - Ricoh scanner-file public functions: RIC_* functions use system I/O, for speed... int RIC_get_hdr(fd,RIC_hdr *) - get scanner-file header int RIC_line(char **) - read one line of scanner data err_RIC_Line(char *,RIC_hdr) - print on stderr int RIC_oline(char **) - write one line of scanner data char *RIC_hdr_toa() - RIC_hdr to ascii printable string */ #include <stdio.h> #include <math.h> #include <string.h> #include "CPU.h" #include "stdocr.h" #define RIC_debug 0 /* treated as local static: */ int RIC_fd; /* file descr. */ int RIC_bpl; /* bytes per line */ char *RIC_bf = NULL; /* (malloc space *) holds one line of scanner data */ /* system I/O variation on fgets(3), except it replaces \n with \0, and returns the number of chars read (including \0) */ int RIC_fgets(bf,max,fd) char *bf; int max; int fd; { char *cp; int stat,mny; cp=bf; mny=0; while(((stat=read(fd,cp,1))==1)&&(++mny<max)&&((*cp)!='\n')) cp++; if(stat!=1) return(stat); else if(mny>=max) return(-1); *cp='\0'; return(mny); } /* read header from scanner file, return status: 1 OK, 0 EOF, -1 error */ int RIC_get_hdr( fd, hp ) int fd; /* should have been open'ed earlier */ RIC_hdr *hp; #define HL_MAX 80 #define HTERM "=, \n" /* terminations for header words: "=,<sp><tab>" */ { char *cp,*parm,hline[HL_MAX]; int status,nrd; RIC_fd = fd; if((status=RIC_fgets(hline,HL_MAX,RIC_fd))<=0) return(status); while(strlen(hline)>1) { if(RIC_debug) err("hline \"%s\"",hline); parm=strtok(hline,HTERM); if(parm!=NULL&&strcmp(parm,"TYPE")==0) { if((parm=strtok(0,HTERM))!=NULL &&strcmp(parm,"binary")==0) ; else return(-1); } else if(parm!=NULL&&strcmp(parm,"WINDOW")==0) { if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.x=atoi(parm); else return(-1); if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.y=atoi(parm); else return(-1); if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.x=atoi(parm)-1; else return(-1); hp->bpl=(hp->bx.b.x-hp->bx.a.x+1+7)/8; if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.y=atoi(parm)-1; else return(-1); } else if(parm!=NULL&&strcmp(parm,"RES")==0) { if((parm=strtok(0,HTERM))!=NULL) hp->res_x=atoi(parm); else return(-1); if((parm=strtok(0,HTERM))!=NULL) hp->res_y=atoi(parm); else return(-1); } else return(-1); if((status=RIC_fgets(hline,HL_MAX,RIC_fd))<=0) return(status); }; RIC_bpl=hp->bpl; /* allocate one extra byte in scanner buffer as a favor to RLE */ if((RIC_bf = (char *) malloc(RIC_bpl+1))==NULL) { fprintf(stderr, "riclib: can't alloc RIC_bf (%d bytes) - abort\n", RIC_bpl+1); return(-1); }; return(1); } /* write header to scanner file */ RIC_put_hdr( fd, hp ) int fd; /* should have been open'ed earlier */ RIC_hdr *hp; { char *cp,*parm,hline[HL_MAX]; int status,nrd; sprintf(hline,"TYPE=binary\n"); write(fd,hline,strlen(hline)); sprintf(hline,"WINDOW=%d %d %d %d\n", hp->bx.a.x,hp->bx.a.y,hp->bpl,hp->bx.b.y+1); write(fd,hline,strlen(hline)); sprintf(hline,"RES=%d %d\n\n",hp->res_x,hp->res_y); write(fd,hline,strlen(hline)); } err_RIC_line(sl,shdr) char *sl; RIC_hdr shdr; #define BPL 20 /* bytes to display per line */ { char *cp,*ep; int bpl; /* bytes per display line */ bpl=0; for(cp=sl,ep=sl+shdr.bpl; cp!=ep; cp++) { fprintf(stderr,"%o ",0377&(*cp)); if((++bpl)%BPL==0) fprintf(stderr,"\n "); }; if((bpl)%BPL!=0)fprintf(stderr,"\n"); } /* skip `y' lines, starting from current read pointer */ RIC_skip(y) int y; { lseek(RIC_fd,(long)(y*RIC_bpl),1); } /* read next full line of scanner data, return status: 1 OK, 0 EOF, -1 ERR */ int RIC_line(lbpp) char **lbpp; { int stat; if( (stat=read(RIC_fd,RIC_bf,RIC_bpl)) == RIC_bpl) { *lbpp=RIC_bf; if(RIC_debug) err("read %d bytes from RIC_fd - OK",stat); return(1); } else { /* EOF or ERR */ *lbpp=NULL; free(RIC_bf); if(RIC_debug) err("read from RIC_fd stat%d",stat); if((stat>=0)&&(stat<RIC_bpl)) return(0 /*EOF*/); else return(-1); }; } /* write a full line of scanner data, returning status: 1 OK, 0 EOF, -1 ERR */ int RIC_oline(fd,bf) int fd; char *bf; { int stat; if( (stat=write(fd,bf,RIC_bpl)) == RIC_bpl) { if(RIC_debug) err("wrote %d bytes to fd%d - OK",stat,fd); return(1); } else { /* ERR */ err("write to fd%d stat%d",fd,stat); if((stat>=0)&&(stat<RIC_bpl)) return(0 /*EOF*/); else return(-1); }; } char *RIC_hdr_toa(hp) RIC_hdr *hp; { static char s[40]; sprintf(s,"{res%d,%d bpl%d bx%s}\n", hp->res_x,hp->res_y, hp->bpl, bbx_toa(&(hp->bx))); return(s); } 0707070035351135311006640007620000050000010264170476773367400000600000007317rle.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* A rle file consists of any number of: `scan_line's, each of which has the form: (short) bytes_mny, followed by bytes_mny bytes in the form: (packed short) runs_mny if >0, then followed by runs_mny runs else if ==0, then followed by: (packed short) blank_lines_mny skipped, -1 (packed short) runs_mny (>0), then... ...runs_mny runs A `run' is two (packed short) oxs,oxe which are both offset counts >=0 from the prior `?x?' (starts at 0 at left margin). Suppose that xs, xe are the corresponding accumulated pixel indices, then xs is the pixel index of the first black pixel of the run, and xe the pixel index of the first white pixel following the run. A `packed short' is a byte if its value is <128, else two bytes `HIGH' & `LOW' with the 0200 bit of its HIGH byte set. */ #define HIGH(A) ((A>>8)&0177) #define LOW(A) (A&0377) /* run-length-encoding constants, typedefs */ /* The following assumes a worst case page width of 17 inches (Legal page, >ISO A2) and worst case digitizing resolution of 400 pixels/inch (e.g. CCITT Group 4), for a maximum of 6800 pixels/line */ #define RLE_RUNS 3401 /* maximum no. runs in a line */ #define RLE_BYTES 6800 /* maximum no. data bytes in a rle line (enough?) */ typedef struct RLE_Run { short xs; /* x-coord of first pixel in run */ short xe; /* x-coord of last pixel in run (NOT first following) */ } RLE_Run; #define Init_RLE_Run {0,0} typedef struct DRLE_Run { short xs; /* x-coord of first pixel in run */ short xe; /* x-coord of last pixel in run (NOT first following) */ struct DRLE_Run *next; } DRLE_Run; typedef struct RLE_Yrun { short y,xs,xe; } RLE_Yrun; #define Init_RLE_Yrun {0,0,0} typedef struct RLE_Line { short y; /* y-coord of line */ short len; /* length of line in pixels (white+black) */ short runs; /* no. of runs */ RLE_Run r[RLE_RUNS]; } RLE_Line; #define Init_RLE_Line {0,0,0,Init_RLE_Run} typedef struct DRLE_Line { /* dynamically allocated version */ DRLE_Run *r; /* first run */ DRLE_Run *lastr; /* last run */ } DRLE_Line; #define Init_DRLE_Line {0,0} typedef struct RLE_Lines { int mny; RLE_Line *rla; /* array of RLE_Lines */ } RLE_Lines; #define Init_RLE_Lines {0,NULL} #if MAIN RLE_Lines empty_RLE_Lines = Init_RLE_Lines; #else extern RLE_Lines empty_RLE_Lines; #endif typedef struct Transform_rlel_arg { boolean ident; /* if T, then no change (speed-optimization) */ Bbx tr; /* trim: select just this window of input */ Sp off; /* offset: translate by off.x,off.y */ Pp scl; /* scale: X & Y expansion factors (about 0,0) */ Sp wh; /* truncate: exact maximum output width,height */ Radians rot; /* rotate: angle (multiple of PI/4) */ boolean rev; /* reverse: swap black and white */ int sy; /* next integer line no. to write */ double dy; /* next real line no. to write */ } Transform_rlel_arg; #define Init_Transform_rlel_arg {T,Init_Bbx,Init_Zero_Sp,{1.0,1.0},Init_Zero_Sp,0.0,F,0,0.0} #if MAIN Transform_rlel_arg empty_Transform_rlel_arg = Init_Transform_rlel_arg; #else extern Transform_rlel_arg empty_Transform_rlel_arg; #endif #ifdef MAIN /* these routines are found in rlelib.c */ boolean RLE_open(); /* arg: (FILE *) */ RLE_Line *RLE_line(); /* args: l,r - left,right interval */ RLE_Line *RLE_get_Line(); /* args: l,r - left,right interval */ int RLE_run(); /* arg: (RLE_Run *) */ fwrb_rlines(); /* args: (FILE *), (RLE_Lines *) */ insert_rlel(); #endif 0707070035351135301006640007620000050000010264210476773367400001100000047356rlelib.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* T. Pavlidis - ATT-BL MH - first versions */ /* H. S. Baird - ATT-BL MH - first versions */ /* rlelib.c - subroutines for writing/reading run-length-encoded format files. BUG: Uses system I/O for speed, but sacrifices machine-independence: should use fioi.h macroes instead. See rle.h for summary of rle file and format of public functions. Writing a rle file: fd=creat() RLE_put_hdr(fd,hp) - once: allocate buffers, write header RLE_put_Line(fd,lp) - repeatedly RLE_close(fd) - once: flush and deallocate buffers Reading a rle file: fd=open() RLE_open(fd,hp) - once: read header, 1st line into buffer RLE_get_Line(l,r) - repeatedly (on EOF, deallocates buffer) The user can read line-at-a-time or run-at-a-time, but should not intermix them: line-at-a-time: (RLE_Line *) RLE_get_Line(l,r) - return ptr to next line with some run in the interval [l,r]; read from opened file (NULL if EOF, abort on error) allocates large buffer and frees it when done run-at-a-time: int RLE_get_Run(&R) - read next run into (RLE_Run) R returns the line number (-1 for EOF, abort on ERROR) does not allocate large buffer; if only a few runs will be used, can be faster */ #include <stdio.h> #define LIBC_INCL 1 #include "CPU.h" #include "stdocr.h" #include "rle.h" #define RLE_dbg F #define dbg_rd F #define dbg_wr F /* Treated as local static: */ typedef struct RLE_global { int fd; /* rle file descriptor */ boolean eof; int cy, cx; /* current line no., x-coord */ short runs, nrun; /* no. runs, next run in current line */ RLE_Line *lp; /* pointer to line (malloc space) */ int bpl; /* maximum no. bytes in packed rle line */ char *bf; /* I/O buffer (malloc space) */ int bfsize; /* size of buffer */ char *cp; /* cur. ptr, into bf */ } RLE_global; #define Init_RLE_global {0,F,-1,-1,0,0,NULL,0,NULL,0,NULL} RLE_global _RLE = Init_RLE_global; RLE_put_hdr( fd, rhp, bufn ) int fd; RIC_hdr *rhp; int bufn; /* minimum number of lines to buffer locally */ { char hdr[100]; int stat; sprintf(hdr,"TYPE=rle\nWINDOW=%d %d %d %d\nRES=%d %d\n\n", /* use half-open WINDOW convention: l&t closed, r&b open*/ rhp->bx.a.x,rhp->bx.a.y,rhp->bx.b.x+1,rhp->bx.b.y+1, rhp->res_x,rhp->res_y); if((stat=write(fd,hdr,strlen(hdr)))!=strlen(hdr)) { abort("rlelib: can't put hdr, stat %d",stat); }; _RLE.fd = fd; _RLE.cy = rhp->bx.a.y-1; _RLE.bpl = rhp->bx.b.x-rhp->bx.a.x+9; /* maximum bytes per line */ _RLE.bfsize = bufn*_RLE.bpl; if((_RLE.bf=(char *)malloc(_RLE.bfsize))==NULL) abort("can't alloc _RLE.bf[%d]",_RLE.bfsize); _RLE.cp = _RLE.bf; } #define PUT(A,B) { if((A)<128) *(B)++ = (A); \ else { *(B)++ = HIGH(A) | 0200; *(B)++ = LOW(A); } \ } /* write out a non-blank line of runs */ RLE_put_Line(fd,rlp) int fd; /* file descr (already open) */ RLE_Line *rlp; { register char *bp; short blank_lines_mny; /* the number of preceding blank lines, minus 1 */ register RLE_Run *rp,*ep; Scoor xsofar; short bytes_mny; int stat; /* I/O status */ if((_RLE.bfsize-(_RLE.cp-_RLE.bf)) < _RLE.bpl) { /* not enough room left in buffer for worst-case line */ RLE_flush(); }; /* leave space for (short) bytes_mny count */ bp=_RLE.cp+sizeof(short); if((blank_lines_mny=(rlp->y-_RLE.cy-1))>0) /* blank lines were skipped */ { PUT(0,bp); /* ``0 runs'' signals blank lines */ PUT(blank_lines_mny,bp); }; _RLE.cy=rlp->y; PUT(rlp->runs,bp); xsofar=0; for(rp=rlp->r,ep=rp+rlp->runs; rp!=ep; rp++) { PUT(rp->xs-xsofar,bp); xsofar = rp->xs; PUT(rp->xe-xsofar+1,bp); xsofar = rp->xe+1; }; /* go back & write no. bytes at top of line */ *((short *) _RLE.cp) = bp-_RLE.cp-sizeof(short); _RLE.cp = bp; if(dbg_wr) err("RLE_put_Line y%d nh%d",_RLE.cy,bytes_mny-2); }; /* write out a set of runs */ RLE_put_Lines(fd,rlsp) int fd; /* file descr (already open) */ RLE_Lines *rlsp; { int i; RLE_Line *rlp; for(i=0,rlp=rlsp->rla; i<rlsp->mny; i++,rlp++) RLE_put_Line(fd,rlp); } RLE_flush() { int bytes; int stat; if((bytes=(_RLE.cp-_RLE.bf))>0) if(stat=write(_RLE.fd,_RLE.bf,bytes)!=bytes) abort("can't write _RLE.bf[%d], status %d",bytes,stat); _RLE.cp = _RLE.bf; } RLE_close(fd) int fd; { RLE_flush(); if(_RLE.bf!=NULL) free(_RLE.bf); _RLE.bf = _RLE.cp = NULL; _RLE.bfsize = 0; } /* ``open'' RLE_file for reading: save filedes, read header, and read first line into buffer */ boolean RLE_open( fd, hp ) int fd; RIC_hdr *hp; { _RLE.fd = fd; /* read header */ RLE_get_hdr( fd, hp ); if(_RLE.bf!=NULL) free(_RLE.bf); _RLE.bfsize = _RLE.bpl; if((_RLE.bf=(char *)malloc(_RLE.bfsize))==NULL) abort("can't alloc _RLE.bf[%d]",_RLE.bfsize); /* read first non-blank line */ _RLE.cy = hp->bx.a.y-1; if (!RLE_rdbf()) return(F); _RLE.eof = F; return(T); } /* read next short from rle-line buffer, updating arg ptr */ short RLE_gshort(p) char **p; { register n; register char *q; q = *p; if((*q)&0200) { n = (((*q & 0177)<<8)&077400) | (*(q+1) & 0377); (*p)++; } else n = *q; (*p)++; return(n); } /* system I/O variation on fgets(3), except it replaces \n with \0, and returns the number of chars read (including \0) */ int RLE_fgets(bf,max,fd) char *bf; int max; int fd; { char *cp; int stat,mny; cp=bf; mny=0; while(((stat=read(fd,cp,1))==1)&&(++mny<max)&&((*cp)!='\n')) cp++; if(stat!=1) return(stat); else if(mny>=max) return(-1); *cp='\0'; return(mny); } /* read ascii header from rle file, convert to RIC_hdr, return status: 1 OK, 0 EOF, -1 error */ int RLE_get_hdr( fd, hp ) int fd; /* should have been open'ed earlier */ RIC_hdr *hp; #define HL_MAX 80 #define HTERM "=, \n" /* terminations for header words: "=,<sp><tab>" */ { char *cp,*parm,hline[HL_MAX]; int status,nrd; if((status=RLE_fgets(hline,HL_MAX,fd))<=0) return(status); while(strlen(hline)>1) { if(RLE_dbg) err("hline \"%s\"",hline); parm=strtok(hline,HTERM); if(parm!=NULL&&strcmp(parm,"TYPE")==0) { if((parm=strtok(0,HTERM))!=NULL &&strcmp(parm,"rle")==0) ; else return(-1); } else if(parm!=NULL&&strcmp(parm,"WINDOW")==0) { /* assume half-open WINDOW: l&t closed, r&b open */ if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.x=atoi(parm); else return(-1); if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.y=atoi(parm); else return(-1); if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.x=atoi(parm)-1; else return(-1); if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.y=atoi(parm)-1; else return(-1); } else if(parm!=NULL&&strcmp(parm,"RES")==0) { if((parm=strtok(0,HTERM))!=NULL) hp->res_x=atoi(parm); else return(-1); if((parm=strtok(0,HTERM))!=NULL) hp->res_y=atoi(parm); else return(-1); } else return(-1); if((status=RLE_fgets(hline,HL_MAX,fd))<=0) return(status); }; /* maximum possible no. bytes in a packed rle line */ _RLE.bpl = hp->bpl = hp->bx.b.x-hp->bx.a.x+9; if(dbg_rd) fprintf(stderr,"rlelib: RLE_get_hdr: %s\n",RIC_hdr_toa(hp)); return(1); } /* read the next run into *Rp, and return line number (-1 for EOF, abort on error) */ int RLE_get_Run( Rp ) RLE_Run *Rp; { if(_RLE.nrun >= _RLE.runs) { /* no more, try to read next line */ if (!RLE_rdbf()) /* EOF */ return(-1); }; /* another run */ Rp->xs = (_RLE.cx += RLE_gshort(&_RLE.cp)); Rp->xe = (_RLE.cx += RLE_gshort(&_RLE.cp)) - 1; _RLE.nrun++; return(_RLE.cy); } /* Return ptr to the next line with at least one run overlapping the margins [lm,rm]. The reported runs are not trimmed to fit exactly within margins. If no more lines, return NULL. On error, abort */ RLE_Line *RLE_get_Line(lm,rm) int lm, rm; /* left, right margins */ { register int rr; /* runs read */ register RLE_Run *rp; /* write ptr */ do { if(_RLE.eof) { free(_RLE.lp); _RLE.lp = NULL; free(_RLE.bf); _RLE.bf = NULL; return(NULL); }; if(_RLE.lp==NULL) { /* allocate space for RLE_Line */ _RLE.lp = (RLE_Line *) malloc(sizeof(RLE_Line)); if(_RLE.lp==NULL) { abort("rlelib: can't malloc RLE_Line (%d bytes)", sizeof(RLE_Line)); }; }; _RLE.lp->y = _RLE.cy; /* guaranteed to be at least one run in line */ rr=0; rp=_RLE.lp->r; _RLE.lp->runs=0; /* skip runs that are outside left margin */ do RLE_get_Run(rp); while((rr++ < _RLE.runs) && (rp->xe < lm)); /* accept runs until cross right margin */ while(rp->xs <= rm) { _RLE.lp->runs++; /* count accepted runs */ if(rr++ >= _RLE.runs) break; RLE_get_Run(++rp); }; /* look ahead to next line */ if (!RLE_rdbf()) /* EOF */ _RLE.eof=T; } while(_RLE.lp->runs==0); /* as result of margins, some lines may empty */ return(_RLE.lp); } /* read next line buffer - return F if EOF, abort on error sideffects: sets up _RLE.cp, _RLE.cy, _RLE.cx, _RLE.runs, _RLE.nrun */ boolean RLE_rdbf() { short nh; if(dbg_rd) err("enter RLE_rdbf"); /* get number of bytes holding RLE of a scan line */ if( read(_RLE.fd,&nh,sizeof(short)) != sizeof(short)) { return(F); /* normal EOF */ }; if( Readvax ) nh = swapshortin( nh ); if(dbg_rd) err("rlelib: RLE_rdbf: nh %d",nh); if(nh > _RLE.bpl) { abort("rlelib: too many bytes in line: %d > %d(_RLE.bpl)", nh,_RLE.bpl); }; /* get those bytes */ if( read(_RLE.fd,_RLE.bf,nh) != nh) { abort("rlelib: rle line truncated"); }; if(dbg_rd) { int bi; err("rlelib: RLE_rdbf: _RLE.bf[0-%d] octal:",nh-1); for(bi=0;bi<nh;bi++) fprintf(stderr," 0%o",0377&(_RLE.bf[bi])); fprintf(stderr,"\n"); }; /* decode the bytes */ _RLE.cp = _RLE.bf; _RLE.runs = RLE_gshort(&_RLE.cp); if(dbg_rd) err("rlelib: _RLE.runs %d",_RLE.runs); if(_RLE.runs==0) { /* blank lines seen */ _RLE.cy += RLE_gshort(&_RLE.cp); _RLE.runs = RLE_gshort(&_RLE.cp); if(dbg_rd) err("rlelib: _RLE.cy %d _RLE.runs %d",_RLE.cy,_RLE.runs); }; if(_RLE.runs>RLE_RUNS || _RLE.runs<1) { abort("rlelib: illegal no. runs %d in line",_RLE.runs); }; _RLE.cy++; if(dbg_rd) err("rlelib: RLE_rdbf: _RLE.runs %d _RLE.cy %d",_RLE.runs,_RLE.cy); _RLE.cx = _RLE.nrun = 0; /* next run will be first */ if(dbg_rd) err("rlelib: RLE_rdbf: T exit"); return(T); } /* brrl - compute a binary raster line from a run-length-encoded scanline. runa[] is an array of shorts, grouped in pairs (xs,xe) to describe the starting and ending index (inclusive) of each run of black pixels (1 bits). xe >= xs > xe. The runs are in strictly ascending order on xs. lm & rm are the left and right margin indices of pixels, outside of which the pixels are forced to be white. rm >= lm. The `lm'th pixel is written into the `olm'th bit of the output raster (olm>=0). rasp[] is a raser line of chars; on entry, it is assumed to have been zeroed out. rasp[0] holds the leftmost byte in the line and the 001 bit of each byte is the leftmost bit in that byte. The user must ensure that rasp[] is at least (rm-lm+olm+9)/8 bytes long. Returns the number of black pixels in the raster line. NOTE: this uses the ``little-endian'' convention, in which the leftmost pixel in a byte is placed in the least-significant bit (0x01). See `brrlb()' below for the alternative ``big-endian'' version. */ int brrl(runs,runa,lm,rm,olm,rasp) int runs; /* number of run-segments in runa[] */ short runa[]; /* array of run-segments [xs,xe] (pairs of short) */ int lm,rm; /* left,right margin bit indices within raster */ int olm; /* `lm'th input pixel will be written to `olm'th bit */ char unsigned rasp[]; /* binary raster line (zeroed out on entry) */ { int pixels,bi; RLE_Run r,*rp,*re; pixels = 0; re = (rp = (RLE_Run *) runa) + runs; while(rp<re && rp->xe<lm) rp++; /* skip runs to the left of 'lm' */ while(rp<re && rp->xs<=rm) { /* truncate to margins */ if((r.xs = rp->xs)<lm) r.xs = lm; if((r.xe = rp->xe)>rm) r.xe = rm; /* shift to output indices */ r.xs += olm-lm; r.xe += olm-lm; /** SLOW **/ for(bi=r.xs; bi<=r.xe; bi++) rasp[bi/8] |= (01)<<(bi%8); pixels += r.xe-r.xs+1; rp++; }; return(pixels); } /* ``big-endian'' version of brrl: bits are packed so that the leftmost pixel is placed in the high-order bit (0x80) of each byte. */ int brrlb(runs,runa,lm,rm,olm,rasp) int runs; short runa[]; int lm,rm,olm; char unsigned rasp[]; { int pixels,bi; RLE_Run r,*rp,*re; pixels = 0; re = (rp = (RLE_Run *) runa) + runs; while(rp<re && rp->xe<lm) rp++; /* skip runs to the left of 'lm' */ while(rp<re && rp->xs<=rm) { /* truncate to margins */ if((r.xs = rp->xs)<lm) r.xs = lm; if((r.xe = rp->xe)>rm) r.xe = rm; /* shift to output indices */ r.xs += olm-lm; r.xe += olm-lm; /** SLOW **/ for(bi=r.xs; bi<=r.xe; bi++) rasp[bi/8] |= (0200)>>(bi%8); pixels += r.xe-r.xs+1; rp++; }; return(pixels); } /* crrl - compute a character raster line from a run-length-encoded scanline. runa[] is an array of shorts, grouped in pairs (xs,xe) to describe the starting and ending index (inclusive) of each run of black pixels (1 bits): xs<=xe. The runs are in strictly ascending order on xs. lm & rm are the left and right margin indices, outside of which pixels are forced to be white. rm >= lm. rasp[] is a raster line, one unsigned char per pixel; rasp[0] holds the leftmost pixel. The user must ensure that rasp[] is at least (rm-lm+1) bytes long. Black pixels are encoded as 0, white as 255. Returns the number of black pixels in the raster line. */ #define WHITE_pel 0377 #define BLACK_pel 0000 int crrl(runs,runa,lm,rm,rasp) int runs; /* number of run-segments in runa[] */ short runa[]; /* array of run-segments [xs,xe] (pairs of short) */ int lm,rm; /* left,right margin bit indices within raster */ unsigned char rasp[]; /* char raster line */ { int pixels,bi,wid; RLE_Run r,*rp,*re; unsigned char *cp,*ep; wid=rm-lm+1; memset(rasp,WHITE_pel,wid); re = (rp = (RLE_Run *) runa) + runs; while(rp<re&&rp->xe<lm) rp++; /* skip runs to the left of 'lm' */ if(rp>=re) return(0); r = *rp; r.xs -= lm; r.xe -= lm; pixels = 0; do { /* truncate left,right margin */ if(r.xs<0) r.xs = 0; if(r.xe>(wid-1)) r.xe = wid-1; /* write r into raster line */ pixels += (r.xe-r.xs+1); for(cp=rasp+r.xs,ep=rasp+r.xe; cp<=ep; cp++) *cp = BLACK_pel; /* step to next run */ r = *(++rp); r.xs -= lm; r.xe -= lm; } while(r.xs<=(wid-1)&&rp<re); return(pixels); } /* trcr - threshold & run-length-encode a char raster line. `rasp' is a raster line, one unsigned char per pixel: rasp[0] is the leftmost pixel in the line. Pixels with value < 'thresh' are translated to black, else white. Analyzes the line into a series of runs of `1's, placing them into array `runs'. Observes margins: starts at `lm' bit and continues through `rm'; bits outside the margins are assumed 0. A `run' is two shorts (the starting & ending indices of the run of `1's, inclusive). The indices are shifted so that the `lm'th pixel goes to run index `olm'. Returns the number of runs. NOTE: The user must ensure that: (1) margins fall within `rasp[]'; (2) `runp[]' is big enough to hold the worst-case no. of runs that can result ((rm-lm+2)/2). The contents of the raster-line are unmodified. */ int trcr(rasp,lm,rm,olm,thresh,runp) char unsigned rasp[]; /* binary raster line (with 1 extra byte at end) */ int lm,rm; /* left,right margin indices within raster */ int olm; /* `lm' pixel goes to `olm' run index */ int thresh; short runp[]; /* array of run-segments [xs,xe] (pairs of short) */ #define dbg_trcr (T) { unsigned char *cp,*ep; short x,*xp; int cv,pv; /* current,prior binary pixel value */ ep=(cp=rasp+lm)+rm; x=olm; xp=runp; pv=0; /* assume pixels left of 'lm' are 0 */ while (cp<=ep) { if((*cp)<thresh) { /* black pixel */ cv=1; if(pv==0) { *xp = x; xp++; }; } else { /* white pixel */ cv=0; if(pv==1) { *xp = x-1; xp++; }; }; pv=cv; x++; cp++; }; if(pv==1) { *xp = x-1; xp++; }; /* assume pixels right of 'rm' is 0 */ return((xp-runp)/2); } /* Transform a sequence of rle-lines using trimming, offsetting, scaling, truncation, and reverse-video. Scaling may lead to interpolation or decimation of lines, so an input line may be mapped into 0, 1, or more output lines. Input lines may be buffered, and there may be latency. To flush buffers, this must be called with NULL argument at end of the sequence. Each output line will be passed to function `sink()', which returns 1 if OK and 0 to quit. Quits are passed back immediately with no latency. Sink's 1st arg RLE_Line *l is a line of runs in output coordinates, whose `len' is the maximum length of the line. l==NULL means end of sequence. Return 1 if OK, 0 to quit. A copy of *l is passed to sink(). a->sy is incremented for every line written to the sink, and is attached to the output lines as *.y. */ int transform_rlel(l,a,sink,sa) RLE_Line *l; /* NULL if end of sequence */ Transform_rlel_arg *a; int (*sink)(); /* takes args: (RLE_Line *), and int */ VOID *sa; /* passed to sink() as 2nd arg */ { RLE_Line m,r; register RLE_Run *rp,*ep,*mp; RLE_Run mr,mm,rr; int rm; int o_a_x,o_b_x; /* maximum output index */ if(l==NULL) { sink(NULL,sa); return(1); }; m.len = l->len; m.runs = l->runs; if(a->ident) { if(m.runs>0) memcpy(m.r,l->r,2*m.runs*sizeof(short)); m.y = a->sy; if(sink(&m,sa)==0) return(0); else { a->sy++; return(1); }; }; /* maximum permissable output bounds */ o_a_x = (int)((a->tr.a.x + a->off.x)*a->scl.x); o_b_x = o_a_x + a->wh.x - 1; if(a->sy<=((int)a->dy)) { /* compute runs to be ouput: rp - input runs; mp - output runs*/ mp=(m.r - 1); for(ep=(rp=l->r)+l->runs; rp<ep; rp++) { /* trim using a->tr */ mr = *rp; if(mr.xe < a->tr.a.x) /* off left margin */ continue; if(mr.xs > a->tr.b.x) /* off right margin */ break; if(mr.xs < a->tr.a.x) /* extends left too far */ mr.xs=a->tr.a.x; if(mr.xe > a->tr.b.x) /* extends right too far */ mr.xe=a->tr.b.x; /* offset using a->off */ mr.xs += a->off.x; mr.xe += a->off.x; /* expand using a->scl */ mr.xs = (int)(mr.xs*a->scl.x); mr.xe = ((int)((mr.xe+1)*a->scl.x))-1; if(mr.xe<mr.xs) mr.xe=mr.xs; /* truncate to maximum output width */ if(mr.xe<o_a_x) /* off left margin */ continue; if(mr.xs>o_b_x) /* off right margin */ break; if(mr.xs<o_a_x) /* extends left too far */ mr.xs=o_a_x; if(mr.xe>o_b_x) /* extends right too far */ mr.xe=o_b_x; /* store */ if(mp < m.r) /* first */ *(++mp) = mr; else /* can merge with prior run? */ { if(mp->xe >= (mr.xs-1)) /* yes */ mp->xe = mr.xe; else /* no */ *(++mp) = mr; }; }; m.runs = mp - m.r + 1; m.len = a->wh.x; do { m.y = a->sy; if(a->rev) { /* r = reverse-video(m) */ rp=r.r; rr.xs=o_a_x; for(ep=(mp=m.r)+m.runs; mp<ep; mp++) { if(rr.xs<mp->xs) { rr.xe=mp->xs-1; *(rp++)=rr; }; rr.xs=mp->xe+1; }; if(rr.xs<=o_b_x) { rr.xe=o_b_x; *(rp++)=rr; }; r.runs = rp-r.r; r.len = m.len; r.y = m.y; if(sink(&r,sa)==0) return(0); } else { if(sink(&m,sa)==0) return(0); }; a->sy++; } while(a->sy<=((int)a->dy)); }; a->dy += a->scl.y; return(1); } /* Insert a (copy of) the given RLE_Line in the RLE_Lines */ insert_rlel(rlp,rlsp) RLE_Line *rlp; RLE_Lines *rlsp; { abort("insert_rlel: unimplemented"); } err_RLE_line(s,rl) char *s; /* name */ RLE_Line *rl; { RLE_Run *r; int ri; if(rl==NULL) fprintf(stderr,"RLEL %10s NULL\n",s); else { fprintf(stderr,"RLEL %10s y%d r%d l%d: ", s,rl->y,rl->runs,rl->len); for(ri=0,r=rl->r;ri<rl->runs;ri++,r++) fprintf(stderr,"[%d,%d] ",r->xs,r->xe); fprintf(stderr,"\n"); }; } 0707070035351135271006640007620000050000010264220476773367400001100000047346stdocr.h /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* H. S. Baird - ATT-BL MH - first versions */ /* stdocr.h -- conventional OCGR constants, typedefs, and file formats NOTE: sensitive to prior: `#define MAIN 1' `#define CPU ?' `#define OS ?' */ extern int errno; /* UNIX system call error number */ #ifndef MAIN #define MAIN 0 #endif #define FWRI (T) /* use machine-independent format for dim-file writes */ #define FRDI (T) /* use machine-independent format for dim-file reads */ #ifndef PI #define PI 3.1415926535 #endif extern int Readvax; /* T. Thompson flag: see Coord.c */ #include "limits.h" /* machine-dependent numeric extreme values */ #include "fioi.h" /* machine-independent types and binary I/O */ #include "boole.h" /* boolean type */ #include "Units.h" /* OCR-specific units */ #include "Coord.h" /* scanner coordinates & basic geometry */ #include "ric.h" /* ricoh scanner page & file formats */ /* 5620 dimensions, in dots */ #define Width5620 800 #define Height5620 1024 /* used (in clc.c) to compute absolute maximum value of natural log values used in Bayesian binary weights */ #define LOG_ABS_MAX 3.0 #define Merit float /* heuristic ``merit'' takes on values in [0,1] */ /* machine-independent I/O: range [0.0-1.0], precision .0000153 */ #define fwri_Merit(F,V) fwri_uint2((F),((V)*USHRT_MAX)) #define frdi_Merit(F) (frdi_uint2(F)/(Merit)USHRT_MAX) #define Prob float /* ``probability'' takes on values in [0,1] */ /* machine-independent I/O: range [0.0-1.0], precision .0000153 */ #define fwri_Prob(F,V) fwri_uint2((F),((V)*USHRT_MAX)) #define frdi_Prob(F) (frdi_uint2(F)/(Prob)USHRT_MAX) #define Pts float /* text-size units: ``points'' (1/72) inch */ /* machine-independent I/O: range [0,655.36], precision 0.01 ([0,9.1] inches) */ #define fwri_Pts(F,V) fwri_uint2((F),((V)*100.0)) #define frdi_Pts(F) (frdi_uint2(F)/100.0) #define Ems float /* em-space units */ /* machine-independent I/O: range [-32.768,32.767], precision 0.001 */ #define fwri_Ems(F,V) fwri_int2((F),((V)*1000.0)) #define frdi_Ems(F) (frdi_int2(F)/1000.0) /* class name - long enough to be a unix file name */ #define Cln_len (14) /* maximum no. chars (DIRSIZ in some UNIX's) */ #define Cln_lenp (Cln_len+1) /* maximum size of array */ typedef char Cln[Cln_lenp]; #define fwri_Cln(F,S) fwri_str((F),(S)) #define frdi_Cln(F,S) frdi_strn((F),(S),Cln_lenp) /* font name */ #define Fontn_len (Cln_len) /* maximum no. chars */ #define Fontn_lenp (Cln_lenp) /* maximum size of array */ typedef char Fontn[Fontn_lenp]; #define fwri_Fontn(F,S) fwri_str((F),(S)) #define frdi_Fontn(F,S) frdi_strn((F),(S),Fontn_lenp) typedef struct ClassId { Fontn f; /* font name */ Pts s; /* size in points */ Cln c; /* printable symbol name (``class-name'') */ short v; /* symbol variant no. 0,1,... */ } ClassId; #define Init_ClassId {"",0.0,"",0} #if MAIN ClassId empty_ClassId = Init_ClassId; #else extern ClassId empty_ClassId; #endif char *classid_toa(); /* in chcln.c */ #define eq_classid(a,b) ((!strcmp((a).f,(b).f))&&((a).s==(b).s)&&(!strcmp((a).c,(b).c))&&((a).v==(b).v)) #define fwri_ClassId(F,P) { \ fwri_Fontn((F),(P)->f); \ fwri_Pts((F),(P)->s); \ fwri_Cln((F),(P)->c); \ fwri_uint1((F),(P)->v); \ } #define frdi_ClassId(F,P) ( feof(F)? 0: ( \ frdi_Fontn((F),(P)->f), \ (P)->s=frdi_Pts(F), \ frdi_Cln((F),(P)->c), \ (P)->v=frdi_uint1(F), \ (ferror(F)? -errno: 1) ) ) /* Convert variant no. to ASCII character, and vice versa */ #define vtoc(V) (((V)<=9)?('0'+(V)):(((V)<=35)?('a'+((V)-10)):('A'+((V)-36)))) #define ctov(C) ((((C)>='0')&&((C)<='9'))?((C)-'0'):((((C)>='a')&&((C)<='z'))?(10+((C)-'a')):(36+((C)-'A')))) /* parametric values: */ #define Pval float /* machine-independent I/O: precision 0.0001 & range [-838.8608,838.8607] */ #define fwri_Pval(F,V) fwri_int4((F),(V)*1000.0) #define frdi_Pval(F) (frdi_int4(F)/1000.0) typedef struct { /* parametric point */ Pval x; Pval y; } Pp; #define Init_Zero_Pp {0.0,0.0} #if MAIN Pp zero_Pp = Init_Zero_Pp; #else extern Pp zero_Pp; #endif #define fwri_Pp(F,P) { fwri_Pval((F),(P)->x); fwri_Pval((F),(P)->y); } #define frdi_Pp(F,P) ( feof(F)? 0: ( \ (P)->x=frdi_Pval(F), \ (P)->y=frdi_Pval(F), \ (ferror(F)? -errno: 1) ) ) /* metrics: ABSS, EUCL, MAXV */ #define ABSS 'a' #define EUCL 'e' #define MAXV 'm' typedef short Metric; #define fwri_Metric(F,V) fwri_ch((F),(V)) #define frdi_Metric(F) (frdi_ch(F)) /* a vectorized blob file is a sequence of blob-descriptions. a blob-description is a sequence of "vector" records; there are two types of blob descriptions: DOT: 'D'-vector (with bounding box) CHAR: 'C'-vector, followed by: one 'B'-vector (bounding-box), and any number of: 'S' (stroke), 'G' (edge), 'O' (hole), 'A' (arc), 'C' (corner), 'P' (end-point), and 'V' & 'W' (boundary angles - 1 each), and terminated with one 'E' vector (giving classname) */ #define Vrec_len 5 typedef short Vrec[Vrec_len]; /* subshape values */ /* #define U 0 uninitialized */ #define NA (SHRT_MAX) /* deliberately not-assigned (classifier failure) */ #define Dim short /* specifies dimension 1,..,MaxDim */ #define MaxDim 4 #define fwri_Dim(F,V) fwri_uint1((F),(V)) #define frdi_Dim(F) (frdi_uint1(F)) #define Seq int /* sequence nos; indices into tables */ #define FISeq 0 /* first value */ #define NLSeq -1 /* conventional NULL value */ #define S1Seq 0200000000 /* special bit 1 of Seq */ #define S2Seq 0100000000 /* special bit 2 of Seq */ #define NSSeq 0077777777 /* non-special bits */ #define fwri_Seq(F,V) fwri_int4((F),(V)) #define frdi_Seq(F) (frdi_int4(F)) typedef short Liv; /* limit value: scaled and truncated from floating-pt */ #define Liv_MAX (SHRT_MAX) #define Liv_MIN (SHRT_MIN) #define fwri_Liv(F,V) fwri_int2((F),(V)) #define frdi_Liv(F) (frdi_int2(F)) typedef short Lit; /* limit type, two flavors: */ #define MN 0 /* min: MN < v */ #define MX 1 /* max: v <= MX */ typedef Liv Ivl[2]; /* interval: ( Ivl[MN], Ivl[MX] ] */ typedef Ivl Rec[MaxDim]; /* rectangular parallelopiped of limits in DIM-space */ /* a normalized blob file is a sequence of: Nb_h header, followed by Nb_h.ss of: Nb_s contour shapes */ typedef struct { ClassId ci; /* class name */ Bbx bb; /* bounding box */ Pval rsz; /* raw character size (Ems) */ Pval bht; /* height-above-baseline (Ems) */ Pval rwd; /* width (Ems) */ Pval rar; /* area (square-Ems) */ Pval rpe; /* perimiter (Ems) */ Pval asp; /* aspect ratio (h/w) */ Pval blk; /* fraction of Bbx area that is black */ Pval per; /* perimeter of blob as multiple of Bbx perim */ Pval gale; /* Gale's feature: incl. angle 'tween 2 longest sides */ short ss; /* no. of shapes to follow */ } Nb_h; #define MAX_SHAPES_EACH 1024 /* Max no. shapes per Blob/Char/item */ /* Shape is tiny (below threshold, may be pruned): a flag ORed into shape type */ #define Sh_tiny (0x80) /* Shape types: */ #define U 0 /* uninitialized */ #define Sh_FI 1 /* first shape no. */ #define Sh_B 1 /* blob (connected black region) */ #define Sh_H 2 /* hole (connected white region) */ #define Sh_S 3 /* stroke (undirected line-segment) */ #define Sh_E 4 /* edge (directed line-segment along boundary) */ #define Sh_C 5 /* concavity (intrusion from convex hull): its `cover' edge */ #define Sh_D 6 /* direction and depth of concavity */ #define Sh_A 7 /* locally-maximal convex arc (encloses black) */ #define Sh_V 8 /* locally-maximal concave arc (encloses white) */ #define Sh_P 9 /* endpoint (0-junction) */ #define Sh_T 10 /* detail (left- and right-facing ticks) */ #define Sh_X 11 /* crossing (X) */ #define Sh_Y 12 /* global scalar variables, combined */ #define Sh_Z 13 /* more global scalar variables, combined */ #define Sh_LA 13 /* last of variable-no-of-occurences shape-types */ #define Sh_MNY (Sh_LA+1) #define SHS_MNY (Sh_MNY) #if (MAIN) /* shape-names, given shape-type */ char Sh_nam[SHS_MNY] = {'U', 'B', 'H', 'S', 'E', 'C', 'D', 'A', 'V', 'P', 'T', 'X', 'Y', 'Z'}; /* "dimension" -- no parameters in normalized form */ short Sh_dim[SHS_MNY] = { 0, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 3, 1}; /* absolute minimum parametric values possible -- must be >= -1.0 (see norm.c & fiodict.c) */ Pval Sh_MN[SHS_MNY][MaxDim] = { { 0.0, 0.0, 0.0, 0.0}, /* U */ {-0.5, -0.5, -0.5/*see mkd*/}, /* B */ {-0.5, -0.5, -0.5/*see mkd*/}, /* H */ {-0.5, -0.5, -0.5, -0.5}, /* S */ {-0.5, -0.5, -0.5, -0.5}, /* E */ {-0.5, -0.5, -0.5, -0.5}, /* C */ {-0.5, -0.5, -0.5, -0.5}, /* D */ {-0.5, -0.5, -0.5, -0.5}, /* A */ {-0.5, -0.5, -0.5, -0.5}, /* V */ {-0.5, -0.5, -0.5, -0.5}, /* P */ {-0.5, -0.5, -0.5}, /* T */ {-0.5, -0.5}, /* X */ {-0.5, -0.5, -0.5}, /* Y */ {-0.5} /* Z */ }; /* absolute maximum parametric value possible -- must be <= 1.0 (see norm.c & fiodict.c) */ Pval Sh_MX[SHS_MNY][MaxDim] = { { 0.0, 0.0, 0.0, 0.0}, /* U */ {0.5, 0.5, 1.0/*see mkd*/}, /* B */ {0.5, 0.5, 1.0/*see mkd*/}, /* H */ {0.5, 0.5, 0.5, 0.5}, /* S */ {0.5, 0.5, 0.5, 0.5}, /* E */ {0.5, 0.5, 0.5, 0.5}, /* C */ {0.5, 0.5, 0.5, 0.5}, /* D */ {0.5, 0.5, 0.5, 0.5}, /* A */ {0.5, 0.5, 0.5, 0.5}, /* V */ {0.5, 0.5, 0.5, 0.5}, /* P */ {0.5, 0.5, 0.5}, /* T */ {0.5, 0.5}, /* X */ {0.5, 0.5, 0.5}, /* Y */ {0.5} /* Z */ }; /* minimum magnitude of (r,i) part of certain shapes */ Pval A_ri_minmag = 0.25; Pval P_ri_minmag = 0.25; #else extern char Sh_nam[]; extern short Sh_dim[]; extern Pval Sh_MN[][MaxDim]; extern Pval Sh_MX[][MaxDim]; extern Pval A_ri_minmag; extern Pval P_ri_minmag; #endif #define MIN_SD 0.001 /* minimum std-dev permitted */ typedef Pval Spar[MaxDim]; /* shape parameters */ typedef struct Nb_s { short t; /* shape type: one of U S O A C etc, perhaps |Sh_tiny */ Spar p; /* parametric values */ } Nb_s; /* indices into parametric values */ /* blobs */ #define B_x 0 /* (x,y) location of dot wrt bounding-box */ #define B_y 1 #define B_r 2 /* size of dot */ /* holes */ #define H_x 0 /* (x,y) location of center wrt bounding-box */ #define H_y 1 #define H_r 2 /* size of hole */ /* strokes */ #define S_x 0 /* (x,y) location of stroke center wrt bounding box */ #define S_y 1 #define S_r 2 /* (r,i) real-imag parts of rotation-length vector; */ #define S_i 3 /* rotation angle *2 since strokes have only [0,PI] range */ /* edges */ #define E_x 0 /* (x,y) location of edge center wrt bounding box */ #define E_y 1 #define E_r 2 /* (r,i) real-imag parts of direction-length vector */ #define E_i 3 /* concavity hull edge */ #define C_x 0 /* (x,y) location of center of hull-bdy edge wrt bounding-box */ #define C_y 1 #define C_r 2 /* (r,i) real-imag parts of hull-bdy edge */ #define C_i 3 /* concavity depth & direction */ #define D_x 0 /* (x,y) location of center of depth & direction vector */ #define D_y 1 #define D_r 2 /* (r,i) real-imag parts of depth & direction vector */ #define D_i 3 /* locally-maximal convex arc */ #define A_x 0 /* (x,y) location of center of enclosed area */ #define A_y 1 #define A_r 2 /* (r,i) real-imag parts of `incompleteness' vector */ #define A_i 3 /* locally-maximal concave arc */ #define V_x 0 /* (x,y) location of center of enclosed area */ #define V_y 1 #define V_r 2 /* (r,i) real-imag parts of `incompleteness' vector */ #define V_i 3 /* endpoint */ #define P_x 0 /* (x,y) location of center of hull-bdy wrt bounding-box */ #define P_y 1 #define P_r 2 /* (r,i) real-imag parts of direction-depth vector */ #define P_i 3 /* ticks: left-, right-, top-, & bottom-facing extrema near ends */ #define T_x 0 /* signed distance from centroid along principal axis */ #define T_y 1 /* signed perpendicular distance from axis */ #define T_a 2 /* angle of principal axis, within worst-case range */ /* crossings */ #define X_x 0 /* (x,y) location of crossing wrt bounding-box */ #define X_y 1 /* global scalars, combined */ #define Y_a 0 /* log(aspect_ratio=hgt/wid) */ #define Y_b 1 /* ratio of area to bbx_area */ #define Y_p 2 /* ratio of perimeter to bbx_perimeter */ /* global scalars, combined (more) */ #define Z_g 0 /* Gale's feature: included angle between two longest bdy edges */ /* scalar features field indices */ #define SF_RSZ 0 /* relative size (height in ems) */ #define SF_BHT 1 /* height above baseline (ems) */ #define SF_RWD 2 /* relative width (ems) */ #define SF_RAR 3 /* relative area (square-ems) */ #define SF_RPE 4 /* relative perimeter (ems) */ #define SF_ASP 5 /* aspect-ratio */ #define SF_BLK 6 /* fraction of Bbx that is black */ #define SF_PER 7 /* ratio of perimeter to BBx per */ #define SF_GALE 8 /* Gale's feature: incl. ang. between 2 longest edges */ #define SF_N 8 /* index of last var that's not an occurrence-count */ #define SF_MNY (SF_N+Sh_LA+1) #if MAIN /* ``Is this feature available early enough to be used in fast scalar- feature preclassifier?'' (Must not depend on shape analysis.) */ boolean SFfeature[SF_MNY] = { F, F, F, F, F, T, T, T, F, T, T, T, T, T, T, T, T, T, T, T, F, F }; /* ``Is this feature discrete (integer-valued)?'' (Affects construction of scalar-decision tree preclassifier.) */ boolean SFdiscrete[SF_MNY] = { F, F, F, F, F, F, F, F, F, T, T, T, T, T, T, T, T, T, T, T, T, T }; #else extern boolean SFfeature[]; extern boolean SFdiscrete[]; #endif typedef Pval SFv[SF_MNY]; /* blob tracer (boundary angles) features field indices */ #define TR_MNY 8 typedef Pval TRv[TR_MNY]; /* tracer decision-tree header */ typedef struct TRtr { struct SFdnode *TRd; /* array of decision-nodes */ struct Cl ***clist; /* list of (class-ptr)-lists */ } TRtr; /* Ss - sub-shape list-item */ typedef struct Ss { Seq seq; /* globally unique sequence no */ Seq shs; /* shape-hdr seq no */ Seq cls; /* class sequence no */ short no; /* sub-shape number (0,1,2..., NA) */ float focc; /* fraction of training set w/ >=1 occurrence */ float fdup; /* fraction of training set w/ >=2 occurrence */ Spar me; /* mean parameters */ Spar sd; /* std-dev parameters */ Spar min; /* min limits (for fast checking) */ Spar max; /* max limits (for fast checking) */ Rec r; /* rectangular parallelopiped in Liv space */ Pval fr; /* fraction of training set covered */ short nuse; /* for current blob, no. uses */ float nocc; /* occurrences: no. blobs with >=1 of these */ float ndup; /* duplicates: no. blobs with >=2 of these */ float mind; /* minimum scaled distance from cluster among uses */ float merit; /* merit score resulting from 'nuse' matches to this */ struct Ss *ne; /* ptr to next in list */ } Ss; #define MAX_SS 8192 /* see 'kdt.h' for reasons */ /* BMask: 1-d, variable-length packed bitstring (N = no. bits). The string is stored in an array of (unsigned int). It is often accessed via a fast ascending sequence of 'short' pointers (unsigned short *) or (unsigned char *): in these cases, enough are used to completely cover all the (unsigned int)s, even though that may be more than enough, to ensure that the result is insensitive to machine-dependent short-order-in-ints and char-order-in-shorts. BMask_ni(N) no. unsigned ints holding bit-data BMask_si(N) no. unsigned shorts covering bit-data (exactly 2x _ni) BMask_ci(N) no. unsigned chars covering bit-data (exactly 4x _ni) BMask_size(N) total no. bytes in, or pointed to by BMask: sizeof(n) + sizeof(mny) + sizeof(r) + sizeof(malloc space) */ #define BMask_ni(N) (((N)+(8*sizeof(unsigned int))-1)/(8*sizeof(unsigned int))) #define BMask_si(N) (2*BMask_ni(N)) #define BMask_ci(N) (4*BMask_ni(N)) #define BMask_size(N) (3*sizeof(unsigned int)+(BMask_ci((N)))) typedef struct BMask { unsigned int n; /* no. of bits stored (==N above) */ unsigned int mny; /* no. bits set to 1 */ unsigned int r; /* represents `r' BMasks altogether */ union { /* packed bits: 0th bit is 01 */ unsigned int *i; /* malloc space: int [Bmask_ni] */ unsigned short *s; /* malloc space: short [Bmask_si] */ int ii; /* index into (unsigned int)[] array */ int si; /* index into (unsigned short)[] array */ } u; } BMask; #define Init_BMask {0,0,0,} #if MAIN BMask empty_BMask = Init_BMask; #else extern BMask empty_BMask; #endif typedef struct BMasks { unsigned short mny; /* no. BMasks */ unsigned short r; /* represents `r' BMasks altogether */ unsigned short shallow; /* 0 <= shallow <= mny */ unsigned short alloc; /* no. items allocated in .a[] */ union { BMask *a; /* array[mny] of BMasks */ int bi; /* index into (BMask)[] array */ } u; } BMasks; #define Init_BMasks {0,0,0,0,} #if MAIN BMasks empty_BMasks = Init_BMasks; #else extern empty_BMasks; #endif /* Sh - shape list-item */ typedef struct Sh { Seq seq; /* unique sequence no. */ short t; /* shape type: S, H, X, etc */ short nss; /* no. sub-shapes in the list */ float mess; /* mean no. sub-shapes in training set */ float sdss; /* std-dev of sub-shapes in training set */ float NAocc; /* prob at least one shape not-assigned */ float NAdup; /* prob more than one not-assigned */ Ss NAss; /* "not-assigned" data */ Ss *fi; /* first sub-shape */ Ss *la; /* last sub-shape */ struct Sh *ne; /* next shape */ } Sh; /* Cl - class list-item */ typedef struct Cl { Seq seq; /* unique sequence no. 0,1,... */ Cln c; /* class name */ float shNA; /* fraction of shapes unassigned */ float blDP; /* fraction of blobs w/ >=1 duplicate shape-match*/ float blAL; /* average extra alternate shape-matches / blob */ SFv sf_me; /* scalar-features: means, std-devs */ SFv sf_sd; BMask bm; /* canonical BMask */ BMasks bms; /* additional representative BMask records */ Sh *sha[Sh_MNY]; /* table of pointers to shape-types */ Sh *fi; /* first owned shape */ Sh *la; /* last owned shape */ short unmat[Sh_MNY]; /* counts of unmatched shapes/shape-type */ struct Ssm *ssmfi; /* first sub-shape match for this class */ TRtr *tr; /* pointer to tracer decision tree (if any) */ TRv tr_me; /* tracer-features: means, std-devs */ TRv tr_sd; float m_me; /* mean, std-err of merit (in training set) */ float m_sd; float bayes; /* Bayesian merit: a posteriori log-probability */ Merit m01; /* Haming, etc. merit in range [0,1] */ Merit merit; /* sort and truncate based on this merit */ short pass; /* the last classification method this class passed */ int ch_mny; /* No. Chars of this class in a subset */ int ss_mny; /* No. Chars with given feature */ boolean force_reseg; /* forcibly resegment Chars of this Class */ struct Cl *ne; /* next class */ } Cl; /* MAX_CL (max no. of classes) is defined in CPU.h */ #define MAX_SH (MAX_CL*SH_MNY) typedef struct Classes { int mny; /* number of items in array */ Cl **clpa; /* Cl *clpa[cl_mny+1]: NULL-term'd array of ptrs */ } Classes; #define Init_Classes {0,NULL} #if MAIN Classes empty_Classes = Init_Classes; #else extern Classes empty_Classes; #endif typedef struct Ssm { /* sub-shape match record */ Seq isn; /* input shape sequence no (w/in blob) */ Cl *clp; /* owning class, shape, sub-shape... */ Sh *shp; Ss *ssp; float mind; /* distance to closest assigned sub-shape */ boolean alt; /* T if this is an alternative (not the first) */ struct Ssm *ne; /* next, prior ptrs in list */ struct Ssm *pr; } Ssm; /* return pathname of OCR directory; if environment variable OCRDIR is set, it is used; otherwise #defined variable OCRDIR is used. */ #if MAIN char *getenv(); char *ocrdir() { char *ocrdir_ev; if((ocrdir_ev=getenv("OCRDIR"))!=NULL) { return(ocrdir_ev); } else return(OCRDIR); } #else char *ocrdir(); #endif 0707070035351135261006640007620000050000010264330476773367400001100000033171sunlib.c /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ /* The copyright notice does not imply actual or intended publication. */ /* AUTHORS: */ /* T. Thompson - ATT-BL HO - first versions */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <pixrect/pixrect.h> #include <pixrect/pixfont.h> #include <suntool/sunview.h> #include <suntool/canvas.h> #include "met.h" #include "boole.h" #include "Coord.h" #define XYSCALE(x,y) (x=(x-obotx)*scx+botx),(y=(y-oboty)*scy+boty) struct pixrect *source_pixrect; Frame Mainframe; Canvas Win; int Winfd; Pixwin *Pw; int Key = -1; int Mousex; int Mousey; int Colorval; /* CMAPSIZE MUST BE A POWER OF 2 (restriction in sun colormap stuff)*/ #define CMAPSIZE 8 #define DEFAULTCOLOR (CMAPSIZE-1) #define S_WHITE 0 #define S_RED 1 #define S_GREEN 2 #define S_BLUE 3 #define S_GREY 4 #define S_AQUA 5 #define S_YELLOW 6 #define S_BLACK 7 int mycolors[CMAPSIZE][3] = { 255, 255, 255, /* white */ 230, 0, 75, /* red */ 0, 200, 0, /* green */ 0, 0, 200, /* blue */ 200, 200, 200, /* grey */ 0, 160, 170, /* aqua */ 250, 220, 0, /* yellow */ 0,0,0 /* foreground (black) */ }; void domouse(); extern int Debug; extern event_proc(); static int boty = 32767, /* screen bottom y */ botx = 0, /* screen bottom x */ topx = 32767, /* screen top x */ topy = 0, /* screen top y */ oboty = 0, /* user's bottom y */ obotx = 0, /* user's bottom x */ otopy = 32767, /* user's top y */ otopx = 32767; /* user's top x */ static double scx = 1.0, /* scale factor x */ scy = 1.0 /* scale factor y */ ; static int lastx = 0; static int lasty = 0; static int lmode = 3; /* drawing mode (default is xor)*/ int Prevlmode = 3; #define signof(x) ((x)>=0.0?(1):(-1)) #define absof(x) ((x)>=0.0?(x):(-x)) void flushout() { } short bsy_pixrect_data[] = { /* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 */ 0x7FFE,0x4002,0x200C,0x1A38,0x0FF0,0x07E0,0x03C0,0x0180, 0x0180,0x0240,0x0520,0x0810,0x1108,0x23C4,0x47E2,0x7FFE }; mpr_static(busy_pixrect, 16, 16, 1, bsy_pixrect_data); int childpid; Rect sweeparect(); om_open() { Rect r; r = sweeparect(); notify_errno = NOTIFY_OK; Mainframe = window_create((Window)NULL, FRAME, FRAME_LABEL, "ocr", 0 ); Win = window_create(Mainframe, CANVAS, 0); Pw = canvas_pixwin(Win); window_set(Mainframe, WIN_X, r.r_left, WIN_Y, r.r_top, 0); window_set(Win, WIN_WIDTH, r.r_width, WIN_HEIGHT, r.r_height, 0); window_fit(Win); window_fit(Mainframe); window_set(Mainframe, WIN_SHOW, TRUE, 0); Winfd = (int) window_get(Win, WIN_FD); if ( notify_errno != NOTIFY_OK ) { notify_perror("ocr"); exit(1); } setcolormap(); set_color(DEFAULTCOLOR); linemod("solid"); window_set(Win, WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS, WIN_ASCII_EVENTS, WIN_MOUSE_BUTTONS, LOC_MOVE, /* LOC_DRAG, */ LOC_WINEXIT, LOC_WINENTER, LOC_RGNEXIT, LOC_RGNENTER, 0, 0); window_set(Win, WIN_EVENT_PROC, event_proc, 0); space(0,0,M_WID,M_HGT); interact(); } /***********************************************************/ /* The code below was taken from the 'dumpregion' program. */ /***********************************************************/ /* * Copyright Richard Tobin 1987. You may freely copy, modify and distribute * this program in source form provided this comment remains intact. * * Richard Tobin, JANET: R.Tobin@uk.ac.ed * AI Applications Institute, ARPA: R.Tobin%uk.ac.ed@nss.cs.ucl.ac.uk * Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin */ #include <sys/file.h> #include <suntool/fullscreen.h> short nwdata[] = { #include </usr/include/images/stretchNW.cursor> }; mpr_static(nwpixrect, 16, 16, 1, nwdata); short sedata[] = { #include </usr/include/images/stretchSE.cursor> }; mpr_static(sepixrect, 16, 16, 1, sedata); Rect rect = {0,0,0,0}; Rect sweeparect() { int wfd, n; struct fullscreen *fs; Event event; Pixwin *pw; int left, right, top, bottom, temp; Window win; double w; Rect r; win = window_create(0, FRAME, FRAME_OPEN_RECT, &rect, WIN_CONSUME_PICK_EVENTS, WIN_ASCII_EVENTS, LOC_MOVE, WIN_MOUSE_BUTTONS, 0, 0); wfd = (int)window_get(win, WIN_FD); fs = fullscreen_init(wfd); pw = fs->fs_pixwin; window_set(win, WIN_CURSOR, cursor_create(CURSOR_IMAGE, &nwpixrect, CURSOR_XHOT, 0, CURSOR_YHOT, 0, 0), 0); for ( ;; ) { n = window_read_event(win, &event); if ( n < 0 ) continue; if ( event_is_ascii(&event) ) { if ( event_id(&event) == 'F' ) { r.r_left = 10; r.r_top = 10; r.r_width = 900; r.r_height = 900; } else { r.r_left = 542; r.r_top = 0; r.r_width = 540; r.r_height = 512; } goto getout; } if ( event_is_down(&event) && event_is_button(&event) ) break; } right = left = event_x(&event); bottom = top = event_y(&event); window_set(win, WIN_CURSOR, cursor_create(CURSOR_IMAGE, &sepixrect, CURSOR_XHOT, 15, CURSOR_YHOT, 15, 0), 0); drawbox(pw, left, top, right, bottom); while(window_read_event(win, &event) == -1 || !event_is_up(&event) || !event_is_button(&event)) { drawbox(pw, left, top, right, bottom); right = event_x(&event); bottom = event_y(&event); drawbox(pw, left, top, right, bottom); } drawbox(pw, left, top, right, bottom); if(right < left) { temp = right; right = left; left = temp; } if(bottom < top) { temp = bottom; bottom = top; top = temp; } r.r_left = left; r.r_top = top; r.r_width = (right-left); r.r_height = (bottom-top); getout: fullscreen_destroy(fs); window_set(win, FRAME_NO_CONFIRM, TRUE, 0); window_destroy(win); return r; } drawbox(pw, left, top, right, bottom) Pixwin *pw; int left, top, right, bottom; { fullscreen_pw_vector(pw, left, top, right, top, PIX_NOT(PIX_DST), 0); fullscreen_pw_vector(pw, right, top, right, bottom, PIX_NOT(PIX_DST), 0); fullscreen_pw_vector(pw, right, bottom, left, bottom, PIX_NOT(PIX_DST), 0); fullscreen_pw_vector(pw, left, bottom, left, top, PIX_NOT(PIX_DST), 0); } ttygets(buff,len) char *buff; { int x, y, n, key; char *p = buff; for ( n=0; n<(len-1); n++ ) { while ( (key=mouseorkey(&x,&y)) < 0 ) ; if ( key == '\r' ) /* just in case */ key = '\n'; *p++ = key; if ( key == '\n' || key == '\0' ) break; } *p++ = '\0'; } int mouseorkey(x,y) int* x; int* y; { Event anevent; char c; int n; Key = -1; notify_do_dispatch(); n = read(0,&c,1); notify_no_dispatch(); if ( n == 1 ) { /* character was typed in text (original) window */ /* ie. stdin */ Key = c; *x = Mousex; *y = Mousey; xyunscale(x,y); } else if ( Key >= 0 ) { /* character was typed in graphics window */ /* so it must be echoed. */ putchar(Key); if ( Key == '\r' ) putchar('\n'); fflush(stdout); *x = Mousex; *y = Mousey; xyunscale(x,y); } return(Key); } interact() { (void) notify_dispatch(); } setcolormap() { u_char red[CMAPSIZE], green[CMAPSIZE], blue[CMAPSIZE]; int n; for(n=0;n<CMAPSIZE;n++) { red[n] = mycolors[n][0]; green[n] = mycolors[n][1]; blue[n] = mycolors[n][2]; } pw_setcmsname(Pw,"showcolor"); pw_putcolormap(Pw, 0, CMAPSIZE, red, green, blue); } /*ARGSUSED*/ wait_proc(window,event,arg) Window window; Event *event; caddr_t arg; { int id = event_id(event); if ( event_is_ascii(event) && id == 'q' ) notify_stop(0); } om_close() { window_set(Win, WIN_EVENT_PROC, wait_proc, 0); if ( fork() == 0 ) { close(0); close(1); close(2); /* This stuff doesn't seem to work. I'm trying to */ /* get the window to be able to repaint itself when */ /* uncovered. */ sleep(1); window_main_loop(Mainframe); exit(0); } } space(x0,y0,x1,y1) int x0, y0, x1, y1; { int tx, ty; obotx = x0; oboty = y0; otopx = x1; otopy = y1; boty = 0; botx = 0; tx = (int) window_get(Win,WIN_WIDTH); ty = (int) window_get(Win,WIN_HEIGHT); topx = tx; topy = ty; scx = (double)(topx-botx)/(otopx-obotx); scy = (double)(topy-boty)/(otopy-oboty); } #ifdef OLDSTUFF xyscale(x, y) int *x, *y; { *x = (*x-obotx)*scx+botx; *y = (*y-oboty)*scy+boty; } #endif xyunscale(x, y) int *x, *y; { /* map from device coordinates to space() coordinates */ *x = ( (*x - botx)/scx + obotx ); *y = ( (*y - boty)/scy + oboty ); } wline(x1,y1,x2,y2) int x1, y1, x2, y2; { lastx = x2; lasty = y2; XYSCALE(x1, y1); XYSCALE(x2, y2); arawline(x1,y1,x2,y2); } wrect(x1,y1,x2,y2) int x1, y1, x2, y2; { lastx = x2; lasty = y2; XYSCALE(x1, y1); XYSCALE(x2, y2); arawbox(x1,y1,x2,y2); } arawbox(x1,y1,x2,y2) int x1, y1, x2, y2; { arawline(x1,y1,x2,y1); arawline(x2,y1,x2,y2); arawline(x2,y2,x1,y2); arawline(x1,y2,x1,y1); } arawline(x1,y1,x2,y2) int x1, y1, x2, y2; { int op, col; currentopcol(&op,&col); /* fprintf(stderr,"calling pw_vector, %d,%d %d,%d currentop=%d Colorval=%d Pw=%ld\n",x1,y1,x2,y2,op,col,Pw); */ pw_vector(Pw, (int)x1,(int)y1, (int)x2,(int)y2, op, col); interact(); } currentopcol(aop,acol) int *aop, *acol; { if ( lmode == 1 && Colorval == S_WHITE ) { *aop = (PIX_NOT(PIX_SRC) & PIX_DST); *acol = S_BLACK; } else { *acol = Colorval; switch (lmode) { case 0: *aop = (PIX_NOT(PIX_SRC) & PIX_DST); break; case 1: case 2: /* *aop = (PIX_SRC | PIX_DST); */ *aop = PIX_SRC; break; case 3: *aop = (PIX_SRC ^ PIX_DST); break; default: *aop = (PIX_SRC | PIX_DST); break; } } } wt(s,scl,left,top,right,bot) char *s; { int op, col; /* fprintf(stderr,"wt() called, s=%s lastxy=%d,%d scl=%d left-top=%d,%d\n", s,left,top,scl,left,top); */ currentopcol(&op,&col); XYSCALE(left, top); pw_ttext(Pw,(int)left,(int)top,op,NULL,s); } Sp * set_font(n) { static Sp chsz; struct pr_size prs; int x, y; prs = pf_textwidth(1,pf_default(),"x"); x = prs.x; y = prs.y; xyunscale(&x,&y); chsz.x = ++x; chsz.y = y; return &chsz; } #ifdef OLDSTUFF textwidth(s) { struct pr_size prs; prs = pf_textwidth(bound,strlen(s),pf_default(),s); prs = pf_textwidth(1,pf_default(),"x"); *ax = prs.x; *ay = prs.y; xyunscale(ax,ay); } #endif amove(x,y) int x,y; { lastx = x; lasty = y; } cont(x,y) int x,y; { wline(lastx,lasty,x,y); /* last[xy] are then updated by line */ } set_color(n) int n; { switch(n){ case M_WHITE: n = S_WHITE; break; case M_PALE_GREY: case M_GREY_7: n = S_GREY; break; case M_BLACK: n = S_BLACK; break; case M_YELLOW_13: case M_YELLOW_11: n = S_YELLOW; break; case M_MAGENTA: case M_CYAN: case M_CYAN_14: n = S_AQUA; break; case M_GREEN: case M_GREEN_7: n = S_GREEN; break; case M_BLUE: n = S_BLUE; break; case M_RED: n = S_RED; break; default: fprintf(stderr,"Unknown color in set_color (%d)\n",n); n = S_WHITE; break; } Colorval = n; /* fprintf(stderr,"set_color = (sun#) %d\n",n); */ } linemod(s) char *s; { if ( strcmp(s,"erase")==0 ) lmode = 0; else if ( strcmp(s,"dotted")==0 || strcmp(s,"hilight")==0 ) lmode = 2; else if ( strcmp(s,"xor")==0 ) lmode = 3; else { /* everything, including "solid" defaults to this */ lmode = 1; } } aerase() { pw_writebackground(Pw,0,0,(int)topx,(int)topy,PIX_SRC); } wfrect(x1,y1,x2,y2) int x1, y1, x2, y2; { int op, col; int t; XYSCALE(x1, y1); XYSCALE(x2, y2); currentopcol(&op,&col); if ( x1 > x2 ) { t = x1; x1 = x2; x2 = t; } if ( y1 > y2 ) { t = y1; y1 = y2; y2 = t; } /* fprintf(stderr,"wfrect(%d,%d to %d,%d lmode=%d op=%d col=%d)\n", x1,y1,x2,y2,lmode,op,col); */ for ( t=y1; t<=y2; t++ ) { pw_vector(Pw, x1,t, x2,t, op, col); } interact(); } /*ARGSUSED*/ event_proc(window,event,arg) Window window; Event *event; caddr_t arg; { int id = event_id(event); if ( event_is_ascii(event) ) { Key = id; notify_stop(0); return; } } /* trim a Metheus X coordinate to fit on screen */ int M_trimX(x) int x; { if(x<0) return(0); else if(x>(topx-1)) return((topx-1)); return(x); } /* trim a Metheus Y coordinate to fit on screen */ int M_trimY(y) int y; { if(y<0) return(0); else if(y>(topy-1)) return((topy-1)); return(y); } /* show Sp (Metheus coordinates) on Metheus, enlarged to a `dot'-sided square */ sh_Mp(mpp,dot) Sp *mpp; int dot; { int half_dot; if(dot==1) wfrect(mpp->x,mpp->y,mpp->x,mpp->y); else { half_dot=dot/2; if((dot%2)==0) wfrect( M_trimX(mpp->x-half_dot+1), M_trimY(mpp->y-half_dot+1), M_trimX(mpp->x+half_dot), M_trimY(mpp->y+half_dot) ); else wfrect( M_trimX(mpp->x-half_dot), M_trimY(mpp->y-half_dot), M_trimX(mpp->x+half_dot), M_trimY(mpp->y+half_dot) ); }; } om_force(){} /* write "thick" line, two pixels wide */ wtline(x1,y1,x2,y2) { int absdx, absdy; wline(x1,y1,x2,y2); absdx = (x1-x2)>=0 ? x1-x2 : x2-x1; absdy = (y1-y2)>=0 ? y1-y2 : y2-y1; if(absdx>absdy) /* more horizontal -- thicken vertically */ wline(x1,M_trimY(y1+1),x2,M_trimY(y2+1)); else /* more vertical -- thicken horizontally */ wline(M_trimX(x1+1),y1,M_trimX(x2+1),y2); } /* write "fat" line, three pixels wide */ wfline(x1,y1,x2,y2) { register int absdx, absdy; wline(x1,y1,x2,y2); absdx = (x1-x2)>=0 ? x1-x2 : x2-x1; absdy = (y1-y2)>=0 ? y1-y2 : y2-y1; if(absdx>absdy) { /* more horizontal -- thicken vertically */ wline(x1,M_trimY(y1+1),x2,M_trimY(y2+1)); wline(x1,M_trimY(y1-1),x2,M_trimY(y2-1)); } else { /* more vertical -- thicken horizontally */ wline(M_trimX(x1+1),y1,M_trimX(x2+1),y2); wline(M_trimX(x1-1),y1,M_trimX(x2-1),y2); }; } om_wrpix() { printf("om_wrpix called\n"); } om_buffer(n) { } rreset() { } 0707070035351136761006640007620000050000011476070476773366200001100000004314makefile # for all OS -- OPT = -O PROF = -p PI = -g PRODUCTION = $(OPT) DEBUG = $(PROF) $(PI) # -- for UNIX 9th Ed -- CFLAGS = $(PRODUCTION) LIBS = -lY3610 -lY PORTLIB = -lport LDFLAGS = F77LIBS = $(LIBS) MLIB = REGEX = FTW = METLIB = mlib.o RASTLIB = POSTLIB = GRAPHICLIBS = # -- For Sun OS 4.x -- ##GRAPHICLIBS = -lsuntool -lsunwindow -lpixrect ##MLIB = -lm ##LIBS = $(GRAPHICLIBS) $(MLIB) ##PORTLIB = /usr/lib/libport3.a ##F77LIBS = -lF77 -lI77 -lc $(MLIB) $(GRAPHICLIBS) ##REGEX = regexec.o regcomp.o regerror.o ##FTW = myftw.o ##LDFLAGS = $(PROF) -fswitch ##CFLAGS = $(PROF) -fswitch -Bstatic ##METLIB = sunlib.o ##RASTLIB = rastlib.o ##POSTLIB = postlib.o all: bcp touch bcp clean: rm -rf *.[cho15] bcp bcp.cpio *.srcs makefile # the next three targets are for use in 1127 software distribution on bowell install: /usr/bin/bcp cp bcp.1 /usr/man/man1 /usr/bin/bcp: bcp strip bcp cp bcp /usr/bin ship: /usr/bin/bcp ship /usr/bin/bcp # If you want to use UNIX FILE_TREEs: Path.o: Path.c CPU.h myftw.h Path.h cc $(CFLAGS) -c Path.c FTREE=Path.o # If you DON'T want to use FILE_TREEs: ##FTREE= bcp: bcp.o CCITT.o rlelib.o riclib.o Coord.o piclib.o jslr.o Text.o $(FTREE) $(POSTLIB) $(RASTLIB) cc $(CFLAGS) bcp.o CCITT.o rlelib.o riclib.o Coord.o piclib.o jslr.o Text.o $(FTREE) $(POSTLIB) $(RASTLIB) $(MLIB) $(GRAPHICLIBS) -o bcp bcp.o: bcp.c CPU.h stdocr.h rle.h CCITT.h bitio.h pic.h Path.h Bitmap.h Text.h abort.h cc $(CFLAGS) $(MLIB) $(GRAPHICLIBS) -c bcp.c stdocr.h: boole.h limits.h Units.h ric.h fioi.h touch stdocr.h CCITT.o: CCITT.c CPU.h stdocr.h rle.h Bitmap.h CCITT.h bitio.h cc $(CFLAGS) -c CCITT.c rlelib.o: rlelib.c CPU.h stdocr.h rle.h ric.h cc $(CFLAGS) -c rlelib.c riclib.o: riclib.c CPU.h stdocr.h cc $(CFLAGS) -c riclib.c Coord.o: Coord.c CPU.h boole.h Units.h Coord.h cc $(CFLAGS) -c Coord.c Text.o: Text.c font.h Bfeats.h stdocr.h cc $(CFLAGS) -c Text.c piclib.o: piclib.c CPU.h boole.h limits.h Units.h Coord.h pic.h cc $(CFLAGS) -c piclib.c jslr.o: jslr.c cc $(CFLAGS) -c jslr.c rastlib.o: rastlib.c cc $(CFLAGS) $(MLIB) $(GRAPHICLIBS) -c rastlib.c postlib.o: postlib.c cc $(CFLAGS) -c postlib.c sunlib.o: sunlib.c cc $(CFLAGS) -c sunlib.c myftw.o: myftw.c myftw.h cc $(CFLAGS) -c myftw.c 0707070035350335411006640007620000050000010556240457561704600000700000001365README Copy bcp.cpio.z into an empty directory, cd there, and... unpack bcp.cpio.z cpio -ic <bcp.cpio If your cpu is not a VAX or your OS is not research UNIX: edit CPU.h to specify SUN, CRAY, 3B, etc (and specify OS too) edit makefile to enable SUN, CRAY, 3B, etc compilation options Next, defeat the UNIX file-tree code (later, you may decide you want this; but it seldom ports easily), by taking these steps: 1) in CPU.h, change this line to: #define FILE_TREE 0 2) in makefile, remove all references to Path.c Path.o (this is spelled out in the comments). Then say: make and hope for the best, which is a working `bcp'. Bcp.1 and picfile.5 are man pages; print them using `troff -man'. More detailed documentation can be found in source bcp.c. 0707070035351136771006640007620000050000011476110476773366300000600000011432bcp.1 .TH BCP 1 .CT 1 graphics .SH NAME bcp \(mi reformat black-and-white picture files .SH SYNOPSIS .B bcp [ .I option ... ] [ .I file1 [ .I file2 ] ] .SH DESCRIPTION .I Bcp copies black-and-white (B&W) image .I file1 to .I file2, optionally changing the file format and transforming the image. If .I file1 is a directory name, then every leaf of its file tree is processed in turn; and, in this case, if .I file2 also is specified, it is made the root directory of an isomorphic tree of output files. If .I file2 is not specified, all output is catenated to stdout. .PP .I Bcp can copy among all the B&W .IR picfile (5) formats, and some others. The default output format is .BR TYPE=ccitt-g4 . Image transformations include trimming, translation, scaling, and rotation, performed in that order (not in argument order). .PP Input files in .IR picfile (5) format must begin with an ASCII .BI TYPE= type header line. .I Types supported both as input and output are: .nr xx \w'\fLccitt-g4\ ' .TP \n(xxu .B dump One byte/pixel. .B NCHAN=1 is required. On input, the grey pixel values are thresholded to B&W; see option .BR -T . On output, black becomes 0 and white 255. .TP .B bitmap One bit/pixel. Essentially Sun rasterfile format, with a .IR picfile (5) header replacing the Sun binary header. .TP .B ccitt-g4 CCITT Group 4 FAX encoding, strongly compressive on printed text. Also, .B ccitt-g31 (Group 3, 1-dim) and .B ccitt-g32 (Group 3, 2-dim; see .BR -k ). .LP Other supported .I types are: .TP \n(xxu .B binary One bit/pixel encoding; obsolescent, but needed for old image archives. Both input and output. .TP .B rle Fast run-length encoding; obsolescent, but needed for old image archives. Input or output, but not both. .TP .B pico Same as .BR dump . Input only. .TP .B cdf `Compound document format', used in AT&T FAX Connection product. Input only. Only the first of multiple pages is read. .LP Other formats not using a .BI TYPE= type header, are: .IR bitfile (9.5) format; PostScript bitmap format (output only); and Sun rasterfile format (with the Sun binary header; output only). .PP The options are: .TP \n(xxu .B -B[io] Read/write .IR bitfile (9.5) format (no .BI TYPE= type header). .TP .B -M Write .B TYPE=bitmap format. .TP .B -P Write Postscript bitmap format (Suns only). .TP .BI -R x , y Force output resolutions to .I x,y (pixels/inch). If .BI , y is missing, it is taken to be the same as .I x. Overrides .BI -x x , y . Requires a .BI RES= "x y line in the header (but, see .BR -Z ). .TP .B -R= Force the output resolution to be equal to the greater of the input resolutions. .TP .B -S Write Sun rasterfile format (no .BI TYPE= type header; on Suns only). .TP .BI -T t Threshold. When reading .BR TYPE=dump , assign black to grey levels less than .I t, and white to others. Default: .BR -T128 . .TP .BI -Z x , y Force input .BI RES= "x y. .TP .B -b Write .B TYPE=binary format. .TP .B -g4 .br .ns .TP .B -4 Write .B TYPE=ccitt-g4 format. Similarly, .B -g31 or .B -31 and .B -g32 or .BR -32 . .TP .BI -k n Set the `k' for .B ccitt-g32 encoding on output (default .BR -k4 ). .TP .BI -o x , y Offset (translate) the image by .I x,y pixels. The width and height of the picture are not changed. .TP .B -p Write .B TYPE=dump NCHAN=1 format. Map black to 0, white to 255. .TP .B -r Write .B TYPE=rle format. .TP .B -tl Rotate the image to bring the left edge of the page to the top. Set top-left corner of the rotated image at the top-left corner of the image. .TP .BI -t d Rotate the image .I d degrees counterclockwise about its center. .I d is a real number. .TP .BI -w l,t,r,b Specify window (trim the image): .I l,t is the left-top corner and .I r,b the right-bottom corner measured in pixels. If the new margins are outside the original picture, the new area is set to white. An argument given as .L % leaves the edge unchanged. .TP .BI -x x , y Expand/contract (scale) the image, by real factors .I x and .I y. If .BI , y is missing, .I y is taken to be the same as .I x. May be overridden by .BI -R x , y. Requires a .BI RES= "x y line in the header (but, see .BR -Z ). .SH SEE ALSO .IR cscan (1), .IR imscan (1), .IR ocr (1), .IR pico (1), .IR picfile (5) .br CCITT facsimile coding standards Rec. T.4(1988) and T.6(1988). .SH BUGS Concatenated pages are supported, but only if each new page has a complete header. .br Scaling is accomplished by naive replication/deletion of pixels. .br Rotation by small angles exhibits aliasing effects, and is slow. .br Rotations .B -tr and .B -tb are unfinished. .br CCITT FAX `uncompressed' (or, `transparent') mode is not implemented. .br Postscript output is useful only for small images. .br .BI WINDOW= "l t r b where .I l or .I t is non-zero may not be handled correctly for every combination of file types. .br .B TYPE=rle can't be both input and output. .br Should be merged with T. Duff's .I pcp. 0707070035351137001006640007620000050000010260120476773366300001200000006503picfile.5 .TH PICFILE 5 .CT 1 inst_info graphics .SH NAME picfile \- raster graphic image format .SH DESCRIPTION Files in this format store images represented as two-dimensional arrays of multiple-channel pixels. A .I picfile consists of an .SM ASCII header followed by binary data encoding the pixels in row-major order. The header is a list of attribute/value pairs separated by newlines, terminated by an empty line. Each header line has the form .IB name = value. The name may not contain an .SM ASCII NUL, newline or .LR = ; the value may not contain null or newline. The last line of a header is empty. .PP The standard attributes are described below; all but .BR TYPE and .BR WINDOW are optional. .B TYPE must come first; otherwise order is irrelevant. As any unrecognised attribute is passed over uninterpreted by all standard software, applications are welcome to include arbitrary annotations, like .BR SHOESIZE=10 , if they wish. .TP .BI TYPE= type How the pixels are encoded. Standard types are .PD 0 .RS .TF runcode .TP .B runcode A run-length encoding. The data are a sequence of .RI ( nchan +1)-byte records each containing a count .I k and .I nchan bytes giving a pixel value to be repeated .IR k +1 times. A run may not span scanlines. .TP .B dump A two-dimensional array of .IR nchan -byte records in row major order. .TP .B bitmap One-bit pixels, packed into bytes high bit leftmost. Zero bits are white, one bits are black. Rows are padded with zeros to a multiple of 16 bits. .TP .B ccitt-g4 A black-and-white image under CCITT FAX Group 4 compression. This format is highly compressive on images of text and line art. Similarly, .L ccitt-g31 and .L ccitt-g32 for Group 3, 1-D and 2-D. .TP .B pico A sequence of .I nchan two-dimensional arrays of single bytes. .TP .B ccir601 Pixels are in dump order, 2 bytes per pixel encoded according to the IEEE digital component video standard. .RE .TP .BI WINDOW= "x0 y0 x1 y1 The .I x,y coordinates of the upper left corner and the point just diagonally outside the lower right corner, .I x increasing to the right, .I y down. .TP .BI NCHAN= nchan The number of channels, default 1. .TP .BI CHAN= value The order of channels. .TP .BI RES= "x y The digitizing resolution horizontally and vertically, in pixels/inch. .PD .TP .B CMAP= (The value is empty.) A color map, a 256\(mu3-byte translation table for color values, follows the header. In a full-color picture, each color-map row maps pixel values of the corresponding channel. In a monochrome picture, pixel values index the color map to yield red, green and blue, like this: .IP .EX unsigned char cmap[256][3]; red=cmap[pixel][0]; green=cmap[pixel][1]; blue=cmap[pixel][2]; .EE .SH EXAMPLES .TP .B sed '/^$/q' image Print a header. A sample header follows. .LP .EX TYPE=dump WINDOW=0 0 512 512 NCHAN=1 CHAN=m RES=300 300 CMAP= COMMAND= antiquantize 'halftone CLASSIC' 512.halftone LIBERTY.anticlassic COMMAND= halftone CLASSIC 512.liberty 512.halftone 1.75 512.halftone COMMAND= transpose IN OUT COMMAND= resample 512 IN OUT COMMAND= transpose IN OUT COMMAND= resample 512 IN OUT COMMAND= clip 400 400 LIBERTY OUT .EE .SH "SEE ALSO" .IR bcp (1), .IR cscan (1), .IR imscan (1), .IR pico (1), .IR flicks (9.1), .IR mugs in .IR face (9.7), .IR rebecca (9.1), .IR flickfile (9.5) .br T. Duff, `The 10th Edition Raster Graphics System', this manual, Volume\ 2 0707070035351137001006640007620000050000010260120476773366300001300000000000TRAILER!!! , .IR flickfile (9.5) .br T. Duff, `The 10th Edition Raster Graphics System', this manual, Volume\ 2 0707070035351137001006640007620000050000010260120476773366300001300000000000TRAILER!!! , .IR flickfile (9.5) .br T. Duff, `The 10th Edition Raster Graphics System', this manual, Volume\ 2 07070700353511370010066400076200000