1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 
8 /* Code inspired by cairo and adapted for Scribus by Jean Ghali */
9 
10 #include "scstreamfilter_flate.h"
11 
12 #include <cstdlib>
13 #include <zlib.h>
14 
15 #include <QDataStream>
16 
17 #define BUFFER_SIZE 16384
18 struct  ScFlateEncodeFilterData
19 {
20     z_stream      zlib_stream;
21     unsigned char input_buffer [BUFFER_SIZE];
22     unsigned char output_buffer[BUFFER_SIZE];
23 };
24 
ScFlateEncodeFilter(QDataStream * stream)25 ScFlateEncodeFilter::ScFlateEncodeFilter(QDataStream* stream)
26 				   : ScStreamFilter(stream)
27 {
28 	m_filterData   = nullptr;
29 	m_openedFilter = false;
30 }
31 
ScFlateEncodeFilter(ScStreamFilter * filter)32 ScFlateEncodeFilter::ScFlateEncodeFilter(ScStreamFilter* filter)
33 				   : ScStreamFilter(filter)
34 {
35 	m_filterData   = nullptr;
36 	m_openedFilter = false;
37 }
38 
~ScFlateEncodeFilter()39 ScFlateEncodeFilter::~ScFlateEncodeFilter()
40 {
41 	if (m_filterData && m_openedFilter)
42 		closeFilter();
43 	freeData();
44 }
45 
freeData()46 void ScFlateEncodeFilter::freeData()
47 {
48 	if (m_filterData)
49 		free (m_filterData);
50 	m_filterData = nullptr;
51 }
52 
openFilter()53 bool ScFlateEncodeFilter::openFilter()
54 {
55 	freeData();
56 
57 	m_filterData = (ScFlateEncodeFilterData*) malloc(sizeof(ScFlateEncodeFilterData));
58 	if (m_filterData == nullptr)
59 		return false;
60 
61 	m_filterData->zlib_stream.zalloc = Z_NULL;
62 	m_filterData->zlib_stream.zfree  = Z_NULL;
63 	m_filterData->zlib_stream.opaque = Z_NULL;
64 
65 	if (deflateInit (&m_filterData->zlib_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
66 	{
67 		freeData();
68 		return false;
69 	}
70 
71 	m_filterData->zlib_stream.next_in   = m_filterData->input_buffer;
72     m_filterData->zlib_stream.avail_in  = 0;
73     m_filterData->zlib_stream.next_out  = m_filterData->output_buffer;
74     m_filterData->zlib_stream.avail_out = BUFFER_SIZE;
75 
76 	m_openedFilter = ScStreamFilter::openFilter();
77 	return m_openedFilter;
78 }
closeFilter()79 bool ScFlateEncodeFilter::closeFilter()
80 {
81 	bool closeSucceed = writeDeflate(true);
82     deflateEnd (&m_filterData->zlib_stream);
83 	m_openedFilter = false;
84 	closeSucceed  &= ScStreamFilter::closeFilter();
85 	return closeSucceed;
86 }
87 
writeData(const char * data,int dataLen)88 bool ScFlateEncodeFilter::writeData(const char* data, int dataLen)
89 {
90 	bool deflateSuccess = true;
91     unsigned int count;
92     const unsigned char *p = (const unsigned char *) data;
93 
94 	if (!m_filterData)
95 		return false;
96 
97     while (dataLen) {
98         count = dataLen;
99         if (count > BUFFER_SIZE - m_filterData->zlib_stream.avail_in)
100             count = BUFFER_SIZE - m_filterData->zlib_stream.avail_in;
101         memcpy (m_filterData->input_buffer + m_filterData->zlib_stream.avail_in, p, count);
102         p += count;
103         m_filterData->zlib_stream.avail_in += count;
104         dataLen -= count;
105 
106         if (m_filterData->zlib_stream.avail_in == BUFFER_SIZE)
107             deflateSuccess &= writeDeflate(false);
108     }
109 
110 	return deflateSuccess;
111 }
112 
writeDeflate(bool flush)113 bool ScFlateEncodeFilter::writeDeflate(bool flush)
114 {
115 	int  ret;
116 	bool deflateSuccess = true;
117     bool finished;
118 
119 	do {
120 		ret = deflate (&m_filterData->zlib_stream, flush ? Z_FINISH : Z_NO_FLUSH);
121         if (flush || m_filterData->zlib_stream.avail_out == 0)
122         {
123 			deflateSuccess &= writeDataInternal((const char*) m_filterData->output_buffer, BUFFER_SIZE - m_filterData->zlib_stream.avail_out);
124             m_filterData->zlib_stream.next_out  = m_filterData->output_buffer;
125             m_filterData->zlib_stream.avail_out = BUFFER_SIZE;
126         }
127 
128         finished = true;
129         if (m_filterData->zlib_stream.avail_in != 0)
130             finished = false;
131         if (flush && ret != Z_STREAM_END)
132             finished = false;
133 
134     } while (!finished);
135 
136     m_filterData->zlib_stream.next_in = m_filterData->input_buffer;
137 	return deflateSuccess;
138 }
139