WvStreams
wvencoder.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * A top-level data encoder class.  See wvencoder.h.
00006  */
00007 #include "wvencoder.h"
00008 
00009 /***** WvEncoder *****/
00010 
00011 WvEncoder::WvEncoder()
00012 {
00013     okay = true;
00014     finished = false;
00015 }
00016 
00017 
00018 WvEncoder::~WvEncoder()
00019 {
00020 }
00021 
00022 
00023 WvString WvEncoder::geterror() const
00024 {
00025     if (isok())
00026         return WvString::null;
00027     if (!!errstr)
00028         return errstr;
00029     WvString message = _geterror();
00030     if (!!message)
00031         return message;
00032     return "unknown encoder error";
00033 }
00034 
00035 
00036 bool WvEncoder::encode(WvBuf &inbuf, WvBuf &outbuf,
00037                        bool flush, bool _finish)
00038 {
00039     // deliberately not using isok() and isfinished() here
00040     bool success = okay && !finished && (inbuf.used() != 0 || flush);
00041     if (success)
00042         success = _encode(inbuf, outbuf, flush);
00043     if (_finish)
00044         success = finish(outbuf) && success;
00045     return success;
00046 }
00047 
00048 
00049 bool WvEncoder::finish(WvBuf &outbuf)
00050 {
00051     // deliberately not using isok() and isfinished() here
00052     bool success = okay && !finished;
00053     if (success)
00054         success = _finish(outbuf);
00055     setfinished();
00056     return success;
00057 }
00058 
00059 
00060 bool WvEncoder::reset()
00061 {
00062     // reset local state
00063     okay = true;
00064     finished = false;
00065     errstr = WvString::null;
00066     // attempt to reset the encoder
00067     bool success = _reset();
00068     if (!success)
00069     {
00070         if (okay)
00071             seterror("reset not supported by encoder");
00072     }
00073     return success;
00074 }
00075 
00076 
00077 bool WvEncoder::flushstrbuf(WvStringParm instr, WvBuf &outbuf,
00078     bool finish)
00079 {
00080     WvConstStringBuffer inbuf(instr);
00081     bool success = encode(inbuf, outbuf, true, finish);
00082     return success;
00083 }
00084 
00085 
00086 bool WvEncoder::flushstrstr(WvStringParm instr, WvString &outstr,
00087     bool finish)
00088 {
00089     WvConstStringBuffer inbuf(instr);
00090     WvDynBuf outbuf;
00091     bool success = encode(inbuf, outbuf, true, finish);
00092     outstr.append(outbuf.getstr());
00093     return success;
00094 }
00095 
00096 
00097 bool WvEncoder::encodebufstr(WvBuf &inbuf, WvString &outstr,
00098     bool flush, bool finish)
00099 {
00100     WvDynBuf outbuf;
00101     bool success = encode(inbuf, outbuf, flush, finish);
00102     outstr.append(outbuf.getstr());
00103     return success;
00104 }
00105 
00106 
00107 WvString WvEncoder::strflushstr(WvStringParm instr, bool finish)
00108 {
00109     WvString outstr;
00110     flushstrstr(instr, outstr, finish);
00111     return outstr;
00112 }
00113 
00114 
00115 WvString WvEncoder::strflushbuf(WvBuf &inbuf, bool finish)
00116 {
00117     WvString outstr;
00118     flushbufstr(inbuf, outstr, finish);
00119     return outstr;
00120 }
00121 
00122 
00123 bool WvEncoder::flushmembuf(const void *inmem, size_t inlen,
00124     WvBuf &outbuf, bool finish)
00125 {
00126     WvConstInPlaceBuf inbuf(inmem, inlen);
00127     bool success = encode(inbuf, outbuf, true, finish);
00128     return success;
00129 }
00130 
00131 
00132 bool WvEncoder::flushmemmem(const void *inmem, size_t inlen,
00133     void *outmem, size_t *outlen, bool finish)
00134 {
00135     WvConstInPlaceBuf inbuf(inmem, inlen);
00136     return encodebufmem(inbuf, outmem, outlen, true, finish);
00137 }
00138 
00139 
00140 bool WvEncoder::encodebufmem(WvBuf &inbuf,
00141     void *outmem, size_t *outlen, bool flush, bool finish)
00142 {
00143     WvInPlaceBuf outbuf(outmem, 0, *outlen);
00144     bool success = encode(inbuf, outbuf, true, finish);
00145     *outlen = outbuf.used();
00146     return success;
00147 }
00148 
00149 
00150 bool WvEncoder::flushstrmem(WvStringParm instr,
00151     void *outmem, size_t *outlen, bool finish)
00152 {
00153     WvConstStringBuffer inbuf(instr);
00154     return flushbufmem(inbuf, outmem, outlen, finish);
00155 }
00156 
00157 
00158 WvString WvEncoder::strflushmem(const void *inmem, size_t inlen, bool finish)
00159 {
00160     WvConstInPlaceBuf inbuf(inmem, inlen);
00161     return strflushbuf(inbuf, finish);
00162 }
00163 
00164 
00165 /***** WvNullEncoder *****/
00166 
00167 bool WvNullEncoder::_encode(WvBuf &in, WvBuf &out, bool flush)
00168 {
00169     in.zap();
00170     return true;
00171 }
00172 
00173 
00174 bool WvNullEncoder::_reset()
00175 {
00176     return true;
00177 }
00178 
00179 
00180 
00181 /***** WvPassthroughEncoder *****/
00182 
00183 WvPassthroughEncoder::WvPassthroughEncoder()
00184 {
00185     _reset();
00186 }
00187 
00188 
00189 bool WvPassthroughEncoder::_encode(WvBuf &in, WvBuf &out, bool flush)
00190 {
00191     total += in.used();
00192     out.merge(in);
00193     return true;
00194 }
00195 
00196 
00197 bool WvPassthroughEncoder::_reset()
00198 {
00199     total = 0;
00200     return true;
00201 }
00202 
00203 
00204 
00205 /***** WvEncoderChain *****/
00206 
00207 WvEncoderChain::WvEncoderChain()
00208 {
00209     last_run = NULL;
00210 }
00211 
00212 
00213 WvEncoderChain::~WvEncoderChain()
00214 {
00215 }
00216 
00217 
00218 bool WvEncoderChain::_isok() const
00219 {
00220     ChainElemList::Iter it(const_cast<ChainElemList&>(encoders));
00221     for (it.rewind(); it.next(); )
00222         if (!it->enc->isok())
00223             return false;
00224     return true;
00225 }
00226 
00227 
00228 bool WvEncoderChain::_isfinished() const
00229 {
00230     ChainElemList::Iter it(const_cast<ChainElemList&>(encoders));
00231     for (it.rewind(); it.next(); )
00232         if (it->enc->isfinished())
00233             return true;
00234     return false;
00235 }
00236 
00237 
00238 WvString WvEncoderChain::_geterror() const
00239 {
00240     ChainElemList::Iter it(const_cast<ChainElemList&>(encoders));
00241     for (it.rewind(); it.next(); )
00242     {
00243         WvString message = it->enc->geterror();
00244         if (!!message) return message;
00245     }
00246     return WvString::null;
00247 }
00248 
00249 
00250 // NOTE: In this function we deliberately ignore deep isok() and
00251 //       isfinished() results to allow addition/removal of
00252 //       individual broken encoders while still processing data
00253 //       through as much of the chain as possible.
00254 bool WvEncoderChain::do_encode(WvBuf &in, WvBuf &out, ChainElem *start_after,
00255                                bool flush, bool finish)
00256 {
00257     bool success = true;
00258     WvBuf *tmpin = &in;
00259     ChainElemList::Iter it(encoders);
00260     it.rewind();
00261     if (start_after) it.find(start_after);
00262     last_run = start_after;
00263     for (; it.cur() && it.next(); )
00264     {
00265         if (!it->enc->encode(*tmpin, it->out, flush))
00266             success = false;
00267         if (finish && !it->enc->finish(it->out))
00268             success = false;
00269         last_run = it.ptr();
00270         tmpin = &it->out;
00271     }
00272     out.merge(*tmpin);
00273     return success;
00274 }
00275 
00276 
00277 bool WvEncoderChain::_encode(WvBuf &in, WvBuf &out, bool flush)
00278 {
00279     return do_encode(in, out, NULL, flush, false);
00280 }
00281 
00282 
00283 bool WvEncoderChain::_finish(WvBuf &out)
00284 {
00285     WvNullBuf empty;
00286     return do_encode(empty, out, NULL, true, true);
00287 }
00288 
00289 
00290 bool WvEncoderChain::continue_encode(WvBuf &in, WvBuf &out)
00291 {
00292     //fprintf(stderr, "continue_encode(%d,%d,%p)\n",
00293     //      in.used(), out.used(), last_run);
00294     return do_encode(in, out, last_run, false, false);
00295 }
00296 
00297 
00298 bool WvEncoderChain::_reset()
00299 {
00300     bool success = true;
00301     ChainElemList::Iter it(encoders);
00302     for (it.rewind(); it.next(); )
00303     {
00304         it->out.zap();
00305         if (!it->enc->reset())
00306             success = false;
00307     }
00308     return success;
00309 }
00310 
00311 
00312 void WvEncoderChain::append(WvEncoder *enc, bool autofree)
00313 {
00314     encoders.append(new ChainElem(enc, autofree), true);
00315 }
00316 
00317 
00318 void WvEncoderChain::prepend(WvEncoder *enc, bool autofree)
00319 {
00320     encoders.prepend(new ChainElem(enc, autofree), true);
00321 }
00322 
00323 
00324 bool WvEncoderChain::get_autofree(WvEncoder *enc) const
00325 {
00326     ChainElemList::Iter i(encoders);
00327     for (i.rewind(); i.next(); )
00328         if (i->enc == enc && i.get_autofree())
00329             return true;
00330     return false;
00331 }
00332 
00333 
00334 void WvEncoderChain::set_autofree(WvEncoder *enc, bool autofree)
00335 {
00336     ChainElemList::Iter i(encoders);
00337     if (autofree)
00338     {
00339         // Ensure only the first matching encoder has autofree set
00340         bool first = true;
00341         for (i.rewind(); i.next(); )
00342         {
00343             if (i->enc == enc)
00344             {
00345                 if (first)
00346                 {
00347                     i.set_autofree(true);
00348                     first = false;
00349                 }
00350                 else
00351                     i.set_autofree(false);
00352             }
00353         }
00354     }
00355     else
00356     {
00357         // Clear autofree for all matching encoders
00358         for (i.rewind(); i.next(); )
00359             if (i->enc == enc)
00360                 i.set_autofree(false);
00361     }
00362 }
00363 
00364 
00365 void WvEncoderChain::unlink(WvEncoder *enc)
00366 {
00367     ChainElemList::Iter it(encoders);
00368     for (it.rewind(); it.next(); )
00369         if (it->enc == enc)
00370             it.xunlink();
00371 }
00372 
00373 
00374 void WvEncoderChain::zap()
00375 {
00376     encoders.zap();
00377 }
00378 
00379 
00380 size_t WvEncoderChain::buffered()
00381 {
00382     size_t used = 0;
00383     ChainElemList::Iter it(encoders);
00384     for (it.rewind(); it.next(); )
00385         used += it().out.used();
00386     return used;
00387 }
00388