123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970 |
- /*
- * Copyright (c) 2005-2014 Rich Felker, et al.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #include <stdarg.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #include <float.h>
- #include "config.h"
- #include "common.h"
- #include "mem.h"
- #include "avassert.h"
- #include "avstring.h"
- #include "bprint.h"
- typedef struct FFFILE {
- size_t buf_size;
- unsigned char *buf;
- unsigned char *rpos, *rend;
- unsigned char *shend;
- ptrdiff_t shlim, shcnt;
- void *cookie;
- size_t (*read)(struct FFFILE *, unsigned char *, size_t);
- } FFFILE;
- #define SIZE_hh -2
- #define SIZE_h -1
- #define SIZE_def 0
- #define SIZE_l 1
- #define SIZE_L 2
- #define SIZE_ll 3
- #define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->buf))
- static int fftoread(FFFILE *f)
- {
- f->rpos = f->rend = f->buf + f->buf_size;
- return 0;
- }
- static size_t ffstring_read(FFFILE *f, unsigned char *buf, size_t len)
- {
- char *src = f->cookie;
- size_t k = len+256;
- char *end = memchr(src, 0, k);
- if (end) k = end-src;
- if (k < len) len = k;
- memcpy(buf, src, len);
- f->rpos = (void *)(src+len);
- f->rend = (void *)(src+k);
- f->cookie = src+k;
- return len;
- }
- static int ffuflow(FFFILE *f)
- {
- unsigned char c;
- if (!fftoread(f) && f->read(f, &c, 1)==1) return c;
- return EOF;
- }
- static void ffshlim(FFFILE *f, ptrdiff_t lim)
- {
- f->shlim = lim;
- f->shcnt = f->buf - f->rpos;
- /* If lim is nonzero, rend must be a valid pointer. */
- if (lim && f->rend - f->rpos > lim)
- f->shend = f->rpos + lim;
- else
- f->shend = f->rend;
- }
- static int ffshgetc(FFFILE *f)
- {
- int c;
- ptrdiff_t cnt = shcnt(f);
- if (f->shlim && cnt >= f->shlim || (c=ffuflow(f)) < 0) {
- f->shcnt = f->buf - f->rpos + cnt;
- f->shend = 0;
- return EOF;
- }
- cnt++;
- if (f->shlim && f->rend - f->rpos > f->shlim - cnt)
- f->shend = f->rpos + (f->shlim - cnt);
- else
- f->shend = f->rend;
- f->shcnt = f->buf - f->rpos + cnt;
- if (f->rpos[-1] != c) f->rpos[-1] = c;
- return c;
- }
- #define shlim(f, lim) ffshlim((f), (lim))
- #define shgetc(f) (((f)->rpos != (f)->shend) ? *(f)->rpos++ : ffshgetc(f))
- #define shunget(f) ((f)->shend ? (void)(f)->rpos-- : (void)0)
- static const unsigned char table[] = { -1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
- -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
- 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
- -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
- 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- };
- static unsigned long long ffintscan(FFFILE *f, unsigned base, int pok, unsigned long long lim)
- {
- const unsigned char *val = table+1;
- int c, neg=0;
- unsigned x;
- unsigned long long y;
- if (base > 36 || base == 1) {
- errno = EINVAL;
- return 0;
- }
- while (av_isspace((c=shgetc(f))));
- if (c=='+' || c=='-') {
- neg = -(c=='-');
- c = shgetc(f);
- }
- if ((base == 0 || base == 16) && c=='0') {
- c = shgetc(f);
- if ((c|32)=='x') {
- c = shgetc(f);
- if (val[c]>=16) {
- shunget(f);
- if (pok) shunget(f);
- else shlim(f, 0);
- return 0;
- }
- base = 16;
- } else if (base == 0) {
- base = 8;
- }
- } else {
- if (base == 0) base = 10;
- if (val[c] >= base) {
- shunget(f);
- shlim(f, 0);
- errno = EINVAL;
- return 0;
- }
- }
- if (base == 10) {
- for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f))
- x = x*10 + (c-'0');
- for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f))
- y = y*10 + (c-'0');
- if (c-'0'>=10U) goto done;
- } else if (!(base & base-1)) {
- int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7];
- for (x=0; val[c]<base && x<=UINT_MAX/32; c=shgetc(f))
- x = x<<bs | val[c];
- for (y=x; val[c]<base && y<=ULLONG_MAX>>bs; c=shgetc(f))
- y = y<<bs | val[c];
- } else {
- for (x=0; val[c]<base && x<=UINT_MAX/36-1; c=shgetc(f))
- x = x*base + val[c];
- for (y=x; val[c]<base && y<=ULLONG_MAX/base && base*y<=ULLONG_MAX-val[c]; c=shgetc(f))
- y = y*base + val[c];
- }
- if (val[c]<base) {
- for (; val[c]<base; c=shgetc(f));
- errno = ERANGE;
- y = lim;
- if (lim&1) neg = 0;
- }
- done:
- shunget(f);
- if (y>=lim) {
- if (!(lim&1) && !neg) {
- errno = ERANGE;
- return lim-1;
- } else if (y>lim) {
- errno = ERANGE;
- return lim;
- }
- }
- return (y^neg)-neg;
- }
- static long long scanexp(FFFILE *f, int pok)
- {
- int c;
- int x;
- long long y;
- int neg = 0;
- c = shgetc(f);
- if (c=='+' || c=='-') {
- neg = (c=='-');
- c = shgetc(f);
- if (c-'0'>=10U && pok) shunget(f);
- }
- if (c-'0'>=10U) {
- shunget(f);
- return LLONG_MIN;
- }
- for (x=0; c-'0'<10U && x<INT_MAX/10; c = shgetc(f))
- x = 10*x + c-'0';
- for (y=x; c-'0'<10U && y<LLONG_MAX/100; c = shgetc(f))
- y = 10*y + c-'0';
- for (; c-'0'<10U; c = shgetc(f));
- shunget(f);
- return neg ? -y : y;
- }
- #define LD_B1B_DIG 2
- #define LD_B1B_MAX 9007199, 254740991
- #define KMAX 128
- #define MASK (KMAX-1)
- static double decfloat(FFFILE *f, int c, int bits, int emin, int sign, int pok)
- {
- uint32_t x[KMAX];
- static const uint32_t th[] = { LD_B1B_MAX };
- int i, j, k, a, z;
- long long lrp=0, dc=0;
- long long e10=0;
- int lnz = 0;
- int gotdig = 0, gotrad = 0;
- int rp;
- int e2;
- int emax = -emin-bits+3;
- int denormal = 0;
- double y;
- double frac=0;
- double bias=0;
- static const int p10s[] = { 10, 100, 1000, 10000,
- 100000, 1000000, 10000000, 100000000 };
- j=0;
- k=0;
- /* Don't let leading zeros consume buffer space */
- for (; c=='0'; c = shgetc(f)) gotdig=1;
- if (c=='.') {
- gotrad = 1;
- for (c = shgetc(f); c=='0'; c = shgetc(f)) gotdig=1, lrp--;
- }
- x[0] = 0;
- for (; c-'0'<10U || c=='.'; c = shgetc(f)) {
- if (c == '.') {
- if (gotrad) break;
- gotrad = 1;
- lrp = dc;
- } else if (k < KMAX-3) {
- dc++;
- if (c!='0') lnz = dc;
- if (j) x[k] = x[k]*10 + c-'0';
- else x[k] = c-'0';
- if (++j==9) {
- k++;
- j=0;
- }
- gotdig=1;
- } else {
- dc++;
- if (c!='0') {
- lnz = (KMAX-4)*9;
- x[KMAX-4] |= 1;
- }
- }
- }
- if (!gotrad) lrp=dc;
- if (gotdig && (c|32)=='e') {
- e10 = scanexp(f, pok);
- if (e10 == LLONG_MIN) {
- if (pok) {
- shunget(f);
- } else {
- shlim(f, 0);
- return 0;
- }
- e10 = 0;
- }
- lrp += e10;
- } else if (c>=0) {
- shunget(f);
- }
- if (!gotdig) {
- errno = EINVAL;
- shlim(f, 0);
- return 0;
- }
- /* Handle zero specially to avoid nasty special cases later */
- if (!x[0]) return sign * 0.0;
- /* Optimize small integers (w/no exponent) and over/under-flow */
- if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0))
- return sign * (double)x[0];
- if (lrp > -emin/2) {
- errno = ERANGE;
- return sign * DBL_MAX * DBL_MAX;
- }
- if (lrp < emin-2*DBL_MANT_DIG) {
- errno = ERANGE;
- return sign * DBL_MIN * DBL_MIN;
- }
- /* Align incomplete final B1B digit */
- if (j) {
- for (; j<9; j++) x[k]*=10;
- k++;
- j=0;
- }
- a = 0;
- z = k;
- e2 = 0;
- rp = lrp;
- /* Optimize small to mid-size integers (even in exp. notation) */
- if (lnz<9 && lnz<=rp && rp < 18) {
- int bitlim;
- if (rp == 9) return sign * (double)x[0];
- if (rp < 9) return sign * (double)x[0] / p10s[8-rp];
- bitlim = bits-3*(int)(rp-9);
- if (bitlim>30 || x[0]>>bitlim==0)
- return sign * (double)x[0] * p10s[rp-10];
- }
- /* Drop trailing zeros */
- for (; !x[z-1]; z--);
- /* Align radix point to B1B digit boundary */
- if (rp % 9) {
- int rpm9 = rp>=0 ? rp%9 : rp%9+9;
- int p10 = p10s[8-rpm9];
- uint32_t carry = 0;
- for (k=a; k!=z; k++) {
- uint32_t tmp = x[k] % p10;
- x[k] = x[k]/p10 + carry;
- carry = 1000000000/p10 * tmp;
- if (k==a && !x[k]) {
- a = (a+1 & MASK);
- rp -= 9;
- }
- }
- if (carry) x[z++] = carry;
- rp += 9-rpm9;
- }
- /* Upscale until desired number of bits are left of radix point */
- while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a]<th[0])) {
- uint32_t carry = 0;
- e2 -= 29;
- for (k=(z-1 & MASK); ; k=(k-1 & MASK)) {
- uint64_t tmp = ((uint64_t)x[k] << 29) + carry;
- if (tmp > 1000000000) {
- carry = tmp / 1000000000;
- x[k] = tmp % 1000000000;
- } else {
- carry = 0;
- x[k] = tmp;
- }
- if (k==(z-1 & MASK) && k!=a && !x[k]) z = k;
- if (k==a) break;
- }
- if (carry) {
- rp += 9;
- a = (a-1 & MASK);
- if (a == z) {
- z = (z-1 & MASK);
- x[z-1 & MASK] |= x[z];
- }
- x[a] = carry;
- }
- }
- /* Downscale until exactly number of bits are left of radix point */
- for (;;) {
- uint32_t carry = 0;
- int sh = 1;
- for (i=0; i<LD_B1B_DIG; i++) {
- k = (a+i & MASK);
- if (k == z || x[k] < th[i]) {
- i=LD_B1B_DIG;
- break;
- }
- if (x[a+i & MASK] > th[i]) break;
- }
- if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break;
- /* FIXME: find a way to compute optimal sh */
- if (rp > 9+9*LD_B1B_DIG) sh = 9;
- e2 += sh;
- for (k=a; k!=z; k=(k+1 & MASK)) {
- uint32_t tmp = x[k] & (1<<sh)-1;
- x[k] = (x[k]>>sh) + carry;
- carry = (1000000000>>sh) * tmp;
- if (k==a && !x[k]) {
- a = (a+1 & MASK);
- i--;
- rp -= 9;
- }
- }
- if (carry) {
- if ((z+1 & MASK) != a) {
- x[z] = carry;
- z = (z+1 & MASK);
- } else x[z-1 & MASK] |= 1;
- }
- }
- /* Assemble desired bits into floating point variable */
- for (y=i=0; i<LD_B1B_DIG; i++) {
- if ((a+i & MASK)==z) x[(z=(z+1 & MASK))-1] = 0;
- y = 1000000000.0L * y + x[a+i & MASK];
- }
- y *= sign;
- /* Limit precision for denormal results */
- if (bits > DBL_MANT_DIG+e2-emin) {
- bits = DBL_MANT_DIG+e2-emin;
- if (bits<0) bits=0;
- denormal = 1;
- }
- /* Calculate bias term to force rounding, move out lower bits */
- if (bits < DBL_MANT_DIG) {
- bias = copysign(scalbn(1, 2*DBL_MANT_DIG-bits-1), y);
- frac = fmod(y, scalbn(1, DBL_MANT_DIG-bits));
- y -= frac;
- y += bias;
- }
- /* Process tail of decimal input so it can affect rounding */
- if ((a+i & MASK) != z) {
- uint32_t t = x[a+i & MASK];
- if (t < 500000000 && (t || (a+i+1 & MASK) != z))
- frac += 0.25*sign;
- else if (t > 500000000)
- frac += 0.75*sign;
- else if (t == 500000000) {
- if ((a+i+1 & MASK) == z)
- frac += 0.5*sign;
- else
- frac += 0.75*sign;
- }
- if (DBL_MANT_DIG-bits >= 2 && !fmod(frac, 1))
- frac++;
- }
- y += frac;
- y -= bias;
- if ((e2+DBL_MANT_DIG & INT_MAX) > emax-5) {
- if (fabs(y) >= pow(2, DBL_MANT_DIG)) {
- if (denormal && bits==DBL_MANT_DIG+e2-emin)
- denormal = 0;
- y *= 0.5;
- e2++;
- }
- if (e2+DBL_MANT_DIG>emax || (denormal && frac))
- errno = ERANGE;
- }
- return scalbn(y, e2);
- }
- static double hexfloat(FFFILE *f, int bits, int emin, int sign, int pok)
- {
- uint32_t x = 0;
- double y = 0;
- double scale = 1;
- double bias = 0;
- int gottail = 0, gotrad = 0, gotdig = 0;
- long long rp = 0;
- long long dc = 0;
- long long e2 = 0;
- int d;
- int c;
- c = shgetc(f);
- /* Skip leading zeros */
- for (; c=='0'; c = shgetc(f))
- gotdig = 1;
- if (c=='.') {
- gotrad = 1;
- c = shgetc(f);
- /* Count zeros after the radix point before significand */
- for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1;
- }
- for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) {
- if (c=='.') {
- if (gotrad) break;
- rp = dc;
- gotrad = 1;
- } else {
- gotdig = 1;
- if (c > '9') d = (c|32)+10-'a';
- else d = c-'0';
- if (dc<8) {
- x = x*16 + d;
- } else if (dc < DBL_MANT_DIG/4+1) {
- y += d*(scale/=16);
- } else if (d && !gottail) {
- y += 0.5*scale;
- gottail = 1;
- }
- dc++;
- }
- }
- if (!gotdig) {
- shunget(f);
- if (pok) {
- shunget(f);
- if (gotrad) shunget(f);
- } else {
- shlim(f, 0);
- }
- return sign * 0.0;
- }
- if (!gotrad) rp = dc;
- while (dc<8) x *= 16, dc++;
- if ((c|32)=='p') {
- e2 = scanexp(f, pok);
- if (e2 == LLONG_MIN) {
- if (pok) {
- shunget(f);
- } else {
- shlim(f, 0);
- return 0;
- }
- e2 = 0;
- }
- } else {
- shunget(f);
- }
- e2 += 4*rp - 32;
- if (!x) return sign * 0.0;
- if (e2 > -emin) {
- errno = ERANGE;
- return sign * DBL_MAX * DBL_MAX;
- }
- if (e2 < emin-2*DBL_MANT_DIG) {
- errno = ERANGE;
- return sign * DBL_MIN * DBL_MIN;
- }
- while (x < 0x80000000) {
- if (y>=0.5) {
- x += x + 1;
- y += y - 1;
- } else {
- x += x;
- y += y;
- }
- e2--;
- }
- if (bits > 32+e2-emin) {
- bits = 32+e2-emin;
- if (bits<0) bits=0;
- }
- if (bits < DBL_MANT_DIG)
- bias = copysign(scalbn(1, 32+DBL_MANT_DIG-bits-1), sign);
- if (bits<32 && y && !(x&1)) x++, y=0;
- y = bias + sign*(double)x + sign*y;
- y -= bias;
- if (!y) errno = ERANGE;
- return scalbn(y, e2);
- }
- static double fffloatscan(FFFILE *f, int prec, int pok)
- {
- int sign = 1;
- size_t i;
- int bits;
- int emin;
- int c;
- switch (prec) {
- case 0:
- bits = FLT_MANT_DIG;
- emin = FLT_MIN_EXP-bits;
- break;
- case 1:
- bits = DBL_MANT_DIG;
- emin = DBL_MIN_EXP-bits;
- break;
- case 2:
- bits = DBL_MANT_DIG;
- emin = DBL_MIN_EXP-bits;
- break;
- default:
- return 0;
- }
- while (av_isspace((c = shgetc(f))));
- if (c=='+' || c=='-') {
- sign -= 2*(c=='-');
- c = shgetc(f);
- }
- for (i=0; i<8 && (c|32)=="infinity"[i]; i++)
- if (i<7) c = shgetc(f);
- if (i==3 || i==8 || (i>3 && pok)) {
- if (i!=8) {
- shunget(f);
- if (pok) for (; i>3; i--) shunget(f);
- }
- return sign * INFINITY;
- }
- if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++)
- if (i<2) c = shgetc(f);
- if (i==3) {
- if (shgetc(f) != '(') {
- shunget(f);
- return NAN;
- }
- for (i=1; ; i++) {
- c = shgetc(f);
- if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_')
- continue;
- if (c==')') return NAN;
- shunget(f);
- if (!pok) {
- errno = EINVAL;
- shlim(f, 0);
- return 0;
- }
- while (i--) shunget(f);
- return NAN;
- }
- return NAN;
- }
- if (i) {
- shunget(f);
- errno = EINVAL;
- shlim(f, 0);
- return 0;
- }
- if (c=='0') {
- c = shgetc(f);
- if ((c|32) == 'x')
- return hexfloat(f, bits, emin, sign, pok);
- shunget(f);
- c = '0';
- }
- return decfloat(f, c, bits, emin, sign, pok);
- }
- static void *arg_n(va_list ap, unsigned int n)
- {
- void *p;
- unsigned int i;
- va_list ap2;
- va_copy(ap2, ap);
- for (i=n; i>1; i--) va_arg(ap2, void *);
- p = va_arg(ap2, void *);
- va_end(ap2);
- return p;
- }
- static void store_int(void *dest, int size, unsigned long long i)
- {
- if (!dest) return;
- switch (size) {
- case SIZE_hh:
- *(char *)dest = i;
- break;
- case SIZE_h:
- *(short *)dest = i;
- break;
- case SIZE_def:
- *(int *)dest = i;
- break;
- case SIZE_l:
- *(long *)dest = i;
- break;
- case SIZE_ll:
- *(long long *)dest = i;
- break;
- }
- }
- static int ff_vfscanf(FFFILE *f, const char *fmt, va_list ap)
- {
- int width;
- int size;
- int base;
- const unsigned char *p;
- int c, t;
- char *s;
- void *dest=NULL;
- int invert;
- int matches=0;
- unsigned long long x;
- double y;
- ptrdiff_t pos = 0;
- unsigned char scanset[257];
- size_t i;
- for (p=(const unsigned char *)fmt; *p; p++) {
- if (av_isspace(*p)) {
- while (av_isspace(p[1])) p++;
- shlim(f, 0);
- while (av_isspace(shgetc(f)));
- shunget(f);
- pos += shcnt(f);
- continue;
- }
- if (*p != '%' || p[1] == '%') {
- shlim(f, 0);
- if (*p == '%') {
- p++;
- while (av_isspace((c=shgetc(f))));
- } else {
- c = shgetc(f);
- }
- if (c!=*p) {
- shunget(f);
- if (c<0) goto input_fail;
- goto match_fail;
- }
- pos += shcnt(f);
- continue;
- }
- p++;
- if (*p=='*') {
- dest = 0; p++;
- } else if (av_isdigit(*p) && p[1]=='$') {
- dest = arg_n(ap, *p-'0'); p+=2;
- } else {
- dest = va_arg(ap, void *);
- }
- for (width=0; av_isdigit(*p); p++) {
- width = 10*width + *p - '0';
- }
- if (*p=='m') {
- s = 0;
- p++;
- }
- size = SIZE_def;
- switch (*p++) {
- case 'h':
- if (*p == 'h') p++, size = SIZE_hh;
- else size = SIZE_h;
- break;
- case 'l':
- if (*p == 'l') p++, size = SIZE_ll;
- else size = SIZE_l;
- break;
- case 'j':
- size = SIZE_ll;
- break;
- case 'z':
- case 't':
- size = SIZE_l;
- break;
- case 'L':
- size = SIZE_L;
- break;
- case 'd': case 'i': case 'o': case 'u': case 'x':
- case 'a': case 'e': case 'f': case 'g':
- case 'A': case 'E': case 'F': case 'G': case 'X':
- case 's': case 'c': case '[':
- case 'S': case 'C':
- case 'p': case 'n':
- p--;
- break;
- default:
- goto fmt_fail;
- }
- t = *p;
- /* C or S */
- if ((t&0x2f) == 3) {
- t |= 32;
- size = SIZE_l;
- }
- switch (t) {
- case 'c':
- if (width < 1) width = 1;
- case '[':
- break;
- case 'n':
- store_int(dest, size, pos);
- /* do not increment match count, etc! */
- continue;
- default:
- shlim(f, 0);
- while (av_isspace(shgetc(f)));
- shunget(f);
- pos += shcnt(f);
- }
- shlim(f, width);
- if (shgetc(f) < 0) goto input_fail;
- shunget(f);
- switch (t) {
- case 's':
- case 'c':
- case '[':
- if (t == 'c' || t == 's') {
- memset(scanset, -1, sizeof scanset);
- scanset[0] = 0;
- if (t == 's') {
- scanset[1 + '\t'] = 0;
- scanset[1 + '\n'] = 0;
- scanset[1 + '\v'] = 0;
- scanset[1 + '\f'] = 0;
- scanset[1 + '\r'] = 0;
- scanset[1 + ' ' ] = 0;
- }
- } else {
- if (*++p == '^') p++, invert = 1;
- else invert = 0;
- memset(scanset, invert, sizeof scanset);
- scanset[0] = 0;
- if (*p == '-') p++, scanset[1+'-'] = 1-invert;
- else if (*p == ']') p++, scanset[1+']'] = 1-invert;
- for (; *p != ']'; p++) {
- if (!*p) goto fmt_fail;
- if (*p=='-' && p[1] && p[1] != ']')
- for (c=p++[-1]; c<*p; c++)
- scanset[1+c] = 1-invert;
- scanset[1+*p] = 1-invert;
- }
- }
- s = 0;
- i = 0;
- if ((s = dest)) {
- while (scanset[(c=shgetc(f))+1])
- s[i++] = c;
- } else {
- while (scanset[(c=shgetc(f))+1]);
- }
- shunget(f);
- if (!shcnt(f)) goto match_fail;
- if (t == 'c' && shcnt(f) != width) goto match_fail;
- if (t != 'c') {
- if (s) s[i] = 0;
- }
- break;
- case 'p':
- case 'X':
- case 'x':
- base = 16;
- goto int_common;
- case 'o':
- base = 8;
- goto int_common;
- case 'd':
- case 'u':
- base = 10;
- goto int_common;
- case 'i':
- base = 0;
- int_common:
- x = ffintscan(f, base, 0, ULLONG_MAX);
- if (!shcnt(f))
- goto match_fail;
- if (t=='p' && dest)
- *(void **)dest = (void *)(uintptr_t)x;
- else
- store_int(dest, size, x);
- break;
- case 'a': case 'A':
- case 'e': case 'E':
- case 'f': case 'F':
- case 'g': case 'G':
- y = fffloatscan(f, size, 0);
- if (!shcnt(f))
- goto match_fail;
- if (dest) {
- switch (size) {
- case SIZE_def:
- *(float *)dest = y;
- break;
- case SIZE_l:
- *(double *)dest = y;
- break;
- case SIZE_L:
- *(double *)dest = y;
- break;
- }
- }
- break;
- }
- pos += shcnt(f);
- if (dest) matches++;
- }
- if (0) {
- fmt_fail:
- input_fail:
- if (!matches) matches--;
- }
- match_fail:
- return matches;
- }
- static int ff_vsscanf(const char *s, const char *fmt, va_list ap)
- {
- FFFILE f = {
- .buf = (void *)s, .cookie = (void *)s,
- .read = ffstring_read,
- };
- return ff_vfscanf(&f, fmt, ap);
- }
- int av_sscanf(const char *string, const char *format, ...)
- {
- int ret;
- va_list ap;
- va_start(ap, format);
- ret = ff_vsscanf(string, format, ap);
- va_end(ap);
- return ret;
- }
|