ZBar bar code reader . http://zbar.sourceforge.net/ ZBar is licensed under the GNU LGPL 2.1 to enable development of both open source and commercial projects.

Dependents:   GR-PEACH_Camera_in_barcode levkov_ov7670

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers code128.c Source File

code128.c

00001 /*------------------------------------------------------------------------
00002  *  Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
00003  *
00004  *  This file is part of the ZBar Bar Code Reader.
00005  *
00006  *  The ZBar Bar Code Reader is free software; you can redistribute it
00007  *  and/or modify it under the terms of the GNU Lesser Public License as
00008  *  published by the Free Software Foundation; either version 2.1 of
00009  *  the License, or (at your option) any later version.
00010  *
00011  *  The ZBar Bar Code Reader is distributed in the hope that it will be
00012  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00013  *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU Lesser Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU Lesser Public License
00017  *  along with the ZBar Bar Code Reader; if not, write to the Free
00018  *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
00019  *  Boston, MA  02110-1301  USA
00020  *
00021  *  http://sourceforge.net/projects/zbar
00022  *------------------------------------------------------------------------*/
00023 
00024 #include <config.h>
00025 #include <string.h>     /* memmove */
00026 
00027 #include <zbar.h>
00028 #include "decoder.h"
00029 
00030 #ifdef DEBUG_CODE128
00031 # define DEBUG_LEVEL (DEBUG_CODE128)
00032 #endif
00033 #include "zbar_debug.h"
00034 
00035 #define NUM_CHARS 108           /* total number of character codes */
00036 
00037 typedef enum code128_char_e {
00038     FNC3        = 0x60,
00039     FNC2        = 0x61,
00040     SHIFT       = 0x62,
00041     CODE_C      = 0x63,
00042     CODE_B      = 0x64,
00043     CODE_A      = 0x65,
00044     FNC1        = 0x66,
00045     START_A     = 0x67,
00046     START_B     = 0x68,
00047     START_C     = 0x69,
00048     STOP_FWD    = 0x6a,
00049     STOP_REV    = 0x6b,
00050     FNC4        = 0x6c,
00051 } code128_char_t;
00052 
00053 static const unsigned char characters[NUM_CHARS] = {
00054     0x5c, 0xbf, 0xa1,                                           /* [00] 00 */
00055     0x2a, 0xc5, 0x0c, 0xa4,                                     /* [03] 01 */
00056     0x2d, 0xe3, 0x0f,                                           /* [07] 02 */
00057     0x5f, 0xe4,                                                 /* [0a] 03 */
00058 
00059     0x6b, 0xe8, 0x69, 0xa7, 0xe7,                               /* [0c] 10 */
00060     0xc1, 0x51, 0x1e, 0x83, 0xd9, 0x00, 0x84, 0x1f,             /* [11] 11 */
00061     0xc7, 0x0d, 0x33, 0x86, 0xb5, 0x0e, 0x15, 0x87,             /* [19] 12 */
00062     0x10, 0xda, 0x11,                                           /* [21] 13 */
00063 
00064     0x36, 0xe5, 0x18, 0x37,                                     /* [24] 20 */
00065     0xcc, 0x13, 0x39, 0x89, 0x97, 0x14, 0x1b, 0x8a, 0x3a, 0xbd, /* [28] 21 */
00066     0xa2, 0x5e, 0x01, 0x85, 0xb0, 0x02, 0xa3,                   /* [32] 22 */
00067     0xa5, 0x2c, 0x16, 0x88, 0xbc, 0x12, 0xa6,                   /* [39] 23 */
00068 
00069     0x61, 0xe6, 0x56, 0x62,                                     /* [40] 30 */
00070     0x19, 0xdb, 0x1a,                                           /* [44] 31 */
00071     0xa8, 0x32, 0x1c, 0x8b, 0xcd, 0x1d, 0xa9,                   /* [47] 32 */
00072     0xc3, 0x20, 0xc4,                                           /* [4e] 33 */
00073 
00074     0x50, 0x5d, 0xc0,       /* [51] 0014 0025 0034 */
00075     0x2b, 0xc6,             /* [54] 0134 0143 */
00076     0x2e,                   /* [56] 0243 */
00077     0x53, 0x60,             /* [57] 0341 0352 */
00078     0x31,                   /* [59] 1024 */
00079     0x52, 0xc2,             /* [5a] 1114 1134 */
00080     0x34, 0xc8,             /* [5c] 1242 1243 */
00081     0x55,                   /* [5e] 1441 */
00082 
00083     0x57, 0x3e, 0xce,       /* [5f] 4100 5200 4300 */
00084     0x3b, 0xc9,             /* [62] 4310 3410 */
00085     0x6a,                   /* [64] 3420 */
00086     0x54, 0x4f,             /* [65] 1430 2530 */
00087     0x38,                   /* [67] 4201 */
00088     0x58, 0xcb,             /* [68] 4111 4311 */
00089     0x2f, 0xca,             /* [6a] 2421 3421 */
00090 };
00091 
00092 static const unsigned char lo_base[8] = {
00093     0x00, 0x07, 0x0c, 0x19, 0x24, 0x32, 0x40, 0x47
00094 };
00095 
00096 static const unsigned char lo_offset[0x80] = {
00097     0xff, 0xf0, 0xff, 0x1f, 0xff, 0xf2, 0xff, 0xff,     /* 00 [00] */
00098     0xff, 0xff, 0xff, 0x3f, 0xf4, 0xf5, 0xff, 0x6f,     /* 01 */
00099     0xff, 0xff, 0xff, 0xff, 0xf0, 0xf1, 0xff, 0x2f,     /* 02 [07] */
00100     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x4f,     /* 03 */
00101     0xff, 0x0f, 0xf1, 0xf2, 0xff, 0x3f, 0xff, 0xf4,     /* 10 [0c] */
00102     0xf5, 0xf6, 0xf7, 0x89, 0xff, 0xab, 0xff, 0xfc,     /* 11 */
00103     0xff, 0xff, 0x0f, 0x1f, 0x23, 0x45, 0xf6, 0x7f,     /* 12 [19] */
00104     0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xf9, 0xaf,     /* 13 */
00105 
00106     0xf0, 0xf1, 0xff, 0x2f, 0xff, 0xf3, 0xff, 0xff,     /* 20 [24] */
00107     0x4f, 0x5f, 0x67, 0x89, 0xfa, 0xbf, 0xff, 0xcd,     /* 21 */
00108     0xf0, 0xf1, 0xf2, 0x3f, 0xf4, 0x56, 0xff, 0xff,     /* 22 [32] */
00109     0xff, 0xff, 0x7f, 0x8f, 0x9a, 0xff, 0xbc, 0xdf,     /* 23 */
00110     0x0f, 0x1f, 0xf2, 0xff, 0xff, 0x3f, 0xff, 0xff,     /* 30 [40] */
00111     0xf4, 0xff, 0xf5, 0x6f, 0xff, 0xff, 0xff, 0xff,     /* 31 */
00112     0x0f, 0x1f, 0x23, 0xff, 0x45, 0x6f, 0xff, 0xff,     /* 32 [47] */
00113     0xf7, 0xff, 0xf8, 0x9f, 0xff, 0xff, 0xff, 0xff,     /* 33 */
00114 };
00115 
00116 static inline signed char decode_lo (int sig)
00117 {
00118     unsigned char offset = (((sig >> 1) & 0x01) |
00119                             ((sig >> 3) & 0x06) |
00120                             ((sig >> 5) & 0x18) |
00121                             ((sig >> 7) & 0x60));
00122     unsigned char idx = lo_offset[offset];
00123     if(sig & 1)
00124         idx &= 0xf;
00125     else
00126         idx >>= 4;
00127     if(idx == 0xf)
00128         return(-1);
00129 
00130     unsigned char base = (sig >> 11) | ((sig >> 9) & 1);
00131     zassert(base < 8, -1, "sig=%x offset=%x idx=%x base=%x\n",
00132             sig, offset, idx, base);
00133     idx += lo_base[base];
00134 
00135     zassert(idx <= 0x50, -1, "sig=%x offset=%x base=%x idx=%x\n",
00136             sig, offset, base, idx);
00137     unsigned char c = characters[idx];
00138     dprintf(2, " %02x(%x(%02x)/%x(%02x)) => %02x",
00139             idx, base, lo_base[base], offset, lo_offset[offset],
00140             (unsigned char)c);
00141     return(c);
00142 }
00143 
00144 static inline signed char decode_hi (int sig)
00145 {
00146     unsigned char rev = (sig & 0x4400) != 0;
00147     if(rev)
00148         sig = (((sig >> 12) & 0x000f) |
00149                ((sig >>  4) & 0x00f0) |
00150                ((sig <<  4) & 0x0f00) |
00151                ((sig << 12) & 0xf000));
00152     dprintf(2, " rev=%x", rev != 0);
00153 
00154     unsigned char idx;
00155     switch(sig) {
00156     case 0x0014: idx = 0x0; break;
00157     case 0x0025: idx = 0x1; break;
00158     case 0x0034: idx = 0x2; break;
00159     case 0x0134: idx = 0x3; break;
00160     case 0x0143: idx = 0x4; break;
00161     case 0x0243: idx = 0x5; break;
00162     case 0x0341: idx = 0x6; break;
00163     case 0x0352: idx = 0x7; break;
00164     case 0x1024: idx = 0x8; break;
00165     case 0x1114: idx = 0x9; break;
00166     case 0x1134: idx = 0xa; break;
00167     case 0x1242: idx = 0xb; break;
00168     case 0x1243: idx = 0xc; break;
00169     case 0x1441: idx = 0xd; rev = 0; break;
00170     default: return(-1);
00171     }
00172     if(rev)
00173         idx += 0xe;
00174     unsigned char c = characters[0x51 + idx];
00175     dprintf(2, " %02x => %02x", idx, c);
00176     return(c);
00177 }
00178 
00179 static inline unsigned char calc_check (unsigned char c)
00180 {
00181     if(!(c & 0x80))
00182         return(0x18);
00183     c &= 0x7f;
00184     if(c < 0x3d)
00185         return((c < 0x30 && c != 0x17) ? 0x10 : 0x20);
00186     if(c < 0x50)
00187         return((c == 0x4d) ? 0x20 : 0x10);
00188     return((c < 0x67) ? 0x20 : 0x10);
00189 }
00190 
00191 static inline signed char decode6 (zbar_decoder_t *dcode)
00192 {
00193     /* build edge signature of character */
00194     unsigned s = dcode->code128.s6;
00195     dprintf(2, " s=%d", s);
00196     if(s < 5)
00197         return(-1);
00198     /* calculate similar edge measurements */
00199     int sig = (get_color(dcode) == ZBAR_BAR)
00200         ? ((decode_e(get_width(dcode, 0) + get_width(dcode, 1), s, 11) << 12) |
00201            (decode_e(get_width(dcode, 1) + get_width(dcode, 2), s, 11) << 8) |
00202            (decode_e(get_width(dcode, 2) + get_width(dcode, 3), s, 11) << 4) |
00203            (decode_e(get_width(dcode, 3) + get_width(dcode, 4), s, 11)))
00204         : ((decode_e(get_width(dcode, 5) + get_width(dcode, 4), s, 11) << 12) |
00205            (decode_e(get_width(dcode, 4) + get_width(dcode, 3), s, 11) << 8) |
00206            (decode_e(get_width(dcode, 3) + get_width(dcode, 2), s, 11) << 4) |
00207            (decode_e(get_width(dcode, 2) + get_width(dcode, 1), s, 11)));
00208     if(sig < 0)
00209         return(-1);
00210     dprintf(2, " sig=%04x", sig);
00211     /* lookup edge signature */
00212     signed char c = (sig & 0x4444) ? decode_hi(sig) : decode_lo(sig);
00213     if(c == -1)
00214         return(-1);
00215 
00216     /* character validation */
00217     unsigned bars = (get_color(dcode) == ZBAR_BAR)
00218         ? (get_width(dcode, 0) + get_width(dcode, 2) + get_width(dcode, 4))
00219         : (get_width(dcode, 1) + get_width(dcode, 3) + get_width(dcode, 5));
00220     bars = bars * 11 * 4 / s;
00221     unsigned char chk = calc_check(c);
00222     dprintf(2, " bars=%d chk=%d", bars, chk);
00223     if(chk - 7 > bars || bars > chk + 7)
00224         return(-1);
00225 
00226     return(c & 0x7f);
00227 }
00228 
00229 static inline unsigned char validate_checksum (zbar_decoder_t *dcode)
00230 {
00231     code128_decoder_t *dcode128 = &dcode->code128;
00232     if(dcode128->character < 3)
00233         return(1);
00234 
00235     /* add in irregularly weighted start character */
00236     unsigned idx = (dcode128->direction) ? dcode128->character - 1 : 0;
00237     unsigned sum = dcode->buf[idx];
00238     if(sum >= 103)
00239         sum -= 103;
00240 
00241     /* calculate sum in reverse to avoid multiply operations */
00242     unsigned i, acc = 0;
00243     for(i = dcode128->character - 3; i; i--) {
00244         zassert(sum < 103, -1, "dir=%x i=%x sum=%x acc=%x %s\n",
00245                 dcode128->direction, i, sum, acc,
00246                 _zbar_decoder_buf_dump(dcode->buf, dcode128->character));
00247         idx = (dcode128->direction) ? dcode128->character - 1 - i : i;
00248         acc += dcode->buf[idx];
00249         if(acc >= 103)
00250             acc -= 103;
00251         zassert(acc < 103, -1, "dir=%x i=%x sum=%x acc=%x %s\n",
00252                 dcode128->direction, i, sum, acc,
00253                 _zbar_decoder_buf_dump(dcode->buf, dcode128->character));
00254         sum += acc;
00255         if(sum >= 103)
00256             sum -= 103;
00257     }
00258 
00259     /* and compare to check character */
00260     idx = (dcode128->direction) ? 1 : dcode128->character - 2;
00261     unsigned char check = dcode->buf[idx];
00262     dprintf(2, " chk=%02x(%02x)", sum, check);
00263     unsigned char err = (sum != check);
00264     if(err)
00265         dprintf(1, " [checksum error]\n");
00266     return(err);
00267 }
00268 
00269 /* expand and decode character set C */
00270 static inline unsigned postprocess_c (zbar_decoder_t *dcode,
00271                                       unsigned start,
00272                                       unsigned end,
00273                                       unsigned dst)
00274 {
00275     /* expand buffer to accomodate 2x set C characters (2 digits per-char) */
00276     unsigned delta = end - start;
00277     unsigned newlen = dcode->code128.character + delta;
00278     size_buf(dcode, newlen);
00279 
00280     /* relocate unprocessed data to end of buffer */
00281     memmove(dcode->buf + start + delta, dcode->buf + start,
00282             dcode->code128.character - start);
00283     dcode->code128.character = newlen;
00284 
00285     unsigned i, j;
00286     for(i = 0, j = dst; i < delta; i++, j += 2) {
00287         /* convert each set C character into two ASCII digits */
00288         unsigned char code = dcode->buf[start + delta + i];
00289         dcode->buf[j] = '0';
00290         if(code >= 50) {
00291             code -= 50;
00292             dcode->buf[j] += 5;
00293         }
00294         if(code >= 30) {
00295             code -= 30;
00296             dcode->buf[j] += 3;
00297         }
00298         if(code >= 20) {
00299             code -= 20;
00300             dcode->buf[j] += 2;
00301         }
00302         if(code >= 10) {
00303             code -= 10;
00304             dcode->buf[j] += 1;
00305         }
00306         zassert(dcode->buf[j] <= '9', delta,
00307                 "start=%x end=%x i=%x j=%x %s\n", start, end, i, j,
00308                 _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
00309         zassert(code <= 9, delta,
00310                 "start=%x end=%x i=%x j=%x %s\n", start, end, i, j,
00311                 _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
00312         dcode->buf[j + 1] = '0' + code;
00313     }
00314     return(delta);
00315 }
00316 
00317 /* resolve scan direction and convert to ASCII */
00318 static inline unsigned char postprocess (zbar_decoder_t *dcode)
00319 {
00320     code128_decoder_t *dcode128 = &dcode->code128;
00321     dprintf(2, "\n    postproc len=%d", dcode128->character);
00322     unsigned i, j;
00323     unsigned char code = 0;
00324     if(dcode128->direction) {
00325         /* reverse buffer */
00326         dprintf(2, " (rev)");
00327         for(i = 0; i < dcode128->character / 2; i++) {
00328             unsigned j = dcode128->character - 1 - i;
00329             code = dcode->buf[i];
00330             dcode->buf[i] = dcode->buf[j];
00331             dcode->buf[j] = code;
00332         }
00333         zassert(dcode->buf[dcode128->character - 1] == STOP_REV, 1,
00334                 "dir=%x %s\n", dcode128->direction,
00335                 _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
00336     }
00337     else
00338         zassert(dcode->buf[dcode128->character - 1] == STOP_FWD, 1,
00339                 "dir=%x %s\n", dcode128->direction,
00340                 _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
00341 
00342     code = dcode->buf[0];
00343     zassert(code >= START_A && code <= START_C, 1, "%s\n",
00344             _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
00345 
00346     unsigned char charset = code - START_A;
00347     unsigned cexp = (code == START_C) ? 1 : 0;
00348     dprintf(2, " start=%c", 'A' + charset);
00349 
00350     for(i = 1, j = 0; i < dcode128->character - 2; i++) {
00351         unsigned char code = dcode->buf[i];
00352         zassert(!(code & 0x80), 1,
00353                 "i=%x j=%x code=%02x charset=%x cexp=%x %s\n",
00354                 i, j, code, charset, cexp,
00355                 _zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
00356 
00357         if((charset & 0x2) && (code < 100))
00358             /* defer character set C for expansion */
00359             continue;
00360         else if(code < 0x60) {
00361             /* convert character set B to ASCII */
00362             code = code + 0x20;
00363             if((!charset || (charset == 0x81)) && (code >= 0x60))
00364                 /* convert character set A to ASCII */
00365                 code -= 0x60;
00366             dcode->buf[j++] = code;
00367             if(charset & 0x80)
00368                 charset &= 0x7f;
00369         }
00370         else {
00371             dprintf(2, " %02x", code);
00372             if(charset & 0x2) {
00373                 /* expand character set C to ASCII */
00374                 zassert(cexp, 1, "i=%x j=%x code=%02x charset=%x cexp=%x %s\n",
00375                         i, j, code, charset, cexp,
00376                         _zbar_decoder_buf_dump(dcode->buf,
00377                                                 dcode->code128.character));
00378                 unsigned delta = postprocess_c(dcode, cexp, i, j);
00379                 i += delta;
00380                 j += delta * 2;
00381                 cexp = 0;
00382             }
00383             if(code < CODE_C) {
00384                 if(code == SHIFT)
00385                     charset |= 0x80;
00386                 else if(code == FNC2)
00387                     /* FIXME FNC2 - message append */;
00388                 else if(code == FNC3)
00389                     /* FIXME FNC3 - initialize */;
00390             }
00391             else if(code == FNC1)
00392                 /* FIXME FNC1 - Code 128 subsets or ASCII 0x1d */;
00393             else if(code >= START_A) {
00394                 dprintf(1, " [truncated]\n");
00395                 return(1);
00396             }
00397             else {
00398                 zassert(code >= CODE_C && code <= CODE_A, 1,
00399                         "i=%x j=%x code=%02x charset=%x cexp=%x %s\n",
00400                         i, j, code, charset, cexp,
00401                         _zbar_decoder_buf_dump(dcode->buf,
00402                                                 dcode->code128.character));
00403                 unsigned char newset = CODE_A - code;
00404                 if(newset != charset)
00405                     charset = newset;
00406                 else
00407                     /* FIXME FNC4 - extended ASCII */;
00408             }
00409             if(charset & 0x2)
00410                 cexp = i + 1;
00411         }
00412     }
00413     if(charset & 0x2) {
00414         zassert(cexp, 1, "i=%x j=%x code=%02x charset=%x cexp=%x %s\n",
00415                 i, j, code, charset, cexp,
00416                 _zbar_decoder_buf_dump(dcode->buf,
00417                                         dcode->code128.character));
00418         j += postprocess_c(dcode, cexp, i, j) * 2;
00419     }
00420     dcode->buflen = j;
00421     dcode->buf[j] = '\0';
00422     dcode->code128.character = j;
00423     return(0);
00424 }
00425 
00426 zbar_symbol_type_t _zbar_decode_code128 (zbar_decoder_t *dcode)
00427 {
00428     code128_decoder_t *dcode128 = &dcode->code128;
00429 
00430     /* update latest character width */
00431     dcode128->s6 -= get_width(dcode, 6);
00432     dcode128->s6 += get_width(dcode, 0);
00433 
00434     if(/* process every 6th element of active symbol */
00435        (dcode128->character >= 0 &&
00436         (++dcode128->element) != 6) ||
00437        /* decode color based on direction */
00438        (get_color(dcode) != dcode128->direction))
00439         return(0);
00440     dcode128->element = 0;
00441 
00442     dprintf(2, "      code128[%c%02d+%x]:",
00443             (dcode128->direction) ? '<' : '>',
00444             dcode128->character, dcode128->element);
00445 
00446     signed char c = decode6(dcode);
00447     if(dcode128->character < 0) {
00448         dprintf(2, " c=%02x", c);
00449         if(c < START_A || c > STOP_REV || c == STOP_FWD) {
00450             dprintf(2, " [invalid]\n");
00451             return(0);
00452         }
00453         unsigned qz = get_width(dcode, 6);
00454         if(qz && qz < (dcode->code128.s6 * 3) / 4) {
00455             dprintf(2, " [invalid qz %d]\n", qz);
00456             return(0);
00457         }
00458         /* lock shared resources */
00459         if(get_lock(dcode, ZBAR_CODE128)) {
00460             dprintf(2, " [locked %d]\n", dcode->lock);
00461             dcode128->character = -1;
00462             return(0);
00463         }
00464         /* decoded valid start/stop */
00465         /* initialize state */
00466         dcode128->character = 0;
00467         if(c == STOP_REV) {
00468             dcode128->direction = ZBAR_BAR;
00469             dcode128->element = 7;
00470         }
00471         else
00472             dcode128->direction = ZBAR_SPACE;
00473         dprintf(2, " dir=%x [valid start]", dcode128->direction);
00474     }
00475     else if((c < 0) ||
00476             ((dcode128->character >= BUFFER_MIN) &&
00477              size_buf(dcode, dcode128->character + 1))) {
00478         dprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n");
00479         dcode->lock = 0;
00480         dcode128->character = -1;
00481         return(0);
00482     }
00483 
00484     zassert(dcode->buf_alloc > dcode128->character, 0,
00485             "alloc=%x idx=%x c=%02x %s\n",
00486             dcode->buf_alloc, dcode128->character, c,
00487             _zbar_decoder_buf_dump(dcode->buf, dcode->buf_alloc));
00488 
00489     dcode->buf[dcode128->character++] = c;
00490 
00491     if(dcode128->character > 2 &&
00492        ((dcode128->direction)
00493         ? c >= START_A && c <= START_C
00494         : c == STOP_FWD)) {
00495         /* FIXME STOP_FWD should check extra bar (and QZ!) */
00496         zbar_symbol_type_t sym = ZBAR_CODE128;
00497         if(validate_checksum(dcode) || postprocess(dcode))
00498             sym = ZBAR_NONE;
00499         else if(dcode128->character < CFG(*dcode128, ZBAR_CFG_MIN_LEN) ||
00500                 (CFG(*dcode128, ZBAR_CFG_MAX_LEN) > 0 &&
00501                  dcode128->character > CFG(*dcode128, ZBAR_CFG_MAX_LEN))) {
00502             dprintf(2, " [invalid len]\n");
00503             sym = ZBAR_NONE;
00504         }
00505         else
00506             dprintf(2, " [valid end]\n");
00507         dcode128->character = -1;
00508         if(!sym)
00509             dcode->lock = 0;
00510         return(sym);
00511     }
00512 
00513     dprintf(2, "\n");
00514     return(0);
00515 }
00516