xref: /haiku/src/kits/package/hpkg/RepositoryReaderImpl.cpp (revision 16c83730262f1e4f0fc69d80744bb36dcfbbe3af)
1 /*
2  * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <package/hpkg/RepositoryReaderImpl.h>
8 
9 #include <errno.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 
15 #include <algorithm>
16 #include <new>
17 
18 #include <ByteOrder.h>
19 #include <Message.h>
20 
21 #include <package/hpkg/HPKGDefsPrivate.h>
22 #include <package/hpkg/RepositoryContentHandler.h>
23 
24 
25 namespace BPackageKit {
26 
27 namespace BHPKG {
28 
29 namespace BPrivate {
30 
31 
32 //#define TRACE(format...)	printf(format)
33 #define TRACE(format...)	do {} while (false)
34 
35 
36 // maximum repository info size we support reading
37 static const size_t kMaxRepositoryInfoSize		= 1 * 1024 * 1024;
38 
39 // maximum package attributes size we support reading
40 static const size_t kMaxPackageAttributesSize	= 64 * 1024 * 1024;
41 
42 
43 // #pragma mark - PackagesAttributeHandler
44 
45 
46 class RepositoryReaderImpl::PackagesAttributeHandler
47 	: public AttributeHandler {
48 private:
49 	typedef AttributeHandler super;
50 public:
51 	PackagesAttributeHandler(BRepositoryContentHandler* contentHandler)
52 		:
53 		fContentHandler(contentHandler),
54 		fPackageName(NULL)
55 	{
56 	}
57 
58 	virtual status_t HandleAttribute(AttributeHandlerContext* context, uint8 id,
59 		const AttributeValue& value, AttributeHandler** _handler)
60 	{
61 		switch (id) {
62 			case B_HPKG_ATTRIBUTE_ID_PACKAGE:
63 			{
64 				status_t error = _NotifyPackageDone();
65 				if (error != B_OK)
66 					return error;
67 
68 				if (_handler != NULL) {
69 					if (fContentHandler != NULL) {
70 						error = fContentHandler->HandlePackage(value.string);
71 						if (error != B_OK)
72 							return error;
73 					}
74 
75 					*_handler = new(std::nothrow) PackageAttributeHandler;
76 					if (*_handler == NULL)
77 						return B_NO_MEMORY;
78 
79 					fPackageName = value.string;
80 				}
81 				break;
82 			}
83 
84 			default:
85 				if (context->ignoreUnknownAttributes)
86 					break;
87 
88 				context->errorOutput->PrintError(
89 					"Error: Invalid package attribute section: unexpected "
90 					"top level attribute id %d encountered\n", id);
91 				return B_BAD_DATA;
92 		}
93 
94 		return B_OK;
95 	}
96 
97 	virtual status_t NotifyDone(AttributeHandlerContext* context)
98 	{
99 		status_t result = _NotifyPackageDone();
100 		if (result == B_OK)
101 			result = super::NotifyDone(context);
102 		return result;
103 	}
104 
105 private:
106 	status_t _NotifyPackageDone()
107 	{
108 		if (fPackageName == NULL || fContentHandler == NULL)
109 			return B_OK;
110 
111 		status_t error = fContentHandler->HandlePackageDone(fPackageName);
112 		fPackageName = NULL;
113 		return error;
114 	}
115 
116 private:
117 	BRepositoryContentHandler*	fContentHandler;
118 	const char*					fPackageName;
119 };
120 
121 
122 // #pragma mark - PackageContentHandlerAdapter
123 
124 
125 class RepositoryReaderImpl::PackageContentHandlerAdapter
126 	: public BPackageContentHandler {
127 public:
128 	PackageContentHandlerAdapter(BRepositoryContentHandler* contentHandler)
129 		:
130 		fContentHandler(contentHandler)
131 	{
132 	}
133 
134 	virtual status_t HandleEntry(BPackageEntry* entry)
135 	{
136 		return B_OK;
137 	}
138 
139 	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
140 		BPackageEntryAttribute* attribute)
141 	{
142 		return B_OK;
143 	}
144 
145 	virtual status_t HandleEntryDone(BPackageEntry* entry)
146 	{
147 		return B_OK;
148 	}
149 
150 	virtual status_t HandlePackageAttribute(
151 		const BPackageInfoAttributeValue& value)
152 	{
153 		return fContentHandler->HandlePackageAttribute(value);
154 	}
155 
156 	virtual void HandleErrorOccurred()
157 	{
158 		return fContentHandler->HandleErrorOccurred();
159 	}
160 
161 private:
162 	BRepositoryContentHandler*	fContentHandler;
163 };
164 
165 
166 // #pragma mark - RepositoryReaderImpl
167 
168 
169 RepositoryReaderImpl::RepositoryReaderImpl(BErrorOutput* errorOutput)
170 	:
171 	inherited("repository", errorOutput)
172 {
173 }
174 
175 
176 RepositoryReaderImpl::~RepositoryReaderImpl()
177 {
178 }
179 
180 
181 status_t
182 RepositoryReaderImpl::Init(const char* fileName)
183 {
184 	// open file
185 	int fd = open(fileName, O_RDONLY);
186 	if (fd < 0) {
187 		ErrorOutput()->PrintError(
188 			"Error: Failed to open repository file \"%s\": %s\n", fileName,
189 			strerror(errno));
190 		return errno;
191 	}
192 
193 	return Init(fd, true);
194 }
195 
196 
197 status_t
198 RepositoryReaderImpl::Init(int fd, bool keepFD)
199 {
200 	hpkg_repo_header header;
201 	status_t error = inherited::Init<hpkg_repo_header, B_HPKG_REPO_MAGIC,
202 		B_HPKG_REPO_VERSION, B_HPKG_REPO_MINOR_VERSION>(fd, keepFD, header, 0);
203 	if (error != B_OK)
204 		return error;
205 
206 	// init package attributes section
207 	error = InitSection(fPackageAttributesSection,
208 		UncompressedHeapSize(),
209 		B_BENDIAN_TO_HOST_INT64(header.packages_length),
210 		kMaxPackageAttributesSize,
211 		B_BENDIAN_TO_HOST_INT64(header.packages_strings_length),
212 		B_BENDIAN_TO_HOST_INT64(header.packages_strings_count));
213 	if (error != B_OK)
214 		return error;
215 
216 	// init repository info section
217 	PackageFileSection repositoryInfoSection("repository info");
218 	error = InitSection(repositoryInfoSection,
219 		fPackageAttributesSection.offset,
220 		B_BENDIAN_TO_HOST_INT32(header.info_length), kMaxRepositoryInfoSize, 0,
221 		0);
222 	if (error != B_OK)
223 		return error;
224 
225 	// prepare the sections for use
226 	error = PrepareSection(repositoryInfoSection);
227 	if (error != B_OK)
228 		return error;
229 
230 	error = PrepareSection(fPackageAttributesSection);
231 	if (error != B_OK)
232 		return error;
233 
234 	// unarchive repository info
235 	BMessage repositoryInfoArchive;
236 	error = repositoryInfoArchive.Unflatten((char*)repositoryInfoSection.data);
237 	if (error != B_OK) {
238 		ErrorOutput()->PrintError(
239 			"Error: Unable to unflatten repository info archive!\n");
240 		return error;
241 	}
242 	error = fRepositoryInfo.SetTo(&repositoryInfoArchive);
243 	if (error != B_OK) {
244 		ErrorOutput()->PrintError(
245 			"Error: Unable to unarchive repository info!\n");
246 		return error;
247 	}
248 
249 	return B_OK;
250 }
251 
252 
253 status_t
254 RepositoryReaderImpl::GetRepositoryInfo(BRepositoryInfo* _repositoryInfo) const
255 {
256 	if (_repositoryInfo == NULL)
257 		return B_BAD_VALUE;
258 
259 	*_repositoryInfo = fRepositoryInfo;
260 	return B_OK;
261 }
262 
263 
264 status_t
265 RepositoryReaderImpl::ParseContent(BRepositoryContentHandler* contentHandler)
266 {
267 	status_t result = contentHandler->HandleRepositoryInfo(fRepositoryInfo);
268 	if (result == B_OK) {
269 		PackageContentHandlerAdapter contentHandlerAdapter(contentHandler);
270 		AttributeHandlerContext context(ErrorOutput(),
271 			contentHandler != NULL ? &contentHandlerAdapter : NULL,
272 			B_HPKG_SECTION_PACKAGE_ATTRIBUTES,
273 			MinorFormatVersion() > B_HPKG_REPO_MINOR_VERSION);
274 		PackagesAttributeHandler rootAttributeHandler(contentHandler);
275 		result = ParsePackageAttributesSection(&context, &rootAttributeHandler);
276 	}
277 	return result;
278 }
279 
280 
281 }	// namespace BPrivate
282 
283 }	// namespace BHPKG
284 
285 }	// namespace BPackageKit
286