1 /*****************************************************************************
2 Major portions of this software are copyrighted by the Medical College
3 of Wisconsin, 1994-2000, and are released under the Gnu General Public
4 License, Version 2. See the file README.Copyright for details.
5 ******************************************************************************/
6
7 #include "mrilib.h"
8 #include "thd.h"
9
10 /*---------------------------------------------------------------------*/
11
12 static int compress_mode = COMPRESS_NOFILE ;
13
THD_set_write_compression(int mm)14 void THD_set_write_compression( int mm )
15 {
16 if( mm >= COMPRESS_NONE && mm <= COMPRESS_LASTCODE )
17 compress_mode = mm ;
18 else
19 compress_mode = COMPRESS_NONE ;
20 return ;
21 }
22
23 /*---------------------------------------------------------------------*/
24
THD_get_write_compression(void)25 int THD_get_write_compression(void)
26 {
27 if( compress_mode == COMPRESS_NOFILE ) THD_enviro_write_compression() ;
28 return compress_mode ;
29 }
30
31 /*---------------------------------------------------------------------*/
32
THD_enviro_write_compression(void)33 int THD_enviro_write_compression(void)
34 {
35 char *hh = my_getenv("AFNI_COMPRESSOR") ;
36 int ii ;
37
38 compress_mode = COMPRESS_NONE ;
39 if( hh == NULL ) return COMPRESS_NONE ;
40
41 for( ii=0 ; ii <= COMPRESS_LASTCODE ; ii++ ){
42 if( strcmp(hh,COMPRESS_enviro[ii]) == 0 ){
43 compress_mode = ii ;
44 return ii ;
45 }
46 }
47
48 return COMPRESS_NONE ;
49 }
50
51 /*---------------------------------------------------------------------*/
52
53 static int native_order = -1 ;
54 static int output_order = -1 ;
55
THD_set_write_order(int mm)56 void THD_set_write_order( int mm )
57 {
58 if( mm == LSB_FIRST || mm == MSB_FIRST )
59 output_order = mm ;
60 else
61 output_order = -1 ;
62 return ;
63 }
64
65 /*---------------------------------------------------------------------*/
66
THD_enviro_write_order(void)67 void THD_enviro_write_order(void)
68 {
69 char *hh = my_getenv("AFNI_BYTEORDER") ;
70
71 if( hh == NULL ){ output_order = -1 ; return ; }
72
73 if( strcmp(hh,LSB_FIRST_STRING) == 0 ){ output_order = LSB_FIRST; return; }
74 if( strcmp(hh,MSB_FIRST_STRING) == 0 ){ output_order = MSB_FIRST; return; }
75
76 output_order = -1 ; return ;
77 }
78
79 /*---------------------------------------------------------------------*/
80
THD_get_write_order(void)81 int THD_get_write_order(void)
82 {
83 if( native_order < 0 ) native_order = mri_short_order() ;
84 if( output_order < 0 ) THD_enviro_write_order() ;
85
86 return (output_order > 0) ? output_order
87 : native_order ;
88 }
89
90 /*---------------------------------------------------------------------*/
91 /*! Write an AFNI datablock to disk in the .HEAD/.BRIK format:
92 - Returns True if OK, False if an error.
93 - See also AFNI_refashion_dataset.
94 - All attributes must now be set prior to calling this,
95 via function THD_set_dataset_attributes().
96 - The one exception to the above rule is the BYTEORDER attribute.
97 -----------------------------------------------------------------------*/
98
THD_write_datablock(THD_datablock * blk,RwcBoolean write_brick)99 RwcBoolean THD_write_datablock( THD_datablock *blk , RwcBoolean write_brick )
100 {
101 THD_diskptr *dkptr ;
102 RwcBoolean good ;
103 int id , nx , ny , nz , nv , nxy , nxyz , ibr ;
104 int atrank[ATRSIZE_DATASET_RANK] , atdims[ATRSIZE_DATASET_DIMENSIONS] ;
105 MRI_IMAGE *im ;
106 int save_order ;
107 int64_t nb , idone ;
108 int do_mripurge ;
109
110 /*-- sanity checks --*/
111
112 if( ! ISVALID_DATABLOCK(blk) ) return False ;
113 if( DBLK_IS_MASTERED(blk) ) return False ; /* 11 Jan 1999 */
114 if( DBLK_IS_MINC(blk) ) WRITE_ERR("MINC with bad name extension?") ;
115 /* 29 Oct 2001 */
116 if( DBLK_IS_ANALYZE(blk) ) WRITE_ERR("ANALYZE but bad name extension?") ;
117 /* 27 Aug 2002 */
118 if( DBLK_IS_NIFTI(blk) ) WRITE_ERR("NIFTI but bad name extension?") ;
119 /* 28 Aug 2003 */
120
121 dkptr = blk->diskptr ;
122 if( ! ISVALID_DISKPTR(dkptr) ) WRITE_ERR("illegal file type") ;
123
124 if( strlen(dkptr->directory_name) == 0 ||
125 strlen(dkptr->header_name) == 0 ||
126 strlen(dkptr->filecode) == 0 )
127 WRITE_ERR("illegal file names stored in dataset") ;
128
129 if( dkptr->rank != 3 )
130 WRITE_ERR("cannot write non-3D datablock") ;
131
132 /*-- create directory if necessary --*/
133
134 if( ! THD_is_directory(dkptr->directory_name) ){
135 id = mkdir( dkptr->directory_name , THD_MKDIR_MODE ) ;
136 if( id != 0 ){
137 fprintf(stderr,
138 "\n"
139 "*** cannot mkdir new directory: %s\n"
140 " - Do you have permission to write to this disk?\n"
141 " - Is the disk full?\n" ,
142 dkptr->directory_name) ;
143 return False ;
144 }
145 }
146
147 /* 25 April 1998: deal with byte order issues */
148
149 if( native_order < 0 ){ /* initialization */
150 native_order = mri_short_order() ;
151 if( output_order < 0 ) THD_enviro_write_order() ;
152 }
153 if( dkptr->byte_order <= 0 ) dkptr->byte_order = native_order ;
154 save_order = (output_order > 0) ? output_order
155 : dkptr->byte_order ;
156
157 #if 0
158 fprintf(stderr,"THD_write_datablock: save_order=%d dkptr->byte_order=%d\n",
159 save_order, dkptr->byte_order ) ;
160 #endif
161
162 if( save_order != LSB_FIRST && save_order != MSB_FIRST )
163 save_order = native_order ;
164
165 if( save_order == LSB_FIRST )
166 THD_set_string_atr( blk , ATRNAME_BYTEORDER , LSB_FIRST_STRING ) ;
167 else if( save_order == MSB_FIRST )
168 THD_set_string_atr( blk , ATRNAME_BYTEORDER , MSB_FIRST_STRING ) ;
169
170 /*-- actually write attributes to disk --*/
171
172 good = THD_write_atr( blk ) ;
173 if( good == False )
174 WRITE_ERR(
175 "failure to write attributes - is disk full? do you have write permission?");
176
177 /*-- if not writing data, can exit --*/
178
179 if( write_brick == False || blk->brick == NULL ||
180 dkptr->storage_mode == STORAGE_UNDEFINED ) return True ;
181
182 if( dkptr->storage_mode == STORAGE_BY_VOLUMES ){ /* 20 Jun 2002 */
183 fprintf(stderr,"** Writing dataset by VOLUMES not yet supported.\n") ;
184 return False ;
185 }
186
187 /*-- check each brick for existence:
188 if none exist, cannot write, but is OK
189 if some but not all exist, cannot write, and is an error --*/
190
191 id = THD_count_potential_databricks( blk ) ;
192 if( id <= 0 ) return True ;
193 if( id < blk->nvals ){
194 ERROR_message("Write dataset error: only %d out of %d bricks in memory",
195 id,blk->nvals) ; return False ;
196 }
197
198 if( blk->malloc_type == DATABLOCK_MEM_UNDEFINED )
199 WRITE_ERR("undefined data exists in memory") ;
200
201 /*-- 13 Mar 2006: check for free disk space --*/
202
203 { int mm = THD_freemegabytes( dkptr->header_name ) ;
204 int rr = blk->total_bytes / (1024l * 1024l) ;
205 if( mm >= 0 && mm <= rr )
206 WARNING_message("Disk space: writing file %s (%d MB),"
207 " but only %d free MB on disk" ,
208 dkptr->brick_name , rr , mm ) ;
209 }
210
211 /*-- write data out in whatever format is ordered --*/
212
213 nx = dkptr->dimsizes[0] ;
214 ny = dkptr->dimsizes[1] ; nxy = nx * ny ;
215 nz = dkptr->dimsizes[2] ; nxyz = nxy * nz ;
216 nv = dkptr->nvals ; nb = blk->total_bytes ;
217
218 switch( dkptr->storage_mode ){
219
220 default: WRITE_ERR("illegal storage_mode!") ; break ;
221
222 case STORAGE_BY_BRICK:{
223 FILE *far ;
224 RwcBoolean purge_when_done = False , ok ;
225 int force_gzip=0 , csave=COMPRESS_NONE ;
226
227 /** if we have a mmap-ed file, copy into RAM (ugh) **/
228
229 if( blk->malloc_type == DATABLOCK_MEM_MMAP ){
230 char *bnew , *bold ;
231 int64_t offset ;
232
233 bnew = (char *) malloc( (size_t)nb ) ; /* work space */
234 bold = DBLK_ARRAY(blk,0) ; /* start of mapped file */
235
236 if( bnew == NULL )
237 WRITE_ERR("cannot rewrite due to malloc failure - is memory exhausted?") ;
238
239 memcpy( bnew , bold , (size_t)nb ) ; /* make a copy, */
240 munmap( (void *)bold , (size_t)nb ) ; /* then unmap file */
241
242 /* fix sub-brick pointers */
243
244 offset = 0 ;
245 for( ibr=0 ; ibr < nv ; ibr++ ){
246 mri_fix_data_pointer( (void *)(bnew+offset) , DBLK_BRICK(blk,ibr) ) ;
247 offset += DBLK_BRICK_BYTES(blk,ibr) ;
248 DBLK_BRICK(blk,ibr)->fondisk = 0 ; /* 31 Jan 2007 */
249 }
250
251 purge_when_done = True ;
252
253 } /** fall thru to here if have a malloc-ed dataset **/
254
255 if( save_order != native_order ) purge_when_done = True ;
256
257 /** delete old file, if any **/
258
259 COMPRESS_unlink( dkptr->brick_name ) ; /* Feb 1998 */
260
261 /** create new file **/
262
263 id = strlen(dkptr->directory_name) ;
264 ok = ( dkptr->directory_name[id-1] == '/' ) ;
265 if( ok ) sprintf( dkptr->brick_name , "%s%s.%s",
266 dkptr->directory_name ,
267 dkptr->filecode , DATASET_BRICK_SUFFIX );
268
269 else sprintf( dkptr->brick_name , "%s/%s.%s",
270 dkptr->directory_name ,
271 dkptr->filecode , DATASET_BRICK_SUFFIX );
272
273 /** COMPRESS for output added Feb 1998 */
274
275 if( compress_mode == COMPRESS_NOFILE ) THD_enviro_write_compression() ;
276
277 #ifdef COMPRESS_GZIP
278 /*-- 02 Mar 2001: check if we will force gzip --*/
279
280 if( compress_mode == COMPRESS_NONE && AFNI_yesenv("AFNI_AUTOGZIP") ){
281 double entrop = ENTROPY_datablock(blk) ;
282 force_gzip = (entrop < 2.7) ;
283 #if 0
284 fprintf(stderr,"Entropy=%g ==> forcing write gzip on %s\n",entrop,dkptr->brick_name) ;
285 #endif
286 } else {
287 force_gzip = 0 ;
288 }
289 if( force_gzip ){
290 csave = compress_mode ; compress_mode = COMPRESS_GZIP ;
291 }
292 #endif
293
294 far = COMPRESS_fopen_write( dkptr->brick_name , compress_mode ) ;
295 if( far == NULL ){
296 if( compress_mode != COMPRESS_NONE ){
297 compress_mode = COMPRESS_NONE ; force_gzip = 0 ;
298 far = COMPRESS_fopen_write( dkptr->brick_name , compress_mode ) ;
299 }
300 }
301 if( far == NULL )
302 WRITE_ERR("cannot open output brick file - do you have write permission?") ;
303
304 /** write each brick out in a separate operation **/
305
306 idone = 0 ;
307 for( ibr=0 ; ibr < nv ; ibr++ ){
308
309 do_mripurge = MRI_IS_PURGED( DBLK_BRICK(blk,ibr) ) ;
310 if( do_mripurge ) mri_unpurge( DBLK_BRICK(blk,ibr) ) ;
311
312 if( save_order != native_order ){ /* 25 April 1998 */
313 switch( DBLK_BRICK_TYPE(blk,ibr) ){
314 default: break ;
315 case MRI_short:
316 mri_swap2( DBLK_BRICK_NVOX(blk,ibr) , DBLK_ARRAY(blk,ibr) ) ;
317 break ;
318
319 case MRI_complex: /* 23 Nov 1999 */
320 mri_swap4( 2*DBLK_BRICK_NVOX(blk,ibr), DBLK_ARRAY(blk,ibr)) ;
321 break ;
322
323 case MRI_float: /* 23 Nov 1999 */
324 case MRI_int:
325 mri_swap4( DBLK_BRICK_NVOX(blk,ibr) , DBLK_ARRAY(blk,ibr) ) ;
326 break ;
327 }
328 }
329
330 idone += fwrite( DBLK_ARRAY(blk,ibr), 1, DBLK_BRICK_BYTES(blk,ibr), far );
331
332 if( do_mripurge ){ /* 31 Jan 2007 */
333 if( !purge_when_done ) mri_purge( DBLK_BRICK(blk,ibr) ) ;
334 else mri_clear( DBLK_BRICK(blk,ibr) ) ;
335 }
336 } /* end of loop over sub-bricks */
337
338 COMPRESS_fclose(far) ;
339
340 if( purge_when_done ){
341 if( blk->malloc_type == DATABLOCK_MEM_MMAP ){
342 free( DBLK_ARRAY(blk,0) ) ;
343 for( ibr=0 ; ibr < nv ; ibr++ )
344 mri_clear_data_pointer( DBLK_BRICK(blk,ibr) ) ;
345 } else {
346 THD_purge_datablock( blk , DATABLOCK_MEM_MALLOC ) ;
347 }
348 }
349
350 if( compress_mode >= 0 || save_order != native_order ){
351 blk->malloc_type = DATABLOCK_MEM_MALLOC ;
352 }
353 DBLK_mmapfix(blk) ; /* 28 Mar 2005 */
354
355 if( force_gzip ) compress_mode = csave ; /* 02 Mar 2001 */
356
357 if( idone != blk->total_bytes )
358 WRITE_ERR("Write error in brick file: Is disk full, or write_protected?") ;
359
360 dkptr->byte_order = save_order ; /* 23 Nov 1999 */
361
362 return True ;
363 }
364 break ;
365
366 } /* end of switch over data storage mode */
367
368 return False ; /* should NEVER be reached */
369 }
370