1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
5 #include <ctype.h>
6 
7 #include "dmemory.h"
8 #include "service.h"
9 #include "error.h"
10 #include "file.h"
11 #include "binary.h"
12 #include "exse.h"
13 #include "swap.h"
14 
15 
16 enum {
17   SRV_HEADER_LEN = 8,
18 };
19 
20 union SRV_HEADER
21 {
22   INT32 i32[SRV_HEADER_LEN];
23   INT64 i64[SRV_HEADER_LEN];
24 };
25 
26 static int initSrvLib      = 0;
27 static int srvDefaultHprec = 0;
28 static int srvDefaultDprec = 0;
29 
30 
31 // A version string.
32 #undef  LIBVERSION
33 #define LIBVERSION      1.4.2
34 #define XSTRING(x)	#x
35 #define STRING(x)	XSTRING(x)
36 static const char srv_libvers[] = STRING(LIBVERSION);
37 
srvLibraryVersion(void)38 const char *srvLibraryVersion(void)
39 {
40   return srv_libvers;
41 }
42 
43 
44 static int SRV_Debug = 0;    // If set to 1, debugging
45 
46 
srvDebug(int debug)47 void srvDebug(int debug)
48 {
49   if (debug) Message("debug level %d", debug);
50   SRV_Debug = debug;
51 }
52 
53 static
srvLibInit()54 void srvLibInit()
55 {
56   const char *envName = "SRV_PRECISION";
57 
58   char *envString = getenv(envName);
59   if ( envString )
60     {
61       int nrun = (strlen(envString) == 2) ? 1 : 2;
62       int pos = 0;
63       while ( nrun-- )
64 	{
65 	  switch ( tolower((int) envString[pos]) )
66 	    {
67 	    case 'i':
68 	      {
69 		switch ( (int) envString[pos+1] )
70 		  {
71 		  case '4': srvDefaultHprec = EXSE_SINGLE_PRECISION; break;
72 		  case '8': srvDefaultHprec = EXSE_DOUBLE_PRECISION; break;
73 		  default: Message("Invalid digit in %s: %s", envName, envString);
74 		  }
75 		break;
76 	      }
77 	    case 'r':
78 	      {
79 		switch ( (int) envString[pos+1] )
80 		  {
81 		  case '4': srvDefaultDprec = EXSE_SINGLE_PRECISION; break;
82 		  case '8': srvDefaultDprec = EXSE_DOUBLE_PRECISION; break;
83 		  default: Message("Invalid digit in %s: %s", envName, envString);
84 		  }
85 		break;
86 	      }
87 	    default:
88               {
89                 Message("Invalid character in %s: %s", envName, envString);
90                 break;
91               }
92             }
93 	  pos += 2;
94 	}
95     }
96 
97   initSrvLib = 1;
98 }
99 
100 static
srvInit(srvrec_t * srvp)101 void srvInit(srvrec_t *srvp)
102 {
103   srvp->checked    = 0;
104   srvp->byteswap   = 0;
105   srvp->hprec      = 0;
106   srvp->dprec      = 0;
107   srvp->datasize   = 0;
108   srvp->buffersize = 0;
109   srvp->buffer     = NULL;
110 }
111 
112 
srvNew(void)113 void *srvNew(void)
114 {
115   if ( ! initSrvLib ) srvLibInit();
116 
117   srvrec_t *srvp = (srvrec_t *) Malloc(sizeof(srvrec_t));
118   srvInit(srvp);
119 
120   return (void*)srvp;
121 }
122 
123 
srvDelete(void * srv)124 void srvDelete(void *srv)
125 {
126   srvrec_t *srvp = (srvrec_t *) srv;
127 
128   if ( srvp )
129     {
130       if ( srvp->buffer ) Free(srvp->buffer);
131       Free(srvp);
132     }
133 }
134 
135 
srvCheckFiletype(int fileID,int * swap)136 int srvCheckFiletype(int fileID, int *swap)
137 {
138   size_t data = 0;
139   size_t dimx = 0, dimy = 0;
140   size_t fact = 0;
141   unsigned char buffer[72], *pbuf;
142 
143   if ( fileRead(fileID, buffer, 4) != 4 ) return 0;
144 
145   const size_t blocklen  = (size_t) get_UINT32(buffer);
146   const size_t sblocklen = (size_t) get_SUINT32(buffer);
147 
148   if ( SRV_Debug ) Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
149 
150   // clang-format off
151   if ( blocklen == 32 )
152     {
153      *swap = 0;
154       fact = blocklen>>3;
155       if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
156       pbuf = buffer+4*fact;      dimx = (size_t) get_UINT32(pbuf);
157       pbuf = buffer+5*fact;      dimy = (size_t) get_UINT32(pbuf);
158       pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
159     }
160   else if ( blocklen == 64 )
161     {
162      *swap = 0;
163       fact = blocklen>>3;
164       if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
165       pbuf = buffer+4*fact;      dimx = (size_t) get_UINT64(pbuf);
166       pbuf = buffer+5*fact;      dimy = (size_t) get_UINT64(pbuf);
167       pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
168     }
169   else if ( sblocklen == 32 )
170     {
171      *swap = 1;
172       fact = sblocklen>>3;
173       if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
174       pbuf = buffer+4*fact;       dimx = (size_t) get_SUINT32(pbuf);
175       pbuf = buffer+5*fact;       dimy = (size_t) get_SUINT32(pbuf);
176       pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
177     }
178   else if ( sblocklen == 64 )
179     {
180      *swap = 1;
181       fact = sblocklen>>3;
182       if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
183       pbuf = buffer+4*fact;       dimx = (size_t) get_SUINT64(pbuf);
184       pbuf = buffer+5*fact;       dimy = (size_t) get_SUINT64(pbuf);
185       pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
186     }
187   // clang-format on
188 
189   fileRewind(fileID);
190 
191   if ( SRV_Debug )
192     {
193       Message("swap = %d fact = %d", *swap, fact);
194       Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
195     }
196 
197   const int found = data && (dimx*dimy*fact == data || dimx*dimy*8 == data);
198   return found;
199 }
200 
201 
srvInqHeader(void * srv,int * header)202 int srvInqHeader(void *srv, int *header)
203 {
204   srvrec_t *srvp = (srvrec_t *) srv;
205 
206   for (int i = 0; i < SRV_HEADER_LEN; i++) header[i] = srvp->header[i];
207 
208   if (SRV_Debug) Message("datasize = %lu", srvp->datasize);
209 
210   return 0;
211 }
212 
213 
srvDefHeader(void * srv,const int * header)214 int srvDefHeader(void *srv, const int *header)
215 {
216   srvrec_t *srvp = (srvrec_t *) srv;
217 
218   for (int i = 0; i < SRV_HEADER_LEN; i++) srvp->header[i] = header[i];
219 
220   srvp->datasize = (size_t)header[4] * (size_t)header[5];
221 
222   if (SRV_Debug) Message("datasize = %zu", srvp->datasize);
223 
224   return 0;
225 }
226 
227 static
srvInqData(srvrec_t * srvp,int prec,void * data)228 int srvInqData(srvrec_t *srvp, int prec, void *data)
229 {
230   int ierr = 0;
231   const int byteswap = srvp->byteswap;
232   const size_t datasize = srvp->datasize;
233   void *buffer = srvp->buffer;
234   const int dprec = srvp->dprec;
235 
236   switch ( dprec )
237     {
238     case EXSE_SINGLE_PRECISION:
239       {
240 	if ( sizeof(FLT32) == 4 )
241 	  {
242 	    if ( byteswap ) swap4byte(buffer, datasize);
243 
244 	    if ( dprec == prec )
245 	      memcpy(data, buffer, datasize*sizeof(FLT32));
246 	    else
247 	      for (size_t i = 0; i < datasize; i++)
248 		((double *) data)[i] = (double) ((float *) buffer)[i];
249 	  }
250 	else
251 	  {
252 	    Error("not implemented for %d byte float", sizeof(FLT32));
253 	  }
254 	break;
255       }
256     case EXSE_DOUBLE_PRECISION:
257 	if ( sizeof(FLT64) == 8 )
258 	  {
259 	    if ( byteswap ) swap8byte(buffer, datasize);
260 
261 	    if ( dprec == prec )
262 	      memcpy(data, buffer, datasize*sizeof(FLT64));
263 	    else
264 	      for (size_t i = 0; i < datasize; i++)
265 		((float *) data)[i] = (float) ((double *) buffer)[i];
266 	  }
267 	else
268 	  {
269 	    Error("not implemented for %d byte float", sizeof(FLT64));
270 	  }
271 	break;
272     default:
273       {
274 	Error("unexpected data precision %d", dprec);
275         break;
276       }
277     }
278 
279   return ierr;
280 }
281 
282 
srvInqDataSP(void * srv,float * data)283 int srvInqDataSP(void *srv, float *data)
284 {
285   return srvInqData((srvrec_t *)srv, EXSE_SINGLE_PRECISION, (void *) data);
286 }
287 
288 
srvInqDataDP(void * srv,double * data)289 int srvInqDataDP(void *srv, double *data)
290 {
291   return srvInqData((srvrec_t *)srv, EXSE_DOUBLE_PRECISION, (void *) data);
292 }
293 
294 
295 static int
srvDefData(void * srv,int prec,const void * data)296 srvDefData(void *srv, int prec, const void *data)
297 {
298   srvrec_t *srvp = (srvrec_t *) srv;
299 
300   const int dprec = srvDefaultDprec ? srvDefaultDprec : srvp->dprec;
301   srvp->dprec = dprec ? dprec : prec;
302 
303   const int hprec = srvDefaultHprec ? srvDefaultHprec : srvp->hprec;
304   srvp->hprec = hprec ? hprec : dprec;
305 
306   int *header = srvp->header;
307 
308   const size_t datasize = (size_t)header[4] * (size_t)header[5];
309   const size_t blocklen = datasize * (size_t)dprec;
310 
311   srvp->datasize = datasize;
312 
313   if ( srvp->buffersize != blocklen )
314     {
315       srvp->buffersize = blocklen;
316       srvp->buffer = Realloc(srvp->buffer, srvp->buffersize);
317     }
318 
319   switch ( dprec )
320     {
321     case EXSE_SINGLE_PRECISION:
322       {
323 	if ( dprec == prec )
324 	  memcpy(srvp->buffer, data, datasize*sizeof(FLT32));
325 	else
326 	  for (size_t i = 0; i < datasize; i++)
327 	    ((float *) srvp->buffer)[i] = (float) ((double *) data)[i];
328 
329 	break;
330       }
331     case EXSE_DOUBLE_PRECISION:
332       {
333 	if ( dprec == prec )
334 	  memcpy(srvp->buffer, data, datasize*sizeof(FLT64));
335 	else
336 	  for (size_t i = 0; i < datasize; i++)
337 	    ((double *) srvp->buffer)[i] = (double) ((float *) data)[i];
338 
339 	break;
340       }
341     default:
342       {
343 	Error("unexpected data precision %d", dprec);
344         break;
345       }
346     }
347 
348   return 0;
349 }
350 
351 
srvDefDataSP(void * srv,const float * data)352 int srvDefDataSP(void *srv, const float *data)
353 {
354   return srvDefData(srv, EXSE_SINGLE_PRECISION, (void *) data);
355 }
356 
357 
srvDefDataDP(void * srv,const double * data)358 int srvDefDataDP(void *srv, const double *data)
359 {
360   return srvDefData(srv, EXSE_DOUBLE_PRECISION, (void *) data);
361 }
362 
363 
srvRead(int fileID,void * srv)364 int srvRead(int fileID, void *srv)
365 {
366   srvrec_t *srvp = (srvrec_t *) srv;
367   union SRV_HEADER tempheader;
368 
369   if ( ! srvp->checked )
370     {
371       const int status = srvCheckFiletype(fileID, &srvp->byteswap);
372       if ( status == 0 ) Error("Not a SERVICE file!");
373       srvp->checked = 1;
374     }
375 
376   const int byteswap = srvp->byteswap;
377 
378   // read header record
379   size_t blocklen = binReadF77Block(fileID, byteswap);
380 
381   if ( fileEOF(fileID) ) return -1;
382 
383   if ( SRV_Debug ) Message("blocklen = %lu", blocklen);
384 
385   const size_t hprec = blocklen / SRV_HEADER_LEN;
386 
387   srvp->hprec = (int)hprec;
388 
389   switch ( hprec )
390     {
391     case EXSE_SINGLE_PRECISION:
392       {
393 	binReadInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
394 	for (int i = 0; i < SRV_HEADER_LEN; i++) srvp->header[i] = (int)tempheader.i32[i];
395 	break;
396       }
397     case EXSE_DOUBLE_PRECISION:
398       {
399 	binReadInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
400 	for (int i = 0; i < SRV_HEADER_LEN; i++) srvp->header[i] = (int)tempheader.i64[i];
401 	break;
402       }
403     default:
404       {
405 	Error("Unexpected header precision %d", hprec);
406         break;
407       }
408     }
409 
410   size_t blocklen2 = binReadF77Block(fileID, byteswap);
411 
412   if ( blocklen2 != blocklen )
413     {
414       Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
415       if ( blocklen2 != 0 ) return -1;
416     }
417 
418   srvp->datasize = (size_t)srvp->header[4] * (size_t)srvp->header[5];
419 
420   if ( SRV_Debug ) Message("datasize = %zu", srvp->datasize);
421 
422   blocklen = binReadF77Block(fileID, byteswap);
423 
424   if ( srvp->buffersize < blocklen )
425     {
426       srvp->buffersize = blocklen;
427       srvp->buffer = Realloc(srvp->buffer, srvp->buffersize);
428     }
429 
430   const size_t dprec = blocklen / srvp->datasize;
431 
432   srvp->dprec = (int)dprec;
433 
434   if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
435     {
436       Warning("Unexpected data precision %d", dprec);
437       return -1;
438     }
439 
440   fileRead(fileID, srvp->buffer, blocklen);
441 
442   blocklen2 = binReadF77Block(fileID, byteswap);
443 
444   if ( blocklen2 != blocklen )
445     {
446       Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
447       if ( blocklen2 != 0 ) return -1;
448     }
449 
450   return 0;
451 }
452 
453 
srvWrite(int fileID,void * srv)454 void srvWrite(int fileID, void *srv)
455 {
456   srvrec_t *srvp = (srvrec_t *) srv;
457   union SRV_HEADER tempheader;
458   const int byteswap = srvp->byteswap;
459   const int dprec  = srvp->dprec;
460   const int hprec  = srvp->hprec;
461   int *restrict header = srvp->header;
462 
463   // write header record
464   size_t blocklen = SRV_HEADER_LEN * (size_t)hprec;
465 
466   binWriteF77Block(fileID, byteswap, blocklen);
467 
468   switch ( hprec )
469     {
470     case EXSE_SINGLE_PRECISION:
471       {
472 	for (int i = 0; i < SRV_HEADER_LEN; i++) tempheader.i32[i] = (INT32) header[i];
473 	binWriteInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
474 	break;
475       }
476     case EXSE_DOUBLE_PRECISION:
477       {
478 	for (int i = 0; i < SRV_HEADER_LEN; i++) tempheader.i64[i] = (INT64) header[i];
479 	binWriteInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
480 	break;
481       }
482     default:
483       {
484 	Error("unexpected header precision %d", hprec);
485         break;
486       }
487     }
488 
489   binWriteF77Block(fileID, byteswap, blocklen);
490 
491   srvp->datasize = (size_t)header[4] * (size_t)header[5];
492   blocklen = srvp->datasize * (size_t)dprec;
493 
494   binWriteF77Block(fileID, byteswap, blocklen);
495 
496   switch ( dprec )
497     {
498     case EXSE_SINGLE_PRECISION:
499       {
500 	binWriteFlt32(fileID, byteswap, srvp->datasize, (FLT32 *) srvp->buffer);
501 	break;
502       }
503     case EXSE_DOUBLE_PRECISION:
504       {
505 	binWriteFlt64(fileID, byteswap, srvp->datasize, (FLT64 *) srvp->buffer);
506 	break;
507       }
508     default:
509       {
510 	Error("unexpected data precision %d", dprec);
511         break;
512       }
513     }
514 
515   binWriteF77Block(fileID, byteswap, blocklen);
516 }
517 /*
518  * Local Variables:
519  * c-file-style: "Java"
520  * c-basic-offset: 2
521  * indent-tabs-mode: nil
522  * show-trailing-whitespace: t
523  * require-trailing-newline: t
524  * End:
525  */
526