/// // Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING /// #include "encode.h" #include #include 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= 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 = 0; for(int i = 0; i < 4; i++) { number <<= 8; number |= chunk[i]; } 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(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 bytes are the same bytes.push_back(buffer[0]); // as this } else { // dissimilar bytes.push_back(fill - 1); // the next 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(); } }