diff options
Diffstat (limited to 'lib/Input.cc')
-rw-r--r-- | lib/Input.cc | 1160 |
1 files changed, 580 insertions, 580 deletions
diff --git a/lib/Input.cc b/lib/Input.cc index 2e91e03..c27e168 100644 --- a/lib/Input.cc +++ b/lib/Input.cc @@ -1,580 +1,580 @@ -/*
- * Baltisot
- * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* $Id: Input.cc,v 1.48 2004-11-27 21:35:19 pixel Exp $ */
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#else
-#include <io.h>
-#endif
-
-#include "Input.h"
-#include "Exceptions.h"
-#include "gettext.h"
-
-#ifndef S_ISREG
-#define S_ISREG(x) 1
-#endif
-
-#ifdef WORDS_BIGENDIAN
-#define BUILTIN_SIG 0x4e504151
-#else
-#define BUILTIN_SIG 0x5141504e
-#endif
-
-/*
-
- NPAQ file format
- ================
-
-off|siz|description
----+---+-----------
- 0 | 4 | Magic: NPAQ
- 4 | X | Index
-4+X| Y | Files
-
-Index:
-It's composed of entries. Each entries have the same format:
-
-off|siz|description
----+---+-----------
- 0 | 1 | name size = n
- 1 | n | file name
-1+n| 4 | file size
-5+n| 1 | type --> 0 = file / 1 = directory
-
-If it's a directory, it means the following entries belongs to this directory.
-If n = 0, there is nothing else afterward (no filesize nor type) and it
-means the end of the current directory. The end of the root directory
-means the end of the index.
-
-Files:
-Each file are gzipped. They are all concatenated after the index. They
-all start with a four bytes length which correspond to the unpacked size.
-The size in the index corresponds to the size of the gzipped result plus
-those 4 bytes.
-
-*/
-
-static Input::openresults_t gresults;
-
-Input::Input(const String & no) throw (GeneralException) :
- Handle(no.strlen() ? wrapopen(no, &gresults) : dup(0)),
- n(no) {
-
-#ifdef DEBUG
- printm(M_BARE, String(_("Opening file")) + no + _("Input at %p\n"), this);
-#endif
-
- if (GetHandle() < 0) {
-#ifdef DEBUG
- printm(M_BARE, "Got handle: %i opening file " + no + "\n", GetHandle());
-#endif
- throw IOGeneral(String(_("Error opening file ")) + no + _(" for reading: ") + strerror(errno));
- }
-
- results = gresults;
-
- UNLOCK
-
- fromarchive = false;
- if (results.name == "") {
- struct stat s;
- fstat(GetHandle(), &s);
- date_modif = s.st_mtime;
-
-#ifdef __linux__
- if (S_ISREG(s.st_mode)) {
-#endif
-#if 0
-#if defined (_WIN32) && !defined (NO_HFILE)
- if (hFile) {
- GetFileSize(hFile, (LPDWORD)&size);
- } else
-#endif
-#endif
- {
- size = seek(0, SEEK_END);
- seek(0, SEEK_SET);
- }
-#ifdef __linux__
- }
-#endif
- } else {
-#ifdef DEBUG
- printm(M_INFO, String(_("Opening file in archive, position ")) + results.ptr + "\n");
-#endif
- size = results.size;
- seek(results.ptr, SEEK_SET);
- size = readU32();
- date_modif = 0;
- SetZ();
- fromarchive = true;
- itell = 0;
- }
-}
-
-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 (!fromarchive) {
- 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;
- } else {
- return Handle::seek(offset, whence);
- }
-}
-
-int Input::wrapopen(const String & fname, openresults_t * results) {
- LOCK;
-#ifdef DEBUG
- printm(M_INFO, _("Wrap-opening ") + fname + "\n");
-#endif
- if (fname[0] != '/') {
- Archive * t;
- t = Archive::inarchive(fname);
- if (t) {
-#ifdef DEBUG
- printm(M_BARE, _("Trying to open the file in archive, since it seems to be here\n"));
-#endif
- hFile = 0;
-#if defined (_WIN32) && !defined (NO_HFILE)
-// hFile = t->GetHandle()->GetHFile();
-#endif
- return t->open(fname, results);
- }
- }
- results->name = "";
- hFile = 0;
-#if !defined (_WIN32) || defined (NO_HFILE)
- return open(fname.to_charp(), O_RDONLY
-#ifdef _WIN32
- | O_BINARY
-#endif
- );
-#else
- hFile = CreateFile(fname.to_charp(), GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
- return _open_osfhandle((INT_PTR) hFile, O_RDONLY | O_BINARY);
-#endif
-}
-
-void Input::SetZ(int l) throw(GeneralException) {
- if (!fromarchive)
- Handle::SetZ(l);
-}
-
-Stdin_t::Stdin_t() { }
-
-bool Stdin_t::CanSeek() const {
- return 0;
-}
-
-String Stdin_t::GetName() const {
- return "Stdin";
-}
-
-#ifdef HOOK_STDS
-Stdin_t Stdin;
-#endif
-
-Archive * Archive::header = 0;
-
-Archive::Archive(const String & fname, int atype) :
- name(fname), archive(new Input(fname)), type(atype) {
- create();
-}
-
-Archive::Archive(Handle * hand, int atype) :
- name(hand->GetName()), archive(hand), type(atype) {
- create();
-}
-
-#ifdef _MSC_VER
-#pragma pack(1)
-#endif
-
-struct PEsection_t {
- char name[8];
- Uint32 VSize, VAdd, SizeOf, Pointer, PTRelocs, PTLNs;
- Uint16 NR, NLN;
- Uint32 Chars;
-} PACKED;
-
-struct elf_header_t {
- union {
- Uint8 raw[16];
- struct e_ident_t {
- Uint8 ei_magic[4];
- Uint8 ei_class;
- Uint8 ei_data;
- Uint8 ei_version;
- } cook;
- } e_ident;
- Uint16 e_type;
- Uint16 e_machine;
- Uint32 e_version;
- Uint32 e_entry;
- Uint32 e_phoff;
- Uint32 e_shoff;
- Uint32 e_flags;
- Uint16 e_ehsize;
- Uint16 e_phentsize;
- Uint16 e_phnum;
- Uint16 e_shentsize;
- Uint16 e_shnum;
- Uint16 e_shstrndx;
-} PACKED;
-
-struct elf_section_t {
- Uint32 sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size;
- Uint32 sh_link, sh_info, sh_addralign, sh_entsize;
-} PACKED;
-
-void Archive::create() throw (GeneralException) {
- char buffer[1024];
- int len;
- Uint32 sig, ptr, maxptr = 0, startptr;
- Uint16 sections;
- PEsection_t PEsection;
- size_t size;
- FileTree * p = &filetree, * t;
- String ifname;
- int i;
-
- switch(type) {
- case ARCHIVE_EXECUTABLE:
- startptr = archive->tell();
- sig = archive->readU32();
- archive->seek(-4, SEEK_CUR);
- if ((sig & 0xffff) == 0x5a4d) { /* MZ */
- archive->seek(60, SEEK_CUR);
- sig = archive->readU32();
- archive->seek(sig - 64, SEEK_CUR);
- sig = archive->readU32();
- if (sig != 0x4550)
- throw GeneralException(_("Archive: file is not a PE."));
- archive->seek(2, SEEK_CUR);
- sections = archive->readU16();
- archive->seek(240, SEEK_CUR);
- for (i = 0; i < sections; i++) {
- archive->read(&PEsection, sizeof(PEsection));
- printm(M_INFO, "Section: %s\n", PEsection.name);
- ptr = PEsection.Pointer + PEsection.SizeOf;
- if (ptr > maxptr)
- maxptr = ptr;
- }
- archive->seek(startptr - archive->tell() + maxptr, SEEK_CUR);
- } else if (sig == 0x464c457f) { /* ELF */
- elf_header_t head;
- elf_section_t sec;
- int cur_end, max_end = 0;
- int i;
-
- archive->read(&head, sizeof(head));
- archive->seek(startptr + head.e_shoff);
-
- for (i = 0; i < head.e_shnum; i++) {
- archive->read(&sec, sizeof(elf_section_t));
- archive->seek(head.e_shentsize - sizeof(elf_section_t), SEEK_CUR);
- if (sec.sh_type == 8)
- continue;
- cur_end = sec.sh_offset + sec.sh_size;
- if (cur_end > max_end)
- max_end = cur_end;
- }
- archive->seek(startptr + max_end);
- }
- case ARCHIVE_BUILTIN:
- memset(buffer, 0, 4);
- archive->read(buffer, 4);
- if (*((Uint32 *)buffer) != BUILTIN_SIG)
- throw GeneralException(_("Archive: not in built-in format."));
- while (p) {
- archive->read(buffer, 1);
- len = *buffer;
- if (len) {
- archive->read(buffer, len);
- buffer[len] = 0;
- ifname = buffer;
- size = archive->readU32();
- archive->read(buffer, 1);
-#ifdef DEBUG
- printm(M_BARE, _("Adding file `") + ifname + _("' to node `") + p->name + "'\n");
-#endif
- t = new FileTree(ifname, size, buffer[0], p);
- if (buffer[0])
- p = t;
- } else {
- p = p->Father();
- }
- }
- filetree.compute_ptrs(archive->tell());
- 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;
-
- delete archive;
-}
-
-Archive * Archive::inarchive(const String & fname) {
- Archive * p;
- for (p = header; p; p = p->next) {
-#ifdef DEBUG
- printm(M_BARE, _("Looking for file `") + fname + _("' in archive ") + p->name + "\n");
-#endif
- if (p->inarchivein(fname)) {
-#ifdef DEBUG
- printm(M_BARE, _("File `") + fname + _("' found in archive ") + p->name + "\n");
-#endif
- return p;
- }
- }
- return 0;
-}
-
-int Archive::open(const String & fname, Input::openresults_t * results) {
-#if 0
- Archive * p;
-
- for (p = header; p; p = p->next) {
- bool t;
- t = p->inarchive(fname);
- if (t)
- return p->openin(fname, results);
- }
- throw IOGeneral(_("File `") + fname + _("' not found in archive collection."));
-#endif
- return openin(fname, results);
-}
-
-Handle * Archive::GetHandle() {
- return archive;
-}
-
-bool Archive::inarchivein(const String & fname) {
- Archive::FileTree * p = filetree.Child();
- ssize_t pos;
- String name = fname;
- String reste;
-
- while((name != "") && p) {
- pos = name.strchr('/');
- if (pos >= 0) {
- reste = name.extract(0, pos - 1);
- name = name.extract(pos + 1);
- } else {
- reste = name;
- name = "";
- }
-#ifdef DEBUG
- printm(M_BARE, _("Checking against node `") + p->name + "'\n");
-#endif
- while (p) {
- if (p->name == reste) {
- if (name != "")
- p = p->Child();
- break;
- } else {
- p = p->Next();
- }
- }
- }
-
- return p != 0;
-}
-
-int Archive::openin(const String & fname, Input::openresults_t * results) throw (GeneralException) {
- Archive::FileTree * p = filetree.Child();
- ssize_t pos;
- String name = fname;
- String reste;
-
- while((name != "") && p) {
- 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) {
- if (name != "")
- p = p->Child();
- break;
- } else {
- p = p->Next();
- }
- }
- }
-
- if (!p)
- throw IOGeneral(_("File `") + fname + _("' not in archive ") + this->name);
-
- if (p->Child())
- throw IOGeneral(_("File `") + fname + _("' in archive ") + this->name + _(" is a directory - can't open."));
-
- results->name = p->name;
- results->ptr = p->ptr;
- results->size = p->size;
- results->type = p->type;
- return archive->Dup();
-}
-
-Archive::FileTree::FileTree(const String & fname, size_t fsize, int ftype, Archive::FileTree * fFather) :
- 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;
- } else {
-#ifdef DEBUG
- std::cerr << _("Adding `") << fname << _("' as first child of node `") << father->name << "'\n";
-#endif
- father->child = this;
- }
- }
-}
-
-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(size_t cptr) {
- ptr = cptr;
-
-#ifdef DEBUG
- std::cerr << _("Computed pointer for `") << name << "' = " << ptr << std::endl;
- if (child)
- std::cerr << _("Node has child\n");
- else
- std::cerr << _("Node is ") << size << _(" bytes large.\n");
-#endif
-
- if (child) {
- FileTree * p;
- size = 0;
- for (p = child; p; p = p->next) {
- size = p->compute_ptrs(ptr + size) - ptr;
- }
- }
-
- return size + ptr;
-}
-
-Archive::FileTree * Archive::FileTree::Father() {
- return father;
-}
-
-Archive::FileTree * Archive::FileTree::Child() {
- return child;
-}
-
-Archive::FileTree * Archive::FileTree::Next() {
- return next;
-}
-
-Archive::FileTree * Archive::FileTree::Prev() {
- return prev;
-}
+/* + * Baltisot + * Copyright (C) 1999-2003 Nicolas "Pixel" Noble + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* $Id: Input.cc,v 1.49 2004-11-27 21:46:04 pixel Exp $ */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#else +#include <io.h> +#endif + +#include "Input.h" +#include "Exceptions.h" +#include "gettext.h" + +#ifndef S_ISREG +#define S_ISREG(x) 1 +#endif + +#ifdef WORDS_BIGENDIAN +#define BUILTIN_SIG 0x4e504151 +#else +#define BUILTIN_SIG 0x5141504e +#endif + +/* + + NPAQ file format + ================ + +off|siz|description +---+---+----------- + 0 | 4 | Magic: NPAQ + 4 | X | Index +4+X| Y | Files + +Index: +It's composed of entries. Each entries have the same format: + +off|siz|description +---+---+----------- + 0 | 1 | name size = n + 1 | n | file name +1+n| 4 | file size +5+n| 1 | type --> 0 = file / 1 = directory + +If it's a directory, it means the following entries belongs to this directory. +If n = 0, there is nothing else afterward (no filesize nor type) and it +means the end of the current directory. The end of the root directory +means the end of the index. + +Files: +Each file are gzipped. They are all concatenated after the index. They +all start with a four bytes length which correspond to the unpacked size. +The size in the index corresponds to the size of the gzipped result plus +those 4 bytes. + +*/ + +static Input::openresults_t gresults; + +Input::Input(const String & no) throw (GeneralException) : + Handle(no.strlen() ? wrapopen(no, &gresults) : dup(0)), + n(no) { + +#ifdef DEBUG + printm(M_BARE, String(_("Opening file")) + no + _("Input at %p\n"), this); +#endif + + if (GetHandle() < 0) { +#ifdef DEBUG + printm(M_BARE, "Got handle: %i opening file " + no + "\n", GetHandle()); +#endif + throw IOGeneral(String(_("Error opening file ")) + no + _(" for reading: ") + strerror(errno)); + } + + results = gresults; + + UNLOCK + + fromarchive = false; + if (results.name == "") { + struct stat s; + fstat(GetHandle(), &s); + date_modif = s.st_mtime; + +#ifdef __linux__ + if (S_ISREG(s.st_mode)) { +#endif +#if 0 +#if defined (_WIN32) && !defined (NO_HFILE) + if (hFile) { + GetFileSize(hFile, (LPDWORD)&size); + } else +#endif +#endif + { + size = seek(0, SEEK_END); + seek(0, SEEK_SET); + } +#ifdef __linux__ + } +#endif + } else { +#ifdef DEBUG + printm(M_INFO, String(_("Opening file in archive, position ")) + results.ptr + "\n"); +#endif + size = results.size; + seek(results.ptr, SEEK_SET); + size = readU32(); + date_modif = 0; + SetZ(); + fromarchive = true; + itell = 0; + } +} + +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 (!fromarchive) { + 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; + } else { + return Handle::seek(offset, whence); + } +} + +int Input::wrapopen(const String & fname, openresults_t * results) { + LOCK; +#ifdef DEBUG + printm(M_INFO, _("Wrap-opening ") + fname + "\n"); +#endif + if (fname[0] != '/') { + Archive * t; + t = Archive::inarchive(fname); + if (t) { +#ifdef DEBUG + printm(M_BARE, _("Trying to open the file in archive, since it seems to be here\n")); +#endif + hFile = 0; +#if defined (_WIN32) && !defined (NO_HFILE) +// hFile = t->GetHandle()->GetHFile(); +#endif + return t->open(fname, results); + } + } + results->name = ""; + hFile = 0; +#if !defined (_WIN32) || defined (NO_HFILE) + return open(fname.to_charp(), O_RDONLY +#ifdef _WIN32 + | O_BINARY +#endif + ); +#else + hFile = CreateFile(fname.to_charp(), GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + return _open_osfhandle((INT_PTR) hFile, O_RDONLY | O_BINARY); +#endif +} + +void Input::SetZ(int l) throw(GeneralException) { + if (!fromarchive) + Handle::SetZ(l); +} + +Stdin_t::Stdin_t() { } + +bool Stdin_t::CanSeek() const { + return 0; +} + +String Stdin_t::GetName() const { + return "Stdin"; +} + +#ifdef HOOK_STDS +Stdin_t Stdin; +#endif + +Archive * Archive::header = 0; + +Archive::Archive(const String & fname, int atype) : + name(fname), archive(new Input(fname)), type(atype) { + create(); +} + +Archive::Archive(Handle * hand, int atype) : + name(hand->GetName()), archive(hand), type(atype) { + create(); +} + +#ifdef _MSC_VER +#pragma pack(1) +#endif + +struct PEsection_t { + char name[8]; + Uint32 VSize, VAdd, SizeOf, Pointer, PTRelocs, PTLNs; + Uint16 NR, NLN; + Uint32 Chars; +} PACKED; + +struct elf_header_t { + union { + Uint8 raw[16]; + struct e_ident_t { + Uint8 ei_magic[4]; + Uint8 ei_class; + Uint8 ei_data; + Uint8 ei_version; + } cook; + } e_ident; + Uint16 e_type; + Uint16 e_machine; + Uint32 e_version; + Uint32 e_entry; + Uint32 e_phoff; + Uint32 e_shoff; + Uint32 e_flags; + Uint16 e_ehsize; + Uint16 e_phentsize; + Uint16 e_phnum; + Uint16 e_shentsize; + Uint16 e_shnum; + Uint16 e_shstrndx; +} PACKED; + +struct elf_section_t { + Uint32 sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size; + Uint32 sh_link, sh_info, sh_addralign, sh_entsize; +} PACKED; + +void Archive::create() throw (GeneralException) { + char buffer[1024]; + int len; + Uint32 sig, ptr, maxptr = 0, startptr; + Uint16 sections; + PEsection_t PEsection; + size_t size; + FileTree * p = &filetree, * t; + String ifname; + int i; + + switch(type) { + case ARCHIVE_EXECUTABLE: + startptr = archive->tell(); + sig = archive->readU32(); + archive->seek(-4, SEEK_CUR); + if ((sig & 0xffff) == 0x5a4d) { /* MZ */ + archive->seek(60, SEEK_CUR); + sig = archive->readU32(); + archive->seek(sig - 64, SEEK_CUR); + sig = archive->readU32(); + if (sig != 0x4550) + throw GeneralException(_("Archive: file is not a PE.")); + archive->seek(2, SEEK_CUR); + sections = archive->readU16(); + archive->seek(240, SEEK_CUR); + for (i = 0; i < sections; i++) { + archive->read(&PEsection, sizeof(PEsection)); + printm(M_INFO, "Section: %s\n", PEsection.name); + ptr = PEsection.Pointer + PEsection.SizeOf; + if (ptr > maxptr) + maxptr = ptr; + } + archive->seek(startptr - archive->tell() + maxptr, SEEK_CUR); + } else if (sig == 0x464c457f) { /* ELF */ + elf_header_t head; + elf_section_t sec; + int cur_end, max_end = 0; + int i; + + archive->read(&head, sizeof(head)); + archive->seek(startptr + head.e_shoff); + + for (i = 0; i < head.e_shnum; i++) { + archive->read(&sec, sizeof(elf_section_t)); + archive->seek(head.e_shentsize - sizeof(elf_section_t), SEEK_CUR); + if (sec.sh_type == 8) + continue; + cur_end = sec.sh_offset + sec.sh_size; + if (cur_end > max_end) + max_end = cur_end; + } + archive->seek(startptr + max_end); + } + case ARCHIVE_BUILTIN: + memset(buffer, 0, 4); + archive->read(buffer, 4); + if (*((Uint32 *)buffer) != BUILTIN_SIG) + throw GeneralException(_("Archive: not in built-in format.")); + while (p) { + archive->read(buffer, 1); + len = *buffer; + if (len) { + archive->read(buffer, len); + buffer[len] = 0; + ifname = buffer; + size = archive->readU32(); + archive->read(buffer, 1); +#ifdef DEBUG + printm(M_BARE, _("Adding file `") + ifname + _("' to node `") + p->name + "'\n"); +#endif + t = new FileTree(ifname, size, buffer[0], p); + if (buffer[0]) + p = t; + } else { + p = p->Father(); + } + } + filetree.compute_ptrs(archive->tell()); + 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; + + delete archive; +} + +Archive * Archive::inarchive(const String & fname) { + Archive * p; + for (p = header; p; p = p->next) { +#ifdef DEBUG + printm(M_BARE, _("Looking for file `") + fname + _("' in archive ") + p->name + "\n"); +#endif + if (p->inarchivein(fname)) { +#ifdef DEBUG + printm(M_BARE, _("File `") + fname + _("' found in archive ") + p->name + "\n"); +#endif + return p; + } + } + return 0; +} + +int Archive::open(const String & fname, Input::openresults_t * results) { +#if 0 + Archive * p; + + for (p = header; p; p = p->next) { + bool t; + t = p->inarchive(fname); + if (t) + return p->openin(fname, results); + } + throw IOGeneral(_("File `") + fname + _("' not found in archive collection.")); +#endif + return openin(fname, results); +} + +Handle * Archive::GetHandle() { + return archive; +} + +bool Archive::inarchivein(const String & fname) { + Archive::FileTree * p = filetree.Child(); + ssize_t pos; + String name = fname; + String reste; + + while((name != "") && p) { + pos = name.strchr('/'); + if (pos >= 0) { + reste = name.extract(0, pos - 1); + name = name.extract(pos + 1); + } else { + reste = name; + name = ""; + } +#ifdef DEBUG + printm(M_BARE, _("Checking against node `") + p->name + "'\n"); +#endif + while (p) { + if (p->name == reste) { + if (name != "") + p = p->Child(); + break; + } else { + p = p->Next(); + } + } + } + + return p != 0; +} + +int Archive::openin(const String & fname, Input::openresults_t * results) throw (GeneralException) { + Archive::FileTree * p = filetree.Child(); + ssize_t pos; + String name = fname; + String reste; + + while((name != "") && p) { + 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) { + if (name != "") + p = p->Child(); + break; + } else { + p = p->Next(); + } + } + } + + if (!p) + throw IOGeneral(_("File `") + fname + _("' not in archive ") + this->name); + + if (p->Child()) + throw IOGeneral(_("File `") + fname + _("' in archive ") + this->name + _(" is a directory - can't open.")); + + results->name = p->name; + results->ptr = p->ptr; + results->size = p->size; + results->type = p->type; + return archive->Dup(); +} + +Archive::FileTree::FileTree(const String & fname, size_t fsize, int ftype, Archive::FileTree * fFather) : + 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; + } else { +#ifdef DEBUG + std::cerr << _("Adding `") << fname << _("' as first child of node `") << father->name << "'\n"; +#endif + father->child = this; + } + } +} + +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(size_t cptr) { + ptr = cptr; + +#ifdef DEBUG + std::cerr << _("Computed pointer for `") << name << "' = " << ptr << std::endl; + if (child) + std::cerr << _("Node has child\n"); + else + std::cerr << _("Node is ") << size << _(" bytes large.\n"); +#endif + + if (child) { + FileTree * p; + size = 0; + for (p = child; p; p = p->next) { + size = p->compute_ptrs(ptr + size) - ptr; + } + } + + return size + ptr; +} + +Archive::FileTree * Archive::FileTree::Father() { + return father; +} + +Archive::FileTree * Archive::FileTree::Child() { + return child; +} + +Archive::FileTree * Archive::FileTree::Next() { + return next; +} + +Archive::FileTree * Archive::FileTree::Prev() { + return prev; +} |