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