1/*
2 * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <ctype.h>
8#include <errno.h>
9#include <getopt.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <package/hpkg/HPKGDefs.h>
15#include <package/hpkg/PackageAttributeValue.h>
16#include <package/hpkg/PackageContentHandler.h>
17#include <package/hpkg/PackageEntry.h>
18#include <package/hpkg/PackageEntryAttribute.h>
19#include <package/hpkg/PackageReader.h>
20#include <package/hpkg/StandardErrorOutput.h>
21
22#include "package.h"
23
24
25using namespace BPackageKit::BHPKG;
26
27
28struct PackageContentDumpHandler : BLowLevelPackageContentHandler {
29	PackageContentDumpHandler()
30		:
31		fLevel(0),
32		fErrorOccurred(false),
33		fHasChildren(false)
34	{
35	}
36
37	virtual status_t HandleSectionStart(BHPKGPackageSectionID sectionID,
38		bool& _handleSection)
39	{
40		const char* sectionName;
41
42		switch (sectionID) {
43			case B_HPKG_SECTION_HEADER:
44				sectionName = "header";
45				break;
46			case B_HPKG_SECTION_HEAP:
47				sectionName = "heap";
48				break;
49			case B_HPKG_SECTION_PACKAGE_TOC:
50				sectionName = "TOC";
51				break;
52			case B_HPKG_SECTION_PACKAGE_ATTRIBUTES:
53				sectionName = "package attributes";
54				break;
55			case B_HPKG_SECTION_REPOSITORY_INFO:
56				sectionName = "repository info";
57				break;
58			default:
59				sectionName = "<unknown section>";
60				break;
61		}
62
63		printf("\n====  SECTION: %s ====\n", sectionName);
64
65		_handleSection = true;
66		return B_OK;
67	}
68
69	virtual status_t HandleSectionEnd(BHPKGPackageSectionID sectionID)
70	{
71		return B_OK;
72	}
73
74	virtual status_t HandleAttribute(BHPKGAttributeID attributeID,
75		const BPackageAttributeValue& value, void* parentToken, void*& _token)
76	{
77		if (fErrorOccurred)
78			return B_OK;
79
80		printf("%*s>%s: ", fLevel * 2, "", AttributeNameForID(attributeID));
81		_PrintValue(value);
82		printf("\n");
83
84		fHasChildren = false;
85		fLevel++;
86		return B_OK;
87	}
88
89	virtual status_t HandleAttributeDone(BHPKGAttributeID attributeID,
90		const BPackageAttributeValue& value, void* parentToken, void* token)
91	{
92		if (fErrorOccurred)
93			return B_OK;
94
95		fLevel--;
96
97		if (fHasChildren)
98			printf("%*s<%s\n", fLevel * 2, "", AttributeNameForID(attributeID));
99
100		fHasChildren = true;
101		return B_OK;
102	}
103
104	virtual void HandleErrorOccurred()
105	{
106		fErrorOccurred = true;
107	}
108
109private:
110	void _PrintValue(const BPackageAttributeValue& value)
111	{
112		switch (value.type) {
113			case B_HPKG_ATTRIBUTE_TYPE_INT:
114				printf("%lld (%#llx)", (long long)value.signedInt,
115					(long long)value.signedInt);
116				break;
117			case B_HPKG_ATTRIBUTE_TYPE_UINT:
118				printf("%llu (%#llx)", (unsigned long long)value.unsignedInt,
119					(unsigned long long)value.unsignedInt);
120				break;
121			case B_HPKG_ATTRIBUTE_TYPE_STRING:
122				printf("\"%s\"", value.string);
123				break;
124			case B_HPKG_ATTRIBUTE_TYPE_RAW:
125				switch (value.encoding) {
126					case B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE:
127						printf("data: size: %llu, inline",
128							(unsigned long long)value.data.size);
129						// TODO: Print the data bytes!
130						break;
131					case B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP:
132						printf("data: size: %llu, offset: %llu",
133							(unsigned long long)value.data.size,
134							(unsigned long long)value.data.offset);
135						break;
136					default:
137						break;
138				}
139				break;
140			default:
141				printf("<unknown type %u>\n", value.type);
142				break;
143		}
144	}
145
146private:
147	int		fLevel;
148	bool	fErrorOccurred;
149	bool	fHasChildren;
150};
151
152
153int
154command_dump(int argc, const char* const* argv)
155{
156	while (true) {
157		static struct option sLongOptions[] = {
158			{ "help", no_argument, 0, 'h' },
159			{ 0, 0, 0, 0 }
160		};
161
162		opterr = 0; // don't print errors
163		int c = getopt_long(argc, (char**)argv, "+h", sLongOptions, NULL);
164		if (c == -1)
165			break;
166
167		switch (c) {
168			case 'h':
169				print_usage_and_exit(false);
170				break;
171
172			default:
173				print_usage_and_exit(true);
174				break;
175		}
176	}
177
178	// One argument should remain -- the package file name.
179	if (optind + 1 != argc)
180		print_usage_and_exit(true);
181
182	const char* packageFileName = argv[optind++];
183
184	// open package
185	BStandardErrorOutput errorOutput;
186	BPackageReader packageReader(&errorOutput);
187	status_t error = packageReader.Init(packageFileName);
188	if (error != B_OK)
189		return 1;
190
191	// list
192	PackageContentDumpHandler handler;
193	error = packageReader.ParseContent(&handler);
194	if (error != B_OK)
195		return 1;
196
197	return 0;
198}
199