EMAN2
serio.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 "serio.h"
00037 #include "util.h"
00038 #include "portable_fileio.h"
00039 
00040 #include <cassert>
00041 
00042 using namespace EMAN;
00043 
00044 static const short SER_BYTE_ORDER               = 0x4949;
00045 static const short SER_SERIES_ID                = 0x0197;
00046 static const short SER_SERIES_VERSION   = 0x0210;
00047 static const int   ValidNumberElementsOffset = 18;      //the offset to ValidNumberElements, which is the number of images in the file
00048 
00049 SerIO::SerIO(const string & file, IOMode rw) :
00050                 filename(file), rw_mode(rw), serfile(0), initialized(false),
00051                 is_new_file(false), data_offset_array(0),tag_offset_array(0),
00052                 nimg(0), nx(0), ny(0), nz(0), datatypeid(0), datamode(0)
00053 {
00054 }
00055 
00056 SerIO::~SerIO()
00057 {
00058         if (serfile) {
00059                 fclose(serfile);
00060                 serfile = 0;
00061         }
00062 
00063         if (data_offset_array) {
00064                 delete [] data_offset_array;
00065                 data_offset_array = 0;
00066         }
00067 
00068         if (tag_offset_array) {
00069                 delete [] tag_offset_array;
00070                 tag_offset_array = 0;
00071         }
00072 }
00073 
00074 void SerIO::init()
00075 {
00076         ENTERFUNC;
00077 
00078         if (initialized) {
00079                 return;
00080         }
00081 
00082         initialized = true;
00083         serfile = sfopen(filename, rw_mode, &is_new_file);
00084 
00085         if (!is_new_file) {
00086                 if (fread(&serh, sizeof(SerHeader), 1, serfile) != 1) {
00087                         throw ImageReadException(filename, "SER header");
00088                 }
00089 
00090                 if (!is_valid(&serh)) {
00091                         throw ImageReadException(filename, "invalid SER");
00092                 }
00093         }
00094 
00095         EXITFUNC;
00096 }
00097 
00098 bool SerIO::is_valid(const void *first_block)
00099 {
00100         ENTERFUNC;
00101 
00102         if (!first_block) {
00103                 return false;
00104         }
00105 
00106         const short *data = static_cast < const short *>(first_block);
00107         short ByteOrder = data[0];
00108         short SeriesID = data[1];
00109 
00110         if(ByteOrder != 0x4949 || SeriesID != 0x0197) {
00111                 return false;
00112         }
00113 
00114         EXITFUNC;
00115         return true;
00116 }
00117 
00118 int SerIO::read_header(Dict & dict, int image_index, const Region * area, bool is_3d)
00119 {
00120         ENTERFUNC;
00121         init();
00122         rewind(serfile);
00123 
00124         short hitem1[3];
00125         if (fread(hitem1, sizeof(short), 3, serfile) != 3) {
00126                 throw ImageReadException(filename, "SER header");
00127         }
00128 
00129         dict["SER.ByteOrder"]           = hitem1[0];
00130         dict["SER.SeriesID"]            = hitem1[1];
00131         dict["SER.SeriesVersion"]       = hitem1[2];
00132 
00133         if((hitem1[0]!=SER_BYTE_ORDER) || (hitem1[1]!=SER_SERIES_ID) || (hitem1[2]!=SER_SERIES_VERSION) ) {
00134                 throw ImageReadException(filename, "SER header");
00135         }
00136 
00137         int hitem2[6];
00138         if (fread(hitem2, sizeof(int), 6, serfile) != 6) {
00139                 throw ImageReadException(filename, "SER header");
00140         }
00141 
00142         dict["SER.DataTypeID"]          = hitem2[0];
00143         dict["SER.TagTypeID"]           = hitem2[1];
00144         dict["SER.TotalNumberElements"] = hitem2[2];
00145         dict["SER.ValidNumberElements"] = hitem2[3];
00146         dict["SER.OffsetArrayOffset"]   = hitem2[4];
00147         dict["SER.NumberDimensions"]    = hitem2[5];
00148 
00149         nimg = (int)dict["SER.ValidNumberElements"];
00150 
00151         if(image_index >= (int)dict["SER.ValidNumberElements"]) {
00152                 throw ImageReadException(filename, "Image index out of bound");
00153         }
00154 
00155         for(int idx=0; idx<(int)dict["SER.NumberDimensions"]; idx++) {
00156                 read_dim_arr(dict, idx);
00157         }
00158 
00159         long pos = ftell(serfile);
00160         assert(pos == (int)dict["SER.OffsetArrayOffset"]);
00161 
00162         int tot = (int)dict["SER.TotalNumberElements"];
00163 
00164         data_offset_array = new int[tot];
00165         if (fread(data_offset_array, sizeof(int), tot, serfile) != (unsigned int)tot) {
00166                 throw ImageReadException(filename, "SER header");
00167         }
00168 
00169         tag_offset_array = new int[tot];
00170         if (fread(tag_offset_array, sizeof(int), tot, serfile) != (unsigned int)tot) {
00171                 throw ImageReadException(filename, "SER header");
00172         }
00173 
00174         this->datatypeid = (int)dict["SER.DataTypeID"];
00175 
00176         int dataoffset = data_offset_array[image_index];
00177         portable_fseek(serfile, dataoffset, SEEK_SET);
00178 
00179         //To read the attribute in data element(not the actual data)
00180         read_data_element(dict);
00181 
00182         int tagoffset = tag_offset_array[image_index];
00183         portable_fseek(serfile, tagoffset, SEEK_SET);
00184 
00185         //To read the data tag appended after data values
00186         read_data_tag(dict);
00187 
00188         EXITFUNC;
00189         return 0;
00190 }
00191 
00192 int SerIO::write_header(const Dict & dict, int image_index, const Region* area,
00193                                                 EMUtil::EMDataType filestoragetype, bool use_host_endian)
00194 {
00195         ENTERFUNC;
00196 
00197         throw ImageWriteException(filename, "SER Writing not supported");
00198 
00199         EXITFUNC;
00200         return 0;
00201 }
00202 
00203 int SerIO::read_data(float *rdata, int image_index, const Region *, bool )
00204 {
00205         ENTERFUNC;
00206 
00207         if(!data_offset_array) {
00208                 throw ImageReadException(filename, "SER header, empty DataOffsetarray");
00209         }
00210 
00211         size_t size = (size_t)nx * ny * nz;
00212         int data_offset = data_offset_array[image_index];
00213 
00214         size_t i;       //loop index
00215         unsigned char * puchar = 0;
00216         char * pchar = 0;
00217         int * pint = 0;
00218         unsigned int * puint = 0;
00219         short * pshort = 0;
00220         unsigned short * pushort = 0;
00221         double * pdouble = 0;
00222         switch(this->datatypeid) {
00223         case oneD:
00224                 portable_fseek(serfile, data_offset+26, SEEK_SET);      //offset 26 to actual data values
00225                 break;
00226         case twoD:
00227                 portable_fseek(serfile, data_offset+50, SEEK_SET);      //offset 50 to actual data values
00228                 break;
00229         default:
00230                 throw ImageReadException(filename, "SER header, wrong DataTypeID");
00231         }
00232 
00233         switch(this->datamode) {
00234         case SER_UCHAR:
00235                 puchar = new unsigned char[size];
00236                 if (fread(puchar, sizeof(unsigned char), size, serfile) != size) {
00237                         throw ImageReadException(filename, "SER data");
00238                 }
00239                 for (i = 0; i<size; ++i) {
00240                         rdata[i] = static_cast<float>(puchar[i]);
00241                 }
00242                 delete [] puchar;
00243                 break;
00244         case SER_USHORT:
00245                 pushort = new unsigned short[size];
00246                 if (fread(pushort, sizeof(unsigned short), size, serfile) != size) {
00247                         throw ImageReadException(filename, "SER data");
00248                 }
00249                 for (i = 0; i<size; ++i) {
00250                         rdata[i] = static_cast<float>(pushort[i]);
00251                 }
00252                 delete [] pushort;
00253                 break;
00254         case SER_UINT:
00255                 puint = new unsigned int[size];
00256                 if (fread(puint, sizeof(unsigned int), size, serfile) != size) {
00257                         throw ImageReadException(filename, "SER data");
00258                 }
00259                 for (i = 0; i<size; ++i) {
00260                         rdata[i] = static_cast<float>(puint[i]);
00261                 }
00262                 delete [] puint;
00263                 break;
00264         case SER_CHAR:
00265                 pchar = new char[size];
00266                 if (fread(pchar, sizeof(unsigned char), size, serfile) != size) {
00267                         throw ImageReadException(filename, "SER data");
00268                 }
00269                 for (i = 0; i<size; ++i) {
00270                         rdata[i] = static_cast<float>(pchar[i]);
00271                 }
00272                 delete [] pchar;
00273                 break;
00274         case SER_SHORT:
00275                 pshort = new short[size];
00276                 if (fread(pshort, sizeof(short), size, serfile) != size) {
00277                         throw ImageReadException(filename, "SER data");
00278                 }
00279                 for (i = 0; i<size; ++i) {
00280                         rdata[i] = static_cast<float>(pshort[i]);
00281                 }
00282                 delete [] pshort;
00283                 break;
00284         case SER_INT:
00285                 pint = new int[size];
00286                 if (fread(pint, sizeof(int), size, serfile) != size) {
00287                         throw ImageReadException(filename, "SER data");
00288                 }
00289                 for (i = 0; i<size; ++i) {
00290                         rdata[i] = static_cast<float>(pint[i]);
00291                 }
00292                 delete [] pint;
00293                 break;
00294         case SER_FLOAT:
00295                 if (fread(rdata, sizeof(float), size, serfile) != size) {
00296                         throw ImageReadException(filename, "SER data");
00297                 }
00298                 break;
00299         case SER_DOUBLE:
00300                 pdouble = new double[size];
00301                 if (fread(pdouble, sizeof(double), size, serfile) != size) {
00302                         throw ImageReadException(filename, "SER data");
00303                 }
00304                 for (i = 0; i<size; ++i) {
00305                         rdata[i] = static_cast<float>(pdouble[i]);
00306                 }
00307                 delete [] pdouble;
00308                 break;
00309         case SER_COMPLEX8:
00310         case SER_COMPLEX16:
00311                 throw ImageReadException(filename, "complex data not supported.");
00312                 break;
00313         default:
00314                 throw ImageReadException(filename, "Unknown data value type");
00315         }
00316 
00317         EXITFUNC;
00318         return 0;
00319 }
00320 
00321 int SerIO::write_data(float *data, int image_index, const Region* area,
00322                                           EMUtil::EMDataType, bool use_host_endian)
00323 {
00324         ENTERFUNC;
00325 
00326         throw ImageWriteException(filename, "SER Writing not supported");
00327 
00328         EXITFUNC;
00329         return 0;
00330 }
00331 
00332 bool SerIO::is_complex_mode()
00333 {
00334         return false;   //not support complex ser for now
00335 }
00336 
00337 void SerIO::flush()
00338 {
00339         fflush(serfile);
00340 }
00341 
00342 bool SerIO::is_image_big_endian()
00343 {
00344         return false;   //ser image is always little endian
00345 }
00346 
00347 int SerIO::get_nimg() {
00348         init();
00349 
00350         portable_fseek(serfile, ValidNumberElementsOffset, SEEK_SET);
00351         int nimg;
00352         if (fread(&nimg, sizeof(int), 1, serfile) != 1) {
00353                 throw ImageReadException(filename, "SER header");
00354         }
00355 
00356         return nimg;
00357 }
00358 
00359 void SerIO::read_dim_arr(Dict & dict, int idx)
00360 {
00361         int dimsize;
00362         if (fread(&dimsize, sizeof(int), 1, serfile) != 1) {
00363                 throw ImageReadException(filename, "SER header");
00364         }
00365 
00366         string sidx = Util::int2str(idx);
00367         dict["SER.DimensionSize"+sidx]  = dimsize;
00368 
00369         double hitem3[2];
00370         if (fread(hitem3, sizeof(double), 2, serfile) != 2) {
00371                 throw ImageReadException(filename, "SER header");
00372         }
00373         dict["SER.CalibrationOffset"+sidx]      = hitem3[0];
00374         dict["SER.CalibrationDelta"+sidx]       = hitem3[1];
00375 
00376         int celement;
00377         if (fread(&celement, sizeof(int), 1, serfile) != 1) {
00378                 throw ImageReadException(filename, "SER header");
00379         }
00380         dict["SER.CalibrationElement"+sidx]     = celement;
00381 
00382         int desclen;
00383         if (fread(&desclen, sizeof(int), 1, serfile) != 1) {
00384                 throw ImageReadException(filename, "SER header");
00385         }
00386         dict["SER.DescriptionLength"+sidx]      = desclen;
00387 
00388         if(desclen != 0) {
00389                 char * descr = new char[desclen+1];
00390                 //char descr[desclen+1];
00391                 if (fread(descr, sizeof(char), desclen, serfile) != (unsigned int)desclen) {
00392                         throw ImageReadException(filename, "SER header");
00393                 }
00394                 descr[desclen] = '\0';
00395                 string sdescr(descr);
00396                 dict["SER.Description"+sidx] = sdescr;
00397                 delete [] descr;
00398         }
00399 
00400         int unitslen;
00401         if (fread(&unitslen, sizeof(int), 1, serfile) != 1) {
00402                 throw ImageReadException(filename, "SER header");
00403         }
00404         dict["SER.UnitsLength"+sidx] = unitslen;
00405 
00406         if(unitslen != 0) {
00407                 char * units = new char[unitslen+1];
00408                 //char units[unitslen+1];
00409                 if (fread(units, sizeof(int), unitslen, serfile) != (unsigned int)unitslen) {
00410                         throw ImageReadException(filename, "SER header");
00411                 }
00412                 units[unitslen] = '\0';
00413                 string sunits(units);
00414                 dict["SER.Units"+sidx] = sunits;
00415                 delete [] units;
00416         }
00417 
00418 }
00419 
00420 void SerIO::read_data_element(Dict & dict)
00421 {
00422         if(this->datatypeid == oneD) {  //1D image
00423                 double hitem4[2];
00424                 if (fread(hitem4, sizeof(double), 2, serfile) != 2) {
00425                         throw ImageReadException(filename, "SER header");
00426                 }
00427                 dict["SER.CalibrationOffset"]   = hitem4[0];
00428                 dict["SER.CalibrationDelta"]    = hitem4[1];
00429 
00430                 int cali;
00431                 if (fread(&cali, sizeof(int), 1, serfile) != 1) {
00432                         throw ImageReadException(filename, "SER header");
00433                 }
00434                 dict["SER.CalibrationElement"] = cali;
00435 
00436                 short datatype;
00437                 if (fread(&datatype, sizeof(short), 1, serfile) != 1) {
00438                         throw ImageReadException(filename, "SER header");
00439                 }
00440                 dict["SER.DataType"] = datatype;
00441 
00442                 int arrlen;
00443                 if (fread(&arrlen, sizeof(int), 1, serfile) != 1) {
00444                         throw ImageReadException(filename, "SER header");
00445                 }
00446                 dict["nx"] = arrlen;
00447                 dict["ny"] = 1;
00448                 dict["nz"] = 1;
00449 
00450                 nx = arrlen;
00451                 ny = 1;
00452                 nz = 1;
00453         }
00454         else if(this->datatypeid == twoD) {     //2D image
00455                 double hitem4[2];
00456                 if (fread(hitem4, sizeof(double), 2, serfile) != 2) {
00457                         throw ImageReadException(filename, "SER header");
00458                 }
00459                 dict["SER.CalibrationOffsetX"]  = hitem4[0];
00460                 dict["SER.CalibrationDeltaX"]   = hitem4[1];
00461 
00462                 int calix;
00463                 if (fread(&calix, sizeof(int), 1, serfile) != 1) {
00464                         throw ImageReadException(filename, "SER header");
00465                 }
00466                 dict["SER.CalibrationElementX"] = calix;
00467 
00468                 double hitem5[2];
00469                 if (fread(hitem5, sizeof(double), 2, serfile) != 2) {
00470                         throw ImageReadException(filename, "SER header");
00471                 }
00472                 dict["SER.CalibrationOffsetX"]  = hitem5[0];
00473                 dict["SER.CalibrationDeltaX"]   = hitem5[1];
00474 
00475                 int caliy;
00476                 if (fread(&caliy, sizeof(int), 1, serfile) != 1) {
00477                         throw ImageReadException(filename, "SER header");
00478                 }
00479                 dict["SER.CalibrationElementY"] = caliy;
00480 
00481                 short datatype;
00482                 if (fread(&datatype, sizeof(short), 1, serfile) != 1) {
00483                         throw ImageReadException(filename, "SER header");
00484                 }
00485                 dict["SER.DataType"] = datatype;
00486                 this->datamode = datatype;
00487 
00488                 int arrsize[2];
00489                 if (fread(&arrsize, sizeof(int), 2, serfile) != 2) {
00490                         throw ImageReadException(filename, "SER header");
00491                 }
00492                 dict["nx"] = arrsize[0];
00493                 dict["ny"] = arrsize[1];
00494                 dict["nz"] = 1;
00495 
00496                 nx = arrsize[0];
00497                 ny = arrsize[1];
00498                 nz = 1;
00499         }
00500 }
00501 
00502 void SerIO::read_data_tag(Dict & dict)
00503 {
00504         int tag_type = (int)dict["SER.TagTypeID"];
00505         if( tag_type == timeOnly ) {
00506                 short tagtype;
00507                 if (fread(&tagtype, sizeof(short), 1, serfile) != 1) {
00508                         throw ImageReadException(filename, "SER header");
00509                 }
00510                 assert((int)tagtype == tag_type);
00511 
00512                 int sertime;
00513                 if (fread(&sertime, sizeof(int), 1, serfile) != 1) {
00514                         throw ImageReadException(filename, "SER header");
00515                 }
00516                 dict["SER.Time"] = sertime;
00517         }
00518         else if( tag_type == posTime ) {
00519                 short tagtype;
00520                 if (fread(&tagtype, sizeof(short), 1, serfile) != 1) {
00521                         throw ImageReadException(filename, "SER header");
00522                 }
00523                 assert((int)tagtype == tag_type);
00524 
00525                 int sertime;
00526                 if (fread(&sertime, sizeof(int), 1, serfile) != 1) {
00527                         throw ImageReadException(filename, "SER header");
00528                 }
00529                 dict["SER.Time"] = sertime;
00530 
00531                 double pos[2];
00532                 if (fread(&pos, sizeof(double), 2, serfile) != 2) {
00533                         throw ImageReadException(filename, "SER header");
00534                 }
00535                 dict["SER.PosionX"] = pos[0];
00536                 dict["SER.PosionY"] = pos[1];
00537         }
00538         else {
00539                 throw ImageReadException(filename, "SER header, wrong TagTypeID");
00540         }
00541 }