static gboolean read_dimensions(GHashTable *hash, gint *ndata, Dimensions *dimensions, GError **error) { const gchar *value; /* Number of fields */ if (!(value = g_hash_table_lookup(hash, "Channels"))) { err_MISSING_FIELD(error, "Channels"); return FALSE; } *ndata = atoi(value); if (*ndata <= 0 || *ndata > 1024) { err_INVALID(error, "Channels"); return FALSE; } /* Pixel sizes */ if (!(value = g_hash_table_lookup(hash, "Lines"))) { err_MISSING_FIELD(error, "Lines"); return FALSE; } dimensions->yres = atoi(value); if (err_DIMENSION(error, dimensions->yres)) return FALSE; if (!(value = g_hash_table_lookup(hash, "Rows"))) { err_MISSING_FIELD(error, "Rows"); return FALSE; } /* XXX: When the file says Rows, it actually means Columns-1. Bite me. */ dimensions->xres = atoi(value) + 1; if (err_DIMENSION(error, dimensions->xres)) return FALSE; /* Real sizes */ if (!(value = g_hash_table_lookup(hash, "X-Length"))) { err_MISSING_FIELD(error, "X-Length"); return FALSE; } dimensions->xreal = Micrometer * g_ascii_strtod(value, NULL); if (!((dimensions->xreal = fabs(dimensions->xreal)) > 0)) { g_warning("Real x size is 0.0, fixing to 1.0"); dimensions->xreal = 1.0; } if (!(value = g_hash_table_lookup(hash, "Y-Length"))) { err_MISSING_FIELD(error, "Y-Length"); return FALSE; } dimensions->yreal = Micrometer * g_ascii_strtod(value, NULL); if (!((dimensions->yreal = fabs(dimensions->yreal)) > 0)) { g_warning("Real y size is 0.0, fixing to 1.0"); dimensions->yreal = 1.0; } return TRUE; }
static const guchar* get_param_pointer(const guchar *buffer, gsize size, guint32 pos, guint32 len, const guchar *name, GError **error) { if (pos < HEADER_SIZE || pos > size - len) { err_INVALID(error, name); return NULL; } return buffer + pos; }
static guint find_data_offsets(const gchar *buffer, gsize size, GPtrArray *ezdfile, GError **error) { EZDSection *dataset, *section; GString *grkey; guint required_size = 0; gint ngroups, nchannels, i, j, k; guint ndata = 0; gchar *p; /* Sanity check */ if (!ezdfile->len) { err_NO_DATA(error); return 0; } dataset = (EZDSection*)g_ptr_array_index(ezdfile, 0); if (strcmp(dataset->name, "DataSet")) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("First section isn't DataSet")); return 0; } if (!(p = g_hash_table_lookup(dataset->meta, "GroupCount")) || (ngroups = atol(p)) <= 0) { err_INVALID(error, _("GroupCount in [DataSet]")); return 0; } /* Scan groups */ grkey = g_string_new(""); for (i = 0; i < ngroups; i++) { g_string_printf(grkey, "Gr%d-Count", i); if (!(p = g_hash_table_lookup(dataset->meta, grkey->str))) { g_warning("No count for group %u", i); continue; } if ((nchannels = atol(p)) <= 0) continue; /* Scan channels inside a group, note it's OK there's less channels * than specified */ for (j = 0; j < nchannels; j++) { g_string_printf(grkey, "Gr%d-Ch%d", i, j); if (!(p = g_hash_table_lookup(dataset->meta, grkey->str))) continue; section = NULL; for (k = 1; k < ezdfile->len; k++) { section = (EZDSection*)g_ptr_array_index(ezdfile, k); if (gwy_strequal(section->name, p)) break; } if (!section) { g_warning("Cannot find section for %s", p); continue; } /* Compute data position */ gwy_debug("Data %s at offset %u from data start", grkey->str, required_size); gwy_debug("xres = %d, yres = %d, bpp = %d, z-name = %s", section->xres, section->yres, section->bitdepth, section->zrange.name); if (section->yres < 2) { gwy_debug("Skipping 1D data Gr%d-Ch%d. FIXME.", i, j); continue; } ndata++; section->data = buffer + required_size; required_size += section->xres * section->yres * (section->bitdepth/8); if (required_size > size) { g_warning("Truncated file, %s doesn't fit", grkey->str); g_string_free(grkey, TRUE); section->data = NULL; return 0; } section->group = i; section->channel = j; } } g_string_free(grkey, TRUE); if (!ndata) err_NO_DATA(error); return ndata; }
static RHKPage* rhk_sm3_read_page(const guchar **buffer, gsize *len, GError **error) { RHKPage *page; const guchar *p = *buffer; guint i, expected; if (!*len) return NULL; if (*len < HEADER_SIZE + 4) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("End of file reached in page header.")); return NULL; } if (memcmp(p + MAGIC_OFFSET, MAGIC, MAGIC_SIZE) != 0) { err_INVALID(error, _("magic page header")); return NULL; } page = g_new0(RHKPage, 1); page->param_size = gwy_get_guint16_le(&p); gwy_debug("param_size = %u", page->param_size); if (*len < page->param_size + 4) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("End of file reached in page header.")); goto FAIL; } /* TODO: Convert to UTF-8, store to meta */ memcpy(page->version, p, MAGIC_TOTAL_SIZE); p += MAGIC_TOTAL_SIZE; page->string_count = gwy_get_guint16_le(&p); gwy_debug("string_count = %u", page->string_count); page->type = gwy_get_guint32_le(&p); gwy_debug("type = %u", page->type); page->page_type = gwy_get_guint32_le(&p); gwy_debug("page_type = %u", page->page_type); page->data_sub_source = gwy_get_guint32_le(&p); page->line_type = gwy_get_guint32_le(&p); page->x_coord = gwy_get_gint32_le(&p); page->y_coord = gwy_get_gint32_le(&p); page->x_size = gwy_get_guint32_le(&p); page->y_size = gwy_get_guint32_le(&p); gwy_debug("x_size = %u, y_size = %u", page->x_size, page->y_size); page->source_type = gwy_get_guint32_le(&p); page->image_type = gwy_get_guint32_le(&p); gwy_debug("image_type = %u", page->image_type); page->scan_dir = gwy_get_guint32_le(&p); gwy_debug("scan_dir = %u", page->scan_dir); page->group_id = gwy_get_guint32_le(&p); gwy_debug("group_id = %u", page->group_id); page->data_size = gwy_get_guint32_le(&p); gwy_debug("data_size = %u", page->data_size); page->min_z_value = gwy_get_gint32_le(&p); page->max_z_value = gwy_get_gint32_le(&p); gwy_debug("min,max_z_value = %d %d", page->min_z_value, page->max_z_value); page->x_scale = gwy_get_gfloat_le(&p); page->y_scale = gwy_get_gfloat_le(&p); page->z_scale = gwy_get_gfloat_le(&p); gwy_debug("x,y,z_scale = %g %g %g", page->x_scale, page->y_scale, page->z_scale); page->xy_scale = gwy_get_gfloat_le(&p); page->x_offset = gwy_get_gfloat_le(&p); page->y_offset = gwy_get_gfloat_le(&p); page->z_offset = gwy_get_gfloat_le(&p); gwy_debug("x,y,z_offset = %g %g %g", page->x_offset, page->y_offset, page->z_offset); page->period = gwy_get_gfloat_le(&p); page->bias = gwy_get_gfloat_le(&p); page->current = gwy_get_gfloat_le(&p); page->angle = gwy_get_gfloat_le(&p); gwy_debug("period = %g, bias = %g, current = %g, angle = %g", page->period, page->bias, page->current, page->angle); get_CHARARRAY(page->page_id, &p); p = *buffer + 2 + page->param_size; for (i = 0; i < page->string_count; i++) { gchar *s; gwy_debug("position %04x", p - *buffer); s = rhk_sm3_read_string(&p, *len - (p - *buffer)); if (!s) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("End of file reached in string #%u."), i); goto FAIL; } if (i < RHK_STRING_NSTRINGS) page->strings[i] = s; else g_free(s); } expected = page->x_size * page->y_size * sizeof(gint32); gwy_debug("expecting %u bytes of page data now", expected); if (*len < (p - *buffer) + expected) { err_SIZE_MISMATCH(error, expected, *len - (p - *buffer)); goto FAIL; } if (page->type == RHK_TYPE_IMAGE) page->page_data = p; else page->spectral_data = p; p += expected; if (page->type == RHK_TYPE_IMAGE) { if (*len < (p - *buffer) + 4) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("End of file reached in color data header.")); goto FAIL; } /* Info size includes itself */ page->color_info.size = gwy_get_guint32_le(&p) - 2; if (*len < (p - *buffer) + page->color_info.size) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("End of file reached in color data.")); goto FAIL; } p += page->color_info.size; } *len -= p - *buffer; *buffer = p; return page; FAIL: rhk_sm3_page_free(page); return NULL; }
static GwyContainer* ecs_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *meta, *container = NULL; guchar *buffer = NULL; gsize size = 0; GError *err = NULL; GwyDataField *dfield = NULL; gchar *s = NULL, *s2 = NULL; GwySIUnit *siunit; const guchar *p; gdouble *data, *row; guint xres, yres, i, j; gdouble xreal, q; const gint16 *pdata; guchar c; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); g_clear_error(&err); return NULL; } if (size < HEADER_SIZE + 2) { err_TOO_SHORT(error); goto fail; } p = buffer + ECS_RESOLUTION; xres = gwy_get_guint16_le(&p); yres = gwy_get_guint16_le(&p); gwy_debug("xres: %u, yres: %u", xres, yres); if (size != HEADER_SIZE + 2*xres*yres) { err_SIZE_MISMATCH(error, HEADER_SIZE + 2*xres*yres, size); goto fail; } /* Scan size */ p = buffer + ECS_SCAN_SIZE; s = get_PASCAL_STRING(&p, HEADER_SIZE - ECS_SCAN_SIZE); if (!s) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Scan size header field overlaps with data.")); goto fail; } gwy_debug("Scan size str: <%s>", s); if (!g_str_has_prefix(s, "Scan Size: ")) { err_FILE_TYPE(error, "ECS"); goto fail; } if (sscanf(s + strlen("Scan Size: "), "%lf %lf%c", &xreal, &q, &c) != 3) { err_INVALID(error, "Scan Size"); goto fail; } g_free(s); s = NULL; gwy_debug("xreal: %g q: %g unit: %s", xreal, q, c == 0x8f ? "Angstrom" : "Nanometer"); if (c == 0x8f) { xreal *= 1e-10; q *= 1e-10; } else { xreal *= 1e-9; q *= 1e-9; } q /= 65536.0; /* This does not make much sense when xres != yres, but it is what * Snomputz does. */ dfield = gwy_data_field_new(xres, yres, xreal, xreal, FALSE); data = gwy_data_field_get_data(dfield); pdata = (const gint16*)(buffer + HEADER_SIZE); for (i = 0; i < yres; i++) { row = data + (yres-1 - i)*xres; for (j = 0; j < xres; j++) row[j] = GINT16_TO_LE(pdata[i*xres + j])*q; } siunit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_xy(dfield, siunit); g_object_unref(siunit); siunit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_z(dfield, siunit); g_object_unref(siunit); container = gwy_container_new(); gwy_container_set_object_by_name(container, "/0/data", dfield); /* Channel title */ p = buffer + ECS_CHANNEL; s = get_PASCAL_STRING(&p, HEADER_SIZE - ECS_CHANNEL); if (!s || !*s) s = g_strdup("Topography"); gwy_container_set_string_by_name(container, "/0/data/title", s); s = NULL; meta = gwy_container_new(); /* Date & time */ p = buffer + ECS_DATE; s = get_PASCAL_STRING(&p, HEADER_SIZE - ECS_DATE); if (s) { p = buffer + ECS_TIME; s2 = get_PASCAL_STRING(&p, HEADER_SIZE - ECS_TIME); if (s2) { gwy_container_set_string_by_name(meta, "Date", g_strconcat(s, " ", s2, NULL)); g_free(s2); s2 = NULL; } g_free(s); s = NULL; } /* Channel title */ p = buffer + ECS_CHANNEL; s = get_PASCAL_STRING(&p, HEADER_SIZE - ECS_CHANNEL); if (s && *s) { gwy_container_set_string_by_name(meta, "Comment", s); s = NULL; } if (gwy_container_get_n_items(meta)) gwy_container_set_object_by_name(container, "/0/meta", meta); g_object_unref(meta); fail: g_free(s); g_free(s2); gwy_object_unref(dfield); gwy_file_abandon_contents(buffer, size, NULL); return container; }
static gboolean rhkspm32_read_header(RHKPage *rhkpage, GError **error) { const gchar *buffer; gchar *end; guint pos; buffer = rhkpage->buffer; rhkpage->date = g_strstrip(g_strndup(buffer + MAGIC_SIZE, 0x20 - MAGIC_SIZE)); if (sscanf(buffer + 0x20, "%d %d %d %d %d %d %d", (gint*)&rhkpage->type, (gint*)&rhkpage->data_type, &rhkpage->line_type, &rhkpage->xres, &rhkpage->yres, &rhkpage->size, (gint*)&rhkpage->page_type) != 7) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Invalid file header.")); return FALSE; } gwy_debug("type = %u, data = %u, line = %u, image = %u", rhkpage->type, rhkpage->data_type, rhkpage->line_type, rhkpage->page_type); gwy_debug("xres = %d, yres = %d", rhkpage->xres, rhkpage->yres); if (err_DIMENSION(error, rhkpage->xres) || err_DIMENSION(error, rhkpage->yres)) return FALSE; if (!((rhkpage->type == RHK_TYPE_IMAGE) || (rhkpage->type == RHK_TYPE_LINE))) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Only image and line files are supported.")); return FALSE; } if ((rhkpage->type == RHK_TYPE_IMAGE) && (rhkpage->data_type != RHK_DATA_INT16)) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Invalid data type %d for image data."), rhkpage->data_type); return FALSE; } if ((rhkpage->type == RHK_TYPE_LINE) && !((rhkpage->data_type == RHK_DATA_INT16) || (rhkpage->data_type == RHK_DATA_SINGLE))) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Invalid data type %d for line data."), rhkpage->data_type); return FALSE; } if ((rhkpage->data_type) == RHK_DATA_INT8) rhkpage->item_size = 1; else if ((rhkpage->data_type) == RHK_DATA_INT16) rhkpage->item_size = 2; else if ((rhkpage->data_type) == RHK_DATA_INT32) rhkpage->item_size = 4; else if ((rhkpage->data_type) == RHK_DATA_SINGLE) rhkpage->item_size = 4; //rhkpage->item_size = rhkpage->data_type; // niv if (!rhkspm32_read_range(buffer + 0x40, "X", &rhkpage->x) || !rhkspm32_read_range(buffer + 0x60, "Y", &rhkpage->y) || !rhkspm32_read_range(buffer + 0x80, "Z", &rhkpage->z)) { err_INVALID(error, _("data ranges")); return FALSE; } /* Use negated positive conditions to catch NaNs */ // niv - modifying this - otherwise it messes with the spectra // (but i don;t really understand it) if (!((fabs(rhkpage->x.scale)) > 0)) { g_warning("Real x scale is 0.0, fixing to 1.0"); rhkpage->x.scale = 1.0; } if (!((fabs(rhkpage->y.scale)) > 0)) { /* The y scale seem unused for non-image data */ if (rhkpage->type == RHK_TYPE_IMAGE) g_warning("Real y scale is 0.0, fixing to 1.0"); rhkpage->y.scale = 1.0; } if (!g_str_has_prefix(buffer + 0xa0, "XY ")) { err_MISSING_FIELD(error, "XY"); return FALSE; } pos = 0xa0 + sizeof("XY"); rhkpage->xyskew = g_ascii_strtod(buffer + pos, &end); if (end == buffer + pos) { err_INVALID(error, "XY"); return FALSE; } pos = (end - buffer) + 2; /* Don't check failure, it seems the value is optional */ rhkpage->alpha = g_ascii_strtod(buffer + pos, &end); // not failing, but setting an existance flag, this happens for spectra, // but otherwise i want to add this to the metadata if (end == buffer + pos) rhkpage->e_alpha = FALSE; else rhkpage->e_alpha = TRUE; if (!rhkspm32_read_range(buffer + 0xc0, "IV", &rhkpage->iv)) { err_INVALID(error, "IV"); return FALSE; } if (g_str_has_prefix(buffer + 0xe0, "scan ")) pos = 0xe0 + sizeof("scan"); rhkpage->scan = strtol(buffer + pos, &end, 10); if (end == buffer + pos) { err_INVALID(error, "scan"); return FALSE; } pos = (end - buffer); rhkpage->period = g_ascii_strtod(buffer + pos, &end); if (end == buffer + pos) { err_INVALID(error, "period"); return FALSE; } if (sscanf(buffer + 0x100, "id %u %u", &rhkpage->id, &rhkpage->data_offset) != 2) { /* XXX: Some braindamaged files encountered in practice do not contain * the data offset. Cross fingers and substitute HEADER_SIZE. */ g_warning("Data offset is missing, just guessing from now..."); rhkpage->id = 0; rhkpage->data_offset = HEADER_SIZE; } gwy_debug("data_offset = %u", rhkpage->data_offset); if (rhkpage->data_offset < HEADER_SIZE) { err_INVALID(error, _("data offset")); return FALSE; } /* XXX: The same braindamaged files overwrite the label and comment part * with some XML mumbo jumbo. Sigh and ignore it. */ if (strncmp(buffer + 0x140, "\x0d\x0a<?", 4) != 0) { rhkpage->label = g_strstrip(g_strndup(buffer + 0x140, 0x20)); rhkpage->comment = g_strstrip(g_strndup(buffer + 0x160, HEADER_SIZE - 0x160)); } return TRUE; }
static gboolean unisoku_read_header(gchar *buffer, UnisokuFile *ufile, GError **error) { gchar *line; gint type1, type2; line = gwy_str_next_line(&buffer); if (!line) return FALSE; NEXT(buffer, line, error); /* garbage */ NEXT(buffer, line, error); if (unisoku_sscanf(line, "i", &ufile->format_version) != 1) { err_UNSUPPORTED(error, _("format version")); return FALSE; } NEXT(buffer, line, error); ufile->date = g_strdup(line); NEXT(buffer, line, error); ufile->time = g_strdup(line); NEXT(buffer, line, error); ufile->sample_name = g_strdup(line); NEXT(buffer, line, error); ufile->remark = g_strdup(line); NEXT(buffer, line, error); if (unisoku_sscanf(line, "ii", &ufile->ascii_flag, &type1) != 2) { err_INVALID(error, _("format flags")); return FALSE; } ufile->data_type = type1; NEXT(buffer, line, error); if (unisoku_sscanf(line, "ii", &ufile->xres, &ufile->yres) != 2) { err_INVALID(error, _("resolution")); return FALSE; } if (err_DIMENSION(error, ufile->xres) || err_DIMENSION(error, ufile->yres)) return FALSE; NEXT(buffer, line, error); if (unisoku_sscanf(line, "ii", &type1, &type2) != 2) { /* FIXME */ g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Missing or invalid some integers heaven knows what " "they mean but that should be here.")); return FALSE; } ufile->dim_x = type1; ufile->dim_y = type2; NEXT(buffer, line, error); ufile->unit_x = g_strdup(line); NEXT(buffer, line, error); if (unisoku_sscanf(line, "ddi", &ufile->start_x, &ufile->end_x, &ufile->log_flag_x) != 3) { err_INVALID(error, _("x scale parameters")); return FALSE; } NEXT(buffer, line, error); ufile->unit_y = g_strdup(line); NEXT(buffer, line, error); if (unisoku_sscanf(line, "ddii", &ufile->start_y, &ufile->end_y, &ufile->ineq_flag, &ufile->log_flag_y) != 4) { err_INVALID(error, _("y scale parameters")); return FALSE; } /* Use negated positive conditions to catch NaNs */ if (!(ufile->end_x - ufile->start_x > 0)) { g_warning("Real x size is 0.0, fixing to 1.0"); ufile->start_x = 0.0; ufile->end_x = 1.0; } if (!(ufile->end_y - ufile->start_y > 0)) { g_warning("Real y size is 0.0, fixing to 1.0"); ufile->start_y = 0.0; ufile->end_y = 1.0; } NEXT(buffer, line, error); ufile->unit_z = g_strdup(line); NEXT(buffer, line, error); if (unisoku_sscanf(line, "ddddi", &ufile->max_raw_z, &ufile->min_raw_z, &ufile->max_z, &ufile->min_z, &ufile->log_flag_z) != 5) { err_INVALID(error, _("z scale parameters")); return FALSE; } NEXT(buffer, line, error); if (unisoku_sscanf(line, "dddi", &ufile->stm_voltage, &ufile->stm_current, &ufile->scan_time, &ufile->accum) != 4) { err_INVALID(error, _("data type parameters")); return FALSE; } NEXT(buffer, line, error); /* reserved */ NEXT(buffer, line, error); ufile->stm_voltage_unit = g_strdup(line); NEXT(buffer, line, error); ufile->stm_current_unit = g_strdup(line); NEXT(buffer, line, error); ufile->ad_name = g_strdup(line); /* There is more stuff after that, but heaven knows what it means... */ return TRUE; }
static GwyContainer* hitachi_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL, *meta; GdkPixbuf *pixbuf = NULL; GwyDataField *dfield = NULL; gchar *value, *imagename = NULL, *header = NULL; guchar *pixels; GHashTable *hash = NULL; GError *err = NULL; gdouble dx; gint pxres, pyres, hxres, hyres, rowstride, nchannels, i, j; gdouble *data; if (!(hash = hitachi_load_header(filename, &header, error))) return NULL; if (!require_keys(hash, error, "ImageName", "DataSize", "PixelSize", NULL)) goto fail; value = g_hash_table_lookup(hash, "ImageName"); if (!(imagename = hitachi_find_data_name(filename, value))) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("No corresponding data file was found for header file.")); goto fail; } if (!(pixbuf = gdk_pixbuf_new_from_file(imagename, &err))) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_IO, _("Cannot load image: %s"), err->message); g_clear_error(&err); goto fail; } /* We know the image dimensions so check them. */ pxres = gdk_pixbuf_get_width(pixbuf); pyres = gdk_pixbuf_get_height(pixbuf); value = g_hash_table_lookup(hash, "DataSize"); if (sscanf(value, "%ux%u", &hxres, &hyres) != 2) { err_INVALID(error, "DataSize"); goto fail; } if (hxres != pxres || hyres != pyres) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Field DataSize %ux%u does not match image dimensions " "%ux%u."), hxres, hyres, pxres, pyres); goto fail; } if (err_DIMENSION(error, hxres) || err_DIMENSION(error, hyres)) goto fail; dx = g_ascii_strtod(g_hash_table_lookup(hash, "PixelSize"), NULL); /* Use negated positive conditions to catch NaNs */ if (!((dx = fabs(dx)) > 0)) { g_warning("Pixel size is 0.0, fixing to 1.0"); dx = 1.0; } dx *= Nanometre; dfield = gwy_data_field_new(hxres, hyres, hxres*dx, hyres*dx, FALSE); gwy_si_unit_set_from_string(gwy_data_field_get_si_unit_xy(dfield), "m"); data = gwy_data_field_get_data(dfield); pixels = gdk_pixbuf_get_pixels(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); nchannels = gdk_pixbuf_get_n_channels(pixbuf); for (i = 0; i < hyres; i++) { gdouble *drow = data + i*hxres; guchar *p = pixels + i*rowstride; for (j = 0; j < hxres; j++, p += nchannels) drow[j] = (p[0] + p[1] + p[2])/765.0; } 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, "SampleName")) && *value) gwy_container_set_string_by_name(container, "/0/data/title", g_strdup(value)); else gwy_container_set_string_by_name(container, "/0/data/title", g_strdup("SEM")); meta = gwy_container_new(); g_hash_table_foreach(hash, store_meta, 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_object_unref(pixbuf); g_free(imagename); g_free(header); g_hash_table_destroy(hash); return container; }
static GwyContainer* microprof_txt_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL; guchar *p, *buffer = NULL; GwyTextHeaderParser parser; GHashTable *meta = NULL; GwySIUnit *siunit; gchar *header = NULL, *s, *prev; gsize size = 0; GError *err = NULL; GwyDataField *dfield = NULL; gdouble xreal, yreal, zscale, v; gint hlines, xres, yres, i, j; gdouble *d; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size < MICROPROF_MIN_TEXT_SIZE || memcmp(buffer, MAGIC_TXT, MAGIC_TXT_SIZE) != 0) { err_FILE_TYPE(error, "MicroProf"); goto fail; } hlines = atoi(buffer + MAGIC_TXT_SIZE); if (hlines < 7) { err_FILE_TYPE(error, "MicroProf"); goto fail; } /* Skip specified number of lines */ for (p = buffer, i = 0; i < hlines; i++) { while (*p != '\n' && (gsize)(p - buffer) < size) p++; if ((gsize)(p - buffer) == size) { err_FILE_TYPE(error, "MicroProf"); goto fail; } /* Now skip the \n */ p++; } header = g_memdup(buffer, p - buffer + 1); header[p - buffer] = '\0'; gwy_clear(&parser, 1); parser.key_value_separator = "="; meta = gwy_text_header_parse(header, &parser, NULL, NULL); if (!(s = g_hash_table_lookup(meta, "XSize")) || !((xres = atoi(s)) > 0)) { err_INVALID(error, "XSize"); goto fail; } if (!(s = g_hash_table_lookup(meta, "YSize")) || !((yres = atoi(s)) > 0)) { err_INVALID(error, "YSize"); goto fail; } if (!(s = g_hash_table_lookup(meta, "XRange")) || !((xreal = g_ascii_strtod(s, NULL)) > 0.0)) { err_INVALID(error, "YRange"); goto fail; } if (!(s = g_hash_table_lookup(meta, "YRange")) || !((yreal = g_ascii_strtod(s, NULL)) > 0.0)) { err_INVALID(error, "YRange"); goto fail; } if (!(s = g_hash_table_lookup(meta, "ZScale")) || !((zscale = g_ascii_strtod(s, NULL)) > 0.0)) { err_INVALID(error, "ZScale"); goto fail; } dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE); d = gwy_data_field_get_data(dfield); s = (gchar*)p; for (i = 0; i < yres; i++) { for (j = 0; j < xres; j++) { prev = s; /* Skip x */ v = strtol(s, &s, 10); if (v != j) g_warning("Column number mismatch"); /* Skip y */ v = strtol(s, &s, 10); if (v != i) g_warning("Row number mismatch"); /* Read value */ d[(yres-1 - i)*xres + j] = strtol(s, &s, 10)*zscale; /* Check whether we moved in the file */ if (s == prev) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("File contains fewer than XSize*YSize data " "points.")); goto fail; } } } siunit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_xy(dfield, siunit); g_object_unref(siunit); siunit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_z(dfield, siunit); g_object_unref(siunit); container = gwy_container_new(); gwy_container_set_object_by_name(container, "/0/data", dfield); g_object_unref(dfield); gwy_container_set_string_by_name(container, "/0/data/title", g_strdup("Topography")); gwy_file_channel_import_log_add(container, 0, NULL, filename); fail: gwy_file_abandon_contents(buffer, size, NULL); if (meta) g_hash_table_destroy(meta); g_free(header); return container; }
static GwyContainer* igor_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *meta = NULL, *container = NULL; GwyDataField *dfield = NULL, *maskfield = NULL; GwyTextHeaderParser parser; IgorFile igorfile; IgorWaveHeader5 *wave5; GError *err = NULL; guchar *p, *buffer = NULL; gint xres, yres; gsize expected_size, size = 0; gchar *note = NULL; const gchar *value; gchar key[64]; guint i, chid; GQuark quark; guint nlabels; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } gwy_clear(&igorfile, 1); if (!igor_read_headers(&igorfile, buffer, size, FALSE, error)) goto fail; /* Only accept v5 files because older do not support 2D data */ if (igorfile.header.version != 5) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Format version is %d. Only version 5 is supported."), igorfile.header.version); goto fail; } /* Detect Asylum research files, leave it at generic if not detected. */ if (memcmp(buffer + size-5, "MFP3D", 5) == 0) igorfile.variant = IGOR_ASYLUM_MPF3D; else if (memcmp(buffer + size-5, "Force", 5) == 0) igorfile.variant = IGOR_ASYLUM_FORCE; gwy_debug("producer variant %u", igorfile.variant); /* Must have exactly 3 dims: xres, yres, nchannels */ wave5 = &igorfile.wave5; xres = wave5->n_dim[0]; yres = wave5->n_dim[1]; igorfile.nchannels = wave5->n_dim[2]; if (igorfile.nchannels==0) igorfile.nchannels=1; if (!xres || !yres || !igorfile.nchannels || wave5->n_dim[3]) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Only two-dimensional data are supported.")); goto fail; } igorfile.type_size = igor_data_type_size(wave5->type); if (!igorfile.type_size) { err_DATA_TYPE(error, wave5->type); goto fail; } if (wave5->npts != xres*yres*igorfile.nchannels) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Number of data points %u does not match resolutions " "%u×%u×%u."), wave5->npts, xres, yres, igorfile.nchannels); goto fail; } if (igorfile.header.wfm_size <= igorfile.wave_header_size) { err_INVALID(error, "wfmSize"); goto fail; } expected_size = igorfile.header.wfm_size - igorfile.wave_header_size; if (expected_size != wave5->npts*igorfile.type_size) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Data size %u does not match " "the number of data points %u×%u."), (guint)expected_size, wave5->npts, igorfile.type_size); } if (err_SIZE_MISMATCH(error, expected_size + igorfile.headers_size, size, FALSE)) goto fail; p = buffer + igorfile.headers_size + expected_size; gwy_debug("remaning data size: %lu", (gulong)(size - (p - buffer))); p += igorfile.header.formula_size; if ((igorfile.variant == IGOR_ASYLUM_FORCE || igorfile.variant == IGOR_ASYLUM_MPF3D) && igorfile.header.note_size && (p - buffer) + igorfile.header.note_size <= size) { note = g_strndup((const gchar*)p, size); gwy_clear(&parser, 1); parser.key_value_separator = ":"; igorfile.meta = gwy_text_header_parse(note, &parser, NULL, NULL); } p += igorfile.header.note_size; /* FIXME: Support extended units for non-Asylum files! */ p += igorfile.header.data_e_units_size; for (i = 0; i < MAXDIMS; i++) p += igorfile.header.dim_e_units_size[i]; /* Skip labels of x and y dimension, we don't know what to do with them. */ for (i = 0; i < 2; i++) p += igorfile.header.dim_labels_size[i]; /* FIXME: The labels are mandatory only in Asylum Research files. */ nlabels = igorfile.header.dim_labels_size[2]/(MAX_WAVE_NAME5+1); expected_size = (MAX_WAVE_NAME5 + 1)*(nlabels); if ((p - buffer) + expected_size > size ) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Cannot read channel labels.")); goto fail; } igorfile.titles = read_channel_labels(p, igorfile.nchannels+1, nlabels); p += igorfile.header.dim_labels_size[2]; if (igorfile.meta) { igorfile.channel_info = g_new0(AsylumChannelInfo, igorfile.nchannels); for (i = 0; i < igorfile.nchannels; i++) { AsylumChannelInfo *chinfo = igorfile.channel_info + i; const gchar *title = g_ptr_array_index(igorfile.titles, i+1); if (title) { chinfo->name = canonicalize_title(title); g_snprintf(key, sizeof(key), "%sUnit", chinfo->name); value = g_hash_table_lookup(igorfile.meta, key); if (value) chinfo->units = value; else chinfo->units = channel_title_to_units(chinfo->name); } } } container = gwy_container_new(); for (i = chid = 0; i < igorfile.nchannels; i++, chid++) { const gchar *title = g_ptr_array_index(igorfile.titles, i+1); const gchar *zunits = NULL; if (igorfile.channel_info) { AsylumChannelInfo *chinfo = igorfile.channel_info + i; zunits = chinfo->units; meta = igor_get_metadata(&igorfile, i + 1); } dfield = igor_read_data_field(&igorfile, buffer, i, zunits, FALSE); maskfield = gwy_app_channel_mask_of_nans(dfield, TRUE); quark = gwy_app_get_data_key_for_id(chid); gwy_container_set_object(container, quark, dfield); g_object_unref(dfield); if (maskfield) { g_snprintf(key, sizeof(key), "/%d/mask", chid); gwy_container_set_object_by_name(container, key, maskfield); } if (meta) { g_snprintf(key, sizeof(key), "/%d/meta", chid); gwy_container_set_object_by_name(container, key, meta); } if (title) { g_snprintf(key, sizeof(key), "/%d/data/title", chid); gwy_container_set_string_by_name(container, key, g_strdup(title)); } gwy_app_channel_title_fall_back(container,chid); if (wave5->type & IGOR_COMPLEX) { chid++; dfield = igor_read_data_field(&igorfile, buffer, i, zunits, TRUE); quark = gwy_app_get_data_key_for_id(chid); gwy_container_set_object(container, quark, dfield); g_object_unref(dfield); if (meta) { g_snprintf(key, sizeof(key), "/%d/meta", chid); /* container still holds a reference */ g_object_unref(meta); meta = gwy_container_duplicate(meta); gwy_container_set_object_by_name(container, key, meta); } if (maskfield) { g_snprintf(key, sizeof(key), "/%d/mask", chid); /* container still holds a reference */ g_object_unref(maskfield); maskfield = gwy_data_field_duplicate(maskfield); gwy_container_set_object_by_name(container, key, maskfield); } if (title) { g_snprintf(key, sizeof(key), "/%d/data/title", chid); gwy_container_set_string_by_name(container, key, g_strdup(title)); }; gwy_app_channel_title_fall_back(container,chid); } gwy_object_unref(meta); gwy_object_unref(maskfield); gwy_file_channel_import_log_add(container, chid, NULL, filename); } fail: gwy_file_abandon_contents(buffer, size, NULL); g_free(note); if (igorfile.channel_info) { for (i = 0; i < igorfile.nchannels; i++) g_free(igorfile.channel_info[i].name); g_free(igorfile.channel_info); } if (igorfile.meta) g_hash_table_destroy(igorfile.meta); if (igorfile.titles) { g_ptr_array_foreach(igorfile.titles, (GFunc)g_free, NULL); g_ptr_array_free(igorfile.titles, TRUE); } return container; }