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