581 lines
14 KiB
C++
581 lines
14 KiB
C++
/*
|
|
* Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
|
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
#ifndef _PACKAGE__HPKG__PRIVATE__READER_IMPL_BASE_H_
|
|
#define _PACKAGE__HPKG__PRIVATE__READER_IMPL_BASE_H_
|
|
|
|
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <ByteOrder.h>
|
|
#include <SupportDefs.h>
|
|
|
|
#include <Array.h>
|
|
#include <util/SinglyLinkedList.h>
|
|
|
|
#include <package/hpkg/ErrorOutput.h>
|
|
#include <package/hpkg/PackageAttributeValue.h>
|
|
#include <package/hpkg/PackageContentHandler.h>
|
|
#include <package/hpkg/PackageInfoAttributeValue.h>
|
|
|
|
|
|
namespace BPackageKit {
|
|
|
|
namespace BHPKG {
|
|
|
|
|
|
class BAbstractBufferedDataReader;
|
|
class BErrorOutput;
|
|
|
|
|
|
namespace BPrivate {
|
|
|
|
|
|
class PackageFileHeapReader;
|
|
|
|
|
|
struct PackageFileSection {
|
|
uint32 uncompressedLength;
|
|
uint8* data;
|
|
uint64 offset;
|
|
uint64 currentOffset;
|
|
uint64 stringsLength;
|
|
uint64 stringsCount;
|
|
char** strings;
|
|
const char* name;
|
|
|
|
PackageFileSection(const char* _name)
|
|
:
|
|
data(NULL),
|
|
strings(NULL),
|
|
name(_name)
|
|
{
|
|
}
|
|
|
|
~PackageFileSection()
|
|
{
|
|
delete[] strings;
|
|
delete[] data;
|
|
}
|
|
};
|
|
|
|
|
|
class ReaderImplBase {
|
|
public:
|
|
inline const PackageFileSection& PackageAttributesSection() const
|
|
{ return fPackageAttributesSection; }
|
|
|
|
protected:
|
|
ReaderImplBase(const char* fileType,
|
|
BErrorOutput* errorOutput);
|
|
virtual ~ReaderImplBase();
|
|
|
|
int FD() const;
|
|
|
|
BErrorOutput* ErrorOutput() const;
|
|
|
|
uint16 MinorFormatVersion() const
|
|
{ return fMinorFormatVersion; }
|
|
|
|
uint64 UncompressedHeapSize() const;
|
|
|
|
PackageFileHeapReader* RawHeapReader() const
|
|
{ return fRawHeapReader; }
|
|
BAbstractBufferedDataReader* HeapReader() const
|
|
{ return fHeapReader; }
|
|
// equals RawHeapReader(), if uncached
|
|
|
|
BAbstractBufferedDataReader* DetachHeapReader(
|
|
PackageFileHeapReader** _rawHeapReader
|
|
= NULL);
|
|
// Detaches both raw and (if applicable)
|
|
// cached heap reader. The called gains
|
|
// ownership. The FD may need to be set on
|
|
// the raw heap reader, if it shall be used
|
|
// after destroying this object and Init()
|
|
// has been called with keepFD == true.
|
|
|
|
protected:
|
|
class AttributeHandlerContext;
|
|
class AttributeHandler;
|
|
class IgnoreAttributeHandler;
|
|
class PackageInfoAttributeHandlerBase;
|
|
class PackageVersionAttributeHandler;
|
|
class PackageResolvableAttributeHandler;
|
|
class PackageResolvableExpressionAttributeHandler;
|
|
class GlobalWritableFileInfoAttributeHandler;
|
|
class UserSettingsFileInfoAttributeHandler;
|
|
class UserAttributeHandler;
|
|
class PackageAttributeHandler;
|
|
class LowLevelAttributeHandler;
|
|
|
|
typedef BPackageAttributeValue AttributeValue;
|
|
typedef SinglyLinkedList<AttributeHandler> AttributeHandlerList;
|
|
|
|
protected:
|
|
template<typename Header, uint32 kMagic, uint16 kVersion,
|
|
uint16 kMinorVersion>
|
|
status_t Init(int fd, bool keepFD, Header& header,
|
|
uint32 flags);
|
|
status_t InitHeapReader(uint32 compression,
|
|
uint32 chunkSize, off_t offset,
|
|
uint64 compressedSize,
|
|
uint64 uncompressedSize);
|
|
virtual status_t CreateCachedHeapReader(
|
|
PackageFileHeapReader* heapReader,
|
|
BAbstractBufferedDataReader*&
|
|
_cachedReader);
|
|
status_t InitSection(PackageFileSection& section,
|
|
uint64 endOffset, uint64 length,
|
|
uint64 maxSaneLength, uint64 stringsLength,
|
|
uint64 stringsCount);
|
|
status_t PrepareSection(PackageFileSection& section);
|
|
|
|
status_t ParseStrings();
|
|
|
|
status_t ParsePackageAttributesSection(
|
|
AttributeHandlerContext* context,
|
|
AttributeHandler* rootAttributeHandler);
|
|
status_t ParseAttributeTree(
|
|
AttributeHandlerContext* context,
|
|
bool& _sectionHandled);
|
|
|
|
virtual status_t ReadAttributeValue(uint8 type, uint8 encoding,
|
|
AttributeValue& _value);
|
|
|
|
status_t ReadUnsignedLEB128(uint64& _value);
|
|
|
|
status_t ReadBuffer(off_t offset, void* buffer,
|
|
size_t size);
|
|
status_t ReadSection(const PackageFileSection& section);
|
|
|
|
inline AttributeHandler* CurrentAttributeHandler() const;
|
|
inline void PushAttributeHandler(
|
|
AttributeHandler* handler);
|
|
inline AttributeHandler* PopAttributeHandler();
|
|
inline void ClearAttributeHandlerStack();
|
|
|
|
inline PackageFileSection* CurrentSection();
|
|
inline void SetCurrentSection(PackageFileSection* section);
|
|
|
|
protected:
|
|
PackageFileSection fPackageAttributesSection;
|
|
|
|
private:
|
|
status_t _Init(int fd, bool keepFD);
|
|
|
|
status_t _ParseAttributeTree(
|
|
AttributeHandlerContext* context);
|
|
|
|
template<typename Type>
|
|
inline status_t _Read(Type& _value);
|
|
|
|
status_t _ReadSectionBuffer(void* buffer, size_t size);
|
|
|
|
status_t _ReadAttribute(uint8& _id,
|
|
AttributeValue& _value,
|
|
bool* _hasChildren = NULL,
|
|
uint64* _tag = NULL);
|
|
|
|
status_t _ReadString(const char*& _string,
|
|
size_t* _stringLength = NULL);
|
|
|
|
private:
|
|
const char* fFileType;
|
|
BErrorOutput* fErrorOutput;
|
|
int fFD;
|
|
bool fOwnsFD;
|
|
uint16 fMinorFormatVersion;
|
|
uint16 fCurrentMinorFormatVersion;
|
|
|
|
PackageFileHeapReader* fRawHeapReader;
|
|
BAbstractBufferedDataReader* fHeapReader;
|
|
|
|
PackageFileSection* fCurrentSection;
|
|
|
|
AttributeHandlerList fAttributeHandlerStack;
|
|
};
|
|
|
|
|
|
// #pragma mark - attribute handlers
|
|
|
|
|
|
class ReaderImplBase::AttributeHandlerContext {
|
|
public:
|
|
BErrorOutput* errorOutput;
|
|
union {
|
|
BPackageContentHandler* packageContentHandler;
|
|
BLowLevelPackageContentHandler* lowLevelHandler;
|
|
};
|
|
bool hasLowLevelHandler;
|
|
bool ignoreUnknownAttributes;
|
|
|
|
BHPKGPackageSectionID section;
|
|
|
|
public:
|
|
AttributeHandlerContext(
|
|
BErrorOutput* errorOutput,
|
|
BPackageContentHandler*
|
|
packageContentHandler,
|
|
BHPKGPackageSectionID section,
|
|
bool ignoreUnknownAttributes);
|
|
AttributeHandlerContext(
|
|
BErrorOutput* errorOutput,
|
|
BLowLevelPackageContentHandler*
|
|
lowLevelHandler,
|
|
BHPKGPackageSectionID section,
|
|
bool ignoreUnknownAttributes);
|
|
|
|
void ErrorOccurred();
|
|
};
|
|
|
|
|
|
class ReaderImplBase::AttributeHandler
|
|
: public SinglyLinkedListLinkImpl<AttributeHandler> {
|
|
public:
|
|
virtual ~AttributeHandler();
|
|
|
|
void SetLevel(int level);
|
|
virtual status_t HandleAttribute(
|
|
AttributeHandlerContext* context, uint8 id,
|
|
const AttributeValue& value,
|
|
AttributeHandler** _handler);
|
|
|
|
virtual status_t NotifyDone(AttributeHandlerContext* context);
|
|
|
|
virtual status_t Delete(AttributeHandlerContext* context);
|
|
|
|
protected:
|
|
int fLevel;
|
|
};
|
|
|
|
|
|
class ReaderImplBase::IgnoreAttributeHandler : public AttributeHandler {
|
|
};
|
|
|
|
|
|
class ReaderImplBase::PackageInfoAttributeHandlerBase
|
|
: public AttributeHandler {
|
|
private:
|
|
typedef AttributeHandler super;
|
|
public:
|
|
PackageInfoAttributeHandlerBase(
|
|
BPackageInfoAttributeValue&
|
|
packageInfoValue);
|
|
|
|
virtual status_t NotifyDone(AttributeHandlerContext* context);
|
|
|
|
protected:
|
|
BPackageInfoAttributeValue& fPackageInfoValue;
|
|
};
|
|
|
|
|
|
class ReaderImplBase::PackageVersionAttributeHandler
|
|
: public PackageInfoAttributeHandlerBase {
|
|
private:
|
|
typedef PackageInfoAttributeHandlerBase super;
|
|
public:
|
|
PackageVersionAttributeHandler(
|
|
BPackageInfoAttributeValue&
|
|
packageInfoValue,
|
|
BPackageVersionData& versionData,
|
|
bool notify);
|
|
|
|
virtual status_t HandleAttribute(
|
|
AttributeHandlerContext* context, uint8 id,
|
|
const AttributeValue& value,
|
|
AttributeHandler** _handler);
|
|
|
|
virtual status_t NotifyDone(AttributeHandlerContext* context);
|
|
|
|
private:
|
|
BPackageVersionData& fPackageVersionData;
|
|
bool fNotify;
|
|
};
|
|
|
|
|
|
class ReaderImplBase::PackageResolvableAttributeHandler
|
|
: public PackageInfoAttributeHandlerBase {
|
|
private:
|
|
typedef PackageInfoAttributeHandlerBase super;
|
|
public:
|
|
PackageResolvableAttributeHandler(
|
|
BPackageInfoAttributeValue&
|
|
packageInfoValue);
|
|
|
|
virtual status_t HandleAttribute(
|
|
AttributeHandlerContext* context, uint8 id,
|
|
const AttributeValue& value,
|
|
AttributeHandler** _handler);
|
|
};
|
|
|
|
|
|
class ReaderImplBase::PackageResolvableExpressionAttributeHandler
|
|
: public PackageInfoAttributeHandlerBase {
|
|
private:
|
|
typedef PackageInfoAttributeHandlerBase super;
|
|
public:
|
|
PackageResolvableExpressionAttributeHandler(
|
|
BPackageInfoAttributeValue&
|
|
packageInfoValue);
|
|
|
|
virtual status_t HandleAttribute(
|
|
AttributeHandlerContext* context, uint8 id,
|
|
const AttributeValue& value,
|
|
AttributeHandler** _handler);
|
|
};
|
|
|
|
|
|
class ReaderImplBase::GlobalWritableFileInfoAttributeHandler
|
|
: public PackageInfoAttributeHandlerBase {
|
|
private:
|
|
typedef PackageInfoAttributeHandlerBase super;
|
|
public:
|
|
GlobalWritableFileInfoAttributeHandler(
|
|
BPackageInfoAttributeValue&
|
|
packageInfoValue);
|
|
|
|
virtual status_t HandleAttribute(
|
|
AttributeHandlerContext* context, uint8 id,
|
|
const AttributeValue& value,
|
|
AttributeHandler** _handler);
|
|
};
|
|
|
|
|
|
class ReaderImplBase::UserSettingsFileInfoAttributeHandler
|
|
: public PackageInfoAttributeHandlerBase {
|
|
private:
|
|
typedef PackageInfoAttributeHandlerBase super;
|
|
public:
|
|
UserSettingsFileInfoAttributeHandler(
|
|
BPackageInfoAttributeValue&
|
|
packageInfoValue);
|
|
|
|
virtual status_t HandleAttribute(
|
|
AttributeHandlerContext* context, uint8 id,
|
|
const AttributeValue& value,
|
|
AttributeHandler** _handler);
|
|
};
|
|
|
|
|
|
class ReaderImplBase::UserAttributeHandler
|
|
: public PackageInfoAttributeHandlerBase {
|
|
private:
|
|
typedef PackageInfoAttributeHandlerBase super;
|
|
public:
|
|
UserAttributeHandler(
|
|
BPackageInfoAttributeValue&
|
|
packageInfoValue);
|
|
|
|
virtual status_t HandleAttribute(
|
|
AttributeHandlerContext* context, uint8 id,
|
|
const AttributeValue& value,
|
|
AttributeHandler** _handler);
|
|
|
|
virtual status_t NotifyDone(AttributeHandlerContext* context);
|
|
|
|
private:
|
|
Array<const char*> fGroups;
|
|
};
|
|
|
|
|
|
class ReaderImplBase::PackageAttributeHandler : public AttributeHandler {
|
|
private:
|
|
typedef AttributeHandler super;
|
|
public:
|
|
virtual status_t HandleAttribute(
|
|
AttributeHandlerContext* context, uint8 id,
|
|
const AttributeValue& value,
|
|
AttributeHandler** _handler);
|
|
|
|
private:
|
|
BPackageInfoAttributeValue fPackageInfoValue;
|
|
};
|
|
|
|
|
|
class ReaderImplBase::LowLevelAttributeHandler : public AttributeHandler {
|
|
private:
|
|
typedef AttributeHandler super;
|
|
public:
|
|
LowLevelAttributeHandler();
|
|
LowLevelAttributeHandler(uint8 id,
|
|
const BPackageAttributeValue& value,
|
|
void* parentToken, void* token);
|
|
|
|
virtual status_t HandleAttribute(
|
|
AttributeHandlerContext* context, uint8 id,
|
|
const AttributeValue& value,
|
|
AttributeHandler** _handler);
|
|
|
|
virtual status_t NotifyDone(AttributeHandlerContext* context);
|
|
|
|
private:
|
|
void* fParentToken;
|
|
void* fToken;
|
|
uint8 fID;
|
|
AttributeValue fValue;
|
|
};
|
|
|
|
|
|
// #pragma mark - template and inline methods
|
|
|
|
|
|
template<typename Header, uint32 kMagic, uint16 kVersion, uint16 kMinorVersion>
|
|
status_t
|
|
ReaderImplBase::Init(int fd, bool keepFD, Header& header, uint32 flags)
|
|
{
|
|
status_t error = _Init(fd, keepFD);
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
// stat the file
|
|
struct stat st;
|
|
if (fstat(FD(), &st) < 0) {
|
|
ErrorOutput()->PrintError("Error: Failed to access %s file: %s\n",
|
|
fFileType, strerror(errno));
|
|
return errno;
|
|
}
|
|
|
|
// read the header
|
|
if ((error = ReadBuffer(0, &header, sizeof(header))) != B_OK)
|
|
return error;
|
|
|
|
// check the header
|
|
|
|
// magic
|
|
if (B_BENDIAN_TO_HOST_INT32(header.magic) != kMagic) {
|
|
ErrorOutput()->PrintError("Error: Invalid %s file: Invalid "
|
|
"magic\n", fFileType);
|
|
return B_BAD_DATA;
|
|
}
|
|
|
|
// version
|
|
if (B_BENDIAN_TO_HOST_INT16(header.version) != kVersion) {
|
|
if ((flags & B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE) == 0) {
|
|
ErrorOutput()->PrintError("Error: Invalid/unsupported %s file "
|
|
"version (%d)\n", fFileType,
|
|
B_BENDIAN_TO_HOST_INT16(header.version));
|
|
}
|
|
return B_MISMATCHED_VALUES;
|
|
}
|
|
|
|
fMinorFormatVersion = B_BENDIAN_TO_HOST_INT16(header.minor_version);
|
|
fCurrentMinorFormatVersion = kMinorVersion;
|
|
|
|
// header size
|
|
uint64 heapOffset = B_BENDIAN_TO_HOST_INT16(header.header_size);
|
|
if (heapOffset < (off_t)sizeof(header)) {
|
|
ErrorOutput()->PrintError("Error: Invalid %s file: Invalid header "
|
|
"size (%" B_PRIu64 ")\n", fFileType, heapOffset);
|
|
return B_BAD_DATA;
|
|
}
|
|
|
|
// total size
|
|
uint64 totalSize = B_BENDIAN_TO_HOST_INT64(header.total_size);
|
|
if (totalSize != (uint64)st.st_size) {
|
|
ErrorOutput()->PrintError("Error: Invalid %s file: Total size in "
|
|
"header (%" B_PRIu64 ") doesn't agree with total file size (%"
|
|
B_PRIdOFF ")\n", fFileType, totalSize, st.st_size);
|
|
return B_BAD_DATA;
|
|
}
|
|
|
|
// heap size
|
|
uint64 compressedHeapSize
|
|
= B_BENDIAN_TO_HOST_INT64(header.heap_size_compressed);
|
|
if (compressedHeapSize > totalSize
|
|
|| heapOffset > totalSize - compressedHeapSize) {
|
|
ErrorOutput()->PrintError("Error: Invalid %s file: Heap size in "
|
|
"header (%" B_PRIu64 ") doesn't agree with total file size (%"
|
|
B_PRIu64 ") and heap offset (%" B_PRIu64 ")\n", fFileType,
|
|
compressedHeapSize, totalSize, heapOffset);
|
|
return B_BAD_DATA;
|
|
}
|
|
|
|
error = InitHeapReader(
|
|
B_BENDIAN_TO_HOST_INT16(header.heap_compression),
|
|
B_BENDIAN_TO_HOST_INT32(header.heap_chunk_size), heapOffset,
|
|
compressedHeapSize,
|
|
B_BENDIAN_TO_HOST_INT64(header.heap_size_uncompressed));
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
inline int
|
|
ReaderImplBase::FD() const
|
|
{
|
|
return fFD;
|
|
}
|
|
|
|
|
|
inline BErrorOutput*
|
|
ReaderImplBase::ErrorOutput() const
|
|
{
|
|
return fErrorOutput;
|
|
}
|
|
|
|
|
|
PackageFileSection*
|
|
ReaderImplBase::CurrentSection()
|
|
{
|
|
return fCurrentSection;
|
|
}
|
|
|
|
|
|
void
|
|
ReaderImplBase::SetCurrentSection(PackageFileSection* section)
|
|
{
|
|
fCurrentSection = section;
|
|
}
|
|
|
|
|
|
template<typename Type>
|
|
status_t
|
|
ReaderImplBase::_Read(Type& _value)
|
|
{
|
|
return _ReadSectionBuffer(&_value, sizeof(Type));
|
|
}
|
|
|
|
|
|
inline ReaderImplBase::AttributeHandler*
|
|
ReaderImplBase::CurrentAttributeHandler() const
|
|
{
|
|
return fAttributeHandlerStack.Head();
|
|
}
|
|
|
|
|
|
inline void
|
|
ReaderImplBase::PushAttributeHandler(AttributeHandler* handler)
|
|
{
|
|
fAttributeHandlerStack.Add(handler);
|
|
}
|
|
|
|
|
|
inline ReaderImplBase::AttributeHandler*
|
|
ReaderImplBase::PopAttributeHandler()
|
|
{
|
|
return fAttributeHandlerStack.RemoveHead();
|
|
}
|
|
|
|
|
|
inline void
|
|
ReaderImplBase::ClearAttributeHandlerStack()
|
|
{
|
|
fAttributeHandlerStack.MakeEmpty();
|
|
}
|
|
|
|
|
|
} // namespace BPrivate
|
|
|
|
} // namespace BHPKG
|
|
|
|
} // namespace BPackageKit
|
|
|
|
|
|
#endif // _PACKAGE__HPKG__PRIVATE__READER_IMPL_BASE_H_
|