summaryrefslogtreecommitdiff
path: root/lib/Input.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Input.cc')
-rw-r--r--lib/Input.cc1160
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;
+}