rstr_t * backend_prop_make(prop_t *model, const char *suggest) { proppage_t *pp; rstr_t *r; hts_mutex_lock(&pp_mutex); pp = calloc(1, sizeof(proppage_t)); if(suggest == NULL) { char url[50]; pp_tally++; snprintf(url, sizeof(url), "prop:%d", pp_tally); r = rstr_alloc(url); } else { r = rstr_alloc(suggest); } pp->pp_url = rstr_dup(r); pp->pp_model = prop_ref_inc(model); pp->pp_model_sub = prop_subscribe(PROP_SUB_TRACK_DESTROY, PROP_TAG_CALLBACK, pp_cb, pp, PROP_TAG_MUTEX, &pp_mutex, PROP_TAG_ROOT, model, NULL); LIST_INSERT_HEAD(&proppages, pp, pp_link); hts_mutex_unlock(&pp_mutex); return r; }
static int sidfile_scandir(fa_dir_t *fd, const char *url, char *errbuf, size_t errlen) { void *fh = NULL; char *p, *fpath = mystrdupa(url); char buf[128]; char name[32]; char turl[URL_MAX]; int tracks, i; fa_dir_entry_t *fde; rstr_t *album, *artist; if((p = strrchr(fpath, '/')) == NULL) { snprintf(errbuf, errlen, "Invalid filename"); return -1; } *p = 0; if((fh = fa_open(fpath, errbuf, errlen)) == NULL) return -1; if(fa_read(fh, buf, 128) != 128) { snprintf(errbuf, errlen, "Unable to read file"); fa_close(fh); return -1; } album = rstr_alloc(utf8_from_bytes((char *)buf + 0x16, 32, NULL)); artist = rstr_alloc(utf8_from_bytes((char *)buf + 0x36, 32, NULL)); tracks = buf[0xf]; for(i = 0; i < tracks; i++) { snprintf(name, sizeof(name), "Track %02d", i + 1); snprintf(turl, sizeof(turl), "sidplayer:%s/%d", fpath, i + 1); fde = fa_dir_add(fd, turl, name, CONTENT_AUDIO); fde->fde_probestatus = FDE_PROBE_DEEP; fde->fde_metadata = prop_create_root("metadata"); prop_set_string(prop_create(fde->fde_metadata, "title"), name); prop_set_rstring(prop_create(fde->fde_metadata, "album"), album); prop_set_rstring(prop_create(fde->fde_metadata, "artist"), artist); } rstr_release(album); rstr_release(artist); fa_close(fh); return 0; }
static nls_string_t * nls_string_find(const char *key) { nls_string_t *ns; unsigned int hash = mystrhash(key) % NLS_STRING_HASH_WIDTH; hts_mutex_lock(&nls_mutex); LIST_FOREACH(ns, &nls_strings[hash], ns_link) if(!strcmp(rstr_get(ns->ns_key), key)) break; if(ns == NULL) { ns = calloc(1, sizeof(nls_string_t)); ns->ns_key = rstr_alloc(key); ns->ns_prop = prop_create_root(NULL); prop_set_rstring(ns->ns_prop, ns->ns_key); } else { LIST_REMOVE(ns, ns_link); } LIST_INSERT_HEAD(&nls_strings[hash], ns, ns_link); hts_mutex_unlock(&nls_mutex); return ns; }
static void video_query(bmdb_t *b, void *db) { sqlite3_stmt *stmt; int rc = db_prepare(db, &stmt, "SELECT i.url, p.url, i.contenttype " "FROM item AS i, item AS p " "WHERE i.url LIKE ?1 " "AND (i.contenttype == 5 OR i.contenttype == 7) " "AND i.parent = p.id" ); if(rc != SQLITE_OK) return; char q[PATH_MAX]; db_escape_path_query(q, sizeof(q), b->b_query); sqlite3_bind_text(stmt, 1, q, -1, SQLITE_STATIC); while((rc = db_step(stmt)) == SQLITE_ROW) { const char *url = (const char *)sqlite3_column_text(stmt, 0); const char *parent = (const char *)sqlite3_column_text(stmt, 1); rstr_t *ct = rstr_alloc(content2type(sqlite3_column_int(stmt, 2))); add_item(b, url, parent, ct, NULL, 0, NULL, 0); rstr_release(ct); } sqlite3_finalize(stmt); }
static void set_source(glw_t *w, rstr_t *filename) { glw_image_t *gi = (glw_image_t *)w; const rstr_t *curname; if(gi->gi_pending_url != NULL) curname = gi->gi_pending_url; else if(gi->gi_pending != NULL) curname = gi->gi_pending->glt_url; else if(gi->gi_current != NULL) curname = gi->gi_current->glt_url; else curname = NULL; if(curname != NULL && filename != NULL && !strcmp(rstr_get(filename), rstr_get(curname))) return; if(gi->gi_pending_url != NULL) rstr_release(gi->gi_pending_url); gi->gi_pending_url = filename ? rstr_dup(filename) : rstr_alloc(""); }
void metadata_filename_to_title(const char *filename, int *yearp, rstr_t **titlep) { int year = 0; char *s = mystrdupa(filename); url_deescape(s); int i = strlen(s); while(i > 0) { if(i > 5 && s[i-5] == '.' && isnum(s[i-4]) && isnum(s[i-3]) && isnum(s[i-2]) && isnum(s[i-1])) { year = atoi(s + i - 4); i -= 5; s[i] = 0; continue; } if(i > 7 && s[i-7] == ' ' && s[i-6] == '(' && isnum(s[i-5]) && isnum(s[i-4]) && isnum(s[i-3]) && isnum(s[i-2]) && s[i-1] == ')') { year = atoi(s + i - 5); i -= 7; s[i] = 0; continue; } int j; for(j = 0; stopstrings[j] != NULL; j++) { int len = strlen(stopstrings[j]); if(i > len+1 && (s[i-len-1] == '.' || s[i-len-1] == ' ') && !strncasecmp(s+i-len, stopstrings[j], len) && (s[i] == '.' || s[i] == ' ' || s[i] == '-' || s[i] == 0)) { i -= len+1; s[i] = 0; break; } } if(stopstrings[j] != NULL) continue; i--; } for(i = 0; s[i]; i++) { if(s[i] == '.') { s[i] = ' '; } } if(yearp != NULL) *yearp = year; if(titlep != NULL) *titlep = rstr_alloc(s); }
static void artists_query(bmdb_t *b, void *db) { sqlite3_stmt *stmt; int rc = db_prepare(db, &stmt, "SELECT artist.id, artist.title " "FROM artist,item,audioitem " "WHERE audioitem.item_id = item.id " "AND audioitem.artist_id = artist.id " "AND item.url like ?1 " "AND audioitem.ds_id = 1 " "GROUP by artist_id"); if(rc != SQLITE_OK) return; char q[PATH_MAX]; db_escape_path_query(q, sizeof(q), b->b_query); sqlite3_bind_text(stmt, 1, q, -1, SQLITE_STATIC); rstr_t *ct = rstr_alloc("artist"); while((rc = db_step(stmt)) == SQLITE_ROW) { char url[PATH_MAX]; snprintf(url, sizeof(url), "library:artist:%d", sqlite3_column_int(stmt, 0)); add_item(b, url, NULL, ct, (const char *)sqlite3_column_text(stmt, 1), 0, NULL, 0); } rstr_release(ct); sqlite3_finalize(stmt); }
static int is_plugin_blacklisted(const char *id, const char *version, rstr_t **reason) { char tmp[512]; int verint = parse_version_int(version); if(!strcmp(id, "custombg")) { if(reason != NULL) { *reason = _("Custom backgrounds can now be set in Settings -> Look and Feel"); } return 1; } for(int i = 0; i < ARRAYSIZE(blacklist); i++) { if(strcmp(id, blacklist[i].id)) continue; if(verint >= blacklist[i].version) continue; if(reason != NULL) { rstr_t *f = _("Version %s is no longer compatible with Movian"); snprintf(tmp, sizeof(tmp), rstr_get(f), version); rstr_release(f); *reason = rstr_alloc(tmp); } return 1; } return 0; }
static void set_torrent_cache_path(void *opaque, const char *str) { rstr_release(btg.btg_cache_path); btg.btg_cache_path = rstr_alloc(str); if(allow_update) torrent_diskio_scan(0); }
static rstr_t * title_from_url(const char *url) { char tmp[1024]; fa_url_get_last_component(tmp, sizeof(tmp), url); rstr_t *r = rstr_alloc(tmp); return r; }
rstr_t * htsmsg_store_get_str(const char *store, const char *key) { hts_mutex_lock(&loaded_msg_mutex); loaded_msg_t *lm = htsmsg_store_obtain(store, 1); rstr_t *r = rstr_alloc(htsmsg_get_str(lm->lm_msg, key)); hts_mutex_unlock(&loaded_msg_mutex); return r; }
static int set_rstring(glw_view_eval_context_t *ec, const token_attrib_t *a, struct token *t) { rstr_t *rstr; char buf[30]; void (*fn)(struct glw *w, rstr_t *str) = a->fn; switch(t->type) { case TOKEN_VOID: buf[0] = 0; break; case TOKEN_CSTRING: rstr = rstr_alloc(t->t_cstring); fn(ec->w, rstr); rstr_release(rstr); return 0; case TOKEN_RSTRING: case TOKEN_LINK: fn(ec->w, t->t_rstring); return 0; case TOKEN_INT: snprintf(buf, sizeof(buf), "%d", t->t_int); break; case TOKEN_FLOAT: snprintf(buf, sizeof(buf), "%f", t->t_float); break; default: return glw_view_seterr(ec->ei, t, "Attribute '%s' expects a string or scalar, got %s", a->name, token2name(t)); } rstr = rstr_alloc(buf); fn(ec->w, rstr); rstr_release(rstr); return 0; }
static void artist_query(bmdb_t *b, void *db) { sqlite3_stmt *stmt; int rc; int artist_id = atoi(b->b_query); rc = db_prepare(db, &stmt, "SELECT title " "FROM artist " "WHERE ds_id = 1 " "AND id = ?1"); if(rc != SQLITE_OK) return; sqlite3_bind_int(stmt, 1, artist_id); if(db_step(stmt) == SQLITE_ROW) { rstr_t *artist = db_rstr(stmt, 0); prop_set(b->b_metadata, "title", PROP_SET_RSTRING, artist); prop_t *p = prop_create_r(b->b_metadata, "artist_images"); metadata_bind_artistpics(p, artist); prop_ref_dec(p); rstr_release(artist); } sqlite3_finalize(stmt); rc = db_prepare(db, &stmt, "SELECT id,title " "FROM album " "WHERE ds_id = 1 " "AND artist_id = ?1"); if(rc != SQLITE_OK) return; sqlite3_bind_int(stmt, 1, artist_id); rstr_t *ct = rstr_alloc("album"); while((rc = db_step(stmt)) == SQLITE_ROW) { char url[PATH_MAX]; snprintf(url, sizeof(url), "library:album:%d", sqlite3_column_int(stmt, 0)); add_item(b, url, NULL, ct, (const char *)sqlite3_column_text(stmt, 1), 0, NULL, 0); } rstr_release(ct); sqlite3_finalize(stmt); }
rstr_t * js_prop_rstr(JSContext *cx, JSObject *o, const char *prop) { jsval val; if(!JS_GetProperty(cx, o, prop, &val)) return NULL; if(!JSVAL_IS_STRING(val)) return NULL; JSString *s = JS_ValueToString(cx, val); return s ? rstr_alloc(JS_GetStringBytes(s)) : NULL; }
/** * Probe SPC files */ static void fa_probe_spc(metadata_t *md, uint8_t *pb) { char buf[33]; buf[32] = 0; if(memcmp("v0.30", pb + 0x1c, 4)) return; if(pb[0x23] != 0x1a) return; memcpy(buf, pb + 0x2e, 32); md->md_title = rstr_alloc(buf); memcpy(buf, pb + 0x4e, 32); md->md_album = rstr_alloc(buf); memcpy(buf, pb + 0xa9, 3); buf[3] = 0; md->md_duration = atoi(buf); }
static int hc_image(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; pixmap_t *pm; char errbuf[200]; const char *content; image_meta_t im = {0}; im.im_no_decoding = 1; rstr_t *url = rstr_alloc(remain); pm = backend_imageloader(url, &im, NULL, errbuf, sizeof(errbuf), NULL, NULL, NULL); rstr_release(url); if(pm == NULL) return http_error(hc, 404, "Unable to load image %s : %s", remain, errbuf); if(!pixmap_is_coded(pm)) { pixmap_release(pm); return http_error(hc, 404, "Unable to load image %s : Original data not available", remain); } htsbuf_queue_init(&out, 0); htsbuf_append(&out, pm->pm_data, pm->pm_size); switch(pm->pm_type) { case PIXMAP_JPEG: content = "image/jpeg"; break; case PIXMAP_PNG: content = "image/png"; break; case PIXMAP_GIF: content = "image/gif"; break; default: content = "image"; break; } pixmap_release(pm); return http_send_reply(hc, 0, content, NULL, NULL, 0, &out); }
static void ns_val_set(nls_string_t *ns, int idx, const char *value) { if(ns->ns_values == 0 && idx == 0) { ns->ns_values = 1; ns->ns_u.rstr = rstr_alloc(value); return; } if(ns->ns_values == 1 && idx == 0) { rstr_release(ns->ns_u.rstr); ns->ns_u.rstr = rstr_alloc(value); return; } if(idx < ns->ns_values) { assert(ns->ns_values > 1); rstr_release(ns->ns_u.vec[idx]); ns->ns_u.vec[idx] = rstr_alloc(value); return; } rstr_t *p = NULL; if(ns->ns_values == 1) { p = ns->ns_u.rstr; ns->ns_values = 0; assert(idx > 0); } ns->ns_u.vec = realloc(ns->ns_values ? ns->ns_u.vec : NULL, (1+idx) * sizeof(rstr_t *)); if(p) ns->ns_u.vec[0] = p; ns->ns_u.vec[idx] = rstr_alloc(value); ns->ns_values = idx + 1; }
static JSBool js_notify(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { const char *text; int delay; const char *icon = NULL; if(!JS_ConvertArguments(cx, argc, argv, "si/s", &text, &delay, &icon)) return JS_FALSE; notify_add(NULL, NOTIFY_INFO, icon, delay, rstr_alloc("%s"), text); return JS_TRUE; }
int metadata_filename_to_episode(const char *s, int *seasonp, int *episodep, rstr_t **titlep) { int i, j; int len = strlen(s); int season = -1; int episode = -1; for(i = 0; i < len; i++) { if((s[i] == 's' || s[i] == 'S') && isnum(s[i+1]) && isnum(s[i+2])) { int o = 3+i; if(s[o] == '.') o++; if((s[o] == 'e' || s[o] == 'E') && isnum(s[o+1]) && isnum(s[o+2])) { season = atoi(s+i+1); episode = atoi(s+o+1); break; } } } if(season == -1 || episode == -1) return -1; *seasonp = season; *episodep = episode; char *t = mystrdupa(s); url_deescape(t); for(j= 0; j < i; j++) { if(t[j] == '.') { t[j] = ' '; } } t[j] = 0; if(titlep != NULL) { if(j) *titlep = rstr_alloc(t); else *titlep = NULL; } return 0; }
void glw_load_universe(glw_root_t *gr) { prop_t *page = prop_create(gr->gr_prop_ui, "root"); glw_unload_universe(gr); rstr_t *universe = rstr_alloc("skin://universe.view"); gr->gr_universe = glw_view_create(gr, universe, NULL, page, NULL, NULL, NULL, 0, 1); rstr_release(universe); glw_signal_handler_register(gr->gr_universe, top_event_handler, gr, 1000); }
static int xmp_probe(metadata_t *md, const char *url, fa_handle_t *fh) { struct xmp_test_info info; FILE *f = fa_fopen(fh, 0); if(f == NULL) return 0; int r = xmp_test_modulef(f, &info); fclose(f); if(r < 0) return 0; md->md_title = rstr_alloc(info.name); md->md_contenttype = CONTENT_AUDIO; return 1; }
/** * Check if file is an iso image * pb is guaranteed to point at 128 byts * of data starting 0x8000 of start of file */ static int fa_probe_iso0(metadata_t *md, uint8_t *pb) { uint8_t *p; if(memcmp(pb, isosig, 8)) return -1; p = &pb[40]; while(*p > 32 && p != &pb[72]) p++; *p = 0; if(md != NULL) { md->md_title = rstr_alloc((const char *)pb + 40); md->md_contenttype = CONTENT_DVD; } return 0; }
static void handle_method_call(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *param, GDBusMethodInvocation *inv, gpointer user_data) { TRACE(TRACE_DEBUG, "CONNMAN", "agent method call: %s", method_name); if(!strcmp(method_name, "ReportError")) { connman_service_t *cs = connman_service_from_params(param); const char *msg = g_variant_get_string(g_variant_get_child_value(param, 1), NULL); notify_add(NULL, NOTIFY_ERROR, NULL, 3, rstr_alloc("%s\n%s"), cs ? cs->cs_name : "Unknown network", msg); g_dbus_method_invocation_return_value(inv, NULL); } else if(!strcmp(method_name, "RequestInput")) { connman_service_t *cs = connman_service_from_params(param); if(cs == NULL) { g_dbus_method_invocation_return_error_literal(inv, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Unknown service"); return; } agent_request_input(cs, g_variant_get_child_value(param, 1), inv); } else { g_dbus_method_invocation_return_error(inv, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Unknown method %s", method_name); return; } }
static nls_string_t * nls_string_find(const char *key) { nls_string_t *ns; LIST_FOREACH(ns, &nls_strings, ns_link) if(!strcmp(rstr_get(ns->ns_key), key)) break; if(ns == NULL) { ns = calloc(1, sizeof(nls_string_t)); ns->ns_key = rstr_alloc(key); ns->ns_prop = prop_create_root(NULL); prop_set_rstring(ns->ns_prop, ns->ns_key); } else { LIST_REMOVE(ns, ns_link); } LIST_INSERT_HEAD(&nls_strings, ns, ns_link); return ns; }
/** * Obtain details from playlist */ static void fa_probe_playlist(metadata_t *md, const char *url, uint8_t *pb, size_t pbsize) { const char *t; char tmp1[300]; int i; t = strrchr(url, '/'); t = t ? t + 1 : url; i = 0; while(*t && *t != '.') tmp1[i++] = *t++; tmp1[i] = 0; md->md_title = rstr_alloc(tmp1); t = strstr((char *)pb, "NumberOfEntries="); if(t != NULL) md->md_tracks = atoi(t + 16); }
/** * Load a file using the 'glw_rawloader' method * * Returns pointer to last token, or NULL if an error occured. * If an error occured 'ei' will be filled with data * */ token_t * glw_view_load1(glw_root_t *gr, const char *filename, errorinfo_t *ei, token_t *prev) { char *src; rstr_t *f; token_t *last; char errbuf[256]; if((src = fa_quickload(filename, NULL, gr->gr_vpaths, errbuf, sizeof(errbuf))) == NULL) { snprintf(ei->error, sizeof(ei->error), "Unable to open \"%s\" -- %s", filename, errbuf); snprintf(ei->file, sizeof(ei->file), "%s", rstr_get(prev->file)); ei->line = prev->line; return NULL; } f = rstr_alloc(filename); last = lexer(src, ei, f, prev); rstr_release(f); free(src); return last; }
static JSBool js_appendItem0(JSContext *cx, js_model_t *model, prop_t *parent, const char *url, const char *type, JSObject *metaobj, jsval *data, jsval *rval, int enabled, const char *metabind) { install_nodesub(model); prop_t *item = prop_create_root(NULL); rstr_t *rurl = url ? rstr_alloc(url) : NULL; if(url != NULL) prop_set(item, "url", PROP_SET_RSTRING, rurl); if(data != NULL) js_prop_set_from_jsval(cx, prop_create(item, "data"), *data); *rval = JSVAL_VOID; if(metabind != NULL) playinfo_bind_url_to_prop(metabind, item); if(type != NULL) { prop_set_string(prop_create(item, "type"), type); if(metaobj) js_prop_from_object(cx, metaobj, prop_create(item, "metadata")); } else if(url != NULL) { if(backend_resolve_item(url, item)) { prop_destroy(item); rstr_release(rurl); return JS_TRUE; } } prop_set_int(prop_create(item, "enabled"), enabled); prop_t *p = prop_ref_inc(item); if(prop_set_parent(item, parent)) { prop_destroy(item); prop_ref_dec(p); } else { JSObject *robj = JS_NewObjectWithGivenProto(cx, &item_class, JSVAL_TO_OBJECT(model->jm_item_proto), NULL); *rval = OBJECT_TO_JSVAL(robj); js_item_t *ji = calloc(1, sizeof(js_item_t)); atomic_add(&model->jm_refcount, 1); ji->ji_url = rstr_dup(rurl); ji->ji_model = model; ji->ji_root = p; TAILQ_INSERT_TAIL(&model->jm_items, ji, ji_link); JS_SetPrivate(cx, robj, ji); ji->ji_enable_set_property = 1; ji->ji_eventsub = prop_subscribe(PROP_SUB_TRACK_DESTROY, PROP_TAG_CALLBACK, js_item_eventsub, ji, PROP_TAG_ROOT, ji->ji_root, PROP_TAG_COURIER, model->jm_pc, NULL); model->jm_subs++; ji->ji_this = OBJECT_TO_JSVAL(robj); JS_AddNamedRoot(cx, &ji->ji_this, "item_this"); prop_tag_set(ji->ji_root, model, ji); } rstr_release(rurl); return JS_TRUE; }
static int hc_image(http_connection_t *hc, const char *remain, void *opaque, http_cmd_t method) { htsbuf_queue_t out; image_t *img; char errbuf[200]; const char *content; image_meta_t im = {0}; im.im_no_decoding = 1; rstr_t *url; const char *u = http_arg_get_req(hc, "url"); if(u != NULL) { url = rstr_alloc(u); url_deescape(rstr_data(url)); } else { if(remain == NULL) { return 404; } url = rstr_alloc(remain); } img = backend_imageloader(url, &im, NULL, errbuf, sizeof(errbuf), NULL, NULL); rstr_release(url); if(img == NULL) return http_error(hc, 404, "Unable to load image %s : %s", remain, errbuf); const image_component_t *ic = image_find_component(img, IMAGE_CODED); if(ic == NULL) { image_release(img); return http_error(hc, 404, "Unable to load image %s : Original data not available", remain); } const image_component_coded_t *icc = &ic->coded; htsbuf_queue_init(&out, 0); htsbuf_append(&out, buf_cstr(icc->icc_buf), buf_len(icc->icc_buf)); switch(icc->icc_type) { case IMAGE_JPEG: content = "image/jpeg"; break; case IMAGE_PNG: content = "image/png"; break; case IMAGE_GIF: content = "image/gif"; break; default: content = "image"; break; } image_release(img); return http_send_reply(hc, 0, content, NULL, NULL, 0, &out); }
static void album_query(bmdb_t *b, void *db) { sqlite3_stmt *stmt; int rc; int album_id = atoi(b->b_query); rc = db_prepare(db, &stmt, "SELECT album.title, artist.title " "FROM album, artist " "WHERE album.id = ?1 " "AND artist.id = album.artist_id " "AND album.ds_id = 1"); if(rc != SQLITE_OK) return; sqlite3_bind_int(stmt, 1, album_id); if(db_step(stmt) == SQLITE_ROW) { rstr_t *album = db_rstr(stmt, 0); rstr_t *artist = db_rstr(stmt, 1); prop_set(b->b_metadata, "title", PROP_SET_RSTRING, album); prop_set(b->b_metadata, "artist_name", PROP_SET_RSTRING, artist); prop_t *p = prop_create_r(b->b_metadata, "album_art"); metadata_bind_albumart(p, artist, album); prop_ref_dec(p); rstr_release(album); rstr_release(artist); } sqlite3_finalize(stmt); rc = db_prepare(db, &stmt, "SELECT url, audioitem.title, track, duration, " "artist.title " "FROM audioitem,item,artist " "WHERE audioitem.item_id = item.id " "AND audioitem.artist_id = artist.id " "AND album_id = ?1 " "AND audioitem.ds_id = 1"); if(rc != SQLITE_OK) return; sqlite3_bind_int(stmt, 1, album_id); rstr_t *ct = rstr_alloc("audio"); while((rc = db_step(stmt)) == SQLITE_ROW) { add_item(b, (const char *)sqlite3_column_text(stmt, 0), NULL, ct, (const char *)sqlite3_column_text(stmt, 1), sqlite3_column_int(stmt, 2), (const char *)sqlite3_column_text(stmt, 4), sqlite3_column_int(stmt, 3)); } rstr_release(ct); sqlite3_finalize(stmt); }
static int parse_app1(jpeginfo_t *ji, const uint8_t *buf, size_t len, int flags) { int bigendian; int ifdbase; int ifd = 0; int thumbnail_jpeg_offset = -1; int thumbnail_jpeg_size = -1; #define EXIF8(off) buf[off] #define EXIF16(off) (bigendian ? \ ((buf[off] << 8) | buf[off + 1]) : (buf[off + 1] << 8 | buf[off])) #define EXIF32(off) (bigendian ? \ ((buf[off ] << 24) | (buf[off+1] << 16) | (buf[off+2] << 8) | (buf[off+3])):\ ((buf[off+3] << 24) | (buf[off+2] << 16) | (buf[off+1] << 8) | (buf[off ]))) #define IFDTAG(ifd, tag) (((ifd) << 16) | tag) // Exif Header if(len < 6 || memcmp(exifheader, buf, 6)) return 0; // Don't fail here, just skip buf += 6; len -= 6; // TIFF header if(len < 8) return -1; if(buf[0] == 'M' && buf[1] == 'M') bigendian = 1; else if(buf[0] == 'I' && buf[1] == 'I') bigendian = 0; else return -1; // printf(" EXIF/TIFF %s endian\n", bigendian ? "Big" : "Little"); if(EXIF16(2) != 0x2a) return -1; ifdbase = EXIF32(4); while(ifdbase) { // printf(" IDF Offset = %d\n", ifdbase); if(len < ifdbase + 2) return -1; int i, entries = EXIF16(ifdbase); // printf(" %d entries\n", entries); if(len < ifdbase + 2 + entries * 12 + 4) return -1; for(i = 0; i < entries; i++) { uint16_t tag = EXIF16(ifdbase + 2 + i * 12 + 0); uint16_t type = EXIF16(ifdbase + 2 + i * 12 + 2); // uint32_t c = EXIF32(ifdbase + 2 + i * 12 + 4); int po = ifdbase + 2 + i * 12 + 8; int value = 0; const char *str = NULL; switch(type) { case 1: value = (uint8_t) EXIF8(po); break; case 2: value = (uint32_t) EXIF32(po); str = (const char *)buf + value; break; case 3: value = (uint16_t) EXIF16(po); break; case 4: value = (uint32_t) EXIF32(po); break; case 6: value = (int8_t) EXIF8(po); break; case 8: value = (int16_t) EXIF8(po); break; } // printf(" IFD%d %04x (%d) == %d\n", ifd, tag, type, value); switch(IFDTAG(ifd, tag)) { case IFDTAG(1, 0x201): // JPEG Thumbnail offset thumbnail_jpeg_offset = value; break; case IFDTAG(1, 0x202): // JPEG Thumbnail size thumbnail_jpeg_size = value; break; case IFDTAG(0, 0x112): // Orientation ji->ji_orientation = value; break; case IFDTAG(0, 0x132): // Datetime ji->ji_time = jpeg_time(str); break; case IFDTAG(0, 0x10f): // Manufacturer rstr_release(ji->ji_manufacturer); ji->ji_manufacturer = rstr_alloc(str); break; case IFDTAG(0, 0x110): // Equipment rstr_release(ji->ji_equipment); ji->ji_equipment = rstr_alloc(str); break; default: break; } } ifd++; ifdbase = EXIF32(ifdbase + 2 + entries * 12); } if(flags & JPEG_INFO_THUMBNAIL && thumbnail_jpeg_offset != -1 && thumbnail_jpeg_size != -1 && thumbnail_jpeg_offset + thumbnail_jpeg_size <= len) { // printf(" Thumbnail @ %d, %d bytes\n", thumbnail_jpeg_offset, thumbnail_jpeg_size); ji->ji_thumbnail = pixmap_alloc_coded(buf + thumbnail_jpeg_offset, thumbnail_jpeg_size, PIXMAP_JPEG); ji->ji_thumbnail->pm_flags |= PIXMAP_THUMBNAIL; ji->ji_thumbnail->pm_orientation = ji->ji_orientation; } return 0; }