emio.cpp

Go to the documentation of this file.
00001 
00005 /*
00006  * Author: Steven Ludtke, 04/10/2003 (sludtke@bcm.edu)
00007  * Copyright (c) 2000-2006 Baylor College of Medicine
00008  *
00009  * This software is issued under a joint BSD/GNU license. You may use the
00010  * source code in this file under either license. However, note that the
00011  * complete EMAN2 and SPARX software packages have some GPL dependencies,
00012  * so you are responsible for compliance with the licenses of these packages
00013  * if you opt to use BSD licensing. The warranty disclaimer below holds
00014  * in either instance.
00015  *
00016  * This complete copyright notice must be included in any revised version of the
00017  * source code. Additional authorship citations may be added, but existing
00018  * author citations must be preserved.
00019  *
00020  * This program is free software; you can redistribute it and/or modify
00021  * it under the terms of the GNU General Public License as published by
00022  * the Free Software Foundation; either version 2 of the License, or
00023  * (at your option) any later version.
00024  *
00025  * This program is distributed in the hope that it will be useful,
00026  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00027  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00028  * GNU General Public License for more details.
00029  *
00030  * You should have received a copy of the GNU General Public License
00031  * along with this program; if not, write to the Free Software
00032  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00033  *
00034  * */
00035 
00036 #include <cstring>
00037 #include "emio.h"
00038 #include "portable_fileio.h"
00039 #include "geometry.h"
00040 
00041 using namespace EMAN;
00042 
00043 EmIO::EmIO(const string & file, IOMode rw)
00044 :       filename(file), rw_mode(rw), em_file(0), initialized(false)
00045 {
00046         mode_size = 0;
00047         mode = EM_EM_UNKNOWN;
00048         is_big_endian = ByteOrder::is_host_big_endian();
00049         is_new_file = false;
00050         memset(&emh, 0, sizeof(EMHeader));
00051 }
00052 
00053 EmIO::~EmIO()
00054 {
00055         if (em_file) {
00056                 fclose(em_file);
00057                 em_file = 0;
00058         }
00059 }
00060 
00061 void EmIO::init()
00062 {
00063         ENTERFUNC;
00064 
00065         if (initialized) {
00066                 return;
00067         }
00068 
00069 
00070         initialized = true;
00071         em_file = sfopen(filename, rw_mode, &is_new_file);
00072 
00073         if (!is_new_file) {
00074                 if (fread(&emh, sizeof(EMHeader), 1, em_file) != 1) {
00075                         throw ImageReadException(filename, "EM header");
00076                 }
00077                 if (!is_valid(&emh)) {
00078                         throw ImageReadException(filename, "invalid EM image");
00079                 }
00080 
00081                 is_big_endian = ByteOrder::is_data_big_endian(&emh.nz);
00082                 become_host_endian(&emh.nx);
00083                 become_host_endian(&emh.ny);
00084                 become_host_endian(&emh.nz);
00085 
00086                 mode = (DataType) emh.data_type;
00087 
00088                 if (mode == EM_EM_DOUBLE) {
00089                         throw ImageReadException(filename, "DOUBLE data type not supported for EM image");
00090                 }
00091 
00092                 mode_size = get_mode_size(emh.data_type);
00093                 if (is_complex_mode()) {
00094                         emh.nx *= 2;
00095                 }
00096         }
00097         EXITFUNC;
00098 }
00099 
00100 bool EmIO::is_valid(const void *first_block, off_t file_size)
00101 {
00102         ENTERFUNC;
00103 
00104         if (!first_block) {
00105                 return false;
00106         }
00107 
00108         const char *data = static_cast < const char *>(first_block);
00109         char machine = data[0];
00110         char is_new_ver = data[1];
00111         char data_type = data[3];
00112 
00113         const int *data1 = static_cast < const int *>(first_block);
00114         int nx = data1[1];
00115         int ny = data1[2];
00116         int nz = data1[3];
00117 
00118         bool data_big_endian = ByteOrder::is_data_big_endian(&nz);
00119         if (data_big_endian != ByteOrder::is_host_big_endian()) {
00120                 ByteOrder::swap_bytes(&nx);
00121                 ByteOrder::swap_bytes(&ny);
00122                 ByteOrder::swap_bytes(&nz);
00123         }
00124 
00125         const int max_dim = 1 << 20;
00126 
00127         if (((int) machine >= EM_OS8 && machine <= EM_PC) &&
00128                 (is_new_ver == 0 || is_new_ver == 1) &&
00129                 (data_type >= EM_EM_CHAR && data_type <= EM_EM_DOUBLE) &&
00130                 (nx > 1 && nx < max_dim) && (ny > 0 && ny < max_dim) && (nz > 0 && nz < max_dim)) {
00131                 if (file_size > 0) {
00132                         off_t file_size1 = (off_t)nx * (off_t)ny * (off_t)nz * (off_t)get_mode_size(data_type) + (off_t)sizeof(EMHeader);
00133                         if (file_size == file_size1) {
00134                                 return true;
00135                         }
00136                 }
00137                 else {
00138                         return true;
00139                 }
00140         }
00141 
00142         return false;
00143 }
00144 
00145 int EmIO::read_header(Dict & dict, int image_index, const Region * area, bool)
00146 {
00147         ENTERFUNC;
00148 
00149         //single image format, index can only be zero
00150         image_index = 0;
00151         check_read_access(image_index);
00152         check_region(area, IntSize(emh.nx, emh.ny, emh.nz),false,false);
00153 
00154         int xlen = 0, ylen = 0, zlen = 0;
00155         EMUtil::get_region_dims(area, emh.nx, &xlen, emh.ny, &ylen, emh.nz, &zlen);
00156 
00157         dict["nx"] = xlen;
00158         dict["ny"] = ylen;
00159         dict["nz"] = zlen;
00160         dict["datatype"] = to_em_datatype(emh.data_type);
00161         EXITFUNC;
00162         return 0;
00163 }
00164 
00165 int EmIO::write_header(const Dict & dict, int image_index, const Region* area,
00166                                            EMUtil::EMDataType, bool)
00167 {
00168         ENTERFUNC;
00169         //single image format, index can only be zero
00170         image_index = 0;
00171         check_write_access(rw_mode, image_index, 1);
00172         if (area) {
00173                 check_region(area, FloatSize(emh.nx, emh.ny, emh.nz), is_new_file);
00174                 EXITFUNC;
00175                 return 0;
00176         }
00177 
00178         emh.machine = static_cast < char >(get_machine_type());
00179         emh.nx = dict["nx"];
00180         emh.ny = dict["ny"];
00181         emh.nz = dict["nz"];
00182         emh.data_type = EM_EM_FLOAT;
00183 
00184         rewind(em_file);
00185         if (fwrite(&emh, sizeof(EMHeader), 1, em_file) != 1) {
00186                 throw ImageWriteException(filename, "EM Header");
00187         }
00188 
00189         EXITFUNC;
00190         return 0;
00191 }
00192 
00193 int EmIO::read_data(float *data, int image_index, const Region * area, bool)
00194 {
00195         ENTERFUNC;
00196 
00197         //single image format, index can only be zero
00198         image_index = 0;
00199         check_read_access(image_index, data);
00200         check_region(area, IntSize(emh.nx, emh.ny, emh.nz),false,false);
00201 
00202         portable_fseek(em_file, sizeof(EMHeader), SEEK_SET);
00203 
00204         unsigned char *cdata = (unsigned char *) data;
00205         EMUtil::process_region_io(cdata, em_file, READ_ONLY, image_index, mode_size,
00206                                                           emh.nx, emh.ny, emh.nz, area);
00207 
00208         int xlen = 0, ylen = 0, zlen = 0;
00209         EMUtil::get_region_dims(area, emh.nx, &xlen, emh.ny, &ylen, emh.nz, &zlen);
00210 
00211         int total_sz = xlen * ylen * zlen;
00212 
00213         if (mode_size == sizeof(short)) {
00214                 become_host_endian((short *) cdata, total_sz);
00215         }
00216         else if (mode_size == sizeof(int)) {
00217                 become_host_endian((int *) cdata, total_sz);
00218         }
00219         else if (mode_size == sizeof(double)) {
00220                 throw ImageReadException(filename, "double type image is not supported");
00221         }
00222 
00223         for (int k = total_sz - 1; k >= 0; k--) {
00224                 float curr_data = 0;
00225 
00226                 if (mode == EM_EM_CHAR) {
00227                         curr_data = static_cast < float >(cdata[k]);
00228                 }
00229                 else if (mode == EM_EM_SHORT) {
00230                         curr_data = static_cast < float >(((short *) cdata)[k]);
00231                 }
00232                 else if (mode == EM_EM_INT) {
00233                         curr_data = static_cast < float >(((int *) cdata)[k]);
00234                 }
00235                 else if (mode == EM_EM_FLOAT || mode == EM_EM_COMPLEX) {
00236                         curr_data = ((float *) cdata)[k];
00237                 }
00238                 else if (mode_size == sizeof(double)) {
00239                         throw ImageReadException(filename, "double type image is not supported");
00240                 }
00241 
00242                 data[k] = curr_data;
00243         }
00244 
00245         EXITFUNC;
00246         return 0;
00247 }
00248 
00249 int EmIO::write_data(float *data, int image_index, const Region* area, EMUtil::EMDataType, bool)
00250 {
00251         ENTERFUNC;
00252         //single image format, index can only be zero
00253         image_index = 0;
00254         check_write_access(rw_mode, image_index, 1, data);
00255         portable_fseek(em_file, sizeof(EMHeader), SEEK_SET);
00256 
00257         EMUtil::process_region_io(data, em_file, rw_mode,
00258                                                           image_index, sizeof(float),
00259                                                           emh.nx, emh.ny, emh.nz, area);
00260 #if 0
00261         int sec_size = emh.nx * emh.ny;
00262         int row_size = sizeof(float) * emh.nx;
00263 
00264         for (int i = 0; i < emh.nz; i++) {
00265                 int k = i * sec_size;
00266                 for (int j = 0; j < emh.ny; j++) {
00267                         fwrite(&data[k + j * emh.nx], row_size, 1, em_file);
00268                 }
00269         }
00270 #endif
00271 
00272         EXITFUNC;
00273         return 0;
00274 }
00275 
00276 void EmIO::flush()
00277 {
00278         fflush(em_file);
00279 }
00280 
00281 bool EmIO::is_complex_mode()
00282 {
00283         init();
00284         if (emh.data_type == EM_EM_COMPLEX) {
00285                 return true;
00286         }
00287         return false;
00288 }
00289 
00290 bool EmIO::is_image_big_endian()
00291 {
00292         init();
00293         return is_big_endian;
00294 }
00295 
00296 
00297 int EmIO::to_em_datatype(char t)
00298 {
00299         DataType type = static_cast < DataType > (t);
00300         switch (type) {
00301         case EM_EM_CHAR:
00302                 return EMUtil::EM_CHAR;
00303         case EM_EM_SHORT:
00304                 return EMUtil::EM_SHORT;
00305         case EM_EM_INT:
00306                 return EMUtil::EM_INT;
00307         case EM_EM_FLOAT:
00308                 return EMUtil::EM_FLOAT;
00309         case EM_EM_DOUBLE:
00310                 return EMUtil::EM_DOUBLE;
00311         case EM_EM_COMPLEX:
00312                 return EMUtil::EM_FLOAT_COMPLEX;
00313         default:
00314                 break;
00315         }
00316         return EMUtil::EM_UNKNOWN;
00317 }
00318 
00319 int EmIO::get_machine_type()
00320 {
00321         int m = EM_UNKNOWN_MACHINE;
00322 #ifdef __sgi
00323         m = EM_SGI;
00324 #elif defined __linux__
00325         m = EM_PC;
00326 #elif defined __CYGWIN__
00327         m = EM_PC;
00328 #elif defined WIN32
00329         m = EM_PC;
00330 #elif defined MACOS
00331         m = EM_MAC;
00332 #elif defined macintosh
00333         m = EM_MAC;
00334 #elif defined __darwin__
00335         m = EM_MAC;
00336 #elif defined __APPLE__
00337         m = EM_MAC;
00338 #else
00339         m = EM_UNKNOWN_MACHINE;
00340 #endif
00341         return m;
00342 }
00343 
00344 size_t EmIO::get_mode_size(char data_type)
00345 {
00346         int mode = (int) data_type;
00347         switch (mode) {
00348         case EM_EM_CHAR:
00349                 return sizeof(char);
00350         case EM_EM_SHORT:
00351                 return sizeof(short);
00352         case EM_EM_INT:
00353         case EM_EM_FLOAT:
00354         case EM_EM_COMPLEX:
00355                 return sizeof(int);
00356         case EM_EM_DOUBLE:
00357                 return sizeof(double);
00358         }
00359         return 0;
00360 }

Generated on Sat Nov 7 02:18:55 2009 for EMAN2 by  doxygen 1.5.6