summaryrefslogtreecommitdiffstats
path: root/src/coff/base/coff_archive.cpp
blob: 72a8883ab36d096937406a89cd2807642018f2db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/***************************************************************************
 *   Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org>                  *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/
#include "coff_archive.h"

//----------------------------------------------------------------------------
Coff::Member::Member(const QByteArray &data, uint &offset, Log::Base &log)
{
  // parse header
  QString s;
  if ( !getString(data, offset, 256, log, s) ) return;
  int i = s.find('/');
  if ( i==-1 ) {
    log.log(Log::LineType::Error, i18n("Member name not terminated by '/' (\"%1\").").arg(s));
    return;
  }
  _name = s.mid(0, i);
  if ( !getString(data, offset, 12, log, s) ) return; // mtime
  if ( !getString(data, offset, 10, log, s) ) return;
  i = s.find('l');
  if ( i==-1 ) {
    log.log(Log::LineType::Error, i18n("File size not terminated by 'l' (\"%1\").").arg(s));
    return;
  }
  bool ok;
  _nbBytes = s.mid(0, i).toUInt(&ok);
  if ( !ok ) {
    log.log(Log::LineType::Error, i18n("Wrong format for file size \"%1\".").arg(s));
    return;
  }
  Q_UINT32 v;
  if ( !getULong(data, offset, 2, log, v) ) return;
  log.log(Log::DebugLevel::Extra, i18n("Magic number: %1").arg(toHexLabel(v, 4)));
//  if ( v!=0x600A ) {
//    log.log(Log::LineType::Error, i18n("Wrong magic for Microchip archive (\"%1\").").arg(toHexLabel(v, 4)));
//    return;
//  }
  offset += _nbBytes;
}

//----------------------------------------------------------------------------
Coff::Archive::Archive(const PURL::Url &url)
  : Base(url)
{}

bool Coff::Archive::parse(Log::Base &log)
{
  QByteArray data;
  uint offset = 0, symbolEnd = 0;
  Member *symbol = 0;
  if ( !initParse(CoffType::Archive, data, offset, log) ) return false;
  for (;;) {
    if ( offset==uint(data.count()) ) break; // end of archive
    uint start = offset;
    Member *member = new Member(data, offset, log);
    if ( log.hasError() ) return false;
    if ( member->name().isEmpty() ) {
      symbolEnd = offset;
      symbol = member;
    } else {
      _members[member->name()] = member;
      _offsets[start] = member;
    }
  }
  if (symbol) {
    if ( !readSymbols(data, symbolEnd - symbol->nbBytes(), log) ) return false;
    delete symbol;
  }
  return true;
}

Coff::Archive::~Archive()
{
  QMap<QString, Member *>::const_iterator it;
  for (it=_members.begin(); it!=_members.end(); ++it) delete it.data();
}

bool Coff::Archive::readSymbols(const QByteArray &data, uint offset, Log::Base &log)
{
  Q_UINT32 nb;
  if ( !getULong(data, offset, 4, log, nb) ) return false;
  QValueVector<Member *> members(nb);
  for (uint i=0; i<nb; i++) {
    Q_UINT32 start;
    if ( !getULong(data, offset, 4, log, start) ) return false;
    if ( !_offsets.contains(start) ) {
      log.log(Log::LineType::Error, i18n("Unknown file member offset: %1").arg(toHexLabel(start, 8)));
      return false;
    }
    members[i] = _offsets[start];
  }
  for (uint i=0; i<nb; i++) {
    QString name(data.data() + offset);
    offset += name.length() + 1;
    _symbols[name] = members[i];
  }
  return true;
}

Log::KeyList Coff::Archive::information() const
{
  Log::KeyList keys(i18n("Information:"));
  keys.append(i18n("No. of file members:"), QString::number(members().count()));
  keys.append(i18n("No. of symbols:"), QString::number(symbols().count()));
  return keys;
}

Log::KeyList Coff::Archive::membersInformation() const
{
  Log::KeyList keys(i18n("File Members:"));
  QMap<QString, Member *>::const_iterator it;
  for (it=members().begin(); it!=members().end(); ++it)
    keys.append(it.key(), i18n("size: %1 bytes").arg(it.data()->nbBytes()));
  return keys;
}

Log::KeyList Coff::Archive::symbolsInformation() const
{
  Log::KeyList keys(i18n("Symbols:"));
  QMap<QString, Member *>::const_iterator it;
  for (it=symbols().begin(); it!=symbols().end(); ++it)
    keys.append(it.key(), it.data()->name());
  return keys;
}