;;---------------------------------------------------------------------------- ;; Name: VERIFY_TABLE ;; ;; Purpose: To verify a PDS TABLE object. ;; ;; Calling Sequence: ;; result = verify_table (label) ;; ;; Input: ;; label - a string array containing PDS header. ;; ;; Output: ;; result - the routine returns 1 if there are no errors in label. ;; The routine outputs an error message if there are any errors ;; found in the PDS label for TABLE objects. ;; ;; Optional inputs: none. ;; ;; External routines: Pdspar, Clean, Remove, Extract_keyword, ;; Test_integer, Get_index, Break_string ;; ;; Modification history: ;; Written by Puneet Khetarpal, 30 June 2005 ;; 12 Feb 08, HJJ: Fixed ITEM bytes error message. ;; Fixed byte count error for tables ending with a ;; character column. ;; ;;---------------------------------------------------------------------------- ;- level 2 ------------------------------------------------------------------- ; precondition: the label has all required table keywords, byte_count is ; passed in by reference and keeps track of the bytes of columns ; postcondition: the current column object is verified for required keywords pro check_column_required, label, startind, endind, byte_count, row_bytes, $ DIFF=diff, DATA_TYPE=data_type ; error check on_error, 1 ; check for NAME keyword name = extract_keyword(label, 'NAME', startind, endind, 1) ; check for DATA_TYPE keyword data_type = extract_keyword(label, 'DATA_TYPE', startind, endind, 1) data_type = remove(data_type, '"') ; remove quotes ; declare viable data_type keyword values datarange = ["ASCII_COMPLEX","ASCII_INTEGER","ASCII_REAL","BIT_STRING", $ "BINARY_CODED_DECIMAL","BOOLEAN","CHARACTER","COMPLEX","DATE","FLOAT", $ "EBCDIC_CHARACTER","IBM_COMPLEX","IBM_INTEGER","IBM_REAL","IEEE_REAL", $ "IBM_UNSIGNED_INTEGER","IEEE_COMPLEX","INTEGER","LSB_BIT_STRING","N/A", $ "LSB_INTEGER","LSB_UNSIGNED_INTEGER","MAC_INTEGER","MAC_REAL","PC_REAL",$ "MAC_UNSIGNED_INTEGER","MSB_BIT_STRING","MSB_INTEGER","PC_COMPLEX", $ "MSB_UNSIGNED_INTEGER","PC_INTEGER","PC_UNSIGNED_INTEGER","SUN_COMPLEX",$ "REAL","SUN_INTEGER","SUN_REAL","SUN_UNSIGNED_INTEGER","TIME","VAX_REAL",$ "UNSIGNED_INTEGER","VAXG_COMPLEX","VAXG_REAL","VAX_BIT_STRING", $ "VAX_COMPLEX","VAX_DOUBLE","VAX_INTEGER","VAX_UNSIGNED_INTEGER"] ; check if specified value is viable pos = where(stregex(datarange, data_type, /boolean) eq 1, matches) if (matches eq 0) then begin ; if not, then issue error message, "Error: invalid DATA_TYPE value found - " + data_type endif ; check for START_BYTE keyword start_byte = extract_keyword(label, 'START_BYTE', startind, endind, 1) test_integer, 'START_BYTE', start_byte, 1, row_bytes ; test for integer ; if startbyte for current COLUMN is in the field of previous column if (long(start_byte) le byte_count) then begin ; issue error message, "Error: You N'wah! Interleaved COLUMN objects currently " + $ "not supported." endif else if (long(start_byte) gt byte_count + 1) then begin ; if there is a buffer between current column and previous column diff = long(start_byte) - byte_count - 1 ; compute the difference byte_count += diff ; and add to byte count endif end ; precondition: the required keywords have been checked for the current ; COLUMN object. ; postcondition: the optional items keywords are verified including BYTES pro check_column_items, label, startind, endind, byte_count ; error check on_error, 1 ; variable for required bytes keyword req = 0 ; default to optional for now total_bytes = 0 ; for items if present ; first check whether there are any ITEMS keywords items = extract_keyword(label, 'ITEMS', startind, endind, 0) if (items eq '###~') then begin ; if no ITEMS keyword, then BYTES req req++ ; make bytes keyword required endif else begin test_integer, 'ITEMS', items, 1 ;; check for ITEM_OFFSET keyword [bytes from start of 1 item ;; to next] item_offset = extract_keyword(label,'ITEM_OFFSET', startind, endind,0) if (item_offset eq '###~') then begin item_offset = 0 ; set item offset to 0, if not found endif else begin ; else test for viability test_integer, 'ITEM_OFFSET', item_offset, 1 endelse ; check for ITEM_BYTES keyword item_bytes = extract_keyword(label, 'ITEM_BYTES', startind, endind, 1) test_integer, 'ITEM_BYTES', item_bytes, 1 ; compute total bytes for items if (item_offset eq 0) then begin ; if no offset then total is total_bytes = long(items) * long(item_bytes) ; items * itembytes endif else begin ; else total is (items - 1 * offset) + itembytes ; since item offset applies to bytes from start of item 1 to ; next, so does not apply to last item in the series, ; so items - 1 and not items * offset. total_bytes = ((long(items) - 1) * item_offset) + long(item_bytes) endelse byte_count += total_bytes ; add total bytes to byte count endelse ; extract bytes whether required or not bytes = extract_keyword(label, 'BYTES', startind, endind, req) if (bytes ne '###~') then begin ; if present then test_integer, 'BYTES', bytes, 1 ; test for integer ; if not required and bytes != total item bytes if (~ req && bytes ne total_bytes) then begin ; issue error message, "Error: BYTES value ("+bytes+") inconsistent with total"+$ " ITEM bytes (" + STRTRIM(total_bytes,2) + ")" endif else if (req) then begin ; else if bytes is required byte_count += long(bytes) ; add to byte count endif endif end ; precondition: the column has been tested for items and bytes ; postcondition: the other optional keywords are tested pro check_column_optional, label, startind, endind, columns ; error check on_error, 1 ; check for BIT_MASK keyword bit_mask = extract_keyword(label, 'BIT_MASK', startind, endind, 0) if (bit_mask ne '###~') && $ (~ stregex(bit_mask, '2#[01]+#', /boolean)) then begin ; check format message, "Error: BIT_MASK value invalid - " + bit_mask endif ; check for COLUMN_NUMBER keyword col_num = extract_keyword(label, 'COLUMN_NUMBER', startind, endind, 0) if (col_num ne '###~') then begin test_integer, 'COLUMN_NUMBER', col_num, 1, columns endif ; check for FORMAT keyword format = extract_keyword(label, 'FORMAT', startind, endind, 0) if (format ne '###~') then begin expr = '[0-9]*\(?[AFDEGI][0-9]+\.?[0-9]*\)?' if (~ stregex(format, expr, /boolean)) then begin message, "Error: invalid FORMAT value specified - " + format endif endif end ;- level 1 ------------------------------------------------------------------- ; precondition: label contains table object definitions; startindex ; and endindex are both viable ; postcondition: the required keywords for current table object are tested function check_table_required, label, startind, endind ; error check on_error, 1 ; check INTERCHANGE_FORMAT keyword inter_form = extract_keyword(label,'INTERCHANGE_FORMAT',startind,endind, 1) inter_form = remove(inter_form, '"') if (inter_form ne "ASCII" && inter_form ne "BINARY") then begin message, "Error: invalid INTERCHANGE_FORMAT value found " + inter_form endif ; check ROWS keyword rows = extract_keyword(label, 'ROWS', startind, endind, 1) test_integer, 'ROWS', rows, 0 if (long(rows) eq 0) then return, long(rows) ; check COLUMNS keyword columns = extract_keyword(label, 'COLUMNS', startind, endind, 1) test_integer, 'COLUMNS', columns, 1 ; check ROW_BYTES keyword row_bytes = extract_keyword(label, 'ROW_BYTES', startind, endind, 1) test_integer, 'ROW_BYTES', row_bytes, 1 return, long(rows) end ; precondition: label has been verified for required keywords, and ; start and endindex are viable ; postcondition: the optional keywords are verified pro check_table_optional, label, startind, endind ; error check on_error, 1 ; check ROW_PREFIX_BYTES keyword row_prefix = extract_keyword(label, 'ROW_PREFIX_BYTES', startind, endind,0) if (row_prefix ne '###~') then begin test_integer, 'ROW_PREFIX_BYTES', row_prefix, 0 endif ; check ROW_SUFFIX_BYTES keyword row_suffix = extract_keyword(label, 'ROW_SUFFIX_BYTES', startind, endind,0) if (row_suffix ne '###~') then begin test_integer, 'ROW_SUFFIX_BYTES', row_suffix, 0 endif ; check for TABLE_STORAGE_TYPE keyword storage = extract_keyword(label, 'TABLE_STORAGE_TYPE', startind, endind, 0) if (storage ne '###~') then begin storage = remove(storage, '"') if (storage ne "COLUMN MAJOR" && storage ne "ROW MAJOR") then begin message, "Error: invalid TABLE_STORAGE_TYPE value " + storage endif endif end ; precondition: the label has non-zero table objects ; postcondition: the column objects for current table objects are processed pro check_column_objects, label, startind, endind ; error check on_error, 1 ; extract COLUMNS and ROW_BYTES keyword value columns = extract_keyword(label, 'COLUMNS', startind, endind, 1) row_bytes = extract_keyword(label,'ROW_BYTES',startind, endind, 1) row_prefix = extract_keyword(label, 'ROW_PREFIX_BYTES',startind,endind,0) row_prefix = (row_prefix eq '###~') ? 0L : long(row_prefix) row_suffix = extract_keyword(label, 'ROW_SUFFIX_BYTES',startind,endind,0) row_suffix = (row_suffix eq '###~') ? 0L : long(row_suffix) rec_bytes = extract_keyword(label, 'RECORD_BYTES', 0, endind, 1) ; extract all column objects within current table objects = pdspar(label, 'OBJECT', COUNT=objcnt, INDEX=objindx) objects = strtrim(objects, 2) ;; get position in index array of column objects within table range pos = where(stregex(objects, 'COLUMN$', /boolean) eq 1 and objindx ge $ startind and objindx le endind, matches) if (matches eq 0) then begin ; if none found then issue error message, "Error: TABLE object must contain at least one COLUMN object." endif else if (matches ne long(columns)) then begin ; if != cols, err message, "Error: Too few COLUMN objects found in label. Must be "+$ columns + " but are " + clean(string(matches), /space) endif col_obj = objects[pos] ; store column object names col_ind = objindx[pos] ; store column object indices col_cnt = matches ; store number of column objects ; initialize byte counter to keep track of the fields byte count byte_count = 0 ; go through all the column objects and verify for j = 0, col_cnt - 1 do begin ; get endindex for current column object endindex = get_index(label, col_ind[j]) ; verify required keywords check_column_required, label, col_ind[j],endindex,byte_count,row_bytes, $ DIFF=diff, DATA_TYPE=data_type ; verify optional items keywords along with BYTES keyword check_column_items, label, col_ind[j], endindex, byte_count ; verify other optional keywords check_column_optional, label, col_ind[j], endindex, col_cnt endfor ; if interchange format is ASCII then add crlf to bytes count inter = extract_keyword(label, 'INTERCHANGE_FORMAT', startind, endind, 1) ; byte_count += (inter eq 'ASCII' && row_suffix eq 0) ? 2 : 0 IF (inter EQ 'ASCII' && row_suffix EQ 0) THEN BEGIN ; fix for character fields when last column (diff > 1) IF (data_type EQ 'CHARACTER') AND (diff GT 1) THEN $ byte_count += diff - 1 byte_count += 2 ENDIF ;; check rowbytes = bytecount if (long(row_bytes) ne byte_count) then begin message, "Error: ROW_BYTES ("+row_bytes+") does not equal " + $ "actual total COLUMN bytes ("+clean(string(byte_count),/space)+")" endif end ;- level 0 ------------------------------------------------------------------- function verify_table, label ; error check on_error, 1 ; return to main level ; extract all object keywords objects = pdspar(label, 'OBJECT', COUNT=objcnt, INDEX=objindx) objects = strtrim(objects, 2) pos = where(stregex(objects, '(TABLE$)|(SERIES$)|(SPECTRUM$)|(PALETTE$)', $ /boolean) eq 1, matches) if (matches eq 0) then return, 1 ;; select table/series/spectrum/palette objects from all the objects objects = objects[pos] index = objindx[pos] count = matches ; check for each object for i = 0, count - 1 do begin ;; determine the end index for current object endindex = get_index(label, index[i]) ; verify required keywords rows = check_table_required(label, index[i], endindex) if (rows eq 0) then continue ; if no rows of data, then next iteration ; verify optional keywords check_table_optional, label, index[i], endindex ; verify column objects check_column_objects, label, index[i], endindex endfor return, 1 end