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