00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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
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
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
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
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 }