/* Copyright ICARE Contributeur : SIX Bruno, Juin 2006 Bruno.Six@univ-lille1.fr Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". En contrepartie de l'accessibilité au code source et des droits de copie, de modification et de redistribution accordés par cette licence, il n'est offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, seule une responsabilité restreinte pèse sur l'auteur du programme, le titulaire des droits patrimoniaux et les concédants successifs. A cet égard, l'attention de l'utilisateur est attirée sur les risques associés au chargement, à l'utilisation, à la modification et/ou au développement et à la reproduction du logiciel par l'utilisateur étant donné sa spécificité de logiciel libre, qui peut le rendre complexe à manipuler et qui le réserve donc à des développeurs et des professionnels avertis possédant des connaissances informatiques approfondies. Les utilisateurs sont donc invités à charger et tester l'adéquation du logiciel à leurs besoins dans des conditions permettant d'assurer la sécurité de leurs systèmes et ou de leurs données et, plus généralement, à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes. */ /** * \file ncf2hdf.c * \brief Conversion NetCDF->HDF. * * Ce programme permet de convertir un fichier NetCDF en fichier HDF. * * ----------------------------------------------------------------------------------------------- * * Usage : ncf2hdf [-v] [-s sds1[,sds2,...]] Fichier_NetCDF * * - Fichier_NetCDF : * Chemin du fichier NetCDF à convertir * * - Options : * - -v : affiche les infos de conversion sur stdout * - -d : traite les SDS de type dimension comme les autres; sans cette * option, les SDS de type dimension sont considérés comme les * "coordonnées" d'autres SDS. En particulier, un SDS de type * dimension non requis lui-même mais représentant une dimension * d'au autre SDS requis ne extrait que sans avec l'option -d. * - -s : sélectionne les SDS à extraire par leur nom * (liste de noms séparés par des virgules et sans espace) * * - Exit code : * - 0 : aucun problème * - 1 : problème grave - conversion impossible * * ----------------------------------------------------------------------------------------------- * * \author SIX Bruno, CGTD ICARE * \author CRI USTL, Domaine Universitaire Scientifique * \version 1.0.0 * \date 2006-05-05 * * ----------------------------------------------------------------------------------------------- * * Modifications, révisions: * * ----------------------------------------------------------------------------------------------- * */ #include #include /** Structure d'information sur les dimensions du fichier d'entrée */ struct dimension { /** Identificateur HDF de la dimension */ int32 id; /** Taille de la dimension */ int32 siz; /** Indique si la dimension concerne un des SDS requis */ int used; /** Nom de la dimension */ char name[MAX_NC_NAME + 1]; }; /* Options d'exécution du programme */ int /** Mode "verbeux" = 0/1 */ verbose = 0, /** Nombre de SDS à extraire (si option -s) */ nslct = 0, /** Traitement des SDS "dimension" = 0/1 (option -d) */ nodim = 0; char /** Chemin du fichier NetCDF d'entrée */ *ncfnam, /** Chemin du fichier HDF de sortie */ *hdfnam, /** Liste des SDS requis (si option -s) */ **slctsds, /** Suffixes NetCDF reconnus */ *suffixes[] = {".nc", ".ncf", ".netcdf", NULL}; /** * Point d'entrée principal */ main( /** Nombre d'arguments de la commande */ int argc, /** Tableaux des arguments */ char **argv ) { /* DECLARATIONS */ struct dimension *dimtab[MAX_NC_DIMS]; /* Table d'informations sur les dimensions du fichier NetCDF d'entrée */ int ierr = 0, /* Type d'erreur: 0=aucune, 1=erreur HDF, 2=erreur standard */ nbdim = 0, /* Nombre total de dimensions du fichier NetCDF d'entrée */ numdim, /* Index dans la table de la dimension courante d'un SDS NetCDF */ selected; /* Indique si le SDS courant est requis pour l'extraction */ long datasize; /* Taille en octets des données du NetCDF SDS courant */ int32 ncfid, /* Identificateur HDF du fichier NetCDF d'entrée */ hdfid, /* Identificateur HDF du fichier HDF de sortie */ nbatt, /* Nombre d'attributs de l'objet NetCDF courant */ nbsds, /* Nombre de SDS du fichier d'entrée */ isds, /* Indice du SDS NetCDF courant */ nsdsid, /* Identificateur HDF du SDS NetCDF courant */ hsdsid, /* Identificateur HDF du nouveau SDS HDF créé */ typ, /* Type de donnée du SDS NetCDF courant */ rnk, /* Nombre de dimensions du SDS NetCDF courant */ idim, /* Indice de la dimension courante d'un SDS NetCDF */ ndimid, /* Identificateur HDF de la dimension courante d'un SDS NetCDF */ hdimid, /* Identificateur HDF de la nouvelle dimension HDF créée */ dsiz, /* Taille de la dimension courante d'un SDS NetCDF */ dtyp, /* Type de donnée de la dimension courante d'un SDS NetCDF */ dimsizes[MAX_VAR_DIMS], /* Tailles des dimensions du SDS NetCDF courant */ start[MAX_VAR_DIMS], /* Manoeuvre: indices de début pour lire/écrire les SDS */ manint32; /* Manoeuvre: variable muette de type DFNT_INT32 */ char sdsnam[MAX_NC_NAME], /* Nom du SDS NetCDF courant */ dimnam[MAX_NC_NAME]; /* Nom de la dimension courante d'un SDS NetCDF */ VOIDP data; /* Buffer de stockage temporaire des données du SDS courant */ /************************/ /* DEBUT DE L'EXECUTION */ /************************/ /* Initialisation à 0 du tableau start */ memset(start, 0, MAX_VAR_DIMS*sizeof(int32)); /* Récupération de paramètres d'exécution */ if (!decodeargs(argc, argv) != 0) return; /* Ouverture des fichiers NetCDF et HDF */ if ((ncfid = SDstart(ncfnam, DFACC_READ )) < 0) goto ERR_HDF; if ((hdfid = SDstart(hdfnam, DFACC_CREATE)) < 0) goto ERR_HDF; /* Récupération des infos globales du fichier NetCDF */ if (SDfileinfo(ncfid, &nbsds, &nbatt) < 0) goto ERR_HDF; if (verbose) { printf("Fichier NetCDF d'entrée: %s\n", ncfnam); printf(" Nombre de SDS du fichier: %d\n", nbsds); } /* Recopie des attributs globaux dans le nouveau fichier */ if ((ierr = att_manager(ncfid, hdfid, nbatt, verbose)) < 0) { if (ierr == -1) goto ERR_HDF; else goto ERR_STD; } if (verbose) printf("-----------------------------------------------------------------\n"); /********************************************/ /* 1ERE PASSE : ANALYSE DU FICHIER D'ENTREE */ /********************************************/ /* Identification des dimensions et des SDS de type coordonnees: pour chaque SDS du fichier NetCDF d'entrée, on extrait ses dimensions et si une dimension extraite n'a pas encore été identifiée dans un SDS précédent, on met à jour la table "dimtab" avec le nom, l'identificateur HDF et la taille de cette nouvelle dimension. Si le SDS courant n'est pas un SDS de type dimension, et si ce SDS doit effectivement être extrait, on retient aussi le fait que cette dimension est "nécéssaire". */ for (isds = 0; isds < nbsds; isds++) { if ((nsdsid = SDselect(ncfid, isds)) < 0) goto ERR_HDF; if (SDgetinfo(nsdsid, sdsnam, &rnk, dimsizes, &typ, &nbatt) < 0) goto ERR_HDF; selected = (searchsds(sdsnam) >= 0); /* Le SDS est-il requis pour extraction ? */ for (idim = 0; idim < rnk; idim++) { if ((ndimid = SDgetdimid(nsdsid, idim)) < 0) goto ERR_HDF; if (SDdiminfo(ndimid, dimnam, &dsiz, &dtyp, &manint32) < 0) goto ERR_HDF; if ((numdim = searchdim(ndimid, nbdim, dimtab)) < 0) { dimtab[numdim = nbdim] = (struct dimension *)malloc(sizeof(struct dimension)); strcpy(dimtab[numdim]->name, dimnam); dimtab[numdim]->id = ndimid; dimtab[numdim]->siz = dsiz; nbdim++; } if (!SDiscoordvar(nsdsid)) dimtab[numdim]->used += selected; /* Dim. "nécessaire" */ } if (SDendaccess(nsdsid) < 0) goto ERR_HDF; } /*************************************/ /* 2EME PASSE : CREATION DES SDS HDF */ /*************************************/ for (isds = 0; isds < nbsds; isds++) { if ((nsdsid = SDselect(ncfid, isds)) < 0) goto ERR_HDF; if (SDgetinfo(nsdsid, sdsnam, &rnk, dimsizes, &typ, &nbatt) < 0) goto ERR_HDF; if ((ndimid = SDgetdimid(nsdsid, 0)) < 0) goto ERR_HDF; if ((numdim = searchdim(ndimid, nbdim, dimtab)) < 0) goto ERR_STD; /* Elimination du SDS s'il n'est pas requis pour extraction (on passe au suivant). Affichage du type de SDS sinon. */ if (searchsds(sdsnam) < 0 && (!SDiscoordvar(nsdsid) || !dimtab[numdim]->used || nodim)) continue; if (verbose) printf("\n%s (%s SDS)\n", sdsnam, SDiscoordvar(nsdsid) ? "dimension" : "standard" ); /* Création du nouveau SDS HDF. Attention, il faut tenir compte des éventuelles dimensions "unlimited". */ manint32 = dimsizes[0]; dimsizes[0] = dimtab[numdim]->siz; if ((hsdsid = SDcreate(hdfid, sdsnam, typ, rnk, dimsizes)) < 0) goto ERR_HDF; dimsizes[0] = manint32; /* Affichage éventuel de quelques infos sur la dimension des SDS "dimension" */ if (verbose) { if (!SDiscoordvar(nsdsid)) printf (" Dimensions:\n"); else printf (" Dimension size: %2d %s\n", *dimsizes, dimtab[numdim]->siz ? "" : "(unlimited)"); } /* - Si on a un SDS "standard", affichage éventuel de quelques infos sur ses dimensions. - Si on a un SDS "dimension", et si les SDS de type "dimension" doivent être particularisés, on se contente de donner à sa dimension le nom du SDS et c'est magique: HDF de débrouille tout seul... On calcule aussi le nombre total d'éléments du SDS courant dans la variable datasize. */ for (idim = 0, datasize = 1; idim < rnk; idim++) { if ((ndimid = SDgetdimid(nsdsid, idim)) < 0) goto ERR_HDF; if ((numdim = searchdim(ndimid, nbdim, dimtab)) < 0) goto ERR_STD; if ((hdimid = SDgetdimid(hsdsid, idim)) < 0) goto ERR_HDF; if (verbose && !SDiscoordvar(nsdsid)) printf (" %3d : %s (%d) %s\n", idim + 1, dimtab[numdim]->name, dimsizes[idim], dimtab[numdim]->siz == 0 ? "unlimited" : ""); if (dimtab[numdim]->used && !nodim) if (SDsetdimname(hdimid, dimtab[numdim]->name) < 0) goto ERR_HDF; /* Magique!!! */ datasize = datasize*dimsizes[idim]; } /* Recopie des attributs de l'ancien SDS dans le nouveau. Là aussi c'est magique: HDF reconnaît et gère tout seul les attributs prédéfinis ... */ if ((ierr = att_manager(nsdsid, hsdsid, nbatt, verbose)) < 0) { if (ierr == -1) goto ERR_HDF; else goto ERR_STD; } /* Lecture des données du SDS NetCDF dans un buffer puis écriture dans le SDS HDF. On a besoin de calculer la taille en octets de ces données pour allouer le buffer; on utilise la fonction HDF interne DFKNTsize qui donne la taille en octets d'un type HDF. On libère le buffer tout de suite après. */ if ((data = (VOIDP)malloc(datasize*DFKNTsize(typ))) == NULL) goto ERR_STD; if (SDreaddata (nsdsid, start, NULL, dimsizes, data) < 0) goto ERR_HDF; if (SDwritedata(hsdsid, start, NULL, dimsizes, data) < 0) goto ERR_HDF; free(data); /* Fin d'accès aux SDS */ if (SDendaccess(nsdsid) < 0) goto ERR_HDF; if (SDendaccess(hsdsid) < 0) goto ERR_HDF; } /**************************/ /* CLOTURE DE L'EXECUTION */ /**************************/ /* Fermeture des fichiers NetCDF et HDF */ if (SDend(ncfid) < 0) goto ERR_HDF; if (SDend(hdfid) < 0) goto ERR_HDF; /* Fin normale du programme */ exit(0); /* Fin anormale du programme sur une erreur HDF */ ERR_HDF: HEprint(stderr, 0); exit(1); /* Fin anormale du programme sur une autre erreur */ ERR_STD: printf("***ERROR***\n"); exit(2); } /** * Recherche du nom d'un SDS dans la liste des SDS requis pour extraction. * Valeur de retour : 1 si le nom est trouvé, 0 si la liste est vide, -1 sinon. */ int searchsds( /** Nom du SDS recherché */ char *sdsnam ) { int i; if (nslct == 0) return 0; for (i = 0; i < nslct; i++) if (strcmp(sdsnam, slctsds[i]) == 0) return 1; return -1; } /** * Recherche de l'identificateur HDF d'une dimension dans la table d'information sur les dimensions. * Valeur de retour : indice de la dimension dans la table, ou -1 si la dimension n'a pas été trouvée. */ int searchdim( /** Identificateur HDF de la dimension recherchée */ int32 dimid, /** Nombre total de dimensions du fichier */ int nbdim, /** Table d'informations sur les dimensions */ struct dimension *dims[] ) { int i; for (i = 0; i < nbdim; i++) if (dimid == dims[i]->id) return i; return -1; } /** * Report des attribut de l'ancien objet du fichier NetCDF vers l'objet correspondant du * nouveau fichier HDF et affichage éventuel de quelques informations sur ces attributs. * Valeur de retour : 0 si OK, -1 si erreur HDF, -2 si erreur standard. */ int att_manager( /** Identificateur HDF de l'ancien objet NetCDF */ int32 fr_id, /** Identificateur HDF du nouvel objet HDF */ int32 to_id, /** Nombre d'attributs de l'ancien objet NetCDF */ int32 nbatt, /** Mode "verbeux" (0/1) */ int verb ) { int32 iatt, /* Indice de l'attribut courant */ typ, /* Type de donnée de l'attribut courant */ cnt; /* Nombre d'éléments de l'attribut courant */ char attnam[MAX_NC_NAME + 1]; /* Nom de l'attribut courant */ int8 *attdat; /* Buffer de stockage temporaire des données de l'attribut courant */ if (verb && nbatt > 0) printf (" Attributs:\n"); for (iatt = 0; iatt < nbatt; iatt++) { if (SDattrinfo(fr_id, iatt, attnam, &typ, &cnt) < 0) return -1; if ((attdat = (int8 *)malloc((1+cnt)*DFKNTsize(typ))) == NULL) return -2; attdat[cnt] = 0; if (SDreadattr(fr_id, iatt, attdat) < 0) return -1; if (SDsetattr(to_id, attnam, typ, cnt, attdat) < 0) return -1; if (verb) printf(" %3d: %s = %s\n" , iatt, attnam, hdf_obj_to_string(typ, cnt, attdat)); } return 0; } /** * Traitement des arguments de la commande * Valeur de retour : 1 si OK, 0 sinon */ int decodeargs( /** Nombre d'arguments de la commande */ int argc, /** Tableaux des arguments */ char **argv ) { int i, /* Manoeuvre: indice de boucle */ argind = 1, /* Indice de l'argument en cours de traitement */ lth; /* Nombre de caractères du chemin du fichier d'entrée */ char *tcp, /* Argument en cours de traitement */ *suff, /* Suffixe du nom du fichier de sortie */ *sdslst = NULL, /* Liste éventuelle des noms des SDS à extraire */ *sds; /* Nom d'un sds de la liste précédente */ /** * On commence par passer en revue les arguments */ while (argind < argc) { if (*(tcp = argv[argind]) == '-') { if (strlen(tcp) != 2) goto ERROR; /* Ici, il s'agit d'une option */ switch(*++tcp) { case 'v' : verbose = 1 ; break; /* Mode verbeux */ case 'd' : nodim = 1 ; break; /* Traitement standard des SDS "dimension" */ case 's' : sdslst = argv[++argind]; break; /* Liste des SDS à extraire */ default : goto ERROR; /* Argument incorrect */ } } else { /* Ici, il s'agit du fichier NetCDF. On prépare le nom du fichier HDF */ lth = strlen(ncfnam = argv[argind]); hdfnam = strcpy((char *)malloc(lth + 5), ncfnam); break; } argind++; /* Argument suivant ... */ } /** * On construit le nom définitif du fichier HDF de sortie: * - si un suffixe est reconnu dans le nom du fichier NetCDF, on le remplace par le "hdf" * - sinon, on ajoute le suffixe "hdf" au nom du fichier d'entrée */ if (ncfnam == NULL) goto ERROR; if ((suff = strrchr(hdfnam, '.')) != NULL) { for (i = 0; i < strlen(suff); i++) suff[i] = tolower(suff[i]); for (i = 0; suffixes[i] != NULL; i++) if (strcmp(suffixes[i], suff) == 0) break; if (suffixes[i] == NULL) suff = hdfnam + lth; } else suff = hdfnam + lth; strcpy(suff, ".hdf"); /** * Si une liste de noms de SDS à extraire est fournie, on en fait un tableau. */ if (sdslst != NULL) { slctsds = (char **)calloc(nslct = 1, sizeof(char *)); slctsds[0] = (char *)strtok(sdslst, ","); while ((sds = (char *)strtok(NULL, ",")) != NULL) { slctsds = (char **)realloc(slctsds, (nslct + 1)*sizeof(char *)); slctsds[nslct++] = sds; } } /* Retour normal de la fonction */ return 1; /* Retour anormal de la fonction: on en affiche un mode d'utilisation succint */ ERROR: printf ("\nUsage: %s [-v] [-s sds1[,sds2,...]] \n", argv[0]); printf ("\n :\n"); printf (" Chemin du fichier NetCDF à convertir\n"); printf ("\n options:\n"); printf (" -v: affiche les infos de conversion sur stdout\n"); printf (" -d: traite les SDS de type dimension comme les SDS standard\n"); printf (" -s: sélectionne les SDS à extraire par leur nom\n"); printf (" (liste de noms séparés par des virgules et sans espace)\n"); printf ("\n exit code:\n"); printf (" 0 : aucun problème\n"); printf (" 1 : problème grave - conversion impossible\n"); return 0; }