1/*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "AbbreviationTable.h"
7
8#include <stdio.h>
9
10#include <new>
11
12
13AbbreviationTable::AbbreviationTable(off_t offset)
14	:
15	fOffset(offset),
16	fData(NULL),
17	fSize(0)
18{
19}
20
21
22AbbreviationTable::~AbbreviationTable()
23{
24	AbbreviationTableEntry* entry = fEntryTable.Clear(true);
25	while (entry != NULL) {
26		AbbreviationTableEntry* next = entry->next;
27		delete entry;
28		entry = next;
29	}
30}
31
32
33status_t
34AbbreviationTable::Init(const void* section, off_t sectionSize)
35{
36	if (fOffset < 0 || fOffset >= sectionSize)
37		return B_BAD_DATA;
38
39	fData = (uint8*)section + fOffset;
40	fSize = sectionSize - fOffset;
41		// That's only the maximum size. Will be adjusted at the end.
42
43	status_t error = fEntryTable.Init();
44	if (error != B_OK)
45		return error;
46
47	DataReader abbrevReader(fData, fSize, 4, false);
48		// address size and endianness don't matter here
49
50	while (true) {
51		bool nullEntry;
52		status_t error = _ParseAbbreviationEntry(abbrevReader, nullEntry);
53		if (error != B_OK)
54			return error;
55
56		if (nullEntry)
57			break;
58	}
59
60	fSize -= abbrevReader.BytesRemaining();
61
62	return B_OK;
63}
64
65
66bool
67AbbreviationTable::GetAbbreviationEntry(uint32 code, AbbreviationEntry& entry)
68{
69	AbbreviationTableEntry* tableEntry = fEntryTable.Lookup(code);
70	if (tableEntry == NULL)
71		return false;
72
73	entry.SetTo(code, fData + tableEntry->offset, tableEntry->size);
74	return true;
75}
76
77
78status_t
79AbbreviationTable::_ParseAbbreviationEntry(DataReader& abbrevReader,
80	bool& _nullEntry)
81{
82	uint32 code = abbrevReader.ReadUnsignedLEB128(0);
83	if (code == 0) {
84		if (abbrevReader.HasOverflow()) {
85			fprintf(stderr, "Invalid abbreviation table 1!\n");
86			return B_BAD_DATA;
87		}
88		_nullEntry = true;
89		return B_OK;
90	}
91
92	off_t remaining = abbrevReader.BytesRemaining();
93
94/*	uint32 tag =*/ abbrevReader.ReadUnsignedLEB128(0);
95/*	uint8 hasChildren =*/ abbrevReader.Read<uint8>(DW_CHILDREN_no);
96
97//	printf("entry: %" B_PRIu32 ", tag: %" B_PRIu32 ", children: %d\n", code, tag,
98//		hasChildren);
99
100	// parse attribute specifications
101	while (true) {
102		uint32 attributeName = abbrevReader.ReadUnsignedLEB128(0);
103		uint32 attributeForm = abbrevReader.ReadUnsignedLEB128(0);
104		if (abbrevReader.HasOverflow()) {
105			fprintf(stderr, "Invalid abbreviation table 2!\n");
106			return B_BAD_DATA;
107		}
108
109		if (attributeName == 0 && attributeForm == 0)
110			break;
111
112		if (attributeForm == DW_FORM_implicit_const)
113			abbrevReader.ReadSignedLEB128(0);
114
115//		printf("  attr: name: %" B_PRIu32 ", form: %" B_PRIu32 "\n", attributeName,
116//			attributeForm);
117	}
118
119	// create the entry
120	if (fEntryTable.Lookup(code) == NULL) {
121		AbbreviationTableEntry* entry = new(std::nothrow)
122			AbbreviationTableEntry(code, fSize - remaining,
123				remaining - abbrevReader.BytesRemaining());
124		if (entry == NULL)
125			return B_NO_MEMORY;
126
127		fEntryTable.Insert(entry);
128	} else {
129		fprintf(stderr, "Duplicate abbreviation table entry %" B_PRIu32 "!\n",
130			code);
131	}
132
133	_nullEntry = false;
134	return B_OK;
135}
136