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