]> Creatis software - clitk.git/blob - common/clitkXdrImageIOWriter.cxx
*** empty log message ***
[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 #pragma pack (1)
344
345 // Fields with data size>8GB (having UINT_MAX short pixels) cannot be compressed using
346 // NKI_MODE2 struct because iOrgSize has type "unsigned int". In that case use NKI_MODE2_64BITS.
347 // The type of structure is indicated as follows:
348 //
349 // iOrgSize==0: NKI_MODE2_64BITS
350 // otherwise  : NKI_MODE2
351 //
352 // Compression modes 1 and 3 (without CRCs) only use the first 2 members (iOrgSize and iMode).
353
354 typedef struct
355 {
356   unsigned int iOrgSize;          /* in pixels (i.e. shorts) */
357   unsigned int iMode;             /* 1, 2, 3 or 4 */
358   unsigned int iCompressedSize;   /* in bytes, excluding header */
359   unsigned int iOrgCRC;           /* CRC of the data (no coords etc) */
360   unsigned int iCompressedCRC;    /* CRC of the compressed data, excluding this header */
361 } NKI_MODE2;
362
363 typedef struct
364 {
365   unsigned int iOrgSize;          /* in pixels (i.e. shorts) */
366   unsigned int iMode;             /* 1, 2, 3 or 4 */
367   unsigned int iCompressedSize;   /* in bytes, excluding header */
368   unsigned int iOrgCRC;           /* CRC of the data (no coords etc) */
369   unsigned int iCompressedCRC;    /* CRC of the compressed data, excluding this header */
370   unsigned int iPad;              /* unused */
371   Q_UINT64     i64OrgSize;        /* used for more than UINT_MAX pixels, indicated by iOrgSize==0 (0-vector not compressed) */ 
372   Q_UINT64     i64CompressedSize; /* value in BYTES, used for more than UINT_MAX PIXELS, indicated by iCompressedSize==0 */ 
373   Q_UINT64     i64Future1;
374   Q_UINT64     i64Future2;
375 } NKI_MODE2_64BITS;
376
377 #pragma pack ()
378
379 // Changed next to static function in stead of macro so it can
380 // have a return value to check in the calling function.
381 // It could be made inline as well, but there is no real time
382 // punishment from the extra layer of function calls.
383
384 // note: some compilers do not like comments ending in a backslash.
385 // so use macro functions to exclude.
386
387
388 /************************************************************************/
389 /*                             GLOBAL VARIABLES                         */
390 /************************************************************************/
391
392 static const unsigned long CRC32_table[256] = {
393       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
394       0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
395       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
396       0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
397       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
398       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
399       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
400       0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
401       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
402       0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
403       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
404       0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
405       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
406       0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
407       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
408       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
409       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
410       0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
411       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
412       0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
413       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
414       0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
415       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
416       0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
417       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
418       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
419       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
420       0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
421       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
422       0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
423       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
424       0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
425       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
426       0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
427       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
428       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
429       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
430       0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
431       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
432       0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
433       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
434       0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
435       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
436 };
437
438 /************************************************************************/
439 /*                             MODULE FUNCTIONS                         */
440 /************************************************************************/
441
442 #ifdef __WATCOMC__
443 _WCRTLINK
444 #endif
445 int writefix(int file, const void *buf, unsigned int count)
446 { int j, k, total=0;
447
448   for (unsigned i=0; i<count; i+=16384)
449   { j = count - i;
450     if (j>16384) j=16384;
451
452     k=write(file, (char *)buf+i, j);
453     if (k < 0) return k;
454
455     total += k;
456
457     if (k != j) break;
458   }
459
460   return total;
461 }
462
463
464 /*
465   Version of write() that takes special action in case of
466   standard output.  Based on commented out macro above.
467   This function overloads the <cstdio> (or stdio.h for old style C++)
468   write() function.
469 */
470
471 // Like the original macro, we do /not/ want writefix from mbfield.c.
472 #ifdef write
473 #undef write
474 #endif
475 static int wxdr_write(int handle, const void * buf, unsigned len)
476 {
477   // if (handle == 1) // stdout
478   if (handle == fileno(stdout))
479   {
480 #ifdef WIN32
481     // Behave as C standard library write(): return number of bytes
482     // written or -1 and errno set on error.
483     fflush(stdout);
484     DWORD dwBytesWritten;
485     if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len,
486                    &dwBytesWritten, NULL))
487     {
488       // There is no simple 1-to-1 mapping between GetLastError()
489       // values that WriteFile() can return (quite a lot) and the two
490       // errno values that write() can return.  So return EACCES in
491       // almost all cases.
492       switch (GetLastError())
493       { case ERROR_INVALID_HANDLE:
494           errno = EBADF ; break;
495         default:
496           errno = EACCES; break;
497       }
498       return -1;
499     }
500     else
501       return (int)dwBytesWritten; // May still be < len!
502       // And... write() may write a maximum of UINT_MAX-1 bytes, whereas
503       // WriteFile() may write UINT_MAX bytes at once.  But since
504       // int(UINT_MAX) == -1 this will pose an actual problem in the
505       // (far?) future.
506 #else // !WIN32
507     //const int oldmode = setmode(handle, O_BINARY);//commented out by joel
508     const int iBytesWritten = write(handle, buf, len);
509     const int saveerrno = errno; // setmode() may change errno.
510     //if (oldmode != -1) setmode(handle, oldmode); //commented out by joel
511     errno = saveerrno;
512     return iBytesWritten;
513 #endif // !WIN32
514   }
515   else
516     return write(handle, buf, len);
517 }
518
519 /*
520   Checked write().
521   Behaves like win32 WriteFile() and returns a Boolean to indicate
522   success or failure, where failure almost invariably means disc full.
523
524   !!! SIDE EFFECT !!!
525
526   In case of failure, this function issues an AVS error message
527   and closes the file (if handle != 1).  It is up to the calling
528   function to return the AVS_ERROR state and before that do things
529   like close other files, free memory etc.  This way, there is less
530   chance of erroneously duplicated code, like in:
531     written = write(f, temp, strlen(temp));
532     if (written == -1 || written != strlen(temp))
533     { AVSerror(...);
534       if (f != fileno(stdout)) close(f);
535       return AVS_ERROR;
536     }
537     written = write(f, buf, buflength)
538     if (written == -1 || written != strlen(temp)) {
539       // oops, wrong length copy'n'pasted
540
541   If more elaborate error handling is needed then the calling
542   functuon should use the (overloaded) write() and act on its return
543   value (and the value of errno) accordingly.
544
545   It does /not/ close stdout.
546
547   !!! SIDE EFFECT !!!
548
549   Note that checked_write() takes a size_t for len, whereas write() takes
550   an unsigned int of 4 bytes. On a 64 bits OS a size_t will be an 8 byte integer, 
551   enabling more than UINT_MAX bytes to write at once.
552 */
553 static bool checked_write(int handle, const void * buf, size_t len, char **buffer)
554 { if (buffer && !handle)
555   { memcpy(*buffer, buf, len);
556     (*buffer) += len;
557     return true;
558   }
559   if (buffer && handle)
560   { (*buffer) += len;
561     return true;
562   }
563   else
564   { for(int i=0; i<2; i++)
565     { int byteswritten;
566       size_t remaining;
567       int chunksize;
568
569       //If write fails, test if not related to big buffer problem
570       //Bug report http://support.microsoft.com/kb/899149 entitled
571       //"You cannot call the fwrite function to write to a buffer
572       // that is larger than 64 MB in Visual C++ 2005,
573       // in Visual C++ .NET 2003, or in Visual C++ .NET 2002"
574       // NB: same thing for write function in binary mode
575       if (i==0)
576       { remaining = len;
577         // call wxdr_write (for handle!=fileno(stdout) a wrapper for write) several times 
578         // to interpret the signed 32-bit return value correctly
579         while (remaining>0)
580         { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
581           byteswritten = wxdr_write(handle, buf, chunksize);
582           if (byteswritten == chunksize)
583             remaining -= chunksize;
584           else
585             break; // try writefix in the next round
586         }
587         if (remaining == 0)
588           return true;
589       }
590       else
591       { remaining = len;   
592         // call writefix (in mbfield.c) several times to interpret the signed 32-bit 
593         // return value correctly. writefix uses chunks of 16384 bytes
594         while (remaining>0)
595         { chunksize = (int)std::min(remaining, (size_t)INT_MAX);
596           byteswritten = writefix(handle, buf, chunksize);
597           if (byteswritten == chunksize)
598             remaining -= chunksize;
599           else
600             break; // even writefix failed: return error        
601         }
602         if (remaining == 0)
603           return true;
604       }
605     }
606     // Note: file is open in binary mode, no need to compensate
607     // for a value of byteswritten > len due to \n -> \r\n conversions.
608     // (write() on a text stream is implementation dependent.)
609     if (handle != fileno(stdout)) close(handle);
610     AVSerror("Avs_wxdr: write failed, disk full?");
611     return false;
612   }
613 }
614
615 /* coder for NKI private compressed pixel data
616    arguments: dest    = (in) points to area where compressed destination data is written (byte)
617               src     = (in) points to uncompressed source data (short)
618               npixels = (in) number of pixels to compress
619
620    The return value is the number of bytes in the compressed data (maximal 3*npixels+10, typical 0.52*npixels)
621
622    if iMode == 1 then
623    - The first 4 bytes contain the number of short-int pixels
624    - The following 4 bytes contain iMode=1
625    - The rest is the compressed image
626
627    if iMode == 2 then
628    - The first 4 bytes contain the number of short-int pixels
629    - The following 4 bytes contain iMode=2
630    - The following 4 bytes contain the size of the compressed image (in bytes)
631    - The following 4 bytes contain the CRC of the original image
632    - The following 4 bytes contain the CRC of the compressed image
633    - The rest is the compressed image
634    - The compressed size will be even (padded by a zero if necessary).
635
636    if iMode == 3 then
637    - The first 4 bytes contain the number of short-int pixels
638    - The following 4 bytes contain iMode=3
639    - The rest is the compressed image, including 4 bit differences
640
641    if iMode == 4 then
642    - The first 4 bytes contain the number of short-int pixels
643    - The following 4 bytes contain iMode=4
644    - The following 4 bytes contain the size of the compressed image (in bytes)
645    - The following 4 bytes contain the CRC of the original image
646    - The following 4 bytes contain 0
647    - The rest is the compressed image, including 4 bit differences
648    - The compressed size will be even (padded by a zero if necessary).
649
650    iMode 1 and iMode 2 are identical, except for the CRC data that is included for iMode 2
651    iMode 3 and iMode 4 are identical, except for the CRC data that is included for iMode 4
652 */
653
654 // optimized settings for the 4 bit run compressor (mode 3 and 4)
655
656 #define MINZEROS 5              // shortest RLE (2 byte overhead, but breaks 4bit run)
657 #define MIN4BIT  6              // shortest 4 bit run (6 bytes compressed to 5 bytes)
658
659 // This internal routine converts an 8 bit difference string into a 4 bit one
660 static signed char *recompress4bit(int n, signed char *dest)
661 { signed char *p, *q;
662   int val;
663
664   n = n & 0xfe;
665   dest -= n;
666   p = dest;
667   val = (((int)p[0])<<4) | (p[1]&15);
668   p += 2;
669   *dest++ = -0x40; // 192 (0xc0) does not fit between -128..127: maps to -64 (0x40) in 2's complement
670   *dest++ = (signed char)n;
671   q = dest++;
672   n -= 2;
673   while(n>0)
674   { *dest++ = (signed char)((((int)p[0])<<4) | (p[1]&15));
675     p += 2;
676     n -= 2;
677   }
678   q[0] = (signed char)val;
679
680   return dest;
681 }
682
683
684 static size_t nki_private_compress(signed char  *dest, short int  *src, size_t npixels, int iMode)
685 { unsigned long         iCRC;
686   unsigned long         iCRC2;
687   unsigned int          iHeaderSize=8;                      // value for iMode==1 and iMode==3
688   register int          val;
689   size_t                i,j;
690   NKI_MODE2*            pHeader = (NKI_MODE2*)dest;
691   NKI_MODE2_64BITS*     pHeader_64bits = (NKI_MODE2_64BITS*)dest;
692   size_t                iBufferSize;
693
694   iBufferSize = (npixels / 2) * 3;                          // Buffer is sizeof(NKI_MODE2_64BITS) + 10 bytes larger
695
696   /* Up till now only Mode=1 .. 4 are supported */
697   if ((iMode < 1) || (iMode > 4))
698     return 0;
699
700   /* Create the header */
701   pHeader->iMode = iMode;
702
703   if (sizeof(int*)>sizeof(int) && npixels>UINT_MAX)         // On a 64 bits OS we want to store files>4GB 
704   { pHeader_64bits->iOrgSize   = 0;                         // This indicates>4GB file (0-vector is not compressed)
705     pHeader_64bits->i64OrgSize = npixels;    
706     iHeaderSize = sizeof(NKI_MODE2_64BITS);
707     dest += sizeof(NKI_MODE2_64BITS);
708   }
709   else
710   { pHeader->iOrgSize = (unsigned int)(npixels & UINT_MAX); // store 32 bit number as first member
711
712     if (iMode==2 || iMode==4)
713       iHeaderSize = sizeof(NKI_MODE2);
714     dest += iHeaderSize;
715   }
716
717   /* Create the compressed image */
718
719   if (iMode == 1)
720   { *(short int *)dest = *src;
721     dest+=2;
722
723     npixels--;
724
725     do
726     { val = src[1] - src[0];
727       src++;
728
729       if (val == 0)                            /* run length-encode zero differences */
730       { for (i=2;; i++)
731         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
732           { if (i==2)
733               *dest++=0;
734             else
735             { *dest++  =  -128; // hexadecimal 0x80
736               *dest++  = (signed char)(i-1);
737               npixels -= (i-2);
738               src     += (i-2);
739             }
740             break;
741           }
742         }
743       }
744       else if (val >= -64 && val <= 63)         /* small difference coded as one byte */
745       { *dest = (signed char)val;
746         dest++;
747       }
748       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
749       { dest[0] = (signed char)((val>>8) ^ 0x40);
750         dest[1] = (signed char)val;
751         dest+=2;
752       }
753       else                                      /* if very large differences code abs val as three bytes */
754       { *dest++ = 0x7F;
755         *dest++ = (signed char)(src[0]>>8);
756         *dest++ = (signed char)(src[0]);
757       }
758       /* Are we beyond the allocated memory? */
759       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
760         return 0;
761     }
762     while (--npixels);
763   }
764
765   else if (iMode == 2)
766   { iCRC  = 0;
767     iCRC2 = 0;
768
769     *(short int *)dest = val = *src;
770     iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char) val    ] ^ ((iCRC2 >> 8));
771     iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
772     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) val    ] ^ ((iCRC  >> 8));
773     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(val>>8)] ^ ((iCRC  >> 8));
774     dest+=2;
775     npixels--;
776
777     do
778     { val = src[1] - src[0];
779       src++;
780       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
781       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
782
783       if (val == 0)                            /* run length-encode zero differences */
784       { for (i=2;; i++)
785         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
786           { if (i==2)
787             { *dest++=0;
788               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0    ] ^ ((iCRC2 >> 8));
789             }
790             else
791             { *dest++  =  -128; // hexadecimal 0x80
792               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x80 ] ^ ((iCRC2 >> 8));
793               *dest++  = (signed char)(i-1);
794               iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (i-1)] ^ ((iCRC2 >> 8));
795               npixels -= (i-2);
796
797               for (j=0; j<i-2; j++)
798               { src++;
799                 iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
800                 iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
801               }
802             }
803             break;
804           }
805         }
806       }
807       else if (val >= -64 && val <= 63)         /* small difference coded as one byte */
808       { *dest = (signed char)val;
809         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
810         dest++;
811       }
812       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
813       { dest[0] = (signed char)((val>>8) ^ 0x40);
814         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)dest[0] ] ^ ((iCRC2 >> 8));
815         dest[1] = (signed char)val;
816         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
817         dest+=2;
818       }
819       else                                      /* if very large differences code abs val as three bytes */
820       { dest[0] = 0x7F;
821         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0x7f                   ] ^ ((iCRC2 >> 8));
822         val     = src[0];
823         dest[1] = (signed char)(val>>8);
824         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)(val>>8)] ^ ((iCRC2 >> 8));
825         dest[2] = (signed char)val;
826         iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ (unsigned char)val     ] ^ ((iCRC2 >> 8));
827         dest+=3;
828       }
829       /* Are we beyond the allocated memory? */
830       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
831         return 0;
832     }
833     while (--npixels);
834     
835     if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
836       pHeader->iCompressedSize = 
837         (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
838     else                                                       // store 64 bit number in extended structure
839       pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
840
841     /* Pad it to get an even length */
842     if (pHeader->iCompressedSize & 1)
843     { *dest++ = 0;
844       iCRC2 = CRC32_table[(unsigned char)iCRC2 ^ 0] ^ ((iCRC2 >> 8));
845       pHeader->iCompressedSize++;
846     }
847
848     pHeader->iOrgCRC        = iCRC;
849     pHeader->iCompressedCRC = iCRC2;
850   }
851
852   /* Create the compressed image - compressor with added 4 bit run */
853
854   else if (iMode == 3)
855   { int n4bit=0;
856     *(short int *)dest = *src;
857     dest+=2;
858     npixels--;
859
860     do
861     { val = src[1] - src[0];
862       src++;
863
864       if (val == 0)                             /* run length-encode zero differences */
865       { for (i=2;; i++)
866         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
867           { if (i<=MINZEROS)                    /* too short run -> write zeros */
868             { for (j=0; j<i-1; j++)
869               { *dest++=0;
870                 n4bit++;
871
872                 if(n4bit>=254)                  /* maximum length 4 bit run */
873                 { dest  = recompress4bit(n4bit, dest);
874                   n4bit = 0;
875                 }
876               }
877             }
878             else
879             { if (n4bit>=MIN4BIT)               /* end (and write) 4 bit run */
880                 dest  = recompress4bit(n4bit, dest);
881
882               n4bit=0;
883               *dest++  = -128; // hexadecimal 0x80
884               *dest++  = (signed char)(i-1);
885             }
886
887             npixels -= (i-2);
888             src     += (i-2);
889             break;
890           }
891         }
892       }
893       else if (val >= -63 && val <= 63)         /* small difference coded as one byte */
894       { if (val >= -8 && val <= 7)
895         { *dest++ = (signed char)val;
896           n4bit++;
897
898           if(n4bit>=254)                        /* maximum length 4 bit run */
899           { dest  = recompress4bit(n4bit, dest);
900             n4bit=0;
901           }
902         }
903         else if(n4bit>=MIN4BIT)                 /* end and write 4 bit run */
904         { j = val;
905           dest  = recompress4bit(n4bit, dest);
906           n4bit=0;
907           *dest++ = (signed char)j;
908         }
909         else
910         { *dest++ = (signed char)val;                   /* end 4 bit run */
911            n4bit  = 0;
912         }
913       }
914       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
915       { j = val;
916
917         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
918           dest  = recompress4bit(n4bit, dest);
919
920         n4bit=0;
921         dest[0] = (signed char)((j>>8) ^ 0x40);
922         dest[1] = (signed char)j;
923         dest+=2;
924       }
925       else                                      /* if very large differences code abs val as three bytes */
926       { j = src[0];
927
928         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
929           dest  = recompress4bit(n4bit, dest);
930
931         n4bit=0;
932         *dest++ = 0x7F;
933         *dest++ = (signed char)(j>>8);
934         *dest++ = (signed char)j;
935       }
936       /* Are we beyond the allocated memory? */
937       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
938         return 0;
939     }
940     while (--npixels);
941   }
942
943   /* Create the compressed image - compressor with added 4 bit run and CRC */
944
945   else if (iMode == 4)
946   { int n4bit=0;
947     iCRC  = 0;
948
949     *(short int *)dest = val = *src;
950     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) val    ] ^ ((iCRC  >> 8));
951     iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(val>>8)] ^ ((iCRC  >> 8));
952     dest+=2;
953     npixels--;
954
955     do
956     { val = src[1] - src[0];
957       src++;
958       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
959       iCRC  = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
960
961       if (val == 0)                             /* run length-encode zero differences */
962       { for (i=2;; i++)
963         { if (i>=npixels || src[i-1]!=src[-1] || i==256)
964           { if (i<=MINZEROS)                    /* too short run -> write zeros */
965             { for (j=0; j<i-1; j++)
966               { *dest++=0;
967                 n4bit++;
968
969                 if(n4bit>=254)                  /* maximum length 4 bit run */
970                 { dest  = recompress4bit(n4bit, dest);
971                   n4bit = 0;
972                 }
973               }
974             }
975             else
976             { if (n4bit>=MIN4BIT)               /* end (and write) 4 bit run */
977                 dest  = recompress4bit(n4bit, dest);
978
979               n4bit=0;
980               *dest++  = -128; // hexadecimal 0x80
981               *dest++  = (signed char)(i-1);
982             }
983
984             npixels -= (i-2);
985             for (j=0; j<i-2; j++)
986             { src++;
987               iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char) src[0]    ] ^ ((iCRC  >> 8));
988               iCRC = CRC32_table[(unsigned char)iCRC  ^ (unsigned char)(src[0]>>8)] ^ ((iCRC  >> 8));
989             }
990             break;
991           }
992         }
993       }
994       else if (val >= -63 && val <= 63)         /* small difference coded as one byte */
995       { if (val >= -8 && val <= 7)
996         { *dest++ = (signed char)val;
997           n4bit++;
998
999           if(n4bit>=254)                        /* maximum length 4 bit run */
1000           { dest  = recompress4bit(n4bit, dest);
1001             n4bit=0;
1002           }
1003         }
1004         else if(n4bit>=MIN4BIT)                 /* end and write 4 bit run */
1005         { j = val;
1006           dest  = recompress4bit(n4bit, dest);
1007           n4bit=0;
1008           *dest++ = (signed char)j;
1009         }
1010         else
1011         { *dest++ = (signed char)val;           /* end 4 bit run */
1012            n4bit  = 0;
1013         }
1014       }
1015       else if (val >= -0x3F00 && val <= 0x3EFF) /* large differences coded as two bytes */
1016       { j = val;
1017
1018         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
1019           dest  = recompress4bit(n4bit, dest);
1020
1021         n4bit=0;
1022         dest[0] = (signed char)((j>>8) ^ 0x40);
1023         dest[1] = (signed char)j;
1024         dest+=2;
1025       }
1026       else                                      /* if very large differences code abs val as three bytes */
1027       { j = src[0];
1028
1029         if(n4bit>=MIN4BIT)                      /* end (and write) 4 bit run */
1030           dest  = recompress4bit(n4bit, dest);
1031
1032         n4bit=0;
1033         *dest++ = 0x7F;
1034         *dest++ = (signed char)(j>>8);
1035         *dest++ = (signed char)j;
1036       }
1037       /* Are we beyond the allocated memory? */
1038       if ((size_t)(dest - (signed char*)pHeader) > iBufferSize)
1039         return 0;
1040     }
1041     while (--npixels);
1042
1043     if ((dest - (signed char*)pHeader - iHeaderSize)<UINT_MAX) // store 32 bit number as third member
1044       pHeader->iCompressedSize = 
1045         (unsigned int)(dest - (signed char*)pHeader - iHeaderSize);
1046     else                                                       // store 64 bit number in extended structure
1047     { pHeader_64bits->iCompressedSize = 0;
1048       pHeader_64bits->i64CompressedSize = dest - (signed char*)pHeader -iHeaderSize;
1049     }
1050
1051     /* Pad it to get an even length */
1052     if (pHeader->iCompressedSize & 1)
1053     { *dest++ = 0;
1054       pHeader->iCompressedSize++;
1055     }
1056
1057     pHeader->iOrgCRC        = iCRC;
1058     pHeader->iCompressedCRC = 0;
1059   }
1060
1061   return dest - (signed char*)pHeader;
1062 }
1063
1064
1065 void clitk::XdrImageIO::WriteImage(const char* file, char* headerinfo, char* headerfile, int raw,
1066                                    int offset, char bLittleEndian, int iNkiCompression,
1067                                    int wcoords, int append, int getsize, char *tobuffer, const void* data)
1068 { AVSINT   total=1;
1069   unsigned int      i;
1070   AVSINT   coords=0;
1071   int      f=0;
1072   char     temp[256];
1073   char     *c;
1074   char     cSwap;
1075   FILE     *fp;
1076   long     swap_test = 0x1000000;
1077   signed char*  pCompressed = NULL;
1078   size_t   FilePos=0;
1079   char     **buffer = NULL;
1080   int      len=0;
1081   char     *buf2;
1082   size_t   slen;
1083
1084   if (bLittleEndian)
1085     swap_test = 0x00000001;
1086
1087   if (getsize)
1088   { swap_test = 0xffffffff;     // never swap to save time
1089     buffer    = (char **) &len;
1090     f         = 1;
1091   }
1092
1093   if (tobuffer)
1094   { buf2   = (char *)tobuffer;
1095     buffer = &buf2;
1096     f      = 0;
1097   }
1098
1099   for (i=0; i<GetNumberOfDimensions(); i++)
1100   { total  *= GetDimensions(i);
1101     coords += GetDimensions(i);
1102   }
1103
1104   /* Try allocate the compressed fielddata - compression disabled if alloc fails */
1105   if ((iNkiCompression > 0) &&
1106         (GetComponentType() == itk::ImageIOBase::SHORT) &&
1107         (GetPixelType() == itk::ImageIOBase::SCALAR))
1108   { pCompressed = (signed char *)malloc((total/2) * 3 + sizeof(NKI_MODE2_64BITS) + 10);
1109     if (pCompressed==NULL)
1110     { iNkiCompression = 0;
1111       AVSwarning("Avs_wxdr: not enough memory to compress data, saving uncompressed");
1112     }
1113   }
1114
1115   if (!(tobuffer || getsize))
1116   { if (offset != -1)
1117     { f = open(file, O_RDWR, 0);
1118       if (f < 0)
1119       {
1120         AVSerror("Avs_wxdr: Opening " << file << "failed.\n" << strerror(errno));
1121         free(pCompressed);
1122         return AVS_ERROR;
1123       }
1124       lseek(f, offset, SEEK_SET);
1125     }
1126     else
1127     { if (strlen(file)==0)
1128         f = fileno(stdout);
1129       else
1130       { if (append)
1131           f = open(file, O_RDWR | O_APPEND, 0);
1132         else
1133           f = creat(file, S_IWRITE | S_IREAD);
1134       }
1135
1136       if (f < 0)
1137       { AVSerror("Avs_wxdr: Creating " << file << " failed.\n" << strerror(errno));
1138         free(pCompressed);
1139         return AVS_ERROR;
1140       }
1141     }
1142   }
1143
1144   if (!raw)
1145   { sprintf(temp, "# AVS wants to have the first line starting with its name\n");
1146     slen = strlen(temp);
1147
1148     if (!checked_write(f, temp, slen, buffer))
1149     { free(pCompressed);
1150       return AVS_ERROR;
1151     }
1152     FilePos += slen;
1153
1154     slen = strlen(headerinfo);
1155     if (slen && !checked_write(f, headerinfo, slen, buffer))
1156     { free(pCompressed);
1157       return AVS_ERROR;
1158     }
1159     FilePos += slen;
1160
1161     if (!checked_write(f, "\n", 1, buffer))
1162     { free(pCompressed);
1163       return AVS_ERROR;
1164     }
1165     FilePos++;
1166
1167     if (strlen(headerfile))
1168     { fp = fopen(headerfile, "rt");
1169       if (fp)
1170       { for (;;)
1171         { if (fgets(temp, 255, fp) == NULL) break;
1172           slen = strlen(temp);
1173           if (!checked_write(f, temp, slen, buffer))
1174           { fclose(fp);
1175             free(pCompressed);
1176             return AVS_ERROR;
1177           }
1178           FilePos += slen;
1179         }
1180         fclose(fp);
1181         if (!checked_write(f, "\n", 1, buffer))
1182         { free(pCompressed);
1183           return AVS_ERROR;
1184         }
1185         FilePos++;
1186       }
1187     }
1188
1189     sprintf(temp, "ndim=%d\n", GetNumberOfDimensions());
1190     slen = strlen(temp);
1191     if (!checked_write(f, temp, slen, buffer))
1192     { free(pCompressed);
1193       return AVS_ERROR;
1194     }
1195     FilePos += slen;
1196   }
1197
1198   for (i=0; i<GetNumberOfDimensions(); i++)
1199   { if (!raw)
1200     { sprintf(temp, "dim%d=%d\n", i+1, GetDimensions(i));
1201       slen = strlen(temp);
1202       if (!checked_write(f, temp, slen, buffer))
1203       { free(pCompressed);
1204         return AVS_ERROR;
1205       }
1206       FilePos += slen;
1207     }
1208   }
1209
1210   if (!raw)
1211   { sprintf(temp, "nspace=%d\n", GetNumberOfDimensions());
1212     slen = strlen(temp);
1213     if (!checked_write(f, temp, slen, buffer))
1214     { free(pCompressed);
1215       return AVS_ERROR;
1216     }
1217     FilePos += slen;
1218
1219     sprintf(temp, "veclen=%d\n", GetNumberOfComponents());
1220     slen = strlen(temp);
1221     if (!checked_write(f, temp, slen, buffer))
1222     { free(pCompressed);
1223       return AVS_ERROR;
1224     }
1225     FilePos += slen;
1226
1227     switch(GetComponentType())
1228     { case itk::ImageIOBase::CHAR   : strcpy(temp, "data=byte\n"); break;
1229       case itk::ImageIOBase::SHORT  : strcpy(temp, "data=xdr_short\n"); break;
1230       case itk::ImageIOBase::INT    : strcpy(temp, "data=xdr_integer\n"); break;
1231       case itk::ImageIOBase::FLOAT  : strcpy(temp, "data=xdr_real\n"); break;
1232       case itk::ImageIOBase::DOUBLE : strcpy(temp, "data=xdr_double\n"); break;
1233       default               : if (f != fileno(stdout)) close(f);
1234                               free(pCompressed);
1235                               return AVS_ERROR;
1236     }
1237     slen = strlen(temp);
1238     if (!checked_write(f, temp, slen, buffer))
1239     { free(pCompressed);
1240       return AVS_ERROR;
1241     }
1242     FilePos += slen;
1243   }
1244
1245
1246   //FilePos = tell(f);
1247 ONCE_AGAIN:
1248
1249
1250   //switch(input->uniform)
1251   //{ case UNIFORM     : 
1252   strcpy(temp, "field=uniform\n");
1253   coords = GetNumberOfDimensions() * 2;
1254                 //       break;
1255   //  case RECTILINEAR : strcpy(temp, "field=rectilinear\n");
1256                 //       break;
1257   //  case IRREGULAR   : strcpy(temp, "field=irregular\n");
1258                 //       coords = total * input->nspace;
1259                 //       break;
1260   //  default          : if (f != fileno(stdout)) close(f);
1261   //                     free(pCompressed);
1262   //                           return;
1263   //}
1264
1265   if (!raw)
1266   { if (!checked_write(f, temp, strlen(temp), buffer))
1267     { free(pCompressed);
1268       return AVS_ERROR;
1269     }
1270
1271     if ((iNkiCompression > 0) &&
1272       (GetComponentType() == itk::ImageIOBase::SHORT) &&
1273       (GetPixelType() == itk::ImageIOBase::SCALAR))
1274     { sprintf(temp, "nki_compression=%d", iNkiCompression);
1275       if (!checked_write(f, temp, strlen(temp), buffer))
1276       { free(pCompressed);
1277         return AVS_ERROR;
1278       }
1279     }
1280
1281     temp[0] = temp[1] = 12;
1282     if (!checked_write(f, temp, 2, buffer))
1283     { free(pCompressed);
1284       return AVS_ERROR;
1285     }
1286   }
1287
1288   total *= GetPixelSize();
1289
1290   if ((!raw) && (iNkiCompression > 0) &&
1291         (GetComponentType() == itk::ImageIOBase::SHORT) &&
1292         (GetPixelType() == itk::ImageIOBase::SCALAR))
1293   { size_t      iCompressedLength;
1294
1295     iCompressedLength = nki_private_compress(pCompressed,
1296       (short int *)(data), total/2, iNkiCompression);
1297
1298     if (iCompressedLength > 0)
1299     { if (!checked_write(f, pCompressed, iCompressedLength, buffer))
1300       { free(pCompressed);
1301         return AVS_ERROR;
1302       }
1303       free(pCompressed);
1304       goto WRITE_COORDS;
1305     }
1306
1307     /* Compressionratio was poor: let's write uncompressed */
1308     iNkiCompression = 0;
1309     total /= 2;
1310     free(pCompressed);
1311     pCompressed = NULL;
1312     lseek(f, (unsigned int)FilePos, SEEK_SET); // use _lseeki64 just in case header size > UINT_MAX bytes
1313     goto ONCE_AGAIN;
1314   }
1315
1316   /* swap data if required (xdr is low-endian) */
1317
1318   if (!(*(char *)(&swap_test)))
1319   { if (GetComponentSize()==2)
1320     { c = (char *)data;
1321       for (i=0; i<total; i+=2)
1322       { cSwap  = c[i];  c[i]   = c[i+1]; c[i+1] = cSwap;
1323       }
1324     }
1325     else if (GetComponentSize()==4)
1326     { c = (char *)data;
1327       for (i=0; i<total; i+=4)
1328       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1329         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1330       }
1331     }
1332     else if (GetComponentSize()==8)
1333     { c = (char *)data;
1334       for (i=0; i<total; i+=8)
1335       { cSwap = c[i];   c[i]   = c[i+7]; c[i+7] = cSwap;
1336         cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1337         cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1338         cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1339       }
1340     }
1341   }
1342
1343   if (total)
1344   { if (!checked_write(f, data, total, buffer))
1345       return AVS_ERROR;
1346   }
1347
1348   /* swap data back if was swapped before writing */
1349
1350   if (!(*(char *)(&swap_test)))
1351   { if (GetComponentSize()==2)
1352     { c = (char *)data;
1353       for (i=0; i<total; i+=2)
1354       { cSwap = c[i];   c[i]   = c[i+1]; c[i+1] = cSwap;
1355       }
1356     }
1357     else if (GetComponentSize()==4)
1358     { c = (char *)data;
1359       for (i=0; i<total; i+=4)
1360       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1361         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1362       }
1363     }
1364     else if (GetComponentSize()==8)
1365     { c = (char *)data;
1366       for (i=0; i<total; i+=8)
1367       { cSwap = c[i];   c[i]   = c[i+7]; c[i+7] = cSwap;
1368         cSwap = c[i+1]; c[i+1] = c[i+6]; c[i+6] = cSwap;
1369         cSwap = c[i+2]; c[i+2] = c[i+5]; c[i+5] = cSwap;
1370         cSwap = c[i+3]; c[i+3] = c[i+4]; c[i+4] = cSwap;
1371       }
1372     }
1373   }
1374
1375 WRITE_COORDS:
1376   float *points;
1377   points = (float *)malloc(sizeof(float)*GetNumberOfDimensions()*2);
1378   for (i=0; i<GetNumberOfDimensions(); i++)
1379   {
1380     points[i*2  ] = 0.1 *  GetOrigin(i);
1381     points[i*2+1] = 0.1 * (GetOrigin(i) + GetSpacing(i)*(GetDimensions(i)-1));
1382   }
1383
1384   if (coords && !raw)                           /* write AVS coordinates ? */
1385   { coords *= sizeof(float);
1386     if (!(*(char *)(&swap_test)))
1387     { c = (char *)(points);              /* swap bytes */
1388       for (i=0; i<coords; i+=4)
1389       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1390         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1391       }
1392     }
1393
1394     if (!checked_write(f, points, coords, buffer))
1395       return AVS_ERROR;
1396
1397     if (!(*(char *)(&swap_test)))
1398     { c = (char *)(points);              /* swap bytes back */
1399       for (i=0; i<coords; i+=4)
1400       { cSwap = c[i];   c[i]   = c[i+3]; c[i+3] = cSwap;
1401         cSwap = c[i+1]; c[i+1] = c[i+2]; c[i+2] = cSwap;
1402       }
1403     }
1404   }
1405
1406   if (!(tobuffer || getsize))
1407     if (f != fileno(stdout)) close(f);
1408
1409   if (getsize) return;
1410   return AVS_OK;
1411 }