EMAN2
dm4io.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 "dm4io.h"
00037 #include "portable_fileio.h"
00038 #include "geometry.h"
00039 
00040 using namespace EMAN;
00041 using namespace EMAN::GatanDM4;
00042 
00043 const char *TagTable::IMAGE_WIDTH_TAG = "Dimensions #0";
00044 const char *TagTable::IMAGE_HEIGHT_TAG = "Dimensions #1";
00045 const char *TagTable::IMAGE_NIMG_TAG = "Dimensions #2";
00046 const char *TagTable::IMAGE_DATATYPE_TAG = "DataType";
00047 const char *TagTable::IMAGE_THUMB_INDEX_TAG = "ImageIndex";
00048 
00049 
00050 TagTable::TagTable()
00051         :       img_index(0), is_big_endian(true), img_counted(1), num_images_found(0)
00052 {
00053 }
00054 
00055 TagTable::~TagTable()
00056 {
00057         for (unsigned int i = 0; i < data_list.size(); i++) {
00058                 if (data_list[i]) {
00059                         delete[]data_list[i];
00060                         data_list[i] = 0;
00061                 }
00062         }
00063 }
00064 
00065 void TagTable::add(const string & name, const string & value)
00066 {
00067         const char *value_str = value.c_str();
00068 
00069         if (name == IMAGE_WIDTH_TAG) {
00070                 x_list.push_back(atoi(value_str));
00071         }
00072         else if (name == IMAGE_HEIGHT_TAG) {
00073                 y_list.push_back(atoi(value_str));
00074         }
00075         else if (name == IMAGE_DATATYPE_TAG) {
00076                 datatype_list.push_back(atoi(value_str));
00077         }
00078         else if (name == IMAGE_THUMB_INDEX_TAG) {
00079                 set_thumb_index(atoi(value_str));
00080         }
00081         else if(name == IMAGE_NIMG_TAG){
00082                 img_counted=atoi(value_str);
00083         }
00084         else {
00085                 tags[name] = value;
00086         }
00087 }
00088 
00089 void TagTable::add_data(char *data)
00090 {
00091         if (!data) {
00092                 throw NullPointerException("DM4 data is NULL");
00093         }
00094         else {
00095                 data_list.push_back(data);
00096         }
00097 }
00098 
00099 string TagTable::get_string(const string & name)
00100 {
00101         return tags[name];
00102 }
00103 
00104 int TagTable::get_int(const string & name)
00105 {
00106         return atoi(tags[name].c_str());
00107 }
00108 
00109 float TagTable::get_float(const string & name)
00110 {
00111         return static_cast < float >(atof(tags[name].c_str()));
00112 }
00113 
00114 double TagTable::get_double(const string & name)
00115 {
00116         return atof(tags[name].c_str());
00117 }
00118 
00119 void TagTable::dump() const
00120 {
00121         map < string, string >::const_iterator p;
00122 
00123         for (p = tags.begin(); p != tags.end(); p++) {
00124 //              LOGDEBUG("  %s: %s", (*p).first.c_str(), (*p).second.c_str());
00125                 printf("  %s: %s\n", (*p).first.c_str(), (*p).second.c_str());
00126         }
00127 }
00128 
00129 int TagTable::get_xsize() const
00130 {
00131         return x_list[img_index];
00132 }
00133 
00134 int TagTable::get_image_counted() const
00135 {
00136         return img_counted;
00137 }
00138 
00139 int TagTable::get_ysize() const
00140 {
00141         return y_list[img_index];
00142 }
00143 
00144 int TagTable::get_datatype() const
00145 {
00146         return datatype_list[img_index];
00147 }
00148 
00149 char *TagTable::get_data() const
00150 {
00151         return data_list[img_index];
00152 }
00153 
00154 void TagTable::set_thumb_index(int i)
00155 {
00156         if (i != 0 && i != 1) {
00157                 throw OutofRangeException(0, 1, i, "image index");
00158         }
00159         else {
00160                 if (i == 0) {
00161                         img_index = 1;
00162                 }
00163                 else {
00164                         img_index = 0;
00165                 }
00166         }
00167 }
00168 
00169 int TagTable::get_num_images_found() const
00170 {
00171         return num_images_found;
00172 }
00173 
00174 void TagTable::set_num_images_found(int num_found)
00175 {
00176         num_images_found = num_found;
00177 }
00178 
00180 
00181 TagData::TagData(FILE * data_file, TagTable * table, const string & tagname)
00182         :       in(data_file), tagtable(table), name(tagname), tag_type(UNKNOWN)
00183 {
00184 }
00185 
00186 TagData::~TagData()
00187 {
00188 }
00189 
00190 string TagData::read_native(bool is_value_stored)
00191 {
00192         size_t sz = typesize();
00193         size_t nr;
00194         char val_str[32];
00195 
00196         if (tag_type == SHORT) {
00197                 short val = 0;
00198                 nr = fread(&val, sz, 1, in);
00199                 tagtable->become_host_endian(&val);
00200                 sprintf(val_str, "%d", val);
00201         }
00202         else if (tag_type == USHORT) {
00203                 unsigned short val = 0;
00204                 nr = fread(&val, sz, 1, in);
00205                 tagtable->become_host_endian(&val);
00206                 sprintf(val_str, "%d", val);
00207         }
00208         else if (tag_type == INT) {
00209                 int val = 0;
00210                 nr = fread(&val, sz, 1, in);
00211                 tagtable->become_host_endian(&val);
00212                 sprintf(val_str, "%d", val);
00213         }
00214         else if (tag_type == CHAR || tag_type == OCTET) {
00215                 char val = 0;
00216                 nr = fread(&val, sz, 1, in);
00217                 sprintf(val_str, "%d", val);
00218         }
00219         else if (tag_type == BOOLEAN) {
00220                 bool val = false;
00221                 nr = fread(&val, sz, 1, in);
00222                 tagtable->become_host_endian(&val);
00223                 sprintf(val_str, "%d", val);
00224         }
00225         else if (tag_type == UINT) {
00226                 unsigned int val = 0;
00227                 nr = fread(&val, sz, 1, in);
00228                 tagtable->become_host_endian(&val);
00229                 sprintf(val_str, "%u", (int) val);
00230         }
00231         else if (tag_type == FLOAT) {
00232                 float val = 0;
00233                 nr = fread(&val, sz, 1, in);
00234                 tagtable->become_host_endian(&val);
00235                 sprintf(val_str, "%f", val);
00236         }
00237         else if (tag_type == DOUBLE) {
00238                 double val = 0;
00239                 nr = fread(&val, sz, 1, in);
00240                 tagtable->become_host_endian(&val);
00241                 sprintf(val_str, "%10e", val);
00242         }
00243         else if (tag_type == OCTEU) {
00244                 long long val = 0;
00245                 nr = fread(&val, sz, 1, in);
00246                 tagtable->become_host_endian(&val);
00247                 sprintf(val_str, "%lld", val);
00248         }
00249         else if (tag_type == OCTEV) {
00250                 unsigned long long val = 0;
00251                 nr = fread(&val, sz, 1, in);
00252                 tagtable->become_host_endian(&val);
00253                 sprintf(val_str, "%lld", val);
00254         }
00255         else {
00256                 LOGERR("invalid tag type: '%lld'", tag_type);
00257                 exit(1);
00258         }
00259 
00260         if (is_value_stored) {
00261                 tagtable->add(name, val_str);
00262         }
00263 
00264         LOGVAR("value = '%s'", val_str);
00265 
00266         return string(val_str);
00267 }
00268 
00269 vector < int >TagData::read_array_types()
00270 {
00271         LOGVAR("TagData::read_array_types()");
00272 
00273         long long array_type = 0;
00274         size_t nr;
00275         nr = fread(&array_type, sizeof(array_type), 1, in);
00276 
00277         ByteOrder::become_big_endian(&array_type);
00278 
00279         LOGVAR("array data type = '%s'", GatanDM4::to_str((Type) array_type));
00280 
00281         vector < int >item_types;
00282 
00283         if (array_type == STRUCT) {
00284                 item_types = read_struct_types();
00285         }
00286         else if (array_type == ARRAY) {
00287                 item_types = read_array_types();
00288                 LOGERR("DM4: don't know how to handle this array type");
00289         }
00290         else {
00291                 item_types.push_back(array_type);
00292         }
00293 
00294         return item_types;
00295 }
00296 
00297 // string tag data are stored in unicode
00298 string TagData::read_string(int size)
00299 {
00300         if (size <= 0) {
00301                 return string("");
00302         }
00303 
00304         unsigned short *buf = new unsigned short[size];
00305         char *str = new char[size + 1];
00306 
00307         size_t nr;
00308         nr = fread(buf, size * sizeof(unsigned short), 1, in);
00309         tagtable->become_host_endian < unsigned short >(buf, size);
00310 
00311         for (int i = 0; i < size; i++) {
00312                 str[i] = static_cast < char >(buf[i]);
00313         }
00314 
00315         str[size] = '\0';
00316         string str1 = string(str);
00317 
00318         if (str) {
00319                 delete [] str;
00320                 str = NULL;
00321         }
00322 
00323         if (buf) {
00324                 delete [] buf;
00325                 buf = NULL;
00326         }
00327 
00328         return str1;
00329 }
00330 
00331 int TagData::read_array_data(vector < int >item_types, bool nodata, int image_index, int num_images)
00332 {
00333         ENTERFUNC;
00334         if (item_types.size() == 0) {
00335                 LOGERR("DM4 item types cannot be empty");
00336                 return 1;
00337         }
00338 
00339         int err = 0;
00340         long long array_size = 0;
00341 
00342         size_t nr;
00343         nr = fread(&array_size, sizeof(array_size), 1, in);
00344         ByteOrder::become_big_endian(&array_size);
00345 
00346         LOGVAR("array size = %lld\n", array_size);
00347 
00348         size_t item_size = 0;
00349         for (size_t i = 0; i < item_types.size(); i++) {
00350                 item_size += typesize(item_types[i]);
00351         }
00352 
00353         LOGVAR("%s array item size = %lld\n", name.c_str(), item_size);
00354 
00355         size_t buf_size = item_size * array_size;
00356 
00357         if (item_types.size() == 1 && item_types[0] == USHORT && nodata) {
00358                 string val = read_string(array_size);
00359                 tagtable->add(name, val);
00360                 LOGVAR("value: %s", val.c_str());
00361         }
00362         else if (!nodata && name == "Data") {
00363                 int num_found = tagtable->get_num_images_found();
00364                 num_found++;
00365                 tagtable->set_num_images_found(num_found);
00366 
00367                 char * data;
00368 
00369                 if (image_index < 0  ||  buf_size % num_images != 0  ||  num_found == 1) {
00370                         data = new char[buf_size];
00371                         nr = fread(data, item_size, array_size, in);
00372                 }
00373                 else {
00374                         size_t image_size = buf_size / num_images;
00375 
00376                         data = new char[image_size];
00377                         portable_fseek(in, image_index * image_size, SEEK_CUR);
00378                         nr = fread(data, image_size, 1, in);
00379                         portable_fseek(in, (num_images - image_index - 1) * image_size, SEEK_CUR);
00380                         array_size = array_size / num_images;
00381                 }
00382 
00383                 if (item_size == sizeof(short)) {
00384                         tagtable->become_host_endian((short *) data, array_size);
00385                 }
00386                 else if (item_size == sizeof(int)) {
00387                         tagtable->become_host_endian((int *) data, array_size);
00388                 }
00389                 else if (item_size == sizeof(double)) {
00390                         tagtable->become_host_endian((double *) data, array_size);
00391                 }
00392                 else {
00393                         LOGERR("cannot handle this type of DM4 image data");
00394                         return 1;
00395                 }
00396 
00397                 tagtable->add_data(data);
00398         }
00399         else {
00400                 portable_fseek(in, buf_size, SEEK_CUR);
00401         }
00402         EXITFUNC;
00403         return err;
00404 }
00405 
00406 vector < int >TagData::read_struct_types()
00407 {
00408         LOGVAR("TagData::read_struct_types()");
00409 
00410         long long namelength = 0;
00411         long long nfields = 0;
00412 
00413         size_t nr;
00414         nr = fread(&namelength, sizeof(namelength), 1, in);
00415         ByteOrder::become_big_endian(&namelength);
00416 
00417         nr = fread(&nfields, sizeof(nfields), 1, in);
00418         ByteOrder::become_big_endian(&nfields);
00419 
00420         LOGVAR("namelength = %lld\n", namelength);
00421         LOGVAR("num fields = %lld\n", nfields);
00422 
00423         vector < int >field_types;
00424 
00425         for (unsigned int i = 0; i < nfields; i++) {
00426                 nr = fread(&namelength, sizeof(namelength), 1, in);
00427                 ByteOrder::become_big_endian(&namelength);
00428 
00429                 long long field_type = 0;
00430                 nr = fread(&field_type, sizeof(field_type), 1, in);
00431                 ByteOrder::become_big_endian(&field_type);
00432                 
00433                 LOGVAR("%dth namelength = %lld, type = '%s'",
00434                            i, namelength, GatanDM4::to_str((Type) field_type));
00435                 field_types.push_back(field_type);
00436         }
00437 
00438         return field_types;
00439 }
00440 
00441 int TagData::read_any(bool nodata, int image_index, int num_images)
00442 {
00443         int err = 0;
00444 
00445         size_t nr;
00446         nr = fread(&tag_type, sizeof(tag_type), 1, in);
00447         
00448         ByteOrder::become_big_endian(&tag_type);
00449         LOGVAR("TagData::read_any tag type = '%s'\n", GatanDM4::to_str((Type) tag_type));
00450 
00451 
00452         if (tag_type == ARRAY) {
00453                 vector < int >item_types = read_array_types();
00454                 err = read_array_data(item_types, nodata, image_index, num_images);
00455         }
00456         else if (tag_type == STRUCT) {
00457                 vector < int >field_types = read_struct_types();
00458 
00459                 for (unsigned int i = 0; i < field_types.size(); i++) {
00460                         
00461                         tag_type = static_cast < Type > (field_types[i]);
00462                         
00463                         string val = read_native(false);
00464                         
00465                         char int_str[32];
00466                         sprintf(int_str, " #%d", i);
00467                         string fieldname = name + string(int_str);
00468                         tagtable->add(fieldname, val);
00469                 }
00470         }
00471         else if (tag_type == STRING) {
00472 
00473                 int str_sz = 0;
00474                 size_t nr;
00475                 nr = fread(&str_sz, sizeof(str_sz), 1, in);
00476                 ByteOrder::become_big_endian(&str_sz);
00477 
00478                 char *val = new char[str_sz + 1];
00479                 nr = fread(val, str_sz, 1, in);
00480                 val[str_sz] = '\0';
00481                 string val_str = string(val);
00482 
00483                 if (val) {
00484                         delete [] val;
00485                         val = NULL;
00486                 }
00487 
00488                 tagtable->add(name, val_str);
00489         }
00490         else {
00491                 read_native(true);
00492         }
00493 
00494         return err;
00495 }
00496 
00497 int TagData::read_tag_data(bool nodata, int image_index, int num_images)
00498 {
00499         LOGVAR("TagData::read_tag_data()");
00500         int err = 0;
00501 
00502         const char *DATA_TYPE_MARK = "%%%%";
00503         const size_t mark_sz = strlen(DATA_TYPE_MARK);
00504         char *mark = new char[mark_sz + 1];
00505 
00506         long long interval;
00507         
00508         size_t nr;
00509         nr = fread(&interval, sizeof(interval), 1, in);
00510 
00511         ByteOrder::become_big_endian(&interval);
00512 
00513         nr = fread(mark, mark_sz, 1, in);
00514         mark[mark_sz] = '\0';
00515 
00516         if (strcmp(mark, DATA_TYPE_MARK) != 0) {
00517                 LOGERR("data type label has been changed from '%s' to '%s'",
00518                            DATA_TYPE_MARK, mark);
00519                 return 1;
00520         }
00521 
00522         if (mark) {
00523                 delete [] mark;
00524                 mark = NULL;
00525         }
00526 
00527         long long encoded_types_size = 0;
00528         nr = fread(&encoded_types_size, sizeof(long long), 1, in);
00529         ByteOrder::become_big_endian(&encoded_types_size);
00530 
00531         LOGVAR("encoded types size = %lld\n", encoded_types_size);
00532 
00533         err = read_any(nodata, image_index, num_images);
00534 
00535         return err;
00536 }
00537 
00538 size_t TagData::typesize() const
00539 {
00540         return typesize((int) tag_type);
00541 }
00542 
00543 size_t TagData::typesize(int t) const
00544 {
00545         size_t size = 0;
00546         Type type = static_cast < Type > (t);
00547 
00548         
00549         switch (type) {
00550         case SHORT:
00551                 size = sizeof(short);
00552                 break;
00553         case USHORT:
00554                 size = sizeof(unsigned short);
00555                 break;
00556         case INT:
00557                 size = sizeof(int);
00558                 break;
00559         case UINT:
00560                 size = sizeof(unsigned int);
00561                 break;
00562         case FLOAT:
00563                 size = sizeof(float);
00564                 break;
00565         case DOUBLE:
00566                 size = sizeof(double);
00567                 break;
00568         case BOOLEAN:
00569                 size = sizeof(bool);
00570                 break;
00571         case CHAR:
00572         case OCTET:
00573                 size = sizeof(char);
00574                 break;
00575         case OCTEU:
00576                 size = sizeof(double);
00577                 break;
00578         case OCTEV:
00579                 size = sizeof(double);
00580                 break;
00581         default:
00582                 LOGERR("no such type: '%d'\n", type);
00583                 break;
00584         }
00585 
00586         return size;
00587 }
00588 
00590 
00591 TagEntry::TagEntry(FILE * data_file, TagTable * table, TagGroup * parent)
00592         :       in(data_file), tagtable(table), parent_group(parent), name("")
00593 {
00594 }
00595 
00596 TagEntry::~TagEntry()
00597 {
00598 }
00599 
00600 int TagEntry::read_tag_entry(bool nodata, int image_index, int num_images)
00601 {
00602         LOGVAR("TagEntry::read_tag_entry()");
00603         int err = 0;
00604         long long pos = 0;
00605         char tagtype = 0;
00606         char *tmp_name = 0;
00607 
00608         pos = ftell(in);
00609         size_t nr;
00610         nr = fread(&tagtype, sizeof(char), 1, in);
00611 
00612         if (tagtype != GROUP_TAG && tagtype != DATA_TAG) {
00613                 portable_fseek(in, sizeof(char) * 7, SEEK_CUR);
00614                 nr = fread(&tagtype, sizeof(char), 1, in);
00615         }
00616 
00617         if (tagtype != GROUP_TAG && tagtype != DATA_TAG) {
00618                 tagtype = fgetc(in);
00619                 if (tagtype == EOF)
00620                 {
00621                         return 1;
00622                 }
00623                 else{
00624                         LOGERR("TagEntry::read_tag_entry() invalid tag type: %d @ position %lld", tagtype, pos);
00625                         return 1;
00626                 }
00627         }
00628 
00629         short name_len = 0;
00630         nr = fread(&name_len, sizeof(short), 1, in);
00631 
00632         ByteOrder::become_big_endian(&name_len);
00633 
00634         if (name_len != 0) {
00635                 tmp_name = new char[name_len + 1];
00636                 nr = fread(tmp_name, name_len, 1, in);
00637                 tmp_name[name_len] = '\0';
00638         }
00639         else {
00640                 string parent_name = parent_group->get_name();
00641                 name_len = static_cast < short >(parent_name.size() + 4);
00642                 tmp_name = new char[name_len + 1];
00643                 sprintf(tmp_name, "%s #%d", parent_name.c_str(), parent_group->get_entry_id());
00644         }
00645 
00646         name = string(tmp_name);
00647 
00648         if (tmp_name) {
00649                 delete [] tmp_name;
00650                 tmp_name = NULL;
00651         }
00652 
00653         LOGVAR("\ntag name: '%s', len: %d, type: '%s'",
00654                    name.c_str(), name_len, GatanDM4::to_str((EntryType) tagtype));
00655 
00656         if (tagtype == DATA_TAG) {
00657                 TagData tag_data(in, tagtable, name);
00658                 err = tag_data.read_tag_data(nodata, image_index, num_images);
00659         }
00660         else if (tagtype == GROUP_TAG) {
00661                 long long tot_size = 0; //size of DataType record + size of data
00662                 nr = fread(&tot_size, sizeof(long long), 1, in);
00663                 ByteOrder::become_big_endian(&tot_size);
00664 
00665                 TagGroup group(in, tagtable, name);
00666                 err = group.read_tag_group(nodata, image_index, num_images);
00667         }
00668 
00669 /*
00670         long long tot_size = 0; //size of DataType record + size of data
00671         nr = fread(&tot_size, sizeof(long long), 1, in);
00672 */
00673         return err;
00674 }
00675 
00677 
00678 TagGroup::TagGroup(FILE * data_file, TagTable * table, const string & groupname)
00679         :       in(data_file), tagtable(table), name(groupname), entry_id(0)
00680 {
00681 }
00682 
00683 TagGroup::~TagGroup()
00684 {
00685 }
00686 
00687 int TagGroup::read_tag_group(bool nodata, int image_index, int num_images)
00688 {
00689         LOGVAR("TagGroup::read_tag_group()");
00690         char is_sorted, is_open;
00691 
00692         long long ntags = 0;
00693         
00694 //      portable_fseek(in, sizeof(char) * 2, SEEK_CUR);
00695         size_t nr;
00696         nr = fread(&is_sorted, sizeof(is_sorted), 1, in);
00697         nr = fread(&is_open,   sizeof(is_open),   1, in);
00698 
00699         nr = fread(&ntags, sizeof(ntags), 1, in);
00700         
00701         ByteOrder::become_big_endian(&ntags);
00702 
00703         LOGVAR("DM4: ntags = %d\n", ntags);
00704         
00705         int err = 0;
00706         // char flagend;
00707         for (int i = 0; i < ntags; i++) {
00708                 /*
00709                 portable_fseek(in, sizeof(char) * 9, SEEK_CUR);
00710                 nr = fread(&flagend, sizeof(char), 1, in);
00711                 
00712                 if (flagend ==EOF){
00713                         break;
00714                 }
00715                 else{
00716                         portable_fseek(in, -sizeof(char) * 10, SEEK_CUR);;
00717                 }
00718                 
00719                 */
00720                 
00721                 TagEntry tag_entry(in, tagtable, this);
00722                 err = tag_entry.read_tag_entry(nodata, image_index, num_images);
00723 
00724                 if (err) {
00725                         break;
00726                 }
00727         }
00728 
00729         return err;
00730 }
00731 
00732 string TagGroup::get_name() const
00733 {
00734         return name;
00735 }
00736 
00737 int TagGroup::get_entry_id()
00738 {
00739         int id = entry_id;
00740         entry_id++;
00741         return id;
00742 }
00743 
00745 
00746 DM4IO::DM4IO(const string & dm4_filename, IOMode rw)
00747         :       filename(dm4_filename), rw_mode(rw), dm4file(0), initialized(false)
00748 {
00749         is_big_endian = ByteOrder::is_host_big_endian();
00750         tagtable = new TagTable();
00751 }
00752 
00753 DM4IO::~DM4IO()
00754 {
00755         if (dm4file) {
00756                 fclose(dm4file);
00757                 dm4file = 0;
00758         }
00759         if (tagtable) {
00760                 delete tagtable;
00761                 tagtable = 0;
00762         }
00763 }
00764 
00765 void DM4IO::init()
00766 {
00767         ENTERFUNC;
00768         if (initialized) {
00769                 return;
00770         }
00771         initialized = true;
00772 
00773         if (rw_mode != READ_ONLY) {
00774                 throw ImageReadException(filename, "only support DM4 read-only");
00775         }
00776 
00777         dm4file = sfopen(filename, READ_ONLY);
00778 
00779         int stream_version = 0;
00780         if (fread(&stream_version, sizeof(stream_version), 1, dm4file) != 1) {
00781                 throw ImageReadException(filename, "read stream version of DM4 file");
00782         }
00783 
00784         long long recsize;
00785         if (fread(&recsize, sizeof(recsize), 1, dm4file) != 1) {
00786                 throw ImageReadException(filename, "read size of TagGroup recoed of DM4 file");
00787         }
00788 
00789         int endianness;
00790         if (fread(&endianness, sizeof(endianness), 1, dm4file) != 1) {
00791                 throw ImageReadException(filename, "read endianness indicator of DM4 file");
00792         }
00793 
00794         if (ByteOrder::is_data_big_endian(&stream_version) != ByteOrder::is_host_big_endian()) {
00795                 ByteOrder::swap_bytes(&stream_version);
00796                 ByteOrder::swap_bytes(&recsize);
00797                 ByteOrder::swap_bytes(&endianness);
00798         }
00799 
00800         if (endianness == 0) {
00801                 is_big_endian = true;
00802         }
00803         else {
00804                 is_big_endian = false;
00805         }
00806 
00807         tagtable->set_endian(is_big_endian);
00808         
00809         LOGDEBUG("dm4 ver = %d, image size = %d, is_big_endian = %d",
00810                         stream_version, recsize, (int) is_big_endian);
00811 
00812         EXITFUNC;
00813 }
00814 
00815 bool DM4IO::is_valid(const void *first_block)
00816 {
00817         ENTERFUNC;
00818 
00819         if (!first_block) {
00820                 return false;
00821         }
00822 
00823         const int *data = static_cast < const int *>(first_block);
00824 
00825         int img_ver = data[0];
00826         int byte_order = data[3];
00827         if (ByteOrder::is_data_big_endian(&img_ver) != ByteOrder::is_host_big_endian()) {
00828                 ByteOrder::swap_bytes(&img_ver);
00829                 ByteOrder::swap_bytes(&byte_order);
00830         }
00831 
00832         if (img_ver != 4) {
00833                 return false;
00834         }
00835 
00836         if (byte_order != 0 && byte_order != 1) {
00837                 return false;
00838         }
00839 
00840         return true;
00841 }
00842 
00843 bool DM4IO::is_image_big_endian()
00844 {
00845         init();
00846         return is_big_endian;
00847 }
00848 
00849 int DM4IO::read_header(Dict & dict, int image_index, const Region * area, bool)
00850 {
00851         ENTERFUNC;
00852         int err = 0;
00853 
00854         //single image format, index can only be zero
00855         if(image_index == -1) {
00856                 image_index = 0;
00857         }
00858         image_index = 0;
00859         check_read_access(image_index);
00860 
00861         portable_fseek(dm4file, NUM_ID_INT * sizeof(int), SEEK_SET);
00862         TagGroup root_group(dm4file, tagtable, "");
00863         root_group.read_tag_group(true, 0, 1);
00864 
00865         int nx = tagtable->get_xsize();
00866         int ny = tagtable->get_ysize();
00867 
00868         check_region(area, IntSize(nx, ny));
00869         int xlen = 0, ylen = 0;
00870         EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
00871 
00872         dict["nx"] = xlen;
00873         dict["ny"] = ylen;
00874         dict["nz"] = 1;
00875 
00876         dict["nimg"] = tagtable->get_image_counted();
00877         dict["DM4.acq_date"] = tagtable->get_string("Acquisition Date");
00878         dict["DM4.acq_time"] = tagtable->get_string("Acquisition Time");
00879         dict["DM4.source"] = tagtable->get_string("Source");
00880         dict["DM4.exposure_number"] = tagtable->get_int("Exposure Number");
00881         dict["DM4.exposure_time"] = tagtable->get_double("Exposure (s)");
00882         dict["DM4.zoom"] = tagtable->get_double("Zoom");
00883         dict["DM4.antiblooming"] = tagtable->get_int("Antiblooming");
00884         dict["DM4.indicated_mag"] = tagtable->get_double("Indicated Magnification");
00885         dict["DM4.actual_mag"] = tagtable->get_double("Actual Magnification");
00886         dict["DM4.pixel_size"] = tagtable->get_double("Pixel Size (um) #0");
00887         dict["DM4.name"] = tagtable->get_string("Name");
00888 
00889         dict["DM4.voltage"] = tagtable->get_double("Voltage")/1000.0;
00890         dict["microscope_voltage"]=(float)dict["DM4.voltage"];
00891         dict["DM4.cs"] = tagtable->get_double("Cs(mm)");
00892         dict["microscope_cs"]=(float)dict["DM4.cs"];
00893 
00894         dict["DM4.frame_type"] = tagtable->get_string("Processing");
00895         dict["DM4.camera_x"] = tagtable->get_int("Active Size (pixels) #0");
00896         dict["DM4.camera_y"] = tagtable->get_int("Active Size (pixels) #1");
00897         dict["DM4.binning_x"] = tagtable->get_int("Binning #0");
00898         dict["DM4.binning_y"] = tagtable->get_int("Binning #1");
00899         dict["datatype"] = to_em_datatype(tagtable->get_datatype());
00900 
00901         if ((float)dict["DM4.actual_mag"] >0.0) {
00902                 float apix=10000.0*(float)dict["DM4.pixel_size"]/(float)dict["DM4.actual_mag"];
00903                 dict["apix_x"]=apix;
00904                 dict["apix_y"]=apix;
00905                 dict["apix_z"]=apix;
00906         }
00907 
00908         EXITFUNC;
00909         return err;
00910 }
00911 
00912 int DM4IO::read_data(float *rdata, int image_index, const Region * area, bool)
00913 {
00914         ENTERFUNC;
00915 
00916         check_read_access(image_index, rdata);
00917 
00918         portable_fseek(dm4file, NUM_ID_INT * sizeof(int), SEEK_SET);
00919         TagGroup root_group(dm4file, tagtable, "");
00920         root_group.read_tag_group(true, 0, 1);
00921 
00922         int nx = tagtable->get_xsize();
00923         int ny = tagtable->get_ysize();
00924         int num_images = tagtable->get_image_counted();
00925 
00926         portable_fseek(dm4file, NUM_ID_INT * sizeof(int), SEEK_SET);
00927         root_group.read_tag_group(false, image_index, num_images);
00928 
00929         check_region(area, IntSize(nx, ny));
00930 
00931         int xlen = 0, ylen = 0, x0 = 0, y0 = 0;
00932         EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
00933         EMUtil::get_region_origins(area, &x0, &y0);
00934 
00935         char *data = tagtable->get_data();
00936         int data_type = tagtable->get_datatype();
00937 
00938         long long offset = 0;
00939         long long k = 0;
00940         long long off = 0;
00941         int xlast = x0 + xlen;
00942         int ylast = y0 + ylen;
00943 
00944 //      bool flip_vertical = (getenv ("FLIP_VERTICAL") != NULL);
00945         bool flip_vertical = true;
00946 
00947         for (int iy = y0; iy < ylast; iy++) {
00948                 if (flip_vertical) {
00949                         off = offset + (y0 + ylast - 1 - iy) * nx;
00950                 }
00951                 else {
00952                         off = offset + iy * nx;
00953                 }
00954 
00955                 switch (data_type) {
00956                 case GatanDM4::DataType::SIGNED_INT8_DATA:
00957                         for (int ix = x0; ix < xlast; ix++) {
00958                                 rdata[k] = (float) ((char *) data)[off + ix];
00959                                 k++;
00960                         }
00961                         break;
00962                 case GatanDM4::DataType::UNSIGNED_INT8_DATA:
00963                         for (int ix = x0; ix < xlast; ix++) {
00964                                 rdata[k] = (float) ((unsigned char *) data)[off + ix];
00965                                 k++;
00966                         }
00967                         break;
00968                 case GatanDM4::DataType::SIGNED_INT16_DATA:
00969                         for (int ix = x0; ix < xlast; ix++) {
00970                                 rdata[k] = (float) ((short *) data)[off + ix];
00971                                 k++;
00972                         }
00973                         break;
00974                 case GatanDM4::DataType::UNSIGNED_INT16_DATA:
00975                         for (int ix = x0; ix < xlast; ix++) {
00976                                 rdata[k] = (float) ((unsigned short *) data)[off + ix];
00977                                 k++;
00978                         }
00979                         break;
00980                 case GatanDM4::DataType::SIGNED_INT32_DATA:
00981                         for (int ix = x0; ix < xlast; ix++) {
00982                                 rdata[k] = (float) ((int *) data)[off + ix];
00983                                 k++;
00984                         }
00985                         break;
00986                 case GatanDM4::DataType::UNSIGNED_INT32_DATA:
00987                         for (int ix = x0; ix < xlast; ix++) {
00988                                 rdata[k] = (float) ((unsigned int *) data)[off + ix];
00989                                 k++;
00990                         }
00991                         break;
00992                 case GatanDM4::DataType::REAL4_DATA:
00993                         for (int ix = x0; ix < xlast; ix++) {
00994                                 rdata[k] = (float) ((float *) data)[off + ix];
00995                                 k++;
00996                         }
00997                         break;
00998                 case GatanDM4::DataType::REAL8_DATA:
00999                         for (int ix = x0; ix < xlast; ix++) {
01000                                 rdata[k] = (float) ((double *) data)[off + ix];
01001                                 k++;
01002                         }
01003                         break;                          
01004                 default:
01005                         string desc = string("unsupported DM4 data type") +
01006                                 string(GatanDM4::to_str((GatanDM4::DataType::GatanDataType) data_type));
01007                         throw ImageReadException(filename, desc);
01008                         k += xlen;
01009                 }
01010         }
01011 
01012 // #include "debug_read_data.h"
01013 
01014         EXITFUNC;
01015         return 0;
01016 
01017         EXITFUNC;
01018 }
01019 
01020 bool DM4IO::is_complex_mode()
01021 {
01022         return false;
01023 }
01024 
01025 int DM4IO::write_header(const Dict &, int, const Region* , EMUtil::EMDataType, bool)
01026 {
01027         ENTERFUNC;
01028         LOGWARN("DM4 write is not supported.");
01029         EXITFUNC;
01030         return 1;
01031 }
01032 
01033 int DM4IO::write_data(float *, int, const Region* , EMUtil::EMDataType, bool)
01034 {
01035         ENTERFUNC;
01036         LOGWARN("DM4 write is not supported.");
01037         EXITFUNC;
01038         return 1;
01039 }
01040 
01041 int DM4IO::get_nimg()
01042 {
01043         init();
01044 
01045         TagGroup root_group(dm4file, tagtable, "");
01046         root_group.read_tag_group(true, 0, 1);
01047 
01048         return tagtable->get_image_counted();
01049 }
01050 
01051 void DM4IO::flush()
01052 {
01053 }
01054 
01055 int GatanDM4::to_em_datatype(int gatan_datatype)
01056 {
01057         DataType::GatanDataType type = static_cast < DataType::GatanDataType > (gatan_datatype);
01058         int t = 0;
01059 
01060         switch (type) {
01061         case GatanDM4::DataType::SIGNED_INT8_DATA:
01062                 t = EMUtil::EM_CHAR;
01063                 break;
01064         case GatanDM4::DataType::UNSIGNED_INT8_DATA:
01065                 t = EMUtil::EM_UCHAR;
01066                 break;
01067         case GatanDM4::DataType::SIGNED_INT16_DATA:
01068                 t = EMUtil::EM_SHORT;
01069                 break;
01070         case GatanDM4::DataType::UNSIGNED_INT16_DATA:
01071                 t = EMUtil::EM_USHORT;
01072                 break;
01073         case GatanDM4::DataType::SIGNED_INT32_DATA:
01074                 t = EMUtil::EM_INT;
01075                 break;
01076         case GatanDM4::DataType::UNSIGNED_INT32_DATA:
01077                 t = EMUtil::EM_UINT;
01078                 break;
01079         default:
01080                 t = EMUtil::EM_UNKNOWN;
01081         }
01082 
01083         return t;
01084 }
01085 
01086 
01087 const char *GatanDM4::to_str(TagData::Type type)
01088 {
01089         const char *str = "unknown";
01090 
01091         switch (type) {
01092         case TagData::SHORT:
01093                 str = "short";
01094                 break;
01095         case TagData::INT:
01096                 str = "int";
01097                 break;
01098         case TagData::USHORT:
01099                 str = "unsigned short";
01100                 break;
01101         case TagData::UINT:
01102                 str = "unsigned int";
01103                 break;
01104         case TagData::FLOAT:
01105                 str = "float";
01106                 break;
01107         case TagData::DOUBLE:
01108                 str = "double";
01109                 break;
01110         case TagData::BOOLEAN:
01111                 str = "boolean";
01112                 break;
01113         case TagData::CHAR:
01114                 str = "char";
01115                 break;
01116         case TagData::OCTET:
01117                 str = "octet";
01118                 break;
01119         case TagData::STRUCT:
01120                 str = "struct";
01121                 break;
01122         case TagData::STRING:
01123                 str = "string";
01124                 break;
01125         case TagData::ARRAY:
01126                 str = "array";
01127                 break;
01128         default:
01129                 str = "unknown";
01130         }
01131         return str;
01132 }
01133 
01134 const char *GatanDM4::to_str(TagEntry::EntryType type)
01135 {
01136         const char *str = "unknown";
01137 
01138         switch (type) {
01139         case TagEntry::GROUP_TAG:
01140                 str = "Group";
01141                 break;
01142         case TagEntry::DATA_TAG:
01143                 str = "Data";
01144                 break;
01145         default:
01146                 str = "unknown";
01147         }
01148         return str;
01149 }
01150 
01151 
01152 const char *GatanDM4::to_str(GatanDM4::DataType::GatanDataType type)
01153 {
01154         switch (type) {
01155         case GatanDM4::DataType::SIGNED_INT16_DATA:
01156                 return "SIGNED_INT16_DATA";
01157         case GatanDM4::DataType::REAL4_DATA:
01158                 return "REAL4_DATA";
01159         case GatanDM4::DataType::COMPLEX8_DATA:
01160                 return "COMPLEX8_DATA";
01161         case GatanDM4::DataType::OBSELETE_DATA:
01162                 return "OBSELETE_DATA";
01163         case GatanDM4::DataType::PACKED_DATA:
01164                 return "PACKED_DATA";
01165         case GatanDM4::DataType::UNSIGNED_INT8_DATA:
01166                 return "UNSIGNED_INT8_DATA";
01167         case GatanDM4::DataType::SIGNED_INT32_DATA:
01168                 return "SIGNED_INT32_DATA";
01169         case GatanDM4::DataType::RGB_DATA:
01170                 return "RGB_DATA";
01171         case GatanDM4::DataType::SIGNED_INT8_DATA:
01172                 return "SIGNED_INT8_DATA";
01173         case GatanDM4::DataType::UNSIGNED_INT16_DATA:
01174                 return "UNSIGNED_INT16_DATA";
01175         case GatanDM4::DataType::UNSIGNED_INT32_DATA:
01176                 return "UNSIGNED_INT32_DATA";
01177         case GatanDM4::DataType::REAL8_DATA:
01178                 return "REAL8_DATA";
01179         case GatanDM4::DataType::COMPLEX16_DATA:
01180                 return "COMPLEX16_DATA";
01181         case GatanDM4::DataType::BINARY_DATA:
01182                 return "BINARY_DATA";
01183         case GatanDM4::DataType::RGB_UINT8_0_DATA:
01184                 return "RGB_UINT8_0_DATA";
01185         case GatanDM4::DataType::RGB_UINT8_1_DATA:
01186                 return "RGB_UINT8_1_DATA";
01187         case GatanDM4::DataType::RGB_UINT16_DATA:
01188                 return "RGB_UINT16_DATA";
01189         case GatanDM4::DataType::RGB_FLOAT32_DATA:
01190                 return "RGB_FLOAT32_DATA";
01191         case GatanDM4::DataType::RGB_FLOAT64_DATA:
01192                 return "RGB_FLOAT64_DATA";
01193         case GatanDM4::DataType::RGBA_UINT8_0_DATA:
01194                 return "RGBA_UINT8_0_DATA";
01195         case GatanDM4::DataType::RGBA_UINT8_1_DATA:
01196                 return "RGBA_UINT8_1_DATA";
01197         case GatanDM4::DataType::RGBA_UINT8_2_DATA:
01198                 return "RGBA_UINT8_2_DATA";
01199         case GatanDM4::DataType::RGBA_UINT8_3_DATA:
01200                 return "RGBA_UINT8_3_DATA";
01201         case GatanDM4::DataType::RGBA_UINT16_DATA:
01202                 return "RGBA_UINT16_DATA";
01203         case GatanDM4::DataType::RGBA_FLOAT32_DATA:
01204                 return "RGBA_FLOAT32_DATA";
01205         case GatanDM4::DataType::RGBA_FLOAT64_DATA:
01206                 return "RGBA_FLOAT64_DATA";
01207         case GatanDM4::DataType::POINT2_SINT16_0_DATA:
01208                 return "POINT2_SINT16_0_DATA";
01209         case GatanDM4::DataType::POINT2_SINT16_1_DATA:
01210                 return "POINT2_SINT16_1_DATA";
01211         case GatanDM4::DataType::POINT2_SINT32_0_DATA:
01212                 return "POINT2_SINT32_0_DATA";
01213         case GatanDM4::DataType::POINT2_FLOAT32_0_DATA:
01214                 return "POINT2_FLOAT32_0_DATA";
01215         case GatanDM4::DataType::RECT_SINT16_1_DATA:
01216                 return "RECT_SINT16_1_DATA";
01217         case GatanDM4::DataType::RECT_SINT32_1_DATA:
01218                 return "RECT_SINT32_1_DATA";
01219         case GatanDM4::DataType::RECT_FLOAT32_1_DATA:
01220                 return "RECT_FLOAT32_1_DATA";
01221         case GatanDM4::DataType::RECT_FLOAT32_0_DATA:
01222                 return "RECT_FLOAT32_0_DATA";
01223         case GatanDM4::DataType::SIGNED_INT64_DATA:
01224                 return "SIGNED_INT64_DATA";
01225         case GatanDM4::DataType::UNSIGNED_INT64_DATA:
01226                 return "UNSIGNED_INT64_DATA";
01227         default:
01228                 break;
01229         }
01230         return "Unknown Type";
01231 }