/* * Grab the timestamps for listing. Doesn't modify the file. */ static int listts(struct exiftags *t, struct linfo *li) { struct exifprop *p; struct tm tv; /* * Try for DateTime, DateTimeOriginal, then DateTimeDigitized. * If none found, print error and list first. */ p = findprop(t->props, tags, EXIF_T_DATETIME); if (!p || !p->str || etstrptm(p->str, &tv)) { p = findprop(t->props, tags, EXIF_T_DATETIMEORIG); if (!p || !p->str || etstrptm(p->str, &tv)) { p = findprop(t->props, tags, EXIF_T_DATETIMEDIGI); if (!p || !p->str || etstrptm(p->str, &tv)) { exifwarn("no timestamp available"); li->ts = 0; return (1); } } } li->ts = mktime(&tv); return (0); }
/* * Process a timestamp. * Returns 0 on success, 1 if it had trouble writing, 2 if the tag wasn't * found (and it was explictly requested), or -1 if the tag wasn't found. */ static int procts(FILE *fp, long pos, struct exiftags *t, const unsigned char *buf, u_int16_t tag, const char *ttype) { int rc; char nts[EXIFTIMELEN]; struct exifprop *p; p = findprop(t->props, tags, tag); if (ettime(nts, p)) { /* * If ttags != 0, then the user explicitly requested the * timestamp, so print an error if it doesn't exist. */ if (ttags) { fprintf(stderr, "%s: image %s time not available\n", fname, ttype); return (2); } return (-1); } if (wflag) rc = writets(fp, pos, t, p, buf, ttype, nts); else { printf("%s%s%s\n", p->descr, delim, nts); rc = 0; } return (rc); }
/* xlputprop - put a property value onto the property list */ void xlputprop(LVAL sym, LVAL val, LVAL prp) { LVAL pair; if ((pair = findprop(sym,prp))) rplaca(pair,val); else setplist(sym,cons(prp,cons(val,getplist(sym)))); }
/* setp - set the value of an object property */ int setp(int obj,int prop,int val) { int p; for (; obj; obj = getofield(obj,O_CLASS)) if (p = findprop(obj,prop)) return (putofield(obj,p,val)); return (NIL); }
/* getp - get the value of an object property */ int getp(int obj,int prop) { int p; for (; obj; obj = getofield(obj,O_CLASS)) if (p = findprop(obj,prop)) return (getofield(obj,p)); return (NIL); }
/* xlputprop - put a property value onto the property list */ void xlputprop(NODE *sym,NODE *val,NODE *prp) { NODE ***oldstk,*p __HEAPIFY,*pair; if ((pair = findprop(sym,prp)) == NIL) { oldstk = xlsave1(&p); p = consa(prp); rplacd(p,pair = cons(val,getplist(sym))); setplist(sym,p); xlstack = oldstk; } rplaca(pair,val); }
xlputprop(NODE *sym, NODE *val, NODE *prp) { NODE ***oldstk,*p,*pair; if ((pair = findprop(sym,prp)) == (NODE *)0) { oldstk = xlsave(&p,(NODE **)0); p = consa(prp); ((p)->n_info.n_xlist.xl_cdr = (pair = cons(val,((sym)->n_info.n_xsym.xsy_plist->n_info.n_xlist.xl_cdr)))); ((sym)->n_info.n_xsym.xsy_plist->n_info.n_xlist.xl_cdr = (p)); xlstack = oldstk; } ((pair)->n_info.n_xlist.xl_car = (val)); }
/* xlapply - apply a function to arguments (already on the stack) */ LVAL xlapply(int argc) { LVAL *oldargv,fun,val; LVAL funname; LVAL old_profile_fixnum = profile_fixnum; FIXTYPE *old_profile_count_ptr = profile_count_ptr; int oldargc; /* get the function */ fun = xlfp[1]; /* get the functional value of symbols */ if (symbolp(fun)) { funname = fun; /* save it */ while ((val = getfunction(fun)) == s_unbound) xlfunbound(fun); fun = xlfp[1] = val; if (profile_flag && atomp(funname)) { LVAL profile_prop = findprop(funname, s_profile); if (null(profile_prop)) { /* make a new fixnum, don't use cvfixnum because it would return shared pointer to zero, but we are going to modify this integer in place -- dangerous but efficient. */ profile_fixnum = newnode(FIXNUM); profile_fixnum->n_fixnum = 0; setplist(funname, cons(s_profile, cons(profile_fixnum, getplist(funname)))); setvalue(s_profile, cons(funname, getvalue(s_profile))); } else profile_fixnum = car(profile_prop); profile_count_ptr = &getfixnum(profile_fixnum); } } /* check for nil */ if (null(fun)) xlerror("bad function",fun); /* dispatch on node type */ switch (ntype(fun)) { case SUBR: oldargc = xlargc; oldargv = xlargv; xlargc = argc; xlargv = xlfp + 3; val = (*getsubr(fun))(); xlargc = oldargc; xlargv = oldargv; break; case CONS: if (!consp(cdr(fun))) xlerror("bad function",fun); if (car(fun) == s_lambda) { fun = xlclose(NIL, s_lambda, car(cdr(fun)), cdr(cdr(fun)), xlenv,xlfenv); } else xlerror("bad function",fun); /**** fall through into the next case ****/ case CLOSURE: if (gettype(fun) != s_lambda) xlerror("bad function",fun); val = evfun(fun,argc,xlfp+3); break; default: xlerror("bad function",fun); } /* restore original profile counting state */ profile_fixnum = old_profile_fixnum; profile_count_ptr = old_profile_count_ptr; /* remove the call frame */ xlsp = xlfp; xlfp = xlfp - (int)getfixnum(*xlfp); /* return the function value */ return (val); }
/* evform - evaluate a form */ LOCAL LVAL evform(LVAL form) { LVAL fun,args,val,type; LVAL tracing=NIL; LVAL *argv; LVAL old_profile_fixnum = profile_fixnum; FIXTYPE *old_profile_count_ptr = profile_count_ptr; LVAL funname; int argc; /* protect some pointers */ xlstkcheck(2); xlsave(fun); xlsave(args); (*profile_count_ptr)++; /* increment profile counter */ /* get the function and the argument list */ fun = car(form); args = cdr(form); funname = fun; /* get the functional value of symbols */ if (symbolp(fun)) { if (getvalue(s_tracelist) && member(fun,getvalue(s_tracelist))) tracing = fun; fun = xlgetfunction(fun); } /* check for nil */ if (null(fun)) xlerror("bad function",NIL); /* dispatch on node type */ switch (ntype(fun)) { case SUBR: argv = xlargv; argc = xlargc; xlargc = evpushargs(fun,args); xlargv = xlfp + 3; trenter(tracing,xlargc,xlargv); val = (*getsubr(fun))(); trexit(tracing,val); xlsp = xlfp; xlfp = xlfp - (int)getfixnum(*xlfp); xlargv = argv; xlargc = argc; break; case FSUBR: argv = xlargv; argc = xlargc; xlargc = pushargs(fun,args); xlargv = xlfp + 3; val = (*getsubr(fun))(); xlsp = xlfp; xlfp = xlfp - (int)getfixnum(*xlfp); xlargv = argv; xlargc = argc; break; case CONS: if (!consp(cdr(fun))) xlerror("bad function",fun); if ((type = car(fun)) == s_lambda) fun = xlclose(NIL, s_lambda, car(cdr(fun)), cdr(cdr(fun)), xlenv,xlfenv); else xlerror("bad function",fun); /**** fall through into the next case ****/ case CLOSURE: /* do profiling */ if (profile_flag && atomp(funname)) { LVAL profile_prop = findprop(funname, s_profile); if (null(profile_prop)) { /* make a new fixnum, don't use cvfixnum because it would return shared pointer to zero, but we are going to modify this integer in place -- dangerous but efficient. */ profile_fixnum = newnode(FIXNUM); profile_fixnum->n_fixnum = 0; setplist(funname, cons(s_profile, cons(profile_fixnum, getplist(funname)))); setvalue(s_profile, cons(funname, getvalue(s_profile))); } else profile_fixnum = car(profile_prop); profile_count_ptr = &getfixnum(profile_fixnum); } if (gettype(fun) == s_lambda) { argc = evpushargs(fun,args); argv = xlfp + 3; trenter(tracing,argc,argv); val = evfun(fun,argc,argv); trexit(tracing,val); xlsp = xlfp; xlfp = xlfp - (int)getfixnum(*xlfp); } else { macroexpand(fun,args,&fun); val = xleval(fun); } profile_fixnum = old_profile_fixnum; profile_count_ptr = old_profile_count_ptr; break; default: xlerror("bad function",fun); } /* restore the stack */ xlpopn(2); /* return the result value */ return (val); }
/* xlgetprop - get the value of a property */ NODE *xlgetprop(NODE *sym,NODE *prp) { NODE *p; return ((p = findprop(sym,prp)) ? car(p) : NIL); }
/* xlgetprop - get the value of a property */ LVAL xlgetprop(LVAL sym, LVAL prp) { LVAL p; return ((p = findprop(sym,prp)) ? car(p) : NIL); }
/* * Scan the JPEG file for Exif data and parse it. */ static int doit(FILE *fp, const char *fname) { int mark, gotapp1, first, rc; unsigned int len, rlen; unsigned char *exifbuf; struct exiftags *t; long app1; gotapp1 = FALSE; first = 0; exifbuf = NULL; rc = 0; while (jpegscan(fp, &mark, &len, !(first++))) { if (mark != JPEG_M_APP1) { if (fseek(fp, len, SEEK_CUR)) exifdie((const char *)strerror(errno)); continue; } exifbuf = (unsigned char *)malloc(len); if (!exifbuf) exifdie((const char *)strerror(errno)); app1 = ftell(fp); rlen = fread(exifbuf, 1, len, fp); if (rlen != len) { fprintf(stderr, "%s: error reading JPEG (length " "mismatch)\n", fname); free(exifbuf); return (1); } gotapp1 = TRUE; t = exifscan(exifbuf, len, FALSE); if (t && t->props) { if (bflag || com) rc = writecom(fp, fname, app1, findprop(t->props, tags, EXIF_T_USERCOMMENT), exifbuf, t->md.btiff); else rc = printcom(fname, findprop(t->props, tags, EXIF_T_USERCOMMENT), t->md.btiff); } else { fprintf(stderr, "%s: couldn't find Exif properties\n", fname); rc = 1; } exiffree(t); free(exifbuf); } if (!gotapp1) { fprintf(stderr, "%s: couldn't find Exif data\n", fname); return (1); } return (rc); }
/* * Process GPS tags. */ void gpsprop(struct exifprop *prop, struct exiftags *t) { u_int32_t i, n, d; double deg, min, sec, alt; char fmt[32], buf[16]; struct exifprop *tmpprop; enum byteorder o = t->md.order; switch (prop->tag) { /* Version. */ case 0x0000: exifstralloc(&prop->str, 8); /* Convert the value back into a string. */ byte4exif(prop->value, (unsigned char *)buf, o); for (i = 0; i < 4; i++) { prop->str[i * 2] = '0' + buf[i]; prop->str[i * 2 + 1] = '.'; } prop->str[7] = '\0'; break; /* * Reference values. The value is 2-count nul-terminated ASCII, * not an offset to the ASCII string. * XXX Shouldn't really be necessary now that short ASCII strings work. */ case 0x0001: case 0x0003: case 0x0009: case 0x000a: case 0x000c: case 0x000e: case 0x0010: case 0x0013: case 0x0015: case 0x0017: case 0x0019: /* Clean-up from any earlier processing. */ free(prop->str); prop->str = NULL; byte4exif(prop->value, (unsigned char *)buf, o); for (i = 0; gpstags[i].tag < EXIF_T_UNKNOWN && gpstags[i].tag != prop->tag; i++); if (gpstags[i].table) prop->str = finddescr(gpstags[i].table, (unsigned char)buf[0]); else { exifstralloc(&prop->str, 2); prop->str[0] = buf[0]; } break; /* * Coordinate values. * * This is really kind of a mess. The display behavior here is * based on image samples from a Nikon D1X and a Fuji FinePix S1 Pro. * The specification allows for fractional minutes (and no seconds). * Not sure if there are any other combinations... */ case 0x0002: case 0x0004: case 0x0014: case 0x0016: if (prop->count != 3 || prop->value + prop->count * 8 > (u_int32_t)(t->md.etiff - t->md.btiff)) { exifwarn("unexpected GPS coordinate values"); break; } free(prop->str); prop->str = NULL; exifstralloc(&prop->str, 32); /* Figure out the reference prefix. */ switch (prop->tag) { case 0x0002: tmpprop = findprop(t->props, gpstags, 0x0001); break; case 0x0004: tmpprop = findprop(t->props, gpstags, 0x0003); break; case 0x0014: tmpprop = findprop(t->props, gpstags, 0x0013); break; case 0x0016: tmpprop = findprop(t->props, gpstags, 0x0015); break; default: tmpprop = NULL; } /* Degrees. */ i = 0; n = exif4byte(t->md.btiff + prop->value + i * 8, o); d = exif4byte(t->md.btiff + prop->value + 4 + i * 8, o); strcpy(fmt, "%s %.f%s "); if (!n || !d) /* Punt. */ deg = 0.0; else { deg = (double)n / (double)d; if (d != 1) sprintf(fmt, "%%s %%.%df%%s ", (int)log10((double)d)); } /* Minutes. */ i++; n = exif4byte(t->md.btiff + prop->value + i * 8, o); d = exif4byte(t->md.btiff + prop->value + 4 + i * 8, o); if (!n || !d) { /* Punt. */ min = 0.0; strcat(fmt, "%.f'"); } else { min = (double)n / (double)d; if (d != 1) { sprintf(buf, "%%.%df'", (int)log10((double)d)); strcat(fmt, buf); } else strcat(fmt, "%.f'"); } /* * Seconds. We'll assume if minutes are fractional, we * should just ignore seconds. */ i++; n = exif4byte(t->md.btiff + prop->value + i * 8, o); d = exif4byte(t->md.btiff + prop->value + 4 + i * 8, o); if (!n || !d) { /* Assume no seconds. */ snprintf(prop->str, 31, fmt, tmpprop && tmpprop->str ? tmpprop->str : "", deg, DEGREE, min); break; } else { sec = (double)n / (double)d; if (d != 1) { sprintf(buf, " %%.%df", (int)log10((double)d)); strcat(fmt, buf); } else strcat(fmt, " %.f"); } snprintf(prop->str, 31, fmt, tmpprop && tmpprop->str ? tmpprop->str : "", deg, DEGREE, min, sec); break; /* Altitude. */ case 0x0006: n = exif4byte(t->md.btiff + prop->value, o); d = exif4byte(t->md.btiff + prop->value + 4, o); /* Look up reference. Non-zero means negative altitude. */ tmpprop = findprop(t->props, gpstags, 0x0005); if (tmpprop && tmpprop->value) n *= -1; if (!n || !d) alt = 0.0; else alt = (double)n / (double)d; /* Should already have a 32-byte buffer from parsetag(). */ snprintf(prop->str, 31, "%.2f m", alt); prop->str[31] = '\0'; break; /* Time. */ case 0x0007: /* Should already have a 32-byte buffer from parsetag(). */ prop->str[0] = '\0'; for (i = 0; i < prop->count; i++) { n = exif4byte(t->md.btiff + prop->value + i * 8, o); d = exif4byte(t->md.btiff + prop->value + 4 + i * 8, o); if (!d) break; if (!i) sprintf(fmt, "%%02.%df", (int)log10((double)d)); else sprintf(fmt, ":%%02.%df", (int)log10((double)d)); snprintf(buf, 8, fmt, (double)n / (double)d); strcat(prop->str, buf); } break; } }
NODE *xlgetprop(NODE *sym, NODE *prp) { NODE *p; return ((p = findprop(sym,prp)) ? ((p)->n_info.n_xlist.xl_car) : (NODE *)0); }