
/*
 *  NXdump: Dump contents of HDF (hierarchical data format) 
 *          file using the NEXUS API
 *
 *  Author: N. Maliszewskyj, NIST Center for Neutron Research, June 1997
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <mfhdf.h>
#include "napi.h"

#define INDENT_AMOUNT " "

char *
type2s(uint type){
  static char unknownType[40];

  switch (type){
  case DFNT_NONE:       return "DFNT_NONE"; 
  case DFNT_FLOAT32:    return "DFNT_FLOAT32"; 
  case DFNT_FLOAT64:    return "DFNT_FLOAT64"; 
  case DFNT_INT8:       return "DFNT_INT8"; 
  case DFNT_UINT8:      return "DFNT_UINT8"; 
  case DFNT_INT16:      return "DFNT_INT16"; 
  case DFNT_UINT16:     return "DFNT_UINT16"; 
  case DFNT_INT32:      return "DFNT_INT32"; 
  case DFNT_UINT32:     return "DFNT_UINT32"; 
  }

  return "Unsupported!";
}


int dumpAttr(NXhandle NXdat, char * parent, char * indent) {
  int length, itype;
  char name[VGNAMELENMAX], *data;
  NXstatus NXstat;

  while((NXstat = NXgetnextattr(NXdat, name, &length, &itype)) != NX_EOD) {
    data = (char *) malloc(length + 1);
    NXstat = NXgetattr(NXdat, name, data, length);
    data[length] = 0;
    printf("%s%s:%s=%s\n",indent,parent,name,data);
  }
  return 0;
}


int dumpSDS(NXhandle NXdat, char * name, char * indent) {
  char new_indent[80];
  int rank, dims[MAX_VAR_DIMS], datatype,i;
  NXstatus NXstat;

  strcpy(new_indent,indent); strcat(new_indent,INDENT_AMOUNT);
  NXstat = NXopendata(NXdat, name);
  NXstat = NXgetinfo(NXdat, &rank, dims, &datatype);

  printf("%sSD %s (datatype=%s, rank=%d, dimensions=%d",new_indent, 
         name, type2s(datatype), rank, dims[0]);
  if (rank > 1) {
    for (i=1;i<rank;i++) printf("X%d",dims[i]);
  }
  printf(")\n");

  NXstat = dumpAttr(NXdat, name, new_indent); 
  NXstat = NXclosedata(NXdat);
  return 0;
}


int dumpVG(NXhandle NXdat, char * indent) {
  char name[VGNAMELENMAX],class[VGNAMELENMAX],new_indent[80];
  int datatype;
  NXstatus NXstat;

  strcpy(new_indent,indent); strcat(new_indent,INDENT_AMOUNT);

  while((NXstat = NXgetnextentry(NXdat, name, class, &datatype)) != NX_EOD){
    switch(datatype){
    case DFTAG_VG:
      /* Do not display HDF internal Vgroups */
      if (!((strcmp(class,"Dim0.0")==0) || (strcmp(class,"CDF0.0") ==0))) {
        printf("%sV %s->%s\n",indent,class,name);
        if ((NXstat = NXopengroup(NXdat,name,class)) == NX_ERROR) {  
          fprintf(stderr,"Error opening V group %s!",name);  
          return -1;  
        }  
        dumpVG(NXdat,new_indent); 
        NXstat = NXclosegroup(NXdat); 
        printf("%sv %s->%s\n",indent,class,name);
      }
        break;
    default:
      dumpSDS(NXdat,name,new_indent);
    }
  }
  return 0;
}


void
main(int argc, char ** argv) {
  char name[VGNAMELENMAX], class[VGNAMELENMAX], indent[80] = "";
  int datatype;
  char filename[80];
  NXhandle NXdat;
  NXstatus NXstat;

  if (argc < 2) {
    fprintf(stderr,"Usage: nxdump <filename>\n");
    exit(1);
  }
  strcpy(filename,argv[1]);

  if ((NXdat = NXopen(filename,DFACC_RDWR)) == NULL) {
    fprintf(stderr,"Unable to access file %s! Exiting...\n",filename);
    exit(1);
  }

  /* Read and display global attributes */
  dumpAttr(NXdat, "", indent);

  /* Read anything else and recurse through V groups */
  dumpVG(NXdat, indent);

  NXclose(NXdat);
}

