static GwyContainer* gxsm_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { static const gchar *dimensions[] = { "time", "value", "dimy", "dimx" }; GwyContainer *data = NULL; GwyDataField *dfield; GwySIUnit *siunit; NetCDF cdffile; const NetCDFDim *dim; const NetCDFVar *var; const NetCDFAttr *attr; gdouble real; gint i, power10; if (!cdffile_load(&cdffile, filename, error)) return NULL; if (cdffile.nrecs) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("NetCDF records are not supported.")); goto gxsm_load_fail; } /* Look for variable "H" or "FloatField". This seems to be how GXSM calls * data. */ if (!(var = cdffile_get_var(&cdffile, "H")) && !(var = cdffile_get_var(&cdffile, "FloatField"))) { err_NO_DATA(error); goto gxsm_load_fail; } /* Check the dimensions. We only know how to handle time=1 and value=1. */ for (i = 0; i < var->ndims; i++) { dim = cdffile.dims + var->dimids[i]; if (!gwy_strequal(dim->name, dimensions[i]) || (i < 2 && dim->length != 1)) { /* XXX */ err_NO_DATA(error); goto gxsm_load_fail; } } if (err_DIMENSION(error, cdffile.dims[var->dimids[3]].length) || err_DIMENSION(error, cdffile.dims[var->dimids[2]].length)) goto gxsm_load_fail; dfield = read_data_field((const guchar*)(cdffile.buffer + var->begin), cdffile.dims[var->dimids[3]].length, cdffile.dims[var->dimids[2]].length, var->type); if ((siunit = read_real_size(&cdffile, "rangex", &real, &power10))) { /* Use negated positive conditions to catch NaNs */ if (!((real = fabs(real)) > 0)) { g_warning("Real x size is 0.0, fixing to 1.0"); real = 1.0; } gwy_data_field_set_xreal(dfield, real*pow10(power10)); gwy_data_field_set_si_unit_xy(dfield, siunit); g_object_unref(siunit); } if ((siunit = read_real_size(&cdffile, "rangey", &real, &power10))) { /* Use negated positive conditions to catch NaNs */ if (!((real = fabs(real)) > 0)) { g_warning("Real y size is 0.0, fixing to 1.0"); real = 1.0; } gwy_data_field_set_yreal(dfield, real*pow10(power10)); /* must be the same gwy_data_field_set_si_unit_xy(dfield, siunit); */ g_object_unref(siunit); } if ((siunit = read_real_size(&cdffile, "rangez", &real, &power10))) { /* rangez seems to be some bogus value, take only units */ gwy_data_field_set_si_unit_z(dfield, siunit); gwy_data_field_multiply(dfield, pow10(power10)); g_object_unref(siunit); } if ((siunit = read_real_size(&cdffile, "dz", &real, &power10))) { /* on the other hand the units seem to be bogus here, take the range */ gwy_data_field_multiply(dfield, real); g_object_unref(siunit); } data = gwy_container_new(); gwy_container_set_object_by_name(data, "/0/data", dfield); g_object_unref(dfield); if ((attr = cdffile_get_attr(var->attrs, var->nattrs, "long_name")) && attr->type == NC_CHAR && attr->nelems) { gwy_container_set_string_by_name(data, "/0/data/title", g_strndup(attr->values, attr->nelems)); } gxsm_load_fail: gwy_file_abandon_contents(cdffile.buffer, cdffile.size, NULL); cdffile_free(&cdffile); return data; }
static GwyContainer* gsf_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL, *meta = NULL; GwyDataField *dfield = NULL; GwyTextHeaderParser parser; GwySIUnit *unit; guchar *p, *value, *buffer = NULL, *header = NULL; const guchar *datap; GHashTable *hash = NULL; gsize size, expected_size; GError *err = NULL; gdouble xreal, yreal, xoff, yoff; guint i, xres, yres; gdouble *d; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size < MAGIC_SIZE || memcmp(buffer, MAGIC, MAGIC_SIZE) != 0) { err_FILE_TYPE(error, "Gwyddion Simple Field"); goto fail; } p = buffer + MAGIC_SIZE; datap = memchr(p, '\0', size - (p - buffer)); if (!datap) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("File header is truncated.")); goto fail; } header = g_strdup(p); datap += 4 - ((datap - buffer) % 4); gwy_clear(&parser, 1); parser.key_value_separator = "="; if (!(hash = gwy_text_header_parse(header, &parser, NULL, NULL))) { g_propagate_error(error, err); goto fail; } xres = read_pixel_size(hash, "XRes", error); yres = read_pixel_size(hash, "YRes", error); if (!xres || !yres) goto fail; expected_size = (datap - buffer) + sizeof(gfloat)*xres*yres; if (err_SIZE_MISMATCH(error, expected_size, size, TRUE)) goto fail; xreal = read_real_size(hash, "XReal"); yreal = read_real_size(hash, "YReal"); dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE); xoff = read_real_offset(hash, "XOffset"); yoff = read_real_offset(hash, "YOffset"); gwy_data_field_set_xoffset(dfield, xoff); gwy_data_field_set_yoffset(dfield, yoff); value = g_hash_table_lookup(hash, "XYUnits"); unit = gwy_si_unit_new(value); gwy_data_field_set_si_unit_xy(dfield, unit); g_object_unref(unit); value = g_hash_table_lookup(hash, "ZUnits"); unit = gwy_si_unit_new(value); gwy_data_field_set_si_unit_z(dfield, unit); g_object_unref(unit); d = gwy_data_field_get_data(dfield); for (i = xres*yres; i; i--) *(d++) = gwy_get_gfloat_le(&datap); container = gwy_container_new(); gwy_container_set_object(container, gwy_app_get_data_key_for_id(0), dfield); g_object_unref(dfield); if ((value = g_hash_table_lookup(hash, "Title"))) { /* FIXME: Ensure valid UTF-8 */ gwy_container_set_string_by_name(container, "/0/data/title", g_strdup(value)); } else gwy_app_channel_title_fall_back(container, 0); meta = gwy_container_new(); g_hash_table_foreach(hash, add_meta, meta); if (gwy_container_get_n_items(meta)) gwy_container_set_object_by_name(container, "/0/meta", meta); g_object_unref(meta); gwy_file_channel_import_log_add(container, 0, NULL, filename); fail: gwy_file_abandon_contents(buffer, size, NULL); if (header) g_free(header); if (hash) g_hash_table_destroy(hash); return container; }