aboutsummaryrefslogtreecommitdiff
path: root/sys/imio/iki/fxf/zfiofxf.x
blob: 97b36264d0754d61888c8d842b2c036f30a6fa34 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
 
include <mach.h>
include <knet.h>
include <fio.h>
include <fset.h>
include <imio.h>
include <imhdr.h>
include	"fxf.h"

# ZFIOFXF -- FITS kernel virtual file driver.   This maps the actual
# FITS file into the virtual pixel file expected by IMIO.


# FXFZOP -- Open the file driver for i/o.  The filename has appended the
# string "_nnnnn", where 'nnnnn' is the FIT descriptor to the structure
# defined in "fit.h".

procedure fxfzop (pkfn, mode, status)

char	pkfn[ARB]		#I packed virtual filename from FIO
int	mode			#I file access mode (ignored)
int	status			#O output status - i/o channel if successful

pointer im, fit
int	ip, indx, channel, strldx(), ctoi()
bool	lscale, lzero, bfloat, fxf_fpl_equald()
char    fname[SZ_PATHNAME]

begin
	# Separate the FIT descriptor from the file name.
	call strupk (pkfn, fname, SZ_PATHNAME)

        ip = strldx ("_", fname)
	indx = ip + 1
	if (ctoi (fname, indx, fit) <= 0) {
	   status = ERR
	   return
	}

	# Determine if we have a Fits Kernel non supported
	# data format; i.e. Bitpix -32 or -64 and BSCALE and/or
	# BZERO with non default values.

	### Only "low level" routines can be falled from a file driver:
	### high level routines like syserr cannot be used due to
	### recursion/reentrancy problems.
	# We are calling syserrs at this level because we want to
	# give the application the freedom to manipulate the FITS header
	# at will and not imposing restriction at that level.

	im = FIT_IM(fit)
	lscale = fxf_fpl_equald (1.0d0, FIT_BSCALE(fit), 1)
	lzero =  fxf_fpl_equald (0.0d0, FIT_BZERO(fit), 1)

	# Determine if scaling is necessary.
	#bfloat = (!lscale || !lzero)
	#if (bfloat && (FIT_BITPIX(fit) == -32 || FIT_BITPIX(fit) == -64)) {
	#    FIT_IOSTAT(fit) = ERR
	#    #call syserrs (SYS_FXFRDHSC,IM_HDRFILE(im))
	#    status = ERR
	#    return
	#}

	fname[ip] = EOS
	call strpak (fname, fname, SZ_PATHNAME)

	# Open the file.
	call zopnbf (fname, mode, channel)
	if (channel == ERR) {
	   status = ERR
	   return
	}

	status = fit
	FIT_IO(fit) = channel
end


# FITZCL -- Close the FIT binary file driver.

procedure fxfzcl (chan, status)

int	chan			#I FIT i/o channel
int	status			#O output status

pointer fit

begin
	fit = chan
	call zclsbf (FIT_IO(fit), status)
end


# FXFZRD --  Read the FIT file (header and pixel data).  An offset pointer
# needs to be set to point to the data portion of the file. If we are reading
# pixel data, the scale routine fxf_unpack_data is called.  We need to keep
# a counter (npix_read) with the current number of pixels unpacked since we
# don't want to convert beyond the total number of pixels; where the last
# block of data read can contain zeros or garbage up to a count of 2880 bytes.

procedure fxfzrd (chan, obuf, nbytes, boffset)

int	chan			#I FIT i/o channel
char	obuf[ARB]		#O output buffer
int	nbytes			#I nbytes to be read
int	boffset			#I file offset at which read commences

pointer fit, im
int	ip, pixtype, nb
int	status, totpix, npix
int	datasizeb, pixoffb, nb_skipped, i
double  dtemp
real    rtemp, rscale, roffset

include <szpixtype.inc>

begin
	fit = chan
	im = FIT_IM(fit)
	FIT_IOSTAT(fit) = OK

	totpix = IM_PHYSLEN(im,1)
	do i = 2, IM_NPHYSDIM(im)
	    totpix = totpix * IM_PHYSLEN(im,i)

	if (FIT_ZCNV(fit) == YES) {
	    if (FIT_PIXTYPE(fit) != TY_REAL && FIT_PIXTYPE(fit) != TY_DOUBLE) {
	       call fxf_cnvpx (im, totpix, obuf, nbytes, boffset)
	       return
	    } 
	}

	pixtype = IM_PIXTYPE(im)
	datasizeb = totpix * (pix_size[pixtype] * SZB_CHAR)
	pixoffb = (FIT_PIXOFF(fit) - 1) * SZB_CHAR + 1

	# We can read the data directly into the caller's output buffer as 
	# any FITS kernel input conversions are guaranteed to not make the
	# data smaller.  

	call zardbf (FIT_IO(fit), obuf, nbytes, boffset)
	call zawtbf (FIT_IO(fit), status)
	if (status == ERR) {
	    FIT_IOSTAT(fit) = ERR
	    return
	}

	### boffset is 1-indexed, so one would expect (boffset/SZB_CHAR) to
	### be ((boffset - 1) * SZB_CHAR + 1).  This is off by one from what
	### is being calculated, so if PIXOFF and boffset point to the same
	### place IP will be one, which happens to be the correct array index. 
	### Nonehtless expressions like this should be written out so that
	### they can be verified easily by reading them.  Any modern compiler
	### will optimize the expression, we don't have to do this in the
	### source code.

	ip = FIT_PIXOFF(fit) - boffset/SZB_CHAR
	if (ip <= 0)
	    ip = 1

	nb_skipped = boffset - pixoffb
	if (nb_skipped <= 0)
	    nb = min (status + nb_skipped, datasizeb)
	else
	    nb = min (status, datasizeb - nb_skipped)
	npix = max (0, nb / (pix_size[pixtype] * SZB_CHAR))

	if (FIT_ZCNV(fit) == YES) {
	    if (FIT_PIXTYPE(fit) == TY_REAL) {
		# This is for scaling -32 (should not be allowed)
		call fxf_zaltrr(obuf[ip], npix, FIT_BSCALE(fit), FIT_BZERO(fit))
            } else if (FIT_PIXTYPE(fit) == TY_DOUBLE) {
	        # This is for scaling -64 data (should not be allowed)
		call fxf_zaltrd(obuf[ip], npix, FIT_BSCALE(fit), FIT_BZERO(fit))
            }	    
        } else {
	   call fxf_unpack_data (obuf[ip],
	       npix, pixtype, FIT_BSCALE(fit), FIT_BZERO(fit)) 
        }
end

procedure fxf_zaltrr (data, npix, bscale, bzero)

real data[ARB], rt
int    npix
double bscale, bzero

int i

begin
	call ieevupkr (data, data, npix)
        do i = 1, npix {
	   data[i] = data[i] * bscale + bzero
        }
end


procedure fxf_zaltrd (data, npix, bscale, bzero)

double data[ARB]
int    npix
double bscale, bzero

int i

begin
	call ieevupkd (data, data, npix)
        do i = 1, npix
	   data[i] = data[i] * bscale + bzero
end


 
# FXFZWR -- Write to the output file. 

procedure fxfzwr (chan, ibuf, nbytes, boffset)

int	chan			#I QPF i/o channel
char	ibuf[ARB]		#O data buffer
int	nbytes			#I nbytes to be written
int	boffset			#I file offset

pointer fit, im, sp, obuf
bool	noconvert, lscale, lzero, bfloat
int	ip, op, pixtype, npix, totpix, nb, nchars, i
int	datasizeb, pixoffb, nb_skipped, obufsize

bool	fxf_fpl_equald()

include	<szpixtype.inc>

begin
	fit = chan
	im = FIT_IM(fit)
	FIT_IOSTAT(fit) = OK

	# We don't have to pack the data if it is integer and we don't need
	# to byte swap; the data buffer can be written directly out.


	# Determine if we are writing into an scaled floating point data
	# unit; i.e. bitpix > 0 and BSCALE or/and BZERO with non default
	# values.  This is an error since we are not supporting this
	# combination for writing at this time.

	lscale = fxf_fpl_equald (1.0d0, FIT_BSCALE(fit), 1)
	lzero =  fxf_fpl_equald (0.0d0, FIT_BZERO(fit), 1)

	# Determine if scaling is necessary.
	bfloat = (!lscale || !lzero)
	if (bfloat &&
		(IM_PIXTYPE(im) == TY_REAL || IM_PIXTYPE(im) == TY_DOUBLE)) {
	    FIT_IOSTAT(fit) = ERR
	    return
	}

	pixtype = IM_PIXTYPE(im)
	noconvert = ((pixtype == TY_SHORT && BYTE_SWAP2 == NO) ||
	    ((pixtype == TY_INT || pixtype == TY_LONG) && BYTE_SWAP4 == NO))

	if (noconvert) {
	    call zawrbf (FIT_IO(fit), ibuf, nbytes, boffset)
	    return
	}

	# Writing pixel data to an image is currently illegal if on-the-fly
	# conversion is in effect, as on-the-fly conversion is currently only
	# available for reading.

	if (FIT_ZCNV(fit) == YES) {
	    FIT_IOSTAT(fit) = ERR
	    return
        }		

	totpix = IM_PHYSLEN(im,1)
	do i = 2, IM_NPHYSDIM(im)
	    totpix = totpix * IM_PHYSLEN(im,i)

	datasizeb = totpix * (pix_size[pixtype] * SZB_CHAR)
	pixoffb = (FIT_PIXOFF(fit) - 1) * SZB_CHAR + 1

	### Same comments as for fxfzrd apply here.
	### There doesn't appear to be any support here for byte data like
	### in fxfzwr.  This must mean that byte images are read-only.
	### This shouldn't be necessary, but we shouldn't try to do anything
	### about it until the fxf_byte_short issue is addressed.

	ip = FIT_PIXOFF(fit) - boffset / SZB_CHAR
	if (ip <= 0)
	    ip = 1

	nb_skipped = boffset - pixoffb
	if (nb_skipped <= 0)
	    nb = min (nbytes + nb_skipped, datasizeb)
	else
	    nb = min (nbytes, datasizeb - nb_skipped)
	npix = max (0, nb / (pix_size[pixtype] * SZB_CHAR))

	if (npix == 0) 
	    return

	# We don't do scaling (e.g. BSCALE/BZERO) when writing.  All the
	# generated FITS files in this interface are ieee fits standard.
	### I didn't look into it but I don't understand this; when accessing
	### a BSCALE image read-write, it should be necessary to scale both
	### when reading and writing if the application sees TY_REAL pixels.
	### When writing a new image I suppose the application would take
	### care of any scaling.

	# Convert any pixel data in the input buffer to the binary format
	# required for FITS and write it out.  Any non-pixel data in the
	# buffer should be left as-is.

	obufsize = (nbytes + SZB_CHAR-1) / SZB_CHAR

	call smark (sp)
	call salloc (obuf, obufsize, TY_CHAR)

	# Preserve any leading non-pixel data.
	op = 1
	if (ip > 1) {
	    nchars = min (obufsize, ip - 1) 
	    call amovc (ibuf[1], Memc[obuf], nchars)
	    op = op + nchars
	}

	# Convert and output the pixels.
	call fxf_pak_data (ibuf[ip], Memc[obuf+op-1], npix, pixtype)
	op = op + npix * pix_size[pixtype]

	# Preserve any remaining non-pixel data.
	nchars = obufsize - op + 1
	if (nchars > 0)
	    call amovc (ibuf[op], Memc[obuf+op-1], nchars)

	# Write out the data.
	call zawrbf (FIT_IO(fit), Memc[obuf], nbytes, boffset)

	call sfree (sp)
end


# FXFZWT -- Return the number of bytes transferred in the last i/o request.

procedure fxfzwt (chan, status)

int	chan			#I QPF i/o channel
int	status			#O i/o channel status

pointer fit, im

begin
	fit = chan
	im = FIT_IM(fit)

	# A file driver returns status for i/o only in the AWAIT routine;
	# hence any i/o errors occurring in the FK itself are indicated by
	# setting FIT_IOSTAT.  Otherwise the actual i/o operation must have
	# been submitted, and we call zawtbf to wait for i/o, and get status.

	if (FIT_IOSTAT(fit) != OK)
	    status = FIT_IOSTAT(fit)
	else
	    call zawtbf (FIT_IO(fit), status)

	# FIT_ZBYTES has the correct number of logical bytes that need
	# to be passed to fio since we are expanding the buffer size
	# from byte to short or real and short to real.

	if (status > 0) {
	    if (FIT_PIXTYPE(fit) == TY_UBYTE)
		status = FIT_ZBYTES(fit)
	    else if (FIT_PIXTYPE(fit) == TY_SHORT && IM_PIXTYPE(im) == TY_REAL)
		status = FIT_ZBYTES(fit)
	}
end


# FXFZST -- Query device/file parameters.

procedure fxfzst (chan, param, value)

int	chan			#I FIT i/o channel
int	param			#I parameter to be returned
int	value			#O parameter value

pointer fit, im
int	i, totpix, szb_pixel, szb_real

include	<szpixtype.inc>

begin
	fit = chan
	im = FIT_IM(fit)

    	totpix = IM_PHYSLEN(im,1)
	do i = 2, IM_NPHYSDIM(im)
	    totpix = totpix * IM_PHYSLEN(im,i)

        szb_pixel = pix_size[IM_PIXTYPE(im)] * SZB_CHAR
	szb_real = SZ_REAL * SZB_CHAR

	call zsttbf (FIT_IO(fit), param, value)

	if (param == FSTT_FILSIZE) {
	    switch (FIT_PIXTYPE(fit)) {
	    case TY_SHORT:
		if (IM_PIXTYPE(im) == TY_REAL) {
		    value = value + int ((totpix * SZ_SHORT * SZB_CHAR) /
			2880. + .5) * 2880
		}
	    case TY_UBYTE:
		if (IM_PIXTYPE(im) == TY_SHORT)
		    value = value + int (totpix/2880. + 0.5)*2880
	        else if (IM_PIXTYPE(im) == TY_REAL)
		    value = value + int(totpix*(szb_real-1)/2880. + 0.5) * 2880
            }
	}
end


# FXF_CNVPX -- Convert FITS type BITPIX = 8 to SHORT or REAL depending
# on the value of BSCALE, BZERO (1, 32768 is already iraf supported as ushort
# and is not treated in here). If BITPIX=16 and BSCALE and BZERO are 
# non-default then the pixels are converted to REAL.

procedure fxf_cnvpx (im, totpix, obuf, nbytes, boffset)

pointer im			#I Image descriptor
int	totpix			#I Total number of pixels		
char    obuf[ARB]		#O Output data buffer
int	nbytes			#I Size in bytes of the output buffer
int	boffset			#I Byte offset into the virtual image

pointer sp, buf, fit, op
double	bscale, bzero
int	ip, nelem, pfactor
int	pixtype, nb, buf_size, bzoff, nboff
int	status, offset, npix
int	datasizeb, pixoffb, nb_skipped

include	<szpixtype.inc>

begin
	fit = IM_KDES(im)
	bscale = FIT_BSCALE(fit)
	bzero  = FIT_BZERO(fit)

	ip = FIT_PIXOFF(fit) - boffset/SZB_CHAR
	if (ip <= 0)
	    ip = 1

	# The beginning of the data portion in bytes.
	pixoffb = (FIT_PIXOFF(fit)-1) * SZB_CHAR + 1
	
	# Determine the factor to applied: size(im_pixtype)/size(fit_pixtype)
	if (FIT_PIXTYPE(fit) == TY_UBYTE) {
	    if (IM_PIXTYPE(im) == TY_REAL)
		pfactor = SZ_REAL * SZB_CHAR
	    else  					# TY_SHORT
		pfactor = SZB_CHAR
	    datasizeb = totpix
	} else if (FIT_PIXTYPE(fit) == TY_SHORT) {
	    pfactor = SZ_REAL / SZ_SHORT
	    pixtype = TY_SHORT
	    datasizeb = totpix * (pix_size[pixtype] * SZB_CHAR)
	} else {
	    FIT_IOSTAT(fit) = ERR
	    return
	}

	# We need to map the virtual image of type im_pixtype to the actual
	# file of type fit_pixtype. 'nbytes' is the number of bytes to read
	# from the virtual image. To find out how many fit_pixtype bytes 
	# we need to read from disk we need to subtract the FITS
	# header size (if boffset is 1) from nbytes and then divide
	# the resultant value by the convertion factor.
	# We then add the size of the header if necessary.

	# Determine the offset into the pixel area.
	nboff = boffset - pixoffb
	if (nboff > 0) {
	    nelem = nboff / pfactor
	    offset = nelem + pixoffb
	} else  {
	    # Keep the 1st boffset.
	    bzoff = boffset
	    offset = boffset
	}

	# Calculates the number of elements to convert. We keep the offset from
	# the beginning of the unit (bzoff) and not from file's 1st byte.

	nelem = nbytes - (pixoffb - bzoff + 1)
	nelem = nelem / pfactor
	buf_size = nelem + (pixoffb - bzoff + 1)
	if (buf_size*pfactor > nbytes && ip == 1)
	    buf_size = (nbytes - 1) / pfactor + 1 

	# Allocate space for TY_SHORT
	call smark(sp)
	call salloc (buf, buf_size/SZB_CHAR, TY_SHORT)
	    
	call zardbf (FIT_IO(fit), Mems[buf], buf_size, offset)
	call zawtbf (FIT_IO(fit), status)
	if (status == ERR) {
	    FIT_IOSTAT(fit) = ERR
	    call sfree (sp)
	    return
	}
	    
	# Map the number of bytes of datatype FIT_PIXTYPE to 
	# IM_PIXTYPE for use in zfxfwt().
	     
	if (status*pfactor >= nbytes)
	    FIT_ZBYTES(fit) = nbytes
	else
	    FIT_ZBYTES(fit) = status * pfactor

	nb_skipped = offset - pixoffb
	if (nb_skipped <= 0)
	    nb = min (status + nb_skipped, datasizeb)
	else
	    nb = min (status, datasizeb - nb_skipped)

	switch (FIT_PIXTYPE(fit)) {
	case TY_UBYTE:
	    npix = max (0, nb)
	    if (IM_PIXTYPE(im) == TY_SHORT)
		call achtbs (Mems[buf+ip-1], obuf[ip], npix)
	    else {
		# Scaled from byte to REAL.
		call achtbl (Mems[buf+ip-1], obuf[ip], npix)
		call fxf_altmr (obuf[ip], obuf[ip], npix, bscale, bzero)
	    }
	case TY_SHORT:
	    op = buf + ip - 1
	    npix = max (0, nb / (pix_size[pixtype] * SZB_CHAR))
	    if (BYTE_SWAP2 == YES)
		call bswap2 (Mems[op], 1, Mems[op], 1, npix*SZB_CHAR)
	    call fxf_astmr (Mems[op], obuf[ip], npix, bscale, bzero)
	}

	call sfree (sp)
end