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