]> Creatis software - clitk.git/blob - common/clitkXdrImageIOWriter.cxx
af50b0ea0dfe3399c3eec82424f810c1dc2f9e5f
[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
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 #if !defined(unix) && !defined(__APPLE__)
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   if (bLittleEndian)
841     swap_test = 0x00000001;
842
843   if (getsize) {
844     swap_test = 0xffffffff;     // never swap to save time
845     buffer    = (char **) &len;
846     f         = 1;
847   }
848
849   if (tobuffer) {
850     buf2   = (char *)tobuffer;
851     buffer = &buf2;
852     f      = 0;
853   }
854
855   for (i=0; i<GetNumberOfDimensions(); i++) {
856     total  *= GetDimensions(i);
857     coords += GetDimensions(i);
858   }
859
860   /* Try allocate the compressed fielddata - compression disabled if alloc fails */
861   if ((iNkiCompression > 0) &&
862       (GetComponentType() == itk::ImageIOBase::SHORT) &&
863       (GetPixelType() == itk::ImageIOBase::SCALAR)) {
864     pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
865     if (pCompressed==NULL) {
866       iNkiCompression = 0;
867       AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
868     }
869   }
870
871   if (!(tobuffer || getsize)) {
872     if (offset != -1) {
873       f = open(file, O_RDWR, 0);
874       if (f < 0) {
875         AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
876         free(pCompressed);
877         return AVS_ERROR;
878       }
879       lseek(f, offset, SEEK_SET);
880     } else {
881       if (strlen(file)==0)
882         f = fileno(stdout);
883       else {
884         if (append)
885           f = open(file, O_RDWR | O_APPEND, 0);
886         else
887           f = creat(file, S_IWRITE | S_IREAD);
888       }
889
890       if (f < 0) {
891         AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
892         free(pCompressed);
893         return AVS_ERROR;
894       }
895     }
896   }
897
898   if (!raw) {
899     sprintf(temp, "# AVS wants to have the first line starting with its name\n");
900     slen = strlen(temp);
901
902     if (!checked_write(f, temp, slen, buffer)) {
903       free(pCompressed);
904       return AVS_ERROR;
905     }
906     FilePos += slen;
907
908     slen = strlen(headerinfo);
909     if (slen && !checked_write(f, headerinfo, slen, buffer)) {
910       free(pCompressed);
911       return AVS_ERROR;
912     }
913     FilePos += slen;
914
915     if (!checked_write(f, "\n", 1, buffer)) {
916       free(pCompressed);
917       return AVS_ERROR;
918     }
919     FilePos++;
920
921     if (strlen(headerfile)) {
922       fp = fopen(headerfile, "rt");
923       if (fp) {
924         for (;;) {
925           if (fgets(temp, 255, fp) == NULL) break;
926           slen = strlen(temp);
927           if (!checked_write(f, temp, slen, buffer)) {
928             fclose(fp);
929             free(pCompressed);
930             return AVS_ERROR;
931           }
932           FilePos += slen;
933         }
934         fclose(fp);
935         if (!checked_write(f, "\n", 1, buffer)) {
936           free(pCompressed);
937           return AVS_ERROR;
938         }
939         FilePos++;
940       }
941     }
942
943     sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
944     slen = strlen(temp);
945     if (!checked_write(f, temp, slen, buffer)) {
946       free(pCompressed);
947       return AVS_ERROR;
948     }
949     FilePos += slen;
950   }
951
952   for (i=0; i<GetNumberOfDimensions(); i++) {
953     if (!raw) {
954       sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
955       slen = strlen(temp);
956       if (!checked_write(f, temp, slen, buffer)) {
957         free(pCompressed);
958         return AVS_ERROR;
959       }
960       FilePos += slen;
961     }
962   }
963
964   if (!raw) {
965     sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
966     slen = strlen(temp);
967     if (!checked_write(f, temp, slen, buffer)) {
968       free(pCompressed);
969       return AVS_ERROR;
970     }
971     FilePos += slen;
972
973     sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
974     slen = strlen(temp);
975     if (!checked_write(f, temp, slen, buffer)) {
976       free(pCompressed);
977       return AVS_ERROR;
978     }
979     FilePos += slen;
980
981     switch(GetComponentType()) {
982     case itk::ImageIOBase::CHAR   :
983       strcpy(temp, "data=byte\n");
984       break;
985     case itk::ImageIOBase::SHORT  :
986       strcpy(temp, "data=xdr_short\n");
987       break;
988     case itk::ImageIOBase::INT    :
989       strcpy(temp, "data=xdr_integer\n");
990       break;
991     case itk::ImageIOBase::FLOAT  :
992       strcpy(temp, "data=xdr_real\n");
993       break;
994     case itk::ImageIOBase::DOUBLE :
995       strcpy(temp, "data=xdr_double\n");
996       break;
997     default               :
998       if (f != fileno(stdout)) close(f);
999       free(pCompressed);
1000       return AVS_ERROR;
1001     }
1002     slen = strlen(temp);
1003     if (!checked_write(f, temp, slen, buffer)) {
1004       free(pCompressed);
1005       return AVS_ERROR;
1006     }
1007     FilePos += slen;
1008   }
1009
1010
1011   //FilePos = tell(f);
1012 ONCE_AGAIN:
1013
1014
1015   //switch(input->uniform)
1016   //{ case UNIFORM     :
1017   strcpy(temp, "field=uniform\n");
1018   coords = GetNumberOfDimensions() * 2;
1019   //       break;
1020   //  case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1021   //       break;
1022   //  case IRREGULAR   : strcpy(temp, "field=irregular\n");
1023   //       coords = total * input->nspace;
1024   //       break;
1025   //  default          : if (f != fileno(stdout)) close(f);
1026   //                     free(pCompressed);
1027   //                           return;
1028   //}
1029
1030   if (!raw) {
1031     if (!checked_write(f, temp, strlen(temp), buffer)) {
1032       free(pCompressed);
1033       return AVS_ERROR;
1034     }
1035
1036     if ((iNkiCompression > 0) &&
1037         (GetComponentType() == itk::ImageIOBase::SHORT) &&
1038         (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1039       sprintf(temp, "nki_compression=%d", iNkiCompression);
1040       if (!checked_write(f, temp, strlen(temp), buffer)) {
1041         free(pCompressed);
1042         return AVS_ERROR;
1043       }
1044     }
1045
1046     temp[0] = temp[1] = 12;
1047     if (!checked_write(f, temp, 2, buffer)) {
1048       free(pCompressed);
1049       return AVS_ERROR;
1050     }
1051   }
1052
1053   total *= GetPixelSize();
1054
1055   if ((!raw) && (iNkiCompression > 0) &&
1056       (GetComponentType() == itk::ImageIOBase::SHORT) &&
1057       (GetPixelType() == itk::ImageIOBase::SCALAR)) {
1058     size_t      iCompressedLength;
1059
1060     iCompressedLength = nki_private_compress(pCompressed,
1061                         (short int *)(data), total/2, iNkiCompression);
1062
1063     if (iCompressedLength > 0) {
1064       if (!checked_write(f, pCompressed, iCompressedLength, buffer)) {
1065         free(pCompressed);
1066         return AVS_ERROR;
1067       }
1068       free(pCompressed);
1069       goto WRITE_COORDS;
1070     }
1071
1072     /* Compressionratio was poor: let's write uncompressed */
1073     iNkiCompression = 0;
1074     total /= 2;
1075     free(pCompressed);
1076     pCompressed = NULL;
1077     lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1078     goto ONCE_AGAIN;
1079   }
1080
1081   /* swap data if required (xdr is low-endian) */
1082
1083   if (!(*(char *)(&swap_test))) {
1084     if (GetComponentSize()==2) {
1085       c = (char *)data;
1086       for (i=0; i<total; i+=2) {
1087         cSwap  = c[i];
1088         c[i]   = c[i+1];
1089         c[i+1] = cSwap;
1090       }
1091     } else if (GetComponentSize()==4) {
1092       c = (char *)data;
1093       for (i=0; i<total; i+=4) {
1094         cSwap = c[i];
1095         c[i]   = c[i+3];
1096         c[i+3] = cSwap;
1097         cSwap = c[i+1];
1098         c[i+1] = c[i+2];
1099         c[i+2] = cSwap;
1100       }
1101     } else if (GetComponentSize()==8) {
1102       c = (char *)data;
1103       for (i=0; i<total; i+=8) {
1104         cSwap = c[i];
1105         c[i]   = c[i+7];
1106         c[i+7] = cSwap;
1107         cSwap = c[i+1];
1108         c[i+1] = c[i+6];
1109         c[i+6] = cSwap;
1110         cSwap = c[i+2];
1111         c[i+2] = c[i+5];
1112         c[i+5] = cSwap;
1113         cSwap = c[i+3];
1114         c[i+3] = c[i+4];
1115         c[i+4] = cSwap;
1116       }
1117     }
1118   }
1119
1120   if (total) {
1121     if (!checked_write(f, data, total, buffer))
1122       return AVS_ERROR;
1123   }
1124
1125   /* swap data back if was swapped before writing */
1126
1127   if (!(*(char *)(&swap_test))) {
1128     if (GetComponentSize()==2) {
1129       c = (char *)data;
1130       for (i=0; i<total; i+=2) {
1131         cSwap = c[i];
1132         c[i]   = c[i+1];
1133         c[i+1] = cSwap;
1134       }
1135     } else if (GetComponentSize()==4) {
1136       c = (char *)data;
1137       for (i=0; i<total; i+=4) {
1138         cSwap = c[i];
1139         c[i]   = c[i+3];
1140         c[i+3] = cSwap;
1141         cSwap = c[i+1];
1142         c[i+1] = c[i+2];
1143         c[i+2] = cSwap;
1144       }
1145     } else if (GetComponentSize()==8) {
1146       c = (char *)data;
1147       for (i=0; i<total; i+=8) {
1148         cSwap = c[i];
1149         c[i]   = c[i+7];
1150         c[i+7] = cSwap;
1151         cSwap = c[i+1];
1152         c[i+1] = c[i+6];
1153         c[i+6] = cSwap;
1154         cSwap = c[i+2];
1155         c[i+2] = c[i+5];
1156         c[i+5] = cSwap;
1157         cSwap = c[i+3];
1158         c[i+3] = c[i+4];
1159         c[i+4] = cSwap;
1160       }
1161     }
1162   }
1163
1164 WRITE_COORDS:
1165   float *points;
1166   points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1167   for (i=0; i<GetNumberOfDimensions(); i++) {
1168     points[i*2  ] = 0.1 *  GetOrigin(i);
1169     points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1170   }
1171
1172   if (coords && !raw) {                         /* write AVS coordinates ? */
1173     coords *= sizeof(float);
1174     if (!(*(char *)(&swap_test))) {
1175       c = (char *)(points);              /* swap bytes */
1176       for (i=0; i<coords; i+=4) {
1177         cSwap = c[i];
1178         c[i]   = c[i+3];
1179         c[i+3] = cSwap;
1180         cSwap = c[i+1];
1181         c[i+1] = c[i+2];
1182         c[i+2] = cSwap;
1183       }
1184     }
1185
1186     if (!checked_write(f, points, coords, buffer))
1187       return AVS_ERROR;
1188
1189     if (!(*(char *)(&swap_test))) {
1190       c = (char *)(points);              /* swap bytes back */
1191       for (i=0; i<coords; i+=4) {
1192         cSwap = c[i];
1193         c[i]   = c[i+3];
1194         c[i+3] = cSwap;
1195         cSwap = c[i+1];
1196         c[i+1] = c[i+2];
1197         c[i+2] = cSwap;
1198       }
1199     }
1200   }
1201
1202   if (!(tobuffer || getsize))
1203     if (f != fileno(stdout)) close(f);
1204
1205   if (getsize) return;
1206   return AVS_OK;
1207 }