Logo Search packages:      
Sourcecode: papaya version File versions  Download package

FilterHandler.cpp

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <glib.h>

#ifdef ZLIB
#include "CompressFilter.h"
#endif // ZLIB

#include "TeloptFilter.h"
#include "PromptFilter.h"
#include "Prefs.h"
#include "Connection.h"
#include "FilterHandler.h"

#include <algorithm>

#undef FILTER_DEBUG

FilterHandler::FilterHandler()
{
}

FilterHandler::~FilterHandler()
{
    for (FilterList::iterator i = filters.begin(); i != filters.end(); ++i)
      delete (*i);
}

char * FilterHandler::queryFilter(char * name, char * question)
{
    for (FilterList::iterator i = filters.begin(); i != filters.end(); ++i) {
      if (!strcmp((*i)->name, name)) {
          return (*i)->query(question);
      }
    }
    
    return "error";
}

#ifdef FILTER_DEBUG
void dump_buffer(char *desc, Buffer &buf)
{
    int len = buf.getLength();
    char *text = buf.getText();
    printf("%s: (%d) =\n", desc, len);
    if (!len) return;
    printf("  ");
    
    int col = 3;

    for (int i = 0; i < len; ++i)
    {
      if (col > 76) {
          printf("\n  ");
          col = 3;
      }

      unsigned char ch = (unsigned char)text[i];
      if (ch == '\n') {
          printf("\\n");
          col += 2;
      }
      else if (ch == '\r') {
          printf("\\r");
          col += 2;
      }
      else if (ch < 32 || ch > 127) {
          printf("\\x%02X", ch);
          col += 4;
      } else if (ch == '\\') {
          printf("\\\\");
          col += 2;
      } else {
          printf("%c", ch);
          ++col;
      }
    }

    printf("\n");
}
#endif

void FilterHandler::processFilters(Buffer &in, Buffer &out)
{
    // Special case: 0 filters
    if (filters.empty())
    {
      in.transfer_to(output);
      output.transfer_to(out);

      return;
    }

    // Fill first input buffer
    in.transfer_to(filters.front()->input);

    // Do all the filtering.
    processPending(NULL);

#ifdef FILTER_DEBUG
    dump_buffer("processFilters: final output", output);
#endif

    // Final transfer.
    output.transfer_to(out);
}

// Controls ordering of filters
static int FilterCmp(Filter *f1, Filter *f2)
{
    if (!f1 || !f2)       // handle null pointers cleanly
      return (f1 < f2);

    if (f1->order() < f2->order())
      return 1;
    if (f1->order() > f2->order())
      return 0;

    // orders are equal, order on pointer value (arbitary)
    return (f1 < f2);
}

void FilterHandler::processPending(Filter *start)
{
    FilterList::iterator f;
    if (!start)
        f = filters.begin();
    else
            f = std::lower_bound(filters.begin(), filters.end(), start, FilterCmp);

    for (; f != filters.end(); ++f)
    {
      FilterList::iterator next = f; ++next;
      bool ok;

#ifdef FILTER_DEBUG
      printf("processPending: %s: ", (*f)->name);
        dump_buffer("input", (*f)->input);
#endif      
      // Output of this filter goes to next input, or output buffer if this
      // is the last one.
      if (next == filters.end())
      {
          ok = (*f)->process(output);
#ifdef FILTER_DEBUG
          if (ok) {
            printf("processPending: %s: ", (*f)->name);
            dump_buffer("residual input", (*f)->input);
          } else {
            printf("processPending: underlying filter maybe deleted\n");
          }
#endif      
      }
      else
      {
          ok = (*f)->process( (*next)->input );
#ifdef FILTER_DEBUG
          if (ok) {
            printf("processPending: %s: ", (*f)->name);
            dump_buffer("residual input", (*f)->input);
          } else {
            printf("processPending: underlying filter maybe deleted\n");
          }
#endif      
      }

      if (!ok)
          return; // list of filters changed
    }
}

void FilterHandler::addFilter(Filter * f)
{
#ifdef FILTER_DEBUG
    printf("FilterHandler::addFilter(%s)\n", f->name);
#endif
    // note: it's assumed that the caller has handled priming f->input as
    // necessary.

    FilterList::iterator i = std::lower_bound(filters.begin(),
                               filters.end(),
                               f,
                               FilterCmp);
    filters.insert(i, f);

    if (f->input.getLength() > 0)
      processPending(f);
}

void FilterHandler::removeFilter(Filter *f)
{
#ifdef FILTER_DEBUG
    printf("FilterHandler::removeFilter(%s)\n", f->name);
#endif
    FilterList::iterator i = std::lower_bound(filters.begin(), filters.end(), f,
                               FilterCmp);
    if (i == filters.end() || (*i) != f)
      return;

    FilterList::iterator next = i; ++next;

    // Remove the filter from the chain
    filters.erase(i);

    // Shift all pending input to the next filter in the chain (or to our
    // output buffer if there is no next filter). This also triggers
    // possible reprocessing.
    if (next == filters.end())
      f->input.transfer_to(output);
    else
    {
      f->input.transfer_to( (*next)->input );
      processPending(*next);
    }

    // Clean up.
    delete f;
}

Filter* FilterHandler::findFilter(char *name)
{
    for (FilterList::const_iterator i = filters.begin();
       i != filters.end();
       ++i)
      if (!strcmp(name, (*i)->name))
          return (*i);

    return NULL;
}

Generated by  Doxygen 1.6.0   Back to index