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