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

encode.cc

///
// Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING
///
#include "encode.h"
#include <sstream>
#include <iomanip>

namespace PS {

  // EncodeFilterCascade

  std::string EncodeFilterCascade::decode_command() const {
    std::string cmd = "";
    for(FilterSequence::const_iterator i = sequence.begin(); 
      i != sequence.end();
      i++)
      cmd += (*i)->decode_command() + " ";
    return cmd;
  }
  
  void EncodeFilterCascade::begin(std::ostream *out_) {
    EncodeFilter::begin(out_);
    // Run begin only for the stream that is actually going to 
    // write to the stream:
    FilterSequence::iterator i = sequence.begin();
    if(sequence.size() > 0)
      (*i)->begin(out_);
    while(++i != sequence.end())
      (*i)->init();
  }

  void EncodeFilterCascade::write(const unsigned char *data, 
                          unsigned long count, 
                          bool flush)
  {
    FilterSequence::iterator i = sequence.end(), j;
    if(i == sequence.begin()) // no filters
      return; /// \todo should really write raw data to out
    j = --i; j--;
    if(i == sequence.begin()) { // only one filter
      (*i)->write(data, count, flush);
      return;
    }
    unsigned char *data1, *data2;
    unsigned long count1, count2;
    (*i)->filter(data, count, data1, count1, flush);
    while(j != sequence.begin()) {
      i--;
      (*i)->filter(data1, count1, data2, count2, flush);      
      delete[] data1;
      data1 = data2;  count1 = count2;
      j--;
    }
    (*j)->write(data1, count1, flush);
    delete[] data1;
  }

  // ASCIIHexEncodeFilter

  void ASCIIHexEncodeFilter::begin(std::ostream *out_) {
    SimpleEncodeFilter::begin(out_);
    (*out) << std::setw(2) << std::hex << std::setfill('0');
  }
  
  void ASCIIHexEncodeFilter::write(const unsigned char *data, 
                           unsigned long count, 
                           bool flush)
  {
    for(unsigned int i = 0; i < count; i++) {
      (*out) << std::setw(2) << std::hex << std::setfill('0') << int(data[i]);
      line_width += 2;
      if(line_width >= max_line_width) {
      (*out) << '\n';
      line_width = 0;
      }
    }
    if(flush) { // reset and write eod marker
      (*out) << std::setw(0) << std::dec << std::setfill(' ');
      if(write_eod)
      (*out) << ">";
      (*out) << std::endl;
    }
  }

  void ASCIIHexEncodeFilter::filter(const unsigned char *data_in, 
                            unsigned long count_in,
                            unsigned char *&data_out, 
                            unsigned long &count_out,
                            bool flush)
  {
    count_out = 2 * count_in;
    data_out = new unsigned char[count_out];
    for(unsigned int i=0; i<count_in; i++) {
      std::ostringstream tmp;
      tmp << std::setw(2) << std::hex << std::setfill('0') 
        << std::setw(2) << int(data_in[i * 2]);
      data_out[i * 2] = tmp.str()[0];
      data_out[i * 2 + 1] = tmp.str()[1];
      }
  }

  // ASCII85EncodeFilter

  void ASCII85EncodeFilter::init() {
    SimpleEncodeFilter::init();
    fill = 0;
  }

  int ASCII85EncodeFilter::write_chunk(const unsigned char *chunk, 
                               bool apply_z_special_case,
                               int output_num)
  {
    if(apply_z_special_case 
       && (chunk[0] | chunk[1] | chunk[2] | chunk[3]) == 0) {
      (*out) << "z";
      line_width++;
      if(line_width >= max_line_width) {
      (*out) << '\n';
      line_width = 0;
      }
      return 1;
    }

    unsigned char out_chunk[5];
    // Conversion from a four-digit base 256 number 
    // to a five-digit base 85 number.
    // number should be at least a 32 bit number
    unsigned long number =
      (((unsigned long) chunk[0]) << 24)
      + (((unsigned long) chunk[1]) << 16)
      + (((unsigned long) chunk[2]) << 8)
      + (((unsigned long) chunk[3]));
      //      chunk[0] * 16777216 // 256^3
      //      + chunk[1] * 65536  // 256^2
      //      + chunk[2] * 256    // 256^1
      //      + chunk[3];         // 256^0
    

    out_chunk[0] = number / 52200625; // 85^4
                  number %= 52200625;
    out_chunk[1] = number / 614125;   // 85^3
                  number %= 614125;
    out_chunk[2] = number / 7225;     // 85^2
                  number %= 7225;
    out_chunk[3] = number / 85;       // 85^1

    out_chunk[4] = number %= 85;

    for(int i = 0; i < 5 && i < output_num; i++) {
      out->put(out_chunk[i] + 33); // 33 is the ASCII code for '!'
      line_width++;
      if(line_width >= max_line_width) {
      (*out) << '\n';
      line_width = 0;
      }
    }
    return 5;
  }
  
  void ASCII85EncodeFilter::write(const unsigned char *data, 
                          unsigned long count, 
                          bool flush)
  {
    unsigned long offset = 0;

    // fill buffer if necessary
    if(fill > 0) {
      while(fill < 4 && offset < count)
      buffer[fill++] = data[offset++];
      if(fill == 4) {
      write_chunk(buffer);
      fill = 0;
      }
    }

    // encode
    while(offset + 4 <= count) { /// \todo watch out for integer overflow
      write_chunk(&data[offset]);
      offset += 4;
    }

    // fill buffer if necessary (again)
    while(offset < count)
      buffer[fill++] = data[offset++];

    // end of data?
    if(flush) {
      // pad buffer with zero
      if(fill > 0) {
      int count = 5;
      if(fill < 4)
        count = fill + 1;
      while(fill < 4)
        buffer[fill++] = 0;
      write_chunk(buffer, false, count); // no z special case
      }

      if(write_eod)
      (*out) << "~>"; // eod marker
      (*out) << std::endl; 
    }
  }

  void ASCII85EncodeFilter::filter(const unsigned char *data_in, 
                           unsigned long count_in,
                           unsigned char *&data_out, 
                           unsigned long &count_out,
                           bool flush)
  {
    /// \todo ...
    data_out = new unsigned char[1];
    count_out = 1;
  }

  // RunLengthEncodeFilter

  void RunLengthEncodeFilter::init() {
    SimpleEncodeFilter::init();
    fill = 0;
    bytes.clear();
  }
  
  void RunLengthEncodeFilter::write(const unsigned char *data, 
                            unsigned long count, 
                            bool flush)
  {
    unsigned long count_out;
    unsigned char *data_out;
    filter(data, count, data_out, count_out, flush);
    out->write(reinterpret_cast<const char*>(data_out), count_out);
    delete[] data_out;
  }

  void RunLengthEncodeFilter::flush_buffer() {
    if(fill > 0) {
      if(fill > 1 && buffer[0] == buffer[1]) { // similar
      bytes.push_back(257 - fill);  // the next <fill> bytes are the same
      bytes.push_back(buffer[0]); // as this
      } else { // dissimilar
      bytes.push_back(fill - 1);    // the next <fill> bytes are different
      for(int i = 0; i < fill; i++)
        bytes.push_back(buffer[i]);
      }
    }
    fill = 0;
  }

  void RunLengthEncodeFilter::filter(const unsigned char *data_in, 
                             unsigned long count_in,
                             unsigned char *&data_out, 
                             unsigned long &count_out,
                             bool flush)
  {
    unsigned long offset = 0;
    while(offset < count_in) {
      if(fill > 1) {
      if(data_in[offset] == buffer[fill - 1]
         && data_in[offset] != buffer[fill - 2]) { // two similar bytes!
        fill--; // pop the last byte
        flush_buffer();
        buffer[fill++] = data_in[offset]; // and push it again
      } else if(data_in[offset] != buffer[fill - 1] 
              && buffer[fill - 2] == buffer[fill - 1]) {
        // a dissimilar byte!
        flush_buffer();
      }
      }
      buffer[fill++] = data_in[offset++];
      if(fill == 128) // buffer is full
      flush_buffer();
    }

    if(flush) {
      flush_buffer();
      if(write_eod)
      bytes.push_back(128U); // eod marker
    }
    
    // copy from vector to bytes
    count_out = bytes.size();
    data_out = new unsigned char[count_out];
    unsigned long j = 0;
    for(Bytes::iterator i = bytes.begin();
      i != bytes.end(); i++) {
      data_out[j++] = *i;
    }
    bytes.clear();
  }

}

Generated by  Doxygen 1.6.0   Back to index