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