raster_metadata.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*!
  2. \file lib/raster/raster_metadata.c
  3. \brief Raster library - Functions to read and write raster "units",
  4. "semantic label" and "vertical datum" meta-data info
  5. (C) 2007-2009, 2021 by Hamish Bowman, Maris Nartiss,
  6. and the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. \author Hamish Bowman
  10. */
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <grass/gis.h>
  14. #include <grass/raster.h>
  15. #include <grass/glocale.h>
  16. static char *misc_read_line(const char *, const char *, const char *);
  17. static void misc_write_line(const char *, const char *, const char *);
  18. /*!
  19. * \brief Get a raster map's units metadata string
  20. *
  21. * Read the raster's units metadata file and put string in str
  22. *
  23. * \param name raster map name
  24. * \param mapset mapset name
  25. *
  26. * \return string representing units on success
  27. * \return NULL on error
  28. */
  29. char *Rast_read_units(const char *name, const char *mapset)
  30. {
  31. return misc_read_line("units", name, mapset);
  32. }
  33. /*!
  34. * \brief Write a string to a raster map's units metadata file
  35. *
  36. * Raster map must exist in the current mapset.
  37. *
  38. * \param name raster map name
  39. * \param str string containing data to be written
  40. */
  41. void Rast_write_units(const char *name, const char *str)
  42. {
  43. misc_write_line("units", name, str);
  44. }
  45. /*!
  46. * \brief Get a raster map's vertical datum metadata string
  47. *
  48. * Read the raster's vertical datum metadata file and put string in str
  49. *
  50. * \param name raster map name
  51. * \param mapset mapset name
  52. *
  53. * \return string representing vertical datum on success
  54. * \return NULL on error
  55. */
  56. char *Rast_read_vdatum(const char *name, const char *mapset)
  57. {
  58. return misc_read_line("vertical_datum", name, mapset);
  59. }
  60. /*!
  61. * \brief Write a string into a raster's vertical datum metadata file
  62. *
  63. * Raster map must exist in the current mapset.
  64. *
  65. * \param name raster map name
  66. * \param str string containing data to be written
  67. */
  68. void Rast_write_vdatum(const char *name, const char *str)
  69. {
  70. misc_write_line("vertical_datum", name, str);
  71. }
  72. /*!
  73. * \brief Get a raster map semantic label metadata string
  74. *
  75. * Read raster semantic label metadata file and put string in to str
  76. *
  77. * \param name raster map name
  78. * \param mapset mapset name
  79. *
  80. * \return string representing semantic label on success
  81. * \return NULL on error
  82. */
  83. char *Rast_read_semantic_label(const char *name, const char *mapset)
  84. {
  85. return misc_read_line("semantic_label", name, mapset);
  86. }
  87. /*!
  88. * \brief Get a raster map semantic label or fall back to its name
  89. *
  90. * Use this function if a semantic label is needed but not mandated.
  91. *
  92. * \param name raster map name
  93. * \param mapset mapset name
  94. *
  95. * \return string representing semantic label or map name
  96. */
  97. char *Rast_get_semantic_label_or_name(const char *name, const char *mapset) {
  98. char *buff;
  99. buff = Rast_read_semantic_label(name, mapset);
  100. return buff ? buff : G_store(name);
  101. }
  102. /*!
  103. * \brief Write a string into a rasters semantic label metadata file
  104. *
  105. * Raster map must exist in the current mapset.
  106. *
  107. * It is up to the caller to validate semantic label string in advance
  108. * with Rast_legal_semantic_label().
  109. *
  110. * \param name raster map name
  111. * \param str string containing data to be written
  112. */
  113. void Rast_write_semantic_label(const char *name, const char *str)
  114. {
  115. misc_write_line("semantic_label", name, str);
  116. }
  117. /*!
  118. * \brief Check for legal semantic label
  119. *
  120. * Legal semantic label must be a legal GRASS file name.
  121. * Semantic labels are capped in legth to GNAME_MAX.
  122. *
  123. * This function will return false if provided semantic label is not
  124. * considered to be valid.
  125. * This function does not check if semantic label maps to any entry in
  126. * metadata files of semantic labels as not all semantic labels have
  127. * files with extra metadata.
  128. *
  129. * The function prints a warning on error.
  130. *
  131. * \param semantic label reference to check
  132. *
  133. * \return true success
  134. * \return false failure
  135. */
  136. bool Rast_legal_semantic_label(const char *semantic_label)
  137. {
  138. const char *s;
  139. if (strlen(semantic_label) >= GNAME_MAX) {
  140. G_warning(_("Semantic label is too long"));
  141. return false;
  142. }
  143. if (G_legal_filename(semantic_label) != 1)
  144. return false;
  145. s = semantic_label;
  146. while (*s) {
  147. if (!((*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') ||
  148. (*s >= '0' && *s <= '9') || *s == '_' || *s == '-')) {
  149. G_warning(_("Character '%c' not allowed in a semantic label."), *s);
  150. return false;
  151. }
  152. s++;
  153. }
  154. return true;
  155. }
  156. /*!
  157. * \brief Read the first line of a file in cell_misc/
  158. *
  159. * Read the first line of data from a cell_misc/ meta-data file.
  160. *
  161. * \param element metadata component filename
  162. * \param name
  163. * \param mapset
  164. * \return dynamically-allocated string on success
  165. * \return NULL on error
  166. */
  167. static char *misc_read_line(const char *elem,
  168. const char *name, const char *mapset)
  169. {
  170. char buff[GNAME_MAX];
  171. FILE *fp;
  172. buff[0] = '\0';
  173. if (G_find_file2_misc("cell_misc", elem, name, mapset) == NULL)
  174. return NULL;
  175. fp = G_fopen_old_misc("cell_misc", elem, name, mapset);
  176. if (!fp) {
  177. G_warning(_("Unable to read <%s> for raster map <%s@%s>"),
  178. elem, name, mapset);
  179. return NULL;
  180. }
  181. if (G_getl2(buff, sizeof(buff) - 1, fp) == 0) {
  182. /* file is empty */
  183. *buff = '\0';
  184. }
  185. if (fclose(fp) != 0)
  186. G_fatal_error(_("Error closing <%s> metadata file for raster map <%s@%s>"),
  187. elem, name, mapset);
  188. return *buff ? G_store(buff) : NULL;
  189. }
  190. /*!
  191. * \brief Write a line to a raster map metadata file
  192. *
  193. * Write (including overwrite) a string into a raster map's metadata file
  194. * found in in cell_misc/ in the current mapset.
  195. *
  196. * \param element metadata component filename
  197. * \param name
  198. * \param *str string containing data to be written
  199. */
  200. static void misc_write_line(const char *elem, const char *name, const char *str)
  201. {
  202. FILE *fp;
  203. fp = G_fopen_new_misc("cell_misc", elem, name);
  204. if (!fp) {
  205. G_fatal_error(_("Unable to create <%s> metadata file for raster map <%s@%s>"),
  206. elem, name, G_mapset());
  207. } /* This else block is unnecessary but helps to silence static code analysis tools */
  208. else {
  209. fprintf(fp, "%s\n", str);
  210. if (fclose(fp) != 0)
  211. G_fatal_error(_("Error closing <%s> metadata file for raster map <%s@%s>"),
  212. elem, name, G_mapset());
  213. }
  214. }