@@ -22,21 +22,19 @@ limitations under the License.
2222#include " ../entropy/EntropyEncoderFactory.hpp"
2323
2424
25- #ifdef _MSC_VER
25+ // Note stat64/lstat64 are deprecated on MacOS/Linux
26+ // Use _FILE_OFFSET_BITS and stat/lstat instead
27+
28+ #ifdef _WIN32
2629 #define FSTAT _fstat64
2730 #define STAT _stat64
2831#else
29- #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__) || defined(__MINGW32__)
30- #define FSTAT fstat
31- #define STAT stat
32- #else
33- #define FSTAT fstat64
34- #define STAT stat64
35- #endif
32+ #define _FILE_OFFSET_BITS 64
33+ #define FSTAT fstat
34+ #define STAT stat
3635#endif
3736
3837
39-
4038#ifdef _MSC_VER
4139 #include < io.h>
4240 #define FILENO (f ) _fileno(f)
@@ -52,30 +50,94 @@ limitations under the License.
5250using namespace std ;
5351using namespace kanzi ;
5452
53+
54+ struct cContext {
55+ kanzi::CompressedOutputStream* pCos;
56+ unsigned int blockSize;
57+ void * fos;
58+ };
59+
60+
5561namespace kanzi {
5662 // Utility classes to map C FILEs to C++ streams
57- class ofstreambuf : public streambuf
58- {
59- public:
60- ofstreambuf (int fd) : _fd(fd) { }
63+ class ofstreambuf : public streambuf
64+ {
65+ public:
66+ ofstreambuf (int fd) : _fd(fd), _buffer(65536 ) {
67+ // Initialize put pointers to the beginning of the buffer
68+ setp (_buffer.data (), _buffer.data () + _buffer.size ());
69+ }
6170
62- private:
63- int _fd;
71+ virtual ~ofstreambuf () {
72+ sync ();
73+ }
6474
75+ protected:
76+ // Called when the buffer is full
6577 virtual int_type overflow (int_type c) {
66- if (c == EOF)
67- return EOF;
78+ if (flush () == EOF) return EOF;
6879
69- char d = char (c);
70- return (WRITE (_fd, &d, 1 ) == 1 ) ? c : EOF;
80+ if (c != EOF) {
81+ *pptr () = char (c);
82+ pbump (1 );
83+ }
84+ return c;
7185 }
7286
73- virtual streamsize xsputn (const char * s, streamsize sz) {
74- return WRITE (_fd, s, sz);
87+ // Called for explicit sync/flush
88+ virtual int sync () {
89+ return (flush () == EOF) ? -1 : 0 ;
7590 }
7691
77- int sync () {
78- // No internal buffer — nothing to flush. Indicate success
92+ // Optimized block write
93+ virtual streamsize xsputn (const char * s, streamsize n) {
94+ streamsize remaining = n;
95+ const char * src = s;
96+
97+ while (remaining > 0 ) {
98+ streamsize avail = epptr () - pptr ();
99+
100+ if (avail >= remaining) {
101+ // Fits in current buffer
102+ memcpy (pptr (), src, remaining);
103+ pbump (int (remaining));
104+ return n;
105+ }
106+
107+ if (avail > 0 ) {
108+ // Fill the rest of the buffer
109+ memcpy (pptr (), src, avail);
110+ pbump (int (avail));
111+ src += avail;
112+ remaining -= avail;
113+ }
114+
115+ // Flush full buffer
116+ if (flush () == EOF) return n - remaining;
117+
118+ // If the remaining chunk is large, write directly to FD to avoid double copy
119+ if (remaining >= streamsize (_buffer.size ())) {
120+ if (WRITE (_fd, src, remaining) != remaining) {
121+ return n - remaining; // Error
122+ }
123+
124+ remaining = 0 ;
125+ }
126+ }
127+
128+ return n;
129+ }
130+
131+ private:
132+ int _fd;
133+ std::vector<char > _buffer;
134+
135+ int flush () {
136+ ptrdiff_t n = pptr () - pbase ();
137+ if (n > 0 ) {
138+ if (WRITE (_fd, pbase (), n) != n) return EOF;
139+ pbump (-int (n)); // Reset pbump by subtracting the amount written
140+ }
79141 return 0 ;
80142 }
81143 };
@@ -94,7 +156,7 @@ namespace kanzi {
94156
95157
96158// Create internal cContext and CompressedOutputStream
97- int CDECL initCompressor (struct cData * pData, FILE* dst, struct cContext ** pCtx)
159+ ARCHIVER_API int CDECL initCompressor (struct cData * pData, FILE* dst, struct cContext ** pCtx)
98160{
99161 if ((pData == nullptr ) || (pCtx == nullptr ) || (dst == nullptr ))
100162 return Error::ERR_INVALID_PARAM;
@@ -112,19 +174,24 @@ int CDECL initCompressor(struct cData* pData, FILE* dst, struct cContext** pCtx)
112174 string transform = TransformFactory<byte>::getName (TransformFactory<byte>::getType (pData->transform ));
113175 string entropy = EntropyEncoderFactory::getName (EntropyEncoderFactory::getType (pData->entropy ));
114176
115- if ((transform.length () >= 63 ) || (entropy.length () >= 15 ))
177+ if ((transform.length () >= sizeof (pData->transform )) ||
178+ (entropy.length () >= sizeof (pData->entropy ))) {
116179 return Error::ERR_INVALID_PARAM;
180+ }
181+
182+ memset (pData->transform , 0 , sizeof (pData->transform ));
183+ strncpy (pData->transform , transform.c_str (), sizeof (pData->transform ) - 1 );
184+ memset (pData->entropy , 0 , sizeof (pData->entropy ));
185+ strncpy (pData->entropy , entropy.c_str (), sizeof (pData->entropy ) - 1 );
117186
118- snprintf (pData->transform , sizeof (pData->transform ), " %s" , transform.c_str ());
119- snprintf (pData->entropy , sizeof (pData->entropy ), " %s" , entropy.c_str ());
120187 pData->blockSize = (pData->blockSize + 15 ) & -16 ;
121188
122189 *pCtx = nullptr ;
123- uint64 fileSize = 0 ;
190+ size_t fileSize = 0 ;
124191 struct STAT sbuf;
125192
126193 if (FSTAT (fd, &sbuf) == 0 ) {
127- fileSize = uint64 ( sbuf.st_size ) ;
194+ fileSize = sbuf.st_size ;
128195 }
129196
130197 // Create compression stream and update context
@@ -134,7 +201,7 @@ int CDECL initCompressor(struct cData* pData, FILE* dst, struct cContext** pCtx)
134201 cctx->pCos = new CompressedOutputStream (*fos, pData->jobs ,
135202 pData->entropy , pData->transform ,
136203 pData->blockSize , pData->checksum ,
137- fileSize,
204+ uint64 ( fileSize) ,
138205#ifdef CONCURRENCY_ENABLED
139206 nullptr ,
140207#endif
@@ -157,72 +224,71 @@ int CDECL initCompressor(struct cData* pData, FILE* dst, struct cContext** pCtx)
157224 return 0 ;
158225}
159226
160- int CDECL compress (struct cContext * pCtx, const unsigned char * src, int * inSize, int * outSize)
227+ ARCHIVER_API int CDECL compress (struct cContext * pCtx, const unsigned char * src, size_t inSize, size_t * outSize)
161228{
162- if ((pCtx == nullptr ) || (inSize == nullptr ) || (outSize == nullptr ) ||
163- (*inSize < 0 ) || (*inSize > int (pCtx->blockSize ))) {
229+ if ((pCtx == nullptr ) || (outSize == nullptr )) {
230+ return Error::ERR_INVALID_PARAM;
231+ }
232+
233+ if (inSize > size_t (pCtx->blockSize )) {
164234 return Error::ERR_INVALID_PARAM;
165235 }
166236
167237 *outSize = 0 ;
168238 int res = 0 ;
169- CompressedOutputStream* pCos = static_cast <CompressedOutputStream*>( pCtx->pCos ) ;
239+ CompressedOutputStream* pCos = pCtx->pCos ;
170240
171241 if (pCos == nullptr ) {
172- *outSize = 0 ;
173242 return Error::ERR_INVALID_PARAM;
174243 }
175244
176245 try {
177246 const uint64 w = pCos->getWritten ();
178- pCos->write ((const char *)src, streamsize (* inSize));
247+ pCos->write ((const char *)src, streamsize (inSize));
179248 res = pCos->good () ? 0 : Error::ERR_WRITE_FILE;
180249 *outSize = int (pCos->getWritten () - w);
181250 }
182251 catch (const exception&) {
183- *outSize = 0 ;
184252 return Error::ERR_UNKNOWN;
185253 }
186254
187255 return res;
188256}
189257
190258// Cleanup allocated internal data structures
191- int CDECL disposeCompressor (struct cContext * pCtx, int * outSize)
259+ ARCHIVER_API int CDECL disposeCompressor (struct cContext ** ppCtx, size_t * outSize)
192260{
193261 *outSize = 0 ;
194262
195- if (pCtx == nullptr )
263+ if ((ppCtx == nullptr ) || (*ppCtx == nullptr ) )
196264 return Error::ERR_INVALID_PARAM;
197265
198- CompressedOutputStream* pCos = (CompressedOutputStream*)pCtx->pCos ;
266+ cContext* pCtx = *ppCtx;
267+ CompressedOutputStream* pCos = pCtx->pCos ;
199268
200269 try {
201270 if (pCos != nullptr ) {
202271 const uint64 w = pCos->getWritten ();
203272 pCos->close ();
204- *outSize = int (pCos->getWritten () - w);
205- }
206- }
207- catch (const exception&) {
208- return Error::ERR_UNKNOWN;
209- }
210273
211- try {
212- if (pCos != nullptr )
274+ if (outSize)
275+ *outSize = int (pCos->getWritten () - w);
276+
213277 delete pCos;
278+ }
214279
215280 if (pCtx->fos != nullptr )
216- delete ( FileOutputStream*) pCtx->fos ;
281+ delete static_cast < FileOutputStream*>( pCtx->fos ) ;
217282
218283 pCtx->fos = nullptr ;
219284 delete pCtx;
220285 }
221286 catch (const exception&) {
222287 if (pCtx->fos != nullptr )
223- delete ( FileOutputStream*) pCtx->fos ;
288+ delete static_cast < FileOutputStream*>( pCtx->fos ) ;
224289
225290 delete pCtx;
291+ *ppCtx = 0 ;
226292 return Error::ERR_UNKNOWN;
227293 }
228294
0 commit comments