File nand_grading_support.patch of Package zbar

diff --git a/include/zbar.h b/include/zbar.h
index 66281c1..cb68b48 100644
--- a/include/zbar.h
+++ b/include/zbar.h
@@ -364,6 +364,23 @@ extern zbar_error_t _zbar_get_error_code(const void *object);
 
 /*@}*/
 
+typedef struct decodeErrorsInfo_struct {
+    int errors[81];
+    int maxCorrectableErrors[81];
+    int checkedBlocks;
+    int totalBlocks;
+    int readError;
+} decodeErrorsInfo;
+typedef struct codeStructureInfo_struct {
+    // int numElems[81][2];
+    int (*numElems)[2];
+    // int blocks[81][2][153][8][2];
+    int (*blocks)[2][153][8][2];
+    int numBlocks;
+    int codeSize;
+    int valid;
+} codeStructureInfo;
+
 struct zbar_symbol_s;
 typedef struct zbar_symbol_s zbar_symbol_t;
 
@@ -1567,6 +1584,10 @@ extern unsigned zbar_scanner_get_edge(const zbar_scanner_t *scn,
 /** retrieve last scanned color. */
 extern zbar_color_t zbar_scanner_get_color(const zbar_scanner_t *scanner);
 
+extern float zbar_uec(const zbar_symbol_t* sym);
+extern codeStructureInfo* zbar_structure(const zbar_symbol_t* sym);
+extern int zbar_size(const zbar_symbol_t* sym);
+
 /*@}*/
 
 #ifdef __cplusplus
diff --git a/include/zbar/Symbol.h b/include/zbar/Symbol.h
index f3a5668..c011c86 100644
--- a/include/zbar/Symbol.h
+++ b/include/zbar/Symbol.h
@@ -35,6 +35,8 @@
 #include <stdlib.h>
 #include <string>
 
+#include <vector>
+
 namespace zbar
 {
 class SymbolIterator;
@@ -398,6 +400,45 @@ public:
 	return (zbar_symbol_xml(_sym, (char **)&_xmlbuf, (unsigned *)&_xmllen));
     }
 
+    float uec() const
+    {
+        return zbar_uec(_sym);
+    }
+    std::vector< std::vector< std::vector< std::vector< std::vector<int> > > > > structure() const
+    {
+        std::vector< std::vector< std::vector< std::vector< std::vector<int> > > > > ret;
+        if (_type != ZBAR_QRCODE) {
+            return ret;
+        }
+        codeStructureInfo* res = zbar_structure(_sym);
+        if (!res->valid) {
+            return ret;
+        }
+        for (int block = 0; block < res->numBlocks; ++block) {
+            std::vector< std::vector< std::vector< std::vector<int> > > > t4;
+            for (int type = 0; type < 2; ++type) {
+                std::vector< std::vector< std::vector<int> > > t3;
+                for (int sym = 0; sym < res->numElems[block][type]; ++sym) {
+                    std::vector< std::vector<int> > t2;
+                    for (int bit = 0; bit < 8; ++bit) {
+                        std::vector<int> t1;
+                        t1.push_back(res->blocks[block][type][sym][bit][0]);
+                        t1.push_back(res->blocks[block][type][sym][bit][1]);
+                        t2.push_back( std::move(t1) );
+                    }
+                    t3.push_back( std::move(t2) );
+                }
+                t4.push_back( std::move(t3) );
+            }
+            ret.push_back( std::move(t4) );
+        }
+        return ret;
+    }
+    int size() const
+    {
+        return zbar_size(_sym);
+    }
+
 protected:
     /// (re)initialize Symbol from C symbol object.
     void init(const zbar_symbol_t *sym = NULL)
diff --git a/zbar/img_scanner.c b/zbar/img_scanner.c
index 3e235d1..71fcfc5 100644
--- a/zbar/img_scanner.c
+++ b/zbar/img_scanner.c
@@ -169,6 +169,11 @@ void _zbar_image_scanner_recycle_syms(zbar_image_scanner_t *iscn,
 		free(sym->data);
 		sym->data	= NULL;
 		sym->data_alloc = 0;
+
+		sym->str.valid = 0;
+		if (sym->str.numElems) {free(sym->str.numElems); sym->str.numElems = NULL;}
+		if (sym->str.blocks) {free(sym->str.blocks); sym->str.blocks = NULL;}
+
 		i		= 0;
 	    }
 	    bucket = &iscn->recycle[i];
@@ -253,6 +258,12 @@ inline zbar_symbol_t *_zbar_image_scanner_alloc_sym(zbar_image_scanner_t *iscn,
     sym->orient	     = ZBAR_ORIENT_UNKNOWN;
     sym->cache_count = 0;
     sym->time	     = iscn->time;
+
+    sym->uec.readError = 1;
+    sym->str.valid = 0;
+    sym->str.numElems = malloc(sizeof(*sym->str.numElems) * 81);
+    sym->str.blocks = malloc(sizeof(*sym->str.blocks) * 81);
+
     assert(!sym->syms);
 
     if (datalen > 0) {
diff --git a/zbar/qrcode/qrdec.c b/zbar/qrcode/qrdec.c
index 905336a..27f2398 100644
--- a/zbar/qrcode/qrdec.c
+++ b/zbar/qrcode/qrdec.c
@@ -3289,7 +3289,8 @@ static void qr_sampling_grid_sample(const qr_sampling_grid *_grid,
 static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
 			      int _nshort_data, int _nshort_blocks,
 			      const unsigned *_data_bits,
-			      const unsigned *_fp_mask, int _dim)
+			      const unsigned *_fp_mask, int _dim,
+			      codeStructureInfo *_info)
 {
     unsigned bits;
     int biti;
@@ -3298,6 +3299,23 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
     int blockj;
     int i;
     int j;
+
+    int numTotalDataSyms;
+    int currInsSyms;
+    int storage[9][2];
+    _info->codeSize = _dim;
+    _info->numBlocks = _nblocks;
+    if (_info->numElems) {free(_info->numElems);}
+    _info->numElems = malloc(sizeof(*_info->numElems) * _nblocks);
+    if (_info->blocks) {free(_info->blocks);}
+    _info->blocks = malloc(sizeof(*_info->blocks) * _nblocks);
+    for (int ij = 0; ij < _nblocks; ++ij) {
+        _info->numElems[ij][0] = 0;
+        _info->numElems[ij][1] = 0;
+    }
+    numTotalDataSyms = _nshort_blocks * _nshort_data + (_nblocks - _nshort_blocks) * (_nshort_data + 1);
+    currInsSyms = 0;
+
     stride = _dim + QR_INT_BITS - 1 >> QR_INT_LOGBITS;
     /*If _all_ the blocks are short, don't skip anything (see below).*/
     if (_nshort_blocks >= _nblocks)
@@ -3323,16 +3341,36 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
 		/*Pull a bit from the right column.*/
 		if (!(fp_mask1 >> nbits & 1)) {
 		    bits = bits << 1 | data1 >> nbits & 1;
+
+		    storage[biti][0] = j;
+		    storage[biti][1] = nbits + QR_INT_BITS * i;
+
 		    biti++;
 		}
 		/*Pull a bit from the left column.*/
 		if (!(fp_mask2 >> nbits & 1)) {
 		    bits = bits << 1 | data2 >> nbits & 1;
+
+		    storage[biti][0] = j - 1;
+		    storage[biti][1] = nbits + QR_INT_BITS * i;
+
 		    biti++;
 		}
 		/*If we finished a byte, drop it in a block.*/
 		if (biti >= 8) {
+
 		    biti -= 8;
+
+		    for (int bi = 0; bi < 8; ++bi) {
+		        _info->blocks[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ][ _info->numElems[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ] ][bi][0] = storage[bi][0];
+		        _info->blocks[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ][ _info->numElems[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ] ][bi][1] = storage[bi][1];
+		    }
+		    if (biti > 0) {
+		        storage[0][0] = storage[8][0];
+		        storage[0][1] = storage[8][1];
+		    }
+		    (++currInsSyms > numTotalDataSyms) ? (_info->numElems[blocki][1]++) : (_info->numElems[blocki][0]++);
+
 		    *_blocks[blocki++]++ = (unsigned char)(bits >> biti);
 		    /*For whatever reason, the long blocks are at the _end_ of the list,
              instead of the beginning.
@@ -3356,15 +3394,25 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
 	/*Scan down a pair of columns.*/
 	l = j * stride;
 	for (i = 0; i < stride; i++) {
+
+	    int maxnbits;
+
 	    data1    = _data_bits[l + i];
 	    fp_mask1 = _fp_mask[l + i];
 	    data2    = _data_bits[l + i - stride];
 	    fp_mask2 = _fp_mask[l + i - stride];
 	    nbits    = QR_MINI(_dim - (i << QR_INT_LOGBITS), QR_INT_BITS);
+
+	    maxnbits = nbits - 1;
+
 	    while (nbits-- > 0) {
 		/*Pull a bit from the right column.*/
 		if (!(fp_mask1 & 1)) {
 		    bits = bits << 1 | data1 & 1;
+
+		    storage[biti][0] = j;
+		    storage[biti][1] = (maxnbits - nbits) + QR_INT_BITS * i;
+
 		    biti++;
 		}
 		data1 >>= 1;
@@ -3372,13 +3420,29 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
 		/*Pull a bit from the left column.*/
 		if (!(fp_mask2 & 1)) {
 		    bits = bits << 1 | data2 & 1;
+
+		    storage[biti][0] = j - 1;
+		    storage[biti][1] = (maxnbits - nbits) + QR_INT_BITS * i;
+
 		    biti++;
 		}
 		data2 >>= 1;
 		fp_mask2 >>= 1;
 		/*If we finished a byte, drop it in a block.*/
 		if (biti >= 8) {
+
 		    biti -= 8;
+
+		    for (int bi = 0; bi < 8; ++bi) {
+		        _info->blocks[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ][ _info->numElems[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ] ][bi][0] = storage[bi][0];
+		        _info->blocks[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ][ _info->numElems[blocki][ ((currInsSyms >= numTotalDataSyms) ? 1 : 0) ] ][bi][1] = storage[bi][1];
+		    }
+		    if (biti > 0) {
+		        storage[0][0] = storage[8][0];
+		        storage[0][1] = storage[8][1];
+		    }
+		    (++currInsSyms > numTotalDataSyms) ? (_info->numElems[blocki][1]++) : (_info->numElems[blocki][0]++);
+
 		    *_blocks[blocki++]++ = (unsigned char)(bits >> biti);
 		    /*See comments on the "up" loop for the reason behind this mess.*/
 		    if (blocki >= _nblocks)
@@ -3387,6 +3451,9 @@ static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
 	    }
 	}
     }
+
+    _info->valid = 1;
+
 }
 
 /*Bit reading code blatantly stolen^W^Wadapted from libogg/libtheora (because
@@ -3745,6 +3812,10 @@ static void qr_code_data_clear(qr_code_data *_qrdata)
 	}
     }
     free(_qrdata->entries);
+
+    if (_qrdata->str.numElems) {free(_qrdata->str.numElems); _qrdata->str.numElems = NULL;}
+    if (_qrdata->str.blocks) {free(_qrdata->str.blocks); _qrdata->str.blocks = NULL;}
+
 }
 
 void qr_code_data_list_init(qr_code_data_list *_qrlist)
@@ -3909,7 +3980,7 @@ static int qr_code_decode(qr_code_data *_qrdata, const rs_gf256 *_gf,
     for (i = 1; i < nblocks; i++)
 	blocks[i] = blocks[i - 1] + block_sz + (i > nshort_blocks);
     qr_samples_unpack(blocks, nblocks, block_sz - npar, nshort_blocks,
-		      data_bits, grid.fpmask, dim);
+		      data_bits, grid.fpmask, dim, &_qrdata->str);
     qr_sampling_grid_clear(&grid);
     free(blocks);
     free(data_bits);
@@ -3917,6 +3988,10 @@ static int qr_code_decode(qr_code_data *_qrdata, const rs_gf256 *_gf,
     ndata      = 0;
     ncodewords = 0;
     ret	       = 0;
+
+    _qrdata->uec.checkedBlocks = 0;
+    _qrdata->uec.totalBlocks = nblocks;
+
     for (i = 0; i < nblocks; i++) {
 	int block_szi;
 	int ndatai;
@@ -3925,6 +4000,19 @@ static int qr_code_decode(qr_code_data *_qrdata, const rs_gf256 *_gf,
 			 NULL, 0);
 	zprintf(1, "Number of errors corrected: %i%s\n", ret,
 		ret < 0 ? " (data irrecoverable)" : "");
+
+	_qrdata->uec.errors[i] = ret;
+	if (_version == 1) {
+	    _qrdata->uec.maxCorrectableErrors[i] = (ecc_level + 1) << 1;
+	}
+	else if (_version == 2 && ecc_level == 0) {
+	    _qrdata->uec.maxCorrectableErrors[i] = (npar - 1) >> 1;
+	}
+	else {
+	    _qrdata->uec.maxCorrectableErrors[i] = npar >> 1;
+	}
+	_qrdata->uec.checkedBlocks += 1;
+
 	/*For version 1 symbols and version 2-L and 3-L symbols, we aren't allowed
        to use all the parity bytes for correction.
       They are instead used to improve detection.
@@ -3951,9 +4039,19 @@ static int qr_code_decode(qr_code_data *_qrdata, const rs_gf256 *_gf,
        API support for that; a mode ignoring ECC errors might also be useful.*/
 	if (ret < 0)
 	    qr_code_data_clear(_qrdata);
+
+	else
+	    _qrdata->uec.readError = 0;
+
 	_qrdata->version   = _version;
 	_qrdata->ecc_level = ecc_level;
     }
+
+    else {
+        if (_qrdata->str.numElems) {free(_qrdata->str.numElems); _qrdata->str.numElems = NULL;}
+        if (_qrdata->str.blocks) {free(_qrdata->str.blocks); _qrdata->str.blocks = NULL;}
+    }
+
     free(block_data);
     return ret;
 }
@@ -4247,6 +4345,12 @@ void qr_reader_match_centers(qr_reader *_reader, qr_code_data_list *_qrlist,
 		if (!mark[k]) {
 		    qr_finder_center *c[3];
 		    qr_code_data qrdata;
+
+		    qrdata.uec.readError = 1;
+		    qrdata.str.valid = 0;
+		    qrdata.str.numElems = NULL;
+		    qrdata.str.blocks = NULL;
+
 		    int version;
 		    c[0]    = _centers + i;
 		    c[1]    = _centers + j;
diff --git a/zbar/qrcode/qrdec.h b/zbar/qrcode/qrdec.h
index 40cb204..5192199 100644
--- a/zbar/qrcode/qrdec.h
+++ b/zbar/qrcode/qrdec.h
@@ -140,6 +140,10 @@ struct qr_code_data {
     Points appear in the order up-left, up-right, down-left, down-right,
      relative to the orientation of the QR code.*/
     qr_point bbox[4];
+
+    decodeErrorsInfo uec;
+    codeStructureInfo str;
+
 };
 
 struct qr_code_data_list {
diff --git a/zbar/qrcode/qrdectxt.c b/zbar/qrcode/qrdectxt.c
index 71c59cb..b53a98c 100644
--- a/zbar/qrcode/qrdectxt.c
+++ b/zbar/qrcode/qrdectxt.c
@@ -500,9 +500,20 @@ int qr_code_data_list_extract_text(const qr_code_data_list *_qrlist,
 			(char *)realloc(sa_text, sa_ntext * sizeof(*sa_text));
 		}
 
-		if (sa_size == 1)
+		if (sa_size == 1) {
 		    sa_sym = syms;
-		else {
+		    if (!qrdata[i].uec.readError) {
+		        sa_sym->uec = qrdata[i].uec;
+		    }
+		    if (qrdata[i].str.valid) {
+		        sa_sym->str.valid = qrdata[i].str.valid;
+		        sa_sym->str.codeSize = qrdata[i].str.codeSize;
+		        sa_sym->str.numBlocks = qrdata[i].str.numBlocks;
+		        memcpy(sa_sym->str.numElems, qrdata[i].str.numElems, sizeof(*qrdata[i].str.numElems) * qrdata[i].str.numBlocks);
+		        memcpy(sa_sym->str.blocks, qrdata[i].str.blocks, sizeof(*qrdata[i].str.blocks) * qrdata[i].str.numBlocks);
+		    }
+
+		} else {
 		    /* cheap out w/axis aligned bbox for now */
 		    int xmin = img->width, xmax = -2;
 		    int ymin = img->height, ymax = -2;
diff --git a/zbar/symbol.c b/zbar/symbol.c
index fe2a4f8..20a9866 100644
--- a/zbar/symbol.c
+++ b/zbar/symbol.c
@@ -223,6 +223,10 @@ void _zbar_symbol_free(zbar_symbol_t *sym)
 	free(sym->pts);
     if (sym->data_alloc && sym->data)
 	free(sym->data);
+
+    if (sym->str.numElems) {free(sym->str.numElems); sym->str.numElems = NULL;}
+    if (sym->str.blocks) {free(sym->str.blocks); sym->str.blocks = NULL;}
+
     free(sym);
 }
 
@@ -511,3 +515,40 @@ zbar_symbol_set_first_unfiltered(const zbar_symbol_set_t *syms)
 {
     return (syms->head);
 }
+
+float
+zbar_uec(const zbar_symbol_t* sym)
+{
+    if (sym->type != ZBAR_QRCODE) {
+        return -1;
+    }
+    if (!sym->uec.readError && sym->uec.checkedBlocks == sym->uec.totalBlocks) {
+        float minUEC = 1.0;
+        for (int i = 0; i < sym->uec.checkedBlocks; ++i) {
+            float blockUEC;
+            if (sym->uec.errors[i] > sym->uec.maxCorrectableErrors[i]) {
+                minUEC = 0.0;
+                break;
+            }
+            blockUEC = 1.0 - (float)sym->uec.errors[i] / sym->uec.maxCorrectableErrors[i];
+            if (blockUEC < minUEC) minUEC = blockUEC;
+        }
+        return minUEC;
+    }
+    else {
+        return 0.0;
+    }
+}
+codeStructureInfo*
+zbar_structure(const zbar_symbol_t* sym)
+{
+    return &sym->str;
+}
+int
+zbar_size(const zbar_symbol_t* sym)
+{
+    if (sym->type != ZBAR_QRCODE || !sym->str.valid) {
+        return -1;
+    }
+    return sym->str.codeSize;
+}
diff --git a/zbar/symbol.h b/zbar/symbol.h
index 5ea97a3..cfc78c4 100644
--- a/zbar/symbol.h
+++ b/zbar/symbol.h
@@ -59,6 +59,10 @@ struct zbar_symbol_s {
     unsigned long time;	     /* relative symbol capture time */
     int cache_count;	     /* cache state */
     int quality;	     /* relative symbol reliability metric */
+
+    decodeErrorsInfo uec;
+    codeStructureInfo str;
+
 };
 
 extern int _zbar_get_symbol_hash(zbar_symbol_type_t);
openSUSE Build Service is sponsored by