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

Generated by doxygen