#include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_UNISTD_H #include #else #include #endif #include "Input.h" #include "Exceptions.h" #include "gettext.h" #ifndef S_ISREG #define S_ISREG(x) 1 #endif Input::Input(const String & no) throw (GeneralException) : Handle(no.strlen() ? open(no.to_charp(), O_RDONLY) : dup(0)), n(no) { #ifdef DEBUG fprintf(stderr, "Opening file %s, Input at %p\n", no.to_charp(), this); #endif if (GetHandle() < 0) { throw IOGeneral(String(_("Error opening file ")) + no + _(" for reading: ") + strerror(errno)); } struct stat s; fstat(GetHandle(), &s); date_modif = s.st_mtime; if (S_ISREG(s.st_mode)) { size = seek(0, SEEK_END); seek(0, SEEK_SET); } } Input::Input(const Input & i) : Handle(i), n(i.n), size(i.size), date_modif(i.date_modif) { } bool Input::CanWrite() const { return 0; } bool Input::CanRead() const { return 1; } bool Input::CanSeek() const { struct stat s; fstat(GetHandle(), &s); return S_ISREG(s.st_mode); } String Input::GetName() const { return n; } ssize_t Input::GetSize() const { return size; } time_t Input::GetModif() const { return date_modif; } off_t Input::seek(off_t offset, int whence) throw (GeneralException) { if ((itell = lseek(GetHandle(), offset, whence)) < 0) { throw IOGeneral(String(_("Error seeking file ")) + GetName() + _(": ") + strerror(errno)); } #ifdef PARANOID_SEEK if (itell != lseek(GetHandle(), 0, SEEK_CUR)) { throw IOGeneral(String(_("Error seeking file ")) + GetName() + _(": the position does not match")); } #endif return itell; } #ifdef HOOK_STDS Stdin_t::Stdin_t() { } #endif bool Stdin_t::CanSeek() const { return 0; } String Stdin_t::GetName() const { return "Stdin"; } Stdin_t Stdin; Archive * Archive::header = 0; Archive::Archive(const String & fname, ArchiveType type) : name(fname), archive(fname) throw (GeneralException) { switch(type) { case ARCHIVE_BUILTIN: break; default: throw GeneralException("Archive: unsupported archive format."); } next = header; prev = 0; header = this; if (next) next->prev = this; } Archive::~Archive() { if (prev) prev->next = next; if (next) next->prev = prev; if (header == this) header = next; } bool Archive::inarchive(const String & fname) { Archive * p; for (p = header; p; p = p->next) { if (p->inarchive(fname)) return true; } return false; } Input & Archive::open(const String & fname) throw (GeneralException) { Archive * p; for (p = header; p; p = p->next) { if (p->inarchive(fname)) return p->open(fname); } throw IOGeneral("File `" + fname + "' not found in archive collection."); } bool Archive::inarchivein(const String & fname) { Archive::FileTree * p = filetree->child; ssize_t pos; String name = fname; String reste; while((name != "") && p) { ssize_t pos = name.strchr('/'); if (pos >= 0) { reste = name.extract(0, pos - 1); name = name.extract(pos + 1); } else { reste = name; name = ""; } while (p) { if (p->name == reste) { p = p->child; break; } else { p = p->next; } } } return p; } Input & Archive::openin(const String & fname) throw (GeneralException) { Archive::FileTree * p = filetree->child; ssize_t pos; String name = fname; String reste; while((name != "") && p) { ssize_t pos = name.strchr('/'); if (pos >= 0) { reste = name.extract(0, pos - 1); name = name.extract(pos + 1); } else { reste = name; name = ""; } while (p) { if (p->name == reste) { p = p->child; break; } else { p = p->next; } } } if (!p) throw IOGeneral("File `" + fname + "' not in archive " + name); if (p->child) throw IOGeneral("File `" + fname + "' in archive " + name + " is a directory - can't open."); Input file(archive); file->seek(p->ptr); return file; } Archive::FileTree::FileTree(const String & fname, size_t fsize, Archive::FileTree * fFather, int ftype) : name(fname), type(ftype), size(fsize), next(0), prev(0), father(fFather), child(0) { if (father) { if (father->child) { FileTree * p; for (p = father->child; p->next; p = p->next); p->next = this; prev = p; } } } Archive::FileTree::~FileTree() { if (child) delete child; if (next) next->prev = prev; if (prev) prev->next = next; if (father) { if (father->child == this) father->child = next; father->touched(); } } void Archive::FileTree::touched() { if (father) father->touched() else compute_ptrs(ptr); } int Archive::FileTree::compute_ptrs(int cptr) { ptr = cptr; if (child) { FileTree * p; size = 0; for (p = child; p; p = p->next) { size += p->compute_ptrs(ptr + size) - ptr; } } return size + ptr; }