00001
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <unistd.h>
00028 #include <fcntl.h>
00029 #include <errno.h>
00030
00031 #include "magic/miodevice.h"
00032
00033 BEGIN_NAMESPACE (MagiC);
00034
00036
00037
00038
00039
00040
00041
00042
00044
00045
00048 IODevice::IODevice ()
00049 {
00050 mType = 0;
00051 mMode = 0;
00052 mState = 0;
00053 mStatus = 0;
00054 }
00055
00058 IODevice::~IODevice ()
00059 {
00060 }
00061
00064 bool IODevice::isDirectAccess () const
00065 {
00066 return false;
00067 }
00068
00071 bool IODevice::isSequentialAccess () const
00072 {
00073 return false;
00074 }
00075
00078 bool IODevice::isSynchronous () const
00079 {
00080 return mMode & IO_Raw;
00081 }
00082
00085 bool IODevice::isAsynchronous () const
00086 {
00087 return !(mMode & IO_Raw);
00088 }
00089
00112 bool IODevice::open (int mode )
00113 {
00114 MUST_OVERLOAD;
00115 return false;
00116 }
00117
00122 void IODevice::close ()
00123 {
00124 MUST_OVERLOAD;
00125 }
00126
00137 void IODevice::flush ()
00138 {
00139 MUST_OVERLOAD;
00140 }
00141
00146 uint IODevice::size () const
00147 {
00148 MUST_OVERLOAD;
00149 return 0;
00150 }
00151
00156 int IODevice::at () const
00157 {
00158 MUST_OVERLOAD;
00159 return 0;
00160 }
00161
00166 bool IODevice::atEnd () const
00167 {
00168 MUST_OVERLOAD;
00169 return true;
00170 }
00171
00178 bool IODevice::seek (int position )
00179 {
00180 return false;
00181 }
00182
00187 bool IODevice::reset ()
00188 {
00189 return true;
00190 }
00191
00196 int IODevice::readBlock (char* data,
00197 uint maxlen )
00198 throw (device_not_open)
00199 {
00200 MUST_OVERLOAD;
00201 return 0;
00202 }
00203
00208 int IODevice::writeBlock (
00209 const char* data,
00210 uint len)
00211 throw (device_not_open)
00212 {
00213 MUST_OVERLOAD;
00214 return 0;
00215 }
00216
00242 int IODevice::readLine (
00243 char* data,
00244 uint maxlen)
00245 throw (device_not_open)
00246 {
00247 int pos = 0;
00248
00249
00250
00251 for (pos=0; !atEnd() && pos< int(maxlen)-1; pos++) {
00252 char ch = getch();
00253 data[pos] = ch;
00254 if (ch == '\n')
00255 break;
00256 }
00257 data[pos+1] = '\0';
00258
00259 return 0;
00260 }
00261
00266 int IODevice::writeBlock (const String& str )
00267 throw (device_not_open)
00268 {
00269 return writeBlock ((const char*) str, str.length());
00270 }
00271
00276 Ref<String> IODevice::readAll ()
00277 throw (device_not_open)
00278 {
00279 Ref<String> result = new String ();
00280 char buffer[1024];
00281
00282 while (!atEnd()) {
00283 int bytesread = readBlock (buffer, 1024);
00284 if (bytesread == 0)
00285 break;
00286 result->append (buffer, bytesread);
00287 }
00288
00289 return result;
00290 }
00291
00297 List<String>* IODevice::readLines ()
00298 throw (device_not_open)
00299 {
00300 List<String>* result = new List<String> ();
00301
00302 return result;
00303 }
00304
00309 int IODevice::getch ()
00310 throw (device_not_open)
00311 {
00312 MUST_OVERLOAD;
00313 return 0;
00314 }
00315
00318 void IODevice::putch (char)
00319 throw (device_not_open)
00320 {
00321 MUST_OVERLOAD;
00322 }
00323
00324
00329 void IODevice::ungetch (char)
00330 throw (device_not_open)
00331 {
00332 MUST_OVERLOAD;
00333 }
00334
00335
00336
00338
00339
00340
00341
00342
00343
00344
00346
00351 File::File (FILE* file )
00352 : IODevice ()
00353 {
00354 mName = "";
00355 mpFile = file;
00356 mFd = fileno (mpFile);
00357
00358
00359 setOpen ();
00360 }
00361
00370 File::File (const String& name ,
00371 int mode )
00372 throw (open_failure)
00373 : IODevice ()
00374 {
00375 mName = name;
00376 mpFile = NULL;
00377 mFd = 0;
00378
00379 if (mode) {
00380
00381 if (! ((mode & IO_Readable) || (mode & IO_Writable)))
00382 throw open_failure (i18n("File '%1' must be opened either readable or writable or both; mode was %2.")
00383 .arg(mName).arg(mode));
00384
00385
00386 if (! open (mode))
00387 throw open_failure (i18n("Opening file '%1' with flags %2 failed for some reason.")
00388 .arg(mName).arg(mode));
00389 setOpen ();
00390 }
00391 }
00392
00398 bool File::exists () const throw (system_failure)
00399 {
00400 struct stat statbuf;
00401
00402
00403 int result = stat ((CONSTR) mName, &statbuf);
00404
00405 if (result != 0) {
00406
00407 if (errno == ENOENT)
00408 return false;
00409
00410
00411 throw system_failure (i18n("System error '%1' while checking the existence of file '%2'.")
00412 .arg(strerror(errno)).arg(mName));
00413 }
00414
00415 return true;
00416 }
00417
00422 bool File::remove ()
00423 {
00424 int result = ::remove ((CONSTR) mName);
00425 if (result != 0)
00426 return true;
00427 else
00428 return false;
00429 }
00430
00431
00432
00433
00434 bool File::open (int mode)
00435 {
00436 if (isOpen())
00437 close ();
00438
00439
00440 String fopenMode = translateToFOpenMode (mode);
00441 if (fopenMode.isEmpty())
00442 return false;
00443
00444
00445 FILE* file = fopen ((CONSTR) mName, (CONSTR) fopenMode);
00446
00447 #ifdef IODEV_USE_EXCEPTIONS
00448 if (!file) {
00449
00450
00451 if (errno == EINVAL)
00452 throw invalid_flags (i18n("Invalid mode flags '%1' for opening file '%2'.")
00453 .arg(fopenMode).arg(mName));
00454 if (errno == ENOENT)
00455 throw file_not_found (i18n("File '%2' not found.")
00456 .arg(mName));
00457
00458 throw open_failure (i18n("Error '%1' while trying to open file '%2'.")
00459 .arg(strerror(errno)).arg(mName));
00460 }
00461 #else
00462 if (!file)
00463 return false;
00464 #endif
00465
00466
00467 mpFile = file;
00468 mFd = fileno (mpFile);
00469 setMode (mode);
00470 setOpen ();
00471
00472 return true;
00473 }
00474
00475
00476
00477
00478 void File::close ()
00479 {
00480 #ifdef IODEV_USE_EXCEPTIONS
00481 if (! mpFile)
00482 throw device_not_open (i18n ("File not open when closing file '%1'.").arg(mName));
00483 #else
00484 if (! mpFile)
00485 return;
00486 #endif
00487
00488
00489 fclose (mpFile);
00490
00491
00492 mpFile = NULL;
00493 mFd = 0;
00494 setState (IO_Open, false);
00495 }
00496
00497
00498
00499
00500 void File::flush ()
00501 {
00502 if (! mpFile)
00503 throw device_not_open (i18n ("File not open when flushing file '%1'.").arg(mName));
00504
00505 fflush (mpFile);
00506 }
00507
00510 uint File::size () const
00511 {
00512 struct stat statbuf;
00513
00514
00515 int callResult = stat ((CONSTR) mName, &statbuf);
00516
00517 if (!callResult)
00518 throw system_failure (i18n("System error '%1' while checking the size of file '%1'.")
00519 .arg(strerror(errno)).arg(mName));
00520
00521 return statbuf.st_size;
00522 }
00523
00524
00525
00526
00527 int File::at () const
00528 {
00529 if (!isOpen())
00530 throw device_not_open (i18n ("File not open when inquiring the current position in file '%1'.").arg(mName));
00531
00532 int position = ftell (mpFile);
00533 if (position < 0)
00534 throw system_failure (i18n("System error '%1' while inquiring the current position in file '%1'.")
00535 .arg(strerror(errno)).arg(mName));
00536
00537 return position;
00538 }
00539
00540
00541
00542
00543 bool File::seek (int position)
00544 {
00545 if (!isOpen ())
00546 throw device_not_open (i18n ("File not open when inquiring the current position in file '%1'.").arg(mName));
00547
00548 int callResult = fseek (mpFile, (long) position, SEEK_SET);
00549
00550 if (!callResult)
00551 return false;
00552
00553 return true;
00554 }
00555
00558 bool File::atEnd () const
00559 {
00560 if (mpFile)
00561 return feof (mpFile);
00562 else
00563 return true;
00564 }
00565
00572 int File::readBlock (char* data,
00573 uint maxlen )
00574 throw (device_not_open)
00575 {
00576 ASSERT (data && maxlen>0);
00577 if (atEnd())
00578 return 0;
00579
00580
00581 int bytesread = fread (data, 1, maxlen, mpFile);
00582
00583 if (feof(mpFile))
00584 setState (IO_EOS);
00585
00586 return bytesread;
00587 }
00588
00589
00590
00591
00592 int File::readLine (char* data,
00593 uint maxlen )
00594 throw (device_not_open)
00595 {
00596 ASSERT (data && maxlen>0);
00597 if (atEnd())
00598 return 0;
00599
00600
00601 fgets (data, maxlen, mpFile);
00602
00603 if (feof(mpFile))
00604 setState (IO_EOS);
00605
00606 return strlen (data);
00607 }
00608
00616 int File::readLine (String& buffer,
00617 int maxlen )
00618 throw (device_not_open)
00619 {
00620 if (atEnd())
00621 return 0;
00622
00623 if (!isOpen())
00624 throw device_not_open (i18n ("File not open when reading a line from file '%1'.").arg(mName));
00625
00626
00627 int bytesread = fgetS (mpFile, buffer);
00628
00629 if (feof(mpFile))
00630 setState (IO_EOS);
00631
00632 return bytesread;
00633 }
00634
00639 int File::writeBlock (const char* data,
00640 uint len )
00641 throw (device_not_open)
00642 {
00643 if (!isOpen())
00644 throw device_not_open (i18n ("File not open when writing to file '%1'.").arg(mName));
00645
00646
00647 int result = fwrite (data, 1, len, mpFile);
00648
00649 return result;
00650 }
00651
00652
00653
00654
00655 int File::getch ()
00656 throw (device_not_open)
00657 {
00658 if (!isOpen())
00659 throw device_not_open (i18n ("File not open when reading a from file '%1'.").arg(mName));
00660
00661
00662 int result = ::fgetc(mpFile);
00663
00664 if (result == EOF) {
00665 setState (IO_EOS);
00666 result = 0;
00667 return (-1);
00668 }
00669
00670 return result;
00671 }
00672
00673
00674
00675
00676 void File::putch (char ch)
00677 throw (device_not_open)
00678 {
00679 if (!isOpen())
00680 throw device_not_open (i18n ("File not open when writing to file '%1'.").arg(mName));
00681
00682
00683 fputc (ch, mpFile);
00684
00685 }
00686
00692 void File::ungetch (char ch)
00693 throw (device_not_open)
00694 {
00695 if (!isOpen())
00696 throw device_not_open (i18n ("File not open when ungetting from file '%1'.").arg(mName));
00697
00698
00699 if (state() & IO_EOS)
00700 setState (IO_EOS, false);
00701
00702
00703 ungetc (ch, mpFile);
00704
00705 }
00706
00707
00708
00709
00710 int File::handle ()
00711 {
00712 return mFd;
00713 }
00714
00717 String File::translateToFOpenMode (int mode ) throw (invalid_flags)
00718 {
00719 if (mode & IO_Readable)
00720 if (mode & IO_Writable)
00721 if (mode & IO_Append)
00722 return "a+";
00723 else
00724 if (mode & IO_Truncate)
00725 return "w+";
00726 else
00727 return "r+";
00728 else
00729 return "r";
00730 else
00731 if (mode & IO_Writable)
00732 if (mode & IO_Append)
00733 return "a";
00734 else
00735 return "w";
00736
00737 return "";
00738 }
00739
00742 int File::translateToOpenMode (int mode ) throw (invalid_flags)
00743 {
00744 int sysmode = 0;
00745 if (mode & IO_Readable)
00746 if (mode & IO_Writable)
00747 sysmode |= O_RDWR;
00748 else
00749 sysmode |= O_RDONLY;
00750 else
00751 if (mode & IO_Writable)
00752 sysmode |= O_WRONLY;
00753 else
00754 return false;
00755
00756 if (mode & IO_Append)
00757 sysmode |= O_APPEND;
00758
00759 if (mode & IO_Truncate)
00760 sysmode |= O_TRUNC;
00761
00762 return sysmode;
00763 }
00764
00765
00766
00768
00769
00770
00771
00772
00773
00774
00776
00779 Buffer::Buffer (int mode)
00780 {
00781 mpBuffer = new String();
00782 mPosition = 0;
00783 mOwnBuffer = true;
00784
00785
00786 if (mode)
00787 if (! open (mode))
00788 throw open_failure (i18n("Opening Buffer device with flags %1 failed for some reason.")
00789 .arg(mode));
00790 }
00791
00796 Buffer::Buffer (String& buffer, int mode)
00797 {
00798 mpBuffer = &buffer;
00799 mPosition = 0;
00800 mOwnBuffer = false;
00801
00802
00803 if (mode)
00804 if (! open (mode))
00805 throw open_failure (i18n("Opening Buffer device with flags %1 failed for some reason.")
00806 .arg(mode));
00807 }
00808
00809 Buffer::~Buffer ()
00810 {
00811 if (mOwnBuffer)
00812 delete mpBuffer;
00813 }
00814
00815 bool Buffer::open (int mode)
00816 {
00817 setMode (mode);
00818 setOpen ();
00819
00820
00821 reset ();
00822
00823 if (mode & IO_Truncate)
00824 mpBuffer->empty ();
00825
00826 if (mode & IO_Append)
00827 mPosition = mpBuffer->length ();
00828
00829 return true;
00830 }
00831
00832 bool Buffer::reset ()
00833 {
00834 if (!IODevice::reset ())
00835 return false;
00836
00837 mPosition = 0;
00838 return true;
00839 }
00840
00841 bool Buffer::atEnd () const
00842 {
00843 if ((uint) mPosition >= size())
00844 return true;
00845 else
00846 return false;
00847 }
00848
00849 int Buffer::readBlock (char* data, uint maxlen)
00850 throw (device_not_open)
00851 {
00852 if ((uint) mPosition >= size())
00853 return 0;
00854
00855 int remains = mpBuffer->length() - mPosition;
00856 int readcount = ((uint) remains > maxlen)? maxlen : remains;
00857
00858 memcpy (data, ((const char*) *mpBuffer) + mPosition, readcount);
00859
00860 mPosition += readcount;
00861 return readcount;
00862 }
00863
00864 int Buffer::writeBlock (const char* data, uint len)
00865 throw (device_not_open)
00866 {
00867 mpBuffer->replace (mPosition, data, len);
00868 mPosition += len;
00869 return len;
00870 }
00871
00872 int Buffer::readLine (char* data, uint maxlen)
00873 throw (device_not_open)
00874 {
00875 if ((uint) mPosition >= size())
00876 return 0;
00877
00878 int remains = mpBuffer->length() - mPosition;
00879 int maxread = ((uint) remains > maxlen)? maxlen : remains;
00880 uint newlinePos = mPosition;
00881
00882
00883 for (uint i=0; i < (uint) maxread; i++)
00884 if ((*mpBuffer)[newlinePos++] == '\n')
00885 break;
00886
00887
00888 int readcount = newlinePos - mPosition;
00889
00890
00891 memcpy (data, ((const char*) *mpBuffer) + mPosition, newlinePos-mPosition);
00892 data[readcount] = '\x00';
00893
00894
00895 mPosition = newlinePos;
00896
00897 return readcount;
00898 }
00899
00900 int Buffer::writeBlock (const String& str)
00901 throw (device_not_open)
00902 {
00903 mpBuffer->append (str);
00904 return str.length();
00905 }
00906
00907 int Buffer::getch ()
00908 throw (device_not_open)
00909 {
00910 if ((uint) mPosition >= size())
00911 return -1;
00912
00913
00914 return (*mpBuffer)[uint(mPosition)];
00915 }
00916
00917 void Buffer::putch (char c)
00918 throw (device_not_open)
00919 {
00920
00921
00922 if ((uint) mPosition >= size()) {
00923
00924 mpBuffer->append (c);
00925 mPosition++;
00926 } else
00927 (*mpBuffer)[uint(mPosition++)] = c;
00928 }
00929
00930 void Buffer::ungetch (char c)
00931 throw (device_not_open)
00932 {
00933 if (mPosition==0)
00934 return;
00935
00936
00937 (mpBuffer)[--mPosition] = c;
00938 }
00939
00940 END_NAMESPACE;
00941