]> Creatis software - clitk.git/blob - common/clitkXdrImageIOWriter.cxx
added the new headers
[clitk.git] / common / clitkXdrImageIOWriter.cxx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to: 
5   - University of LYON              http://www.universite-lyon.fr/
6   - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
7   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
8
9   This software is distributed WITHOUT ANY WARRANTY; without even
10   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11   PURPOSE.  See the copyright notices for more information.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ======================================================================-====*/
18 /**
19  * @file   clitkXdrImageIO.cxx
20  * @author Simon Rit <simon.rit@gmail.com>
21  * @date   Sun Jun  1 22:12:20 2008
22  *
23  * @brief
24  *
25  *
26  */
27
28 #include "clitkXdrImageIO.h"
29 #include "clitkCommon.h"
30
31 #include <sys/stat.h>
32
33 //From mbfield.h
34 #ifndef unix
35 //#define _read  readfix
36 #endif
37 #define AVSINT ptrdiff_t
38 #define AVS_ERROR
39 #define AVS_OK
40
41 //From portdefs.h
42 #ifdef unix
43 #define O_BINARY 0
44 #define setmode(a,b) 0
45 #endif
46
47 #ifndef __LARGE__
48 #  if defined(__GNUC__) || defined(unix)
49      typedef long long Q_INT64;
50      typedef unsigned long long Q_UINT64;
51 #    define Q_INT64_CONST(x) (x##ll)
52 #    define Q_UINT64_CONST(x) (x##llu) /* gcc also allows ull */
53      /* When using MINGW with MS(V)CRT DLL, use MS format modifier. */
54 #    ifdef __MSVCRT__
55 #      define Q_INT64_FORMAT "I64"
56 #    else
57 #      define Q_INT64_FORMAT "L"
58 #    endif
59 #  elif defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER)
60      typedef __int64 Q_INT64;
61      typedef unsigned __int64 Q_UINT64;
62 #    define Q_INT64_CONST(x) (x##i64)
63 #    define Q_UINT64_CONST(x) (x##ui64) /* i64u is not allowed! */
64 #    ifdef _MSC_VER
65 #      define Q_INT64_FORMAT "I64"
66 #    else
67 #      define Q_INT64_FORMAT "L"
68 #    endif
69 #  else
70 #    error No 64 bit integers known for this compiler, edit portdefs.h.
71 #  endif
72 #endif
73
74 bool clitk::XdrImageIO::CanWriteFile(const char* FileNameToWrite)
75 { std::string filename(FileNameToWrite);
76   std::string filenameext = GetExtension(filename);
77   if (filenameext != std::string("xdr")) return false;
78   return true;
79 }
80
81 void clitk::XdrImageIO::Write(const void* buffer)
82 { char *s = const_cast<char*>("");
83   WriteImage( m_FileName.c_str(), s, s, 0, -1, 0, 2, 0, 0, 0, 0, buffer);
84 }
85
86 // Based on a true story by the Nederlands Kanker Instituut (AVS_WXDR.CPP from the 20091216)
87
88 /************************************************************************/
89 /*                             INCLUDE FILES                            */
90 /************************************************************************/
91
92 #include <string.h>
93 #include <stdio.h>
94 #include <math.h>
95 #include <stdlib.h>
96 #include <limits.h>
97 #ifndef unix
98 #include <io.h>
99 #endif
100 #include <fcntl.h>
101 #include <errno.h>
102
103 #include <algorithm>
104
105 #ifdef WIN32
106 // don't use min() and max() macros indirectly defined by windows.h, 
107 // but use portable std::min() and std:max() instead
108 #ifndef NOMINMAX
109 #define NOMINMAX
110 #endif
111 #include <windows.h>
112 #endif
113
114 /************************************************************************/
115 /*                    DEFINES, ENUMERATED TYPES AND CONSTANTS           */
116 /************************************************************************/
117
118 #pragma pack (1)
119
120 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
121 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
122 // The type of structure is indicated as follows:
123 //
124 // iOrgSize==0: NKI_MODE2_64BITS
125 // otherwise  : NKI_MODE2
126 //
127 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
128
129 typedef struct
130 {
131   unsigned int iOrgSize;          /* in pixels (i.e. shorts) */
132   unsigned int iMode;             /* 1, 2, 3 or 4 */
133   unsigned int iCompressedSize;   /* in bytes, excluding header */
134   unsigned int iOrgCRC;           /* CRC of the data (no coords etc) */
135   unsigned int iCompressedCRC;    /* CRC of the compressed data, excluding this header */
136 } NKI_MODE2;
137
138 typedef struct
139 {
140   unsigned int iOrgSize;          /* in pixels (i.e. shorts) */
141   unsigned int iMode;             /* 1, 2, 3 or 4 */
142   unsigned int iCompressedSize;   /* in bytes, excluding header */
143   unsigned int iOrgCRC;           /* CRC of the data (no coords etc) */
144   unsigned int iCompressedCRC;    /* CRC of the compressed data, excluding this header */
145   unsigned int iPad;              /* unused */
146   Q_UINT64     i64OrgSize;        /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */ 
147   Q_UINT64     i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */ 
148   Q_UINT64     i64Future1;
149   Q_UINT64     i64Future2;
150 } NKI_MODE2_64BITS;
151
152 #pragma pack ()
153
154 // Changed next to static function in stead of macro so it can
155 // have a return value to check in the calling function.
156 // It could be made inline as well, but there is no real time
157 // punishment from the extra layer of function calls.
158
159 // note: some compilers do not like comments ending in a backslash.
160 // so use macro functions to exclude.
161
162
163 /************************************************************************/
164 /*                             GLOBAL VARIABLES                         */
165 /************************************************************************/
166
167 static const unsigned long CRC32_table[256] = {
168       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
169       0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
170       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
171       0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
172       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
173       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
174       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
175       0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
176       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
177       0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
178       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
179       0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
180       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
181       0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
182       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
183       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
184       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
185       0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
186       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
187       0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
188       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
189       0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
190       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
191       0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
192       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
193       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
194       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
195       0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
196       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
197       0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
198       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
199       0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
200       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
201       0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
202       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
203       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
204       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
205       0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
206       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
207       0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
208       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
209       0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
210       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
211 };
212
213 /************************************************************************/
214 /*                             MODULE FUNCTIONS                         */
215 /************************************************************************/
216
217 #ifdef __WATCOMC__
218 _WCRTLINK
219 #endif
220 int writefix(int file, const void *buf, unsigned int count)
221 { int j, k, total=0;
222
223   for (unsigned i=0; i<count; i+=16384)
224   { j = count - i;
225     if (j>16384) j=16384;
226
227     k=write(file, (char *)buf+i, j);
228     if (k < 0) return k;
229
230     total += k;
231
232     if (k != j) break;
233   }
234
235   return total;
236 }
237
238
239 /*
240   Version of write() that takes special action in case of
241   standard output.  Based on commented out macro above.
242   This function overloads the <cstdio> (or stdio.h for old style C++)
243   write() function.
244 */
245
246 // Like the original macro, we do /not/ want writefix from mbfield.c.
247 #ifdef write
248 #undef write
249 #endif
250 static int wxdr_write(int handle, const void * buf, unsigned len)
251 {
252   // if (handle == 1) // stdout
253   if (handle == fileno(stdout))
254   {
255 #ifdef WIN32
256     // Behave as C standard library write(): return number of bytes
257     // written or -1 and errno set on error.
258     fflush(stdout);
259     DWORD dwBytesWritten;
260     if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
261                    &dwBytesWritten, NULL))
262     {
263       // There is no simple 1-to-1 mapping between GetLastError()
264       // values that WriteFile() can return (quite a lot) and the two
265       // errno values that write() can return.  So return EACCES in
266       // almost all cases.
267       switch (GetLastError())
268       { case ERROR_INVALID_HANDLE:
269           errno = EBADF ; break;
270         default:
271           errno = EACCES; break;
272       }
273       return -1;
274     }
275     else
276       return (int)dwBytesWritten; // May still be < len!
277       // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
278       // WriteFile() may write UINT_MAX bytes at once.  But since
279       // int(UINT_MAX) == -1 this will pose an actual problem in the
280       // (far?) future.
281 #else // !WIN32
282     //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
283     const int iBytesWritten = write(handle, buf, len);
284     const int saveerrno = errno; // setmode() may change errno.
285     //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
286     errno = saveerrno;
287     return iBytesWritten;
288 #endif // !WIN32
289   }
290   else
291     return write(handle, buf, len);
292 }
293
294 /*
295   Checked write().
296   Behaves like win32 WriteFile() and returns a Boolean to indicate
297   success or failure, where failure almost invariably means disc full.
298
299   !!! SIDE EFFECT !!!
300
301   In case of failure, this function issues an AVS error message
302   and closes the file (if handle != 1).  It is up to the calling
303   function to return the AVS_ERROR state and before that do things
304   like close other files, free memory etc.  This way, there is less
305   chance of erroneously duplicated code, like in:
306     written = write(f, temp, strlen(temp));
307     if (written == -1 || written != strlen(temp))
308     { AVSerror(...);
309       if (f != fileno(stdout)) close(f);
310       return AVS_ERROR;
311     }
312     written = write(f, buf, buflength)
313     if (written == -1 || written != strlen(temp)) {
314       // oops, wrong length copy'n'pasted
315
316   If more elaborate error handling is needed then the calling
317   functuon should use the (overloaded) write() and act on its return
318   value (and the value of errno) accordingly.
319
320   It does /not/ close stdout.
321
322   !!! SIDE EFFECT !!!
323
324   Note that checked_write() takes a size_t for len, whereas write() takes
325   an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer, 
326   enabling more than UINT_MAX bytes to write at once.
327 */
328 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
329 { if (buffer && !handle)
330   { memcpy(*buffer, buf, len);
331     (*buffer) += len;
332     return true;
333   }
334   if (buffer && handle)
335   { (*buffer) += len;
336     return true;
337   }
338   else
339   { for(int i=0; i<2; i++)
340     { int byteswritten;
341       size_t remaining;
342       int chunksize;
343
344       //If write fails, test if not related to big buffer problem
345       //Bug report http://support.microsoft.com/kb/899149 entitled
346       //"You cannot call the fwrite function to write to a buffer
347       // that is larger than 64 MB in Visual C++ 2005,
348       // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
349       // NB: same thing for write function in binary mode
350       if (i==0)
351       { remaining = len;
352         // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times 
353         // to interpret the signed 32-bit return value correctly
354         while (remaining>0)
355         { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
356           byteswritten = wxdr_write(handle, buf, chunksize);
357           if (byteswritten == chunksize)
358             remaining -= chunksize;
359           else
360             break; // try writefix in the next round
361         }
362         if (remaining == 0)
363           return true;
364       }
365       else
366       { remaining = len;   
367         // call writefix (in mbfield.c) several times to interpret the signed 32-bit 
368         // return value correctly. writefix uses chunks of 16384 bytes
369         while (remaining>0)
370         { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
371           byteswritten = writefix(handle, buf, chunksize);
372           if (byteswritten == chunksize)
373             remaining -= chunksize;
374           else
375             break; // even writefix failed: return error        
376         }
377         if (remaining == 0)
378           return true;
379       }
380     }
381     // Note: file is open in binary mode, no need to compensate
382     // for a value of byteswritten > len due to \n -> \r\n conversions.
383     // (write() on a text stream is implementation dependent.)
384     if (handle != fileno(stdout)) close(handle);
385     AVSerror("Avs_wxdr: write failed, disk full?");
386     return false;
387   }
388 }
389
390 /* coder for NKI private compressed pixel data
391    arguments: dest    = (in) points to area where compressed destination data is written (byte)
392               src     = (in) points to uncompressed source data (short)
393               npixels = (in) number of pixels to compress
394
395    The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
396
397    if iMode == 1 then
398    - The first 4 bytes contain the number of short-int pixels
399    - The following 4 bytes contain iMode=1
400    - The rest is the compressed image
401
402    if iMode == 2 then
403    - The first 4 bytes contain the number of short-int pixels
404    - The following 4 bytes contain iMode=2
405    - The following 4 bytes contain the size of the compressed image (in bytes)
406    - The following 4 bytes contain the CRC of the original image
407    - The following 4 bytes contain the CRC of the compressed image
408    - The rest is the compressed image
409    - The compressed size will be even (padded by a zero if necessary).
410
411    if iMode == 3 then
412    - The first 4 bytes contain the number of short-int pixels
413    - The following 4 bytes contain iMode=3
414    - The rest is the compressed image, including 4 bit differences
415
416    if iMode == 4 then
417    - The first 4 bytes contain the number of short-int pixels
418    - The following 4 bytes contain iMode=4
419    - The following 4 bytes contain the size of the compressed image (in bytes)
420    - The following 4 bytes contain the CRC of the original image
421    - The following 4 bytes contain 0
422    - The rest is the compressed image, including 4 bit differences
423    - The compressed size will be even (padded by a zero if necessary).
424
425    iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
426    iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
427 */
428
429 // optimized settings for the 4 bit run compressor (mode 3 and 4)
430
431 #define MINZEROS 5              // shortest RLE (2 byte overhead, but breaks 4bit run)
432 #define MIN4BIT  6              // shortest 4 bit run (6 bytes compressed to 5 bytes)
433
434 // This internal routine converts an 8 bit difference string into a 4 bit one
435 static signed char *recompress4bit(int n, signed char *dest)
436 { signed char *p, *q;
437   int val;
438
439   n = n & 0xfe;
440   dest -= n;
441   p = dest;
442   val = (((int)p[0])<<4) | (p[1]&15);
443   p += 2;
444   *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
445   *dest++ = (signed char)n;
446   q = dest++;
447   n -= 2;
448   while(n>0)
449   { *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
450     p += 2;
451     n -= 2;
452   }
453   q[0] = (signed char)val;
454
455   return dest;
456 }
457
458
459 static size_t nki_private_compress(signed char  *dest, short int  *src, size_t npixels, int iMode)
460 { unsigned long         iCRC;
461   unsigned long         iCRC2;
462   unsigned int          iHeaderSize=8;                      // value for iMode==1 and iMode==3
463   register int          val;
464   size_t                i,j;
465   NKI_MODE2*            pHeader = (NKI_MODE2*)dest;
466   NKI_MODE2_64BITS*     pHeader_64bits = (NKI_MODE2_64BITS*)dest;
467   size_t                iBufferSize;
468
469   iBufferSize = (npixels / 2) * 3;                          // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
470
471   /* Up till now only Mode=1 .. 4 are supported */
472   if ((iMode < 1) || (iMode > 4))
473     return 0;
474
475   /* Create the header */
476   pHeader->iMode = iMode;
477
478   if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX)         // On a 64 bits OS we want to store files>4GB 
479   { pHeader_64bits->iOrgSize   = 0;                         // This indicates>4GB file (0-vector is not compressed)
480     pHeader_64bits->i64OrgSize = npixels;    
481     iHeaderSize = sizeof(NKI_MODE2_64BITS);
482     dest += sizeof(NKI_MODE2_64BITS);
483   }
484   else
485   { pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
486
487     if (iMode==2 || iMode==4)
488       iHeaderSize = sizeof(NKI_MODE2);
489     dest += iHeaderSize;
490   }
491
492   /* Create the compressed image */
493
494   if (iMode == 1)
495   { *(short int *)dest = *src;
496     dest+=2;
497
498     npixels--;
499
500     do
501     { val = src[1] - src[0];
502       src++;
503
504       if (val == 0)                            /* run length-encode zero differences */
505       { for (i=2;; i++)
506         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
507           { if (i==2)
508               *dest++=0;
509             else
510             { *dest++  =  -128; // hexadecimal 0x80
511               *dest++  = (signed char)(i-1);
512               npixels -= (i-2);
513               src     += (i-2);
514             }
515             break;
516           }
517         }
518       }
519       else if (val >= -64 && val <= 63)         /* small difference coded as one byte */
520       { *dest = (signed char)val;
521         dest++;
522       }
523       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
524       { dest[0] = (signed char)((val>>8) ^ 0x40);
525         dest[1] = (signed char)val;
526         dest+=2;
527       }
528       else                                      /* if very large differences code abs val as three bytes */
529       { *dest++ = 0x7F;
530         *dest++ = (signed char)(src[0]>>8);
531         *dest++ = (signed char)(src[0]);
532       }
533       /* Are we beyond the allocated memory? */
534       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
535         return 0;
536     }
537     while (--npixels);
538   }
539
540   else if (iMode == 2)
541   { iCRC  = 0;
542     iCRC2 = 0;
543
544     *(short int *)dest = val = *src;
545     iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val    ] ^ ((iCRC2 >> 8));
546     iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
547     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) val    ] ^ ((iCRC  >> 8));
548     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(val>>8)] ^ ((iCRC  >> 8));
549     dest+=2;
550     npixels--;
551
552     do
553     { val = src[1] - src[0];
554       src++;
555       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
556       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
557
558       if (val == 0)                            /* run length-encode zero differences */
559       { for (i=2;; i++)
560         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
561           { if (i==2)
562             { *dest++=0;
563               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0    ] ^ ((iCRC2 >> 8));
564             }
565             else
566             { *dest++  =  -128; // hexadecimal 0x80
567               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
568               *dest++  = (signed char)(i-1);
569               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
570               npixels -= (i-2);
571
572               for (j=0; j<i-2; j++)
573               { src++;
574                 iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
575                 iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
576               }
577             }
578             break;
579           }
580         }
581       }
582       else if (val >= -64 && val <= 63)         /* small difference coded as one byte */
583       { *dest = (signed char)val;
584         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
585         dest++;
586       }
587       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
588       { dest[0] = (signed char)((val>>8) ^ 0x40);
589         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
590         dest[1] = (signed char)val;
591         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
592         dest+=2;
593       }
594       else                                      /* if very large differences code abs val as three bytes */
595       { dest[0] = 0x7F;
596         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f                   ] ^ ((iCRC2 >> 8));
597         val     = src[0];
598         dest[1] = (signed char)(val>>8);
599         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
600         dest[2] = (signed char)val;
601         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
602         dest+=3;
603       }
604       /* Are we beyond the allocated memory? */
605       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
606         return 0;
607     }
608     while (--npixels);
609     
610     if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
611       pHeader->iCompressedSize = 
612         (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
613     else                                                       // store 64 bit number in extended structure
614       pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
615
616     /* Pad it to get an even length */
617     if (pHeader->iCompressedSize & 1)
618     { *dest++ = 0;
619       iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
620       pHeader->iCompressedSize++;
621     }
622
623     pHeader->iOrgCRC        = iCRC;
624     pHeader->iCompressedCRC = iCRC2;
625   }
626
627   /* Create the compressed image - compressor with added 4 bit run */
628
629   else if (iMode == 3)
630   { int n4bit=0;
631     *(short int *)dest = *src;
632     dest+=2;
633     npixels--;
634
635     do
636     { val = src[1] - src[0];
637       src++;
638
639       if (val == 0)                             /* run length-encode zero differences */
640       { for (i=2;; i++)
641         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
642           { if (i<=MINZEROS)                    /* too short run -> write zeros */
643             { for (j=0; j<i-1; j++)
644               { *dest++=0;
645                 n4bit++;
646
647                 if(n4bit>=254)                  /* maximum length 4 bit run */
648                 { dest  = recompress4bit(n4bit, dest);
649                   n4bit = 0;
650                 }
651               }
652             }
653             else
654             { if (n4bit>=MIN4BIT)               /* end (and write) 4 bit run */
655                 dest  = recompress4bit(n4bit, dest);
656
657               n4bit=0;
658               *dest++  = -128; // hexadecimal 0x80
659               *dest++  = (signed char)(i-1);
660             }
661
662             npixels -= (i-2);
663             src     += (i-2);
664             break;
665           }
666         }
667       }
668       else if (val >= -63 && val <= 63)         /* small difference coded as one byte */
669       { if (val >= -8 && val <= 7)
670         { *dest++ = (signed char)val;
671           n4bit++;
672
673           if(n4bit>=254)                        /* maximum length 4 bit run */
674           { dest  = recompress4bit(n4bit, dest);
675             n4bit=0;
676           }
677         }
678         else if(n4bit>=MIN4BIT)                 /* end and write 4 bit run */
679         { j = val;
680           dest  = recompress4bit(n4bit, dest);
681           n4bit=0;
682           *dest++ = (signed char)j;
683         }
684         else
685         { *dest++ = (signed char)val;                   /* end 4 bit run */
686            n4bit  = 0;
687         }
688       }
689       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
690       { j = val;
691
692         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
693           dest  = recompress4bit(n4bit, dest);
694
695         n4bit=0;
696         dest[0] = (signed char)((j>>8) ^ 0x40);
697         dest[1] = (signed char)j;
698         dest+=2;
699       }
700       else                                      /* if very large differences code abs val as three bytes */
701       { j = src[0];
702
703         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
704           dest  = recompress4bit(n4bit, dest);
705
706         n4bit=0;
707         *dest++ = 0x7F;
708         *dest++ = (signed char)(j>>8);
709         *dest++ = (signed char)j;
710       }
711       /* Are we beyond the allocated memory? */
712       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
713         return 0;
714     }
715     while (--npixels);
716   }
717
718   /* Create the compressed image - compressor with added 4 bit run and CRC */
719
720   else if (iMode == 4)
721   { int n4bit=0;
722     iCRC  = 0;
723
724     *(short int *)dest = val = *src;
725     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) val    ] ^ ((iCRC  >> 8));
726     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(val>>8)] ^ ((iCRC  >> 8));
727     dest+=2;
728     npixels--;
729
730     do
731     { val = src[1] - src[0];
732       src++;
733       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
734       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
735
736       if (val == 0)                             /* run length-encode zero differences */
737       { for (i=2;; i++)
738         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
739           { if (i<=MINZEROS)                    /* too short run -> write zeros */
740             { for (j=0; j<i-1; j++)
741               { *dest++=0;
742                 n4bit++;
743
744                 if(n4bit>=254)                  /* maximum length 4 bit run */
745                 { dest  = recompress4bit(n4bit, dest);
746                   n4bit = 0;
747                 }
748               }
749             }
750             else
751             { if (n4bit>=MIN4BIT)               /* end (and write) 4 bit run */
752                 dest  = recompress4bit(n4bit, dest);
753
754               n4bit=0;
755               *dest++  = -128; // hexadecimal 0x80
756               *dest++  = (signed char)(i-1);
757             }
758
759             npixels -= (i-2);
760             for (j=0; j<i-2; j++)
761             { src++;
762               iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
763               iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
764             }
765             break;
766           }
767         }
768       }
769       else if (val >= -63 && val <= 63)         /* small difference coded as one byte */
770       { if (val >= -8 && val <= 7)
771         { *dest++ = (signed char)val;
772           n4bit++;
773
774           if(n4bit>=254)                        /* maximum length 4 bit run */
775           { dest  = recompress4bit(n4bit, dest);
776             n4bit=0;
777           }
778         }
779         else if(n4bit>=MIN4BIT)                 /* end and write 4 bit run */
780         { j = val;
781           dest  = recompress4bit(n4bit, dest);
782           n4bit=0;
783           *dest++ = (signed char)j;
784         }
785         else
786         { *dest++ = (signed char)val;           /* end 4 bit run */
787            n4bit  = 0;
788         }
789       }
790       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
791       { j = val;
792
793         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
794           dest  = recompress4bit(n4bit, dest);
795
796         n4bit=0;
797         dest[0] = (signed char)((j>>8) ^ 0x40);
798         dest[1] = (signed char)j;
799         dest+=2;
800       }
801       else                                      /* if very large differences code abs val as three bytes */
802       { j = src[0];
803
804         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
805           dest  = recompress4bit(n4bit, dest);
806
807         n4bit=0;
808         *dest++ = 0x7F;
809         *dest++ = (signed char)(j>>8);
810         *dest++ = (signed char)j;
811       }
812       /* Are we beyond the allocated memory? */
813       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
814         return 0;
815     }
816     while (--npixels);
817
818     if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
819       pHeader->iCompressedSize = 
820         (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
821     else                                                       // store 64 bit number in extended structure
822     { pHeader_64bits->iCompressedSize = 0;
823       pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
824     }
825
826     /* Pad it to get an even length */
827     if (pHeader->iCompressedSize & 1)
828     { *dest++ = 0;
829       pHeader->iCompressedSize++;
830     }
831
832     pHeader->iOrgCRC        = iCRC;
833     pHeader->iCompressedCRC = 0;
834   }
835
836   return dest - (signed char*)pHeader;
837 }
838
839
840 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
841                                    int offset, char bLittleEndian, int iNkiCompression,
842                                    int wcoords, int append, int getsize, char *tobuffer, const void* data)
843 { AVSINT   total=1;
844   unsigned int      i;
845   AVSINT   coords=0;
846   int      f=0;
847   char     temp[256];
848   char     *c;
849   char     cSwap;
850   FILE     *fp;
851   long     swap_test = 0x1000000;
852   signed char*  pCompressed = NULL;
853   size_t   FilePos=0;
854   char     **buffer = NULL;
855   int      len=0;
856   char     *buf2;
857   size_t   slen;
858
859   if (bLittleEndian)
860     swap_test = 0x00000001;
861
862   if (getsize)
863   { swap_test = 0xffffffff;     // never swap to save time
864     buffer    = (char **) &len;
865     f         = 1;
866   }
867
868   if (tobuffer)
869   { buf2   = (char *)tobuffer;
870     buffer = &buf2;
871     f      = 0;
872   }
873
874   for (i=0; i<GetNumberOfDimensions(); i++)
875   { total  *= GetDimensions(i);
876     coords += GetDimensions(i);
877   }
878
879   /* Try allocate the compressed fielddata - compression disabled if alloc fails */
880   if ((iNkiCompression > 0) &&
881         (GetComponentType() == itk::ImageIOBase::SHORT) &&
882         (GetPixelType() == itk::ImageIOBase::SCALAR))
883   { pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
884     if (pCompressed==NULL)
885     { iNkiCompression = 0;
886       AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
887     }
888   }
889
890   if (!(tobuffer || getsize))
891   { if (offset != -1)
892     { f = open(file, O_RDWR, 0);
893       if (f < 0)
894       {
895         AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
896         free(pCompressed);
897         return AVS_ERROR;
898       }
899       lseek(f, offset, SEEK_SET);
900     }
901     else
902     { if (strlen(file)==0)
903         f = fileno(stdout);
904       else
905       { if (append)
906           f = open(file, O_RDWR | O_APPEND, 0);
907         else
908           f = creat(file, S_IWRITE | S_IREAD);
909       }
910
911       if (f < 0)
912       { AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
913         free(pCompressed);
914         return AVS_ERROR;
915       }
916     }
917   }
918
919   if (!raw)
920   { sprintf(temp, "# AVS wants to have the first line starting with its name\n");
921     slen = strlen(temp);
922
923     if (!checked_write(f, temp, slen, buffer))
924     { free(pCompressed);
925       return AVS_ERROR;
926     }
927     FilePos += slen;
928
929     slen = strlen(headerinfo);
930     if (slen && !checked_write(f, headerinfo, slen, buffer))
931     { free(pCompressed);
932       return AVS_ERROR;
933     }
934     FilePos += slen;
935
936     if (!checked_write(f, "\n", 1, buffer))
937     { free(pCompressed);
938       return AVS_ERROR;
939     }
940     FilePos++;
941
942     if (strlen(headerfile))
943     { fp = fopen(headerfile, "rt");
944       if (fp)
945       { for (;;)
946         { if (fgets(temp, 255, fp) == NULL) break;
947           slen = strlen(temp);
948           if (!checked_write(f, temp, slen, buffer))
949           { fclose(fp);
950             free(pCompressed);
951             return AVS_ERROR;
952           }
953           FilePos += slen;
954         }
955         fclose(fp);
956         if (!checked_write(f, "\n", 1, buffer))
957         { free(pCompressed);
958           return AVS_ERROR;
959         }
960         FilePos++;
961       }
962     }
963
964     sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
965     slen = strlen(temp);
966     if (!checked_write(f, temp, slen, buffer))
967     { free(pCompressed);
968       return AVS_ERROR;
969     }
970     FilePos += slen;
971   }
972
973   for (i=0; i<GetNumberOfDimensions(); i++)
974   { if (!raw)
975     { sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
976       slen = strlen(temp);
977       if (!checked_write(f, temp, slen, buffer))
978       { free(pCompressed);
979         return AVS_ERROR;
980       }
981       FilePos += slen;
982     }
983   }
984
985   if (!raw)
986   { sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
987     slen = strlen(temp);
988     if (!checked_write(f, temp, slen, buffer))
989     { free(pCompressed);
990       return AVS_ERROR;
991     }
992     FilePos += slen;
993
994     sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
995     slen = strlen(temp);
996     if (!checked_write(f, temp, slen, buffer))
997     { free(pCompressed);
998       return AVS_ERROR;
999     }
1000     FilePos += slen;
1001
1002     switch(GetComponentType())
1003     { case itk::ImageIOBase::CHAR   : strcpy(temp, "data=byte\n"); break;
1004       case itk::ImageIOBase::SHORT  : strcpy(temp, "data=xdr_short\n"); break;
1005       case itk::ImageIOBase::INT    : strcpy(temp, "data=xdr_integer\n"); break;
1006       case itk::ImageIOBase::FLOAT  : strcpy(temp, "data=xdr_real\n"); break;
1007       case itk::ImageIOBase::DOUBLE : strcpy(temp, "data=xdr_double\n"); break;
1008       default               : if (f != fileno(stdout)) close(f);
1009                               free(pCompressed);
1010                               return AVS_ERROR;
1011     }
1012     slen = strlen(temp);
1013     if (!checked_write(f, temp, slen, buffer))
1014     { free(pCompressed);
1015       return AVS_ERROR;
1016     }
1017     FilePos += slen;
1018   }
1019
1020
1021   //FilePos = tell(f);
1022 ONCE_AGAIN:
1023
1024
1025   //switch(input->uniform)
1026   //{ case UNIFORM     : 
1027   strcpy(temp, "field=uniform\n");
1028   coords = GetNumberOfDimensions() * 2;
1029                 //       break;
1030   //  case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1031                 //       break;
1032   //  case IRREGULAR   : strcpy(temp, "field=irregular\n");
1033                 //       coords = total * input->nspace;
1034                 //       break;
1035   //  default          : if (f != fileno(stdout)) close(f);
1036   //                     free(pCompressed);
1037   //                           return;
1038   //}
1039
1040   if (!raw)
1041   { if (!checked_write(f, temp, strlen(temp), buffer))
1042     { free(pCompressed);
1043       return AVS_ERROR;
1044     }
1045
1046     if ((iNkiCompression > 0) &&
1047       (GetComponentType() == itk::ImageIOBase::SHORT) &&
1048       (GetPixelType() == itk::ImageIOBase::SCALAR))
1049     { sprintf(temp, "nki_compression=%d", iNkiCompression);
1050       if (!checked_write(f, temp, strlen(temp), buffer))
1051       { free(pCompressed);
1052         return AVS_ERROR;
1053       }
1054     }
1055
1056     temp[0] = temp[1] = 12;
1057     if (!checked_write(f, temp, 2, buffer))
1058     { free(pCompressed);
1059       return AVS_ERROR;
1060     }
1061   }
1062
1063   total *= GetPixelSize();
1064
1065   if ((!raw) && (iNkiCompression > 0) &&
1066         (GetComponentType() == itk::ImageIOBase::SHORT) &&
1067         (GetPixelType() == itk::ImageIOBase::SCALAR))
1068   { size_t      iCompressedLength;
1069
1070     iCompressedLength = nki_private_compress(pCompressed,
1071       (short int *)(data), total/2, iNkiCompression);
1072
1073     if (iCompressedLength > 0)
1074     { if (!checked_write(f, pCompressed, iCompressedLength, buffer))
1075       { free(pCompressed);
1076         return AVS_ERROR;
1077       }
1078       free(pCompressed);
1079       goto WRITE_COORDS;
1080     }
1081
1082     /* Compressionratio was poor: let's write uncompressed */
1083     iNkiCompression = 0;
1084     total /= 2;
1085     free(pCompressed);
1086     pCompressed = NULL;
1087     lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1088     goto ONCE_AGAIN;
1089   }
1090
1091   /* swap data if required (xdr is low-endian) */
1092
1093   if (!(*(char *)(&swap_test)))
1094   { if (GetComponentSize()==2)
1095     { c = (char *)data;
1096       for (i=0; i<total; i+=2)
1097       { cSwap  = c[i];  c[i]   = c[i+1]; c[i+1] = cSwap;
1098       }
1099     }
1100     else if (GetComponentSize()==4)
1101     { c = (char *)data;
1102       for (i=0; i<total; i+=4)
1103       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1104         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1105       }
1106     }
1107     else if (GetComponentSize()==8)
1108     { c = (char *)data;
1109       for (i=0; i<total; i+=8)
1110       { cSwap = c[i];   c[i]   = c[i+7]; c[i+7] = cSwap;
1111         cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1112         cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1113         cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1114       }
1115     }
1116   }
1117
1118   if (total)
1119   { if (!checked_write(f, data, total, buffer))
1120       return AVS_ERROR;
1121   }
1122
1123   /* swap data back if was swapped before writing */
1124
1125   if (!(*(char *)(&swap_test)))
1126   { if (GetComponentSize()==2)
1127     { c = (char *)data;
1128       for (i=0; i<total; i+=2)
1129       { cSwap = c[i];   c[i]   = c[i+1]; c[i+1] = cSwap;
1130       }
1131     }
1132     else if (GetComponentSize()==4)
1133     { c = (char *)data;
1134       for (i=0; i<total; i+=4)
1135       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1136         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1137       }
1138     }
1139     else if (GetComponentSize()==8)
1140     { c = (char *)data;
1141       for (i=0; i<total; i+=8)
1142       { cSwap = c[i];   c[i]   = c[i+7]; c[i+7] = cSwap;
1143         cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1144         cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1145         cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1146       }
1147     }
1148   }
1149
1150 WRITE_COORDS:
1151   float *points;
1152   points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1153   for (i=0; i<GetNumberOfDimensions(); i++)
1154   {
1155     points[i*2  ] = 0.1 *  GetOrigin(i);
1156     points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1157   }
1158
1159   if (coords && !raw)                           /* write AVS coordinates ? */
1160   { coords *= sizeof(float);
1161     if (!(*(char *)(&swap_test)))
1162     { c = (char *)(points);              /* swap bytes */
1163       for (i=0; i<coords; i+=4)
1164       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1165         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1166       }
1167     }
1168
1169     if (!checked_write(f, points, coords, buffer))
1170       return AVS_ERROR;
1171
1172     if (!(*(char *)(&swap_test)))
1173     { c = (char *)(points);              /* swap bytes back */
1174       for (i=0; i<coords; i+=4)
1175       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1176         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1177       }
1178     }
1179   }
1180
1181   if (!(tobuffer || getsize))
1182     if (f != fileno(stdout)) close(f);
1183
1184   if (getsize) return;
1185   return AVS_OK;
1186 }