/*
* Usage: cbd2else [-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 <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#define TOTALSEG 31844
/* number of segments in WDB is really 31845, but one river showing up in
Uganda is faulty and must be deleted ! */
#define CBD_MAGIC 0x20770002
#define REZ_MAGIC 0x86460346
#define JPD_MAGIC "!JPD1.0\n"
#define SHORTFLAG 0x4000
#define BIT32 int
#define BIT16 short
#define DEBUG 1
enum { AFRICA=0, ASIA, EUROPE, NAMERICA, SAMERICA };
enum { BDY=0, PBY, RIV, CIL };
enum {NONE=0, TEXT, REZ, JPD };
enum {INT=0, REAL, BOTH};
struct cbdhead
{
BIT32 magic; /* Magic number */
BIT32 dictaddr; /* Offset of segment dictionary in file */
BIT32 segcount; /* Number of segments in file */
BIT32 segsize; /* Size of segment dictionary */
BIT32 segmax; /* Size of largest segment's strokes, /2 */
BIT32 fill[(40 / sizeof (BIT32)) - 5]; /* Filler */
};
struct segdict
{
BIT32 segid;
BIT32 maxlat, minlat, maxlong, minlong;
BIT32 absaddr;
BIT16 nbytes;
BIT16 rank;
};
struct segment
{
BIT32 orgx, orgy;
BIT32 id;
BIT16 nstrokes;
BIT16 dummy;
};
/*
* Change the two routines below to accomodate the byte ordering on your
* machine! - Joe Dellinger
*/
#if __BYTE_ORDER == __BIG_ENDIAN
void twiddle32 (i32)
BIT32 *i32;
{
BIT32 temp;
temp = 0;
temp |= 0xFF000000 & ((0x000000FF & *i32) << 24);
temp |= 0x00FF0000 & ((0x0000FF00 & *i32) << 8);
temp |= 0x0000FF00 & ((0x00FF0000 & *i32) >> 8);
temp |= 0x000000FF & ((0xFF000000 & *i32) >> 24);
*i32 = temp;
}
void twiddle16 (i16)
BIT16 *i16;
{
BIT16 temp;
temp = 0;
temp |= 0xFF00 & ((0x00FF & *i16) << 8);
temp |= 0x00FF & ((0xFF00 & *i16) >> 8);
*i16 = temp;
}
#else
void twiddle32 (i32)
BIT32 *i32;
{
}
void twiddle16 (i16)
BIT16 *i16;
{
}
#endif
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 prascii(int u, int v, int text_output_type)
{
if (text_output_type == INT)
printf("%7d %7d\n", u, v);
else
if (text_output_type == REAL)
printf("%3.6f %3.6f\n",
(double)u/3600.0, (double)v/3600.0);
else
if (text_output_type == BOTH)
printf("%7d %7d | %3.6f %3.6f\n", u, v,
(double)u/3600.0, (double)v/3600.0);
}
void usage()
{
fprintf(stderr,
"Usage: cbd2else [-datadir name] [-outdir name] [-numseg number]\n"
" [-format type] [-ascii type]\n"
"where format type is one of NONE (default), TEXT, REZ, 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;
{
FILE * fi, * fh, * fd;
char filename[512];
char * data_dir = NULL, * out_dir = NULL;
char magic[20];
int dx[20000], dy[20000];
int Ifile;
int u, v, w, j, k, oln, olt, idx, idy, rejected, text_output_type;
int format, numseg, totalseg, addr, maxlength, maxwidth, maxheight;
#if DEBUG
int w1, w2, z1, z2;
#endif
int segbufsize, segcount, jstroke, iseg, ignore;
char *cont_name[] = { "africa", "asia", "europe", "namer", "samer" };
char *type_name[] = { "bdy", "pby", "riv", "cil" };
int rez_type_code[4] = { 2, 0, 1, 3 };
char *comment[3] = {
"((int) lat, long)",
"(lat, long °decimal)",
"((int) lat, long | lat, long °)"
};
#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 },
{ U, 3, U, 4, U, U, U, U, U, U, U, U, U, U, U, U },
{ U, 5, 6, 7, 8, 9, 10, 11, 12, U, 13, 14, U, 15, U, U },
{ U, 16, 17, 18, 19, U, 20, 21, 22, 23, 24, U, U, 25, 26, 27 }
};
int jpd_min[4] = { 0, 3, 5, 16 };
int jpd_max[4] = { 2, 4, 15, 27 };
int jpd_seg_count[5][28];
BIT32 i32;
BIT16 *segbuf;
struct cbdhead header;
struct segdict *sd, *sdbuf;
struct segment sb;
#if __BYTE_ORDER == __BIG_ENDIAN
fprintf(stderr, "Detected bigendian processor...\n");
#endif
/*
* Parse options
*/
format = TEXT;
totalseg = TOTALSEG;
text_output_type = REAL;
for (j=1; j<argc; j++) {
if (j<argc-1 && !strncmp(argv[j],"-datadir",8))
data_dir = (char *)strdup(argv[++j]);
else
if (j<argc-1 && !strncmp(argv[j],"-outdir",7))
out_dir = (char *)strdup(argv[++j]);
else
if (j<argc-1 && !strncmp(argv[j],"-numseg",7))
totalseg = atoi(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], "rez")) format = REZ;
if (!strcasecmp(argv[j], "jpd")) format = JPD;
}
else
if (j<argc-1 && !strcmp(argv[j], "-ascii")) {
++j;
if (!strcasecmp(argv[j], "int")) text_output_type = INT;
if (!strcasecmp(argv[j], "real")) text_output_type = REAL;
if (!strcasecmp(argv[j], "both")) text_output_type = BOTH;
}
else
usage();
}
numseg = 0;
maxlength = 0;
maxwidth = 0;
maxheight = 0;
if (totalseg<0) totalseg = 0;
rejected = 0;
addr = 0;
if (format == REZ)
addr = 12+totalseg*32;
if (format == JPD)
addr = 576+totalseg*16;
for (v=0; v<4; v++)
sprintf(targets[v], "000000000000000000");
if (!data_dir) {
fprintf(stderr, "The WDB data directory has not been specified !!\n");
exit(-1);
}
/*
* Read in the file header, check it for the correct magic number,
* and learn the address of the segment dictionary
*/
if (format == REZ) {
if (!out_dir) {
fprintf(stderr,
"Output in REZ format requires -outdir to be specified!!\n");
exit(-1);
}
sprintf(filename, "%s/rez_header", out_dir);
fh = fopen(filename, "w");
sprintf(filename, "%s/rez_data", out_dir);
fd = fopen(filename, "w");
fpr4(fh, REZ_MAGIC);
fpr4(fh, 12);
fpr4(fh, totalseg);
}
if (format == JPD) {
if (!out_dir) {
fprintf(stderr,
"Output in JPD format requires -outdir to be specified!!\n");
exit(-1);
}
sprintf(filename, "%s/jpd_ini", out_dir);
fi = fopen(filename, "w");
sprintf(filename, "%s/jpd_header", out_dir);
fh = fopen(filename, "w");
sprintf(filename, "%s/jpd_data", out_dir);
fd = fopen(filename, "w");
bzero(magic, 16);
strcpy(magic, JPD_MAGIC);
for (u=0; u<12; u++) fprintf(fi, "%c", magic[u]);
}
if (format==JPD)
for (u=0; u<5; u++)
for (w=0; w<28; w++)
jpd_seg_count[u][w] = 0;
else
for (v=0; v<4; v++)
jpd_min[v] = jpd_max[v] = 0;
for (u=0; u<5; u++)
for (v=0; v<4; v++)
for (w=jpd_min[v]; w<=jpd_max[v]; w++) {
sprintf(filename, "%s/%s.Map/%s.cbd",
data_dir, cont_name[u], type_name[v]);
Ifile = open (filename, O_RDONLY, 0);
if (Ifile==-1) {
fprintf(stderr, "File %s does not exist !!\n", filename);
continue;
}
fprintf(stderr, "Scanning [%d] %s ...\n", w, filename);
read (Ifile, &header, sizeof(header));
twiddle32 (&(header.magic));
twiddle32 (&(header.dictaddr));
twiddle32 (&(header.segcount));
twiddle32 (&(header.segsize));
twiddle32 (&(header.segmax));
if (header.magic != CBD_MAGIC)
{
fprintf (stderr, "File has bad magic number %d != %d\n",
header.magic, CBD_MAGIC);
exit (2);
}
/* allocate space for the segment buffer */
segbufsize = 2 * header.segmax;
segbuf = (BIT16 *) malloc (50 + segbufsize);
/* allocate space for the segment dictionary */
sdbuf = (struct segdict *) malloc (100 + header.segsize);
sd = sdbuf;
sd++;
/* Go read in the segment dictionary (it's at the end of the file) */
lseek (Ifile, header.dictaddr, L_SET);
j = read (Ifile, sd, header.segsize);
if (j < header.segsize)
{
fprintf (stderr, "File segment dictionary expecting %d got %d\n",
header.segsize, j);
close (Ifile);
free (sdbuf);
free (segbuf);
return -1;
}
/*
* Now look at each segment
*/
segcount = header.segcount;
sd = sdbuf;
for (iseg = 1; iseg <= segcount; iseg++)
{
sd++; /* does this really work? wow! */
twiddle32 (&(sd->segid));
twiddle32 (&(sd->maxlat));
twiddle32 (&(sd->minlat));
twiddle32 (&(sd->maxlong));
twiddle32 (&(sd->minlong));
twiddle32 (&(sd->absaddr));
twiddle16 (&(sd->nbytes));
twiddle16 (&(sd->rank));
if (format==JPD) {
if (jpd_encod[v][sd->rank]!=w) continue;
}
lseek (Ifile, sd->absaddr, L_SET);
read (Ifile, &sb, sizeof sb);
twiddle32 (&(sb.orgx));
twiddle32 (&(sb.orgy));
twiddle32 (&(sb.id));
twiddle16 (&(sb.nstrokes));
if (sd->nbytes > segbufsize)
{
fprintf (stderr, "Segment %d needs %d bytes; buffer limit is %d.\n", iseg, sd->nbytes, segbufsize);
close (Ifile);
free (sdbuf);
free (segbuf);
return -1;
}
read (Ifile, segbuf, sd->nbytes);
k = 0;
oln = sb.orgx;
olt = sb.orgy;
if (format == TEXT) {
printf("Continent [%s], type [%s]\n",
cont_name[u], type_name[v]);
printf("segid = %d\n", sd->segid);
/* printf("sb.id = %d\n", sb.id); */
printf("minlat = %d\n", sd->minlat);
printf("maxlat = %d\n", sd->maxlat);
printf("minlong = %d\n", sd->minlong);
printf("maxlong = %d\n", sd->maxlong);
printf("absaddr = %d\n", sd->absaddr);
printf("nbytes = %d\n", sd->nbytes);
printf("rank = %d\n", sd->rank);
printf("nstrokes = %d %s\n",
sb.nstrokes, comment[text_output_type]);
prascii(olt, oln, text_output_type);
}
ignore = 0;
for (jstroke = 1; jstroke <= sb.nstrokes; jstroke++)
{
twiddle16 (&segbuf[k]);
if (segbuf[k] & SHORTFLAG)
{
/* Flag bit on: unpack a 16-bit field into dx and dy */
i32 = segbuf[k++];
if (i32 > 0)
i32 &= ~SHORTFLAG;
idy = i32 & 0xFF;
if (idy & 0x80)
idy |= ~0xFF; /* extend sign */
idx = i32 >> 8;
if (idx & 0x80)
idx |= ~0xBF; /* extend sign */
}
else
{
/* Flag bit off: take dx and dy from 32-bit fields. */
idx = segbuf[k++];
if (idx < 0)
idx |= SHORTFLAG;
else
idx &= ~SHORTFLAG;
#if DEBUG
w1 = idx;
#endif
twiddle16 (&segbuf[k]);
/* Modification by J.-P. Demailly to correct calculation of cobal data
for which there is a big jump from longitude -180 to longitude +180
Notice that 14720 = 20*65536-1296000 where 1296000=360*60*60
*/
if (idx==19)
idx = 14720 + segbuf[k];
else
if (idx==-20)
idx = segbuf[k] - 14720;
else
idx = (idx << 16) | segbuf[k];
#if DEBUG
w2 = segbuf[k];
#endif
k++;
twiddle16 (&segbuf[k]);
idy = segbuf[k];
#if DEBUG
z1 = idy;
#endif
k++;
if (idy < 0)
idy |= SHORTFLAG;
twiddle16 (&segbuf[k]);
#if DEBUG
z2 = segbuf[k];
#endif
idy = (idy << 16) | segbuf[k];
k++;
if (abs(idx)>8000 || abs(idy)>8000) {
#if DEBUG
fprintf(stderr,
"Segment %d, index %d : %d %d !!! %d %d %d %d\n",
iseg, jstroke, idx, idy, w1, w2, z1, z2);
#endif
ignore = 1;
}
}
dx[jstroke] = idx;
dy[jstroke] = idy;
oln = oln + idx;
olt = olt + idy;
if (format == TEXT) prascii(olt, oln, text_output_type);
}
if (ignore) {
++rejected;
continue;
}
targets[v][sd->rank] = '1';
if (format == REZ) {
fpr4(fh, sd->maxlat);
fpr4(fh, sd->minlat);
fpr4(fh, sd->maxlong);
fpr4(fh, sd->minlong);
fpr4(fh, addr);
fpr4(fh, 1<<u);
fpr4(fh, 1<<rez_type_code[v]);
fpr4(fh, sd->rank);
addr += 12 + 8*sb.nstrokes;
fpr4(fd, sb.orgx);
fpr4(fd, sb.orgy);
fpr4(fd, sb.nstrokes);
for (jstroke = 1; jstroke <= sb.nstrokes; jstroke++) {
fpr4(fd, dx[jstroke]);
fpr4(fd, dy[jstroke]);
}
}
if (format == JPD) {
int dm, count, quot, xp, yp, xt, yt, s;
jpd_seg_count[u][w] += 1;
/*
if (jpd_seg_count[u][w]%100==0)
fprintf(stderr, "Reached seg[%d,%d] = %d\n",
u, w, jpd_seg_count[u][w]);
*/
fpr3(fd, sb.orgx);
fpr3(fd, sb.orgy);
count = 0;
for (jstroke = 1; jstroke <= sb.nstrokes; jstroke++) {
dm = dx[jstroke];
if (dm<0) dm = -dm;
if (dy[jstroke]>dm) dm = dy[jstroke];
if (-dy[jstroke]>dm) dm = -dy[jstroke];
if (dm<128) {
fprintf(fd, "%c%c",
(dx[jstroke])&255, (dy[jstroke])&255 );
++count;
} else {
quot = 1+(dm/128);
xp = yp = 0;
for (s=1; s<=quot; s++) {
xt = xp;
yt = yp;
xp = (s*dx[jstroke])/quot;
yp = (s*dy[jstroke])/quot;
fprintf(fd, "%c%c", (xp-xt)&255, (yp-yt)&255 );
}
count += quot;
}
}
fpr3(fh, sd->minlong);
fpr3(fh, sd->maxlong);
fpr3(fh, sd->minlat);
fpr3(fh, sd->maxlat);
addr += 6+2*count;
fpr4(fh, addr);
}
numseg += 1;
if (sb.nstrokes>maxlength) maxlength = sb.nstrokes;
i32 = sd->maxlong-sd->minlong;
if (i32>maxwidth) maxwidth = i32;
i32 = sd->maxlat-sd->minlat;
if (i32>maxheight) maxheight = i32;
}
close (Ifile);
free (sdbuf);
free (segbuf);
}
if (format == REZ) {
fclose(fh);
fclose(fd);
}
if (format == JPD) {
fclose(fh);
fclose(fd);
}
if (format==JPD) {
int count = 0;
fpr4(fi, maxlength);
for (u=0; u<5; u++)
for (w=0; w<28; w++) {
count += jpd_seg_count[u][w];
fpr4(fi, count);
fprintf(stderr, "Segment index [cont=%d, type=%d] = %d\n",
u, w, count);
}
fclose(fi);
}
fprintf(stderr, "Scanned %d segments, %d rejected\n", numseg, rejected);
fprintf(stderr, "Max length of segments %d\n", maxlength);
fprintf(stderr, "Max width of segments %d\n", maxwidth);
fprintf(stderr, "Max height of segments %d\n", maxheight);
for (v=0; v<4; v++)
fprintf(stderr, "%s : %s\n", type_name[v], targets[v]);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1