;+ ; NAME: ; bin_read ; PURPOSE: ; Read 2D array from binary file ; CALLING SEQUENCE: FUNCTION bin_read, InFile, Array, $ errormessage = errormessage , $ type = type , $ eor = eor , $ bor = bor , $ silent = silent , $ ramdisk = ramdisk , $ nx = nX , $ twod = twod , $ block = block , $ dimonly = dimonly , $ sizeonly = sizeonly , $ unix = unix , $ drop = drop , $ header = header , $ trailer = trailer ; status = bin_read(File, Array, errormessage=errormessage) ; INPUTS: ; File string file name ; OPTIONAL INPUT PARAMETERS: ; type=type scalar; type: integer ; type code for returned array (see href=IsType=) ; If not set then type=2 (short integer is assumed) ; header=header ; scalar; type: integer; default: 0 ; # bytes at start of files preceding the data array ; (these are skipped when reading the data). ; If the file extension is .pph or .nic then ; this keyword is ignored. ; /eor if set, the last column of the array is discarded ; (useful for reading binary files containing a CR at ; the end of each record). ; /bor if set, the first two bytes and the last two bytes ; of each record are discarded ; (some binary VAX files contain 2 bytes of leading ; and trailing garbage???). ; nx=nX used to fix the first dimension of the output array ; /twod reads a 2D array with nX=nY (ignored if nX is used) ; /block ignores the recordlength if its 512 bytes (1 VMS block) ; /sizeonly returns dimensions of the array (NOT the array itself, ; i.e. the file is NOT read) ; /unix forces a call to IEEE_TO_HOST ; OUTPUTS: ; status 0: some error occurred (check 'errormessage') ; 1: file properly read ; Array array[n,m] ; 2D array of requested type ; if something goes wrong Array = -1 is returned ; OPTIONAL OUTPUT PARAMETERS: ; errormessage ; scalar; type: string ; Contains null string if file was read succesfully ; Contains error message if an error occurred ; trailer array; type: byte ; if any data are found after the data area, then these ; trailing data are returned here as a byte array. ; INCLUDE: @compile_opt.pro ; On error, return to caller ; CALLS: ; InitVar, IsType, SetFileSpec, GetFileSpec, gunzip_file, do_file ; PROCEDURE: ; > The FSTAT is function is used to determine the array dimensions from ; file size and record length. ; > The /block keyword should be used to read files created with the /block ; keyword on the open statement. ; > Several file types are recognized as special types and don't require ; any further keywords: ; *.pph contain a header with a valid size vector ; *.nic files from the SMEI camera ; MODIFICATION HISTORY: ; JAN-1995, Paul Hick (UCSD/CASS) ; MAR-2003, Paul Hick (UCSD/CASS) ; Trailer is now output as a byte array, instead of a string scalar ; (the conversion string_trailer = string(byte_trailer) could destroy ; a binary trailer). ; APR-2003, Paul Hick (UCSD/CASS) ; Added check for .gz file (by calling gunzip_file). ; Added check on 3rd element in header (# bytes per number) to ; distinguish between short int (2), long int (4) and float (-4). ; SEP-2003, Paul Hick (UCSD/CASS) ; Renamed sbinarr to bin_read. ; JUL-2004, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Added /ramdisk keyword ;- InitVar, eor , /key InitVar, bor , /key InitVar, twod , /key InitVar, block , /key InitVar, dimonly , /key InitVar, sizeonly, /key InitVar, unix , /key InitVar, silent , 0 fi = (file_search(InFile))[0] ; If file found then unzip if necessary. ; If file not found try adding .gz extension. gzipped = gunzip_file(InFile+(['','.gz'])[fi eq ''], rawfile, $ check=fi eq '',isgz=isgz, ramdisk=ramdisk) CASE gzipped OF 0: IF isgz THEN fi = '' 1: fi = rawfile ENDCASE status = 0 IF fi EQ '' THEN BEGIN errormessage = 'file not found or unzip error: '+InFile goto, EARLY_RETURN ENDIF openr, /get_lun, iu, fi, error=i ; Open file read only IF i NE 0 THEN BEGIN errormessage = !error_state.msg ; Open error goto, EARLY_RETURN ENDIF xd = fstat(iu) fsize = xd.size ; File size in bytes frecl = xd.rec_len IF fsize EQ 0 THEN BEGIN errormessage = 'zero-length: '+fi goto, EARLY_RETURN ENDIF SetFileSpec, fi ; The files from the SMEI camera (file=*.NIC) have a six byte header. ; The first four bytes contain the image dimensions. These are explicitly ; read to set the array dimension. There also may be a trailer, so we ; can't use the file size to calculate nY. CASE strlowcase( GetFileSpec(part='type') ) OF ; For now .raw files are assumed to be .nic files. '.raw': BEGIN header = 6 ; Length of header in bytes sz = intarr(3) readu, iu, sz ; Read header sz = long(sz) ; Build a valid IDL 'size' vector CASE sz[2] OF 2: sz_type = IsType(/unsigned_short, bytes=bytes, name=name) 4: sz_type = IsType(/long , bytes=bytes, name=name) -4: sz_type = IsType(/float, bytes=bytes, name=name) ENDCASE sz = [2L, sz[0:1], sz_type, sz[0]*sz[1]] ntrailer = fsize-header-sz[sz[0]+2]*bytes END ; Length of trailer (should always be 512) '.nic': BEGIN header = 6 ; Length of header in bytes sz = intarr(3) readu, iu, sz ; Read header sz = long(sz) ; Build a valid IDL 'size' vector CASE sz[2] OF 2: sz_type = IsType(/unsigned_short, bytes=bytes, name=name) 4: sz_type = IsType(/long , bytes=bytes, name=name) -4: sz_type = IsType(/float, bytes=bytes, name=name) ENDCASE sz = [2L, sz[0:1], sz_type, sz[0]*sz[1]] ntrailer = fsize-header-sz[sz[0]+2]*bytes END ; Length of trailer (should always be 512) '.pph': BEGIN ; Header is IDL 'size' vector n = 0L readu, iu, n ; # dimensions sz = lonarr(n+2) readu, iu, sz ; Read rest of 'size' vector sz = [n, sz] ; Valid IDL 'size' vector header = 4*n_elements(sz) ; # bytes in header ntrailer = IsType(make_array(1, type=sz[sz[0]+1]), bytes=bytes, name=name) ntrailer = fsize-header-sz[sz[0]+2]*bytes END ELSE: BEGIN InitVar, header, 0 InitVar, type , IsType(0) ntrailer = 0 sz = [2L,-1L,-1L,IsType(make_array(1, type=type), bytes=bytes, name=name),-1L] if IsType(nX, /defined) then sz[1] = nX if header ne 0 then point_lun, iu, header END ; Set pointer to begin of data area ENDCASE fsize = fsize-header ; Size data area IF silent LE 0 THEN message, /info, fi+', size minus header:'+strcompress(fsize) brec = 0B CASE frecl OF ; Record length in bytes 0 : BEGIN xd = 1B point_lun, -iu, i readu, iu, xd point_lun, -iu, recl recl = recl-i point_lun, iu, header ; Rewind the file brec = recl NE 1 IF NOT brec THEN recl = fsize END 512 : IF block THEN recl = fsize ELSE recl = frecl ELSE: recl = frecl ENDCASE CASE sz[1] OF -1: begin sz[1] = recl/bytes IF twod THEN sz[1:2] = sqrt(sz[1]) END ELSE: recl = sz[1]*bytes ENDCASE IF sz[2] EQ -1 THEN sz[2] = fsize/(sz[1]*bytes) IF sz[1] LE eor OR sz[2] LE 0 THEN BEGIN errormessage = 'empty ?: '+fi goto, EARLY_RETURN ENDIF status = 1 errormessage = '' sz[1] = sz[1]-bor IF dimonly THEN BEGIN Array = sz[1:sz[0]] goto, EARLY_RETURN ENDIF IF sizeonly THEN BEGIN status = 1 Array = sz goto, EARLY_RETURN ENDIF on_ioerror, IOERROR ; Establish IO error handler IF sz[2]*(sz[1]+bor)*bytes LT fsize THEN BEGIN IF IsType(drop,/defined) THEN BEGIN point_lun, -iu, i point_lun, iu, i+drop ENDIF ENDIF Array = make_array(/nozero, size=sz) CASE brec OF 0: BEGIN readu, iu, Array IF ntrailer NE 0 THEN BEGIN trailer = bytarr(ntrailer) readu, iu, trailer ENDIF END 1: BEGIN xd = Array[*,0] yd = 0 ; To remove 2 leading bytes FOR i=0,sz[2]-1 DO BEGIN CASE bor OF 0: readu, iu, xd 1: readu, iu, yd, xd ENDCASE Array[*,i] = xd ENDFOR END ENDCASE on_ioerror, NULL IF eor THEN BEGIN sz[1] = sz[1]-1 Array = Array[0:sz[1]-1,*] ENDIF IF unix THEN ieee_to_host, Array IF silent LE 0 THEN message, /info, 'Created '+name+ $ ' array A('+strjoin(strcompress(sz[1:sz[0]], /rem),',')+')' EARLY_RETURN: IF IsType(iu, /defined) THEN free_lun, iu IF NOT status THEN BEGIN IF silent LE 0 THEN message, /info, errormessage Array = -1 ENDIF IF gzipped THEN i = do_file(/delete, rawfile, silent=silent) RETURN, status IOERROR: ; I/O error label free_lun, iu on_ioerror, NULL status = 0 Array = -1 errormessage = !error_state.msg IF silent LE 0 THEN message, /info, errormessage IF gzipped THEN i = do_file(/delete, rawfile, silent=silent) RETURN, status & END