Logo
  • Main Page
  • Related Pages
  • Modules
  • Classes
  • Files

mmsfile.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2007 Stefan Schwarzer, Jens Schneider,             *
00003  *                           Matthias Hardt, Guido Madaus                  *
00004  *                                                                         *
00005  *   Copyright (C) 2007-2008 BerLinux Solutions GbR                        *
00006  *                           Stefan Schwarzer & Guido Madaus               *
00007  *                                                                         *
00008  *   Copyright (C) 2009-2013 BerLinux Solutions GmbH                       *
00009  *                                                                         *
00010  *   Authors:                                                              *
00011  *      Stefan Schwarzer   <stefan.schwarzer@diskohq.org>,                 *
00012  *      Matthias Hardt     <matthias.hardt@diskohq.org>,                   *
00013  *      Jens Schneider     <jens.schneider@diskohq.org>,                   *
00014  *      Guido Madaus       <guido.madaus@diskohq.org>,                     *
00015  *      Patrick Helterhoff <patrick.helterhoff@diskohq.org>,               *
00016  *      René Bählkow       <rene.baehlkow@diskohq.org>                     *
00017  *                                                                         *
00018  *   This library is free software; you can redistribute it and/or         *
00019  *   modify it under the terms of the GNU Lesser General Public            *
00020  *   License version 2.1 as published by the Free Software Foundation.     *
00021  *                                                                         *
00022  *   This library is distributed in the hope that it will be useful,       *
00023  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00024  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00025  *   Lesser General Public License for more details.                       *
00026  *                                                                         *
00027  *   You should have received a copy of the GNU Lesser General Public      *
00028  *   License along with this library; if not, write to the                 *
00029  *   Free Software Foundation, Inc.,                                       *
00030  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
00031  **************************************************************************/
00032 
00033 /**
00034  * @file mmsfile.cpp
00035  *
00036  * Implementation of MMSFile class.
00037  *
00038  * @ingroup mmstools
00039  */
00040 
00041 #include <cstdio>
00042 #include <stdlib.h>
00043 #include <unistd.h>
00044 #include <cerrno>
00045 #include <cstring>
00046 
00047 #include "mmstools/mmsfile.h"
00048 #include "mmstools/tools.h"
00049 
00050 #ifdef __HAVE_CURL__
00051 /**
00052  * Curl calls this c-routine to transfer data to the object.
00053  */
00054 size_t c_write_cb(char *buffer, size_t size, size_t nitems, void *outstream) {
00055     if (outstream)
00056         return ((MMSFile *)outstream)->write_cb(buffer, size, nitems, outstream);
00057     else
00058         return 0;
00059 }
00060 
00061 
00062 size_t MMSFile::write_cb(char *buffer, size_t size, size_t nitems, void *outstream) {
00063     char    *newbuff;                           /* pointer to new buffer */
00064     unsigned int     freebuff;                  /* free memory in old buffer */
00065 
00066     /* get the byte number */
00067     size *= nitems;
00068 
00069     /* calculate free buffer space */
00070     freebuff=this->buf_len - this->buf_pos;
00071 
00072     if(size > freebuff) {
00073         /* not enough space in the old buffer */
00074         newbuff=(char*)realloc(this->buffer,this->buf_len + (size - freebuff));
00075         if(newbuff==NULL) {
00076             /*TODO: ERROR HANDLING */
00077             DEBUGERR("callback buffer grow failed\n");
00078             size=freebuff;
00079         }
00080         else {
00081             /* new buffer size */
00082             this->buf_len+=size - freebuff;
00083             this->buffer=newbuff;
00084         }
00085     }
00086 
00087     memcpy(&(this->buffer[this->buf_pos]), buffer, size);
00088     this->buf_pos += size;
00089 
00090     return size;
00091 }
00092 #endif /* __HAVE_CURL__ */
00093 
00094 
00095 void MMSFile::resetAll() {
00096     this->type=MMSFT_NOTSET;
00097     this->mhandle=NULL;
00098     this->curl=NULL;
00099     this->file=NULL;
00100     this->buffer=NULL;
00101     this->buf_len=0;
00102     this->buf_pos=0;
00103     this->still_progr=0;
00104     this->cache=NULL;
00105     this->cache_fsize=0;
00106     this->cache_fpos=0;
00107 }
00108 
00109 
00110 bool MMSFile::fillCurlBuffer(size_t want, unsigned waittime) {
00111 #ifdef __HAVE_CURL__
00112     fd_set          fdread;
00113     fd_set          fdwrite;
00114     fd_set          fdexcep;
00115     int             maxfd;
00116     struct timeval  timeout;
00117     int             rc;
00118     CURLMcode       cres;
00119 
00120     if((!this->still_progr) || (this->buf_pos > want))
00121         return true;
00122 
00123     /* attempt to fill buffer */
00124     do {
00125         /* maximum loops reached */
00126         if (!waittime) return false;
00127         waittime--;
00128 
00129         FD_ZERO(&fdread);
00130         FD_ZERO(&fdwrite);
00131         FD_ZERO(&fdexcep);
00132 
00133         /* set a timeout */
00134         timeout.tv_sec = 60;
00135         timeout.tv_usec = 0;
00136 
00137         /* get file descriptors from the transfers */
00138         cres=curl_multi_fdset(this->mhandle, &fdread, &fdwrite, &fdexcep, &maxfd);
00139 
00140         if(cres!=CURLM_OK) {
00141             /*TODO: ERROR HANDLING */
00142             DEBUGERR("curl_multi_fdset failed %d\n",cres);
00143             return false;
00144         }
00145 
00146         /* do a select */
00147         rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
00148 
00149         if (rc>0) {
00150             while(curl_multi_perform(this->mhandle, &this->still_progr) == CURLM_CALL_MULTI_PERFORM)
00151                 usleep(10);
00152         }
00153         else
00154         if (rc<0) {
00155             return false;
00156         }
00157 
00158     } while(this->still_progr && (this->buf_pos < want));
00159 
00160     return true;
00161 #else
00162     return false;
00163 #endif
00164 }
00165 
00166 
00167 void MMSFile::freeCurlBuffer(size_t want) {
00168 #ifdef __HAVE_CURL__
00169 
00170     if ((this->buf_pos - want) <=0) {
00171         if (this->buffer) free(this->buffer);
00172         this->buffer  = NULL;
00173         this->buf_pos = 0;
00174         this->buf_len = 0;
00175     }
00176     else {
00177         memmove(this->buffer,
00178                 &(this->buffer[want]),
00179                 (this->buf_pos - want));
00180 
00181         this->buf_pos -= want;
00182     }
00183 #endif /*__HAVE_CURL__*/
00184 }
00185 
00186 bool MMSFile::openFile() {
00187     string tmp;
00188 
00189     /* check if already opened */
00190     if ((this->file)||(this->curl)) {
00191         this->lasterror = EBADF;
00192         return false;
00193     }
00194 
00195     /* reset the type */
00196     this->type=MMSFT_NOTSET;
00197 
00198     /* check name if it is an url string */
00199     tmp=this->name.substr(0, 7);
00200     strToUpr(&tmp);
00201     if (tmp=="HTTP://")
00202         this->type=MMSFT_URL;
00203     else
00204         this->type=MMSFT_FILE;
00205 
00206     if (this->type!=MMSFT_URL) {
00207         /* try to open normal file */
00208         char tmpmode[4];
00209         switch (this->mode) {
00210             case MMSFM_READ:
00211                 strcpy(tmpmode, "rb");
00212                 break;
00213             case MMSFM_WRITE:
00214                 strcpy(tmpmode, "wb");
00215                 this->usecache=false;
00216                 break;
00217             case MMSFM_APPEND:
00218                 strcpy(tmpmode, "ab");
00219                 this->usecache=false;
00220                 break;
00221             case MMSFM_READWRITE:
00222                 strcpy(tmpmode, "r+b");
00223                 this->usecache=false;
00224                 break;
00225             case MMSFM_WRITEREAD:
00226                 strcpy(tmpmode, "w+b");
00227                 this->usecache=false;
00228                 break;
00229             case MMSFM_APPENDREAD:
00230                 strcpy(tmpmode, "a+b");
00231                 this->usecache=false;
00232                 break;
00233             default:
00234                 this->lasterror = EINVAL;
00235                 return false;
00236         }
00237 
00238         if (!(this->file=fopen(name.c_str(), tmpmode))) {
00239             this->lasterror=ENOENT;
00240             return false;
00241         }
00242     }
00243 
00244     if (this->type!=MMSFT_FILE)
00245     {
00246 #ifdef __HAVE_CURL__
00247 
00248         /* try to open a url */
00249         if (this->mode!=MMSFM_READ) {
00250             /* I can't use this mode here */
00251             this->lasterror=EINVAL;
00252             return false;
00253         }
00254 
00255         this->curl = curl_easy_init();
00256 
00257         curl_easy_setopt(this->curl, CURLOPT_URL, this->name.c_str());
00258         curl_easy_setopt(this->curl, CURLOPT_FOLLOWLOCATION, true);
00259         curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, this);
00260         curl_easy_setopt(this->curl, CURLOPT_VERBOSE, false);
00261         curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, c_write_cb);
00262 
00263         this->mhandle = curl_multi_init();
00264 
00265         curl_multi_add_handle(mhandle, this->curl);
00266 
00267         /* start the fetch */
00268         while (curl_multi_perform(this->mhandle, &this->still_progr) == CURLM_CALL_MULTI_PERFORM)
00269             usleep(10);
00270 
00271         if((this->buf_pos == 0) && (!this->still_progr)) {
00272             /* an error occurred */
00273             curl_multi_remove_handle(this->mhandle, this->curl);
00274             curl_multi_cleanup(this->mhandle);
00275             curl_easy_cleanup(this->curl);
00276             resetAll();
00277             this->lasterror=ENOENT;
00278             return false;
00279         }
00280 
00281         /* it is a url */
00282         this->type = MMSFT_URL;
00283 #else
00284         throw MMSFileError(-1, "compile curl support!");
00285 #endif
00286     }
00287 
00288     if (this->usecache) {
00289         /* use separate cache for better performance */
00290         /* the next function has to read real */
00291         this->usecache=false;
00292 
00293         /* read the whole file */
00294         if (!readBufferEx((void**)&(this->cache), &(this->cache_fsize))) {
00295             /* failed to read file, close it */
00296             int err=this->lasterror;
00297             closeFile();
00298             this->lasterror=err;
00299             this->usecache=true; /* back to true */
00300             return false;
00301         }
00302 
00303         /* back to true */
00304         this->usecache=true;
00305 
00306         /* all right, set pos to the begin of cache */
00307         this->cache_fpos=0;
00308     }
00309 
00310     /* clear error */
00311     this->lasterror = 0;
00312     return true;
00313 }
00314 
00315 
00316 bool MMSFile::closeFile() {
00317     bool    retcode=true;
00318 
00319     /* clear error */
00320     this->lasterror = 0;
00321 
00322     switch(this->type) {
00323         case MMSFT_FILE:
00324             if (this->file) {
00325                 if (fclose(this->file)!=0)
00326                     this->lasterror = EOF;
00327             }
00328             else {
00329                 this->lasterror = EBADF;
00330                 retcode=false;
00331             }
00332             break;
00333 
00334         case MMSFT_URL:
00335 #ifdef __HAVE_CURL__
00336             /* free curl */
00337             if (this->curl) {
00338                 if(this->mhandle) {
00339                     curl_multi_remove_handle(this->mhandle, this->curl);
00340                     curl_multi_cleanup(this->mhandle);
00341                 }
00342                 curl_easy_cleanup(this->curl);
00343             }
00344             else {
00345                 this->lasterror = EBADF;
00346                 retcode=false;
00347             }
00348             break;
00349 #else
00350             throw MMSFileError(-1, "compile curl support!");
00351 #endif
00352         default:
00353             /* unknown type */
00354             this->lasterror = EBADF;
00355             retcode=false;
00356             break;
00357     }
00358 
00359     /* free allocated buffer */
00360     if (this->buffer) free(this->buffer);
00361     if (this->cache) free(this->cache);
00362 
00363     /* reset values */
00364     resetAll();
00365 
00366     return retcode;
00367 }
00368 
00369 
00370 MMSFile::MMSFile(string _name, MMSFileMode _mode, bool _usecache) :
00371     name(_name),
00372     mode(_mode),
00373     usecache(_usecache),
00374     lasterror(0) {
00375 
00376     /* reset values */
00377     resetAll();
00378 
00379     /* open the file */
00380     openFile();
00381 }
00382 
00383 
00384 MMSFile::~MMSFile() {
00385     /* free all */
00386     closeFile();
00387 }
00388 
00389 
00390 string MMSFile::getName(const bool effectiveUrl) {
00391 #ifdef __HAVE_CURL__
00392     if(effectiveUrl && this->type == MMSFT_URL) {
00393         char *buf = NULL;
00394         if(curl_easy_getinfo(this->curl, CURLINFO_EFFECTIVE_URL, buf) == CURLE_OK)
00395             return string(buf);
00396     }
00397 
00398     return this->name;
00399 #else
00400             throw MMSFileError(-1, "compile curl support!");
00401 #endif
00402 }
00403 
00404 MMSFileMode MMSFile::getMode() {
00405     return this->mode;
00406 }
00407 
00408 
00409 MMSFileType MMSFile::getType() {
00410     return this->type;
00411 }
00412 
00413 
00414 int MMSFile::getLastError() {
00415     return lasterror;
00416 }
00417 
00418 
00419 int MMSFile::endOfFile() {
00420 
00421     /* clear error */
00422     this->lasterror = 0;
00423 
00424     /* cache given? */
00425     if (this->usecache) {
00426         /* work with separate cache */
00427         if (this->cache) {
00428             if (this->cache_fpos < this->cache_fsize)
00429                 /* not the end of the file */
00430                 return 0;
00431 
00432             /* end of file */
00433             this->lasterror = EOF;
00434             return EOF;
00435         }
00436         /* no cache available */
00437         this->lasterror = EBADF;
00438         return 1;
00439     }
00440 
00441     /* normal access without separate cache */
00442     switch(this->type) {
00443         case MMSFT_FILE:
00444             if (this->file) {
00445                 if (feof(this->file)==0)
00446                     /* not the end of the file */
00447                     return 0;
00448 
00449                 /* end of file */
00450                 this->lasterror = EOF;
00451                 return EOF;
00452             }
00453             this->lasterror = EBADF;
00454             return 1;
00455 
00456         case MMSFT_URL:
00457 #ifdef __HAVE_CURL__
00458             if (this->curl) {
00459                 if((this->buf_pos == 0) && (!this->still_progr)) {
00460                     /* end of file */
00461                     this->lasterror = EOF;
00462                     return EOF;
00463                 }
00464                 /* not the end of the file */
00465                 return 0;
00466             }
00467             this->lasterror = EBADF;
00468             return 1;
00469 #else
00470             throw MMSFileError(-1, "compile curl support!");
00471 #endif
00472 
00473         default:
00474             /* unknown type */
00475             this->lasterror = EBADF;
00476             return 1;
00477     }
00478 }
00479 
00480 
00481 bool MMSFile::rewindFile() {
00482 
00483     /* clear error */
00484     this->lasterror = 0;
00485 
00486     /* cache given? */
00487     if (this->usecache) {
00488         /* work with separate cache */
00489         if (this->cache) {
00490             this->cache_fpos = 0;
00491             return true;
00492         }
00493         /* no cache available */
00494         this->lasterror = EBADF;
00495         return false;
00496     }
00497 
00498     /* normal access without separate cache */
00499     switch(this->type) {
00500         case MMSFT_FILE:
00501             if (this->file) {
00502                 std::rewind(this->file);
00503                 return true;
00504             }
00505             this->lasterror = EBADF;
00506             return false;
00507 
00508         case MMSFT_URL:
00509 #ifdef __HAVE_CURL__
00510             if (this->curl) {
00511                 /* close url */
00512                 closeFile();
00513 
00514                 /* re-open url */
00515                 return openFile();
00516             }
00517             this->lasterror = EBADF;
00518             return false;
00519 #else
00520             throw MMSFileError(-1, "compile curl support!");
00521 #endif
00522 
00523         default:
00524             /* unknown type */
00525             this->lasterror = EBADF;
00526             return false;
00527     }
00528 }
00529 
00530 
00531 bool MMSFile::setFilePos(long offset, MMSFilePosOrigin origin) {
00532 
00533     /* clear error */
00534     this->lasterror = 0;
00535 
00536     /* cache given? */
00537     if (this->usecache) {
00538         /* work with separate cache */
00539         if (this->cache) {
00540             long newfpos;
00541             switch (origin) {
00542                 case MMSFPO_CUR:
00543                     newfpos=(long)this->cache_fpos + offset;
00544                     break;
00545                 case MMSFPO_END:
00546                     newfpos=(long)this->cache_fsize + offset;
00547                     break;
00548                 case MMSFPO_SET:
00549                     newfpos=offset;
00550                     break;
00551                 default:
00552                     this->lasterror = EINVAL;
00553                     return false;
00554             }
00555             if (newfpos<0) {
00556                 this->lasterror = EINVAL;
00557                 return false;
00558             }
00559             if (newfpos>(long)this->cache_fsize) {
00560                 this->lasterror = EINVAL;
00561                 return false;
00562             }
00563             this->cache_fpos = (size_t)newfpos;
00564             return true;
00565         }
00566         /* no cache available */
00567         this->lasterror = EBADF;
00568         return false;
00569     }
00570 
00571     /* normal access without separate cache */
00572     switch(this->type) {
00573         case MMSFT_FILE:
00574             if (this->file) {
00575                 int tmporigin;
00576                 switch (origin) {
00577                     case MMSFPO_CUR:
00578                         tmporigin=SEEK_CUR;
00579                         break;
00580                     case MMSFPO_END:
00581                         tmporigin=SEEK_END;
00582                         break;
00583                     case MMSFPO_SET:
00584                         tmporigin=SEEK_SET;
00585                         break;
00586                     default:
00587                         this->lasterror = EINVAL;
00588                         return false;
00589                 }
00590                 if (fseek(this->file, offset, tmporigin)==0)
00591                     return true;
00592             }
00593             this->lasterror = EBADF;
00594             return false;
00595 
00596         case MMSFT_URL:
00597 #ifdef __HAVE_CURL__
00598             if (this->curl) {
00599                 /* currently I cannot set the pointer in an url stream */
00600                 /* so I will always fail */
00601                 /* if you use the separate cache (usecache=true), you can */
00602                 /* use this function as for normal files */
00603             }
00604             this->lasterror = EBADF;
00605             return false;
00606 #else
00607             throw MMSFileError(-1, "compile curl support!");
00608 #endif
00609         default:
00610             /* unknown type */
00611             this->lasterror = EBADF;
00612             return false;
00613     }
00614 }
00615 
00616 
00617 bool MMSFile::getFilePos(long *pos) {
00618     long    mypos;
00619 
00620     /* clear error */
00621     this->lasterror = 0;
00622 
00623     /* cache given? */
00624     if (this->usecache) {
00625         /* work with separate cache */
00626         if (this->cache) {
00627             *pos=(long)this->cache_fpos;
00628             return true;
00629         }
00630         /* no cache available */
00631         this->lasterror = EBADF;
00632         return false;
00633     }
00634 
00635     /* normal access without separate cache */
00636     switch(this->type) {
00637         case MMSFT_FILE:
00638             if (this->file) {
00639                 if ((mypos=ftell(this->file))>=0) {
00640                     *pos=mypos;
00641                     return true;
00642                 }
00643                 this->lasterror = errno;
00644                 return false;
00645             }
00646             this->lasterror = EBADF;
00647             return false;
00648 
00649         case MMSFT_URL:
00650 #ifdef __HAVE_CURL__
00651             if (this->curl) {
00652                 /* currently I cannot get the pointer from an url stream */
00653                 /* so I will always fail */
00654                 /* if you use the separate cache (usecache=true), you can */
00655                 /* use this function as for normal files */
00656             }
00657             this->lasterror = EBADF;
00658             return false;
00659 #else
00660             throw MMSFileError(-1, "compile curl support!");
00661 #endif
00662 
00663         default:
00664             /* unknown type */
00665             this->lasterror = EBADF;
00666             return false;
00667     }
00668 }
00669 
00670 
00671 bool MMSFile::readBuffer(void *ptr, size_t *ritems, size_t size, size_t nitems) {
00672     size_t  myri;
00673 
00674     /* clear error */
00675     this->lasterror = 0;
00676 
00677     /* clear ritems */
00678     if (!ritems) ritems=&myri;
00679     *ritems=0;
00680 
00681     /* check input */
00682     if ((!size) || (!nitems)) {
00683         this->lasterror = EINVAL;
00684         return false;
00685     }
00686 
00687     /* check if this->mode allowes to read from the file */
00688     switch(this->type) {
00689         case MMSFT_FILE:
00690             if ((this->mode==MMSFM_WRITE)||(this->mode==MMSFM_APPEND)) {
00691                 this->lasterror = EBADF;
00692                 return false;
00693             }
00694             break;
00695 
00696         case MMSFT_URL:
00697 #ifdef __HAVE_CURL__
00698             if (this->mode!=MMSFM_READ) {
00699                 this->lasterror = EBADF;
00700                 return false;
00701             }
00702             break;
00703 #else
00704             throw MMSFileError(-1, "compile curl support!");
00705 #endif
00706         default:
00707             /* unknown type */
00708             this->lasterror = EBADF;
00709             return false;
00710     }
00711 
00712     /* cache given? */
00713     if (this->usecache) {
00714         /* work with separate cache */
00715         if (this->cache) {
00716             /* calc available data */
00717             size_t availdata=this->cache_fsize-this->cache_fpos;
00718             if (availdata <= 0) {
00719                 availdata=0;
00720                 this->lasterror=EOF;
00721             }
00722 
00723             /* calc bytes to copy */
00724             *ritems = nitems * size;
00725             if (availdata < *ritems) *ritems=availdata;
00726 
00727             /* copy from cache to callers buffer */
00728             memcpy(ptr, &(this->cache[this->cache_fpos]), *ritems);
00729 
00730             /* increase fpos */
00731             this->cache_fpos+=*ritems;
00732 
00733             /* recalc number of items which are read */
00734             *ritems=*ritems/size;
00735             return true;
00736         }
00737         /* no cache available */
00738         this->lasterror = EBADF;
00739         return false;
00740     }
00741 
00742     /* normal access without separate cache */
00743     switch(this->type) {
00744         case MMSFT_FILE:
00745             if (this->file) {
00746                 *ritems = fread(ptr, size, nitems, this->file);
00747                 if (*ritems < nitems) {
00748                     /* error, check if eof */
00749                     if (endOfFile()==EOF) return true;
00750 
00751                     /* a read error */
00752                     this->lasterror = EBADF;
00753                     return false;
00754                 }
00755                 return true;
00756             }
00757             this->lasterror = EBADF;
00758             return false;
00759 
00760         case MMSFT_URL:
00761 #ifdef __HAVE_CURL__
00762             if (this->curl) {
00763                 /* calc bytes to receive */
00764                 *ritems = nitems * size;
00765 
00766                 /* receive data, if not available */
00767                 if (!fillCurlBuffer(*ritems)) {
00768                     this->lasterror = EBADF;
00769                     return false;
00770                 }
00771                 if (!this->buf_pos) {
00772                     this->lasterror = EBADF;
00773                     return false;
00774                 }
00775                 if (this->buf_pos < *ritems)
00776                     *ritems = this->buf_pos;
00777 
00778                 /* copy from cached buffer to callers buffer */
00779                 memcpy(ptr, this->buffer, *ritems);
00780 
00781                 /* freeing unneeded memory in my buffer */
00782                 freeCurlBuffer(*ritems);
00783 
00784                 /* recalc number of items which are read */
00785                 *ritems=*ritems/size;
00786                 return true;
00787             }
00788             this->lasterror = EBADF;
00789             return false;
00790 #else
00791             throw MMSFileError(-1, "compile curl support!");
00792 #endif
00793 
00794         default:
00795             /* unknown type */
00796             this->lasterror = EBADF;
00797             return false;
00798     }
00799 }
00800 
00801 
00802 bool MMSFile::readBufferEx(void **ptr, size_t *ritems, size_t size, size_t nitems) {
00803     size_t  myri, myri2;
00804     size_t  myni;
00805     void    *newptr;
00806     bool    ret;
00807 
00808     /* clear error */
00809     this->lasterror = 0;
00810 
00811     /* init return ptr */
00812     *ptr=NULL;
00813 
00814     /* clear ritems */
00815     if (!ritems) ritems=&myri2;
00816     *ritems=0;
00817 
00818     /* check input */
00819     if ((!size) || (!nitems)) {
00820         this->lasterror = EINVAL;
00821         return false;
00822     }
00823 
00824     /* init other */
00825     if ((myni = 0x1000 / size) < 1) myni=1;
00826     myri=0;
00827 
00828     /* read file */
00829     do {
00830         if (endOfFile()==EOF) break;
00831         if ((myri > 0) && (myni > myri)) break;
00832         if (nitems == 0) break;
00833         if (nitems < myni) myni=nitems;
00834         nitems -= myni;
00835         *ritems = *ritems + myri;
00836 
00837         newptr=realloc(*ptr,*ritems*size+myni*size);
00838         if (!newptr) {
00839             free(*ptr);
00840             *ptr=NULL;
00841             this->lasterror = ENOMEM;
00842             return false;
00843         }
00844         *ptr=newptr;
00845 
00846     } while ((ret=readBuffer(&(((char*)*ptr)[*ritems*size]), &myri, size, myni)));
00847 
00848     /* check for error */
00849     if (ret) {
00850         if ((nitems == 0) || (endOfFile()==EOF)) {
00851             *ritems = *ritems + myri;
00852             return true;
00853         }
00854         else {
00855             free(*ptr);
00856             *ptr=NULL;
00857             this->lasterror = EBADF;
00858             return false;
00859         }
00860     }
00861     free(*ptr);
00862     *ptr=NULL;
00863     return false;
00864 }
00865 
00866 
00867 bool MMSFile::getString(char *ptr, size_t size) {
00868     size_t toget;
00869 
00870     /* clear error */
00871     this->lasterror = 0;
00872 
00873     /* check input */
00874     if (!size) {
00875         this->lasterror = EINVAL;
00876         return false;
00877     }
00878 
00879     /* check if this->mode allowes to read from the file */
00880     switch(this->type) {
00881         case MMSFT_FILE:
00882             if ((this->mode==MMSFM_WRITE)||(this->mode==MMSFM_APPEND)) {
00883                 this->lasterror = EBADF;
00884                 return false;
00885             }
00886             break;
00887 
00888         case MMSFT_URL:
00889 #ifdef __HAVE_CURL__
00890             if (this->mode!=MMSFM_READ) {
00891                 this->lasterror = EBADF;
00892                 return false;
00893             }
00894 #else
00895             throw MMSFileError(-1, "compile curl support!");
00896 #endif
00897             break;
00898 
00899         default:
00900             /* unknown type */
00901             this->lasterror = EBADF;
00902             return false;
00903     }
00904 
00905     /* cache given? */
00906     if (this->usecache) {
00907         /* work with separate cache */
00908         if (this->cache) {
00909             /* calc available data */
00910             size_t availdata=this->cache_fsize-this->cache_fpos;
00911             if (availdata <= 0) {
00912                 availdata=0;
00913                 this->lasterror=EOF;
00914             }
00915 
00916             /* one byte for zero termination */
00917             toget=size - 1;
00918             *ptr=0;
00919 
00920             /* calc bytes to copy */
00921             if (availdata < toget) toget=availdata;
00922 
00923             /* through the cache */
00924             for(unsigned int loop=this->cache_fpos; loop < this->cache_fpos + toget; loop++) {
00925                 if (this->cache[loop] == '\n') {
00926                     toget=loop+1-this->cache_fpos;/* include newline */
00927                     break;
00928                 }
00929             }
00930 
00931             /* copy from cache to callers buffer */
00932             memcpy(ptr, &(this->cache[this->cache_fpos]), toget);
00933             ptr[toget]=0;
00934 
00935             /* increase fpos */
00936             this->cache_fpos+=toget;
00937 
00938             return true;
00939         }
00940         /* no cache available */
00941         this->lasterror = EBADF;
00942         return false;
00943     }
00944 
00945     /* normal access without separate cache */
00946     switch(this->type) {
00947         case MMSFT_FILE:
00948             if (this->file) {
00949                 *ptr=0;
00950                 ptr = fgets(ptr, size, this->file);
00951                 if (!ptr) {
00952                     /* error, check if eof */
00953                     if (endOfFile()==EOF) return true;
00954 
00955                     /* a read error */
00956                     this->lasterror = EBADF;
00957                     return false;
00958                 }
00959                 return true;
00960             }
00961             this->lasterror = EBADF;
00962             return false;
00963 
00964         case MMSFT_URL:
00965 #ifdef __HAVE_CURL__
00966             if (this->curl) {
00967                 /* one byte for zero termination */
00968                 toget=size - 1;
00969                 *ptr=0;
00970 
00971                 /* receive data, if not available */
00972                 if (!fillCurlBuffer(toget)) {
00973                     this->lasterror = EBADF;
00974                     return false;
00975                 }
00976                 if (!this->buf_pos) {
00977                     this->lasterror = EBADF;
00978                     return false;
00979                 }
00980                 if (this->buf_pos < toget)
00981                     toget = this->buf_pos;
00982 
00983                 /* through the buffer */
00984                 for(unsigned int loop=0; loop < toget; loop++) {
00985                     if (this->buffer[loop] == '\n') {
00986                         toget=loop+1;/* include newline */
00987                         break;
00988                     }
00989                 }
00990 
00991                 /* copy from cached buffer to callers buffer */
00992                 memcpy(ptr, this->buffer, toget);
00993                 ptr[toget]=0;
00994 
00995                 /* freeing unneeded memory in my buffer */
00996                 freeCurlBuffer(toget);
00997 
00998                 return true;
00999             }
01000             this->lasterror = EBADF;
01001             return false;
01002 #else
01003             throw MMSFileError(-1, "compile curl support!");
01004 #endif
01005 
01006         default:
01007             /* unknown type */
01008             this->lasterror = EBADF;
01009             return false;
01010     }
01011 }
01012 
01013 
01014 bool MMSFile::getStringEx(char **ptr, size_t size) {
01015     size_t  slen, mys;
01016     void    *newptr;
01017     bool    ret=false;
01018 
01019     /* clear error */
01020     this->lasterror = 0;
01021 
01022     /* init return ptr */
01023     *ptr=NULL;
01024 
01025     /* check input */
01026     if (!size) {
01027         this->lasterror = EINVAL;
01028         return false;
01029     }
01030 
01031     /* init other */
01032     mys=0x1000;
01033 
01034     /* read file */
01035     do {
01036         if (endOfFile()==EOF) break;
01037 
01038         slen=0;
01039         if (*ptr) {
01040             if (!**ptr) break;
01041             slen=strlen(*ptr);
01042             if ((*ptr)[slen-1] == '\n') {
01043                 size=0;
01044                 break;
01045             }
01046         }
01047         if (size == 0) break;
01048 
01049         if (size<mys) mys=size;
01050         size-=mys;
01051 
01052         newptr=realloc(*ptr, (!slen)?(slen+mys):(slen+mys+1));
01053         if (!newptr) {
01054             free(*ptr);
01055             *ptr=NULL;
01056             this->lasterror = ENOMEM;
01057             return false;
01058         }
01059         *ptr=(char*)newptr;
01060 
01061     } while ((ret=getString(&((*ptr)[slen]), (!slen)?mys:(mys+1))));
01062 
01063     /* check for error */
01064     if (ret) {
01065         if ((size == 0) || (endOfFile()==EOF)) {
01066             return true;
01067         }
01068         else {
01069             free(*ptr);
01070             *ptr=NULL;
01071             this->lasterror = EBADF;
01072             return false;
01073         }
01074     }
01075     free(*ptr);
01076     *ptr=NULL;
01077     return false;
01078 }
01079 
01080 
01081 bool MMSFile::getLine(char **ptr) {
01082     int slen;
01083 
01084     if (getStringEx(ptr))
01085         if (*ptr)
01086             if (**ptr) {
01087                 slen=strlen(*ptr);
01088                 if ((*ptr)[slen-1]=='\n')
01089                     (*ptr)[slen-1]=0;
01090                 return true;
01091             }
01092 
01093     return false;
01094 }
01095 
01096 bool MMSFile::getLine(string &line) {
01097     int slen;
01098     char *ptr = NULL;
01099     int ret = false;
01100 
01101     if (getStringEx(&ptr)) {
01102         if (ptr) {
01103             if (*ptr) {
01104                 slen=strlen(ptr);
01105                 if ((ptr)[slen-1]=='\n')
01106                     (ptr)[slen-1]=0;
01107                 line = ptr;
01108                 ret = true;
01109             }
01110             free(ptr);
01111         }
01112     }
01113 
01114     return ret;
01115 }
01116 
01117 bool MMSFile::getChar(char *ptr) {
01118     char    retc;
01119     size_t  ritems;
01120 
01121     if (!ptr) ptr=&retc;
01122 
01123     if (readBuffer(ptr, &ritems, 1, 1))
01124         if (ritems==1)
01125             return true;
01126 
01127     return false;
01128 }
01129 
01130 
01131 bool MMSFile::writeBuffer(void *ptr, size_t *ritems, size_t size, size_t nitems) {
01132     size_t  myri;
01133 
01134     /* clear error */
01135     this->lasterror = 0;
01136 
01137     /* clear ritems */
01138     if (!ritems) ritems=&myri;
01139     *ritems=0;
01140 
01141     /* check input */
01142     if ((!size) || (!nitems)) {
01143         this->lasterror = EINVAL;
01144         return false;
01145     }
01146 
01147     /* check if this->mode allowes to write to the file */
01148     switch(this->type) {
01149         case MMSFT_FILE:
01150             if (this->mode==MMSFM_READ) {
01151                 this->lasterror = EBADF;
01152                 return false;
01153             }
01154             break;
01155 
01156         case MMSFT_URL:
01157 #ifdef __HAVE_CURL__
01158             /* currently I cannot write to an url stream */
01159             /* so I will always fail */
01160             this->lasterror = EBADF;
01161             return false;
01162 #else
01163             throw MMSFileError(-1, "compile curl support!");
01164 #endif
01165 
01166         default:
01167             /* unknown type */
01168             this->lasterror = EBADF;
01169             return false;
01170     }
01171 
01172     /* cache given? */
01173     if (this->usecache) {
01174         /* work with separate cache is not supported in this version */
01175         this->lasterror = EBADF;
01176         return false;
01177     }
01178 
01179     /* normal access without separate cache */
01180     switch(this->type) {
01181         case MMSFT_FILE:
01182             if (this->file) {
01183                 *ritems = fwrite(ptr, size, nitems, this->file);
01184                 if (*ritems < nitems) {
01185                     /* a write error */
01186                     this->lasterror = EBADF;
01187                     return false;
01188                 }
01189                 return true;
01190             }
01191             this->lasterror = EBADF;
01192             return false;
01193 
01194         case MMSFT_URL:
01195 #ifdef __HAVE_CURL__
01196             if (this->curl) {
01197                 /* currently I cannot write to an url stream */
01198                 /* so I will always fail */
01199             }
01200             this->lasterror = EBADF;
01201             return false;
01202 #else
01203             throw MMSFileError(-1, "compile curl support!");
01204 #endif
01205 
01206         default:
01207             /* unknown type */
01208             this->lasterror = EBADF;
01209             return false;
01210     }
01211 }

Generated by doxygen