LensSerious 0.1
Lens-correction mathematics as data, not as a library of callbacks
Loading...
Searching...
No Matches
lensserious_import.c
Go to the documentation of this file.
1/*
2 LensSerious — build the database from the upstream XML.
3
4 Copyright (C) 2026 Aurélien PIERRE. License: LGPL-3.0-or-later.
5*/
6
44#include "lensserious.h"
45#include "lensserious_import.h"
46#include "lensserious_db.h"
47
48#include <lensfun.h>
49#include <sqlite3.h>
50
51#ifndef LS_HAVE_LF_DB_LOAD_DIRECTORY
52/* Only the pre-0.3.3 fallback in _load_directory() walks a directory itself. */
53#include <dirent.h>
54#endif
55
56#include <errno.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <time.h>
61#include <unistd.h>
62
63static const char *SCHEMA_PATH_HINT = "src/schema.sql";
64
65/* ------------------------------------------------------------------------- */
66
67static void die(const char *what, sqlite3 *db)
68{
69 fprintf(stderr, "import: %s%s%s\n", what,
70 db ? ": " : "", db ? sqlite3_errmsg(db) : "");
71 exit(1);
72}
73
74static void exec_or_die(sqlite3 *db, const char *sql)
75{
76 char *err = NULL;
77 if(sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK)
78 {
79 fprintf(stderr, "import: %s\n", err ? err : "(no message)");
80 sqlite3_free(err);
81 exit(1);
82 }
83}
84
85static sqlite3_stmt *prep(sqlite3 *db, const char *sql)
86{
87 sqlite3_stmt *st = NULL;
88 if(sqlite3_prepare_v2(db, sql, -1, &st, NULL) != SQLITE_OK) die(sql, db);
89 return st;
90}
91
92static void step_reset(sqlite3 *db, sqlite3_stmt *st)
93{
94 if(sqlite3_step(st) != SQLITE_DONE) die("insert", db);
95 sqlite3_reset(st);
96 sqlite3_clear_bindings(st);
97}
98
99/* ------------------------------------------------------------------------- */
100
102static void for_each_mlstr(const lfMLstr s,
103 void (*fn)(const char *lang, const char *value, void *ud),
104 void *ud)
105{
106 if(!s) return;
107 const char *p = s;
108 fn(NULL, p, ud); /* the default, untranslated spelling */
109 p += strlen(p) + 1;
110 while(*p)
111 {
112 const char *lang = p;
113 p += strlen(p) + 1;
114 if(!*p && !*(p)) { /* malformed tail: stop rather than run off the end */ }
115 const char *value = p;
116 fn(lang, value, ud);
117 p += strlen(p) + 1;
118 }
119}
120
121typedef struct
122{
123 sqlite3 *db;
124 sqlite3_stmt *st;
125 sqlite3_stmt *tok; /* NULL for cameras: only lenses are fuzzy-matched */
126 long long owner_id;
127 const char *kind;
128} name_ctx_t;
129
130static void insert_name(const char *lang, const char *value, void *ud)
131{
132 name_ctx_t *c = (name_ctx_t *)ud;
133 if(!value || !*value) return;
134
135 char norm[512];
136 ls_db_normalize(value, norm, sizeof(norm));
137
138 sqlite3_bind_int64(c->st, 1, c->owner_id);
139 sqlite3_bind_text(c->st, 2, c->kind, -1, SQLITE_STATIC);
140 if(lang) sqlite3_bind_text(c->st, 3, lang, -1, SQLITE_TRANSIENT);
141 else sqlite3_bind_null(c->st, 3);
142 sqlite3_bind_text(c->st, 4, value, -1, SQLITE_TRANSIENT);
143 sqlite3_bind_text(c->st, 5, norm, -1, SQLITE_TRANSIENT);
144 /* Only lens names carry a token digest -- camera lookups are exact and never score -- and
145 * camera_name has no such column, so this statement has five parameters, not six. */
146 if(c->tok)
147 {
148 unsigned char digest[2 + 32 * 5];
149 const size_t dn = ls_db_token_digest(norm, digest, sizeof(digest));
150 sqlite3_bind_blob(c->st, 6, digest, (int)dn, SQLITE_TRANSIENT);
151 }
152 step_reset(c->db, c->st);
153
154 if(!c->tok) return;
155 /* Index this name's tokens, so a lookup can ask which of ITS tokens is rarest instead of
156 * scoring the whole catalogue. Tokenised here, offline, by the same function the matcher
157 * uses on the query. */
158 char tokens[32][48];
159 const int n = ls_db_tokenize(norm, &tokens[0][0], 32, 48);
160 for(int i = 0; i < n; i++)
161 {
162 sqlite3_bind_int64(c->tok, 1, c->owner_id);
163 sqlite3_bind_text(c->tok, 2, c->kind, -1, SQLITE_STATIC);
164 sqlite3_bind_text(c->tok, 3, tokens[i], -1, SQLITE_TRANSIENT);
165 step_reset(c->db, c->tok);
166 }
167}
168
169/* ------------------------------------------------------------------------- */
170/* Model vocabularies. The XML's names become the evaluator's integers here, */
171/* once, offline -- never at render time. */
172/* ------------------------------------------------------------------------- */
173
174static int dist_model(enum lfDistortionModel m)
175{
176 switch(m)
177 {
178 case LF_DIST_MODEL_POLY3: return LS_DIST_POLY3;
179 case LF_DIST_MODEL_POLY5: return LS_DIST_POLY5;
180 case LF_DIST_MODEL_PTLENS: return LS_DIST_PTLENS;
181 default: return LS_DIST_NONE;
182 }
183}
184
185static int tca_model(enum lfTCAModel m)
186{
187 switch(m)
188 {
189 case LF_TCA_MODEL_LINEAR: return LS_TCA_LINEAR;
190 case LF_TCA_MODEL_POLY3: return LS_TCA_POLY3;
191 default: return LS_TCA_NONE;
192 }
193}
194
195static int lens_type(enum lfLensType t)
196{
197 switch(t)
198 {
199 case LF_RECTILINEAR: return LS_LENS_RECTILINEAR;
200 case LF_FISHEYE: return LS_LENS_FISHEYE;
201 case LF_PANORAMIC: return LS_LENS_PANORAMIC;
202 case LF_EQUIRECTANGULAR: return LS_LENS_EQUIRECTANGULAR;
203 case LF_FISHEYE_ORTHOGRAPHIC: return LS_LENS_FISHEYE_ORTHOGRAPHIC;
204 case LF_FISHEYE_STEREOGRAPHIC: return LS_LENS_FISHEYE_STEREOGRAPHIC;
205 case LF_FISHEYE_EQUISOLID: return LS_LENS_FISHEYE_EQUISOLID;
206 case LF_FISHEYE_THOBY: return LS_LENS_FISHEYE_THOBY;
207 default: return LS_LENS_UNKNOWN;
208 }
209}
210
211/* ------------------------------------------------------------------------- */
212
213static long long mount_id_for(sqlite3 *db, sqlite3_stmt *sel, sqlite3_stmt *ins,
214 const char *name)
215{
216 if(!name || !*name) return 0;
217
218 sqlite3_bind_text(sel, 1, name, -1, SQLITE_TRANSIENT);
219 long long id = 0;
220 if(sqlite3_step(sel) == SQLITE_ROW) id = sqlite3_column_int64(sel, 0);
221 sqlite3_reset(sel);
222 sqlite3_clear_bindings(sel);
223 if(id) return id;
224
225 sqlite3_bind_text(ins, 1, name, -1, SQLITE_TRANSIENT);
226 step_reset(db, ins);
227 return sqlite3_last_insert_rowid(db);
228}
229
230static char *read_file(const char *path)
231{
232 FILE *f = fopen(path, "rb");
233 if(!f) return NULL;
234 fseek(f, 0, SEEK_END);
235 const long n = ftell(f);
236 fseek(f, 0, SEEK_SET);
237 char *buf = (char *)malloc((size_t)n + 1);
238 if(!buf || fread(buf, 1, (size_t)n, f) != (size_t)n)
239 {
240 free(buf);
241 fclose(f);
242 return NULL;
243 }
244 buf[n] = '\0';
245 fclose(f);
246 return buf;
247}
248
264static int _load_directory(lfDatabase *ldb, const char *dirname)
265{
266#ifdef LS_HAVE_LF_DB_LOAD_DIRECTORY
267 return lf_db_load_directory(ldb, dirname) ? 1 : 0;
268#else
269 DIR *d = opendir(dirname);
270 if(!d) return 0;
271
272 int loaded = 0;
273 const struct dirent *e;
274 while((e = readdir(d)))
275 {
276 const size_t n = strlen(e->d_name);
277 if(n < 5 || strcmp(e->d_name + n - 4, ".xml")) continue;
278
279 char path[4096];
280 snprintf(path, sizeof(path), "%s/%s", dirname, e->d_name);
281 /* Here 0 IS success: lf_db_load_file() returns an lfError, like lf_db_load(). A file
282 * that fails to parse is skipped rather than fatal, which is what the newer
283 * lf_db_load_directory() does too -- it reports success if ANY file loaded. */
284 if(lf_db_load_file(ldb, path) == LF_NO_ERROR) loaded++;
285 }
286 closedir(d);
287 return loaded > 0;
288#endif
289}
290
291int ls_import_run(const char *schema_path, const char *out_path,
292 const char *base_xml_dir, const char *xml_dir)
293{
294
295 char *schema = read_file(schema_path);
296 if(!schema)
297 {
298 fprintf(stderr, "import: cannot read schema `%s' (expected %s)\n",
299 schema_path, SCHEMA_PATH_HINT);
300 return 1;
301 }
302
303 /* --- read upstream ---------------------------------------------------- */
304
305 lfDatabase *ldb = lf_db_new();
306 if(!ldb) die("lf_db_new", NULL);
307
308 /* The baseline, if the caller has one, goes in FIRST -- lensfun's rule is that a later
309 * definition overrides an earlier one, so everything loaded below can replace a lens
310 * here while a lens nobody else defines survives.
311 *
312 * That is what makes an update additive. A consumer shipping a database can hand its own
313 * calibrations in here, and whatever this machine has is then merged over the top by
314 * lensfun's own precedence rather than by SQL this project would have to write. Without
315 * it, a machine with no system-wide lensfun would produce a database holding nothing but
316 * the handful of profiles the user wrote themselves -- correct as far as it goes, and a
317 * catastrophic replacement for a database of fifteen hundred lenses. */
318 int loaded_any = 0;
319 if(base_xml_dir)
320 {
321 if(_load_directory(ldb, base_xml_dir))
322 loaded_any = 1;
323 else
324 fprintf(stderr, "import: warning: no baseline loaded from `%s'\n", base_xml_dir);
325 }
326
327 if(xml_dir)
328 {
329 if(_load_directory(ldb, xml_dir)) loaded_any = 1;
330 else if(!loaded_any)
331 {
332 fprintf(stderr, "import: no database loaded from `%s'\n", xml_dir);
333 return 1;
334 }
335 }
336 else if(lf_db_load(ldb) == LF_NO_ERROR)
337 loaded_any = 1;
338
339 if(!loaded_any)
340 {
341 fprintf(stderr, "import: no lensfun database found\n");
342 return 1;
343 }
344
345 const lfCamera *const *cameras = lf_db_get_cameras(ldb);
346 const lfLens *const *lenses = lf_db_get_lenses(ldb);
347 const lfMount *const *mounts = lf_db_get_mounts(ldb);
348
349 /* --- write ------------------------------------------------------------ */
350
351 char tmp_path[4096];
352 snprintf(tmp_path, sizeof(tmp_path), "%s.tmp-%ld", out_path, (long)getpid());
353 unlink(tmp_path);
354
355 sqlite3 *db = NULL;
356 if(sqlite3_open_v2(tmp_path, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK)
357 die("open output", db);
358
359 /* Nothing here needs crash-safety: on failure the temporary file is discarded and the
360 * live database is untouched, so durability guarantees are pure cost. */
361 exec_or_die(db, "PRAGMA journal_mode = OFF");
362 exec_or_die(db, "PRAGMA synchronous = OFF");
363 exec_or_die(db, schema);
364 free(schema);
365 exec_or_die(db, "BEGIN");
366
367 sqlite3_stmt *ins_meta = prep(db, "INSERT INTO meta(key, value) VALUES (?1, ?2)");
368 sqlite3_stmt *sel_mount = prep(db, "SELECT id FROM mount WHERE name = ?1");
369 sqlite3_stmt *ins_mount = prep(db, "INSERT INTO mount(name) VALUES (?1)");
370 sqlite3_stmt *ins_compat = prep(db, "INSERT OR IGNORE INTO mount_compat(mount_id, compat_id) VALUES (?1, ?2)");
371 sqlite3_stmt *ins_cam = prep(db, "INSERT INTO camera(maker, model, variant, mount_id, crop_factor)"
372 " VALUES (?1, ?2, ?3, ?4, ?5)");
373 sqlite3_stmt *ins_cam_name = prep(db, "INSERT INTO camera_name(camera_id, kind, lang, value, norm)"
374 " VALUES (?1, ?2, ?3, ?4, ?5)");
375 sqlite3_stmt *ins_lens = prep(db, "INSERT INTO lens(maker, model, type, crop_factor, aspect_ratio,"
376 " center_x, center_y, min_focal, max_focal, min_aperture, max_aperture)"
377 " VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11)");
378 sqlite3_stmt *ins_lens_name = prep(db, "INSERT INTO lens_name(lens_id, kind, lang, value, norm, tokens)"
379 " VALUES (?1, ?2, ?3, ?4, ?5, ?6)");
380 sqlite3_stmt *ins_token = prep(db, "INSERT INTO lens_token(lens_id, kind, token)"
381 " VALUES (?1, ?2, ?3)");
382 sqlite3_stmt *ins_lens_mount = prep(db, "INSERT OR IGNORE INTO lens_mount(lens_id, mount_id) VALUES (?1, ?2)");
383 sqlite3_stmt *ins_dist = prep(db, "INSERT INTO calib_distortion(lens_id, ord, model, focal, t0, t1, t2)"
384 " VALUES (?1,?2,?3,?4,?5,?6,?7)");
385 sqlite3_stmt *ins_tca = prep(db, "INSERT INTO calib_tca(lens_id, ord, model, focal, t0,t1,t2,t3,t4,t5)"
386 " VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10)");
387 sqlite3_stmt *ins_vig = prep(db, "INSERT INTO calib_vignetting(lens_id, ord, model, focal, aperture,"
388 " distance, t0, t1, t2) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9)");
389 sqlite3_stmt *ins_real_focal = prep(db, "INSERT INTO lens_real_focal(lens_id, focal, real_focal)"
390 " VALUES (?1, ?2, ?3)");
391
392 /* mounts, then their compatibility lists (which reference mounts by name) */
393 int n_mounts = 0;
394 for(const lfMount *const *m = mounts; m && *m; m++, n_mounts++)
395 mount_id_for(db, sel_mount, ins_mount, lf_mlstr_get((*m)->Name));
396
397 for(const lfMount *const *m = mounts; m && *m; m++)
398 {
399 const long long id = mount_id_for(db, sel_mount, ins_mount, lf_mlstr_get((*m)->Name));
400 if(!id || !(*m)->Compat) continue;
401 for(char **c = (*m)->Compat; *c; c++)
402 {
403 const long long cid = mount_id_for(db, sel_mount, ins_mount, *c);
404 if(!cid) continue;
405 sqlite3_bind_int64(ins_compat, 1, id);
406 sqlite3_bind_int64(ins_compat, 2, cid);
407 step_reset(db, ins_compat);
408 }
409 }
410
411 int n_cameras = 0;
412 for(const lfCamera *const *c = cameras; c && *c; c++, n_cameras++)
413 {
414 const lfCamera *cam = *c;
415 const long long mid = mount_id_for(db, sel_mount, ins_mount, cam->Mount);
416
417 sqlite3_bind_text(ins_cam, 1, lf_mlstr_get(cam->Maker), -1, SQLITE_TRANSIENT);
418 sqlite3_bind_text(ins_cam, 2, lf_mlstr_get(cam->Model), -1, SQLITE_TRANSIENT);
419 if(cam->Variant) sqlite3_bind_text(ins_cam, 3, lf_mlstr_get(cam->Variant), -1, SQLITE_TRANSIENT);
420 else sqlite3_bind_null(ins_cam, 3);
421 if(mid) sqlite3_bind_int64(ins_cam, 4, mid); else sqlite3_bind_null(ins_cam, 4);
422 sqlite3_bind_double(ins_cam, 5, cam->CropFactor);
423 step_reset(db, ins_cam);
424
425 const long long id = sqlite3_last_insert_rowid(db);
426 name_ctx_t ctx = { db, ins_cam_name, NULL, id, "maker" };
427 for_each_mlstr(cam->Maker, insert_name, &ctx);
428 ctx.kind = "model";
429 for_each_mlstr(cam->Model, insert_name, &ctx);
430 }
431
432 int n_lenses = 0, n_dist = 0, n_tca = 0, n_vig = 0;
433 for(const lfLens *const *l = lenses; l && *l; l++, n_lenses++)
434 {
435 const lfLens *lens = *l;
436
437 sqlite3_bind_text(ins_lens, 1, lf_mlstr_get(lens->Maker), -1, SQLITE_TRANSIENT);
438 sqlite3_bind_text(ins_lens, 2, lf_mlstr_get(lens->Model), -1, SQLITE_TRANSIENT);
439 sqlite3_bind_int(ins_lens, 3, lens_type(lens->Type));
440 sqlite3_bind_double(ins_lens, 4, lens->CropFactor);
441 sqlite3_bind_double(ins_lens, 5, lens->AspectRatio);
442 sqlite3_bind_double(ins_lens, 6, lens->CenterX);
443 sqlite3_bind_double(ins_lens, 7, lens->CenterY);
444 sqlite3_bind_double(ins_lens, 8, lens->MinFocal);
445 sqlite3_bind_double(ins_lens, 9, lens->MaxFocal);
446 sqlite3_bind_double(ins_lens, 10, lens->MinAperture);
447 sqlite3_bind_double(ins_lens, 11, lens->MaxAperture);
448 step_reset(db, ins_lens);
449
450 const long long id = sqlite3_last_insert_rowid(db);
451
452 name_ctx_t ctx = { db, ins_lens_name, ins_token, id, "maker" };
453 for_each_mlstr(lens->Maker, insert_name, &ctx);
454 ctx.kind = "model";
455 for_each_mlstr(lens->Model, insert_name, &ctx);
456
457 if(lens->Mounts)
458 for(char **m = lens->Mounts; *m; m++)
459 {
460 const long long mid = mount_id_for(db, sel_mount, ins_mount, *m);
461 if(!mid) continue;
462 sqlite3_bind_int64(ins_lens_mount, 1, id);
463 sqlite3_bind_int64(ins_lens_mount, 2, mid);
464 step_reset(db, ins_lens_mount);
465 }
466
467 if(lens->CalibDistortion)
468 for(lfLensCalibDistortion **c = lens->CalibDistortion; *c; c++, n_dist++)
469 {
470 sqlite3_bind_int64(ins_dist, 1, id);
471 sqlite3_bind_int(ins_dist, 2, (int)(c - lens->CalibDistortion));
472 sqlite3_bind_int(ins_dist, 3, dist_model((*c)->Model));
473 sqlite3_bind_double(ins_dist, 4, (*c)->Focal);
474 for(int t = 0; t < 3; t++) sqlite3_bind_double(ins_dist, 5 + t, (*c)->Terms[t]);
475 step_reset(db, ins_dist);
476 }
477
478 if(lens->CalibTCA)
479 for(lfLensCalibTCA **c = lens->CalibTCA; *c; c++, n_tca++)
480 {
481 sqlite3_bind_int64(ins_tca, 1, id);
482 sqlite3_bind_int(ins_tca, 2, (int)(c - lens->CalibTCA));
483 sqlite3_bind_int(ins_tca, 3, tca_model((*c)->Model));
484 sqlite3_bind_double(ins_tca, 4, (*c)->Focal);
485 for(int t = 0; t < 6; t++) sqlite3_bind_double(ins_tca, 5 + t, (*c)->Terms[t]);
486 step_reset(db, ins_tca);
487 }
488
489 if(lens->CalibVignetting)
490 for(lfLensCalibVignetting **c = lens->CalibVignetting; *c; c++, n_vig++)
491 {
492 sqlite3_bind_int64(ins_vig, 1, id);
493 sqlite3_bind_int(ins_vig, 2, (int)(c - lens->CalibVignetting));
494 sqlite3_bind_int(ins_vig, 3, LS_VIG_PA);
495 sqlite3_bind_double(ins_vig, 4, (*c)->Focal);
496 sqlite3_bind_double(ins_vig, 5, (*c)->Aperture);
497 sqlite3_bind_double(ins_vig, 6, (*c)->Distance);
498 for(int t = 0; t < 3; t++) sqlite3_bind_double(ins_vig, 7 + t, (*c)->Terms[t]);
499 step_reset(db, ins_vig);
500 }
501
502 /* <real-focal-length>. Rare -- a few dozen lenses -- and load-bearing where it exists:
503 * it is the focal the PROJECTION runs on, and on the Sigma 4.5mm circular fisheye it is
504 * 0.47x the nominal one. Zero entries are dropped here rather than at read time because
505 * upstream skips them when interpolating, so a stored zero is a row nothing can use. */
506 if(lens->CalibRealFocal)
507 for(lfLensCalibRealFocal **c = lens->CalibRealFocal; *c; c++)
508 {
509 if((*c)->RealFocal == 0.f) continue;
510 sqlite3_bind_int64(ins_real_focal, 1, id);
511 sqlite3_bind_double(ins_real_focal, 2, (*c)->Focal);
512 sqlite3_bind_double(ins_real_focal, 3, (*c)->RealFocal);
513 step_reset(db, ins_real_focal);
514 }
515 }
516
517 /* provenance, so a database can always say where it came from */
518 {
519 char buf[256];
520 const time_t now = time(NULL);
521 /* gmtime_r is POSIX and absent on MinGW, where this tool now builds because a consumer
522 * generates its database at build time. gmtime() returns a pointer into static storage,
523 * which matters not at all here: this is a single-threaded offline importer writing one
524 * timestamp. The three-way #ifdef the "thread-safe" variants would need is more risk
525 * than the race it would prevent. */
526 const struct tm *tm_utc = gmtime(&now);
527 if(tm_utc)
528 strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", tm_utc);
529 else
530 snprintf(buf, sizeof(buf), "unknown");
531
532 char lf_version[64];
533 snprintf(lf_version, sizeof(lf_version), "lensfun %d.%d.%d.%d",
534 LF_VERSION_MAJOR, LF_VERSION_MINOR, LF_VERSION_MICRO, LF_VERSION_BUGFIX);
535
536 const struct { const char *k; const char *v; } rows[] = {
537 { "built_utc", buf },
538 { "source", xml_dir ? xml_dir : "system lensfun database" },
539 { "importer", lf_version },
540 };
541 for(size_t i = 0; i < sizeof(rows) / sizeof(rows[0]); i++)
542 {
543 sqlite3_bind_text(ins_meta, 1, rows[i].k, -1, SQLITE_STATIC);
544 sqlite3_bind_text(ins_meta, 2, rows[i].v, -1, SQLITE_TRANSIENT);
545 step_reset(db, ins_meta);
546 }
547 }
548
549 /* Derive the token frequencies from what was just inserted, rather than counting in C:
550 * one statement, and it cannot disagree with the table it summarises. */
551 exec_or_die(db, "INSERT INTO token_df(kind, token, df)"
552 " SELECT kind, token, COUNT(DISTINCT lens_id) FROM lens_token"
553 " GROUP BY kind, token");
554
555 exec_or_die(db, "COMMIT");
556 exec_or_die(db, "ANALYZE");
557 /* One contiguous file with no free pages: it is never written again, and every reader
558 * mmaps it. */
559 exec_or_die(db, "VACUUM");
560
561 sqlite3_finalize(ins_meta);
562 sqlite3_finalize(sel_mount);
563 sqlite3_finalize(ins_mount);
564 sqlite3_finalize(ins_compat);
565 sqlite3_finalize(ins_cam);
566 sqlite3_finalize(ins_cam_name);
567 sqlite3_finalize(ins_lens);
568 sqlite3_finalize(ins_lens_name);
569 sqlite3_finalize(ins_token);
570 sqlite3_finalize(ins_lens_mount);
571 sqlite3_finalize(ins_dist);
572 sqlite3_finalize(ins_real_focal);
573 sqlite3_finalize(ins_tca);
574 sqlite3_finalize(ins_vig);
575 if(sqlite3_close(db) != SQLITE_OK) die("close output", db);
576
577 lf_db_destroy(ldb);
578
579 /* Atomic swap: see @ref rebuild. */
580 /* POSIX rename() replaces an existing destination atomically; the Windows CRT's does
581 * NOT -- it fails outright when the target exists, so a rebuild over yesterday's database
582 * would leave the .tmp behind and report failure. Removing the target first gives up
583 * atomicity on Windows only, which is the correct trade for a build-time tool: the file
584 * is generated, not user data, and a failed build is more visible than a torn write.
585 * Everywhere else the rename stays atomic, which is what lets a reader hold the database
586 * open with immutable=1 while it is being replaced. */
587#ifdef _WIN32
588 unlink(out_path);
589#endif
590 if(rename(tmp_path, out_path) != 0)
591 {
592 fprintf(stderr, "import: cannot rename `%s' to `%s': %s\n",
593 tmp_path, out_path, strerror(errno));
594 unlink(tmp_path);
595 return 1;
596 }
597
598 printf("import: %d mounts, %d cameras, %d lenses "
599 "(%d distortion, %d tca, %d vignetting calibrations) -> %s\n",
600 n_mounts, n_cameras, n_lenses, n_dist, n_tca, n_vig, out_path);
601 return 0;
602}
What this is, and what it deliberately is not.
@ LS_TCA_LINEAR
Definition lensserious.h:73
@ LS_TCA_POLY3
Definition lensserious.h:74
@ LS_TCA_NONE
Definition lensserious.h:72
@ LS_VIG_PA
Definition lensserious.h:80
@ LS_LENS_FISHEYE
Definition lensserious.h:98
@ LS_LENS_RECTILINEAR
Definition lensserious.h:97
@ LS_LENS_EQUIRECTANGULAR
@ LS_LENS_FISHEYE_ORTHOGRAPHIC
@ LS_LENS_UNKNOWN
Definition lensserious.h:96
@ LS_LENS_FISHEYE_EQUISOLID
@ LS_LENS_FISHEYE_STEREOGRAPHIC
@ LS_LENS_FISHEYE_THOBY
@ LS_LENS_PANORAMIC
Definition lensserious.h:99
@ LS_DIST_NONE
Definition lensserious.h:63
@ LS_DIST_PTLENS
Definition lensserious.h:66
@ LS_DIST_POLY5
Definition lensserious.h:65
@ LS_DIST_POLY3
Definition lensserious.h:64
A read-only database, and an API with nothing behind it.
int ls_db_tokenize(const char *norm, char *out_tokens, int max, int stride)
The tokens ls_db_match_lens() compares, from an already-normalised name.
size_t ls_db_token_digest(const char *norm, unsigned char *out, size_t out_size)
Pack a normalised name's tokens into the digest stored in lens_name.tokens.
size_t ls_db_normalize(const char *in, char *out, size_t out_size)
The comparison form of a name: ASCII case-folded, punctuation dropped, runs of whitespace collapsed t...
static int lens_type(enum lfLensType t)
static void for_each_mlstr(const lfMLstr s, void(*fn)(const char *lang, const char *value, void *ud), void *ud)
Walk an lfMLstr: the default string, then (lang, translation) pairs.
static void insert_name(const char *lang, const char *value, void *ud)
static const char * SCHEMA_PATH_HINT
static void exec_or_die(sqlite3 *db, const char *sql)
int ls_import_run(const char *schema_path, const char *out_path, const char *base_xml_dir, const char *xml_dir)
Read a lensfun database and write it as a LensSerious SQLite file.
static void die(const char *what, sqlite3 *db)
static int _load_directory(lfDatabase *ldb, const char *dirname)
Load every XML file in a directory into ldb.
static int dist_model(enum lfDistortionModel m)
static void step_reset(sqlite3 *db, sqlite3_stmt *st)
static char * read_file(const char *path)
static long long mount_id_for(sqlite3 *db, sqlite3_stmt *sel, sqlite3_stmt *ins, const char *name)
static sqlite3_stmt * prep(sqlite3 *db, const char *sql)
static int tca_model(enum lfTCAModel m)
Turn a lensfun database into a LensSerious one.
sqlite3_stmt * tok
const char * kind
sqlite3_stmt * st