]> Creatis software - clitk.git/blob - common/clitkXdrImageIOWriter.cxx
fixes for unix
[clitk.git] / common / clitkXdrImageIOWriter.cxx
1 /**
2  * @file   clitkXdrImageIO.cxx
3  * @author Simon Rit <simon.rit@gmail.com>
4  * @date   Sun Jun  1 22:12:20 2008
5  *
6  * @brief
7  *
8  *
9  */
10
11 #include "clitkXdrImageIO.h"
12 #include "clitkCommon.h"
13
14 #include <sys/stat.h>
15
16 //From mbfield.h
17 #ifndef unix
18 //#define _read  readfix
19 #endif
20 #define AVSINT ptrdiff_t
21 #define AVS_ERROR
22 #define AVS_OK
23
24 //From portdefs.h
25 #ifdef unix
26 #define O_BINARY 0
27 #define setmode(a,b) 0
28 #endif
29
30 #ifndef __LARGE__
31 #  if defined(__GNUC__) || defined(unix)
32      typedef long long Q_INT64;
33      typedef unsigned long long Q_UINT64;
34 #    define Q_INT64_CONST(x) (x##ll)
35 #    define Q_UINT64_CONST(x) (x##llu) /* gcc also allows ull */
36      /* When using MINGW with MS(V)CRT DLL, use MS format modifier. */
37 #    ifdef __MSVCRT__
38 #      define Q_INT64_FORMAT "I64"
39 #    else
40 #      define Q_INT64_FORMAT "L"
41 #    endif
42 #  elif defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER)
43      typedef __int64 Q_INT64;
44      typedef unsigned __int64 Q_UINT64;
45 #    define Q_INT64_CONST(x) (x##i64)
46 #    define Q_UINT64_CONST(x) (x##ui64) /* i64u is not allowed! */
47 #    ifdef _MSC_VER
48 #      define Q_INT64_FORMAT "I64"
49 #    else
50 #      define Q_INT64_FORMAT "L"
51 #    endif
52 #  else
53 #    error No 64 bit integers known for this compiler, edit portdefs.h.
54 #  endif
55 #endif
56
57 bool clitk::XdrImageIO::CanWriteFile(const char* FileNameToWrite)
58 { std::string filename(FileNameToWrite);
59   std::string filenameext = GetExtension(filename);
60   if (filenameext != std::string("xdr")) return false;
61   return true;
62 }
63
64 void clitk::XdrImageIO::Write(const void* buffer)
65 { char *s = const_cast<char*>("");
66   WriteImage( m_FileName.c_str(), s, s, 0, -1, 0, 2, 0, 0, 0, 0, buffer);
67 }
68
69 /************************************************************************/
70 /*                                                                      */
71 /*      file       : AVS_WXDR.C                                         */
72 /*                                                                      */
73 /*      purpose    : AVS module for writing XDR and RAW files           */
74 /*                                                                      */
75 /*      author     : Lambert Zijp (based on a true story by             */
76 /*                   Marcel van Herk)                                   */
77 /*                                                                      */
78 /*      date       : 19970716                                           */
79 /*                                                                      */
80 /*      portability: AVS requires sizeof(void *)==sizeof(int)           */
81 /*                   This module assumes sizeof(int)>=4                 */
82 /*                                                                      */
83 /*      notes      : This module has been integrated in QUIRT           */
84 /*                                                                      */
85 /************************************************************************/
86 /* Updates:
87 When            Who     What
88 19980212        ljz     Creation (i.e. Removed from 'mbfield4.c')
89 19980304        ljz     Added QUIRT_NEXT_PARAMETER_FILE
90 19980310        ljz     Fix: XDRs were written in text-mode when
91                         quirt_init() is not called
92 19980319        ljz     Undone last change: _fmode is set in DllEntryPoint
93 19980408        tp      Moved M$-specific includes;
94                         removed AVS portability anyway
95 19980611        mvh     Added offset to write_raw (write into file)
96 20000214        lsp     Check file handle returned by open before use
97 20000313        nd      Two AVSerror messages added.
98 20000322        lsp     Matched compute func declaration with desc func
99 20000630        ljz     Added WRITE_RAW_LE, to write little-endian pixel-data
100 20000806        lsp     Compute func now 'int', conformal to ANSI C++
101 20000821        ljz     Added NkiCompression parameter to WRITE_XDR. If used,
102                         mode 2 is recommended.
103 20000504        mvh     Added write coordinates in header option to WRITE_XDR
104 20010720        mvh     Added option to write to stdout: pass "" as filename
105 20010723        mvh     Made it working by redefining write; setmode does not work
106 20010725        bb      Changed include order of windows.h and mbavs2q.h
107                         for MS6 compiler.
108 20020124      mvh+kg    The datatype in the header is now e.g. "xdr_integer"
109                         The datatypes as "integer" were intended as having native
110                         byte order, while we wrote bigendian (high byte first). Our
111                         older files read therefore OK on HP and SUN but not on linux.
112 20020124      mvh+kg    On AVS5 xdr_byte is illegal. Replace only that one by 'byte'
113 20030311        bb      Added check on write errors.  Disc full errors during a
114                         write have nasty side-effects for other programs' open files.
115                         Added check on file handle to prevent closing of stdout.
116 20030430       mvh      Added append mode for WRITE_XDR
117 20030717        ljz     Added support for NkiCompressionModes 3 and 4 (4 is recommended)
118 20040426        mvh     ELEKTA NKI-XVI0.1 RELEASE
119 20040910        mvh     Write uncompressed and warn if the compress malloc fails, layout
120 20040920        mvh     Fixed the above option (failed in append mode)
121 20040924        mvh     Fixed warn in option
122 20041117        mvh     ELEKTA NKI-XVI0.1g RELEASE
123 20050302        ljz     Merant tracker ID #1867: Check on bad compression-ratio causing
124                         access violation.
125 20050308      ljz+mvh   ELEKTA NKI-XVI0.1j RELEASE
126 20050411        mvh     Fails on I178_s1_4H.3d mode 1: compression fails and written file corrupted
127 20060903        mvh     Added WRITE_MEM_XDR and QUERY_MEM_XDR
128 20070330        mvh     WRITE_XDR failed on G:\20605104_hypo lung\20605104_incl corr+doseab3.PACK
129 20071015        mvh     ELEKTA NKI-XVI3.08 RELEASE
130 20080411      lsp+mw    NULL->0 in WriteImage() ; __sun__ doesn't know <io.h>
131 20080825        mgw     Corrected slash in sys/stat.h include
132 20081031      lsp+mvh   ELEKTA NKI-XVI4.15 RELEASE
133 20081119      lsp+sr    Removed tell(f) call for Linux
134 20081203        lsp     __sun__ -> unix
135 20090114        mvh     ELEKTA NKI-XVI4.22 RELEASE
136 20090529      lsp+sr    Work around the 64 MB limitation of write() in Windows
137 20090802        mvh     ELEKTA NKI-XVI4.29 RELEASE
138 20091209        lsp     Added WRITE_MEM_RAW
139 20091214        lsp     64 bits adaptations: pass high address of buffer as well,
140                         replaced int by AVSINT when requested, process buffer in chunks
141                         to be able to interpret return value of write() (signed int) correctly,
142                         replaced out-of-range constants 0xc0 and 0x80 by their signed equivalents
143 20091216      lsp+ljz   Prepared compression for more than 4294967295 (UINT_MAX) shorts
144                         by using bigger NKI_MODE2_64BITS struct (backwards compatible)
145 20091216        lsp     Disabled #define write for clarity: checked_write() is used throughout
146                         Use more space for pCompressed to be able to call WRITE_XDR with compression 
147                         on small fields (<10 pixels for mode 2 or 4, <2 pixels for mode 1 and 3)
148 */
149
150 /************************************************************************/
151 /*                         MODULE DOCUMENTATION                         */
152 /************************************************************************/
153 /*
154 AVS Modules  Lambert Zijp                   XDR writer  &  RAW writer
155
156 NAME
157      XDR writer - Module for writing XDR and RAW files
158
159 SUMMARY
160      Name          XDR writer
161
162      Availability : specify in which module libraries
163
164      Source        AVS_WXDR  (C++ interface)
165
166      Type          Render / Output
167
168      QUIRT name    WRITE_XDR  &  WRITE_RAW
169
170      Inputs        Input field = field
171
172      Outputs       none
173
174      Parameters    Name               Type      Default   Min       Max
175                    File name          string
176                    Header info        string    (WRITE_XDR only!)
177                    Header file        string    (WRITE_XDR only!)
178                    File Offset        integer   (WRITE_RAW only!)
179                    NKI compression    integer   (WRITE_XDR only!)
180                    Coords in header   boolean   (WRITE_XDR only!)
181                    Append             boolean   (WRITE_XDR only!)
182
183 DESCRIPTION
184      WRITE_RAW: No header, no coordinates.
185            Data only are written (high byte first); optionally into an
186            existing file (if you specify an offset)
187
188      WRITE_RAW_LE: No header, no coordinates.
189            Data only are written (low byte first);
190            optionally into an existing file (if you specify an offset)
191
192      WRITE_XDR: Successively is written to file:
193            - The string '#AVS wants ...'.
194            - The optional Header info
195            - The contents of the optional Header file
196            - An ascii description of the Input field
197            - Optionally the coordinates (coord%axis%[%pixel%]=%coord%)
198              (%axis% is 1 based, %pixel% 0 based, %coord% is float)
199            - Two bytes containing ascii character 0x0c
200            - The Data in binary (high byte first).
201              Or, if NKI_Compression is greater than zero, compressed data.
202            - The Coordinates in binary IEEE float (high byte first)
203
204 INPUTS
205      Input field (Required; field)
206           Describe input here....
207
208 PARAMETERS
209      File name
210           A string described here....
211
212      Header info
213           A string described here....
214
215      Header file
216           A string described here....
217
218      File offset
219           An integer (default -1). If set, WRITE_RAW writes the data
220           into an existing file.
221
222      NKI compression
223           An integer described here....
224
225      Write coordinates in header
226           A boolean described here....
227
228      Append to file
229           A boolean described here....
230
231 OUTPUTS
232      none
233
234 PORTABILITY
235      QUIRT, C++
236
237 LIBRARIES
238      (optional): in which AVS libraries available
239
240 TYPE
241      Render / Output
242      (optional): further specify type of Render / Output module
243
244 FILE FORMATS
245      (optional): which type of files are read|written
246
247 EXAMPLE
248      The following network shows how .....
249
250                          READ IMA
251                              |
252                              |
253                        XDR WRITER
254                        |              |
255                        |              |
256
257 LIMITATIONS
258      (optional): describe limitations here
259
260 RELATED MODULES
261      Modules that can provide input:
262           .....
263      Modules that could be used in place of XDR writer:
264           .....
265      Modules that can take output:
266           .....
267
268 RELATED FILES
269      (optional): The following files
270      {are needed for|are output from|give examples of|further document}
271      XDR writer:
272           .....
273
274
275 QUIRT MANUAL
276    WRITE_XDR                    AVS module XDR writer
277         numerical_expression    Input field = field
278         string_expression       name of xdr file to create
279         string_expression       extra header info (default "")
280         string_expression       text file with more header info (default none)
281         numerical_expression    NKI compression (default 0)
282         numerical_expression    Coordinates in header (boolean, default 0)
283         numerical_expression    Append to file (boolean, default 0)
284
285    WRITE_RAW                    AVS module Raw writer
286         numerical_expression    Input field = field
287         string_expression       name of file to write
288         numerical_expression    Offset; if not -1 (default) writes into file at offset
289
290    WRITE_RAW_LE                 AVS module Raw writer little endian
291         numerical_expression    Input field = field
292         string_expression       name of file to write
293         numerical_expression    Offset; if not -1 (default) writes into file at offset
294
295    WRITE_MEM_XDR
296         numerical_expression    Input field = field
297         numerical_expression    point to buffer to write xdr data into (use QUERY_MEM_XDR to find length)
298         string_expression       extra header info (default "")
299         string_expression       text file with more header info (default none)
300         numerical_expression    NKI compression (default 0)
301         numerical_expression    Coordinates in header (boolean, default 0)
302
303    QUERY_MEM_XDR
304         numerical_expression    Input field = field
305         name                    recieves required length for data
306         string_expression       extra header info (default "")
307         string_expression       text file with more header info (default none)
308         numerical_expression    NKI compression (default 0)
309         numerical_expression    Coordinates in header (boolean, default 0)
310
311 Release 1.0  19980212  Lambert Zijp             XDR writer  &  RAW writer
312 */
313 /************************************************************************/
314 /*                             INCLUDE FILES                            */
315 /************************************************************************/
316
317 #include <string.h>
318 #include <stdio.h>
319 #include <math.h>
320 #include <stdlib.h>
321 #include <limits.h>
322 #ifndef unix
323 #include <io.h>
324 #endif
325 #include <fcntl.h>
326 #include <errno.h>
327
328 #include <algorithm>
329
330 #ifdef WIN32
331 // don't use min() and max() macros indirectly defined by windows.h, 
332 // but use portable std::min() and std:max() instead
333 #ifndef NOMINMAX
334 #define NOMINMAX
335 #endif
336 #include <windows.h>
337 #endif
338
339 /************************************************************************/
340 /*                    DEFINES, ENUMERATED TYPES AND CONSTANTS           */
341 /************************************************************************/
342
343 //#undef fileno
344 //#define fileno _fileno
345 //
346 //#undef close
347 //#define close _close
348 //
349 //#undef open
350 //#define open _open
351 //
352 //#undef lseek
353 //#define lseek _lseek
354 //
355 //#undef creat
356 //#define creat _creat
357 //
358 #pragma pack (1)
359
360 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
361 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
362 // The type of structure is indicated as follows:
363 //
364 // iOrgSize==0: NKI_MODE2_64BITS
365 // otherwise  : NKI_MODE2
366 //
367 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
368
369 typedef struct
370 {
371   unsigned int iOrgSize;          /* in pixels (i.e. shorts) */
372   unsigned int iMode;             /* 1, 2, 3 or 4 */
373   unsigned int iCompressedSize;   /* in bytes, excluding header */
374   unsigned int iOrgCRC;           /* CRC of the data (no coords etc) */
375   unsigned int iCompressedCRC;    /* CRC of the compressed data, excluding this header */
376 } NKI_MODE2;
377
378 typedef struct
379 {
380   unsigned int iOrgSize;          /* in pixels (i.e. shorts) */
381   unsigned int iMode;             /* 1, 2, 3 or 4 */
382   unsigned int iCompressedSize;   /* in bytes, excluding header */
383   unsigned int iOrgCRC;           /* CRC of the data (no coords etc) */
384   unsigned int iCompressedCRC;    /* CRC of the compressed data, excluding this header */
385   unsigned int iPad;              /* unused */
386   Q_UINT64     i64OrgSize;        /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */ 
387   Q_UINT64     i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */ 
388   Q_UINT64     i64Future1;
389   Q_UINT64     i64Future2;
390 } NKI_MODE2_64BITS;
391
392 #pragma pack ()
393
394 // Changed next to static function in stead of macro so it can
395 // have a return value to check in the calling function.
396 // It could be made inline as well, but there is no real time
397 // punishment from the extra layer of function calls.
398
399 // note: some compilers do not like comments ending in a backslash.
400 // so use macro functions to exclude.
401
402
403 /************************************************************************/
404 /*                             GLOBAL VARIABLES                         */
405 /************************************************************************/
406
407 static const unsigned long CRC32_table[256] = {
408       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
409       0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
410       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
411       0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
412       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
413       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
414       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
415       0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
416       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
417       0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
418       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
419       0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
420       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
421       0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
422       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
423       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
424       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
425       0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
426       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
427       0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
428       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
429       0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
430       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
431       0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
432       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
433       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
434       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
435       0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
436       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
437       0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
438       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
439       0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
440       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
441       0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
442       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
443       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
444       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
445       0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
446       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
447       0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
448       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
449       0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
450       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
451 };
452
453 /************************************************************************/
454 /*                             MODULE FUNCTIONS                         */
455 /************************************************************************/
456
457 #ifdef __WATCOMC__
458 _WCRTLINK
459 #endif
460 int writefix(int file, const void *buf, unsigned int count)
461 { int j, k, total=0;
462
463   for (unsigned i=0; i<count; i+=16384)
464   { j = count - i;
465     if (j>16384) j=16384;
466
467     k=write(file, (char *)buf+i, j);
468     if (k < 0) return k;
469
470     total += k;
471
472     if (k != j) break;
473   }
474
475   return total;
476 }
477
478
479 /*
480   Version of write() that takes special action in case of
481   standard output.  Based on commented out macro above.
482   This function overloads the <cstdio> (or stdio.h for old style C++)
483   write() function.
484 */
485
486 // Like the original macro, we do /not/ want writefix from mbfield.c.
487 #ifdef write
488 #undef write
489 #endif
490 static int wxdr_write(int handle, const void * buf, unsigned len)
491 {
492   // if (handle == 1) // stdout
493   if (handle == fileno(stdout))
494   {
495 #ifdef WIN32
496     // Behave as C standard library write(): return number of bytes
497     // written or -1 and errno set on error.
498     fflush(stdout);
499     DWORD dwBytesWritten;
500     if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
501                    &dwBytesWritten, NULL))
502     {
503       // There is no simple 1-to-1 mapping between GetLastError()
504       // values that WriteFile() can return (quite a lot) and the two
505       // errno values that write() can return.  So return EACCES in
506       // almost all cases.
507       switch (GetLastError())
508       { case ERROR_INVALID_HANDLE:
509           errno = EBADF ; break;
510         default:
511           errno = EACCES; break;
512       }
513       return -1;
514     }
515     else
516       return (int)dwBytesWritten; // May still be < len!
517       // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
518       // WriteFile() may write UINT_MAX bytes at once.  But since
519       // int(UINT_MAX) == -1 this will pose an actual problem in the
520       // (far?) future.
521 #else // !WIN32
522     //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
523     const int iBytesWritten = write(handle, buf, len);
524     const int saveerrno = errno; // setmode() may change errno.
525     //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
526     errno = saveerrno;
527     return iBytesWritten;
528 #endif // !WIN32
529   }
530   else
531     return write(handle, buf, len);
532 }
533
534 /*
535   Checked write().
536   Behaves like win32 WriteFile() and returns a Boolean to indicate
537   success or failure, where failure almost invariably means disc full.
538
539   !!! SIDE EFFECT !!!
540
541   In case of failure, this function issues an AVS error message
542   and closes the file (if handle != 1).  It is up to the calling
543   function to return the AVS_ERROR state and before that do things
544   like close other files, free memory etc.  This way, there is less
545   chance of erroneously duplicated code, like in:
546     written = write(f, temp, strlen(temp));
547     if (written == -1 || written != strlen(temp))
548     { AVSerror(...);
549       if (f != fileno(stdout)) close(f);
550       return AVS_ERROR;
551     }
552     written = write(f, buf, buflength)
553     if (written == -1 || written != strlen(temp)) {
554       // oops, wrong length copy'n'pasted
555
556   If more elaborate error handling is needed then the calling
557   functuon should use the (overloaded) write() and act on its return
558   value (and the value of errno) accordingly.
559
560   It does /not/ close stdout.
561
562   !!! SIDE EFFECT !!!
563
564   Note that checked_write() takes a size_t for len, whereas write() takes
565   an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer, 
566   enabling more than UINT_MAX bytes to write at once.
567 */
568 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
569 { if (buffer && !handle)
570   { memcpy(*buffer, buf, len);
571     (*buffer) += len;
572     return true;
573   }
574   if (buffer && handle)
575   { (*buffer) += len;
576     return true;
577   }
578   else
579   { for(int i=0; i<2; i++)
580     { int byteswritten;
581       size_t remaining;
582       int chunksize;
583
584       //If write fails, test if not related to big buffer problem
585       //Bug report http://support.microsoft.com/kb/899149 entitled
586       //"You cannot call the fwrite function to write to a buffer
587       // that is larger than 64 MB in Visual C++ 2005,
588       // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
589       // NB: same thing for write function in binary mode
590       if (i==0)
591       { remaining = len;
592         // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times 
593         // to interpret the signed 32-bit return value correctly
594         while (remaining>0)
595         { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
596           byteswritten = wxdr_write(handle, buf, chunksize);
597           if (byteswritten == chunksize)
598             remaining -= chunksize;
599           else
600             break; // try writefix in the next round
601         }
602         if (remaining == 0)
603           return true;
604       }
605       else
606       { remaining = len;   
607         // call writefix (in mbfield.c) several times to interpret the signed 32-bit 
608         // return value correctly. writefix uses chunks of 16384 bytes
609         while (remaining>0)
610         { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
611           byteswritten = writefix(handle, buf, chunksize);
612           if (byteswritten == chunksize)
613             remaining -= chunksize;
614           else
615             break; // even writefix failed: return error        
616         }
617         if (remaining == 0)
618           return true;
619       }
620     }
621     // Note: file is open in binary mode, no need to compensate
622     // for a value of byteswritten > len due to \n -> \r\n conversions.
623     // (write() on a text stream is implementation dependent.)
624     if (handle != fileno(stdout)) close(handle);
625     AVSerror("Avs_wxdr: write failed, disk full?");
626     return false;
627   }
628 }
629
630 /* coder for NKI private compressed pixel data
631    arguments: dest    = (in) points to area where compressed destination data is written (byte)
632               src     = (in) points to uncompressed source data (short)
633               npixels = (in) number of pixels to compress
634
635    The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
636
637    if iMode == 1 then
638    - The first 4 bytes contain the number of short-int pixels
639    - The following 4 bytes contain iMode=1
640    - The rest is the compressed image
641
642    if iMode == 2 then
643    - The first 4 bytes contain the number of short-int pixels
644    - The following 4 bytes contain iMode=2
645    - The following 4 bytes contain the size of the compressed image (in bytes)
646    - The following 4 bytes contain the CRC of the original image
647    - The following 4 bytes contain the CRC of the compressed image
648    - The rest is the compressed image
649    - The compressed size will be even (padded by a zero if necessary).
650
651    if iMode == 3 then
652    - The first 4 bytes contain the number of short-int pixels
653    - The following 4 bytes contain iMode=3
654    - The rest is the compressed image, including 4 bit differences
655
656    if iMode == 4 then
657    - The first 4 bytes contain the number of short-int pixels
658    - The following 4 bytes contain iMode=4
659    - The following 4 bytes contain the size of the compressed image (in bytes)
660    - The following 4 bytes contain the CRC of the original image
661    - The following 4 bytes contain 0
662    - The rest is the compressed image, including 4 bit differences
663    - The compressed size will be even (padded by a zero if necessary).
664
665    iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
666    iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
667 */
668
669 // optimized settings for the 4 bit run compressor (mode 3 and 4)
670
671 #define MINZEROS 5              // shortest RLE (2 byte overhead, but breaks 4bit run)
672 #define MIN4BIT  6              // shortest 4 bit run (6 bytes compressed to 5 bytes)
673
674 // This internal routine converts an 8 bit difference string into a 4 bit one
675 static signed char *recompress4bit(int n, signed char *dest)
676 { signed char *p, *q;
677   int val;
678
679   n = n & 0xfe;
680   dest -= n;
681   p = dest;
682   val = (((int)p[0])<<4) | (p[1]&15);
683   p += 2;
684   *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
685   *dest++ = (signed char)n;
686   q = dest++;
687   n -= 2;
688   while(n>0)
689   { *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
690     p += 2;
691     n -= 2;
692   }
693   q[0] = (signed char)val;
694
695   return dest;
696 }
697
698
699 static size_t nki_private_compress(signed char  *dest, short int  *src, size_t npixels, int iMode)
700 { unsigned long         iCRC;
701   unsigned long         iCRC2;
702   unsigned int          iHeaderSize=8;                      // value for iMode==1 and iMode==3
703   register int          val;
704   size_t                i,j;
705   NKI_MODE2*            pHeader = (NKI_MODE2*)dest;
706   NKI_MODE2_64BITS*     pHeader_64bits = (NKI_MODE2_64BITS*)dest;
707   size_t                iBufferSize;
708
709   iBufferSize = (npixels / 2) * 3;                          // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
710
711   /* Up till now only Mode=1 .. 4 are supported */
712   if ((iMode < 1) || (iMode > 4))
713     return 0;
714
715   /* Create the header */
716   pHeader->iMode = iMode;
717
718   if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX)         // On a 64 bits OS we want to store files>4GB 
719   { pHeader_64bits->iOrgSize   = 0;                         // This indicates>4GB file (0-vector is not compressed)
720     pHeader_64bits->i64OrgSize = npixels;    
721     iHeaderSize = sizeof(NKI_MODE2_64BITS);
722     dest += sizeof(NKI_MODE2_64BITS);
723   }
724   else
725   { pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
726
727     if (iMode==2 || iMode==4)
728       iHeaderSize = sizeof(NKI_MODE2);
729     dest += iHeaderSize;
730   }
731
732   /* Create the compressed image */
733
734   if (iMode == 1)
735   { *(short int *)dest = *src;
736     dest+=2;
737
738     npixels--;
739
740     do
741     { val = src[1] - src[0];
742       src++;
743
744       if (val == 0)                            /* run length-encode zero differences */
745       { for (i=2;; i++)
746         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
747           { if (i==2)
748               *dest++=0;
749             else
750             { *dest++  =  -128; // hexadecimal 0x80
751               *dest++  = (signed char)(i-1);
752               npixels -= (i-2);
753               src     += (i-2);
754             }
755             break;
756           }
757         }
758       }
759       else if (val >= -64 && val <= 63)         /* small difference coded as one byte */
760       { *dest = (signed char)val;
761         dest++;
762       }
763       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
764       { dest[0] = (signed char)((val>>8) ^ 0x40);
765         dest[1] = (signed char)val;
766         dest+=2;
767       }
768       else                                      /* if very large differences code abs val as three bytes */
769       { *dest++ = 0x7F;
770         *dest++ = (signed char)(src[0]>>8);
771         *dest++ = (signed char)(src[0]);
772       }
773       /* Are we beyond the allocated memory? */
774       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
775         return 0;
776     }
777     while (--npixels);
778   }
779
780   else if (iMode == 2)
781   { iCRC  = 0;
782     iCRC2 = 0;
783
784     *(short int *)dest = val = *src;
785     iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val    ] ^ ((iCRC2 >> 8));
786     iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
787     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) val    ] ^ ((iCRC  >> 8));
788     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(val>>8)] ^ ((iCRC  >> 8));
789     dest+=2;
790     npixels--;
791
792     do
793     { val = src[1] - src[0];
794       src++;
795       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
796       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
797
798       if (val == 0)                            /* run length-encode zero differences */
799       { for (i=2;; i++)
800         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
801           { if (i==2)
802             { *dest++=0;
803               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0    ] ^ ((iCRC2 >> 8));
804             }
805             else
806             { *dest++  =  -128; // hexadecimal 0x80
807               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
808               *dest++  = (signed char)(i-1);
809               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
810               npixels -= (i-2);
811
812               for (j=0; j<i-2; j++)
813               { src++;
814                 iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
815                 iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
816               }
817             }
818             break;
819           }
820         }
821       }
822       else if (val >= -64 && val <= 63)         /* small difference coded as one byte */
823       { *dest = (signed char)val;
824         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
825         dest++;
826       }
827       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
828       { dest[0] = (signed char)((val>>8) ^ 0x40);
829         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
830         dest[1] = (signed char)val;
831         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
832         dest+=2;
833       }
834       else                                      /* if very large differences code abs val as three bytes */
835       { dest[0] = 0x7F;
836         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f                   ] ^ ((iCRC2 >> 8));
837         val     = src[0];
838         dest[1] = (signed char)(val>>8);
839         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
840         dest[2] = (signed char)val;
841         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
842         dest+=3;
843       }
844       /* Are we beyond the allocated memory? */
845       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
846         return 0;
847     }
848     while (--npixels);
849     
850     if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
851       pHeader->iCompressedSize = 
852         (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
853     else                                                       // store 64 bit number in extended structure
854       pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
855
856     /* Pad it to get an even length */
857     if (pHeader->iCompressedSize & 1)
858     { *dest++ = 0;
859       iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
860       pHeader->iCompressedSize++;
861     }
862
863     pHeader->iOrgCRC        = iCRC;
864     pHeader->iCompressedCRC = iCRC2;
865   }
866
867   /* Create the compressed image - compressor with added 4 bit run */
868
869   else if (iMode == 3)
870   { int n4bit=0;
871     *(short int *)dest = *src;
872     dest+=2;
873     npixels--;
874
875     do
876     { val = src[1] - src[0];
877       src++;
878
879       if (val == 0)                             /* run length-encode zero differences */
880       { for (i=2;; i++)
881         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
882           { if (i<=MINZEROS)                    /* too short run -> write zeros */
883             { for (j=0; j<i-1; j++)
884               { *dest++=0;
885                 n4bit++;
886
887                 if(n4bit>=254)                  /* maximum length 4 bit run */
888                 { dest  = recompress4bit(n4bit, dest);
889                   n4bit = 0;
890                 }
891               }
892             }
893             else
894             { if (n4bit>=MIN4BIT)               /* end (and write) 4 bit run */
895                 dest  = recompress4bit(n4bit, dest);
896
897               n4bit=0;
898               *dest++  = -128; // hexadecimal 0x80
899               *dest++  = (signed char)(i-1);
900             }
901
902             npixels -= (i-2);
903             src     += (i-2);
904             break;
905           }
906         }
907       }
908       else if (val >= -63 && val <= 63)         /* small difference coded as one byte */
909       { if (val >= -8 && val <= 7)
910         { *dest++ = (signed char)val;
911           n4bit++;
912
913           if(n4bit>=254)                        /* maximum length 4 bit run */
914           { dest  = recompress4bit(n4bit, dest);
915             n4bit=0;
916           }
917         }
918         else if(n4bit>=MIN4BIT)                 /* end and write 4 bit run */
919         { j = val;
920           dest  = recompress4bit(n4bit, dest);
921           n4bit=0;
922           *dest++ = (signed char)j;
923         }
924         else
925         { *dest++ = (signed char)val;                   /* end 4 bit run */
926            n4bit  = 0;
927         }
928       }
929       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
930       { j = val;
931
932         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
933           dest  = recompress4bit(n4bit, dest);
934
935         n4bit=0;
936         dest[0] = (signed char)((j>>8) ^ 0x40);
937         dest[1] = (signed char)j;
938         dest+=2;
939       }
940       else                                      /* if very large differences code abs val as three bytes */
941       { j = src[0];
942
943         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
944           dest  = recompress4bit(n4bit, dest);
945
946         n4bit=0;
947         *dest++ = 0x7F;
948         *dest++ = (signed char)(j>>8);
949         *dest++ = (signed char)j;
950       }
951       /* Are we beyond the allocated memory? */
952       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
953         return 0;
954     }
955     while (--npixels);
956   }
957
958   /* Create the compressed image - compressor with added 4 bit run and CRC */
959
960   else if (iMode == 4)
961   { int n4bit=0;
962     iCRC  = 0;
963
964     *(short int *)dest = val = *src;
965     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) val    ] ^ ((iCRC  >> 8));
966     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(val>>8)] ^ ((iCRC  >> 8));
967     dest+=2;
968     npixels--;
969
970     do
971     { val = src[1] - src[0];
972       src++;
973       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
974       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
975
976       if (val == 0)                             /* run length-encode zero differences */
977       { for (i=2;; i++)
978         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
979           { if (i<=MINZEROS)                    /* too short run -> write zeros */
980             { for (j=0; j<i-1; j++)
981               { *dest++=0;
982                 n4bit++;
983
984                 if(n4bit>=254)                  /* maximum length 4 bit run */
985                 { dest  = recompress4bit(n4bit, dest);
986                   n4bit = 0;
987                 }
988               }
989             }
990             else
991             { if (n4bit>=MIN4BIT)               /* end (and write) 4 bit run */
992                 dest  = recompress4bit(n4bit, dest);
993
994               n4bit=0;
995               *dest++  = -128; // hexadecimal 0x80
996               *dest++  = (signed char)(i-1);
997             }
998
999             npixels -= (i-2);
1000             for (j=0; j<i-2; j++)
1001             { src++;
1002               iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
1003               iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
1004             }
1005             break;
1006           }
1007         }
1008       }
1009       else if (val >= -63 && val <= 63)         /* small difference coded as one byte */
1010       { if (val >= -8 && val <= 7)
1011         { *dest++ = (signed char)val;
1012           n4bit++;
1013
1014           if(n4bit>=254)                        /* maximum length 4 bit run */
1015           { dest  = recompress4bit(n4bit, dest);
1016             n4bit=0;
1017           }
1018         }
1019         else if(n4bit>=MIN4BIT)                 /* end and write 4 bit run */
1020         { j = val;
1021           dest  = recompress4bit(n4bit, dest);
1022           n4bit=0;
1023           *dest++ = (signed char)j;
1024         }
1025         else
1026         { *dest++ = (signed char)val;           /* end 4 bit run */
1027            n4bit  = 0;
1028         }
1029       }
1030       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
1031       { j = val;
1032
1033         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
1034           dest  = recompress4bit(n4bit, dest);
1035
1036         n4bit=0;
1037         dest[0] = (signed char)((j>>8) ^ 0x40);
1038         dest[1] = (signed char)j;
1039         dest+=2;
1040       }
1041       else                                      /* if very large differences code abs val as three bytes */
1042       { j = src[0];
1043
1044         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
1045           dest  = recompress4bit(n4bit, dest);
1046
1047         n4bit=0;
1048         *dest++ = 0x7F;
1049         *dest++ = (signed char)(j>>8);
1050         *dest++ = (signed char)j;
1051       }
1052       /* Are we beyond the allocated memory? */
1053       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
1054         return 0;
1055     }
1056     while (--npixels);
1057
1058     if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
1059       pHeader->iCompressedSize = 
1060         (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
1061     else                                                       // store 64 bit number in extended structure
1062     { pHeader_64bits->iCompressedSize = 0;
1063       pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
1064     }
1065
1066     /* Pad it to get an even length */
1067     if (pHeader->iCompressedSize & 1)
1068     { *dest++ = 0;
1069       pHeader->iCompressedSize++;
1070     }
1071
1072     pHeader->iOrgCRC        = iCRC;
1073     pHeader->iCompressedCRC = 0;
1074   }
1075
1076   return dest - (signed char*)pHeader;
1077 }
1078
1079
1080 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
1081                                    int offset, char bLittleEndian, int iNkiCompression,
1082                                    int wcoords, int append, int getsize, char *tobuffer, const void* data)
1083 { AVSINT   total=1;
1084   unsigned int      i;
1085   AVSINT   coords=0;
1086   int      f=0;
1087   char     temp[256];
1088   char     *c;
1089   char     cSwap;
1090   FILE     *fp;
1091   long     swap_test = 0x1000000;
1092   signed char*  pCompressed = NULL;
1093   size_t   FilePos=0;
1094   char     **buffer = NULL;
1095   int      len=0;
1096   char     *buf2;
1097   size_t   slen;
1098
1099   if (bLittleEndian)
1100     swap_test = 0x00000001;
1101
1102   if (getsize)
1103   { swap_test = 0xffffffff;     // never swap to save time
1104     buffer    = (char **) &len;
1105     f         = 1;
1106   }
1107
1108   if (tobuffer)
1109   { buf2   = (char *)tobuffer;
1110     buffer = &buf2;
1111     f      = 0;
1112   }
1113
1114   for (i=0; i<GetNumberOfDimensions(); i++)
1115   { total  *= GetDimensions(i);
1116     coords += GetDimensions(i);
1117   }
1118
1119   /* Try allocate the compressed fielddata - compression disabled if alloc fails */
1120   if ((iNkiCompression > 0) &&
1121         (GetComponentType() == itk::ImageIOBase::SHORT) &&
1122         (GetPixelType() == itk::ImageIOBase::SCALAR))
1123   { pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
1124     if (pCompressed==NULL)
1125     { iNkiCompression = 0;
1126       AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
1127     }
1128   }
1129
1130   if (!(tobuffer || getsize))
1131   { if (offset != -1)
1132     { f = open(file, O_RDWR, 0);
1133       if (f < 0)
1134       {
1135         AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
1136         free(pCompressed);
1137         return AVS_ERROR;
1138       }
1139       lseek(f, offset, SEEK_SET);
1140     }
1141     else
1142     { if (strlen(file)==0)
1143         f = fileno(stdout);
1144       else
1145       { if (append)
1146           f = open(file, O_RDWR | O_APPEND, 0);
1147         else
1148           f = creat(file, S_IWRITE | S_IREAD);
1149       }
1150
1151       if (f < 0)
1152       { AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
1153         free(pCompressed);
1154         return AVS_ERROR;
1155       }
1156     }
1157   }
1158
1159   if (!raw)
1160   { sprintf(temp, "# AVS wants to have the first line starting with its name\n");
1161     slen = strlen(temp);
1162
1163     if (!checked_write(f, temp, slen, buffer))
1164     { free(pCompressed);
1165       return AVS_ERROR;
1166     }
1167     FilePos += slen;
1168
1169     slen = strlen(headerinfo);
1170     if (slen && !checked_write(f, headerinfo, slen, buffer))
1171     { free(pCompressed);
1172       return AVS_ERROR;
1173     }
1174     FilePos += slen;
1175
1176     if (!checked_write(f, "\n", 1, buffer))
1177     { free(pCompressed);
1178       return AVS_ERROR;
1179     }
1180     FilePos++;
1181
1182     if (strlen(headerfile))
1183     { fp = fopen(headerfile, "rt");
1184       if (fp)
1185       { for (;;)
1186         { if (fgets(temp, 255, fp) == NULL) break;
1187           slen = strlen(temp);
1188           if (!checked_write(f, temp, slen, buffer))
1189           { fclose(fp);
1190             free(pCompressed);
1191             return AVS_ERROR;
1192           }
1193           FilePos += slen;
1194         }
1195         fclose(fp);
1196         if (!checked_write(f, "\n", 1, buffer))
1197         { free(pCompressed);
1198           return AVS_ERROR;
1199         }
1200         FilePos++;
1201       }
1202     }
1203
1204     sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
1205     slen = strlen(temp);
1206     if (!checked_write(f, temp, slen, buffer))
1207     { free(pCompressed);
1208       return AVS_ERROR;
1209     }
1210     FilePos += slen;
1211   }
1212
1213   for (i=0; i<GetNumberOfDimensions(); i++)
1214   { if (!raw)
1215     { sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
1216       slen = strlen(temp);
1217       if (!checked_write(f, temp, slen, buffer))
1218       { free(pCompressed);
1219         return AVS_ERROR;
1220       }
1221       FilePos += slen;
1222     }
1223   }
1224
1225   if (!raw)
1226   { sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
1227     slen = strlen(temp);
1228     if (!checked_write(f, temp, slen, buffer))
1229     { free(pCompressed);
1230       return AVS_ERROR;
1231     }
1232     FilePos += slen;
1233
1234     sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
1235     slen = strlen(temp);
1236     if (!checked_write(f, temp, slen, buffer))
1237     { free(pCompressed);
1238       return AVS_ERROR;
1239     }
1240     FilePos += slen;
1241
1242     switch(GetComponentType())
1243     { case itk::ImageIOBase::CHAR   : strcpy(temp, "data=byte\n"); break;
1244       case itk::ImageIOBase::SHORT  : strcpy(temp, "data=xdr_short\n"); break;
1245       case itk::ImageIOBase::INT    : strcpy(temp, "data=xdr_integer\n"); break;
1246       case itk::ImageIOBase::FLOAT  : strcpy(temp, "data=xdr_real\n"); break;
1247       case itk::ImageIOBase::DOUBLE : strcpy(temp, "data=xdr_double\n"); break;
1248       default               : if (f != fileno(stdout)) close(f);
1249                               free(pCompressed);
1250                               return AVS_ERROR;
1251     }
1252     slen = strlen(temp);
1253     if (!checked_write(f, temp, slen, buffer))
1254     { free(pCompressed);
1255       return AVS_ERROR;
1256     }
1257     FilePos += slen;
1258   }
1259
1260
1261   //FilePos = tell(f);
1262 ONCE_AGAIN:
1263
1264
1265   //switch(input->uniform)
1266   //{ case UNIFORM     : 
1267   strcpy(temp, "field=uniform\n");
1268   coords = GetNumberOfDimensions() * 2;
1269                 //       break;
1270   //  case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1271                 //       break;
1272   //  case IRREGULAR   : strcpy(temp, "field=irregular\n");
1273                 //       coords = total * input->nspace;
1274                 //       break;
1275   //  default          : if (f != fileno(stdout)) close(f);
1276   //                     free(pCompressed);
1277   //                           return;
1278   //}
1279
1280   if (!raw)
1281   { if (!checked_write(f, temp, strlen(temp), buffer))
1282     { free(pCompressed);
1283       return AVS_ERROR;
1284     }
1285
1286     if ((iNkiCompression > 0) &&
1287       (GetComponentType() == itk::ImageIOBase::SHORT) &&
1288       (GetPixelType() == itk::ImageIOBase::SCALAR))
1289     { sprintf(temp, "nki_compression=%d", iNkiCompression);
1290       if (!checked_write(f, temp, strlen(temp), buffer))
1291       { free(pCompressed);
1292         return AVS_ERROR;
1293       }
1294     }
1295
1296     temp[0] = temp[1] = 12;
1297     if (!checked_write(f, temp, 2, buffer))
1298     { free(pCompressed);
1299       return AVS_ERROR;
1300     }
1301   }
1302
1303   total *= GetPixelSize();
1304
1305   if ((!raw) && (iNkiCompression > 0) &&
1306         (GetComponentType() == itk::ImageIOBase::SHORT) &&
1307         (GetPixelType() == itk::ImageIOBase::SCALAR))
1308   { size_t      iCompressedLength;
1309
1310     iCompressedLength = nki_private_compress(pCompressed,
1311       (short int *)(data), total/2, iNkiCompression);
1312
1313     if (iCompressedLength > 0)
1314     { if (!checked_write(f, pCompressed, iCompressedLength, buffer))
1315       { free(pCompressed);
1316         return AVS_ERROR;
1317       }
1318       free(pCompressed);
1319       goto WRITE_COORDS;
1320     }
1321
1322     /* Compressionratio was poor: let's write uncompressed */
1323     iNkiCompression = 0;
1324     total /= 2;
1325     free(pCompressed);
1326     pCompressed = NULL;
1327     lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1328     goto ONCE_AGAIN;
1329   }
1330
1331   /* swap data if required (xdr is low-endian) */
1332
1333   if (!(*(char *)(&swap_test)))
1334   { if (GetComponentSize()==2)
1335     { c = (char *)data;
1336       for (i=0; i<total; i+=2)
1337       { cSwap  = c[i];  c[i]   = c[i+1]; c[i+1] = cSwap;
1338       }
1339     }
1340     else if (GetComponentSize()==4)
1341     { c = (char *)data;
1342       for (i=0; i<total; i+=4)
1343       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1344         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1345       }
1346     }
1347     else if (GetComponentSize()==8)
1348     { c = (char *)data;
1349       for (i=0; i<total; i+=8)
1350       { cSwap = c[i];   c[i]   = c[i+7]; c[i+7] = cSwap;
1351         cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1352         cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1353         cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1354       }
1355     }
1356   }
1357
1358   if (total)
1359   { if (!checked_write(f, data, total, buffer))
1360       return AVS_ERROR;
1361   }
1362
1363   /* swap data back if was swapped before writing */
1364
1365   if (!(*(char *)(&swap_test)))
1366   { if (GetComponentSize()==2)
1367     { c = (char *)data;
1368       for (i=0; i<total; i+=2)
1369       { cSwap = c[i];   c[i]   = c[i+1]; c[i+1] = cSwap;
1370       }
1371     }
1372     else if (GetComponentSize()==4)
1373     { c = (char *)data;
1374       for (i=0; i<total; i+=4)
1375       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1376         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1377       }
1378     }
1379     else if (GetComponentSize()==8)
1380     { c = (char *)data;
1381       for (i=0; i<total; i+=8)
1382       { cSwap = c[i];   c[i]   = c[i+7]; c[i+7] = cSwap;
1383         cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1384         cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1385         cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1386       }
1387     }
1388   }
1389
1390 WRITE_COORDS:
1391   float *points;
1392   points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1393   for (i=0; i<GetNumberOfDimensions(); i++)
1394   {
1395     points[i*2  ] = 0.1 *  GetOrigin(i);
1396     points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1397   }
1398
1399   if (coords && !raw)                           /* write AVS coordinates ? */
1400   { coords *= sizeof(float);
1401     if (!(*(char *)(&swap_test)))
1402     { c = (char *)(points);              /* swap bytes */
1403       for (i=0; i<coords; i+=4)
1404       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1405         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1406       }
1407     }
1408
1409     if (!checked_write(f, points, coords, buffer))
1410       return AVS_ERROR;
1411
1412     if (!(*(char *)(&swap_test)))
1413     { c = (char *)(points);              /* swap bytes back */
1414       for (i=0; i<coords; i+=4)
1415       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1416         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1417       }
1418     }
1419   }
1420
1421   if (!(tobuffer || getsize))
1422     if (f != fileno(stdout)) close(f);
1423
1424   if (getsize) return;
1425   return AVS_OK;
1426 }