summaryrefslogtreecommitdiffhomepage
path: root/windows/nsis-plugins/src/tray/trayparser.cpp
blob: 6efff0b2f05675a187346e57179afab7fbc4db0c (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
#include "stdafx.h"
#include "trayparser.h"
#include <libcommon/error.h>
#include <iterator>
#include <algorithm>

TrayParser::TrayParser(const std::vector<uint8_t> &blob)
{
	if (blob.size() < sizeof(ICON_STREAMS_HEADER))
	{
		THROW_ERROR("Invalid icon streams header - truncated");
	}

	auto header = reinterpret_cast<const ICON_STREAMS_HEADER *>(&blob[0]);

	if (header->HeaderSize != sizeof(ICON_STREAMS_HEADER))
	{
		THROW_ERROR("Invalid icon streams header - size mismatch");
	}

	memcpy(&m_header, header, sizeof(ICON_STREAMS_HEADER));

	if (0 == header->NumberRecords)
	{
		return;
	}

	//
	// At least one record.
	//

	if (blob.size() < sizeof(ICON_STREAMS_HEADER) + sizeof(ICON_STREAMS_RECORD))
	{
		THROW_ERROR("Invalid icon streams - truncated");
	}

	const auto lastValidRecordOffset = blob.size() - sizeof(ICON_STREAMS_RECORD);

	if (header->OffsetFirstRecord < header->HeaderSize
		|| header->OffsetFirstRecord > lastValidRecordOffset)
	{
		THROW_ERROR("Invalid icon streams header - record offset");
	}

	const auto estimatedSize = header->HeaderSize
		+ (header->OffsetFirstRecord - header->HeaderSize)
		+ (header->NumberRecords * sizeof(ICON_STREAMS_RECORD));

	if (blob.size() != estimatedSize)
	{
		THROW_ERROR("Invalid icon streams - size mismatch");
	}

	//
	// Size checks out.
	//

	m_records.reserve(header->NumberRecords);

	auto begin = reinterpret_cast<const ICON_STREAMS_RECORD *>(&blob[0] + header->OffsetFirstRecord);
	auto end = reinterpret_cast<const ICON_STREAMS_RECORD *>(&blob[0] + blob.size());

	std::copy(begin, end, std::back_inserter(m_records));
}

const ICON_STREAMS_HEADER &TrayParser::getHeader() const
{
	return m_header;
}

const std::vector<ICON_STREAMS_RECORD> &TrayParser::getRecords() const
{
	return m_records;
}