1/*
2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "UnpackingAttributeCookie.h"
8
9#include <algorithm>
10#include <new>
11
12#include <package/hpkg/DataReader.h>
13#include <package/hpkg/PackageData.h>
14#include <package/hpkg/PackageDataReader.h>
15
16#include <AutoDeleter.h>
17
18#include "AttributeIndexer.h"
19#include "AutoPackageAttributes.h"
20#include "DebugSupport.h"
21#include "GlobalFactory.h"
22#include "Package.h"
23#include "PackageNode.h"
24
25
26using BPackageKit::BHPKG::BBufferDataReader;
27using BPackageKit::BHPKG::BFDDataReader;
28
29
30static status_t
31read_package_data(const BPackageData& data, BDataReader* dataReader,
32	off_t offset, void* buffer, size_t* bufferSize)
33{
34	// create a BPackageDataReader
35	BPackageDataReader* reader;
36	status_t error = GlobalFactory::Default()->CreatePackageDataReader(
37		dataReader, data, reader);
38	if (error != B_OK)
39		RETURN_ERROR(error);
40	ObjectDeleter<BPackageDataReader> readerDeleter(reader);
41
42	// check the offset
43	if (offset < 0 || (uint64)offset > data.UncompressedSize())
44		return B_BAD_VALUE;
45
46	// clamp the size
47	size_t toRead = std::min((uint64)*bufferSize,
48		data.UncompressedSize() - offset);
49
50	// read
51	if (toRead > 0) {
52		status_t error = reader->ReadData(offset, buffer, toRead);
53		if (error != B_OK)
54			RETURN_ERROR(error);
55	}
56
57	*bufferSize = toRead;
58	return B_OK;
59}
60
61
62UnpackingAttributeCookie::UnpackingAttributeCookie(PackageNode* packageNode,
63	PackageNodeAttribute* attribute, int openMode)
64	:
65	fPackageNode(packageNode),
66	fPackage(packageNode->GetPackage()),
67	fAttribute(attribute),
68	fOpenMode(openMode)
69{
70	fPackageNode->AcquireReference();
71	fPackage->AcquireReference();
72}
73
74
75UnpackingAttributeCookie::~UnpackingAttributeCookie()
76{
77	fPackageNode->ReleaseReference();
78	fPackage->ReleaseReference();
79}
80
81
82/*static*/ status_t
83UnpackingAttributeCookie::Open(PackageNode* packageNode, const char* name,
84	int openMode, AttributeCookie*& _cookie)
85{
86	if (packageNode == NULL)
87		return B_ENTRY_NOT_FOUND;
88
89	// get the attribute
90	PackageNodeAttribute* attribute = packageNode->FindAttribute(name);
91	if (attribute == NULL) {
92		// We don't know the attribute -- maybe it's an auto-generated one.
93		return AutoPackageAttributes::OpenCookie(packageNode->GetPackage(),
94			name, openMode, _cookie);
95	}
96
97	// allocate the cookie
98	UnpackingAttributeCookie* cookie = new(std::nothrow)
99		UnpackingAttributeCookie(packageNode, attribute, openMode);
100	if (cookie == NULL)
101		RETURN_ERROR(B_NO_MEMORY);
102
103	_cookie = cookie;
104	return B_OK;
105}
106
107
108status_t
109UnpackingAttributeCookie::ReadAttribute(off_t offset, void* buffer,
110	size_t* bufferSize)
111{
112	return ReadAttribute(fPackageNode, fAttribute, offset, buffer, bufferSize);
113}
114
115
116status_t
117UnpackingAttributeCookie::ReadAttributeStat(struct stat* st)
118{
119	st->st_size = fAttribute->Data().UncompressedSize();
120	st->st_type = fAttribute->Type();
121
122	return B_OK;
123}
124
125
126/*static*/ status_t
127UnpackingAttributeCookie::ReadAttribute(PackageNode* packageNode,
128	PackageNodeAttribute* attribute, off_t offset, void* buffer,
129	size_t* bufferSize)
130{
131	const BPackageData& data = attribute->Data();
132	if (data.IsEncodedInline()) {
133		// inline data
134		BBufferDataReader dataReader(data.InlineData(), data.CompressedSize());
135		return read_package_data(data, &dataReader, offset, buffer, bufferSize);
136	}
137
138	// data not inline -- open the package
139	Package* package = packageNode->GetPackage();
140	int fd = package->Open();
141	if (fd < 0)
142		RETURN_ERROR(fd);
143	PackageCloser packageCloser(package);
144
145	BFDDataReader dataReader(fd);
146	return read_package_data(data, &dataReader, offset, buffer, bufferSize);
147}
148
149
150/*static*/ status_t
151UnpackingAttributeCookie::IndexAttribute(PackageNode* packageNode,
152	AttributeIndexer* indexer)
153{
154	if (packageNode == NULL)
155		return B_ENTRY_NOT_FOUND;
156
157	// get the attribute
158	PackageNodeAttribute* attribute = packageNode->FindAttribute(
159		indexer->IndexName());
160	if (attribute == NULL)
161		return B_ENTRY_NOT_FOUND;
162
163	// create the index cookie
164	void* data;
165	size_t toRead;
166	status_t error = indexer->CreateCookie(packageNode, attribute,
167		attribute->Type(), attribute->Data().UncompressedSize(), data, toRead);
168	if (error != B_OK)
169		return error;
170
171	// read the attribute
172	if (toRead > 0) {
173		error = ReadAttribute(packageNode, attribute, 0, data, &toRead);
174		if (error != B_OK) {
175			indexer->DeleteCookie();
176			return error;
177		}
178	}
179
180	attribute->SetIndexCookie(indexer->Cookie());
181
182	return B_OK;
183}
184