1 /* mcidas.c:
2  *
3  * McIDAS areafile support.  contributed by Glenn P. Davis
4  * (davis@unidata.ucar.edu).
5  */
6 
7 #include "xloadimage.h"
8 #include "mcidas.h"
9 
10 char *mc_sensor();
11 
12 static struct {
13   int   days;
14   char *name;
15 } month_info[13] = {
16   { 0,  "Pad" },
17   { 31, "Jan" },
18   { 29, "Feb" }, /* longest */
19   { 31, "Mar" },
20   { 30, "Apr" },
21   { 31, "May" },
22   { 30, "Jun" },
23   { 31, "Jul" },
24   { 31, "Aug" },
25   { 30, "Sep" },
26   { 31, "Oct" },
27   { 30, "Nov" },
28   { 31, "Dec" }
29 };
30 
31 /* convert numeric dates to human-readable
32  */
convert_date(time,date)33 static char *convert_date(time, date)
34      int time, date;
35 { static char buf[30];
36   int hour;
37   int minute;
38   int second;
39   int year;
40   int month;
41   int day;
42 
43   year = date / 1000;
44   if (year > 50) /* gives us a range from 1950 - 2050, probably good enough */
45     year += 1900;
46   else
47     year += 2000;
48   day = date % 1000;
49 
50   /* adjust day for non-leap-years if necessary
51    */
52   if ((day > 31 + 28) && ((year % 4) || (year == 2000)))
53     day++;
54 
55   /* find month in year that this day falls in
56    */
57   for (month= 1; day > month_info[month].days; day -= month_info[month].days)
58     month++;
59 
60   /* break time-of-day up
61    */
62   hour = time / 10000;
63   minute = (time % 10000) / 100;
64   second = (time % 100);
65 
66   snprintf(buf, 29, "%d:%2.2d:%2.2d %s %d, %d (day %d)",
67 	  hour, minute, second, month_info[month].name, day, year,
68 	  (date % 1000));
69   return(buf);
70 }
71 
72 /*
73  * convert from little endian to big endian four byte object
74  */
75 static unsigned long
vhtonl(lend)76 vhtonl(lend)
77 unsigned long lend ;
78 {
79 	unsigned long bend ;
80 	unsigned char *lp, *bp ;
81 
82 	lp = ((unsigned char *)&lend) + 3 ;
83 	bp = (unsigned char *) &bend ;
84 
85 	*bp++ = *lp-- ;
86 	*bp++ = *lp-- ;
87 	*bp++ = *lp-- ;
88 	*bp = *lp ;
89 
90 	return(bend) ;
91 }
92 
babble(name,dir)93 static void babble(name, dir)
94      char *name;
95      struct area_dir *dir;
96 {
97   printf("%s is a %ldx%ld McIDAS areafile from %s at %s (%ld, %ld) (%ld, %ld)\n",
98 	 name,
99 	 dir->esiz, dir->lsiz,
100 	 mc_sensor(dir->satid),
101 	 convert_date(dir->itime, dir->idate),
102 	 dir->lcor,
103 	 dir->ecor,
104 	 dir->lres,
105 	 dir->eres) ;
106 }
107 
swap_bytes(dir)108 static void swap_bytes(dir)
109      struct area_dir *dir;
110 {
111   unsigned long *begin ;
112   unsigned long *ulp ;
113 
114   begin = (unsigned long *)dir ;
115   for(ulp = begin ; ulp < &begin[AREA_COMMENTS] ; ulp++)
116     *ulp = vhtonl(*ulp) ;
117   for(ulp = &begin[AREA_CALKEY] ; ulp < &begin[AREA_STYPE] ; ulp++)
118     *ulp = vhtonl(*ulp) ;
119 }
120 
121 /* ARGSUSED */
mcidasIdent(fullname,name)122 int mcidasIdent(fullname, name)
123      char *fullname, *name;
124 { ZFILE          *zf;
125   struct area_dir dir ;
126   int             r;
127 
128   if (! (zf= zopen(fullname))) {
129     perror("mcidasIdent");
130     return(0);
131   }
132   switch (zread(zf, (byte *)&dir, sizeof(struct area_dir))) {
133   case -1:
134     perror("mcidasIdent");
135     r= 0;
136     break;
137 
138   case sizeof(struct area_dir):
139     if (memToValLSB((char *)&dir.type, 4) != 4) {
140       r= 0;
141       break;
142     }
143     if (dir.type != 4)
144       swap_bytes(&dir);
145     babble(name, &dir);
146     r= 1;
147     break;
148 
149   default:
150     r= 0;
151     break;
152   }
153   zclose(zf);
154   return(r);
155 }
156 
157 
mcidasLoad(fullname,name,verbose)158 Image *mcidasLoad(fullname, name, verbose)
159      char         *fullname, *name;
160      unsigned int  verbose;
161 { ZFILE          *zf;
162   struct area_dir  dir;
163   struct navigation  nav;
164   Image          *image;
165   unsigned int    y;
166 
167   if (! (zf= zopen(fullname))) {
168     perror("mcidasLoad");
169     return(NULL);
170   }
171   switch (zread(zf, (byte *)&dir, sizeof(struct area_dir))) {
172   case -1:
173     perror("mcidasLoad");
174     zclose(zf);
175     exit(1);
176 
177   case sizeof(struct area_dir):
178     if (memToValLSB((char *)&dir.type, 4) != 4) {
179       zclose(zf);
180       return(NULL) ;
181     }
182     if (dir.type != 4)
183       swap_bytes(&dir);
184     break;
185 
186   default:
187     zclose(zf);
188     return(NULL);
189   }
190 
191   if (verbose)
192     babble(name, &dir);
193 
194   znocache(zf);
195   /* skip the nav */
196   if( zread(zf, (byte *)&nav, sizeof(struct navigation)) !=
197      sizeof(struct navigation)) {
198       zclose(zf);
199       return(NULL) ;
200   }
201 
202   /* get an image to put the data in
203    */
204   image= newRGBImage(dir.esiz, dir.lsiz, dir.zsiz * 8);
205 
206   /* set up the colormap, linear grey scale
207    */
208   for (y= 0; y < image->rgb.size; y++) {
209       *(image->rgb.red + y)=
210 	  *(image->rgb.green + y)=
211 	      *(image->rgb.blue + y)= y * (65536 / image->rgb.size) ;
212   }
213   image->rgb.used= image->rgb.size ;
214 
215   /* read the first band from the image and warn if there are other bands
216    * we can't read.
217    */
218   zread(zf, image->data, dir.esiz * dir.lsiz * dir.zsiz) ;
219   if (dir.bands > 1)
220       printf("Warning: Only showing first of %ld bands\n", dir.bands);
221 
222   zclose(zf);
223   image->title= dupString(name);
224   return(image);
225 }
226