/*
* Usage: rez2else [-rezfile name] [-output name] [-format type]
* [-continents list] [-types list]
* [-ascii type] [-verbose] [-silent]
* where format type is one of NONE (default), TEXT, JPD
* and TXT ascii type is one of DXDY (default), INT, REAL
*
*/
#include <endian.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
#if __BYTE_ORDER == __BIG_ENDIAN
#define WORDS_BIGENDIAN
#endif
#ifdef ZLIB
#include <zlib.h>
#endif
#define BIT32 int
#define BIT16 short
#ifdef WORDS_BIGENDIAN
void bitflip (BIT32 *x) {
BIT32 y=0;
y |= 0xFF000000 & ((0x000000FF & *x) << 24);
y |= 0x00FF0000 & ((0x0000FF00 & *x) << 8);
y |= 0x0000FF00 & ((0x00FF0000 & *x) >> 8);
y |= 0x000000FF & ((0xFF000000 & *x) >> 24);
*x = y;
}
#endif /* WORDS_BIGENDIAN */
#define DEFAULT_REZ_FILE "/usr/share/rmap/CIA_map.rez"
#define MAXSTROKES 6000000
/* conservative upper estimate */
#define REZ_TOTALSEG 31844
/* number of segments in WDB is really 31845, but one river showing up in
Uganda is faulty and must be deleted ! */
#define SHORTFLAG 0x4000
#define REZ_MAGIC 0x86460346
#define JPD_MAGIC "!JPD1.0\n"
#define DEBUG 1
enum { AFRICA=0, ASIA, EUROPE, NAMERICA, SAMERICA };
enum { BDY=0, PBY, RIV, CIL };
enum {NONE=0, TEXT, JPD };
enum {DX_DY=0, INT, REAL};
struct header
{
BIT32 magic;
BIT32 segment_index_address;
BIT32 segment_index_count;
};
struct segment_index
{
BIT32 maxlat;
BIT32 minlat;
BIT32 maxlong;
BIT32 minlong;
BIT32 segment_address;
BIT32 continent;
BIT32 category;
BIT32 type;
};
struct segment_header
{
BIT32 orgx;
BIT32 orgy;
BIT32 nstrokes;
};
struct stroke
{
BIT32 dx;
BIT32 dy;
};
char *cont_name[] = { "Africa", "Asia", "Europe", "North America",
"South America" };
char *type_name[] = { "int", "nat", "riv", "cil" };
int jpd2rez_type_code[4] = { 2, 0, 1, 3 };
void fpr2(FILE * f, BIT32 n)
{
fprintf(f, "%c%c", n&255, (n>>8)&255);
}
void fpr3(FILE * f, BIT32 n)
{
fprintf(f, "%c%c%c", n&255, (n>>8)&255, (n>>16)&255);
}
void fpr4(FILE * f, BIT32 n)
{
fprintf(f, "%c%c%c%c", n&255, (n>>8)&255, (n>>16)&255, n>>24);
}
void usage()
{
fprintf(stderr,
"Usage: rez2else [-rezfile name] [-output name] [-format type]\n"
" [-continents list] [-types list]\n"
" [-ascii type] [-verbose] [-silent]\n"
"where format type is one of NONE (default), TEXT, JPD,\n"
"and TEXT ascii type is one of DXDY (default), INT, REAL\n\n");
exit(-1);
}
int main (argc, argv)
int argc;
char **argv;
{
#ifdef ZLIB
gzFile *ff;
#else
int ff;
#endif
FILE *fd;
char *rez_file = NULL;
char *list_cont=NULL, *list_types=NULL;
int u, v, up, vp, w, i, j, k;
int dm, quot, xp, yp, xt, yt, s;
int format, numseg, rejected, verbose;
int rez_length, jpd_length, rez_total_strokes;
int maxwidth, maxheight;
int text_output_type, count, addr;
char magic[20], dx[MAXSTROKES], dy[MAXSTROKES];
/* +10 just to be safe */
int rez_nstrokes[REZ_TOTALSEG+10],
rez_orgx[REZ_TOTALSEG+10], rez_orgy[REZ_TOTALSEG+10];
int jpd_count[REZ_TOTALSEG+10];
char * output;
struct segment_index * segment_index_data = NULL;
struct header header_data;
struct segment_header segment_header_data;
struct stroke stroke_data;
#define U -1
char targets[4][20];
int jpd_encod[4][16] = {
{ U, 0, 1, 2, U, U, U, U, U, U, U, U, U, U, U, U }, /* int 2^2 */
{ U, 3, U, 4, U, U, U, U, U, U, U, U, U, U, U, U }, /* nat 2^0 */
{ U, 5, 6, 7, 8, 9, 10, 11, 12, U, 13, 14, U, 15, U, U }, /* riv 2^1 */
{ U, 16, 17, 18, 19, U, 20, 21, 22, 23, 24, U, U, 25, 26, 27 }/* cil 2^3 */
};
int jpd_min[4] = { 0, 3, 5, 16 };
int jpd_max[4] = { 2, 4, 15, 27 };
int jpd_seg_count[5][28];
format = TEXT;
text_output_type = DX_DY;
verbose = 1;
for (j=1; j<argc; j++) {
if (j<argc-1 && !strcmp(argv[j],"-rezfile"))
rez_file = (char *)strdup(argv[++j]);
else
if (j<argc-1 && !strcmp(argv[j],"-output"))
output = (char *)strdup(argv[++j]);
else
if (j<argc-1 && !strcmp(argv[j], "-format")) {
++j;
if (!strcasecmp(argv[j], "none")) format = NONE;
if (!strcasecmp(argv[j], "text")) format = TEXT;
if (!strcasecmp(argv[j], "jpd")) format = JPD;
}
else
if (j<argc-1 && !strcmp(argv[j], "-ascii")) {
++j;
if (!strcasecmp(argv[j], "dxdy")) text_output_type = DX_DY;
if (!strcasecmp(argv[j], "int")) text_output_type = INT;
if (!strcasecmp(argv[j], "real")) text_output_type = REAL;
}
else
if (j<argc-1 && !strcmp(argv[j], "-continents")) {
++j;
list_cont = strdup(argv[j]);
}
else
if (j<argc-1 && !strcmp(argv[j], "-types")) {
++j;
list_types = strdup(argv[j]);
}
else
if (!strcmp(argv[j], "-verbose")) verbose = 1;
else
if (!strcmp(argv[j], "-silent")) verbose = 0;
else
usage();
}
if (!output) {
fprintf(stderr,
"No -output specified, using stdout as default\n\n");
fd = stdout;
} else
fd = fopen(output, "w");
numseg = 0;
rez_length = 0;
rez_total_strokes = 0;
jpd_length = 0;
maxwidth = 0;
maxheight = 0;
rejected = 0;
for (v=0; v<4; v++)
sprintf(targets[v], "000000000000000000");
if (!rez_file) {
fprintf(stderr, "No input REZ file has been specified\n"
"Trying default %s\n\n", DEFAULT_REZ_FILE);
rez_file = DEFAULT_REZ_FILE;
}
#ifdef ZLIB
ff = gzopen(rez_file, "r");
if (!ff) {
fprintf(stderr, "Cannot open REZ file %s !!\n", rez_file);
exit(-1);
}
#else
ff = open(rez_file, O_RDONLY, 0);
if (ff==-1) {
fprintf(stderr, "Cannot open REZ file %s !!\n", rez_file);
exit(-1);
}
#endif
for (u=0; u<5; u++)
for (w=0; w<28; w++)
jpd_seg_count[u][w] = 0;
#ifdef ZLIB
gzread(ff, &header_data, sizeof(header_data));
#else
read(ff, &header_data, sizeof(header_data));
#endif
#ifdef WORDS_BIGENDIAN
bitflip( &(header_data.magic) );
bitflip( &(header_data.segment_index_address) );
bitflip( &(header_data.segment_index_count) );
#endif /* WORDS_BIGENDIAN */
if (header_data.magic != REZ_MAGIC) {
fprintf(stderr, "File %s has wrong magic number %X\n"
"instead of %X . Aborting !!\n",
rez_file, header_data.magic, REZ_MAGIC);
exit(-2);
}
segment_index_data = (struct segment_index *)
malloc(header_data.segment_index_count*sizeof(struct segment_index));
for (i=0; i<header_data.segment_index_count; i++) {
#ifdef ZLIB
gzseek(ff, sizeof(header_data) + sizeof(struct segment_index)*i,
SEEK_SET);
gzread(ff, &segment_index_data[i], sizeof(struct segment_index));
#else
lseek(ff, sizeof(header_data) + sizeof(struct segment_index)*i,
SEEK_SET);
read(ff, &segment_index_data[i], sizeof(struct segment_index));
#endif
#ifdef WORDS_BIGENDIAN
bitflip( &(segment_index_data[i].maxlat) );
bitflip( &(segment_index_data[i].minlat) );
bitflip( &(segment_index_data[i].maxlong) );
bitflip( &(segment_index_data[i].minlong) );
bitflip( &(segment_index_data[i].segment_address) );
bitflip( &(segment_index_data[i].continent) );
bitflip( &(segment_index_data[i].category) );
bitflip( &(segment_index_data[i].type) );
#endif /* WORDS_BIGENDIAN */
xp = segment_index_data[i].maxlong-segment_index_data[i].minlong;
yp = segment_index_data[i].maxlat-segment_index_data[i].minlat;
if (xp>maxwidth) maxwidth = xp;
if (yp>maxheight) maxheight = yp;
}
count = 0;
jpd_count[0] = 0;
for (i=0; i<header_data.segment_index_count; i++) {
/*
* Awful work-around for bug in chunk 3532 in CIA_map.rez !!
* associated address is 7554516, and nstrokes = 410
* point j=38 obviously wrong, maybe orgx, orgy as well
*/
if (i == 3532) {
segment_index_data[i].continent = -1;
jpd_count[i+1] = jpd_count[i];
++rejected;
continue;
}
++numseg;
#ifdef ZLIB
gzseek(ff, segment_index_data[i].segment_address, SEEK_SET);
gzread(ff, &segment_header_data, sizeof(struct segment_header));
#else
lseek(ff, segment_index_data[i].segment_address, SEEK_SET);
read(ff, &segment_header_data, sizeof(struct segment_header));
#endif
#ifdef WORDS_BIGENDIAN
bitflip( &(segment_header_data.orgx) );
bitflip( &(segment_header_data.orgy) );
bitflip( &(segment_header_data.nstrokes) );
#endif /* WORDS_BIGENDIAN */
rez_orgx[i] = segment_header_data.orgx;
rez_orgy[i] = segment_header_data.orgy;
rez_nstrokes[i] = segment_header_data.nstrokes;
rez_total_strokes += segment_header_data.nstrokes;
for (j=0; j<segment_header_data.nstrokes; j++) {
#ifdef ZLIB
gzread(ff, &stroke_data, sizeof(struct stroke));
#else
read(ff, &stroke_data, sizeof(struct stroke));
#endif
#ifdef WORDS_BIGENDIAN
bitflip( &(stroke_data.dx) );
bitflip( &(stroke_data.dy) );
#endif /* WORDS_BIGENDIAN */
quot = 0;
retry:
dm = stroke_data.dx;
if (dm<0) dm = -dm;
if (stroke_data.dy>dm) dm = stroke_data.dy;
if (-stroke_data.dy>dm) dm = -stroke_data.dy;
if (dm>8000) {
if (stroke_data.dx<-650000)
stroke_data.dx +=1296000;
else
if (stroke_data.dx>650000)
stroke_data.dx -=1296000;
++quot;
if (quot==1) goto retry;
fprintf(stderr, "Strange values dx = %d , dy = %d\n",
stroke_data.dx, stroke_data.dy);
}
if (dm<128) {
dx[count] = (stroke_data.dx)&255;
dy[count] = (stroke_data.dy)&255;
++count;
} else {
quot = 1+(dm/128);
xp = yp = 0;
for (s=1; s<=quot; s++) {
xt = xp;
yt = yp;
xp = (s*stroke_data.dx)/quot;
yp = (s*stroke_data.dy)/quot;
dx[count] = (xp-xt)&255;
dy[count] = (yp-yt)&255;
++count;
}
}
}
if (verbose && (i%500)==499)
fprintf(stderr, "Read segments %d -- %d from REZ file\n", i-499, i);
jpd_count[i+1] = count;
if (segment_header_data.nstrokes>rez_length)
rez_length = segment_header_data.nstrokes;
xt = jpd_count[i+1]-jpd_count[i];
if (xt>jpd_length) jpd_length = xt;
}
fprintf(stderr, "Scanned %d REZ segments, %d rejected\n\n",
numseg, rejected);
fprintf(stderr, "Max length of REZ segments %d\n", rez_length);
fprintf(stderr, "Max width of REZ segments %d\n", maxwidth);
fprintf(stderr, "Max height of REZ segments %d\n", maxheight);
fprintf(stderr, "Total number of REZ segment strokes %d\n\n",
rez_total_strokes);
fprintf(stderr, "Max length of JPD segments after refragmentation %d\n",
jpd_length);
fprintf(stderr, "Total number of JPD segment strokes %d\n\n", count);
if (format == JPD) {
bzero(magic, 16);
strcpy(magic, JPD_MAGIC);
/* Write 16 bytes = magic(12) + max length of segments(4) */
for (u=0; u<12; u++) fprintf(fd, "%c", magic[u]);
fpr4(fd, jpd_length);
/* Write segment counts for the 5*28=140 continents * types
* 560 bytes in total
*/
count = 0;
for (u=0; u<5; u++)
for (v=0; v<4; v++) {
up = 1<<u;
vp = 1<<jpd2rez_type_code[v];
for (w=jpd_min[v]; w<=jpd_max[v]; w++) {
for (i=0; i<header_data.segment_index_count; i++) {
if (segment_index_data[i].continent!=up ||
segment_index_data[i].category!=vp ||
jpd_encod[v][segment_index_data[i].type]!= w) continue;
jpd_seg_count[u][w] += 1;
targets[v][segment_index_data[i].type] = '1';
}
if (verbose)
fprintf(stderr, "Section %d %02d : %d segments\n",
u, w, jpd_seg_count[u][w]);
count += jpd_seg_count[u][w];
fpr4(fd, count);
}
}
if (verbose)
for (v=0; v<4; v++)
fprintf(stderr, "%s : %s\n", type_name[v], targets[v]);
/* Write numseg headers of 16 bytes;
* the segments themselves will start at address 576+numseg*16
*/
addr = 576+numseg*16;
for (u=0; u<5; u++)
for (v=0; v<4; v++) {
up = 1<<u;
vp = 1<<jpd2rez_type_code[v];
for (w=jpd_min[v]; w<=jpd_max[v]; w++) {
for (i=0; i<header_data.segment_index_count; i++) {
if (segment_index_data[i].continent!=up ||
segment_index_data[i].category!=vp ||
jpd_encod[v][segment_index_data[i].type]!= w) continue;
fpr3(fd, segment_index_data[i].minlong);
fpr3(fd, segment_index_data[i].maxlong);
fpr3(fd, segment_index_data[i].minlat);
fpr3(fd, segment_index_data[i].maxlat);
/* 6 bytes for orgx, orgy + 2 bytes for each stroke */
addr += 6+2*(jpd_count[i+1]-jpd_count[i]);
fpr4(fd, addr);
}
}
}
if (verbose)
fprintf(stderr,
"Wrote JPD segment headers, %d such segments\n", numseg);
count = 0;
for (u=0; u<5; u++)
for (v=0; v<4; v++) {
up = 1<<u;
vp = 1<<jpd2rez_type_code[v];
for (w=jpd_min[v]; w<=jpd_max[v]; w++) {
for (i=0; i<header_data.segment_index_count; i++) {
if (segment_index_data[i].continent!=up ||
segment_index_data[i].category!=vp ||
jpd_encod[v][segment_index_data[i].type]!= w) continue;
fpr3(fd, rez_orgx[i]);
fpr3(fd, rez_orgy[i]);
for (j=jpd_count[i]; j<jpd_count[i+1]; j++) {
fprintf(fd, "%c%c", dx[j], dy[j]);
++count;
}
}
if (verbose)
fprintf(stderr,
"Wrote JPD data for continent = %d, type = %d\n", u, w);
}
}
if (verbose)
fprintf(stderr, "Wrote %d segment strokes in total.\n\n", count);
}
if (format==TEXT) {
k = 0;
count = 0;
addr = 576+numseg*16;
for (u=0; u<5; u++)
for (v=0; v<4; v++) {
up = 1<<u;
vp = 1<<jpd2rez_type_code[v];
for (w=jpd_min[v]; w<=jpd_max[v]; w++) {
for (i=0; i<header_data.segment_index_count; i++) {
if (segment_index_data[i].continent!=up ||
segment_index_data[i].category!=vp ||
jpd_encod[v][segment_index_data[i].type]!= w) continue;
addr += 6+2*(jpd_count[i+1]-jpd_count[i]);
if ( (list_cont && !index(list_cont, '0'+u)) ||
(list_types && !index(list_types, '0'+v)) ) {
++k;
continue;
}
fprintf(fd, "<%d> %s (%s %d)\nJPD address: %d\n",
k, cont_name[u], type_name[v], w-jpd_min[v], addr);
++k;
if (text_output_type == REAL) {
fprintf(fd,"Box [%4.6f %4.6f] [%3.6f %3.6f]\nStrokes %d\n",
segment_index_data[i].minlong/3600.0,
segment_index_data[i].maxlong/3600.0,
segment_index_data[i].minlat/3600.0,
segment_index_data[i].maxlat/3600.0,
jpd_count[i+1]-jpd_count[i]);
fprintf(fd, "Origin %4.6f %3.6f\n",
rez_orgx[i]/3600.0, rez_orgy[i]/3600.0);
} else {
fprintf(fd, "Box [%d %d] [%d %d]\nStrokes %d\n",
segment_index_data[i].minlong,
segment_index_data[i].maxlong,
segment_index_data[i].minlat,
segment_index_data[i].maxlat,
jpd_count[i+1]-jpd_count[i]);
fprintf(fd, "Origin %d %d\n", rez_orgx[i], rez_orgy[i]);
}
xp = rez_orgx[i];
yp = rez_orgy[i];
for (j=jpd_count[i]; j<jpd_count[i+1]; j++) {
if (text_output_type == DX_DY)
fprintf(fd, "%d %d\n", dx[j], dy[j]);
else {
xp += (signed char)dx[j];
yp += (signed char)dy[j];
if (text_output_type == INT)
fprintf(fd, "%d %d\n", xp, yp);
else
fprintf(fd, "%4.6f %3.6f\n", xp/3600.0, yp/3600.0);
}
++count;
}
}
if (verbose)
fprintf(stderr,
"Wrote JPD data for continent = %d, type = %d\n", u, w);
}
}
if (verbose)
fprintf(stderr, "Wrote %d segment strokes in total.\n\n", count);
}
fclose(fd);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1