X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Finput%2Finput.c;h=2a23aec2bd81d4a7a4326fb8c06c9acf3b1c47f4;hb=090f1e1e5478ea15baa3731fefbd4aff9be78c77;hp=e93925d2b1c590572d7eb5b66ad7fa839b57d283;hpb=4619fab47acf4fb0a1c035072c2e8552b4bcbae3;p=libsigrok.git diff --git a/src/input/input.c b/src/input/input.c index e93925d2..2a23aec2 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -29,6 +29,8 @@ #define LOG_PREFIX "input" /** @endcond */ +#define CHUNK_SIZE (4 * 1024 * 1024) + /** * @file * @@ -62,16 +64,24 @@ extern SR_PRIV struct sr_input_module input_chronovu_la8; extern SR_PRIV struct sr_input_module input_csv; extern SR_PRIV struct sr_input_module input_binary; +extern SR_PRIV struct sr_input_module input_trace32_ad; extern SR_PRIV struct sr_input_module input_vcd; extern SR_PRIV struct sr_input_module input_wav; +extern SR_PRIV struct sr_input_module input_raw_analog; +extern SR_PRIV struct sr_input_module input_logicport; +extern SR_PRIV struct sr_input_module input_null; /* @endcond */ static const struct sr_input_module *input_module_list[] = { &input_binary, &input_chronovu_la8, &input_csv, + &input_trace32_ad, &input_vcd, &input_wav, + &input_raw_analog, + &input_logicport, + &input_null, NULL, }; @@ -242,7 +252,7 @@ SR_API struct sr_input *sr_input_new(const struct sr_input_module *imod, GHashTable *options) { struct sr_input *in; - struct sr_option *mod_opts; + const struct sr_option *mod_opts; const GVariantType *gvt; GHashTable *new_opts; GHashTableIter iter; @@ -330,11 +340,15 @@ static gboolean check_required_metadata(const uint8_t *metadata, uint8_t *avail) * Try to find an input module that can parse the given buffer. * * The buffer must contain enough of the beginning of the file for - * the input modules to find a match. This is format-dependent, but - * 128 bytes is normally enough. + * the input modules to find a match. This is format-dependent. When + * magic strings get checked, 128 bytes normally could be enough. Note + * that some formats try to parse larger header sections, and benefit + * from seeing a larger scope. * * If an input module is found, an instance is created into *in. - * Otherwise, *in contains NULL. + * Otherwise, *in contains NULL. When multiple input moduless claim + * support for the format, the one with highest confidence takes + * precedence. Applications will see at most one input module spec. * * If an instance is created, it has the given buffer used for scanning * already submitted to it, to be processed before more data is sent. @@ -345,9 +359,10 @@ static gboolean check_required_metadata(const uint8_t *metadata, uint8_t *avail) */ SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in) { - const struct sr_input_module *imod; + const struct sr_input_module *imod, *best_imod; GHashTable *meta; unsigned int m, i; + unsigned int conf, best_conf; int ret; uint8_t mitem, avail_metadata[8]; @@ -356,7 +371,8 @@ SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in) avail_metadata[1] = 0; *in = NULL; - ret = SR_ERR; + best_imod = NULL; + best_conf = ~0; for (i = 0; input_module_list[i]; i++) { imod = input_module_list[i]; if (!imod->metadata[0]) { @@ -380,82 +396,55 @@ SR_API int sr_input_scan_buffer(GString *buf, const struct sr_input **in) continue; } sr_spew("Trying module %s.", imod->id); - ret = imod->format_match(meta); + ret = imod->format_match(meta, &conf); g_hash_table_destroy(meta); if (ret == SR_ERR_DATA) { /* Module recognized this buffer, but cannot handle it. */ - break; + continue; } else if (ret == SR_ERR) { /* Module didn't recognize this buffer. */ continue; } else if (ret != SR_OK) { /* Can be SR_ERR_NA. */ - return ret; + continue; } /* Found a matching module. */ - sr_spew("Module %s matched.", imod->id); - *in = sr_input_new(imod, NULL); - g_string_insert_len((*in)->buf, 0, buf->str, buf->len); - break; + sr_spew("Module %s matched, confidence %u.", imod->id, conf); + if (conf >= best_conf) + continue; + best_imod = imod; + best_conf = conf; } - return ret; -} + if (best_imod) { + *in = sr_input_new(best_imod, NULL); + g_string_insert_len((*in)->buf, 0, buf->str, buf->len); + return SR_OK; + } -/** Retrieve the size of the open stream @a file. - * This function only works on seekable streams. However, the set of seekable - * streams is generally congruent with the set of streams that have a size. - * Code that needs to work with any type of stream (including pipes) should - * require neither seekability nor advance knowledge of the size. - * On failure, the return value is negative and errno is set. - * @param file An I/O stream opened in binary mode. - * @return The size of @a file in bytes, or a negative value on failure. - */ -SR_PRIV int64_t sr_file_get_size(FILE *file) -{ - off_t filepos, filesize; - - /* ftello() and fseeko() are not standard C, but part of POSIX.1-2001. - * Thus, if these functions are available at all, they can reasonably - * be expected to also conform to POSIX semantics. In particular, this - * means that ftello() after fseeko(..., SEEK_END) has a defined result - * and can be used to get the size of a seekable stream. - * On Windows, the result is fully defined only for binary streams. - */ - filepos = ftello(file); - if (filepos < 0) - return -1; - - if (fseeko(file, 0, SEEK_END) < 0) - return -1; - - filesize = ftello(file); - if (filesize < 0) - return -1; - - if (fseeko(file, filepos, SEEK_SET) < 0) - return -1; - - return filesize; + return SR_ERR; } /** * Try to find an input module that can parse the given file. * * If an input module is found, an instance is created into *in. - * Otherwise, *in contains NULL. + * Otherwise, *in contains NULL. When multiple input moduless claim + * support for the format, the one with highest confidence takes + * precedence. Applications will see at most one input module spec. * */ SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in) { int64_t filesize; FILE *stream; - const struct sr_input_module *imod; + const struct sr_input_module *imod, *best_imod; GHashTable *meta; GString *header; size_t count; unsigned int midx, i; + unsigned int conf, best_conf; int ret; uint8_t avail_metadata[8]; @@ -477,11 +466,9 @@ SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in) fclose(stream); return SR_ERR; } - /* This actually allocates 256 bytes to allow for NUL termination. */ - header = g_string_sized_new(255); + header = g_string_sized_new(CHUNK_SIZE); count = fread(header->str, 1, header->allocated_len - 1, stream); - - if (count != header->allocated_len - 1 && ferror(stream)) { + if (count < 1 || ferror(stream)) { sr_err("Failed to read %s: %s", filename, g_strerror(errno)); fclose(stream); g_string_free(header, TRUE); @@ -504,8 +491,8 @@ SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in) avail_metadata[midx] = 0; /* TODO: MIME type */ - ret = SR_ERR; - + best_imod = NULL; + best_conf = ~0; for (i = 0; input_module_list[i]; i++) { imod = input_module_list[i]; if (!imod->metadata[0]) { @@ -519,24 +506,46 @@ SR_API int sr_input_scan_file(const char *filename, const struct sr_input **in) sr_dbg("Trying module %s.", imod->id); - ret = imod->format_match(meta); + ret = imod->format_match(meta, &conf); if (ret == SR_ERR) { /* Module didn't recognize this buffer. */ continue; } else if (ret != SR_OK) { /* Module recognized this buffer, but cannot handle it. */ - break; + continue; } /* Found a matching module. */ - sr_dbg("Module %s matched.", imod->id); - - *in = sr_input_new(imod, NULL); - break; + sr_dbg("Module %s matched, confidence %u.", imod->id, conf); + if (conf >= best_conf) + continue; + best_imod = imod; + best_conf = conf; } g_hash_table_destroy(meta); g_string_free(header, TRUE); - return ret; + if (best_imod) { + *in = sr_input_new(best_imod, NULL); + return SR_OK; + } + + return SR_ERR; +} + +/** + * Return the input instance's module "class". This can be used to find out + * which input module handles a specific input file. This is especially + * useful when an application did not create the input stream by specifying + * an input module, but instead some shortcut or convenience wrapper did. + * + * @since 0.6.0 + */ +SR_API const struct sr_input_module *sr_input_module_get(const struct sr_input *in) +{ + if (!in) + return NULL; + + return in->module; } /** @@ -592,6 +601,27 @@ SR_API int sr_input_end(const struct sr_input *in) return in->module->end((struct sr_input *)in); } +/** + * Reset the input module's input handling structures. + * + * Causes the input module to reset its internal state so that we can re-send + * the input data from the beginning without having to re-create the entire + * input module. + * + * @since 0.5.0 + */ +SR_API int sr_input_reset(const struct sr_input *in) +{ + if (!in->module->reset) { + sr_spew("Tried to reset %s module but no reset handler found.", + in->module->id); + return SR_OK; + } + + sr_spew("Resetting %s module.", in->module->id); + return in->module->reset((struct sr_input *)in); +} + /** * Free the specified input instance and all associated resources. * @@ -604,8 +634,7 @@ SR_API void sr_input_free(const struct sr_input *in) if (in->module->cleanup) in->module->cleanup((struct sr_input *)in); - if (in->sdi) - sr_dev_inst_free(in->sdi); + sr_dev_inst_free(in->sdi); if (in->buf->len > 64) { /* That seems more than just some sub-unitsize leftover... */ sr_warn("Found %" G_GSIZE_FORMAT