Move frameworks/base/tools/ to frameworks/tools/
Change-Id: I3ffafdab27cc4aca256c3a5806b630795b75d5c8
@@ -1,633 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// Information about assets being operated on.
|
||||
//
|
||||
#ifndef __AAPT_ASSETS_H
|
||||
#define __AAPT_ASSETS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <androidfw/AssetManager.h>
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/SortedVector.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Vector.h>
|
||||
#include "ZipFile.h"
|
||||
|
||||
#include "Bundle.h"
|
||||
#include "SourcePos.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
|
||||
extern const char * const gDefaultIgnoreAssets;
|
||||
extern const char * gUserIgnoreAssets;
|
||||
|
||||
bool valid_symbol_name(const String8& str);
|
||||
|
||||
class AaptAssets;
|
||||
|
||||
enum {
|
||||
AXIS_NONE = 0,
|
||||
AXIS_MCC = 1,
|
||||
AXIS_MNC,
|
||||
AXIS_LANGUAGE,
|
||||
AXIS_REGION,
|
||||
AXIS_SCREENLAYOUTSIZE,
|
||||
AXIS_SCREENLAYOUTLONG,
|
||||
AXIS_ORIENTATION,
|
||||
AXIS_UIMODETYPE,
|
||||
AXIS_UIMODENIGHT,
|
||||
AXIS_DENSITY,
|
||||
AXIS_TOUCHSCREEN,
|
||||
AXIS_KEYSHIDDEN,
|
||||
AXIS_KEYBOARD,
|
||||
AXIS_NAVHIDDEN,
|
||||
AXIS_NAVIGATION,
|
||||
AXIS_SCREENSIZE,
|
||||
AXIS_SMALLESTSCREENWIDTHDP,
|
||||
AXIS_SCREENWIDTHDP,
|
||||
AXIS_SCREENHEIGHTDP,
|
||||
AXIS_LAYOUTDIR,
|
||||
AXIS_VERSION,
|
||||
|
||||
AXIS_START = AXIS_MCC,
|
||||
AXIS_END = AXIS_VERSION,
|
||||
};
|
||||
|
||||
/**
|
||||
* This structure contains a specific variation of a single file out
|
||||
* of all the variations it can have that we can have.
|
||||
*/
|
||||
struct AaptGroupEntry
|
||||
{
|
||||
public:
|
||||
AaptGroupEntry() : mParamsChanged(true) { }
|
||||
AaptGroupEntry(const String8& _locale, const String8& _vendor)
|
||||
: locale(_locale), vendor(_vendor), mParamsChanged(true) { }
|
||||
|
||||
bool initFromDirName(const char* dir, String8* resType);
|
||||
|
||||
static status_t parseNamePart(const String8& part, int* axis, uint32_t* value);
|
||||
|
||||
static uint32_t getConfigValueForAxis(const ResTable_config& config, int axis);
|
||||
|
||||
static bool configSameExcept(const ResTable_config& config,
|
||||
const ResTable_config& otherConfig, int axis);
|
||||
|
||||
static bool getMccName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getMncName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getLocaleName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getScreenLayoutSizeName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getScreenLayoutLongName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getOrientationName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getUiModeTypeName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getUiModeNightName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getDensityName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getTouchscreenName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getKeysHiddenName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getKeyboardName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getNavigationName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getNavHiddenName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getScreenSizeName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getSmallestScreenWidthDpName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getScreenWidthDpName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getScreenHeightDpName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getLayoutDirectionName(const char* name, ResTable_config* out = NULL);
|
||||
static bool getVersionName(const char* name, ResTable_config* out = NULL);
|
||||
|
||||
int compare(const AaptGroupEntry& o) const;
|
||||
|
||||
const ResTable_config& toParams() const;
|
||||
|
||||
inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
|
||||
inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
|
||||
inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; }
|
||||
inline bool operator!=(const AaptGroupEntry& o) const { return compare(o) != 0; }
|
||||
inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; }
|
||||
inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; }
|
||||
|
||||
String8 toString() const;
|
||||
String8 toDirName(const String8& resType) const;
|
||||
|
||||
const String8& getVersionString() const { return version; }
|
||||
|
||||
private:
|
||||
String8 mcc;
|
||||
String8 mnc;
|
||||
String8 locale;
|
||||
String8 vendor;
|
||||
String8 smallestScreenWidthDp;
|
||||
String8 screenWidthDp;
|
||||
String8 screenHeightDp;
|
||||
String8 screenLayoutSize;
|
||||
String8 screenLayoutLong;
|
||||
String8 orientation;
|
||||
String8 uiModeType;
|
||||
String8 uiModeNight;
|
||||
String8 density;
|
||||
String8 touchscreen;
|
||||
String8 keysHidden;
|
||||
String8 keyboard;
|
||||
String8 navHidden;
|
||||
String8 navigation;
|
||||
String8 screenSize;
|
||||
String8 layoutDirection;
|
||||
String8 version;
|
||||
|
||||
mutable bool mParamsChanged;
|
||||
mutable ResTable_config mParams;
|
||||
};
|
||||
|
||||
inline int compare_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
|
||||
{
|
||||
return lhs.compare(rhs);
|
||||
}
|
||||
|
||||
inline int strictly_order_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
|
||||
{
|
||||
return compare_type(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
class AaptGroup;
|
||||
class FilePathStore;
|
||||
|
||||
/**
|
||||
* A single asset file we know about.
|
||||
*/
|
||||
class AaptFile : public RefBase
|
||||
{
|
||||
public:
|
||||
AaptFile(const String8& sourceFile, const AaptGroupEntry& groupEntry,
|
||||
const String8& resType)
|
||||
: mGroupEntry(groupEntry)
|
||||
, mResourceType(resType)
|
||||
, mSourceFile(sourceFile)
|
||||
, mData(NULL)
|
||||
, mDataSize(0)
|
||||
, mBufferSize(0)
|
||||
, mCompression(ZipEntry::kCompressStored)
|
||||
{
|
||||
//printf("new AaptFile created %s\n", (const char*)sourceFile);
|
||||
}
|
||||
virtual ~AaptFile() {
|
||||
free(mData);
|
||||
}
|
||||
|
||||
const String8& getPath() const { return mPath; }
|
||||
const AaptGroupEntry& getGroupEntry() const { return mGroupEntry; }
|
||||
|
||||
// Data API. If there is data attached to the file,
|
||||
// getSourceFile() is not used.
|
||||
bool hasData() const { return mData != NULL; }
|
||||
const void* getData() const { return mData; }
|
||||
size_t getSize() const { return mDataSize; }
|
||||
void* editData(size_t size);
|
||||
void* editData(size_t* outSize = NULL);
|
||||
void* padData(size_t wordSize);
|
||||
status_t writeData(const void* data, size_t size);
|
||||
void clearData();
|
||||
|
||||
const String8& getResourceType() const { return mResourceType; }
|
||||
|
||||
// File API. If the file does not hold raw data, this is
|
||||
// a full path to a file on the filesystem that holds its data.
|
||||
const String8& getSourceFile() const { return mSourceFile; }
|
||||
|
||||
String8 getPrintableSource() const;
|
||||
|
||||
// Desired compression method, as per utils/ZipEntry.h. For example,
|
||||
// no compression is ZipEntry::kCompressStored.
|
||||
int getCompressionMethod() const { return mCompression; }
|
||||
void setCompressionMethod(int c) { mCompression = c; }
|
||||
private:
|
||||
friend class AaptGroup;
|
||||
|
||||
String8 mPath;
|
||||
AaptGroupEntry mGroupEntry;
|
||||
String8 mResourceType;
|
||||
String8 mSourceFile;
|
||||
void* mData;
|
||||
size_t mDataSize;
|
||||
size_t mBufferSize;
|
||||
int mCompression;
|
||||
};
|
||||
|
||||
/**
|
||||
* A group of related files (the same file, with different
|
||||
* vendor/locale variations).
|
||||
*/
|
||||
class AaptGroup : public RefBase
|
||||
{
|
||||
public:
|
||||
AaptGroup(const String8& leaf, const String8& path)
|
||||
: mLeaf(leaf), mPath(path) { }
|
||||
virtual ~AaptGroup() { }
|
||||
|
||||
const String8& getLeaf() const { return mLeaf; }
|
||||
|
||||
// Returns the relative path after the AaptGroupEntry dirs.
|
||||
const String8& getPath() const { return mPath; }
|
||||
|
||||
const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& getFiles() const
|
||||
{ return mFiles; }
|
||||
|
||||
status_t addFile(const sp<AaptFile>& file);
|
||||
void removeFile(size_t index);
|
||||
|
||||
void print(const String8& prefix) const;
|
||||
|
||||
String8 getPrintableSource() const;
|
||||
|
||||
private:
|
||||
String8 mLeaf;
|
||||
String8 mPath;
|
||||
|
||||
DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > mFiles;
|
||||
};
|
||||
|
||||
/**
|
||||
* A single directory of assets, which can contain files and other
|
||||
* sub-directories.
|
||||
*/
|
||||
class AaptDir : public RefBase
|
||||
{
|
||||
public:
|
||||
AaptDir(const String8& leaf, const String8& path)
|
||||
: mLeaf(leaf), mPath(path) { }
|
||||
virtual ~AaptDir() { }
|
||||
|
||||
const String8& getLeaf() const { return mLeaf; }
|
||||
|
||||
const String8& getPath() const { return mPath; }
|
||||
|
||||
const DefaultKeyedVector<String8, sp<AaptGroup> >& getFiles() const { return mFiles; }
|
||||
const DefaultKeyedVector<String8, sp<AaptDir> >& getDirs() const { return mDirs; }
|
||||
|
||||
virtual status_t addFile(const String8& name, const sp<AaptGroup>& file);
|
||||
|
||||
void removeFile(const String8& name);
|
||||
void removeDir(const String8& name);
|
||||
|
||||
/*
|
||||
* Perform some sanity checks on the names of files and directories here.
|
||||
* In particular:
|
||||
* - Check for illegal chars in filenames.
|
||||
* - Check filename length.
|
||||
* - Check for presence of ".gz" and non-".gz" copies of same file.
|
||||
* - Check for multiple files whose names match in a case-insensitive
|
||||
* fashion (problematic for some systems).
|
||||
*
|
||||
* Comparing names against all other names is O(n^2). We could speed
|
||||
* it up some by sorting the entries and being smarter about what we
|
||||
* compare against, but I'm not expecting to have enough files in a
|
||||
* single directory to make a noticeable difference in speed.
|
||||
*
|
||||
* Note that sorting here is not enough to guarantee that the package
|
||||
* contents are sorted -- subsequent updates can rearrange things.
|
||||
*/
|
||||
status_t validate() const;
|
||||
|
||||
void print(const String8& prefix) const;
|
||||
|
||||
String8 getPrintableSource() const;
|
||||
|
||||
private:
|
||||
friend class AaptAssets;
|
||||
|
||||
status_t addDir(const String8& name, const sp<AaptDir>& dir);
|
||||
sp<AaptDir> makeDir(const String8& name);
|
||||
status_t addLeafFile(const String8& leafName,
|
||||
const sp<AaptFile>& file);
|
||||
virtual ssize_t slurpFullTree(Bundle* bundle,
|
||||
const String8& srcDir,
|
||||
const AaptGroupEntry& kind,
|
||||
const String8& resType,
|
||||
sp<FilePathStore>& fullResPaths);
|
||||
|
||||
String8 mLeaf;
|
||||
String8 mPath;
|
||||
|
||||
DefaultKeyedVector<String8, sp<AaptGroup> > mFiles;
|
||||
DefaultKeyedVector<String8, sp<AaptDir> > mDirs;
|
||||
};
|
||||
|
||||
/**
|
||||
* All information we know about a particular symbol.
|
||||
*/
|
||||
class AaptSymbolEntry
|
||||
{
|
||||
public:
|
||||
AaptSymbolEntry()
|
||||
: isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
|
||||
{
|
||||
}
|
||||
AaptSymbolEntry(const String8& _name)
|
||||
: name(_name), isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
|
||||
{
|
||||
}
|
||||
AaptSymbolEntry(const AaptSymbolEntry& o)
|
||||
: name(o.name), sourcePos(o.sourcePos), isPublic(o.isPublic)
|
||||
, isJavaSymbol(o.isJavaSymbol), comment(o.comment), typeComment(o.typeComment)
|
||||
, typeCode(o.typeCode), int32Val(o.int32Val), stringVal(o.stringVal)
|
||||
{
|
||||
}
|
||||
AaptSymbolEntry operator=(const AaptSymbolEntry& o)
|
||||
{
|
||||
sourcePos = o.sourcePos;
|
||||
isPublic = o.isPublic;
|
||||
isJavaSymbol = o.isJavaSymbol;
|
||||
comment = o.comment;
|
||||
typeComment = o.typeComment;
|
||||
typeCode = o.typeCode;
|
||||
int32Val = o.int32Val;
|
||||
stringVal = o.stringVal;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const String8 name;
|
||||
|
||||
SourcePos sourcePos;
|
||||
bool isPublic;
|
||||
bool isJavaSymbol;
|
||||
|
||||
String16 comment;
|
||||
String16 typeComment;
|
||||
|
||||
enum {
|
||||
TYPE_UNKNOWN = 0,
|
||||
TYPE_INT32,
|
||||
TYPE_STRING
|
||||
};
|
||||
|
||||
int typeCode;
|
||||
|
||||
// Value. May be one of these.
|
||||
int32_t int32Val;
|
||||
String8 stringVal;
|
||||
};
|
||||
|
||||
/**
|
||||
* A group of related symbols (such as indices into a string block)
|
||||
* that have been generated from the assets.
|
||||
*/
|
||||
class AaptSymbols : public RefBase
|
||||
{
|
||||
public:
|
||||
AaptSymbols() { }
|
||||
virtual ~AaptSymbols() { }
|
||||
|
||||
status_t addSymbol(const String8& name, int32_t value, const SourcePos& pos) {
|
||||
if (!check_valid_symbol_name(name, pos, "symbol")) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
AaptSymbolEntry& sym = edit_symbol(name, &pos);
|
||||
sym.typeCode = AaptSymbolEntry::TYPE_INT32;
|
||||
sym.int32Val = value;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t addStringSymbol(const String8& name, const String8& value,
|
||||
const SourcePos& pos) {
|
||||
if (!check_valid_symbol_name(name, pos, "symbol")) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
AaptSymbolEntry& sym = edit_symbol(name, &pos);
|
||||
sym.typeCode = AaptSymbolEntry::TYPE_STRING;
|
||||
sym.stringVal = value;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t makeSymbolPublic(const String8& name, const SourcePos& pos) {
|
||||
if (!check_valid_symbol_name(name, pos, "symbol")) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
AaptSymbolEntry& sym = edit_symbol(name, &pos);
|
||||
sym.isPublic = true;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t makeSymbolJavaSymbol(const String8& name, const SourcePos& pos) {
|
||||
if (!check_valid_symbol_name(name, pos, "symbol")) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
AaptSymbolEntry& sym = edit_symbol(name, &pos);
|
||||
sym.isJavaSymbol = true;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void appendComment(const String8& name, const String16& comment, const SourcePos& pos) {
|
||||
if (comment.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
AaptSymbolEntry& sym = edit_symbol(name, &pos);
|
||||
if (sym.comment.size() == 0) {
|
||||
sym.comment = comment;
|
||||
} else {
|
||||
sym.comment.append(String16("\n"));
|
||||
sym.comment.append(comment);
|
||||
}
|
||||
}
|
||||
|
||||
void appendTypeComment(const String8& name, const String16& comment) {
|
||||
if (comment.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
AaptSymbolEntry& sym = edit_symbol(name, NULL);
|
||||
if (sym.typeComment.size() == 0) {
|
||||
sym.typeComment = comment;
|
||||
} else {
|
||||
sym.typeComment.append(String16("\n"));
|
||||
sym.typeComment.append(comment);
|
||||
}
|
||||
}
|
||||
|
||||
sp<AaptSymbols> addNestedSymbol(const String8& name, const SourcePos& pos) {
|
||||
if (!check_valid_symbol_name(name, pos, "nested symbol")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sp<AaptSymbols> sym = mNestedSymbols.valueFor(name);
|
||||
if (sym == NULL) {
|
||||
sym = new AaptSymbols();
|
||||
mNestedSymbols.add(name, sym);
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
status_t applyJavaSymbols(const sp<AaptSymbols>& javaSymbols);
|
||||
|
||||
const KeyedVector<String8, AaptSymbolEntry>& getSymbols() const
|
||||
{ return mSymbols; }
|
||||
const DefaultKeyedVector<String8, sp<AaptSymbols> >& getNestedSymbols() const
|
||||
{ return mNestedSymbols; }
|
||||
|
||||
const String16& getComment(const String8& name) const
|
||||
{ return get_symbol(name).comment; }
|
||||
const String16& getTypeComment(const String8& name) const
|
||||
{ return get_symbol(name).typeComment; }
|
||||
|
||||
private:
|
||||
bool check_valid_symbol_name(const String8& symbol, const SourcePos& pos, const char* label) {
|
||||
if (valid_symbol_name(symbol)) {
|
||||
return true;
|
||||
}
|
||||
pos.error("invalid %s: '%s'\n", label, symbol.string());
|
||||
return false;
|
||||
}
|
||||
AaptSymbolEntry& edit_symbol(const String8& symbol, const SourcePos* pos) {
|
||||
ssize_t i = mSymbols.indexOfKey(symbol);
|
||||
if (i < 0) {
|
||||
i = mSymbols.add(symbol, AaptSymbolEntry(symbol));
|
||||
}
|
||||
AaptSymbolEntry& sym = mSymbols.editValueAt(i);
|
||||
if (pos != NULL && sym.sourcePos.line < 0) {
|
||||
sym.sourcePos = *pos;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
const AaptSymbolEntry& get_symbol(const String8& symbol) const {
|
||||
ssize_t i = mSymbols.indexOfKey(symbol);
|
||||
if (i >= 0) {
|
||||
return mSymbols.valueAt(i);
|
||||
}
|
||||
return mDefSymbol;
|
||||
}
|
||||
|
||||
KeyedVector<String8, AaptSymbolEntry> mSymbols;
|
||||
DefaultKeyedVector<String8, sp<AaptSymbols> > mNestedSymbols;
|
||||
AaptSymbolEntry mDefSymbol;
|
||||
};
|
||||
|
||||
class ResourceTypeSet : public RefBase,
|
||||
public KeyedVector<String8,sp<AaptGroup> >
|
||||
{
|
||||
public:
|
||||
ResourceTypeSet();
|
||||
};
|
||||
|
||||
// Storage for lists of fully qualified paths for
|
||||
// resources encountered during slurping.
|
||||
class FilePathStore : public RefBase,
|
||||
public Vector<String8>
|
||||
{
|
||||
public:
|
||||
FilePathStore();
|
||||
};
|
||||
|
||||
/**
|
||||
* Asset hierarchy being operated on.
|
||||
*/
|
||||
class AaptAssets : public AaptDir
|
||||
{
|
||||
public:
|
||||
AaptAssets();
|
||||
virtual ~AaptAssets() { delete mRes; }
|
||||
|
||||
const String8& getPackage() const { return mPackage; }
|
||||
void setPackage(const String8& package) {
|
||||
mPackage = package;
|
||||
mSymbolsPrivatePackage = package;
|
||||
mHavePrivateSymbols = false;
|
||||
}
|
||||
|
||||
const SortedVector<AaptGroupEntry>& getGroupEntries() const;
|
||||
|
||||
virtual status_t addFile(const String8& name, const sp<AaptGroup>& file);
|
||||
|
||||
sp<AaptFile> addFile(const String8& filePath,
|
||||
const AaptGroupEntry& entry,
|
||||
const String8& srcDir,
|
||||
sp<AaptGroup>* outGroup,
|
||||
const String8& resType);
|
||||
|
||||
void addResource(const String8& leafName,
|
||||
const String8& path,
|
||||
const sp<AaptFile>& file,
|
||||
const String8& resType);
|
||||
|
||||
void addGroupEntry(const AaptGroupEntry& entry) { mGroupEntries.add(entry); }
|
||||
|
||||
ssize_t slurpFromArgs(Bundle* bundle);
|
||||
|
||||
sp<AaptSymbols> getSymbolsFor(const String8& name);
|
||||
|
||||
sp<AaptSymbols> getJavaSymbolsFor(const String8& name);
|
||||
|
||||
status_t applyJavaSymbols();
|
||||
|
||||
const DefaultKeyedVector<String8, sp<AaptSymbols> >& getSymbols() const { return mSymbols; }
|
||||
|
||||
String8 getSymbolsPrivatePackage() const { return mSymbolsPrivatePackage; }
|
||||
void setSymbolsPrivatePackage(const String8& pkg) {
|
||||
mSymbolsPrivatePackage = pkg;
|
||||
mHavePrivateSymbols = mSymbolsPrivatePackage != mPackage;
|
||||
}
|
||||
|
||||
bool havePrivateSymbols() const { return mHavePrivateSymbols; }
|
||||
|
||||
bool isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const;
|
||||
|
||||
status_t buildIncludedResources(Bundle* bundle);
|
||||
status_t addIncludedResources(const sp<AaptFile>& file);
|
||||
const ResTable& getIncludedResources() const;
|
||||
|
||||
void print(const String8& prefix) const;
|
||||
|
||||
inline const Vector<sp<AaptDir> >& resDirs() const { return mResDirs; }
|
||||
sp<AaptDir> resDir(const String8& name) const;
|
||||
|
||||
inline sp<AaptAssets> getOverlay() { return mOverlay; }
|
||||
inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
|
||||
|
||||
inline KeyedVector<String8, sp<ResourceTypeSet> >* getResources() { return mRes; }
|
||||
inline void
|
||||
setResources(KeyedVector<String8, sp<ResourceTypeSet> >* res) { delete mRes; mRes = res; }
|
||||
|
||||
inline sp<FilePathStore>& getFullResPaths() { return mFullResPaths; }
|
||||
inline void
|
||||
setFullResPaths(sp<FilePathStore>& res) { mFullResPaths = res; }
|
||||
|
||||
inline sp<FilePathStore>& getFullAssetPaths() { return mFullAssetPaths; }
|
||||
inline void
|
||||
setFullAssetPaths(sp<FilePathStore>& res) { mFullAssetPaths = res; }
|
||||
|
||||
private:
|
||||
virtual ssize_t slurpFullTree(Bundle* bundle,
|
||||
const String8& srcDir,
|
||||
const AaptGroupEntry& kind,
|
||||
const String8& resType,
|
||||
sp<FilePathStore>& fullResPaths);
|
||||
|
||||
ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
|
||||
ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
|
||||
|
||||
status_t filter(Bundle* bundle);
|
||||
|
||||
String8 mPackage;
|
||||
SortedVector<AaptGroupEntry> mGroupEntries;
|
||||
DefaultKeyedVector<String8, sp<AaptSymbols> > mSymbols;
|
||||
DefaultKeyedVector<String8, sp<AaptSymbols> > mJavaSymbols;
|
||||
String8 mSymbolsPrivatePackage;
|
||||
bool mHavePrivateSymbols;
|
||||
|
||||
Vector<sp<AaptDir> > mResDirs;
|
||||
|
||||
bool mChanged;
|
||||
|
||||
bool mHaveIncludedAssets;
|
||||
AssetManager mIncludedAssets;
|
||||
|
||||
sp<AaptAssets> mOverlay;
|
||||
KeyedVector<String8, sp<ResourceTypeSet> >* mRes;
|
||||
|
||||
sp<FilePathStore> mFullResPaths;
|
||||
sp<FilePathStore> mFullAssetPaths;
|
||||
};
|
||||
|
||||
#endif // __AAPT_ASSETS_H
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
#
|
||||
# Copyright 2006 The Android Open Source Project
|
||||
#
|
||||
# Android Asset Packaging Tool
|
||||
#
|
||||
|
||||
# This tool is prebuilt if we're doing an app-only build.
|
||||
ifeq ($(TARGET_BUILD_APPS),)
|
||||
|
||||
|
||||
aapt_src_files := \
|
||||
AaptAssets.cpp \
|
||||
Command.cpp \
|
||||
CrunchCache.cpp \
|
||||
FileFinder.cpp \
|
||||
Main.cpp \
|
||||
Package.cpp \
|
||||
StringPool.cpp \
|
||||
XMLNode.cpp \
|
||||
ResourceFilter.cpp \
|
||||
ResourceIdCache.cpp \
|
||||
ResourceTable.cpp \
|
||||
Images.cpp \
|
||||
Resource.cpp \
|
||||
pseudolocalize.cpp \
|
||||
SourcePos.cpp \
|
||||
WorkQueue.cpp \
|
||||
ZipEntry.cpp \
|
||||
ZipFile.cpp \
|
||||
qsort_r_compat.c
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := $(aapt_src_files)
|
||||
|
||||
LOCAL_CFLAGS += -Wno-format-y2k
|
||||
ifeq (darwin,$(HOST_OS))
|
||||
LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
|
||||
endif
|
||||
|
||||
LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
|
||||
|
||||
LOCAL_C_INCLUDES += external/libpng
|
||||
LOCAL_C_INCLUDES += external/zlib
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libandroidfw \
|
||||
libutils \
|
||||
libcutils \
|
||||
libexpat \
|
||||
libpng \
|
||||
liblog
|
||||
|
||||
ifeq ($(HOST_OS),linux)
|
||||
LOCAL_LDLIBS += -lrt -ldl -lpthread
|
||||
endif
|
||||
|
||||
# Statically link libz for MinGW (Win SDK under Linux),
|
||||
# and dynamically link for all others.
|
||||
ifneq ($(strip $(USE_MINGW)),)
|
||||
LOCAL_STATIC_LIBRARIES += libz
|
||||
else
|
||||
LOCAL_LDLIBS += -lz
|
||||
endif
|
||||
|
||||
LOCAL_MODULE := aapt
|
||||
|
||||
include $(BUILD_HOST_EXECUTABLE)
|
||||
|
||||
# aapt for running on the device
|
||||
# =========================================================
|
||||
ifneq ($(SDK_ONLY),true)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := $(aapt_src_files)
|
||||
|
||||
LOCAL_MODULE := aapt
|
||||
|
||||
LOCAL_C_INCLUDES += bionic
|
||||
LOCAL_C_INCLUDES += bionic/libstdc++/include
|
||||
LOCAL_C_INCLUDES += external/stlport/stlport
|
||||
LOCAL_C_INCLUDES += external/libpng
|
||||
LOCAL_C_INCLUDES += external/zlib
|
||||
|
||||
LOCAL_CFLAGS += -Wno-non-virtual-dtor
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libandroidfw \
|
||||
libutils \
|
||||
libcutils \
|
||||
libpng \
|
||||
liblog \
|
||||
libz
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libstlport_static \
|
||||
libexpat_static
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
endif
|
||||
|
||||
endif # TARGET_BUILD_APPS
|
||||
@@ -1,309 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// State bundle. Used to pass around stuff like command-line args.
|
||||
//
|
||||
#ifndef __BUNDLE_H
|
||||
#define __BUNDLE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
enum {
|
||||
SDK_CUPCAKE = 3,
|
||||
SDK_DONUT = 4,
|
||||
SDK_ECLAIR = 5,
|
||||
SDK_ECLAIR_0_1 = 6,
|
||||
SDK_MR1 = 7,
|
||||
SDK_FROYO = 8,
|
||||
SDK_HONEYCOMB_MR2 = 13,
|
||||
SDK_ICE_CREAM_SANDWICH = 14,
|
||||
SDK_ICE_CREAM_SANDWICH_MR1 = 15,
|
||||
};
|
||||
|
||||
/*
|
||||
* Things we can do.
|
||||
*/
|
||||
typedef enum Command {
|
||||
kCommandUnknown = 0,
|
||||
kCommandVersion,
|
||||
kCommandList,
|
||||
kCommandDump,
|
||||
kCommandAdd,
|
||||
kCommandRemove,
|
||||
kCommandPackage,
|
||||
kCommandCrunch,
|
||||
kCommandSingleCrunch,
|
||||
} Command;
|
||||
|
||||
/*
|
||||
* Bundle of goodies, including everything specified on the command line.
|
||||
*/
|
||||
class Bundle {
|
||||
public:
|
||||
Bundle(void)
|
||||
: mCmd(kCommandUnknown), mVerbose(false), mAndroidList(false),
|
||||
mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
|
||||
mUpdate(false), mExtending(false),
|
||||
mRequireLocalization(false), mPseudolocalize(false),
|
||||
mWantUTF16(false), mValues(false), mIncludeMetaData(false),
|
||||
mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL),
|
||||
mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
|
||||
mAutoAddOverlay(false), mGenDependencies(false),
|
||||
mAssetSourceDir(NULL),
|
||||
mCrunchedOutputDir(NULL), mProguardFile(NULL),
|
||||
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
|
||||
mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
|
||||
mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
|
||||
mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), mExtraPackages(NULL),
|
||||
mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false), mProduct(NULL),
|
||||
mUseCrunchCache(false), mErrorOnFailedInsert(false), mOutputTextSymbols(NULL),
|
||||
mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
|
||||
mArgc(0), mArgv(NULL)
|
||||
{}
|
||||
~Bundle(void) {}
|
||||
|
||||
/*
|
||||
* Set the command value. Returns "false" if it was previously set.
|
||||
*/
|
||||
Command getCommand(void) const { return mCmd; }
|
||||
void setCommand(Command cmd) { mCmd = cmd; }
|
||||
|
||||
/*
|
||||
* Command modifiers. Not all modifiers are appropriate for all
|
||||
* commands.
|
||||
*/
|
||||
bool getVerbose(void) const { return mVerbose; }
|
||||
void setVerbose(bool val) { mVerbose = val; }
|
||||
bool getAndroidList(void) const { return mAndroidList; }
|
||||
void setAndroidList(bool val) { mAndroidList = val; }
|
||||
bool getForce(void) const { return mForce; }
|
||||
void setForce(bool val) { mForce = val; }
|
||||
void setGrayscaleTolerance(int val) { mGrayscaleTolerance = val; }
|
||||
int getGrayscaleTolerance() const { return mGrayscaleTolerance; }
|
||||
bool getMakePackageDirs(void) const { return mMakePackageDirs; }
|
||||
void setMakePackageDirs(bool val) { mMakePackageDirs = val; }
|
||||
bool getUpdate(void) const { return mUpdate; }
|
||||
void setUpdate(bool val) { mUpdate = val; }
|
||||
bool getExtending(void) const { return mExtending; }
|
||||
void setExtending(bool val) { mExtending = val; }
|
||||
bool getRequireLocalization(void) const { return mRequireLocalization; }
|
||||
void setRequireLocalization(bool val) { mRequireLocalization = val; }
|
||||
bool getPseudolocalize(void) const { return mPseudolocalize; }
|
||||
void setPseudolocalize(bool val) { mPseudolocalize = val; }
|
||||
void setWantUTF16(bool val) { mWantUTF16 = val; }
|
||||
bool getValues(void) const { return mValues; }
|
||||
void setValues(bool val) { mValues = val; }
|
||||
bool getIncludeMetaData(void) const { return mIncludeMetaData; }
|
||||
void setIncludeMetaData(bool val) { mIncludeMetaData = val; }
|
||||
int getCompressionMethod(void) const { return mCompressionMethod; }
|
||||
void setCompressionMethod(int val) { mCompressionMethod = val; }
|
||||
bool getJunkPath(void) const { return mJunkPath; }
|
||||
void setJunkPath(bool val) { mJunkPath = val; }
|
||||
const char* getOutputAPKFile() const { return mOutputAPKFile; }
|
||||
void setOutputAPKFile(const char* val) { mOutputAPKFile = val; }
|
||||
const char* getManifestPackageNameOverride() const { return mManifestPackageNameOverride; }
|
||||
void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; }
|
||||
const char* getInstrumentationPackageNameOverride() const { return mInstrumentationPackageNameOverride; }
|
||||
void setInstrumentationPackageNameOverride(const char * val) { mInstrumentationPackageNameOverride = val; }
|
||||
bool getAutoAddOverlay() { return mAutoAddOverlay; }
|
||||
void setAutoAddOverlay(bool val) { mAutoAddOverlay = val; }
|
||||
bool getGenDependencies() { return mGenDependencies; }
|
||||
void setGenDependencies(bool val) { mGenDependencies = val; }
|
||||
bool getErrorOnFailedInsert() { return mErrorOnFailedInsert; }
|
||||
void setErrorOnFailedInsert(bool val) { mErrorOnFailedInsert = val; }
|
||||
|
||||
bool getUTF16StringsOption() {
|
||||
return mWantUTF16 || !isMinSdkAtLeast(SDK_FROYO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input options.
|
||||
*/
|
||||
const char* getAssetSourceDir() const { return mAssetSourceDir; }
|
||||
void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; }
|
||||
const char* getCrunchedOutputDir() const { return mCrunchedOutputDir; }
|
||||
void setCrunchedOutputDir(const char* dir) { mCrunchedOutputDir = dir; }
|
||||
const char* getProguardFile() const { return mProguardFile; }
|
||||
void setProguardFile(const char* file) { mProguardFile = file; }
|
||||
const android::Vector<const char*>& getResourceSourceDirs() const { return mResourceSourceDirs; }
|
||||
void addResourceSourceDir(const char* dir) { mResourceSourceDirs.insertAt(dir,0); }
|
||||
const char* getAndroidManifestFile() const { return mAndroidManifestFile; }
|
||||
void setAndroidManifestFile(const char* file) { mAndroidManifestFile = file; }
|
||||
const char* getPublicOutputFile() const { return mPublicOutputFile; }
|
||||
void setPublicOutputFile(const char* file) { mPublicOutputFile = file; }
|
||||
const char* getRClassDir() const { return mRClassDir; }
|
||||
void setRClassDir(const char* dir) { mRClassDir = dir; }
|
||||
const char* getConfigurations() const { return mConfigurations.size() > 0 ? mConfigurations.string() : NULL; }
|
||||
void addConfigurations(const char* val) { if (mConfigurations.size() > 0) { mConfigurations.append(","); mConfigurations.append(val); } else { mConfigurations = val; } }
|
||||
const char* getPreferredConfigurations() const { return mPreferredConfigurations.size() > 0 ? mPreferredConfigurations.string() : NULL; }
|
||||
void addPreferredConfigurations(const char* val) { if (mPreferredConfigurations.size() > 0) { mPreferredConfigurations.append(","); mPreferredConfigurations.append(val); } else { mPreferredConfigurations = val; } }
|
||||
const char* getResourceIntermediatesDir() const { return mResourceIntermediatesDir; }
|
||||
void setResourceIntermediatesDir(const char* dir) { mResourceIntermediatesDir = dir; }
|
||||
const android::Vector<const char*>& getPackageIncludes() const { return mPackageIncludes; }
|
||||
void addPackageInclude(const char* file) { mPackageIncludes.add(file); }
|
||||
const android::Vector<const char*>& getJarFiles() const { return mJarFiles; }
|
||||
void addJarFile(const char* file) { mJarFiles.add(file); }
|
||||
const android::Vector<const char*>& getNoCompressExtensions() const { return mNoCompressExtensions; }
|
||||
void addNoCompressExtension(const char* ext) { mNoCompressExtensions.add(ext); }
|
||||
|
||||
const char* getManifestMinSdkVersion() const { return mManifestMinSdkVersion; }
|
||||
void setManifestMinSdkVersion(const char* val) { mManifestMinSdkVersion = val; }
|
||||
const char* getMinSdkVersion() const { return mMinSdkVersion; }
|
||||
void setMinSdkVersion(const char* val) { mMinSdkVersion = val; }
|
||||
const char* getTargetSdkVersion() const { return mTargetSdkVersion; }
|
||||
void setTargetSdkVersion(const char* val) { mTargetSdkVersion = val; }
|
||||
const char* getMaxSdkVersion() const { return mMaxSdkVersion; }
|
||||
void setMaxSdkVersion(const char* val) { mMaxSdkVersion = val; }
|
||||
const char* getVersionCode() const { return mVersionCode; }
|
||||
void setVersionCode(const char* val) { mVersionCode = val; }
|
||||
const char* getVersionName() const { return mVersionName; }
|
||||
void setVersionName(const char* val) { mVersionName = val; }
|
||||
const char* getCustomPackage() const { return mCustomPackage; }
|
||||
void setCustomPackage(const char* val) { mCustomPackage = val; }
|
||||
const char* getExtraPackages() const { return mExtraPackages; }
|
||||
void setExtraPackages(const char* val) { mExtraPackages = val; }
|
||||
const char* getMaxResVersion() const { return mMaxResVersion; }
|
||||
void setMaxResVersion(const char * val) { mMaxResVersion = val; }
|
||||
bool getDebugMode() const { return mDebugMode; }
|
||||
void setDebugMode(bool val) { mDebugMode = val; }
|
||||
bool getNonConstantId() const { return mNonConstantId; }
|
||||
void setNonConstantId(bool val) { mNonConstantId = val; }
|
||||
const char* getProduct() const { return mProduct; }
|
||||
void setProduct(const char * val) { mProduct = val; }
|
||||
void setUseCrunchCache(bool val) { mUseCrunchCache = val; }
|
||||
bool getUseCrunchCache() const { return mUseCrunchCache; }
|
||||
const char* getOutputTextSymbols() const { return mOutputTextSymbols; }
|
||||
void setOutputTextSymbols(const char* val) { mOutputTextSymbols = val; }
|
||||
const char* getSingleCrunchInputFile() const { return mSingleCrunchInputFile; }
|
||||
void setSingleCrunchInputFile(const char* val) { mSingleCrunchInputFile = val; }
|
||||
const char* getSingleCrunchOutputFile() const { return mSingleCrunchOutputFile; }
|
||||
void setSingleCrunchOutputFile(const char* val) { mSingleCrunchOutputFile = val; }
|
||||
|
||||
/*
|
||||
* Set and get the file specification.
|
||||
*
|
||||
* Note this does NOT make a copy of argv.
|
||||
*/
|
||||
void setFileSpec(char* const argv[], int argc) {
|
||||
mArgc = argc;
|
||||
mArgv = argv;
|
||||
}
|
||||
int getFileSpecCount(void) const { return mArgc; }
|
||||
const char* getFileSpecEntry(int idx) const { return mArgv[idx]; }
|
||||
void eatArgs(int n) {
|
||||
if (n > mArgc) n = mArgc;
|
||||
mArgv += n;
|
||||
mArgc -= n;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Package count. Nothing to do with anything else here; this is
|
||||
* just a convenient place to stuff it so we don't have to pass it
|
||||
* around everywhere.
|
||||
*/
|
||||
int getPackageCount(void) const { return mPackageCount; }
|
||||
void setPackageCount(int val) { mPackageCount = val; }
|
||||
#endif
|
||||
|
||||
/* Certain features may only be available on a specific SDK level or
|
||||
* above. SDK levels that have a non-numeric identifier are assumed
|
||||
* to be newer than any SDK level that has a number designated.
|
||||
*/
|
||||
bool isMinSdkAtLeast(int desired) {
|
||||
/* If the application specifies a minSdkVersion in the manifest
|
||||
* then use that. Otherwise, check what the user specified on
|
||||
* the command line. If neither, it's not available since
|
||||
* the minimum SDK version is assumed to be 1.
|
||||
*/
|
||||
const char *minVer;
|
||||
if (mManifestMinSdkVersion != NULL) {
|
||||
minVer = mManifestMinSdkVersion;
|
||||
} else if (mMinSdkVersion != NULL) {
|
||||
minVer = mMinSdkVersion;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
char *end;
|
||||
int minSdkNum = (int)strtol(minVer, &end, 0);
|
||||
if (*end == '\0') {
|
||||
if (minSdkNum < desired) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
/* commands & modifiers */
|
||||
Command mCmd;
|
||||
bool mVerbose;
|
||||
bool mAndroidList;
|
||||
bool mForce;
|
||||
int mGrayscaleTolerance;
|
||||
bool mMakePackageDirs;
|
||||
bool mUpdate;
|
||||
bool mExtending;
|
||||
bool mRequireLocalization;
|
||||
bool mPseudolocalize;
|
||||
bool mWantUTF16;
|
||||
bool mValues;
|
||||
bool mIncludeMetaData;
|
||||
int mCompressionMethod;
|
||||
bool mJunkPath;
|
||||
const char* mOutputAPKFile;
|
||||
const char* mManifestPackageNameOverride;
|
||||
const char* mInstrumentationPackageNameOverride;
|
||||
bool mAutoAddOverlay;
|
||||
bool mGenDependencies;
|
||||
const char* mAssetSourceDir;
|
||||
const char* mCrunchedOutputDir;
|
||||
const char* mProguardFile;
|
||||
const char* mAndroidManifestFile;
|
||||
const char* mPublicOutputFile;
|
||||
const char* mRClassDir;
|
||||
const char* mResourceIntermediatesDir;
|
||||
android::String8 mConfigurations;
|
||||
android::String8 mPreferredConfigurations;
|
||||
android::Vector<const char*> mPackageIncludes;
|
||||
android::Vector<const char*> mJarFiles;
|
||||
android::Vector<const char*> mNoCompressExtensions;
|
||||
android::Vector<const char*> mResourceSourceDirs;
|
||||
|
||||
const char* mManifestMinSdkVersion;
|
||||
const char* mMinSdkVersion;
|
||||
const char* mTargetSdkVersion;
|
||||
const char* mMaxSdkVersion;
|
||||
const char* mVersionCode;
|
||||
const char* mVersionName;
|
||||
const char* mCustomPackage;
|
||||
const char* mExtraPackages;
|
||||
const char* mMaxResVersion;
|
||||
bool mDebugMode;
|
||||
bool mNonConstantId;
|
||||
const char* mProduct;
|
||||
bool mUseCrunchCache;
|
||||
bool mErrorOnFailedInsert;
|
||||
const char* mOutputTextSymbols;
|
||||
const char* mSingleCrunchInputFile;
|
||||
const char* mSingleCrunchOutputFile;
|
||||
|
||||
/* file specification */
|
||||
int mArgc;
|
||||
char* const* mArgv;
|
||||
|
||||
#if 0
|
||||
/* misc stuff */
|
||||
int mPackageCount;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // __BUNDLE_H
|
||||
@@ -1,107 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
// Abstraction of calls to system to make directories and delete files and
|
||||
// wrapper to image processing.
|
||||
|
||||
#ifndef CACHE_UPDATER_H
|
||||
#define CACHE_UPDATER_H
|
||||
|
||||
#include <utils/String8.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include "Images.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
/** CacheUpdater
|
||||
* This is a pure virtual class that declares abstractions of functions useful
|
||||
* for managing a cache files. This manager is set up to be used in a
|
||||
* mirror cache where the source tree is duplicated and filled with processed
|
||||
* images. This class is abstracted to allow for dependency injection during
|
||||
* unit testing.
|
||||
* Usage:
|
||||
* To update/add a file to the cache, call processImage
|
||||
* To remove a file from the cache, call deleteFile
|
||||
*/
|
||||
class CacheUpdater {
|
||||
public:
|
||||
// Make sure all the directories along this path exist
|
||||
virtual void ensureDirectoriesExist(String8 path) = 0;
|
||||
|
||||
// Delete a file
|
||||
virtual void deleteFile(String8 path) = 0;
|
||||
|
||||
// Process an image from source out to dest
|
||||
virtual void processImage(String8 source, String8 dest) = 0;
|
||||
private:
|
||||
};
|
||||
|
||||
/** SystemCacheUpdater
|
||||
* This is an implementation of the above virtual cache updater specification.
|
||||
* This implementations hits the filesystem to manage a cache and calls out to
|
||||
* the PNG crunching in images.h to process images out to its cache components.
|
||||
*/
|
||||
class SystemCacheUpdater : public CacheUpdater {
|
||||
public:
|
||||
// Constructor to set bundle to pass to preProcessImage
|
||||
SystemCacheUpdater (Bundle* b)
|
||||
: bundle(b) { };
|
||||
|
||||
// Make sure all the directories along this path exist
|
||||
virtual void ensureDirectoriesExist(String8 path)
|
||||
{
|
||||
// Check to see if we're dealing with a fully qualified path
|
||||
String8 existsPath;
|
||||
String8 toCreate;
|
||||
String8 remains;
|
||||
struct stat s;
|
||||
|
||||
// Check optomistically to see if all directories exist.
|
||||
// If something in the path doesn't exist, then walk the path backwards
|
||||
// and find the place to start creating directories forward.
|
||||
if (stat(path.string(),&s) == -1) {
|
||||
// Walk backwards to find place to start creating directories
|
||||
existsPath = path;
|
||||
do {
|
||||
// As we remove the end of existsPath add it to
|
||||
// the string of paths to create.
|
||||
toCreate = existsPath.getPathLeaf().appendPath(toCreate);
|
||||
existsPath = existsPath.getPathDir();
|
||||
} while (stat(existsPath.string(),&s) == -1);
|
||||
|
||||
// Walk forwards and build directories as we go
|
||||
do {
|
||||
// Advance to the next segment of the path
|
||||
existsPath.appendPath(toCreate.walkPath(&remains));
|
||||
toCreate = remains;
|
||||
#ifdef HAVE_MS_C_RUNTIME
|
||||
_mkdir(existsPath.string());
|
||||
#else
|
||||
mkdir(existsPath.string(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
|
||||
#endif
|
||||
} while (remains.length() > 0);
|
||||
} //if
|
||||
};
|
||||
|
||||
// Delete a file
|
||||
virtual void deleteFile(String8 path)
|
||||
{
|
||||
if (remove(path.string()) != 0)
|
||||
fprintf(stderr,"ERROR DELETING %s\n",path.string());
|
||||
};
|
||||
|
||||
// Process an image from source out to dest
|
||||
virtual void processImage(String8 source, String8 dest)
|
||||
{
|
||||
// Make sure we're trying to write to a directory that is extant
|
||||
ensureDirectoriesExist(dest.getPathDir());
|
||||
|
||||
preProcessImageToCache(bundle, source, dest);
|
||||
};
|
||||
private:
|
||||
Bundle* bundle;
|
||||
};
|
||||
|
||||
#endif // CACHE_UPDATER_H
|
||||
@@ -1,104 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
// Implementation file for CrunchCache
|
||||
// This file defines functions laid out and documented in
|
||||
// CrunchCache.h
|
||||
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include "DirectoryWalker.h"
|
||||
#include "FileFinder.h"
|
||||
#include "CacheUpdater.h"
|
||||
#include "CrunchCache.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
CrunchCache::CrunchCache(String8 sourcePath, String8 destPath, FileFinder* ff)
|
||||
: mSourcePath(sourcePath), mDestPath(destPath), mSourceFiles(0), mDestFiles(0), mFileFinder(ff)
|
||||
{
|
||||
// We initialize the default value to return to 0 so if a file doesn't exist
|
||||
// then all files are automatically "newer" than it.
|
||||
|
||||
// Set file extensions to look for. Right now just pngs.
|
||||
mExtensions.push(String8(".png"));
|
||||
|
||||
// Load files into our data members
|
||||
loadFiles();
|
||||
}
|
||||
|
||||
size_t CrunchCache::crunch(CacheUpdater* cu, bool forceOverwrite)
|
||||
{
|
||||
size_t numFilesUpdated = 0;
|
||||
|
||||
// Iterate through the source files and compare to cache.
|
||||
// After processing a file, remove it from the source files and
|
||||
// from the dest files.
|
||||
// We're done when we're out of files in source.
|
||||
String8 relativePath;
|
||||
while (mSourceFiles.size() > 0) {
|
||||
// Get the full path to the source file, then convert to a c-string
|
||||
// and offset our beginning pointer to the length of the sourcePath
|
||||
// This efficiently strips the source directory prefix from our path.
|
||||
// Also, String8 doesn't have a substring method so this is what we've
|
||||
// got to work with.
|
||||
const char* rPathPtr = mSourceFiles.keyAt(0).string()+mSourcePath.length();
|
||||
// Strip leading slash if present
|
||||
int offset = 0;
|
||||
if (rPathPtr[0] == OS_PATH_SEPARATOR)
|
||||
offset = 1;
|
||||
relativePath = String8(rPathPtr + offset);
|
||||
|
||||
if (forceOverwrite || needsUpdating(relativePath)) {
|
||||
cu->processImage(mSourcePath.appendPathCopy(relativePath),
|
||||
mDestPath.appendPathCopy(relativePath));
|
||||
numFilesUpdated++;
|
||||
// crunchFile(relativePath);
|
||||
}
|
||||
// Delete this file from the source files and (if it exists) from the
|
||||
// dest files.
|
||||
mSourceFiles.removeItemsAt(0);
|
||||
mDestFiles.removeItem(mDestPath.appendPathCopy(relativePath));
|
||||
}
|
||||
|
||||
// Iterate through what's left of destFiles and delete leftovers
|
||||
while (mDestFiles.size() > 0) {
|
||||
cu->deleteFile(mDestFiles.keyAt(0));
|
||||
mDestFiles.removeItemsAt(0);
|
||||
}
|
||||
|
||||
// Update our knowledge of the files cache
|
||||
// both source and dest should be empty by now.
|
||||
loadFiles();
|
||||
|
||||
return numFilesUpdated;
|
||||
}
|
||||
|
||||
void CrunchCache::loadFiles()
|
||||
{
|
||||
// Clear out our data structures to avoid putting in duplicates
|
||||
mSourceFiles.clear();
|
||||
mDestFiles.clear();
|
||||
|
||||
// Make a directory walker that points to the system.
|
||||
DirectoryWalker* dw = new SystemDirectoryWalker();
|
||||
|
||||
// Load files in the source directory
|
||||
mFileFinder->findFiles(mSourcePath, mExtensions, mSourceFiles,dw);
|
||||
|
||||
// Load files in the destination directory
|
||||
mFileFinder->findFiles(mDestPath,mExtensions,mDestFiles,dw);
|
||||
|
||||
delete dw;
|
||||
}
|
||||
|
||||
bool CrunchCache::needsUpdating(String8 relativePath) const
|
||||
{
|
||||
// Retrieve modification dates for this file entry under the source and
|
||||
// cache directory trees. The vectors will return a modification date of 0
|
||||
// if the file doesn't exist.
|
||||
time_t sourceDate = mSourceFiles.valueFor(mSourcePath.appendPathCopy(relativePath));
|
||||
time_t destDate = mDestFiles.valueFor(mDestPath.appendPathCopy(relativePath));
|
||||
return sourceDate > destDate;
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
// Cache manager for pre-processed PNG files.
|
||||
// Contains code for managing which PNG files get processed
|
||||
// at build time.
|
||||
//
|
||||
|
||||
#ifndef CRUNCHCACHE_H
|
||||
#define CRUNCHCACHE_H
|
||||
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/String8.h>
|
||||
#include "FileFinder.h"
|
||||
#include "CacheUpdater.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
/** CrunchCache
|
||||
* This class is a cache manager which can pre-process PNG files and store
|
||||
* them in a mirror-cache. It's capable of doing incremental updates to its
|
||||
* cache.
|
||||
*
|
||||
* Usage:
|
||||
* Create an instance initialized with the root of the source tree, the
|
||||
* root location to store the cache files, and an instance of a file finder.
|
||||
* Then update the cache by calling crunch.
|
||||
*/
|
||||
class CrunchCache {
|
||||
public:
|
||||
// Constructor
|
||||
CrunchCache(String8 sourcePath, String8 destPath, FileFinder* ff);
|
||||
|
||||
// Nobody should be calling the default constructor
|
||||
// So this space is intentionally left blank
|
||||
|
||||
// Default Copy Constructor and Destructor are fine
|
||||
|
||||
/** crunch is the workhorse of this class.
|
||||
* It goes through all the files found in the sourcePath and compares
|
||||
* them to the cached versions in the destPath. If the optional
|
||||
* argument forceOverwrite is set to true, then all source files are
|
||||
* re-crunched even if they have not been modified recently. Otherwise,
|
||||
* source files are only crunched when they needUpdating. Afterwards,
|
||||
* we delete any leftover files in the cache that are no longer present
|
||||
* in source.
|
||||
*
|
||||
* PRECONDITIONS:
|
||||
* No setup besides construction is needed
|
||||
* POSTCONDITIONS:
|
||||
* The cache is updated to fully reflect all changes in source.
|
||||
* The function then returns the number of files changed in cache
|
||||
* (counting deletions).
|
||||
*/
|
||||
size_t crunch(CacheUpdater* cu, bool forceOverwrite=false);
|
||||
|
||||
private:
|
||||
/** loadFiles is a wrapper to the FileFinder that places matching
|
||||
* files into mSourceFiles and mDestFiles.
|
||||
*
|
||||
* POSTCONDITIONS
|
||||
* mDestFiles and mSourceFiles are refreshed to reflect the current
|
||||
* state of the files in the source and dest directories.
|
||||
* Any previous contents of mSourceFiles and mDestFiles are cleared.
|
||||
*/
|
||||
void loadFiles();
|
||||
|
||||
/** needsUpdating takes a file path
|
||||
* and returns true if the file represented by this path is newer in the
|
||||
* sourceFiles than in the cache (mDestFiles).
|
||||
*
|
||||
* PRECONDITIONS:
|
||||
* mSourceFiles and mDestFiles must be initialized and filled.
|
||||
* POSTCONDITIONS:
|
||||
* returns true if and only if source file's modification time
|
||||
* is greater than the cached file's mod-time. Otherwise returns false.
|
||||
*
|
||||
* USAGE:
|
||||
* Should be used something like the following:
|
||||
* if (needsUpdating(filePath))
|
||||
* // Recrunch sourceFile out to destFile.
|
||||
*
|
||||
*/
|
||||
bool needsUpdating(String8 relativePath) const;
|
||||
|
||||
// DATA MEMBERS ====================================================
|
||||
|
||||
String8 mSourcePath;
|
||||
String8 mDestPath;
|
||||
|
||||
Vector<String8> mExtensions;
|
||||
|
||||
// Each vector of paths contains one entry per PNG file encountered.
|
||||
// Each entry consists of a path pointing to that PNG.
|
||||
DefaultKeyedVector<String8,time_t> mSourceFiles;
|
||||
DefaultKeyedVector<String8,time_t> mDestFiles;
|
||||
|
||||
// Pointer to a FileFinder to use
|
||||
FileFinder* mFileFinder;
|
||||
};
|
||||
|
||||
#endif // CRUNCHCACHE_H
|
||||
@@ -1,98 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
// Defines an abstraction for opening a directory on the filesystem and
|
||||
// iterating through it.
|
||||
|
||||
#ifndef DIRECTORYWALKER_H
|
||||
#define DIRECTORYWALKER_H
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
// Directory Walker
|
||||
// This is an abstraction for walking through a directory and getting files
|
||||
// and descriptions.
|
||||
|
||||
class DirectoryWalker {
|
||||
public:
|
||||
virtual ~DirectoryWalker() {};
|
||||
virtual bool openDir(String8 path) = 0;
|
||||
virtual bool openDir(const char* path) = 0;
|
||||
// Advance to next directory entry
|
||||
virtual struct dirent* nextEntry() = 0;
|
||||
// Get the stats for the current entry
|
||||
virtual struct stat* entryStats() = 0;
|
||||
// Clean Up
|
||||
virtual void closeDir() = 0;
|
||||
// This class is able to replicate itself on the heap
|
||||
virtual DirectoryWalker* clone() = 0;
|
||||
|
||||
// DATA MEMBERS
|
||||
// Current directory entry
|
||||
struct dirent mEntry;
|
||||
// Stats for that directory entry
|
||||
struct stat mStats;
|
||||
// Base path
|
||||
String8 mBasePath;
|
||||
};
|
||||
|
||||
// System Directory Walker
|
||||
// This is an implementation of the above abstraction that calls
|
||||
// real system calls and is fully functional.
|
||||
// functions are inlined since they're very short and simple
|
||||
|
||||
class SystemDirectoryWalker : public DirectoryWalker {
|
||||
|
||||
// Default constructor, copy constructor, and destructor are fine
|
||||
public:
|
||||
virtual bool openDir(String8 path) {
|
||||
mBasePath = path;
|
||||
dir = NULL;
|
||||
dir = opendir(mBasePath.string() );
|
||||
|
||||
if (dir == NULL)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
virtual bool openDir(const char* path) {
|
||||
String8 p(path);
|
||||
openDir(p);
|
||||
return true;
|
||||
};
|
||||
// Advance to next directory entry
|
||||
virtual struct dirent* nextEntry() {
|
||||
struct dirent* entryPtr = readdir(dir);
|
||||
if (entryPtr == NULL)
|
||||
return NULL;
|
||||
|
||||
mEntry = *entryPtr;
|
||||
// Get stats
|
||||
String8 fullPath = mBasePath.appendPathCopy(mEntry.d_name);
|
||||
stat(fullPath.string(),&mStats);
|
||||
return &mEntry;
|
||||
};
|
||||
// Get the stats for the current entry
|
||||
virtual struct stat* entryStats() {
|
||||
return &mStats;
|
||||
};
|
||||
virtual void closeDir() {
|
||||
closedir(dir);
|
||||
};
|
||||
virtual DirectoryWalker* clone() {
|
||||
return new SystemDirectoryWalker(*this);
|
||||
};
|
||||
private:
|
||||
DIR* dir;
|
||||
};
|
||||
|
||||
#endif // DIRECTORYWALKER_H
|
||||
@@ -1,98 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
|
||||
// File Finder implementation.
|
||||
// Implementation for the functions declared and documented in FileFinder.h
|
||||
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "DirectoryWalker.h"
|
||||
#include "FileFinder.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
using android::String8;
|
||||
|
||||
// Private function to check whether a file is a directory or not
|
||||
bool isDirectory(const char* filename) {
|
||||
struct stat fileStat;
|
||||
if (stat(filename, &fileStat) == -1) {
|
||||
return false;
|
||||
}
|
||||
return(S_ISDIR(fileStat.st_mode));
|
||||
}
|
||||
|
||||
|
||||
// Private function to check whether a file is a regular file or not
|
||||
bool isFile(const char* filename) {
|
||||
struct stat fileStat;
|
||||
if (stat(filename, &fileStat) == -1) {
|
||||
return false;
|
||||
}
|
||||
return(S_ISREG(fileStat.st_mode));
|
||||
}
|
||||
|
||||
bool SystemFileFinder::findFiles(String8 basePath, Vector<String8>& extensions,
|
||||
KeyedVector<String8,time_t>& fileStore,
|
||||
DirectoryWalker* dw)
|
||||
{
|
||||
// Scan the directory pointed to by basePath
|
||||
// check files and recurse into subdirectories.
|
||||
if (!dw->openDir(basePath)) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Go through all directory entries. Check each file using checkAndAddFile
|
||||
* and recurse into sub-directories.
|
||||
*/
|
||||
struct dirent* entry;
|
||||
while ((entry = dw->nextEntry()) != NULL) {
|
||||
String8 entryName(entry->d_name);
|
||||
if (entry->d_name[0] == '.') // Skip hidden files and directories
|
||||
continue;
|
||||
|
||||
String8 fullPath = basePath.appendPathCopy(entryName);
|
||||
// If this entry is a directory we'll recurse into it
|
||||
if (isDirectory(fullPath.string()) ) {
|
||||
DirectoryWalker* copy = dw->clone();
|
||||
findFiles(fullPath, extensions, fileStore,copy);
|
||||
delete copy;
|
||||
}
|
||||
|
||||
// If this entry is a file, we'll pass it over to checkAndAddFile
|
||||
if (isFile(fullPath.string()) ) {
|
||||
checkAndAddFile(fullPath,dw->entryStats(),extensions,fileStore);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
dw->closeDir();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SystemFileFinder::checkAndAddFile(String8 path, const struct stat* stats,
|
||||
Vector<String8>& extensions,
|
||||
KeyedVector<String8,time_t>& fileStore)
|
||||
{
|
||||
// Loop over the extensions, checking for a match
|
||||
bool done = false;
|
||||
String8 ext(path.getPathExtension());
|
||||
ext.toLower();
|
||||
for (size_t i = 0; i < extensions.size() && !done; ++i) {
|
||||
String8 ext2 = extensions[i].getPathExtension();
|
||||
ext2.toLower();
|
||||
// Compare the extensions. If a match is found, add to storage.
|
||||
if (ext == ext2) {
|
||||
done = true;
|
||||
fileStore.add(path,stats->st_mtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
|
||||
// File Finder.
|
||||
// This is a collection of useful functions for finding paths and modification
|
||||
// times of files that match an extension pattern in a directory tree.
|
||||
// and finding files in it.
|
||||
|
||||
#ifndef FILEFINDER_H
|
||||
#define FILEFINDER_H
|
||||
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include "DirectoryWalker.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
// Abstraction to allow for dependency injection. See MockFileFinder.h
|
||||
// for the testing implementation.
|
||||
class FileFinder {
|
||||
public:
|
||||
virtual bool findFiles(String8 basePath, Vector<String8>& extensions,
|
||||
KeyedVector<String8,time_t>& fileStore,
|
||||
DirectoryWalker* dw) = 0;
|
||||
|
||||
virtual ~FileFinder() {};
|
||||
};
|
||||
|
||||
class SystemFileFinder : public FileFinder {
|
||||
public:
|
||||
|
||||
/* findFiles takes a path, a Vector of extensions, and a destination KeyedVector
|
||||
* and places path/modification date key/values pointing to
|
||||
* all files with matching extensions found into the KeyedVector
|
||||
* PRECONDITIONS
|
||||
* path is a valid system path
|
||||
* extensions should include leading "."
|
||||
* This is not necessary, but the comparison directly
|
||||
* compares the end of the path string so if the "."
|
||||
* is excluded there is a small chance you could have
|
||||
* a false positive match. (For example: extension "png"
|
||||
* would match a file called "blahblahpng")
|
||||
*
|
||||
* POSTCONDITIONS
|
||||
* fileStore contains (in no guaranteed order) paths to all
|
||||
* matching files encountered in subdirectories of path
|
||||
* as keys in the KeyedVector. Each key has the modification time
|
||||
* of the file as its value.
|
||||
*
|
||||
* Calls checkAndAddFile on each file encountered in the directory tree
|
||||
* Recursively descends into subdirectories.
|
||||
*/
|
||||
virtual bool findFiles(String8 basePath, Vector<String8>& extensions,
|
||||
KeyedVector<String8,time_t>& fileStore,
|
||||
DirectoryWalker* dw);
|
||||
|
||||
private:
|
||||
/**
|
||||
* checkAndAddFile looks at a single file path and stat combo
|
||||
* to determine whether it is a matching file (by looking at
|
||||
* the extension)
|
||||
*
|
||||
* PRECONDITIONS
|
||||
* no setup is needed
|
||||
*
|
||||
* POSTCONDITIONS
|
||||
* If the given file has a matching extension then a new entry
|
||||
* is added to the KeyedVector with the path as the key and the modification
|
||||
* time as the value.
|
||||
*
|
||||
*/
|
||||
static void checkAndAddFile(String8 path, const struct stat* stats,
|
||||
Vector<String8>& extensions,
|
||||
KeyedVector<String8,time_t>& fileStore);
|
||||
|
||||
};
|
||||
#endif // FILEFINDER_H
|
||||
@@ -1,26 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
|
||||
#ifndef IMAGES_H
|
||||
#define IMAGES_H
|
||||
|
||||
#include "ResourceTable.h"
|
||||
#include "Bundle.h"
|
||||
|
||||
#include <utils/String8.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
using android::String8;
|
||||
|
||||
status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
|
||||
const sp<AaptFile>& file, String8* outNewLeafName);
|
||||
|
||||
status_t preProcessImageToCache(const Bundle* bundle, const String8& source, const String8& dest);
|
||||
|
||||
status_t postProcessImage(const sp<AaptAssets>& assets,
|
||||
ResourceTable* table, const sp<AaptFile>& file);
|
||||
|
||||
#endif
|
||||
@@ -1,655 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// Android Asset Packaging Tool main entry point.
|
||||
//
|
||||
#include "Main.h"
|
||||
#include "Bundle.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
static const char* gProgName = "aapt";
|
||||
|
||||
/*
|
||||
* When running under Cygwin on Windows, this will convert slash-based
|
||||
* paths into back-slash-based ones. Otherwise the ApptAssets file comparisons
|
||||
* fail later as they use back-slash separators under Windows.
|
||||
*
|
||||
* This operates in-place on the path string.
|
||||
*/
|
||||
void convertPath(char *path) {
|
||||
if (path != NULL && OS_PATH_SEPARATOR != '/') {
|
||||
for (; *path; path++) {
|
||||
if (*path == '/') {
|
||||
*path = OS_PATH_SEPARATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print usage info.
|
||||
*/
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Android Asset Packaging Tool\n\n");
|
||||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr,
|
||||
" %s l[ist] [-v] [-a] file.{zip,jar,apk}\n"
|
||||
" List contents of Zip-compatible archive.\n\n", gProgName);
|
||||
fprintf(stderr,
|
||||
" %s d[ump] [--values] [--include-meta-data] WHAT file.{apk} [asset [asset ...]]\n"
|
||||
" strings Print the contents of the resource table string pool in the APK.\n"
|
||||
" badging Print the label and icon for the app declared in APK.\n"
|
||||
" permissions Print the permissions from the APK.\n"
|
||||
" resources Print the resource table from the APK.\n"
|
||||
" configurations Print the configurations in the APK.\n"
|
||||
" xmltree Print the compiled xmls in the given assets.\n"
|
||||
" xmlstrings Print the strings of the given compiled xml assets.\n\n", gProgName);
|
||||
fprintf(stderr,
|
||||
" %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n"
|
||||
" [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
|
||||
" [--debug-mode] [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
|
||||
" [--app-version VAL] [--app-version-name TEXT] [--custom-package VAL] \\\n"
|
||||
" [--rename-manifest-package PACKAGE] \\\n"
|
||||
" [--rename-instrumentation-target-package PACKAGE] \\\n"
|
||||
" [--utf16] [--auto-add-overlay] \\\n"
|
||||
" [--max-res-version VAL] \\\n"
|
||||
" [-I base-package [-I base-package ...]] \\\n"
|
||||
" [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n"
|
||||
" [-S resource-sources [-S resource-sources ...]] \\\n"
|
||||
" [-F apk-file] [-J R-file-dir] \\\n"
|
||||
" [--product product1,product2,...] \\\n"
|
||||
" [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
|
||||
" [raw-files-dir [raw-files-dir] ...] \\\n"
|
||||
" [--output-text-symbols DIR]\n"
|
||||
"\n"
|
||||
" Package the android resources. It will read assets and resources that are\n"
|
||||
" supplied with the -M -A -S or raw-files-dir arguments. The -J -P -F and -R\n"
|
||||
" options control which files are output.\n\n"
|
||||
, gProgName);
|
||||
fprintf(stderr,
|
||||
" %s r[emove] [-v] file.{zip,jar,apk} file1 [file2 ...]\n"
|
||||
" Delete specified files from Zip-compatible archive.\n\n",
|
||||
gProgName);
|
||||
fprintf(stderr,
|
||||
" %s a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...]\n"
|
||||
" Add specified files to Zip-compatible archive.\n\n", gProgName);
|
||||
fprintf(stderr,
|
||||
" %s c[runch] [-v] -S resource-sources ... -C output-folder ...\n"
|
||||
" Do PNG preprocessing on one or several resource folders\n"
|
||||
" and store the results in the output folder.\n\n", gProgName);
|
||||
fprintf(stderr,
|
||||
" %s s[ingleCrunch] [-v] -i input-file -o outputfile\n"
|
||||
" Do PNG preprocessing on a single file.\n\n", gProgName);
|
||||
fprintf(stderr,
|
||||
" %s v[ersion]\n"
|
||||
" Print program version.\n\n", gProgName);
|
||||
fprintf(stderr,
|
||||
" Modifiers:\n"
|
||||
" -a print Android-specific data (resources, manifest) when listing\n"
|
||||
" -c specify which configurations to include. The default is all\n"
|
||||
" configurations. The value of the parameter should be a comma\n"
|
||||
" separated list of configuration values. Locales should be specified\n"
|
||||
" as either a language or language-region pair. Some examples:\n"
|
||||
" en\n"
|
||||
" port,en\n"
|
||||
" port,land,en_US\n"
|
||||
" If you put the special locale, zz_ZZ on the list, it will perform\n"
|
||||
" pseudolocalization on the default locale, modifying all of the\n"
|
||||
" strings so you can look for strings that missed the\n"
|
||||
" internationalization process. For example:\n"
|
||||
" port,land,zz_ZZ\n"
|
||||
" -d one or more device assets to include, separated by commas\n"
|
||||
" -f force overwrite of existing files\n"
|
||||
" -g specify a pixel tolerance to force images to grayscale, default 0\n"
|
||||
" -j specify a jar or zip file containing classes to include\n"
|
||||
" -k junk path of file(s) added\n"
|
||||
" -m make package directories under location specified by -J\n"
|
||||
#if 0
|
||||
" -p pseudolocalize the default configuration\n"
|
||||
#endif
|
||||
" -u update existing packages (add new, replace older, remove deleted files)\n"
|
||||
" -v verbose output\n"
|
||||
" -x create extending (non-application) resource IDs\n"
|
||||
" -z require localization of resource attributes marked with\n"
|
||||
" localization=\"suggested\"\n"
|
||||
" -A additional directory in which to find raw asset files\n"
|
||||
" -G A file to output proguard options into.\n"
|
||||
" -F specify the apk file to output\n"
|
||||
" -I add an existing package to base include set\n"
|
||||
" -J specify where to output R.java resource constant definitions\n"
|
||||
" -M specify full path to AndroidManifest.xml to include in zip\n"
|
||||
" -P specify where to output public resource definitions\n"
|
||||
" -S directory in which to find resources. Multiple directories will be scanned\n"
|
||||
" and the first match found (left to right) will take precedence.\n"
|
||||
" -0 specifies an additional extension for which such files will not\n"
|
||||
" be stored compressed in the .apk. An empty string means to not\n"
|
||||
" compress any files at all.\n"
|
||||
" --debug-mode\n"
|
||||
" inserts android:debuggable=\"true\" in to the application node of the\n"
|
||||
" manifest, making the application debuggable even on production devices.\n"
|
||||
" --include-meta-data\n"
|
||||
" when used with \"dump badging\" also includes meta-data tags.\n"
|
||||
" --min-sdk-version\n"
|
||||
" inserts android:minSdkVersion in to manifest. If the version is 7 or\n"
|
||||
" higher, the default encoding for resources will be in UTF-8.\n"
|
||||
" --target-sdk-version\n"
|
||||
" inserts android:targetSdkVersion in to manifest.\n"
|
||||
" --max-res-version\n"
|
||||
" ignores versioned resource directories above the given value.\n"
|
||||
" --values\n"
|
||||
" when used with \"dump resources\" also includes resource values.\n"
|
||||
" --version-code\n"
|
||||
" inserts android:versionCode in to manifest.\n"
|
||||
" --version-name\n"
|
||||
" inserts android:versionName in to manifest.\n"
|
||||
" --custom-package\n"
|
||||
" generates R.java into a different package.\n"
|
||||
" --extra-packages\n"
|
||||
" generate R.java for libraries. Separate libraries with ':'.\n"
|
||||
" --generate-dependencies\n"
|
||||
" generate dependency files in the same directories for R.java and resource package\n"
|
||||
" --auto-add-overlay\n"
|
||||
" Automatically add resources that are only in overlays.\n"
|
||||
" --preferred-configurations\n"
|
||||
" Like the -c option for filtering out unneeded configurations, but\n"
|
||||
" only expresses a preference. If there is no resource available with\n"
|
||||
" the preferred configuration then it will not be stripped.\n"
|
||||
" --rename-manifest-package\n"
|
||||
" Rewrite the manifest so that its package name is the package name\n"
|
||||
" given here. Relative class names (for example .Foo) will be\n"
|
||||
" changed to absolute names with the old package so that the code\n"
|
||||
" does not need to change.\n"
|
||||
" --rename-instrumentation-target-package\n"
|
||||
" Rewrite the manifest so that all of its instrumentation\n"
|
||||
" components target the given package. Useful when used in\n"
|
||||
" conjunction with --rename-manifest-package to fix tests against\n"
|
||||
" a package that has been renamed.\n"
|
||||
" --product\n"
|
||||
" Specifies which variant to choose for strings that have\n"
|
||||
" product variants\n"
|
||||
" --utf16\n"
|
||||
" changes default encoding for resources to UTF-16. Only useful when API\n"
|
||||
" level is set to 7 or higher where the default encoding is UTF-8.\n"
|
||||
" --non-constant-id\n"
|
||||
" Make the resources ID non constant. This is required to make an R java class\n"
|
||||
" that does not contain the final value but is used to make reusable compiled\n"
|
||||
" libraries that need to access resources.\n"
|
||||
" --error-on-failed-insert\n"
|
||||
" Forces aapt to return an error if it fails to insert values into the manifest\n"
|
||||
" with --debug-mode, --min-sdk-version, --target-sdk-version --version-code\n"
|
||||
" and --version-name.\n"
|
||||
" Insertion typically fails if the manifest already defines the attribute.\n"
|
||||
" --output-text-symbols\n"
|
||||
" Generates a text file containing the resource symbols of the R class in the\n"
|
||||
" specified folder.\n"
|
||||
" --ignore-assets\n"
|
||||
" Assets to be ignored. Default pattern is:\n"
|
||||
" %s\n",
|
||||
gDefaultIgnoreAssets);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch the command.
|
||||
*/
|
||||
int handleCommand(Bundle* bundle)
|
||||
{
|
||||
//printf("--- command %d (verbose=%d force=%d):\n",
|
||||
// bundle->getCommand(), bundle->getVerbose(), bundle->getForce());
|
||||
//for (int i = 0; i < bundle->getFileSpecCount(); i++)
|
||||
// printf(" %d: '%s'\n", i, bundle->getFileSpecEntry(i));
|
||||
|
||||
switch (bundle->getCommand()) {
|
||||
case kCommandVersion: return doVersion(bundle);
|
||||
case kCommandList: return doList(bundle);
|
||||
case kCommandDump: return doDump(bundle);
|
||||
case kCommandAdd: return doAdd(bundle);
|
||||
case kCommandRemove: return doRemove(bundle);
|
||||
case kCommandPackage: return doPackage(bundle);
|
||||
case kCommandCrunch: return doCrunch(bundle);
|
||||
case kCommandSingleCrunch: return doSingleCrunch(bundle);
|
||||
default:
|
||||
fprintf(stderr, "%s: requested command not yet supported\n", gProgName);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse args.
|
||||
*/
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
char *prog = argv[0];
|
||||
Bundle bundle;
|
||||
bool wantUsage = false;
|
||||
int result = 1; // pessimistically assume an error.
|
||||
int tolerance = 0;
|
||||
|
||||
/* default to compression */
|
||||
bundle.setCompressionMethod(ZipEntry::kCompressDeflated);
|
||||
|
||||
if (argc < 2) {
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (argv[1][0] == 'v')
|
||||
bundle.setCommand(kCommandVersion);
|
||||
else if (argv[1][0] == 'd')
|
||||
bundle.setCommand(kCommandDump);
|
||||
else if (argv[1][0] == 'l')
|
||||
bundle.setCommand(kCommandList);
|
||||
else if (argv[1][0] == 'a')
|
||||
bundle.setCommand(kCommandAdd);
|
||||
else if (argv[1][0] == 'r')
|
||||
bundle.setCommand(kCommandRemove);
|
||||
else if (argv[1][0] == 'p')
|
||||
bundle.setCommand(kCommandPackage);
|
||||
else if (argv[1][0] == 'c')
|
||||
bundle.setCommand(kCommandCrunch);
|
||||
else if (argv[1][0] == 's')
|
||||
bundle.setCommand(kCommandSingleCrunch);
|
||||
else {
|
||||
fprintf(stderr, "ERROR: Unknown command '%s'\n", argv[1]);
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
/*
|
||||
* Pull out flags. We support "-fv" and "-f -v".
|
||||
*/
|
||||
while (argc && argv[0][0] == '-') {
|
||||
/* flag(s) found */
|
||||
const char* cp = argv[0] +1;
|
||||
|
||||
while (*cp != '\0') {
|
||||
switch (*cp) {
|
||||
case 'v':
|
||||
bundle.setVerbose(true);
|
||||
break;
|
||||
case 'a':
|
||||
bundle.setAndroidList(true);
|
||||
break;
|
||||
case 'c':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-c' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.addConfigurations(argv[0]);
|
||||
break;
|
||||
case 'f':
|
||||
bundle.setForce(true);
|
||||
break;
|
||||
case 'g':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-g' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
tolerance = atoi(argv[0]);
|
||||
bundle.setGrayscaleTolerance(tolerance);
|
||||
printf("%s: Images with deviation <= %d will be forced to grayscale.\n", prog, tolerance);
|
||||
break;
|
||||
case 'k':
|
||||
bundle.setJunkPath(true);
|
||||
break;
|
||||
case 'm':
|
||||
bundle.setMakePackageDirs(true);
|
||||
break;
|
||||
#if 0
|
||||
case 'p':
|
||||
bundle.setPseudolocalize(true);
|
||||
break;
|
||||
#endif
|
||||
case 'u':
|
||||
bundle.setUpdate(true);
|
||||
break;
|
||||
case 'x':
|
||||
bundle.setExtending(true);
|
||||
break;
|
||||
case 'z':
|
||||
bundle.setRequireLocalization(true);
|
||||
break;
|
||||
case 'j':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-j' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.addJarFile(argv[0]);
|
||||
break;
|
||||
case 'A':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-A' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setAssetSourceDir(argv[0]);
|
||||
break;
|
||||
case 'G':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-G' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setProguardFile(argv[0]);
|
||||
break;
|
||||
case 'I':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-I' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.addPackageInclude(argv[0]);
|
||||
break;
|
||||
case 'F':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-F' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setOutputAPKFile(argv[0]);
|
||||
break;
|
||||
case 'J':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-J' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setRClassDir(argv[0]);
|
||||
break;
|
||||
case 'M':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-M' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setAndroidManifestFile(argv[0]);
|
||||
break;
|
||||
case 'P':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-P' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setPublicOutputFile(argv[0]);
|
||||
break;
|
||||
case 'S':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-S' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.addResourceSourceDir(argv[0]);
|
||||
break;
|
||||
case 'C':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-C' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setCrunchedOutputDir(argv[0]);
|
||||
break;
|
||||
case 'i':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-i' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setSingleCrunchInputFile(argv[0]);
|
||||
break;
|
||||
case 'o':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-o' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
convertPath(argv[0]);
|
||||
bundle.setSingleCrunchOutputFile(argv[0]);
|
||||
break;
|
||||
case '0':
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-e' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
if (argv[0][0] != 0) {
|
||||
bundle.addNoCompressExtension(argv[0]);
|
||||
} else {
|
||||
bundle.setCompressionMethod(ZipEntry::kCompressStored);
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (strcmp(cp, "-debug-mode") == 0) {
|
||||
bundle.setDebugMode(true);
|
||||
} else if (strcmp(cp, "-min-sdk-version") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--min-sdk-version' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setMinSdkVersion(argv[0]);
|
||||
} else if (strcmp(cp, "-target-sdk-version") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--target-sdk-version' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setTargetSdkVersion(argv[0]);
|
||||
} else if (strcmp(cp, "-max-sdk-version") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--max-sdk-version' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setMaxSdkVersion(argv[0]);
|
||||
} else if (strcmp(cp, "-max-res-version") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--max-res-version' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setMaxResVersion(argv[0]);
|
||||
} else if (strcmp(cp, "-version-code") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--version-code' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setVersionCode(argv[0]);
|
||||
} else if (strcmp(cp, "-version-name") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--version-name' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setVersionName(argv[0]);
|
||||
} else if (strcmp(cp, "-values") == 0) {
|
||||
bundle.setValues(true);
|
||||
} else if (strcmp(cp, "-include-meta-data") == 0) {
|
||||
bundle.setIncludeMetaData(true);
|
||||
} else if (strcmp(cp, "-custom-package") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--custom-package' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setCustomPackage(argv[0]);
|
||||
} else if (strcmp(cp, "-extra-packages") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--extra-packages' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setExtraPackages(argv[0]);
|
||||
} else if (strcmp(cp, "-generate-dependencies") == 0) {
|
||||
bundle.setGenDependencies(true);
|
||||
} else if (strcmp(cp, "-utf16") == 0) {
|
||||
bundle.setWantUTF16(true);
|
||||
} else if (strcmp(cp, "-preferred-configurations") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--preferred-configurations' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.addPreferredConfigurations(argv[0]);
|
||||
} else if (strcmp(cp, "-rename-manifest-package") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--rename-manifest-package' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setManifestPackageNameOverride(argv[0]);
|
||||
} else if (strcmp(cp, "-rename-instrumentation-target-package") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--rename-instrumentation-target-package' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setInstrumentationPackageNameOverride(argv[0]);
|
||||
} else if (strcmp(cp, "-auto-add-overlay") == 0) {
|
||||
bundle.setAutoAddOverlay(true);
|
||||
} else if (strcmp(cp, "-error-on-failed-insert") == 0) {
|
||||
bundle.setErrorOnFailedInsert(true);
|
||||
} else if (strcmp(cp, "-output-text-symbols") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '-output-text-symbols' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setOutputTextSymbols(argv[0]);
|
||||
} else if (strcmp(cp, "-product") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--product' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
bundle.setProduct(argv[0]);
|
||||
} else if (strcmp(cp, "-non-constant-id") == 0) {
|
||||
bundle.setNonConstantId(true);
|
||||
} else if (strcmp(cp, "-no-crunch") == 0) {
|
||||
bundle.setUseCrunchCache(true);
|
||||
} else if (strcmp(cp, "-ignore-assets") == 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!argc) {
|
||||
fprintf(stderr, "ERROR: No argument supplied for '--ignore-assets' option\n");
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
gUserIgnoreAssets = argv[0];
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
cp += strlen(cp) - 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "ERROR: Unknown flag '-%c'\n", *cp);
|
||||
wantUsage = true;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
cp++;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
/*
|
||||
* We're past the flags. The rest all goes straight in.
|
||||
*/
|
||||
bundle.setFileSpec(argv, argc);
|
||||
|
||||
result = handleCommand(&bundle);
|
||||
|
||||
bail:
|
||||
if (wantUsage) {
|
||||
usage();
|
||||
result = 2;
|
||||
}
|
||||
|
||||
//printf("--> returning %d\n", result);
|
||||
return result;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// Some global defines that don't really merit their own header.
|
||||
//
|
||||
#ifndef __MAIN_H
|
||||
#define __MAIN_H
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/Errors.h>
|
||||
#include "Bundle.h"
|
||||
#include "AaptAssets.h"
|
||||
#include "ZipFile.h"
|
||||
|
||||
|
||||
/* Benchmarking Flag */
|
||||
//#define BENCHMARK 1
|
||||
|
||||
#if BENCHMARK
|
||||
#include <time.h>
|
||||
#endif /* BENCHMARK */
|
||||
|
||||
extern int doVersion(Bundle* bundle);
|
||||
extern int doList(Bundle* bundle);
|
||||
extern int doDump(Bundle* bundle);
|
||||
extern int doAdd(Bundle* bundle);
|
||||
extern int doRemove(Bundle* bundle);
|
||||
extern int doPackage(Bundle* bundle);
|
||||
extern int doCrunch(Bundle* bundle);
|
||||
extern int doSingleCrunch(Bundle* bundle);
|
||||
|
||||
extern int calcPercent(long uncompressedLen, long compressedLen);
|
||||
|
||||
extern android::status_t writeAPK(Bundle* bundle,
|
||||
const sp<AaptAssets>& assets,
|
||||
const android::String8& outputFile);
|
||||
|
||||
extern android::status_t updatePreProcessedCache(Bundle* bundle);
|
||||
|
||||
extern android::status_t buildResources(Bundle* bundle,
|
||||
const sp<AaptAssets>& assets);
|
||||
|
||||
extern android::status_t writeResourceSymbols(Bundle* bundle,
|
||||
const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate);
|
||||
|
||||
extern android::status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets);
|
||||
|
||||
extern bool isValidResourceType(const String8& type);
|
||||
|
||||
ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
|
||||
|
||||
extern status_t filterResources(Bundle* bundle, const sp<AaptAssets>& assets);
|
||||
|
||||
int dumpResources(Bundle* bundle);
|
||||
|
||||
String8 getAttribute(const ResXMLTree& tree, const char* ns,
|
||||
const char* attr, String8* outError);
|
||||
|
||||
status_t writeDependencyPreReqs(Bundle* bundle, const sp<AaptAssets>& assets,
|
||||
FILE* fp, bool includeRaw);
|
||||
#endif // __MAIN_H
|
||||
@@ -1,190 +0,0 @@
|
||||
|
||||
Copyright (c) 2005-2008, The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
@@ -1,505 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// Package assets into Zip files.
|
||||
//
|
||||
#include "Main.h"
|
||||
#include "AaptAssets.h"
|
||||
#include "ResourceTable.h"
|
||||
#include "ResourceFilter.h"
|
||||
|
||||
#include <androidfw/misc.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/misc.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
static const char* kExcludeExtension = ".EXCLUDE";
|
||||
|
||||
/* these formats are already compressed, or don't compress well */
|
||||
static const char* kNoCompressExt[] = {
|
||||
".jpg", ".jpeg", ".png", ".gif",
|
||||
".wav", ".mp2", ".mp3", ".ogg", ".aac",
|
||||
".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
|
||||
".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
|
||||
".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
|
||||
".amr", ".awb", ".wma", ".wmv"
|
||||
};
|
||||
|
||||
/* fwd decls, so I can write this downward */
|
||||
ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
|
||||
ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
|
||||
const AaptGroupEntry& ge, const ResourceFilter* filter);
|
||||
bool processFile(Bundle* bundle, ZipFile* zip,
|
||||
const sp<AaptGroup>& group, const sp<AaptFile>& file);
|
||||
bool okayToCompress(Bundle* bundle, const String8& pathName);
|
||||
ssize_t processJarFiles(Bundle* bundle, ZipFile* zip);
|
||||
|
||||
/*
|
||||
* The directory hierarchy looks like this:
|
||||
* "outputDir" and "assetRoot" are existing directories.
|
||||
*
|
||||
* On success, "bundle->numPackages" will be the number of Zip packages
|
||||
* we created.
|
||||
*/
|
||||
status_t writeAPK(Bundle* bundle, const sp<AaptAssets>& assets,
|
||||
const String8& outputFile)
|
||||
{
|
||||
#if BENCHMARK
|
||||
fprintf(stdout, "BENCHMARK: Starting APK Bundling \n");
|
||||
long startAPKTime = clock();
|
||||
#endif /* BENCHMARK */
|
||||
|
||||
status_t result = NO_ERROR;
|
||||
ZipFile* zip = NULL;
|
||||
int count;
|
||||
|
||||
//bundle->setPackageCount(0);
|
||||
|
||||
/*
|
||||
* Prep the Zip archive.
|
||||
*
|
||||
* If the file already exists, fail unless "update" or "force" is set.
|
||||
* If "update" is set, update the contents of the existing archive.
|
||||
* Else, if "force" is set, remove the existing archive.
|
||||
*/
|
||||
FileType fileType = getFileType(outputFile.string());
|
||||
if (fileType == kFileTypeNonexistent) {
|
||||
// okay, create it below
|
||||
} else if (fileType == kFileTypeRegular) {
|
||||
if (bundle->getUpdate()) {
|
||||
// okay, open it below
|
||||
} else if (bundle->getForce()) {
|
||||
if (unlink(outputFile.string()) != 0) {
|
||||
fprintf(stderr, "ERROR: unable to remove '%s': %s\n", outputFile.string(),
|
||||
strerror(errno));
|
||||
goto bail;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: '%s' exists (use '-f' to force overwrite)\n",
|
||||
outputFile.string());
|
||||
goto bail;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: '%s' exists and is not a regular file\n", outputFile.string());
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (bundle->getVerbose()) {
|
||||
printf("%s '%s'\n", (fileType == kFileTypeNonexistent) ? "Creating" : "Opening",
|
||||
outputFile.string());
|
||||
}
|
||||
|
||||
status_t status;
|
||||
zip = new ZipFile;
|
||||
status = zip->open(outputFile.string(), ZipFile::kOpenReadWrite | ZipFile::kOpenCreate);
|
||||
if (status != NO_ERROR) {
|
||||
fprintf(stderr, "ERROR: unable to open '%s' as Zip file for writing\n",
|
||||
outputFile.string());
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (bundle->getVerbose()) {
|
||||
printf("Writing all files...\n");
|
||||
}
|
||||
|
||||
count = processAssets(bundle, zip, assets);
|
||||
if (count < 0) {
|
||||
fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
|
||||
outputFile.string());
|
||||
result = count;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (bundle->getVerbose()) {
|
||||
printf("Generated %d file%s\n", count, (count==1) ? "" : "s");
|
||||
}
|
||||
|
||||
count = processJarFiles(bundle, zip);
|
||||
if (count < 0) {
|
||||
fprintf(stderr, "ERROR: unable to process jar files while packaging '%s'\n",
|
||||
outputFile.string());
|
||||
result = count;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (bundle->getVerbose())
|
||||
printf("Included %d file%s from jar/zip files.\n", count, (count==1) ? "" : "s");
|
||||
|
||||
result = NO_ERROR;
|
||||
|
||||
/*
|
||||
* Check for cruft. We set the "marked" flag on all entries we created
|
||||
* or decided not to update. If the entry isn't already slated for
|
||||
* deletion, remove it now.
|
||||
*/
|
||||
{
|
||||
if (bundle->getVerbose())
|
||||
printf("Checking for deleted files\n");
|
||||
int i, removed = 0;
|
||||
for (i = 0; i < zip->getNumEntries(); i++) {
|
||||
ZipEntry* entry = zip->getEntryByIndex(i);
|
||||
|
||||
if (!entry->getMarked() && entry->getDeleted()) {
|
||||
if (bundle->getVerbose()) {
|
||||
printf(" (removing crufty '%s')\n",
|
||||
entry->getFileName());
|
||||
}
|
||||
zip->remove(entry);
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
if (bundle->getVerbose() && removed > 0)
|
||||
printf("Removed %d file%s\n", removed, (removed==1) ? "" : "s");
|
||||
}
|
||||
|
||||
/* tell Zip lib to process deletions and other pending changes */
|
||||
result = zip->flush();
|
||||
if (result != NO_ERROR) {
|
||||
fprintf(stderr, "ERROR: Zip flush failed, archive may be hosed\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* anything here? */
|
||||
if (zip->getNumEntries() == 0) {
|
||||
if (bundle->getVerbose()) {
|
||||
printf("Archive is empty -- removing %s\n", outputFile.getPathLeaf().string());
|
||||
}
|
||||
delete zip; // close the file so we can remove it in Win32
|
||||
zip = NULL;
|
||||
if (unlink(outputFile.string()) != 0) {
|
||||
fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
|
||||
}
|
||||
}
|
||||
|
||||
// If we've been asked to generate a dependency file for the .ap_ package,
|
||||
// do so here
|
||||
if (bundle->getGenDependencies()) {
|
||||
// The dependency file gets output to the same directory
|
||||
// as the specified output file with an additional .d extension.
|
||||
// e.g. bin/resources.ap_.d
|
||||
String8 dependencyFile = outputFile;
|
||||
dependencyFile.append(".d");
|
||||
|
||||
FILE* fp = fopen(dependencyFile.string(), "a");
|
||||
// Add this file to the dependency file
|
||||
fprintf(fp, "%s \\\n", outputFile.string());
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
assert(result == NO_ERROR);
|
||||
|
||||
bail:
|
||||
delete zip; // must close before remove in Win32
|
||||
if (result != NO_ERROR) {
|
||||
if (bundle->getVerbose()) {
|
||||
printf("Removing %s due to earlier failures\n", outputFile.string());
|
||||
}
|
||||
if (unlink(outputFile.string()) != 0) {
|
||||
fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
|
||||
}
|
||||
}
|
||||
|
||||
if (result == NO_ERROR && bundle->getVerbose())
|
||||
printf("Done!\n");
|
||||
|
||||
#if BENCHMARK
|
||||
fprintf(stdout, "BENCHMARK: End APK Bundling. Time Elapsed: %f ms \n",(clock() - startAPKTime)/1000.0);
|
||||
#endif /* BENCHMARK */
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t processAssets(Bundle* bundle, ZipFile* zip,
|
||||
const sp<AaptAssets>& assets)
|
||||
{
|
||||
ResourceFilter filter;
|
||||
status_t status = filter.parse(bundle->getConfigurations());
|
||||
if (status != NO_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t count = 0;
|
||||
|
||||
const size_t N = assets->getGroupEntries().size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
const AaptGroupEntry& ge = assets->getGroupEntries()[i];
|
||||
|
||||
ssize_t res = processAssets(bundle, zip, assets, ge, &filter);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
count += res;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
|
||||
const AaptGroupEntry& ge, const ResourceFilter* filter)
|
||||
{
|
||||
ssize_t count = 0;
|
||||
|
||||
const size_t ND = dir->getDirs().size();
|
||||
size_t i;
|
||||
for (i=0; i<ND; i++) {
|
||||
const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
|
||||
|
||||
const bool filterable = filter != NULL && subDir->getLeaf().find("mipmap-") != 0;
|
||||
|
||||
if (filterable && subDir->getLeaf() != subDir->getPath() && !filter->match(ge.toParams())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ssize_t res = processAssets(bundle, zip, subDir, ge, filterable ? filter : NULL);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
count += res;
|
||||
}
|
||||
|
||||
if (filter != NULL && !filter->match(ge.toParams())) {
|
||||
return count;
|
||||
}
|
||||
|
||||
const size_t NF = dir->getFiles().size();
|
||||
for (i=0; i<NF; i++) {
|
||||
sp<AaptGroup> gp = dir->getFiles().valueAt(i);
|
||||
ssize_t fi = gp->getFiles().indexOfKey(ge);
|
||||
if (fi >= 0) {
|
||||
sp<AaptFile> fl = gp->getFiles().valueAt(fi);
|
||||
if (!processFile(bundle, zip, gp, fl)) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a regular file, adding it to the archive if appropriate.
|
||||
*
|
||||
* If we're in "update" mode, and the file already exists in the archive,
|
||||
* delete the existing entry before adding the new one.
|
||||
*/
|
||||
bool processFile(Bundle* bundle, ZipFile* zip,
|
||||
const sp<AaptGroup>& group, const sp<AaptFile>& file)
|
||||
{
|
||||
const bool hasData = file->hasData();
|
||||
|
||||
String8 storageName(group->getPath());
|
||||
storageName.convertToResPath();
|
||||
ZipEntry* entry;
|
||||
bool fromGzip = false;
|
||||
status_t result;
|
||||
|
||||
/*
|
||||
* See if the filename ends in ".EXCLUDE". We can't use
|
||||
* String8::getPathExtension() because the length of what it considers
|
||||
* to be an extension is capped.
|
||||
*
|
||||
* The Asset Manager doesn't check for ".EXCLUDE" in Zip archives,
|
||||
* so there's no value in adding them (and it makes life easier on
|
||||
* the AssetManager lib if we don't).
|
||||
*
|
||||
* NOTE: this restriction has been removed. If you're in this code, you
|
||||
* should clean this up, but I'm in here getting rid of Path Name, and I
|
||||
* don't want to make other potentially breaking changes --joeo
|
||||
*/
|
||||
int fileNameLen = storageName.length();
|
||||
int excludeExtensionLen = strlen(kExcludeExtension);
|
||||
if (fileNameLen > excludeExtensionLen
|
||||
&& (0 == strcmp(storageName.string() + (fileNameLen - excludeExtensionLen),
|
||||
kExcludeExtension))) {
|
||||
fprintf(stderr, "warning: '%s' not added to Zip\n", storageName.string());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(storageName.getPathExtension().string(), ".gz") == 0) {
|
||||
fromGzip = true;
|
||||
storageName = storageName.getBasePath();
|
||||
}
|
||||
|
||||
if (bundle->getUpdate()) {
|
||||
entry = zip->getEntryByName(storageName.string());
|
||||
if (entry != NULL) {
|
||||
/* file already exists in archive; there can be only one */
|
||||
if (entry->getMarked()) {
|
||||
fprintf(stderr,
|
||||
"ERROR: '%s' exists twice (check for with & w/o '.gz'?)\n",
|
||||
file->getPrintableSource().string());
|
||||
return false;
|
||||
}
|
||||
if (!hasData) {
|
||||
const String8& srcName = file->getSourceFile();
|
||||
time_t fileModWhen;
|
||||
fileModWhen = getFileModDate(srcName.string());
|
||||
if (fileModWhen == (time_t) -1) { // file existence tested earlier,
|
||||
return false; // not expecting an error here
|
||||
}
|
||||
|
||||
if (fileModWhen > entry->getModWhen()) {
|
||||
// mark as deleted so add() will succeed
|
||||
if (bundle->getVerbose()) {
|
||||
printf(" (removing old '%s')\n", storageName.string());
|
||||
}
|
||||
|
||||
zip->remove(entry);
|
||||
} else {
|
||||
// version in archive is newer
|
||||
if (bundle->getVerbose()) {
|
||||
printf(" (not updating '%s')\n", storageName.string());
|
||||
}
|
||||
entry->setMarked(true);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Generated files are always replaced.
|
||||
zip->remove(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//android_setMinPriority(NULL, ANDROID_LOG_VERBOSE);
|
||||
|
||||
if (fromGzip) {
|
||||
result = zip->addGzip(file->getSourceFile().string(), storageName.string(), &entry);
|
||||
} else if (!hasData) {
|
||||
/* don't compress certain files, e.g. PNGs */
|
||||
int compressionMethod = bundle->getCompressionMethod();
|
||||
if (!okayToCompress(bundle, storageName)) {
|
||||
compressionMethod = ZipEntry::kCompressStored;
|
||||
}
|
||||
result = zip->add(file->getSourceFile().string(), storageName.string(), compressionMethod,
|
||||
&entry);
|
||||
} else {
|
||||
result = zip->add(file->getData(), file->getSize(), storageName.string(),
|
||||
file->getCompressionMethod(), &entry);
|
||||
}
|
||||
if (result == NO_ERROR) {
|
||||
if (bundle->getVerbose()) {
|
||||
printf(" '%s'%s", storageName.string(), fromGzip ? " (from .gz)" : "");
|
||||
if (entry->getCompressionMethod() == ZipEntry::kCompressStored) {
|
||||
printf(" (not compressed)\n");
|
||||
} else {
|
||||
printf(" (compressed %d%%)\n", calcPercent(entry->getUncompressedLen(),
|
||||
entry->getCompressedLen()));
|
||||
}
|
||||
}
|
||||
entry->setMarked(true);
|
||||
} else {
|
||||
if (result == ALREADY_EXISTS) {
|
||||
fprintf(stderr, " Unable to add '%s': file already in archive (try '-u'?)\n",
|
||||
file->getPrintableSource().string());
|
||||
} else {
|
||||
fprintf(stderr, " Unable to add '%s': Zip add failed\n",
|
||||
file->getPrintableSource().string());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether or not we want to try to compress this file based
|
||||
* on the file extension.
|
||||
*/
|
||||
bool okayToCompress(Bundle* bundle, const String8& pathName)
|
||||
{
|
||||
String8 ext = pathName.getPathExtension();
|
||||
int i;
|
||||
|
||||
if (ext.length() == 0)
|
||||
return true;
|
||||
|
||||
for (i = 0; i < NELEM(kNoCompressExt); i++) {
|
||||
if (strcasecmp(ext.string(), kNoCompressExt[i]) == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
const android::Vector<const char*>& others(bundle->getNoCompressExtensions());
|
||||
for (i = 0; i < (int)others.size(); i++) {
|
||||
const char* str = others[i];
|
||||
int pos = pathName.length() - strlen(str);
|
||||
if (pos < 0) {
|
||||
continue;
|
||||
}
|
||||
const char* path = pathName.string();
|
||||
if (strcasecmp(path + pos, str) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool endsWith(const char* haystack, const char* needle)
|
||||
{
|
||||
size_t a = strlen(haystack);
|
||||
size_t b = strlen(needle);
|
||||
if (a < b) return false;
|
||||
return strcasecmp(haystack+(a-b), needle) == 0;
|
||||
}
|
||||
|
||||
ssize_t processJarFile(ZipFile* jar, ZipFile* out)
|
||||
{
|
||||
status_t err;
|
||||
size_t N = jar->getNumEntries();
|
||||
size_t count = 0;
|
||||
for (size_t i=0; i<N; i++) {
|
||||
ZipEntry* entry = jar->getEntryByIndex(i);
|
||||
const char* storageName = entry->getFileName();
|
||||
if (endsWith(storageName, ".class")) {
|
||||
int compressionMethod = entry->getCompressionMethod();
|
||||
size_t size = entry->getUncompressedLen();
|
||||
const void* data = jar->uncompress(entry);
|
||||
if (data == NULL) {
|
||||
fprintf(stderr, "ERROR: unable to uncompress entry '%s'\n",
|
||||
storageName);
|
||||
return -1;
|
||||
}
|
||||
out->add(data, size, storageName, compressionMethod, NULL);
|
||||
free((void*)data);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t processJarFiles(Bundle* bundle, ZipFile* zip)
|
||||
{
|
||||
status_t err;
|
||||
ssize_t count = 0;
|
||||
const android::Vector<const char*>& jars = bundle->getJarFiles();
|
||||
|
||||
size_t N = jars.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
ZipFile jar;
|
||||
err = jar.open(jars[i], ZipFile::kOpenReadOnly);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ERROR: unable to open '%s' as a zip file: %d\n",
|
||||
jars[i], err);
|
||||
return err;
|
||||
}
|
||||
err += processJarFile(&jar, zip);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "ERROR: unable to process '%s'\n", jars[i]);
|
||||
return err;
|
||||
}
|
||||
count += err;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
|
||||
#include "ResourceFilter.h"
|
||||
|
||||
status_t
|
||||
ResourceFilter::parse(const char* arg)
|
||||
{
|
||||
if (arg == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* p = arg;
|
||||
const char* q;
|
||||
|
||||
while (true) {
|
||||
q = strchr(p, ',');
|
||||
if (q == NULL) {
|
||||
q = p + strlen(p);
|
||||
}
|
||||
|
||||
String8 part(p, q-p);
|
||||
|
||||
if (part == "zz_ZZ") {
|
||||
mContainsPseudo = true;
|
||||
}
|
||||
int axis;
|
||||
uint32_t value;
|
||||
if (AaptGroupEntry::parseNamePart(part, &axis, &value)) {
|
||||
fprintf(stderr, "Invalid configuration: %s\n", arg);
|
||||
fprintf(stderr, " ");
|
||||
for (int i=0; i<p-arg; i++) {
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
for (int i=0; i<q-p; i++) {
|
||||
fprintf(stderr, "^");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssize_t index = mData.indexOfKey(axis);
|
||||
if (index < 0) {
|
||||
mData.add(axis, SortedVector<uint32_t>());
|
||||
}
|
||||
SortedVector<uint32_t>& sv = mData.editValueFor(axis);
|
||||
sv.add(value);
|
||||
// if it's a locale with a region, also match an unmodified locale of the
|
||||
// same language
|
||||
if (axis == AXIS_LANGUAGE) {
|
||||
if (value & 0xffff0000) {
|
||||
sv.add(value & 0x0000ffff);
|
||||
}
|
||||
}
|
||||
p = q;
|
||||
if (!*p) break;
|
||||
p++;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::isEmpty() const
|
||||
{
|
||||
return mData.size() == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::match(int axis, uint32_t value) const
|
||||
{
|
||||
if (value == 0) {
|
||||
// they didn't specify anything so take everything
|
||||
return true;
|
||||
}
|
||||
ssize_t index = mData.indexOfKey(axis);
|
||||
if (index < 0) {
|
||||
// we didn't request anything on this axis so take everything
|
||||
return true;
|
||||
}
|
||||
const SortedVector<uint32_t>& sv = mData.valueAt(index);
|
||||
return sv.indexOf(value) >= 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::match(int axis, const ResTable_config& config) const
|
||||
{
|
||||
return match(axis, AaptGroupEntry::getConfigValueForAxis(config, axis));
|
||||
}
|
||||
|
||||
bool
|
||||
ResourceFilter::match(const ResTable_config& config) const
|
||||
{
|
||||
for (int i=AXIS_START; i<=AXIS_END; i++) {
|
||||
if (!match(i, AaptGroupEntry::getConfigValueForAxis(config, i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const SortedVector<uint32_t>* ResourceFilter::configsForAxis(int axis) const
|
||||
{
|
||||
ssize_t index = mData.indexOfKey(axis);
|
||||
if (index < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return &mData.valueAt(index);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
|
||||
#ifndef RESOURCE_FILTER_H
|
||||
#define RESOURCE_FILTER_H
|
||||
|
||||
#include "AaptAssets.h"
|
||||
|
||||
/**
|
||||
* Implements logic for parsing and handling "-c" and "--preferred-configurations"
|
||||
* options.
|
||||
*/
|
||||
class ResourceFilter
|
||||
{
|
||||
public:
|
||||
ResourceFilter() : mData(), mContainsPseudo(false) {}
|
||||
status_t parse(const char* arg);
|
||||
bool isEmpty() const;
|
||||
bool match(int axis, uint32_t value) const;
|
||||
bool match(int axis, const ResTable_config& config) const;
|
||||
bool match(const ResTable_config& config) const;
|
||||
const SortedVector<uint32_t>* configsForAxis(int axis) const;
|
||||
inline bool containsPseudo() const { return mContainsPseudo; }
|
||||
|
||||
private:
|
||||
KeyedVector<int,SortedVector<uint32_t> > mData;
|
||||
bool mContainsPseudo;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,107 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 The Android Open Source Project
|
||||
//
|
||||
// Manage a resource ID cache.
|
||||
|
||||
#define LOG_TAG "ResourceIdCache"
|
||||
|
||||
#include <utils/String16.h>
|
||||
#include <utils/Log.h>
|
||||
#include "ResourceIdCache.h"
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
|
||||
static size_t mHits = 0;
|
||||
static size_t mMisses = 0;
|
||||
static size_t mCollisions = 0;
|
||||
|
||||
static const size_t MAX_CACHE_ENTRIES = 2048;
|
||||
static const android::String16 TRUE16("1");
|
||||
static const android::String16 FALSE16("0");
|
||||
|
||||
struct CacheEntry {
|
||||
// concatenation of the relevant strings into a single instance
|
||||
android::String16 hashedName;
|
||||
uint32_t id;
|
||||
|
||||
CacheEntry() {}
|
||||
CacheEntry(const android::String16& name, uint32_t resId) : hashedName(name), id(resId) { }
|
||||
};
|
||||
|
||||
static map< uint32_t, CacheEntry > mIdMap;
|
||||
|
||||
|
||||
// djb2; reasonable choice for strings when collisions aren't particularly important
|
||||
static inline uint32_t hashround(uint32_t hash, int c) {
|
||||
return ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
}
|
||||
|
||||
static uint32_t hash(const android::String16& hashableString) {
|
||||
uint32_t hash = 5381;
|
||||
const char16_t* str = hashableString.string();
|
||||
while (int c = *str++) hash = hashround(hash, c);
|
||||
return hash;
|
||||
}
|
||||
|
||||
namespace android {
|
||||
|
||||
static inline String16 makeHashableName(const android::String16& package,
|
||||
const android::String16& type,
|
||||
const android::String16& name,
|
||||
bool onlyPublic) {
|
||||
String16 hashable = String16(name);
|
||||
hashable += type;
|
||||
hashable += package;
|
||||
hashable += (onlyPublic ? TRUE16 : FALSE16);
|
||||
return hashable;
|
||||
}
|
||||
|
||||
uint32_t ResourceIdCache::lookup(const android::String16& package,
|
||||
const android::String16& type,
|
||||
const android::String16& name,
|
||||
bool onlyPublic) {
|
||||
const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
|
||||
const uint32_t hashcode = hash(hashedName);
|
||||
map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
|
||||
if (item == mIdMap.end()) {
|
||||
// cache miss
|
||||
mMisses++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// legit match?
|
||||
if (hashedName == (*item).second.hashedName) {
|
||||
mHits++;
|
||||
return (*item).second.id;
|
||||
}
|
||||
|
||||
// collision
|
||||
mCollisions++;
|
||||
mIdMap.erase(hashcode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns the resource ID being stored, for callsite convenience
|
||||
uint32_t ResourceIdCache::store(const android::String16& package,
|
||||
const android::String16& type,
|
||||
const android::String16& name,
|
||||
bool onlyPublic,
|
||||
uint32_t resId) {
|
||||
if (mIdMap.size() < MAX_CACHE_ENTRIES) {
|
||||
const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
|
||||
const uint32_t hashcode = hash(hashedName);
|
||||
mIdMap[hashcode] = CacheEntry(hashedName, resId);
|
||||
}
|
||||
return resId;
|
||||
}
|
||||
|
||||
void ResourceIdCache::dump() {
|
||||
printf("ResourceIdCache dump:\n");
|
||||
printf("Size: %ld\n", mIdMap.size());
|
||||
printf("Hits: %ld\n", mHits);
|
||||
printf("Misses: %ld\n", mMisses);
|
||||
printf("(Collisions: %ld)\n", mCollisions);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// Copyright 2012 The Android Open Source Project
|
||||
//
|
||||
// Manage a resource ID cache.
|
||||
|
||||
#ifndef RESOURCE_ID_CACHE_H
|
||||
#define RESOURCE_ID_CACHE_H
|
||||
|
||||
namespace android {
|
||||
class android::String16;
|
||||
|
||||
class ResourceIdCache {
|
||||
public:
|
||||
static uint32_t lookup(const android::String16& package,
|
||||
const android::String16& type,
|
||||
const android::String16& name,
|
||||
bool onlyPublic);
|
||||
|
||||
static uint32_t store(const android::String16& package,
|
||||
const android::String16& type,
|
||||
const android::String16& name,
|
||||
bool onlyPublic,
|
||||
uint32_t resId);
|
||||
|
||||
static void dump(void);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,557 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
|
||||
#ifndef RESOURCE_TABLE_H
|
||||
#define RESOURCE_TABLE_H
|
||||
|
||||
#include "StringPool.h"
|
||||
#include "SourcePos.h"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class XMLNode;
|
||||
class ResourceTable;
|
||||
|
||||
enum {
|
||||
XML_COMPILE_STRIP_COMMENTS = 1<<0,
|
||||
XML_COMPILE_ASSIGN_ATTRIBUTE_IDS = 1<<1,
|
||||
XML_COMPILE_COMPACT_WHITESPACE = 1<<2,
|
||||
XML_COMPILE_STRIP_WHITESPACE = 1<<3,
|
||||
XML_COMPILE_STRIP_RAW_VALUES = 1<<4,
|
||||
XML_COMPILE_UTF8 = 1<<5,
|
||||
|
||||
XML_COMPILE_STANDARD_RESOURCE =
|
||||
XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
|
||||
| XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES
|
||||
};
|
||||
|
||||
status_t compileXmlFile(const sp<AaptAssets>& assets,
|
||||
const sp<AaptFile>& target,
|
||||
ResourceTable* table,
|
||||
int options = XML_COMPILE_STANDARD_RESOURCE);
|
||||
|
||||
status_t compileXmlFile(const sp<AaptAssets>& assets,
|
||||
const sp<AaptFile>& target,
|
||||
const sp<AaptFile>& outTarget,
|
||||
ResourceTable* table,
|
||||
int options = XML_COMPILE_STANDARD_RESOURCE);
|
||||
|
||||
status_t compileXmlFile(const sp<AaptAssets>& assets,
|
||||
const sp<XMLNode>& xmlTree,
|
||||
const sp<AaptFile>& target,
|
||||
ResourceTable* table,
|
||||
int options = XML_COMPILE_STANDARD_RESOURCE);
|
||||
|
||||
status_t compileResourceFile(Bundle* bundle,
|
||||
const sp<AaptAssets>& assets,
|
||||
const sp<AaptFile>& in,
|
||||
const ResTable_config& defParams,
|
||||
const bool overwrite,
|
||||
ResourceTable* outTable);
|
||||
|
||||
struct AccessorCookie
|
||||
{
|
||||
SourcePos sourcePos;
|
||||
String8 attr;
|
||||
String8 value;
|
||||
|
||||
AccessorCookie(const SourcePos&p, const String8& a, const String8& v)
|
||||
:sourcePos(p),
|
||||
attr(a),
|
||||
value(v)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ResourceTable : public ResTable::Accessor
|
||||
{
|
||||
public:
|
||||
class Package;
|
||||
class Type;
|
||||
class Entry;
|
||||
|
||||
struct ConfigDescription : public ResTable_config {
|
||||
ConfigDescription() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
size = sizeof(ResTable_config);
|
||||
}
|
||||
ConfigDescription(const ResTable_config&o) {
|
||||
*static_cast<ResTable_config*>(this) = o;
|
||||
size = sizeof(ResTable_config);
|
||||
}
|
||||
ConfigDescription(const ConfigDescription&o) {
|
||||
*static_cast<ResTable_config*>(this) = o;
|
||||
}
|
||||
|
||||
ConfigDescription& operator=(const ResTable_config& o) {
|
||||
*static_cast<ResTable_config*>(this) = o;
|
||||
size = sizeof(ResTable_config);
|
||||
return *this;
|
||||
}
|
||||
ConfigDescription& operator=(const ConfigDescription& o) {
|
||||
*static_cast<ResTable_config*>(this) = o;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
|
||||
inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
|
||||
inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
|
||||
inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
|
||||
inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
|
||||
inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
|
||||
};
|
||||
|
||||
ResourceTable(Bundle* bundle, const String16& assetsPackage);
|
||||
|
||||
status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);
|
||||
|
||||
status_t addPublic(const SourcePos& pos,
|
||||
const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
const uint32_t ident);
|
||||
|
||||
status_t addEntry(const SourcePos& pos,
|
||||
const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
const String16& value,
|
||||
const Vector<StringPool::entry_style_span>* style = NULL,
|
||||
const ResTable_config* params = NULL,
|
||||
const bool doSetIndex = false,
|
||||
const int32_t format = ResTable_map::TYPE_ANY,
|
||||
const bool overwrite = false);
|
||||
|
||||
status_t startBag(const SourcePos& pos,
|
||||
const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
const String16& bagParent,
|
||||
const ResTable_config* params = NULL,
|
||||
bool overlay = false,
|
||||
bool replace = false,
|
||||
bool isId = false);
|
||||
|
||||
status_t addBag(const SourcePos& pos,
|
||||
const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
const String16& bagParent,
|
||||
const String16& bagKey,
|
||||
const String16& value,
|
||||
const Vector<StringPool::entry_style_span>* style = NULL,
|
||||
const ResTable_config* params = NULL,
|
||||
bool replace = false,
|
||||
bool isId = false,
|
||||
const int32_t format = ResTable_map::TYPE_ANY);
|
||||
|
||||
bool hasBagOrEntry(const String16& package,
|
||||
const String16& type,
|
||||
const String16& name) const;
|
||||
|
||||
bool hasBagOrEntry(const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
const ResTable_config& config) const;
|
||||
|
||||
bool hasBagOrEntry(const String16& ref,
|
||||
const String16* defType = NULL,
|
||||
const String16* defPackage = NULL);
|
||||
|
||||
bool appendComment(const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
const String16& comment,
|
||||
bool onlyIfEmpty = false);
|
||||
|
||||
bool appendTypeComment(const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
const String16& comment);
|
||||
|
||||
void canAddEntry(const SourcePos& pos,
|
||||
const String16& package, const String16& type, const String16& name);
|
||||
|
||||
size_t size() const;
|
||||
size_t numLocalResources() const;
|
||||
bool hasResources() const;
|
||||
|
||||
sp<AaptFile> flatten(Bundle*);
|
||||
|
||||
static inline uint32_t makeResId(uint32_t packageId,
|
||||
uint32_t typeId,
|
||||
uint32_t nameId)
|
||||
{
|
||||
return nameId | (typeId<<16) | (packageId<<24);
|
||||
}
|
||||
|
||||
static inline uint32_t getResId(const sp<Package>& p,
|
||||
const sp<Type>& t,
|
||||
uint32_t nameId);
|
||||
|
||||
uint32_t getResId(const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
bool onlyPublic = true) const;
|
||||
|
||||
uint32_t getResId(const String16& ref,
|
||||
const String16* defType = NULL,
|
||||
const String16* defPackage = NULL,
|
||||
const char** outErrorMsg = NULL,
|
||||
bool onlyPublic = true) const;
|
||||
|
||||
static bool isValidResourceName(const String16& s);
|
||||
|
||||
bool stringToValue(Res_value* outValue, StringPool* pool,
|
||||
const String16& str,
|
||||
bool preserveSpaces, bool coerceType,
|
||||
uint32_t attrID,
|
||||
const Vector<StringPool::entry_style_span>* style = NULL,
|
||||
String16* outStr = NULL, void* accessorCookie = NULL,
|
||||
uint32_t attrType = ResTable_map::TYPE_ANY,
|
||||
const String8* configTypeName = NULL,
|
||||
const ConfigDescription* config = NULL);
|
||||
|
||||
status_t assignResourceIds();
|
||||
status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL);
|
||||
void addLocalization(const String16& name, const String8& locale);
|
||||
status_t validateLocalizations(void);
|
||||
|
||||
status_t flatten(Bundle*, const sp<AaptFile>& dest);
|
||||
|
||||
void writePublicDefinitions(const String16& package, FILE* fp);
|
||||
|
||||
virtual uint32_t getCustomResource(const String16& package,
|
||||
const String16& type,
|
||||
const String16& name) const;
|
||||
virtual uint32_t getCustomResourceWithCreation(const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
const bool createIfNeeded);
|
||||
virtual uint32_t getRemappedPackage(uint32_t origPackage) const;
|
||||
virtual bool getAttributeType(uint32_t attrID, uint32_t* outType);
|
||||
virtual bool getAttributeMin(uint32_t attrID, uint32_t* outMin);
|
||||
virtual bool getAttributeMax(uint32_t attrID, uint32_t* outMax);
|
||||
virtual bool getAttributeKeys(uint32_t attrID, Vector<String16>* outKeys);
|
||||
virtual bool getAttributeEnum(uint32_t attrID,
|
||||
const char16_t* name, size_t nameLen,
|
||||
Res_value* outValue);
|
||||
virtual bool getAttributeFlags(uint32_t attrID,
|
||||
const char16_t* name, size_t nameLen,
|
||||
Res_value* outValue);
|
||||
virtual uint32_t getAttributeL10N(uint32_t attrID);
|
||||
|
||||
virtual bool getLocalizationSetting();
|
||||
virtual void reportError(void* accessorCookie, const char* fmt, ...);
|
||||
|
||||
void setCurrentXmlPos(const SourcePos& pos) { mCurrentXmlPos = pos; }
|
||||
|
||||
class Item {
|
||||
public:
|
||||
Item() : isId(false), format(ResTable_map::TYPE_ANY), bagKeyId(0), evaluating(false)
|
||||
{ memset(&parsedValue, 0, sizeof(parsedValue)); }
|
||||
Item(const SourcePos& pos,
|
||||
bool _isId,
|
||||
const String16& _value,
|
||||
const Vector<StringPool::entry_style_span>* _style = NULL,
|
||||
int32_t format = ResTable_map::TYPE_ANY);
|
||||
Item(const Item& o) : sourcePos(o.sourcePos),
|
||||
isId(o.isId), value(o.value), style(o.style),
|
||||
format(o.format), bagKeyId(o.bagKeyId), evaluating(false) {
|
||||
memset(&parsedValue, 0, sizeof(parsedValue));
|
||||
}
|
||||
~Item() { }
|
||||
|
||||
Item& operator=(const Item& o) {
|
||||
sourcePos = o.sourcePos;
|
||||
isId = o.isId;
|
||||
value = o.value;
|
||||
style = o.style;
|
||||
format = o.format;
|
||||
bagKeyId = o.bagKeyId;
|
||||
parsedValue = o.parsedValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SourcePos sourcePos;
|
||||
mutable bool isId;
|
||||
String16 value;
|
||||
Vector<StringPool::entry_style_span> style;
|
||||
int32_t format;
|
||||
uint32_t bagKeyId;
|
||||
mutable bool evaluating;
|
||||
Res_value parsedValue;
|
||||
};
|
||||
|
||||
class Entry : public RefBase {
|
||||
public:
|
||||
Entry(const String16& name, const SourcePos& pos)
|
||||
: mName(name), mType(TYPE_UNKNOWN),
|
||||
mItemFormat(ResTable_map::TYPE_ANY), mNameIndex(-1), mPos(pos)
|
||||
{ }
|
||||
virtual ~Entry() { }
|
||||
|
||||
enum type {
|
||||
TYPE_UNKNOWN = 0,
|
||||
TYPE_ITEM,
|
||||
TYPE_BAG
|
||||
};
|
||||
|
||||
String16 getName() const { return mName; }
|
||||
type getType() const { return mType; }
|
||||
|
||||
void setParent(const String16& parent) { mParent = parent; }
|
||||
String16 getParent() const { return mParent; }
|
||||
|
||||
status_t makeItABag(const SourcePos& sourcePos);
|
||||
|
||||
status_t emptyBag(const SourcePos& sourcePos);
|
||||
|
||||
status_t setItem(const SourcePos& pos,
|
||||
const String16& value,
|
||||
const Vector<StringPool::entry_style_span>* style = NULL,
|
||||
int32_t format = ResTable_map::TYPE_ANY,
|
||||
const bool overwrite = false);
|
||||
|
||||
status_t addToBag(const SourcePos& pos,
|
||||
const String16& key, const String16& value,
|
||||
const Vector<StringPool::entry_style_span>* style = NULL,
|
||||
bool replace=false, bool isId = false,
|
||||
int32_t format = ResTable_map::TYPE_ANY);
|
||||
|
||||
// Index of the entry's name string in the key pool.
|
||||
int32_t getNameIndex() const { return mNameIndex; }
|
||||
void setNameIndex(int32_t index) { mNameIndex = index; }
|
||||
|
||||
const Item* getItem() const { return mType == TYPE_ITEM ? &mItem : NULL; }
|
||||
const KeyedVector<String16, Item>& getBag() const { return mBag; }
|
||||
|
||||
status_t generateAttributes(ResourceTable* table,
|
||||
const String16& package);
|
||||
|
||||
status_t assignResourceIds(ResourceTable* table,
|
||||
const String16& package);
|
||||
|
||||
status_t prepareFlatten(StringPool* strings, ResourceTable* table,
|
||||
const String8* configTypeName, const ConfigDescription* config);
|
||||
|
||||
status_t remapStringValue(StringPool* strings);
|
||||
|
||||
ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic);
|
||||
|
||||
const SourcePos& getPos() const { return mPos; }
|
||||
|
||||
private:
|
||||
String16 mName;
|
||||
String16 mParent;
|
||||
type mType;
|
||||
Item mItem;
|
||||
int32_t mItemFormat;
|
||||
KeyedVector<String16, Item> mBag;
|
||||
int32_t mNameIndex;
|
||||
uint32_t mParentId;
|
||||
SourcePos mPos;
|
||||
};
|
||||
|
||||
class ConfigList : public RefBase {
|
||||
public:
|
||||
ConfigList(const String16& name, const SourcePos& pos)
|
||||
: mName(name), mPos(pos), mPublic(false), mEntryIndex(-1) { }
|
||||
virtual ~ConfigList() { }
|
||||
|
||||
String16 getName() const { return mName; }
|
||||
const SourcePos& getPos() const { return mPos; }
|
||||
|
||||
void appendComment(const String16& comment, bool onlyIfEmpty = false);
|
||||
const String16& getComment() const { return mComment; }
|
||||
|
||||
void appendTypeComment(const String16& comment);
|
||||
const String16& getTypeComment() const { return mTypeComment; }
|
||||
|
||||
// Index of this entry in its Type.
|
||||
int32_t getEntryIndex() const { return mEntryIndex; }
|
||||
void setEntryIndex(int32_t index) { mEntryIndex = index; }
|
||||
|
||||
void setPublic(bool pub) { mPublic = pub; }
|
||||
bool getPublic() const { return mPublic; }
|
||||
void setPublicSourcePos(const SourcePos& pos) { mPublicSourcePos = pos; }
|
||||
const SourcePos& getPublicSourcePos() { return mPublicSourcePos; }
|
||||
|
||||
void addEntry(const ResTable_config& config, const sp<Entry>& entry) {
|
||||
mEntries.add(config, entry);
|
||||
}
|
||||
|
||||
const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; }
|
||||
private:
|
||||
const String16 mName;
|
||||
const SourcePos mPos;
|
||||
String16 mComment;
|
||||
String16 mTypeComment;
|
||||
bool mPublic;
|
||||
SourcePos mPublicSourcePos;
|
||||
int32_t mEntryIndex;
|
||||
DefaultKeyedVector<ConfigDescription, sp<Entry> > mEntries;
|
||||
};
|
||||
|
||||
class Public {
|
||||
public:
|
||||
Public() : sourcePos(), ident(0) { }
|
||||
Public(const SourcePos& pos,
|
||||
const String16& _comment,
|
||||
uint32_t _ident)
|
||||
: sourcePos(pos),
|
||||
comment(_comment), ident(_ident) { }
|
||||
Public(const Public& o) : sourcePos(o.sourcePos),
|
||||
comment(o.comment), ident(o.ident) { }
|
||||
~Public() { }
|
||||
|
||||
Public& operator=(const Public& o) {
|
||||
sourcePos = o.sourcePos;
|
||||
comment = o.comment;
|
||||
ident = o.ident;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SourcePos sourcePos;
|
||||
String16 comment;
|
||||
uint32_t ident;
|
||||
};
|
||||
|
||||
class Type : public RefBase {
|
||||
public:
|
||||
Type(const String16& name, const SourcePos& pos)
|
||||
: mName(name), mFirstPublicSourcePos(NULL), mPublicIndex(-1), mIndex(-1), mPos(pos)
|
||||
{ }
|
||||
virtual ~Type() { delete mFirstPublicSourcePos; }
|
||||
|
||||
status_t addPublic(const SourcePos& pos,
|
||||
const String16& name,
|
||||
const uint32_t ident);
|
||||
|
||||
void canAddEntry(const String16& name);
|
||||
|
||||
String16 getName() const { return mName; }
|
||||
sp<Entry> getEntry(const String16& entry,
|
||||
const SourcePos& pos,
|
||||
const ResTable_config* config = NULL,
|
||||
bool doSetIndex = false,
|
||||
bool overlay = false,
|
||||
bool autoAddOverlay = false);
|
||||
|
||||
const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; }
|
||||
|
||||
int32_t getPublicIndex() const { return mPublicIndex; }
|
||||
|
||||
int32_t getIndex() const { return mIndex; }
|
||||
void setIndex(int32_t index) { mIndex = index; }
|
||||
|
||||
status_t applyPublicEntryOrder();
|
||||
|
||||
const SortedVector<ConfigDescription>& getUniqueConfigs() const { return mUniqueConfigs; }
|
||||
|
||||
const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
|
||||
const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
|
||||
|
||||
const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
|
||||
|
||||
const SourcePos& getPos() const { return mPos; }
|
||||
private:
|
||||
String16 mName;
|
||||
SourcePos* mFirstPublicSourcePos;
|
||||
DefaultKeyedVector<String16, Public> mPublic;
|
||||
SortedVector<ConfigDescription> mUniqueConfigs;
|
||||
DefaultKeyedVector<String16, sp<ConfigList> > mConfigs;
|
||||
Vector<sp<ConfigList> > mOrderedConfigs;
|
||||
SortedVector<String16> mCanAddEntries;
|
||||
int32_t mPublicIndex;
|
||||
int32_t mIndex;
|
||||
SourcePos mPos;
|
||||
};
|
||||
|
||||
class Package : public RefBase {
|
||||
public:
|
||||
Package(const String16& name, ssize_t includedId=-1);
|
||||
virtual ~Package() { }
|
||||
|
||||
String16 getName() const { return mName; }
|
||||
sp<Type> getType(const String16& type,
|
||||
const SourcePos& pos,
|
||||
bool doSetIndex = false);
|
||||
|
||||
ssize_t getAssignedId() const { return mIncludedId; }
|
||||
|
||||
const ResStringPool& getTypeStrings() const { return mTypeStrings; }
|
||||
uint32_t indexOfTypeString(const String16& s) const { return mTypeStringsMapping.valueFor(s); }
|
||||
const sp<AaptFile> getTypeStringsData() const { return mTypeStringsData; }
|
||||
status_t setTypeStrings(const sp<AaptFile>& data);
|
||||
|
||||
const ResStringPool& getKeyStrings() const { return mKeyStrings; }
|
||||
uint32_t indexOfKeyString(const String16& s) const { return mKeyStringsMapping.valueFor(s); }
|
||||
const sp<AaptFile> getKeyStringsData() const { return mKeyStringsData; }
|
||||
status_t setKeyStrings(const sp<AaptFile>& data);
|
||||
|
||||
status_t applyPublicTypeOrder();
|
||||
|
||||
const DefaultKeyedVector<String16, sp<Type> >& getTypes() const { return mTypes; }
|
||||
const Vector<sp<Type> >& getOrderedTypes() const { return mOrderedTypes; }
|
||||
|
||||
private:
|
||||
status_t setStrings(const sp<AaptFile>& data,
|
||||
ResStringPool* strings,
|
||||
DefaultKeyedVector<String16, uint32_t>* mappings);
|
||||
|
||||
const String16 mName;
|
||||
const ssize_t mIncludedId;
|
||||
DefaultKeyedVector<String16, sp<Type> > mTypes;
|
||||
Vector<sp<Type> > mOrderedTypes;
|
||||
sp<AaptFile> mTypeStringsData;
|
||||
sp<AaptFile> mKeyStringsData;
|
||||
ResStringPool mTypeStrings;
|
||||
ResStringPool mKeyStrings;
|
||||
DefaultKeyedVector<String16, uint32_t> mTypeStringsMapping;
|
||||
DefaultKeyedVector<String16, uint32_t> mKeyStringsMapping;
|
||||
};
|
||||
|
||||
private:
|
||||
void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
|
||||
sp<Package> getPackage(const String16& package);
|
||||
sp<Type> getType(const String16& package,
|
||||
const String16& type,
|
||||
const SourcePos& pos,
|
||||
bool doSetIndex = false);
|
||||
sp<Entry> getEntry(const String16& package,
|
||||
const String16& type,
|
||||
const String16& name,
|
||||
const SourcePos& pos,
|
||||
bool overlay,
|
||||
const ResTable_config* config = NULL,
|
||||
bool doSetIndex = false);
|
||||
sp<const Entry> getEntry(uint32_t resID,
|
||||
const ResTable_config* config = NULL) const;
|
||||
const Item* getItem(uint32_t resID, uint32_t attrID) const;
|
||||
bool getItemValue(uint32_t resID, uint32_t attrID,
|
||||
Res_value* outValue);
|
||||
|
||||
|
||||
String16 mAssetsPackage;
|
||||
sp<AaptAssets> mAssets;
|
||||
DefaultKeyedVector<String16, sp<Package> > mPackages;
|
||||
Vector<sp<Package> > mOrderedPackages;
|
||||
uint32_t mNextPackageId;
|
||||
bool mHaveAppPackage;
|
||||
bool mIsAppPackage;
|
||||
size_t mNumLocal;
|
||||
SourcePos mCurrentXmlPos;
|
||||
Bundle* mBundle;
|
||||
|
||||
// key = string resource name, value = set of locales in which that name is defined
|
||||
map<String16, set<String8> > mLocalizations;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,171 +0,0 @@
|
||||
#include "SourcePos.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
// ErrorPos
|
||||
// =============================================================================
|
||||
struct ErrorPos
|
||||
{
|
||||
String8 file;
|
||||
int line;
|
||||
String8 error;
|
||||
bool fatal;
|
||||
|
||||
ErrorPos();
|
||||
ErrorPos(const ErrorPos& that);
|
||||
ErrorPos(const String8& file, int line, const String8& error, bool fatal);
|
||||
~ErrorPos();
|
||||
bool operator<(const ErrorPos& rhs) const;
|
||||
bool operator==(const ErrorPos& rhs) const;
|
||||
ErrorPos& operator=(const ErrorPos& rhs);
|
||||
|
||||
void print(FILE* to) const;
|
||||
};
|
||||
|
||||
static vector<ErrorPos> g_errors;
|
||||
|
||||
ErrorPos::ErrorPos()
|
||||
:line(-1), fatal(false)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorPos::ErrorPos(const ErrorPos& that)
|
||||
:file(that.file),
|
||||
line(that.line),
|
||||
error(that.error),
|
||||
fatal(that.fatal)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorPos::ErrorPos(const String8& f, int l, const String8& e, bool fat)
|
||||
:file(f),
|
||||
line(l),
|
||||
error(e),
|
||||
fatal(fat)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorPos::~ErrorPos()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ErrorPos::operator<(const ErrorPos& rhs) const
|
||||
{
|
||||
if (this->file < rhs.file) return true;
|
||||
if (this->file == rhs.file) {
|
||||
if (this->line < rhs.line) return true;
|
||||
if (this->line == rhs.line) {
|
||||
if (this->error < rhs.error) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ErrorPos::operator==(const ErrorPos& rhs) const
|
||||
{
|
||||
return this->file == rhs.file
|
||||
&& this->line == rhs.line
|
||||
&& this->error == rhs.error;
|
||||
}
|
||||
|
||||
ErrorPos&
|
||||
ErrorPos::operator=(const ErrorPos& rhs)
|
||||
{
|
||||
this->file = rhs.file;
|
||||
this->line = rhs.line;
|
||||
this->error = rhs.error;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
ErrorPos::print(FILE* to) const
|
||||
{
|
||||
const char* type = fatal ? "error:" : "warning:";
|
||||
|
||||
if (this->line >= 0) {
|
||||
fprintf(to, "%s:%d: %s %s\n", this->file.string(), this->line, type, this->error.string());
|
||||
} else {
|
||||
fprintf(to, "%s: %s %s\n", this->file.string(), type, this->error.string());
|
||||
}
|
||||
}
|
||||
|
||||
// SourcePos
|
||||
// =============================================================================
|
||||
SourcePos::SourcePos(const String8& f, int l)
|
||||
: file(f), line(l)
|
||||
{
|
||||
}
|
||||
|
||||
SourcePos::SourcePos(const SourcePos& that)
|
||||
: file(that.file), line(that.line)
|
||||
{
|
||||
}
|
||||
|
||||
SourcePos::SourcePos()
|
||||
: file("???", 0), line(-1)
|
||||
{
|
||||
}
|
||||
|
||||
SourcePos::~SourcePos()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
SourcePos::error(const char* fmt, ...) const
|
||||
{
|
||||
int retval=0;
|
||||
char buf[1024];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
retval = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
char* p = buf + retval - 1;
|
||||
while (p > buf && *p == '\n') {
|
||||
*p = '\0';
|
||||
p--;
|
||||
}
|
||||
g_errors.push_back(ErrorPos(this->file, this->line, String8(buf), true));
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
SourcePos::warning(const char* fmt, ...) const
|
||||
{
|
||||
int retval=0;
|
||||
char buf[1024];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
retval = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
char* p = buf + retval - 1;
|
||||
while (p > buf && *p == '\n') {
|
||||
*p = '\0';
|
||||
p--;
|
||||
}
|
||||
ErrorPos(this->file, this->line, String8(buf), false).print(stderr);
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool
|
||||
SourcePos::hasErrors()
|
||||
{
|
||||
return g_errors.size() > 0;
|
||||
}
|
||||
|
||||
void
|
||||
SourcePos::printErrors(FILE* to)
|
||||
{
|
||||
vector<ErrorPos>::const_iterator it;
|
||||
for (it=g_errors.begin(); it!=g_errors.end(); it++) {
|
||||
it->print(to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef SOURCEPOS_H
|
||||
#define SOURCEPOS_H
|
||||
|
||||
#include <utils/String8.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
class SourcePos
|
||||
{
|
||||
public:
|
||||
String8 file;
|
||||
int line;
|
||||
|
||||
SourcePos(const String8& f, int l);
|
||||
SourcePos(const SourcePos& that);
|
||||
SourcePos();
|
||||
~SourcePos();
|
||||
|
||||
int error(const char* fmt, ...) const;
|
||||
int warning(const char* fmt, ...) const;
|
||||
|
||||
static bool hasErrors();
|
||||
static void printErrors(FILE* to);
|
||||
};
|
||||
|
||||
|
||||
#endif // SOURCEPOS_H
|
||||
@@ -1,574 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
|
||||
#include "StringPool.h"
|
||||
#include "ResourceTable.h"
|
||||
|
||||
#include <utils/ByteOrder.h>
|
||||
#include <utils/SortedVector.h>
|
||||
#include "qsort_r_compat.h"
|
||||
|
||||
#if HAVE_PRINTF_ZD
|
||||
# define ZD "%zd"
|
||||
# define ZD_TYPE ssize_t
|
||||
#else
|
||||
# define ZD "%ld"
|
||||
# define ZD_TYPE long
|
||||
#endif
|
||||
|
||||
#define NOISY(x) //x
|
||||
|
||||
void strcpy16_htod(uint16_t* dst, const uint16_t* src)
|
||||
{
|
||||
while (*src) {
|
||||
char16_t s = htods(*src);
|
||||
*dst++ = s;
|
||||
src++;
|
||||
}
|
||||
*dst = 0;
|
||||
}
|
||||
|
||||
void printStringPool(const ResStringPool* pool)
|
||||
{
|
||||
SortedVector<const void*> uniqueStrings;
|
||||
const size_t N = pool->size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
size_t len;
|
||||
if (pool->isUTF8()) {
|
||||
uniqueStrings.add(pool->string8At(i, &len));
|
||||
} else {
|
||||
uniqueStrings.add(pool->stringAt(i, &len));
|
||||
}
|
||||
}
|
||||
|
||||
printf("String pool of " ZD " unique %s %s strings, " ZD " entries and "
|
||||
ZD " styles using " ZD " bytes:\n",
|
||||
(ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16",
|
||||
pool->isSorted() ? "sorted" : "non-sorted",
|
||||
(ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes());
|
||||
|
||||
const size_t NS = pool->size();
|
||||
for (size_t s=0; s<NS; s++) {
|
||||
String8 str = pool->string8ObjectAt(s);
|
||||
printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
|
||||
}
|
||||
}
|
||||
|
||||
String8 StringPool::entry::makeConfigsString() const {
|
||||
String8 configStr(configTypeName);
|
||||
if (configStr.size() > 0) configStr.append(" ");
|
||||
if (configs.size() > 0) {
|
||||
for (size_t j=0; j<configs.size(); j++) {
|
||||
if (j > 0) configStr.append(", ");
|
||||
configStr.append(configs[j].toString());
|
||||
}
|
||||
} else {
|
||||
configStr = "(none)";
|
||||
}
|
||||
return configStr;
|
||||
}
|
||||
|
||||
int StringPool::entry::compare(const entry& o) const {
|
||||
// Strings with styles go first, to reduce the size of the styles array.
|
||||
// We don't care about the relative order of these strings.
|
||||
if (hasStyles) {
|
||||
return o.hasStyles ? 0 : -1;
|
||||
}
|
||||
if (o.hasStyles) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Sort unstyled strings by type, then by logical configuration.
|
||||
int comp = configTypeName.compare(o.configTypeName);
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
const size_t LHN = configs.size();
|
||||
const size_t RHN = o.configs.size();
|
||||
size_t i=0;
|
||||
while (i < LHN && i < RHN) {
|
||||
comp = configs[i].compareLogical(o.configs[i]);
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (LHN < RHN) return -1;
|
||||
else if (LHN > RHN) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
StringPool::StringPool(bool utf8) :
|
||||
mUTF8(utf8), mValues(-1)
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans,
|
||||
const String8* configTypeName, const ResTable_config* config)
|
||||
{
|
||||
ssize_t res = add(value, false, configTypeName, config);
|
||||
if (res >= 0) {
|
||||
addStyleSpans(res, spans);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t StringPool::add(const String16& value,
|
||||
bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config)
|
||||
{
|
||||
ssize_t vidx = mValues.indexOfKey(value);
|
||||
ssize_t pos = vidx >= 0 ? mValues.valueAt(vidx) : -1;
|
||||
ssize_t eidx = pos >= 0 ? mEntryArray.itemAt(pos) : -1;
|
||||
if (eidx < 0) {
|
||||
eidx = mEntries.add(entry(value));
|
||||
if (eidx < 0) {
|
||||
fprintf(stderr, "Failure adding string %s\n", String8(value).string());
|
||||
return eidx;
|
||||
}
|
||||
}
|
||||
|
||||
if (configTypeName != NULL) {
|
||||
entry& ent = mEntries.editItemAt(eidx);
|
||||
NOISY(printf("*** adding config type name %s, was %s\n",
|
||||
configTypeName->string(), ent.configTypeName.string()));
|
||||
if (ent.configTypeName.size() <= 0) {
|
||||
ent.configTypeName = *configTypeName;
|
||||
} else if (ent.configTypeName != *configTypeName) {
|
||||
ent.configTypeName = " ";
|
||||
}
|
||||
}
|
||||
|
||||
if (config != NULL) {
|
||||
// Add this to the set of configs associated with the string.
|
||||
entry& ent = mEntries.editItemAt(eidx);
|
||||
size_t addPos;
|
||||
for (addPos=0; addPos<ent.configs.size(); addPos++) {
|
||||
int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
|
||||
if (cmp >= 0) {
|
||||
if (cmp > 0) {
|
||||
NOISY(printf("*** inserting config: %s\n", config->toString().string()));
|
||||
ent.configs.insertAt(*config, addPos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (addPos >= ent.configs.size()) {
|
||||
NOISY(printf("*** adding config: %s\n", config->toString().string()));
|
||||
ent.configs.add(*config);
|
||||
}
|
||||
}
|
||||
|
||||
const bool first = vidx < 0;
|
||||
const bool styled = (pos >= 0 && (size_t)pos < mEntryStyleArray.size()) ?
|
||||
mEntryStyleArray[pos].spans.size() : 0;
|
||||
if (first || styled || !mergeDuplicates) {
|
||||
pos = mEntryArray.add(eidx);
|
||||
if (first) {
|
||||
vidx = mValues.add(value, pos);
|
||||
}
|
||||
entry& ent = mEntries.editItemAt(eidx);
|
||||
ent.indices.add(pos);
|
||||
}
|
||||
|
||||
NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n",
|
||||
String8(value).string(), pos, eidx, vidx));
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
status_t StringPool::addStyleSpan(size_t idx, const String16& name,
|
||||
uint32_t start, uint32_t end)
|
||||
{
|
||||
entry_style_span span;
|
||||
span.name = name;
|
||||
span.span.firstChar = start;
|
||||
span.span.lastChar = end;
|
||||
return addStyleSpan(idx, span);
|
||||
}
|
||||
|
||||
status_t StringPool::addStyleSpans(size_t idx, const Vector<entry_style_span>& spans)
|
||||
{
|
||||
const size_t N=spans.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
status_t err = addStyleSpan(idx, spans[i]);
|
||||
if (err != NO_ERROR) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t StringPool::addStyleSpan(size_t idx, const entry_style_span& span)
|
||||
{
|
||||
// Place blank entries in the span array up to this index.
|
||||
while (mEntryStyleArray.size() <= idx) {
|
||||
mEntryStyleArray.add();
|
||||
}
|
||||
|
||||
entry_style& style = mEntryStyleArray.editItemAt(idx);
|
||||
style.spans.add(span);
|
||||
mEntries.editItemAt(mEntryArray[idx]).hasStyles = true;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int StringPool::config_sort(void* state, const void* lhs, const void* rhs)
|
||||
{
|
||||
StringPool* pool = (StringPool*)state;
|
||||
const entry& lhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(lhs)]];
|
||||
const entry& rhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(rhs)]];
|
||||
return lhe.compare(rhe);
|
||||
}
|
||||
|
||||
void StringPool::sortByConfig()
|
||||
{
|
||||
LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted.");
|
||||
|
||||
const size_t N = mEntryArray.size();
|
||||
|
||||
// This is a vector that starts out with a 1:1 mapping to entries
|
||||
// in the array, which we will sort to come up with the desired order.
|
||||
// At that point it maps from the new position in the array to the
|
||||
// original position the entry appeared.
|
||||
Vector<size_t> newPosToOriginalPos;
|
||||
newPosToOriginalPos.setCapacity(N);
|
||||
for (size_t i=0; i < N; i++) {
|
||||
newPosToOriginalPos.add(i);
|
||||
}
|
||||
|
||||
// Sort the array.
|
||||
NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
|
||||
// Vector::sort uses insertion sort, which is very slow for this data set.
|
||||
// Use quicksort instead because we don't need a stable sort here.
|
||||
qsort_r_compat(newPosToOriginalPos.editArray(), N, sizeof(size_t), this, config_sort);
|
||||
//newPosToOriginalPos.sort(config_sort, this);
|
||||
NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));
|
||||
|
||||
// Create the reverse mapping from the original position in the array
|
||||
// to the new position where it appears in the sorted array. This is
|
||||
// so that clients can re-map any positions they had previously stored.
|
||||
mOriginalPosToNewPos = newPosToOriginalPos;
|
||||
for (size_t i=0; i<N; i++) {
|
||||
mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i;
|
||||
}
|
||||
|
||||
#if 0
|
||||
SortedVector<entry> entries;
|
||||
|
||||
for (size_t i=0; i<N; i++) {
|
||||
printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
|
||||
mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
|
||||
entries.add(mEntries[mEntryArray[i]]);
|
||||
}
|
||||
|
||||
for (size_t i=0; i<entries.size(); i++) {
|
||||
printf("Sorted config #%d: %s\n", i,
|
||||
entries[i].makeConfigsString().string());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Now we rebuild the arrays.
|
||||
Vector<entry> newEntries;
|
||||
Vector<size_t> newEntryArray;
|
||||
Vector<entry_style> newEntryStyleArray;
|
||||
DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset;
|
||||
|
||||
for (size_t i=0; i<N; i++) {
|
||||
// We are filling in new offset 'i'; oldI is where we can find it
|
||||
// in the original data structure.
|
||||
size_t oldI = newPosToOriginalPos[i];
|
||||
// This is the actual entry associated with the old offset.
|
||||
const entry& oldEnt = mEntries[mEntryArray[oldI]];
|
||||
// This is the same entry the last time we added it to the
|
||||
// new entry array, if any.
|
||||
ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI);
|
||||
size_t newOffset;
|
||||
if (newIndexOfOffset < 0) {
|
||||
// This is the first time we have seen the entry, so add
|
||||
// it.
|
||||
newOffset = newEntries.add(oldEnt);
|
||||
newEntries.editItemAt(newOffset).indices.clear();
|
||||
} else {
|
||||
// We have seen this entry before, use the existing one
|
||||
// instead of adding it again.
|
||||
newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset);
|
||||
}
|
||||
// Update the indices to include this new position.
|
||||
newEntries.editItemAt(newOffset).indices.add(i);
|
||||
// And add the offset of the entry to the new entry array.
|
||||
newEntryArray.add(newOffset);
|
||||
// Add any old style to the new style array.
|
||||
if (mEntryStyleArray.size() > 0) {
|
||||
if (oldI < mEntryStyleArray.size()) {
|
||||
newEntryStyleArray.add(mEntryStyleArray[oldI]);
|
||||
} else {
|
||||
newEntryStyleArray.add(entry_style());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now trim any entries at the end of the new style array that are
|
||||
// not needed.
|
||||
for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) {
|
||||
const entry_style& style = newEntryStyleArray[i];
|
||||
if (style.spans.size() > 0) {
|
||||
// That's it.
|
||||
break;
|
||||
}
|
||||
// This one is not needed; remove.
|
||||
newEntryStyleArray.removeAt(i);
|
||||
}
|
||||
|
||||
// All done, install the new data structures and upate mValues with
|
||||
// the new positions.
|
||||
mEntries = newEntries;
|
||||
mEntryArray = newEntryArray;
|
||||
mEntryStyleArray = newEntryStyleArray;
|
||||
mValues.clear();
|
||||
for (size_t i=0; i<mEntries.size(); i++) {
|
||||
const entry& ent = mEntries[i];
|
||||
mValues.add(ent.value, ent.indices[0]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
printf("FINAL SORTED STRING CONFIGS:\n");
|
||||
for (size_t i=0; i<mEntries.size(); i++) {
|
||||
const entry& ent = mEntries[i];
|
||||
printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
|
||||
String8(ent.value).string());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sp<AaptFile> StringPool::createStringBlock()
|
||||
{
|
||||
sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(),
|
||||
String8());
|
||||
status_t err = writeStringBlock(pool);
|
||||
return err == NO_ERROR ? pool : NULL;
|
||||
}
|
||||
|
||||
#define ENCODE_LENGTH(str, chrsz, strSize) \
|
||||
{ \
|
||||
size_t maxMask = 1 << ((chrsz*8)-1); \
|
||||
size_t maxSize = maxMask-1; \
|
||||
if (strSize > maxSize) { \
|
||||
*str++ = maxMask | ((strSize>>(chrsz*8))&maxSize); \
|
||||
} \
|
||||
*str++ = strSize; \
|
||||
}
|
||||
|
||||
status_t StringPool::writeStringBlock(const sp<AaptFile>& pool)
|
||||
{
|
||||
// Allow appending. Sorry this is a little wacky.
|
||||
if (pool->getSize() > 0) {
|
||||
sp<AaptFile> block = createStringBlock();
|
||||
if (block == NULL) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
ssize_t res = pool->writeData(block->getData(), block->getSize());
|
||||
return (res >= 0) ? (status_t)NO_ERROR : res;
|
||||
}
|
||||
|
||||
// First we need to add all style span names to the string pool.
|
||||
// We do this now (instead of when the span is added) so that these
|
||||
// will appear at the end of the pool, not disrupting the order
|
||||
// our client placed their own strings in it.
|
||||
|
||||
const size_t STYLES = mEntryStyleArray.size();
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<STYLES; i++) {
|
||||
entry_style& style = mEntryStyleArray.editItemAt(i);
|
||||
const size_t N = style.spans.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
entry_style_span& span = style.spans.editItemAt(i);
|
||||
ssize_t idx = add(span.name, true);
|
||||
if (idx < 0) {
|
||||
fprintf(stderr, "Error adding span for style tag '%s'\n",
|
||||
String8(span.name).string());
|
||||
return idx;
|
||||
}
|
||||
span.span.name.index = (uint32_t)idx;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t ENTRIES = mEntryArray.size();
|
||||
|
||||
// Now build the pool of unique strings.
|
||||
|
||||
const size_t STRINGS = mEntries.size();
|
||||
const size_t preSize = sizeof(ResStringPool_header)
|
||||
+ (sizeof(uint32_t)*ENTRIES)
|
||||
+ (sizeof(uint32_t)*STYLES);
|
||||
if (pool->editData(preSize) == NULL) {
|
||||
fprintf(stderr, "ERROR: Out of memory for string pool\n");
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(char16_t);
|
||||
|
||||
size_t strPos = 0;
|
||||
for (i=0; i<STRINGS; i++) {
|
||||
entry& ent = mEntries.editItemAt(i);
|
||||
const size_t strSize = (ent.value.size());
|
||||
const size_t lenSize = strSize > (size_t)(1<<((charSize*8)-1))-1 ?
|
||||
charSize*2 : charSize;
|
||||
|
||||
String8 encStr;
|
||||
if (mUTF8) {
|
||||
encStr = String8(ent.value);
|
||||
}
|
||||
|
||||
const size_t encSize = mUTF8 ? encStr.size() : 0;
|
||||
const size_t encLenSize = mUTF8 ?
|
||||
(encSize > (size_t)(1<<((charSize*8)-1))-1 ?
|
||||
charSize*2 : charSize) : 0;
|
||||
|
||||
ent.offset = strPos;
|
||||
|
||||
const size_t totalSize = lenSize + encLenSize +
|
||||
((mUTF8 ? encSize : strSize)+1)*charSize;
|
||||
|
||||
void* dat = (void*)pool->editData(preSize + strPos + totalSize);
|
||||
if (dat == NULL) {
|
||||
fprintf(stderr, "ERROR: Out of memory for string pool\n");
|
||||
return NO_MEMORY;
|
||||
}
|
||||
dat = (uint8_t*)dat + preSize + strPos;
|
||||
if (mUTF8) {
|
||||
uint8_t* strings = (uint8_t*)dat;
|
||||
|
||||
ENCODE_LENGTH(strings, sizeof(uint8_t), strSize)
|
||||
|
||||
ENCODE_LENGTH(strings, sizeof(uint8_t), encSize)
|
||||
|
||||
strncpy((char*)strings, encStr, encSize+1);
|
||||
} else {
|
||||
uint16_t* strings = (uint16_t*)dat;
|
||||
|
||||
ENCODE_LENGTH(strings, sizeof(uint16_t), strSize)
|
||||
|
||||
strcpy16_htod(strings, ent.value);
|
||||
}
|
||||
|
||||
strPos += totalSize;
|
||||
}
|
||||
|
||||
// Pad ending string position up to a uint32_t boundary.
|
||||
|
||||
if (strPos&0x3) {
|
||||
size_t padPos = ((strPos+3)&~0x3);
|
||||
uint8_t* dat = (uint8_t*)pool->editData(preSize + padPos);
|
||||
if (dat == NULL) {
|
||||
fprintf(stderr, "ERROR: Out of memory padding string pool\n");
|
||||
return NO_MEMORY;
|
||||
}
|
||||
memset(dat+preSize+strPos, 0, padPos-strPos);
|
||||
strPos = padPos;
|
||||
}
|
||||
|
||||
// Build the pool of style spans.
|
||||
|
||||
size_t styPos = strPos;
|
||||
for (i=0; i<STYLES; i++) {
|
||||
entry_style& ent = mEntryStyleArray.editItemAt(i);
|
||||
const size_t N = ent.spans.size();
|
||||
const size_t totalSize = (N*sizeof(ResStringPool_span))
|
||||
+ sizeof(ResStringPool_ref);
|
||||
|
||||
ent.offset = styPos-strPos;
|
||||
uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + totalSize);
|
||||
if (dat == NULL) {
|
||||
fprintf(stderr, "ERROR: Out of memory for string styles\n");
|
||||
return NO_MEMORY;
|
||||
}
|
||||
ResStringPool_span* span = (ResStringPool_span*)(dat+preSize+styPos);
|
||||
for (size_t i=0; i<N; i++) {
|
||||
span->name.index = htodl(ent.spans[i].span.name.index);
|
||||
span->firstChar = htodl(ent.spans[i].span.firstChar);
|
||||
span->lastChar = htodl(ent.spans[i].span.lastChar);
|
||||
span++;
|
||||
}
|
||||
span->name.index = htodl(ResStringPool_span::END);
|
||||
|
||||
styPos += totalSize;
|
||||
}
|
||||
|
||||
if (STYLES > 0) {
|
||||
// Add full terminator at the end (when reading we validate that
|
||||
// the end of the pool is fully terminated to simplify error
|
||||
// checking).
|
||||
size_t extra = sizeof(ResStringPool_span)-sizeof(ResStringPool_ref);
|
||||
uint8_t* dat = (uint8_t*)pool->editData(preSize + styPos + extra);
|
||||
if (dat == NULL) {
|
||||
fprintf(stderr, "ERROR: Out of memory for string styles\n");
|
||||
return NO_MEMORY;
|
||||
}
|
||||
uint32_t* p = (uint32_t*)(dat+preSize+styPos);
|
||||
while (extra > 0) {
|
||||
*p++ = htodl(ResStringPool_span::END);
|
||||
extra -= sizeof(uint32_t);
|
||||
}
|
||||
styPos += extra;
|
||||
}
|
||||
|
||||
// Write header.
|
||||
|
||||
ResStringPool_header* header =
|
||||
(ResStringPool_header*)pool->padData(sizeof(uint32_t));
|
||||
if (header == NULL) {
|
||||
fprintf(stderr, "ERROR: Out of memory for string pool\n");
|
||||
return NO_MEMORY;
|
||||
}
|
||||
memset(header, 0, sizeof(*header));
|
||||
header->header.type = htods(RES_STRING_POOL_TYPE);
|
||||
header->header.headerSize = htods(sizeof(*header));
|
||||
header->header.size = htodl(pool->getSize());
|
||||
header->stringCount = htodl(ENTRIES);
|
||||
header->styleCount = htodl(STYLES);
|
||||
if (mUTF8) {
|
||||
header->flags |= htodl(ResStringPool_header::UTF8_FLAG);
|
||||
}
|
||||
header->stringsStart = htodl(preSize);
|
||||
header->stylesStart = htodl(STYLES > 0 ? (preSize+strPos) : 0);
|
||||
|
||||
// Write string index array.
|
||||
|
||||
uint32_t* index = (uint32_t*)(header+1);
|
||||
for (i=0; i<ENTRIES; i++) {
|
||||
entry& ent = mEntries.editItemAt(mEntryArray[i]);
|
||||
*index++ = htodl(ent.offset);
|
||||
NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i,
|
||||
String8(ent.value).string(),
|
||||
mEntryArray[i], ent.offset));
|
||||
}
|
||||
|
||||
// Write style index array.
|
||||
|
||||
for (i=0; i<STYLES; i++) {
|
||||
*index++ = htodl(mEntryStyleArray[i].offset);
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
ssize_t StringPool::offsetForString(const String16& val) const
|
||||
{
|
||||
const Vector<size_t>* indices = offsetsForString(val);
|
||||
ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1;
|
||||
NOISY(printf("Offset for string %s: %d (%s)\n", String8(val).string(), res,
|
||||
res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8()));
|
||||
return res;
|
||||
}
|
||||
|
||||
const Vector<size_t>* StringPool::offsetsForString(const String16& val) const
|
||||
{
|
||||
ssize_t pos = mValues.valueFor(val);
|
||||
if (pos < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return &mEntries[mEntryArray[pos]].indices;
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
|
||||
#ifndef STRING_POOL_H
|
||||
#define STRING_POOL_H
|
||||
|
||||
#include "Main.h"
|
||||
#include "AaptAssets.h"
|
||||
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
#include <utils/String16.h>
|
||||
#include <utils/TypeHelpers.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libexpat/expat.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
#define PRINT_STRING_METRICS 0
|
||||
|
||||
void strcpy16_htod(uint16_t* dst, const uint16_t* src);
|
||||
|
||||
void printStringPool(const ResStringPool* pool);
|
||||
|
||||
/**
|
||||
* The StringPool class is used as an intermediate representation for
|
||||
* generating the string pool resource data structure that can be parsed with
|
||||
* ResStringPool in include/utils/ResourceTypes.h.
|
||||
*/
|
||||
class StringPool
|
||||
{
|
||||
public:
|
||||
struct entry {
|
||||
entry() : offset(0) { }
|
||||
entry(const String16& _value) : value(_value), offset(0), hasStyles(false) { }
|
||||
entry(const entry& o) : value(o.value), offset(o.offset),
|
||||
hasStyles(o.hasStyles), indices(o.indices),
|
||||
configTypeName(o.configTypeName), configs(o.configs) { }
|
||||
|
||||
String16 value;
|
||||
size_t offset;
|
||||
bool hasStyles;
|
||||
Vector<size_t> indices;
|
||||
String8 configTypeName;
|
||||
Vector<ResTable_config> configs;
|
||||
|
||||
String8 makeConfigsString() const;
|
||||
|
||||
int compare(const entry& o) const;
|
||||
|
||||
inline bool operator<(const entry& o) const { return compare(o) < 0; }
|
||||
inline bool operator<=(const entry& o) const { return compare(o) <= 0; }
|
||||
inline bool operator==(const entry& o) const { return compare(o) == 0; }
|
||||
inline bool operator!=(const entry& o) const { return compare(o) != 0; }
|
||||
inline bool operator>=(const entry& o) const { return compare(o) >= 0; }
|
||||
inline bool operator>(const entry& o) const { return compare(o) > 0; }
|
||||
};
|
||||
|
||||
struct entry_style_span {
|
||||
String16 name;
|
||||
ResStringPool_span span;
|
||||
};
|
||||
|
||||
struct entry_style {
|
||||
entry_style() : offset(0) { }
|
||||
|
||||
entry_style(const entry_style& o) : offset(o.offset), spans(o.spans) { }
|
||||
|
||||
size_t offset;
|
||||
Vector<entry_style_span> spans;
|
||||
};
|
||||
|
||||
/**
|
||||
* If 'utf8' is true, strings will be encoded with UTF-8 instead of
|
||||
* left in Java's native UTF-16.
|
||||
*/
|
||||
explicit StringPool(bool utf8 = false);
|
||||
|
||||
/**
|
||||
* Add a new string to the pool. If mergeDuplicates is true, thenif
|
||||
* the string already exists the existing entry for it will be used;
|
||||
* otherwise, or if the value doesn't already exist, a new entry is
|
||||
* created.
|
||||
*
|
||||
* Returns the index in the entry array of the new string entry.
|
||||
*/
|
||||
ssize_t add(const String16& value, bool mergeDuplicates = false,
|
||||
const String8* configTypeName = NULL, const ResTable_config* config = NULL);
|
||||
|
||||
ssize_t add(const String16& value, const Vector<entry_style_span>& spans,
|
||||
const String8* configTypeName = NULL, const ResTable_config* config = NULL);
|
||||
|
||||
status_t addStyleSpan(size_t idx, const String16& name,
|
||||
uint32_t start, uint32_t end);
|
||||
status_t addStyleSpans(size_t idx, const Vector<entry_style_span>& spans);
|
||||
status_t addStyleSpan(size_t idx, const entry_style_span& span);
|
||||
|
||||
// Sort the contents of the string block by the configuration associated
|
||||
// with each item. After doing this you can use mapOriginalPosToNewPos()
|
||||
// to find out the new position given the position originally returned by
|
||||
// add().
|
||||
void sortByConfig();
|
||||
|
||||
// For use after sortByConfig() to map from the original position of
|
||||
// a string to its new sorted position.
|
||||
size_t mapOriginalPosToNewPos(size_t originalPos) const {
|
||||
return mOriginalPosToNewPos.itemAt(originalPos);
|
||||
}
|
||||
|
||||
sp<AaptFile> createStringBlock();
|
||||
|
||||
status_t writeStringBlock(const sp<AaptFile>& pool);
|
||||
|
||||
/**
|
||||
* Find out an offset in the pool for a particular string. If the string
|
||||
* pool is sorted, this can not be called until after createStringBlock()
|
||||
* or writeStringBlock() has been called
|
||||
* (which determines the offsets). In the case of a string that appears
|
||||
* multiple times in the pool, the first offset will be returned. Returns
|
||||
* -1 if the string does not exist.
|
||||
*/
|
||||
ssize_t offsetForString(const String16& val) const;
|
||||
|
||||
/**
|
||||
* Find all of the offsets in the pool for a particular string. If the
|
||||
* string pool is sorted, this can not be called until after
|
||||
* createStringBlock() or writeStringBlock() has been called
|
||||
* (which determines the offsets). Returns NULL if the string does not exist.
|
||||
*/
|
||||
const Vector<size_t>* offsetsForString(const String16& val) const;
|
||||
|
||||
private:
|
||||
static int config_sort(void* state, const void* lhs, const void* rhs);
|
||||
|
||||
const bool mUTF8;
|
||||
|
||||
// The following data structures represent the actual structures
|
||||
// that will be generated for the final string pool.
|
||||
|
||||
// Raw array of unique strings, in some arbitrary order. This is the
|
||||
// actual strings that appear in the final string pool, in the order
|
||||
// that they will be written.
|
||||
Vector<entry> mEntries;
|
||||
// Array of indices into mEntries, in the order they were
|
||||
// added to the pool. This can be different than mEntries
|
||||
// if the same string was added multiple times (it will appear
|
||||
// once in mEntries, with multiple occurrences in this array).
|
||||
// This is the lookup array that will be written for finding
|
||||
// the string for each offset/position in the string pool.
|
||||
Vector<size_t> mEntryArray;
|
||||
// Optional style span information associated with each index of
|
||||
// mEntryArray.
|
||||
Vector<entry_style> mEntryStyleArray;
|
||||
|
||||
// The following data structures are used for book-keeping as the
|
||||
// string pool is constructed.
|
||||
|
||||
// Unique set of all the strings added to the pool, mapped to
|
||||
// the first index of mEntryArray where the value was added.
|
||||
DefaultKeyedVector<String16, ssize_t> mValues;
|
||||
// This array maps from the original position a string was placed at
|
||||
// in mEntryArray to its new position after being sorted with sortByConfig().
|
||||
Vector<size_t> mOriginalPosToNewPos;
|
||||
};
|
||||
|
||||
// The entry types are trivially movable because all fields they contain, including
|
||||
// the vectors and strings, are trivially movable.
|
||||
namespace android {
|
||||
ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry);
|
||||
ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry_style_span);
|
||||
ANDROID_TRIVIAL_MOVE_TRAIT(StringPool::entry_style);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// #define LOG_NDEBUG 0
|
||||
#define LOG_TAG "WorkQueue"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include "WorkQueue.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- WorkQueue ---
|
||||
|
||||
WorkQueue::WorkQueue(size_t maxThreads, bool canCallJava) :
|
||||
mMaxThreads(maxThreads), mCanCallJava(canCallJava),
|
||||
mCanceled(false), mFinished(false), mIdleThreads(0) {
|
||||
}
|
||||
|
||||
WorkQueue::~WorkQueue() {
|
||||
if (!cancel()) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
status_t WorkQueue::schedule(WorkUnit* workUnit, size_t backlog) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mFinished || mCanceled) {
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (mWorkThreads.size() < mMaxThreads
|
||||
&& mIdleThreads < mWorkUnits.size() + 1) {
|
||||
sp<WorkThread> workThread = new WorkThread(this, mCanCallJava);
|
||||
status_t status = workThread->run("WorkQueue::WorkThread");
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
mWorkThreads.add(workThread);
|
||||
mIdleThreads += 1;
|
||||
} else if (backlog) {
|
||||
while (mWorkUnits.size() >= mMaxThreads * backlog) {
|
||||
mWorkDequeuedCondition.wait(mLock);
|
||||
if (mFinished || mCanceled) {
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mWorkUnits.add(workUnit);
|
||||
mWorkChangedCondition.broadcast();
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t WorkQueue::cancel() {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
return cancelLocked();
|
||||
}
|
||||
|
||||
status_t WorkQueue::cancelLocked() {
|
||||
if (mFinished) {
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (!mCanceled) {
|
||||
mCanceled = true;
|
||||
|
||||
size_t count = mWorkUnits.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
delete mWorkUnits.itemAt(i);
|
||||
}
|
||||
mWorkUnits.clear();
|
||||
mWorkChangedCondition.broadcast();
|
||||
mWorkDequeuedCondition.broadcast();
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t WorkQueue::finish() {
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mFinished) {
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
mFinished = true;
|
||||
mWorkChangedCondition.broadcast();
|
||||
} // release lock
|
||||
|
||||
// It is not possible for the list of work threads to change once the mFinished
|
||||
// flag has been set, so we can access mWorkThreads outside of the lock here.
|
||||
size_t count = mWorkThreads.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
mWorkThreads.itemAt(i)->join();
|
||||
}
|
||||
mWorkThreads.clear();
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool WorkQueue::threadLoop() {
|
||||
WorkUnit* workUnit;
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
for (;;) {
|
||||
if (mCanceled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mWorkUnits.isEmpty()) {
|
||||
workUnit = mWorkUnits.itemAt(0);
|
||||
mWorkUnits.removeAt(0);
|
||||
mIdleThreads -= 1;
|
||||
mWorkDequeuedCondition.broadcast();
|
||||
break;
|
||||
}
|
||||
|
||||
if (mFinished) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mWorkChangedCondition.wait(mLock);
|
||||
}
|
||||
} // release lock
|
||||
|
||||
bool shouldContinue = workUnit->run();
|
||||
delete workUnit;
|
||||
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mIdleThreads += 1;
|
||||
|
||||
if (!shouldContinue) {
|
||||
cancelLocked();
|
||||
return false;
|
||||
}
|
||||
} // release lock
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- WorkQueue::WorkThread ---
|
||||
|
||||
WorkQueue::WorkThread::WorkThread(WorkQueue* workQueue, bool canCallJava) :
|
||||
Thread(canCallJava), mWorkQueue(workQueue) {
|
||||
}
|
||||
|
||||
WorkQueue::WorkThread::~WorkThread() {
|
||||
}
|
||||
|
||||
bool WorkQueue::WorkThread::threadLoop() {
|
||||
return mWorkQueue->threadLoop();
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
@@ -1,119 +0,0 @@
|
||||
/*]
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef AAPT_WORK_QUEUE_H
|
||||
#define AAPT_WORK_QUEUE_H
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* A threaded work queue.
|
||||
*
|
||||
* This class is designed to make it easy to run a bunch of isolated work
|
||||
* units in parallel, using up to the specified number of threads.
|
||||
* To use it, write a loop to post work units to the work queue, then synchronize
|
||||
* on the queue at the end.
|
||||
*/
|
||||
class WorkQueue {
|
||||
public:
|
||||
class WorkUnit {
|
||||
public:
|
||||
WorkUnit() { }
|
||||
virtual ~WorkUnit() { }
|
||||
|
||||
/*
|
||||
* Runs the work unit.
|
||||
* If the result is 'true' then the work queue continues scheduling work as usual.
|
||||
* If the result is 'false' then the work queue is canceled.
|
||||
*/
|
||||
virtual bool run() = 0;
|
||||
};
|
||||
|
||||
/* Creates a work queue with the specified maximum number of work threads. */
|
||||
WorkQueue(size_t maxThreads, bool canCallJava = true);
|
||||
|
||||
/* Destroys the work queue.
|
||||
* Cancels pending work and waits for all remaining threads to complete.
|
||||
*/
|
||||
~WorkQueue();
|
||||
|
||||
/* Posts a work unit to run later.
|
||||
* If the work queue has been canceled or is already finished, returns INVALID_OPERATION
|
||||
* and does not take ownership of the work unit (caller must destroy it itself).
|
||||
* Otherwise, returns OK and takes ownership of the work unit (the work queue will
|
||||
* destroy it automatically).
|
||||
*
|
||||
* For flow control, this method blocks when the size of the pending work queue is more
|
||||
* 'backlog' times the number of threads. This condition reduces the rate of entry into
|
||||
* the pending work queue and prevents it from growing much more rapidly than the
|
||||
* work threads can actually handle.
|
||||
*
|
||||
* If 'backlog' is 0, then no throttle is applied.
|
||||
*/
|
||||
status_t schedule(WorkUnit* workUnit, size_t backlog = 2);
|
||||
|
||||
/* Cancels all pending work.
|
||||
* If the work queue is already finished, returns INVALID_OPERATION.
|
||||
* If the work queue is already canceled, returns OK and does nothing else.
|
||||
* Otherwise, returns OK, discards all pending work units and prevents additional
|
||||
* work units from being scheduled.
|
||||
*
|
||||
* Call finish() after cancel() to wait for all remaining work to complete.
|
||||
*/
|
||||
status_t cancel();
|
||||
|
||||
/* Waits for all work to complete.
|
||||
* If the work queue is already finished, returns INVALID_OPERATION.
|
||||
* Otherwise, waits for all work to complete and returns OK.
|
||||
*/
|
||||
status_t finish();
|
||||
|
||||
private:
|
||||
class WorkThread : public Thread {
|
||||
public:
|
||||
WorkThread(WorkQueue* workQueue, bool canCallJava);
|
||||
virtual ~WorkThread();
|
||||
|
||||
private:
|
||||
virtual bool threadLoop();
|
||||
|
||||
WorkQueue* const mWorkQueue;
|
||||
};
|
||||
|
||||
status_t cancelLocked();
|
||||
bool threadLoop(); // called from each work thread
|
||||
|
||||
const size_t mMaxThreads;
|
||||
const bool mCanCallJava;
|
||||
|
||||
Mutex mLock;
|
||||
Condition mWorkChangedCondition;
|
||||
Condition mWorkDequeuedCondition;
|
||||
|
||||
bool mCanceled;
|
||||
bool mFinished;
|
||||
size_t mIdleThreads;
|
||||
Vector<sp<WorkThread> > mWorkThreads;
|
||||
Vector<WorkUnit*> mWorkUnits;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // AAPT_WORK_QUEUE_H
|
||||
@@ -1,202 +0,0 @@
|
||||
//
|
||||
// Copyright 2006 The Android Open Source Project
|
||||
//
|
||||
// Build resource files from raw assets.
|
||||
//
|
||||
|
||||
#ifndef XML_NODE_H
|
||||
#define XML_NODE_H
|
||||
|
||||
#include "StringPool.h"
|
||||
#include "ResourceTable.h"
|
||||
|
||||
class XMLNode;
|
||||
|
||||
extern const char* const RESOURCES_ROOT_NAMESPACE;
|
||||
extern const char* const RESOURCES_ANDROID_NAMESPACE;
|
||||
|
||||
bool isWhitespace(const char16_t* str);
|
||||
|
||||
String16 getNamespaceResourcePackage(String16 namespaceUri, bool* outIsPublic = NULL);
|
||||
|
||||
status_t parseStyledString(Bundle* bundle,
|
||||
const char* fileName,
|
||||
ResXMLTree* inXml,
|
||||
const String16& endTag,
|
||||
String16* outString,
|
||||
Vector<StringPool::entry_style_span>* outSpans,
|
||||
bool isFormatted,
|
||||
bool isPseudolocalizable);
|
||||
|
||||
void printXMLBlock(ResXMLTree* block);
|
||||
|
||||
status_t parseXMLResource(const sp<AaptFile>& file, ResXMLTree* outTree,
|
||||
bool stripAll=true, bool keepComments=false,
|
||||
const char** cDataTags=NULL);
|
||||
|
||||
class XMLNode : public RefBase
|
||||
{
|
||||
public:
|
||||
static sp<XMLNode> parse(const sp<AaptFile>& file);
|
||||
|
||||
static inline
|
||||
sp<XMLNode> newNamespace(const String8& filename, const String16& prefix, const String16& uri) {
|
||||
return new XMLNode(filename, prefix, uri, true);
|
||||
}
|
||||
|
||||
static inline
|
||||
sp<XMLNode> newElement(const String8& filename, const String16& ns, const String16& name) {
|
||||
return new XMLNode(filename, ns, name, false);
|
||||
}
|
||||
|
||||
static inline
|
||||
sp<XMLNode> newCData(const String8& filename) {
|
||||
return new XMLNode(filename);
|
||||
}
|
||||
|
||||
enum type {
|
||||
TYPE_NAMESPACE,
|
||||
TYPE_ELEMENT,
|
||||
TYPE_CDATA
|
||||
};
|
||||
|
||||
type getType() const;
|
||||
|
||||
const String16& getNamespacePrefix() const;
|
||||
const String16& getNamespaceUri() const;
|
||||
|
||||
const String16& getElementNamespace() const;
|
||||
const String16& getElementName() const;
|
||||
const Vector<sp<XMLNode> >& getChildren() const;
|
||||
|
||||
const String8& getFilename() const;
|
||||
|
||||
struct attribute_entry {
|
||||
attribute_entry() : index(~(uint32_t)0), nameResId(0)
|
||||
{
|
||||
value.dataType = Res_value::TYPE_NULL;
|
||||
}
|
||||
|
||||
bool needStringValue() const {
|
||||
return nameResId == 0
|
||||
|| value.dataType == Res_value::TYPE_NULL
|
||||
|| value.dataType == Res_value::TYPE_STRING;
|
||||
}
|
||||
|
||||
String16 ns;
|
||||
String16 name;
|
||||
String16 string;
|
||||
Res_value value;
|
||||
uint32_t index;
|
||||
uint32_t nameResId;
|
||||
mutable uint32_t namePoolIdx;
|
||||
};
|
||||
|
||||
const Vector<attribute_entry>& getAttributes() const;
|
||||
|
||||
const attribute_entry* getAttribute(const String16& ns, const String16& name) const;
|
||||
|
||||
attribute_entry* editAttribute(const String16& ns, const String16& name);
|
||||
|
||||
const String16& getCData() const;
|
||||
|
||||
const String16& getComment() const;
|
||||
|
||||
int32_t getStartLineNumber() const;
|
||||
int32_t getEndLineNumber() const;
|
||||
|
||||
sp<XMLNode> searchElement(const String16& tagNamespace, const String16& tagName);
|
||||
|
||||
sp<XMLNode> getChildElement(const String16& tagNamespace, const String16& tagName);
|
||||
|
||||
status_t addChild(const sp<XMLNode>& child);
|
||||
|
||||
status_t insertChildAt(const sp<XMLNode>& child, size_t index);
|
||||
|
||||
status_t addAttribute(const String16& ns, const String16& name,
|
||||
const String16& value);
|
||||
|
||||
void setAttributeResID(size_t attrIdx, uint32_t resId);
|
||||
|
||||
status_t appendChars(const String16& chars);
|
||||
|
||||
status_t appendComment(const String16& comment);
|
||||
|
||||
void setStartLineNumber(int32_t line);
|
||||
void setEndLineNumber(int32_t line);
|
||||
|
||||
void removeWhitespace(bool stripAll=true, const char** cDataTags=NULL);
|
||||
|
||||
void setUTF8(bool val) { mUTF8 = val; }
|
||||
|
||||
status_t parseValues(const sp<AaptAssets>& assets, ResourceTable* table);
|
||||
|
||||
status_t assignResourceIds(const sp<AaptAssets>& assets,
|
||||
const ResourceTable* table = NULL);
|
||||
|
||||
status_t flatten(const sp<AaptFile>& dest, bool stripComments,
|
||||
bool stripRawValues) const;
|
||||
|
||||
void print(int indent=0);
|
||||
|
||||
private:
|
||||
struct ParseState
|
||||
{
|
||||
String8 filename;
|
||||
XML_Parser parser;
|
||||
sp<XMLNode> root;
|
||||
Vector<sp<XMLNode> > stack;
|
||||
String16 pendingComment;
|
||||
};
|
||||
|
||||
static void XMLCALL
|
||||
startNamespace(void *userData, const char *prefix, const char *uri);
|
||||
static void XMLCALL
|
||||
startElement(void *userData, const char *name, const char **atts);
|
||||
static void XMLCALL
|
||||
characterData(void *userData, const XML_Char *s, int len);
|
||||
static void XMLCALL
|
||||
endElement(void *userData, const char *name);
|
||||
static void XMLCALL
|
||||
endNamespace(void *userData, const char *prefix);
|
||||
|
||||
static void XMLCALL
|
||||
commentData(void *userData, const char *comment);
|
||||
|
||||
// Creating an element node.
|
||||
XMLNode(const String8& filename, const String16& s1, const String16& s2, bool isNamespace);
|
||||
|
||||
// Creating a CDATA node.
|
||||
XMLNode(const String8& filename);
|
||||
|
||||
status_t collect_strings(StringPool* dest, Vector<uint32_t>* outResIds,
|
||||
bool stripComments, bool stripRawValues) const;
|
||||
|
||||
status_t collect_attr_strings(StringPool* outPool,
|
||||
Vector<uint32_t>* outResIds, bool allAttrs) const;
|
||||
|
||||
status_t collect_resid_strings(StringPool* outPool,
|
||||
Vector<uint32_t>* outResIds) const;
|
||||
|
||||
status_t flatten_node(const StringPool& strings, const sp<AaptFile>& dest,
|
||||
bool stripComments, bool stripRawValues) const;
|
||||
|
||||
String16 mNamespacePrefix;
|
||||
String16 mNamespaceUri;
|
||||
String16 mElementName;
|
||||
Vector<sp<XMLNode> > mChildren;
|
||||
Vector<attribute_entry> mAttributes;
|
||||
KeyedVector<uint32_t, uint32_t> mAttributeOrder;
|
||||
uint32_t mNextAttributeIndex;
|
||||
String16 mChars;
|
||||
Res_value mCharsValue;
|
||||
String16 mComment;
|
||||
String8 mFilename;
|
||||
int32_t mStartLineNumber;
|
||||
int32_t mEndLineNumber;
|
||||
|
||||
// Encode compiled XML with UTF-8 StringPools?
|
||||
bool mUTF8;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,696 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
// Access to entries in a Zip archive.
|
||||
//
|
||||
|
||||
#define LOG_TAG "zip"
|
||||
|
||||
#include "ZipEntry.h"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
/*
|
||||
* Initialize a new ZipEntry structure from a FILE* positioned at a
|
||||
* CentralDirectoryEntry.
|
||||
*
|
||||
* On exit, the file pointer will be at the start of the next CDE or
|
||||
* at the EOCD.
|
||||
*/
|
||||
status_t ZipEntry::initFromCDE(FILE* fp)
|
||||
{
|
||||
status_t result;
|
||||
long posn;
|
||||
bool hasDD;
|
||||
|
||||
//ALOGV("initFromCDE ---\n");
|
||||
|
||||
/* read the CDE */
|
||||
result = mCDE.read(fp);
|
||||
if (result != NO_ERROR) {
|
||||
ALOGD("mCDE.read failed\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
//mCDE.dump();
|
||||
|
||||
/* using the info in the CDE, go load up the LFH */
|
||||
posn = ftell(fp);
|
||||
if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
|
||||
ALOGD("local header seek failed (%ld)\n",
|
||||
mCDE.mLocalHeaderRelOffset);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
result = mLFH.read(fp);
|
||||
if (result != NO_ERROR) {
|
||||
ALOGD("mLFH.read failed\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (fseek(fp, posn, SEEK_SET) != 0)
|
||||
return UNKNOWN_ERROR;
|
||||
|
||||
//mLFH.dump();
|
||||
|
||||
/*
|
||||
* We *might* need to read the Data Descriptor at this point and
|
||||
* integrate it into the LFH. If this bit is set, the CRC-32,
|
||||
* compressed size, and uncompressed size will be zero. In practice
|
||||
* these seem to be rare.
|
||||
*/
|
||||
hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
|
||||
if (hasDD) {
|
||||
// do something clever
|
||||
//ALOGD("+++ has data descriptor\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
|
||||
* flag is set, because the LFH is incomplete. (Not a problem, since we
|
||||
* prefer the CDE values.)
|
||||
*/
|
||||
if (!hasDD && !compareHeaders()) {
|
||||
ALOGW("warning: header mismatch\n");
|
||||
// keep going?
|
||||
}
|
||||
|
||||
/*
|
||||
* If the mVersionToExtract is greater than 20, we may have an
|
||||
* issue unpacking the record -- could be encrypted, compressed
|
||||
* with something we don't support, or use Zip64 extensions. We
|
||||
* can defer worrying about that to when we're extracting data.
|
||||
*/
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a new entry. Pass in the file name and an optional comment.
|
||||
*
|
||||
* Initializes the CDE and the LFH.
|
||||
*/
|
||||
void ZipEntry::initNew(const char* fileName, const char* comment)
|
||||
{
|
||||
assert(fileName != NULL && *fileName != '\0'); // name required
|
||||
|
||||
/* most fields are properly initialized by constructor */
|
||||
mCDE.mVersionMadeBy = kDefaultMadeBy;
|
||||
mCDE.mVersionToExtract = kDefaultVersion;
|
||||
mCDE.mCompressionMethod = kCompressStored;
|
||||
mCDE.mFileNameLength = strlen(fileName);
|
||||
if (comment != NULL)
|
||||
mCDE.mFileCommentLength = strlen(comment);
|
||||
mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does
|
||||
|
||||
if (mCDE.mFileNameLength > 0) {
|
||||
mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
|
||||
strcpy((char*) mCDE.mFileName, fileName);
|
||||
}
|
||||
if (mCDE.mFileCommentLength > 0) {
|
||||
/* TODO: stop assuming null-terminated ASCII here? */
|
||||
mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
|
||||
strcpy((char*) mCDE.mFileComment, comment);
|
||||
}
|
||||
|
||||
copyCDEtoLFH();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a new entry, starting with the ZipEntry from a different
|
||||
* archive.
|
||||
*
|
||||
* Initializes the CDE and the LFH.
|
||||
*/
|
||||
status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
|
||||
const ZipEntry* pEntry)
|
||||
{
|
||||
/*
|
||||
* Copy everything in the CDE over, then fix up the hairy bits.
|
||||
*/
|
||||
memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
|
||||
|
||||
if (mCDE.mFileNameLength > 0) {
|
||||
mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
|
||||
if (mCDE.mFileName == NULL)
|
||||
return NO_MEMORY;
|
||||
strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
|
||||
}
|
||||
if (mCDE.mFileCommentLength > 0) {
|
||||
mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
|
||||
if (mCDE.mFileComment == NULL)
|
||||
return NO_MEMORY;
|
||||
strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
|
||||
}
|
||||
if (mCDE.mExtraFieldLength > 0) {
|
||||
/* we null-terminate this, though it may not be a string */
|
||||
mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
|
||||
if (mCDE.mExtraField == NULL)
|
||||
return NO_MEMORY;
|
||||
memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
|
||||
mCDE.mExtraFieldLength+1);
|
||||
}
|
||||
|
||||
/* construct the LFH from the CDE */
|
||||
copyCDEtoLFH();
|
||||
|
||||
/*
|
||||
* The LFH "extra" field is independent of the CDE "extra", so we
|
||||
* handle it here.
|
||||
*/
|
||||
assert(mLFH.mExtraField == NULL);
|
||||
mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
|
||||
if (mLFH.mExtraFieldLength > 0) {
|
||||
mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
|
||||
if (mLFH.mExtraField == NULL)
|
||||
return NO_MEMORY;
|
||||
memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
|
||||
mLFH.mExtraFieldLength+1);
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert pad bytes in the LFH by tweaking the "extra" field. This will
|
||||
* potentially confuse something that put "extra" data in here earlier,
|
||||
* but I can't find an actual problem.
|
||||
*/
|
||||
status_t ZipEntry::addPadding(int padding)
|
||||
{
|
||||
if (padding <= 0)
|
||||
return INVALID_OPERATION;
|
||||
|
||||
//ALOGI("HEY: adding %d pad bytes to existing %d in %s\n",
|
||||
// padding, mLFH.mExtraFieldLength, mCDE.mFileName);
|
||||
|
||||
if (mLFH.mExtraFieldLength > 0) {
|
||||
/* extend existing field */
|
||||
unsigned char* newExtra;
|
||||
|
||||
newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
|
||||
if (newExtra == NULL)
|
||||
return NO_MEMORY;
|
||||
memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
|
||||
memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
|
||||
|
||||
delete[] mLFH.mExtraField;
|
||||
mLFH.mExtraField = newExtra;
|
||||
mLFH.mExtraFieldLength += padding;
|
||||
} else {
|
||||
/* create new field */
|
||||
mLFH.mExtraField = new unsigned char[padding];
|
||||
memset(mLFH.mExtraField, 0, padding);
|
||||
mLFH.mExtraFieldLength = padding;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the fields in the LFH equal to the corresponding fields in the CDE.
|
||||
*
|
||||
* This does not touch the LFH "extra" field.
|
||||
*/
|
||||
void ZipEntry::copyCDEtoLFH(void)
|
||||
{
|
||||
mLFH.mVersionToExtract = mCDE.mVersionToExtract;
|
||||
mLFH.mGPBitFlag = mCDE.mGPBitFlag;
|
||||
mLFH.mCompressionMethod = mCDE.mCompressionMethod;
|
||||
mLFH.mLastModFileTime = mCDE.mLastModFileTime;
|
||||
mLFH.mLastModFileDate = mCDE.mLastModFileDate;
|
||||
mLFH.mCRC32 = mCDE.mCRC32;
|
||||
mLFH.mCompressedSize = mCDE.mCompressedSize;
|
||||
mLFH.mUncompressedSize = mCDE.mUncompressedSize;
|
||||
mLFH.mFileNameLength = mCDE.mFileNameLength;
|
||||
// the "extra field" is independent
|
||||
|
||||
delete[] mLFH.mFileName;
|
||||
if (mLFH.mFileNameLength > 0) {
|
||||
mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
|
||||
strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
|
||||
} else {
|
||||
mLFH.mFileName = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set some information about a file after we add it.
|
||||
*/
|
||||
void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
|
||||
int compressionMethod)
|
||||
{
|
||||
mCDE.mCompressionMethod = compressionMethod;
|
||||
mCDE.mCRC32 = crc32;
|
||||
mCDE.mCompressedSize = compLen;
|
||||
mCDE.mUncompressedSize = uncompLen;
|
||||
mCDE.mCompressionMethod = compressionMethod;
|
||||
if (compressionMethod == kCompressDeflated) {
|
||||
mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
|
||||
}
|
||||
copyCDEtoLFH();
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the data in mCDE and mLFH match up. This is mostly useful for
|
||||
* debugging these classes, but it can be used to identify damaged
|
||||
* archives.
|
||||
*
|
||||
* Returns "false" if they differ.
|
||||
*/
|
||||
bool ZipEntry::compareHeaders(void) const
|
||||
{
|
||||
if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
|
||||
ALOGV("cmp: VersionToExtract\n");
|
||||
return false;
|
||||
}
|
||||
if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
|
||||
ALOGV("cmp: GPBitFlag\n");
|
||||
return false;
|
||||
}
|
||||
if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
|
||||
ALOGV("cmp: CompressionMethod\n");
|
||||
return false;
|
||||
}
|
||||
if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
|
||||
ALOGV("cmp: LastModFileTime\n");
|
||||
return false;
|
||||
}
|
||||
if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
|
||||
ALOGV("cmp: LastModFileDate\n");
|
||||
return false;
|
||||
}
|
||||
if (mCDE.mCRC32 != mLFH.mCRC32) {
|
||||
ALOGV("cmp: CRC32\n");
|
||||
return false;
|
||||
}
|
||||
if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
|
||||
ALOGV("cmp: CompressedSize\n");
|
||||
return false;
|
||||
}
|
||||
if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
|
||||
ALOGV("cmp: UncompressedSize\n");
|
||||
return false;
|
||||
}
|
||||
if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
|
||||
ALOGV("cmp: FileNameLength\n");
|
||||
return false;
|
||||
}
|
||||
#if 0 // this seems to be used for padding, not real data
|
||||
if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
|
||||
ALOGV("cmp: ExtraFieldLength\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (mCDE.mFileName != NULL) {
|
||||
if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
|
||||
ALOGV("cmp: FileName\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert the DOS date/time stamp into a UNIX time stamp.
|
||||
*/
|
||||
time_t ZipEntry::getModWhen(void) const
|
||||
{
|
||||
struct tm parts;
|
||||
|
||||
parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
|
||||
parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
|
||||
parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
|
||||
parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
|
||||
parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
|
||||
parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
|
||||
parts.tm_wday = parts.tm_yday = 0;
|
||||
parts.tm_isdst = -1; // DST info "not available"
|
||||
|
||||
return mktime(&parts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the CDE/LFH timestamp from UNIX time.
|
||||
*/
|
||||
void ZipEntry::setModWhen(time_t when)
|
||||
{
|
||||
#ifdef HAVE_LOCALTIME_R
|
||||
struct tm tmResult;
|
||||
#endif
|
||||
time_t even;
|
||||
unsigned short zdate, ztime;
|
||||
|
||||
struct tm* ptm;
|
||||
|
||||
/* round up to an even number of seconds */
|
||||
even = (time_t)(((unsigned long)(when) + 1) & (~1));
|
||||
|
||||
/* expand */
|
||||
#ifdef HAVE_LOCALTIME_R
|
||||
ptm = localtime_r(&even, &tmResult);
|
||||
#else
|
||||
ptm = localtime(&even);
|
||||
#endif
|
||||
|
||||
int year;
|
||||
year = ptm->tm_year;
|
||||
if (year < 80)
|
||||
year = 80;
|
||||
|
||||
zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
|
||||
ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
|
||||
|
||||
mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
|
||||
mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* ZipEntry::LocalFileHeader
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Read a local file header.
|
||||
*
|
||||
* On entry, "fp" points to the signature at the start of the header.
|
||||
* On exit, "fp" points to the start of data.
|
||||
*/
|
||||
status_t ZipEntry::LocalFileHeader::read(FILE* fp)
|
||||
{
|
||||
status_t result = NO_ERROR;
|
||||
unsigned char buf[kLFHLen];
|
||||
|
||||
assert(mFileName == NULL);
|
||||
assert(mExtraField == NULL);
|
||||
|
||||
if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
|
||||
result = UNKNOWN_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
|
||||
ALOGD("whoops: didn't find expected signature\n");
|
||||
result = UNKNOWN_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
|
||||
mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
|
||||
mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
|
||||
mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
|
||||
mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
|
||||
mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
|
||||
mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
|
||||
mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
|
||||
mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
|
||||
mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
|
||||
|
||||
// TODO: validate sizes
|
||||
|
||||
/* grab filename */
|
||||
if (mFileNameLength != 0) {
|
||||
mFileName = new unsigned char[mFileNameLength+1];
|
||||
if (mFileName == NULL) {
|
||||
result = NO_MEMORY;
|
||||
goto bail;
|
||||
}
|
||||
if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
|
||||
result = UNKNOWN_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
mFileName[mFileNameLength] = '\0';
|
||||
}
|
||||
|
||||
/* grab extra field */
|
||||
if (mExtraFieldLength != 0) {
|
||||
mExtraField = new unsigned char[mExtraFieldLength+1];
|
||||
if (mExtraField == NULL) {
|
||||
result = NO_MEMORY;
|
||||
goto bail;
|
||||
}
|
||||
if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
|
||||
result = UNKNOWN_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
mExtraField[mExtraFieldLength] = '\0';
|
||||
}
|
||||
|
||||
bail:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a local file header.
|
||||
*/
|
||||
status_t ZipEntry::LocalFileHeader::write(FILE* fp)
|
||||
{
|
||||
unsigned char buf[kLFHLen];
|
||||
|
||||
ZipEntry::putLongLE(&buf[0x00], kSignature);
|
||||
ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
|
||||
ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
|
||||
ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
|
||||
ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
|
||||
ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
|
||||
ZipEntry::putLongLE(&buf[0x0e], mCRC32);
|
||||
ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
|
||||
ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
|
||||
ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
|
||||
ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
|
||||
|
||||
if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
|
||||
return UNKNOWN_ERROR;
|
||||
|
||||
/* write filename */
|
||||
if (mFileNameLength != 0) {
|
||||
if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
/* write "extra field" */
|
||||
if (mExtraFieldLength != 0) {
|
||||
if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Dump the contents of a LocalFileHeader object.
|
||||
*/
|
||||
void ZipEntry::LocalFileHeader::dump(void) const
|
||||
{
|
||||
ALOGD(" LocalFileHeader contents:\n");
|
||||
ALOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
|
||||
mVersionToExtract, mGPBitFlag, mCompressionMethod);
|
||||
ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
|
||||
mLastModFileTime, mLastModFileDate, mCRC32);
|
||||
ALOGD(" compressedSize=%lu uncompressedSize=%lu\n",
|
||||
mCompressedSize, mUncompressedSize);
|
||||
ALOGD(" filenameLen=%u extraLen=%u\n",
|
||||
mFileNameLength, mExtraFieldLength);
|
||||
if (mFileName != NULL)
|
||||
ALOGD(" filename: '%s'\n", mFileName);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* ZipEntry::CentralDirEntry
|
||||
* ===========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* Read the central dir entry that appears next in the file.
|
||||
*
|
||||
* On entry, "fp" should be positioned on the signature bytes for the
|
||||
* entry. On exit, "fp" will point at the signature word for the next
|
||||
* entry or for the EOCD.
|
||||
*/
|
||||
status_t ZipEntry::CentralDirEntry::read(FILE* fp)
|
||||
{
|
||||
status_t result = NO_ERROR;
|
||||
unsigned char buf[kCDELen];
|
||||
|
||||
/* no re-use */
|
||||
assert(mFileName == NULL);
|
||||
assert(mExtraField == NULL);
|
||||
assert(mFileComment == NULL);
|
||||
|
||||
if (fread(buf, 1, kCDELen, fp) != kCDELen) {
|
||||
result = UNKNOWN_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
|
||||
ALOGD("Whoops: didn't find expected signature\n");
|
||||
result = UNKNOWN_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
|
||||
mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
|
||||
mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
|
||||
mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
|
||||
mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
|
||||
mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
|
||||
mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
|
||||
mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
|
||||
mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
|
||||
mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
|
||||
mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
|
||||
mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
|
||||
mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
|
||||
mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
|
||||
mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
|
||||
mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
|
||||
|
||||
// TODO: validate sizes and offsets
|
||||
|
||||
/* grab filename */
|
||||
if (mFileNameLength != 0) {
|
||||
mFileName = new unsigned char[mFileNameLength+1];
|
||||
if (mFileName == NULL) {
|
||||
result = NO_MEMORY;
|
||||
goto bail;
|
||||
}
|
||||
if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
|
||||
result = UNKNOWN_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
mFileName[mFileNameLength] = '\0';
|
||||
}
|
||||
|
||||
/* read "extra field" */
|
||||
if (mExtraFieldLength != 0) {
|
||||
mExtraField = new unsigned char[mExtraFieldLength+1];
|
||||
if (mExtraField == NULL) {
|
||||
result = NO_MEMORY;
|
||||
goto bail;
|
||||
}
|
||||
if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
|
||||
result = UNKNOWN_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
mExtraField[mExtraFieldLength] = '\0';
|
||||
}
|
||||
|
||||
|
||||
/* grab comment, if any */
|
||||
if (mFileCommentLength != 0) {
|
||||
mFileComment = new unsigned char[mFileCommentLength+1];
|
||||
if (mFileComment == NULL) {
|
||||
result = NO_MEMORY;
|
||||
goto bail;
|
||||
}
|
||||
if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
|
||||
{
|
||||
result = UNKNOWN_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
mFileComment[mFileCommentLength] = '\0';
|
||||
}
|
||||
|
||||
bail:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a central dir entry.
|
||||
*/
|
||||
status_t ZipEntry::CentralDirEntry::write(FILE* fp)
|
||||
{
|
||||
unsigned char buf[kCDELen];
|
||||
|
||||
ZipEntry::putLongLE(&buf[0x00], kSignature);
|
||||
ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
|
||||
ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
|
||||
ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
|
||||
ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
|
||||
ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
|
||||
ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
|
||||
ZipEntry::putLongLE(&buf[0x10], mCRC32);
|
||||
ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
|
||||
ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
|
||||
ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
|
||||
ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
|
||||
ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
|
||||
ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
|
||||
ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
|
||||
ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
|
||||
ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
|
||||
|
||||
if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
|
||||
return UNKNOWN_ERROR;
|
||||
|
||||
/* write filename */
|
||||
if (mFileNameLength != 0) {
|
||||
if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
/* write "extra field" */
|
||||
if (mExtraFieldLength != 0) {
|
||||
if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
/* write comment */
|
||||
if (mFileCommentLength != 0) {
|
||||
if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump the contents of a CentralDirEntry object.
|
||||
*/
|
||||
void ZipEntry::CentralDirEntry::dump(void) const
|
||||
{
|
||||
ALOGD(" CentralDirEntry contents:\n");
|
||||
ALOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
|
||||
mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
|
||||
ALOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
|
||||
mLastModFileTime, mLastModFileDate, mCRC32);
|
||||
ALOGD(" compressedSize=%lu uncompressedSize=%lu\n",
|
||||
mCompressedSize, mUncompressedSize);
|
||||
ALOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
|
||||
mFileNameLength, mExtraFieldLength, mFileCommentLength);
|
||||
ALOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
|
||||
mDiskNumberStart, mInternalAttrs, mExternalAttrs,
|
||||
mLocalHeaderRelOffset);
|
||||
|
||||
if (mFileName != NULL)
|
||||
ALOGD(" filename: '%s'\n", mFileName);
|
||||
if (mFileComment != NULL)
|
||||
ALOGD(" comment: '%s'\n", mFileComment);
|
||||
}
|
||||
|
||||
@@ -1,345 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
// Zip archive entries.
|
||||
//
|
||||
// The ZipEntry class is tightly meshed with the ZipFile class.
|
||||
//
|
||||
#ifndef __LIBS_ZIPENTRY_H
|
||||
#define __LIBS_ZIPENTRY_H
|
||||
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class ZipFile;
|
||||
|
||||
/*
|
||||
* ZipEntry objects represent a single entry in a Zip archive.
|
||||
*
|
||||
* You can use one of these to get or set information about an entry, but
|
||||
* there are no functions here for accessing the data itself. (We could
|
||||
* tuck a pointer to the ZipFile in here for convenience, but that raises
|
||||
* the likelihood of using ZipEntry objects after discarding the ZipFile.)
|
||||
*
|
||||
* File information is stored in two places: next to the file data (the Local
|
||||
* File Header, and possibly a Data Descriptor), and at the end of the file
|
||||
* (the Central Directory Entry). The two must be kept in sync.
|
||||
*/
|
||||
class ZipEntry {
|
||||
public:
|
||||
friend class ZipFile;
|
||||
|
||||
ZipEntry(void)
|
||||
: mDeleted(false), mMarked(false)
|
||||
{}
|
||||
~ZipEntry(void) {}
|
||||
|
||||
/*
|
||||
* Returns "true" if the data is compressed.
|
||||
*/
|
||||
bool isCompressed(void) const {
|
||||
return mCDE.mCompressionMethod != kCompressStored;
|
||||
}
|
||||
int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
|
||||
|
||||
/*
|
||||
* Return the uncompressed length.
|
||||
*/
|
||||
off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
|
||||
|
||||
/*
|
||||
* Return the compressed length. For uncompressed data, this returns
|
||||
* the same thing as getUncompresesdLen().
|
||||
*/
|
||||
off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
|
||||
|
||||
/*
|
||||
* Return the offset of the local file header.
|
||||
*/
|
||||
off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
|
||||
|
||||
/*
|
||||
* Return the absolute file offset of the start of the compressed or
|
||||
* uncompressed data.
|
||||
*/
|
||||
off_t getFileOffset(void) const {
|
||||
return mCDE.mLocalHeaderRelOffset +
|
||||
LocalFileHeader::kLFHLen +
|
||||
mLFH.mFileNameLength +
|
||||
mLFH.mExtraFieldLength;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the data CRC.
|
||||
*/
|
||||
unsigned long getCRC32(void) const { return mCDE.mCRC32; }
|
||||
|
||||
/*
|
||||
* Return file modification time in UNIX seconds-since-epoch.
|
||||
*/
|
||||
time_t getModWhen(void) const;
|
||||
|
||||
/*
|
||||
* Return the archived file name.
|
||||
*/
|
||||
const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
|
||||
|
||||
/*
|
||||
* Application-defined "mark". Can be useful when synchronizing the
|
||||
* contents of an archive with contents on disk.
|
||||
*/
|
||||
bool getMarked(void) const { return mMarked; }
|
||||
void setMarked(bool val) { mMarked = val; }
|
||||
|
||||
/*
|
||||
* Some basic functions for raw data manipulation. "LE" means
|
||||
* Little Endian.
|
||||
*/
|
||||
static inline unsigned short getShortLE(const unsigned char* buf) {
|
||||
return buf[0] | (buf[1] << 8);
|
||||
}
|
||||
static inline unsigned long getLongLE(const unsigned char* buf) {
|
||||
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
}
|
||||
static inline void putShortLE(unsigned char* buf, short val) {
|
||||
buf[0] = (unsigned char) val;
|
||||
buf[1] = (unsigned char) (val >> 8);
|
||||
}
|
||||
static inline void putLongLE(unsigned char* buf, long val) {
|
||||
buf[0] = (unsigned char) val;
|
||||
buf[1] = (unsigned char) (val >> 8);
|
||||
buf[2] = (unsigned char) (val >> 16);
|
||||
buf[3] = (unsigned char) (val >> 24);
|
||||
}
|
||||
|
||||
/* defined for Zip archives */
|
||||
enum {
|
||||
kCompressStored = 0, // no compression
|
||||
// shrunk = 1,
|
||||
// reduced 1 = 2,
|
||||
// reduced 2 = 3,
|
||||
// reduced 3 = 4,
|
||||
// reduced 4 = 5,
|
||||
// imploded = 6,
|
||||
// tokenized = 7,
|
||||
kCompressDeflated = 8, // standard deflate
|
||||
// Deflate64 = 9,
|
||||
// lib imploded = 10,
|
||||
// reserved = 11,
|
||||
// bzip2 = 12,
|
||||
};
|
||||
|
||||
/*
|
||||
* Deletion flag. If set, the entry will be removed on the next
|
||||
* call to "flush".
|
||||
*/
|
||||
bool getDeleted(void) const { return mDeleted; }
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Initialize the structure from the file, which is pointing at
|
||||
* our Central Directory entry.
|
||||
*/
|
||||
status_t initFromCDE(FILE* fp);
|
||||
|
||||
/*
|
||||
* Initialize the structure for a new file. We need the filename
|
||||
* and comment so that we can properly size the LFH area. The
|
||||
* filename is mandatory, the comment is optional.
|
||||
*/
|
||||
void initNew(const char* fileName, const char* comment);
|
||||
|
||||
/*
|
||||
* Initialize the structure with the contents of a ZipEntry from
|
||||
* another file.
|
||||
*/
|
||||
status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
|
||||
|
||||
/*
|
||||
* Add some pad bytes to the LFH. We do this by adding or resizing
|
||||
* the "extra" field.
|
||||
*/
|
||||
status_t addPadding(int padding);
|
||||
|
||||
/*
|
||||
* Set information about the data for this entry.
|
||||
*/
|
||||
void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
|
||||
int compressionMethod);
|
||||
|
||||
/*
|
||||
* Set the modification date.
|
||||
*/
|
||||
void setModWhen(time_t when);
|
||||
|
||||
/*
|
||||
* Set the offset of the local file header, relative to the start of
|
||||
* the current file.
|
||||
*/
|
||||
void setLFHOffset(off_t offset) {
|
||||
mCDE.mLocalHeaderRelOffset = (long) offset;
|
||||
}
|
||||
|
||||
/* mark for deletion; used by ZipFile::remove() */
|
||||
void setDeleted(void) { mDeleted = true; }
|
||||
|
||||
private:
|
||||
/* these are private and not defined */
|
||||
ZipEntry(const ZipEntry& src);
|
||||
ZipEntry& operator=(const ZipEntry& src);
|
||||
|
||||
/* returns "true" if the CDE and the LFH agree */
|
||||
bool compareHeaders(void) const;
|
||||
void copyCDEtoLFH(void);
|
||||
|
||||
bool mDeleted; // set if entry is pending deletion
|
||||
bool mMarked; // app-defined marker
|
||||
|
||||
/*
|
||||
* Every entry in the Zip archive starts off with one of these.
|
||||
*/
|
||||
class LocalFileHeader {
|
||||
public:
|
||||
LocalFileHeader(void) :
|
||||
mVersionToExtract(0),
|
||||
mGPBitFlag(0),
|
||||
mCompressionMethod(0),
|
||||
mLastModFileTime(0),
|
||||
mLastModFileDate(0),
|
||||
mCRC32(0),
|
||||
mCompressedSize(0),
|
||||
mUncompressedSize(0),
|
||||
mFileNameLength(0),
|
||||
mExtraFieldLength(0),
|
||||
mFileName(NULL),
|
||||
mExtraField(NULL)
|
||||
{}
|
||||
virtual ~LocalFileHeader(void) {
|
||||
delete[] mFileName;
|
||||
delete[] mExtraField;
|
||||
}
|
||||
|
||||
status_t read(FILE* fp);
|
||||
status_t write(FILE* fp);
|
||||
|
||||
// unsigned long mSignature;
|
||||
unsigned short mVersionToExtract;
|
||||
unsigned short mGPBitFlag;
|
||||
unsigned short mCompressionMethod;
|
||||
unsigned short mLastModFileTime;
|
||||
unsigned short mLastModFileDate;
|
||||
unsigned long mCRC32;
|
||||
unsigned long mCompressedSize;
|
||||
unsigned long mUncompressedSize;
|
||||
unsigned short mFileNameLength;
|
||||
unsigned short mExtraFieldLength;
|
||||
unsigned char* mFileName;
|
||||
unsigned char* mExtraField;
|
||||
|
||||
enum {
|
||||
kSignature = 0x04034b50,
|
||||
kLFHLen = 30, // LocalFileHdr len, excl. var fields
|
||||
};
|
||||
|
||||
void dump(void) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Every entry in the Zip archive has one of these in the "central
|
||||
* directory" at the end of the file.
|
||||
*/
|
||||
class CentralDirEntry {
|
||||
public:
|
||||
CentralDirEntry(void) :
|
||||
mVersionMadeBy(0),
|
||||
mVersionToExtract(0),
|
||||
mGPBitFlag(0),
|
||||
mCompressionMethod(0),
|
||||
mLastModFileTime(0),
|
||||
mLastModFileDate(0),
|
||||
mCRC32(0),
|
||||
mCompressedSize(0),
|
||||
mUncompressedSize(0),
|
||||
mFileNameLength(0),
|
||||
mExtraFieldLength(0),
|
||||
mFileCommentLength(0),
|
||||
mDiskNumberStart(0),
|
||||
mInternalAttrs(0),
|
||||
mExternalAttrs(0),
|
||||
mLocalHeaderRelOffset(0),
|
||||
mFileName(NULL),
|
||||
mExtraField(NULL),
|
||||
mFileComment(NULL)
|
||||
{}
|
||||
virtual ~CentralDirEntry(void) {
|
||||
delete[] mFileName;
|
||||
delete[] mExtraField;
|
||||
delete[] mFileComment;
|
||||
}
|
||||
|
||||
status_t read(FILE* fp);
|
||||
status_t write(FILE* fp);
|
||||
|
||||
// unsigned long mSignature;
|
||||
unsigned short mVersionMadeBy;
|
||||
unsigned short mVersionToExtract;
|
||||
unsigned short mGPBitFlag;
|
||||
unsigned short mCompressionMethod;
|
||||
unsigned short mLastModFileTime;
|
||||
unsigned short mLastModFileDate;
|
||||
unsigned long mCRC32;
|
||||
unsigned long mCompressedSize;
|
||||
unsigned long mUncompressedSize;
|
||||
unsigned short mFileNameLength;
|
||||
unsigned short mExtraFieldLength;
|
||||
unsigned short mFileCommentLength;
|
||||
unsigned short mDiskNumberStart;
|
||||
unsigned short mInternalAttrs;
|
||||
unsigned long mExternalAttrs;
|
||||
unsigned long mLocalHeaderRelOffset;
|
||||
unsigned char* mFileName;
|
||||
unsigned char* mExtraField;
|
||||
unsigned char* mFileComment;
|
||||
|
||||
void dump(void) const;
|
||||
|
||||
enum {
|
||||
kSignature = 0x02014b50,
|
||||
kCDELen = 46, // CentralDirEnt len, excl. var fields
|
||||
};
|
||||
};
|
||||
|
||||
enum {
|
||||
//kDataDescriptorSignature = 0x08074b50, // currently unused
|
||||
kDataDescriptorLen = 16, // four 32-bit fields
|
||||
|
||||
kDefaultVersion = 20, // need deflate, nothing much else
|
||||
kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
|
||||
kUsesDataDescr = 0x0008, // GPBitFlag bit 3
|
||||
};
|
||||
|
||||
LocalFileHeader mLFH;
|
||||
CentralDirEntry mCDE;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // __LIBS_ZIPENTRY_H
|
||||
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
// General-purpose Zip archive access. This class allows both reading and
|
||||
// writing to Zip archives, including deletion of existing entries.
|
||||
//
|
||||
#ifndef __LIBS_ZIPFILE_H
|
||||
#define __LIBS_ZIPFILE_H
|
||||
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ZipEntry.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Manipulate a Zip archive.
|
||||
*
|
||||
* Some changes will not be visible in the until until "flush" is called.
|
||||
*
|
||||
* The correct way to update a file archive is to make all changes to a
|
||||
* copy of the archive in a temporary file, and then unlink/rename over
|
||||
* the original after everything completes. Because we're only interested
|
||||
* in using this for packaging, we don't worry about such things. Crashing
|
||||
* after making changes and before flush() completes could leave us with
|
||||
* an unusable Zip archive.
|
||||
*/
|
||||
class ZipFile {
|
||||
public:
|
||||
ZipFile(void)
|
||||
: mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
|
||||
{}
|
||||
~ZipFile(void) {
|
||||
if (!mReadOnly)
|
||||
flush();
|
||||
if (mZipFp != NULL)
|
||||
fclose(mZipFp);
|
||||
discardEntries();
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a new or existing archive.
|
||||
*/
|
||||
enum {
|
||||
kOpenReadOnly = 0x01,
|
||||
kOpenReadWrite = 0x02,
|
||||
kOpenCreate = 0x04, // create if it doesn't exist
|
||||
kOpenTruncate = 0x08, // if it exists, empty it
|
||||
};
|
||||
status_t open(const char* zipFileName, int flags);
|
||||
|
||||
/*
|
||||
* Add a file to the end of the archive. Specify whether you want the
|
||||
* library to try to store it compressed.
|
||||
*
|
||||
* If "storageName" is specified, the archive will use that instead
|
||||
* of "fileName".
|
||||
*
|
||||
* If there is already an entry with the same name, the call fails.
|
||||
* Existing entries with the same name must be removed first.
|
||||
*
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t add(const char* fileName, int compressionMethod,
|
||||
ZipEntry** ppEntry)
|
||||
{
|
||||
return add(fileName, fileName, compressionMethod, ppEntry);
|
||||
}
|
||||
status_t add(const char* fileName, const char* storageName,
|
||||
int compressionMethod, ZipEntry** ppEntry)
|
||||
{
|
||||
return addCommon(fileName, NULL, 0, storageName,
|
||||
ZipEntry::kCompressStored,
|
||||
compressionMethod, ppEntry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a file that is already compressed with gzip.
|
||||
*
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t addGzip(const char* fileName, const char* storageName,
|
||||
ZipEntry** ppEntry)
|
||||
{
|
||||
return addCommon(fileName, NULL, 0, storageName,
|
||||
ZipEntry::kCompressDeflated,
|
||||
ZipEntry::kCompressDeflated, ppEntry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a file from an in-memory data buffer.
|
||||
*
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t add(const void* data, size_t size, const char* storageName,
|
||||
int compressionMethod, ZipEntry** ppEntry)
|
||||
{
|
||||
return addCommon(NULL, data, size, storageName,
|
||||
ZipEntry::kCompressStored,
|
||||
compressionMethod, ppEntry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an entry by copying it from another zip file. If "padding" is
|
||||
* nonzero, the specified number of bytes will be added to the "extra"
|
||||
* field in the header.
|
||||
*
|
||||
* If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
|
||||
*/
|
||||
status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
|
||||
int padding, ZipEntry** ppEntry);
|
||||
|
||||
/*
|
||||
* Mark an entry as having been removed. It is not actually deleted
|
||||
* from the archive or our internal data structures until flush() is
|
||||
* called.
|
||||
*/
|
||||
status_t remove(ZipEntry* pEntry);
|
||||
|
||||
/*
|
||||
* Flush changes. If mNeedCDRewrite is set, this writes the central dir.
|
||||
*/
|
||||
status_t flush(void);
|
||||
|
||||
/*
|
||||
* Expand the data into the buffer provided. The buffer must hold
|
||||
* at least <uncompressed len> bytes. Variation expands directly
|
||||
* to a file.
|
||||
*
|
||||
* Returns "false" if an error was encountered in the compressed data.
|
||||
*/
|
||||
//bool uncompress(const ZipEntry* pEntry, void* buf) const;
|
||||
//bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
|
||||
void* uncompress(const ZipEntry* pEntry);
|
||||
|
||||
/*
|
||||
* Get an entry, by name. Returns NULL if not found.
|
||||
*
|
||||
* Does not return entries pending deletion.
|
||||
*/
|
||||
ZipEntry* getEntryByName(const char* fileName) const;
|
||||
|
||||
/*
|
||||
* Get the Nth entry in the archive.
|
||||
*
|
||||
* This will return an entry that is pending deletion.
|
||||
*/
|
||||
int getNumEntries(void) const { return mEntries.size(); }
|
||||
ZipEntry* getEntryByIndex(int idx) const;
|
||||
|
||||
private:
|
||||
/* these are private and not defined */
|
||||
ZipFile(const ZipFile& src);
|
||||
ZipFile& operator=(const ZipFile& src);
|
||||
|
||||
class EndOfCentralDir {
|
||||
public:
|
||||
EndOfCentralDir(void) :
|
||||
mDiskNumber(0),
|
||||
mDiskWithCentralDir(0),
|
||||
mNumEntries(0),
|
||||
mTotalNumEntries(0),
|
||||
mCentralDirSize(0),
|
||||
mCentralDirOffset(0),
|
||||
mCommentLen(0),
|
||||
mComment(NULL)
|
||||
{}
|
||||
virtual ~EndOfCentralDir(void) {
|
||||
delete[] mComment;
|
||||
}
|
||||
|
||||
status_t readBuf(const unsigned char* buf, int len);
|
||||
status_t write(FILE* fp);
|
||||
|
||||
//unsigned long mSignature;
|
||||
unsigned short mDiskNumber;
|
||||
unsigned short mDiskWithCentralDir;
|
||||
unsigned short mNumEntries;
|
||||
unsigned short mTotalNumEntries;
|
||||
unsigned long mCentralDirSize;
|
||||
unsigned long mCentralDirOffset; // offset from first disk
|
||||
unsigned short mCommentLen;
|
||||
unsigned char* mComment;
|
||||
|
||||
enum {
|
||||
kSignature = 0x06054b50,
|
||||
kEOCDLen = 22, // EndOfCentralDir len, excl. comment
|
||||
|
||||
kMaxCommentLen = 65535, // longest possible in ushort
|
||||
kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
|
||||
|
||||
};
|
||||
|
||||
void dump(void) const;
|
||||
};
|
||||
|
||||
|
||||
/* read all entries in the central dir */
|
||||
status_t readCentralDir(void);
|
||||
|
||||
/* crunch deleted entries out */
|
||||
status_t crunchArchive(void);
|
||||
|
||||
/* clean up mEntries */
|
||||
void discardEntries(void);
|
||||
|
||||
/* common handler for all "add" functions */
|
||||
status_t addCommon(const char* fileName, const void* data, size_t size,
|
||||
const char* storageName, int sourceType, int compressionMethod,
|
||||
ZipEntry** ppEntry);
|
||||
|
||||
/* copy all of "srcFp" into "dstFp" */
|
||||
status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
|
||||
/* copy all of "data" into "dstFp" */
|
||||
status_t copyDataToFp(FILE* dstFp,
|
||||
const void* data, size_t size, unsigned long* pCRC32);
|
||||
/* copy some of "srcFp" into "dstFp" */
|
||||
status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
|
||||
unsigned long* pCRC32);
|
||||
/* like memmove(), but on parts of a single file */
|
||||
status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
|
||||
/* compress all of "srcFp" into "dstFp", using Deflate */
|
||||
status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
|
||||
const void* data, size_t size, unsigned long* pCRC32);
|
||||
|
||||
/* get modification date from a file descriptor */
|
||||
time_t getModTime(int fd);
|
||||
|
||||
/*
|
||||
* We use stdio FILE*, which gives us buffering but makes dealing
|
||||
* with files >2GB awkward. Until we support Zip64, we're fine.
|
||||
*/
|
||||
FILE* mZipFp; // Zip file pointer
|
||||
|
||||
/* one of these per file */
|
||||
EndOfCentralDir mEOCD;
|
||||
|
||||
/* did we open this read-only? */
|
||||
bool mReadOnly;
|
||||
|
||||
/* set this when we trash the central dir */
|
||||
bool mNeedCDRewrite;
|
||||
|
||||
/*
|
||||
* One ZipEntry per entry in the zip file. I'm using pointers instead
|
||||
* of objects because it's easier than making operator= work for the
|
||||
* classes and sub-classes.
|
||||
*/
|
||||
Vector<ZipEntry*> mEntries;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // __LIBS_ZIPFILE_H
|
||||
@@ -1,127 +0,0 @@
|
||||
#include <utils/ResourceTypes.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/String16.h>
|
||||
#include <zipfile/zipfile.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
static int
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: apk APKFILE\n"
|
||||
"\n"
|
||||
"APKFILE an android packge file produced by aapt.\n"
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
const char* filename;
|
||||
int fd;
|
||||
ssize_t amt;
|
||||
off_t size;
|
||||
void* buf;
|
||||
zipfile_t zip;
|
||||
zipentry_t entry;
|
||||
void* cookie;
|
||||
void* resfile;
|
||||
int bufsize;
|
||||
int err;
|
||||
|
||||
if (argc != 2) {
|
||||
return usage();
|
||||
}
|
||||
|
||||
filename = argv[1];
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "apk: couldn't open file for read: %s\n", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
amt = lseek(fd, 0, SEEK_SET);
|
||||
|
||||
if (size < 0 || amt < 0) {
|
||||
fprintf(stderr, "apk: error determining file size: %s\n", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf = malloc(size);
|
||||
if (buf == NULL) {
|
||||
fprintf(stderr, "apk: file too big: %s\n", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
amt = read(fd, buf, size);
|
||||
if (amt != size) {
|
||||
fprintf(stderr, "apk: error reading file: %s\n", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
zip = init_zipfile(buf, size);
|
||||
if (zip == NULL) {
|
||||
fprintf(stderr, "apk: file doesn't seem to be a zip file: %s\n",
|
||||
filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("files:\n");
|
||||
cookie = NULL;
|
||||
while ((entry = iterate_zipfile(zip, &cookie))) {
|
||||
char* name = get_zipentry_name(entry);
|
||||
printf(" %s\n", name);
|
||||
free(name);
|
||||
}
|
||||
|
||||
entry = lookup_zipentry(zip, "resources.arsc");
|
||||
if (entry != NULL) {
|
||||
size = get_zipentry_size(entry);
|
||||
bufsize = size + (size / 1000) + 1;
|
||||
resfile = malloc(bufsize);
|
||||
|
||||
err = decompress_zipentry(entry, resfile, bufsize);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "apk: error decompressing resources.arsc");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ResTable res(resfile, size, resfile);
|
||||
res.print();
|
||||
#if 0
|
||||
size_t tableCount = res.getTableCount();
|
||||
printf("Tables: %d\n", (int)tableCount);
|
||||
for (size_t tableIndex=0; tableIndex<tableCount; tableIndex++) {
|
||||
const ResStringPool* strings = res.getTableStringBlock(tableIndex);
|
||||
size_t stringCount = strings->size();
|
||||
for (size_t stringIndex=0; stringIndex<stringCount; stringIndex++) {
|
||||
size_t len;
|
||||
const char16_t* ch = strings->stringAt(stringIndex, &len);
|
||||
String8 s(String16(ch, len));
|
||||
printf(" [%3d] %s\n", (int)stringIndex, s.string());
|
||||
}
|
||||
}
|
||||
|
||||
size_t basePackageCount = res.getBasePackageCount();
|
||||
printf("Base Packages: %d\n", (int)basePackageCount);
|
||||
for (size_t bpIndex=0; bpIndex<basePackageCount; bpIndex++) {
|
||||
const char16_t* ch = res.getBasePackageName(bpIndex);
|
||||
String8 s = String8(String16(ch));
|
||||
printf(" [%3d] %s\n", (int)bpIndex, s.string());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
#include "pseudolocalize.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const char*
|
||||
pseudolocalize_char(char c)
|
||||
{
|
||||
switch (c) {
|
||||
case 'a': return "\xc4\x83";
|
||||
case 'b': return "\xcf\x84";
|
||||
case 'c': return "\xc4\x8b";
|
||||
case 'd': return "\xc4\x8f";
|
||||
case 'e': return "\xc4\x99";
|
||||
case 'f': return "\xc6\x92";
|
||||
case 'g': return "\xc4\x9d";
|
||||
case 'h': return "\xd1\x9b";
|
||||
case 'i': return "\xcf\x8a";
|
||||
case 'j': return "\xc4\xb5";
|
||||
case 'k': return "\xc4\xb8";
|
||||
case 'l': return "\xc4\xba";
|
||||
case 'm': return "\xe1\xb8\xbf";
|
||||
case 'n': return "\xd0\xb8";
|
||||
case 'o': return "\xcf\x8c";
|
||||
case 'p': return "\xcf\x81";
|
||||
case 'q': return "\x51";
|
||||
case 'r': return "\xd2\x91";
|
||||
case 's': return "\xc5\xa1";
|
||||
case 't': return "\xd1\x82";
|
||||
case 'u': return "\xce\xb0";
|
||||
case 'v': return "\x56";
|
||||
case 'w': return "\xe1\xba\x85";
|
||||
case 'x': return "\xd1\x85";
|
||||
case 'y': return "\xe1\xbb\xb3";
|
||||
case 'z': return "\xc5\xba";
|
||||
case 'A': return "\xc3\x85";
|
||||
case 'B': return "\xce\xb2";
|
||||
case 'C': return "\xc4\x88";
|
||||
case 'D': return "\xc4\x90";
|
||||
case 'E': return "\xd0\x84";
|
||||
case 'F': return "\xce\x93";
|
||||
case 'G': return "\xc4\x9e";
|
||||
case 'H': return "\xc4\xa6";
|
||||
case 'I': return "\xd0\x87";
|
||||
case 'J': return "\xc4\xb5";
|
||||
case 'K': return "\xc4\xb6";
|
||||
case 'L': return "\xc5\x81";
|
||||
case 'M': return "\xe1\xb8\xbe";
|
||||
case 'N': return "\xc5\x83";
|
||||
case 'O': return "\xce\x98";
|
||||
case 'P': return "\xcf\x81";
|
||||
case 'Q': return "\x71";
|
||||
case 'R': return "\xd0\xaf";
|
||||
case 'S': return "\xc8\x98";
|
||||
case 'T': return "\xc5\xa6";
|
||||
case 'U': return "\xc5\xa8";
|
||||
case 'V': return "\xce\xbd";
|
||||
case 'W': return "\xe1\xba\x84";
|
||||
case 'X': return "\xc3\x97";
|
||||
case 'Y': return "\xc2\xa5";
|
||||
case 'Z': return "\xc5\xbd";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts characters so they look like they've been localized.
|
||||
*
|
||||
* Note: This leaves escape sequences untouched so they can later be
|
||||
* processed by ResTable::collectString in the normal way.
|
||||
*/
|
||||
string
|
||||
pseudolocalize_string(const string& source)
|
||||
{
|
||||
const char* s = source.c_str();
|
||||
string result;
|
||||
const size_t I = source.length();
|
||||
for (size_t i=0; i<I; i++) {
|
||||
char c = s[i];
|
||||
if (c == '\\') {
|
||||
if (i<I-1) {
|
||||
result += '\\';
|
||||
i++;
|
||||
c = s[i];
|
||||
switch (c) {
|
||||
case 'u':
|
||||
// this one takes up 5 chars
|
||||
result += string(s+i, 5);
|
||||
i += 4;
|
||||
break;
|
||||
case 't':
|
||||
case 'n':
|
||||
case '#':
|
||||
case '@':
|
||||
case '?':
|
||||
case '"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
default:
|
||||
result += c;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result += c;
|
||||
}
|
||||
} else {
|
||||
const char* p = pseudolocalize_char(c);
|
||||
if (p != NULL) {
|
||||
result += p;
|
||||
} else {
|
||||
result += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printf("result=\'%s\'\n", result.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef HOST_PSEUDOLOCALIZE_H
|
||||
#define HOST_PSEUDOLOCALIZE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string pseudolocalize_string(const std::string& source);
|
||||
|
||||
#endif // HOST_PSEUDOLOCALIZE_H
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "qsort_r_compat.h"
|
||||
|
||||
/*
|
||||
* Note: This code is only used on the host, and is primarily here for
|
||||
* Mac OS compatibility. Apparently, glibc and Apple's libc disagree on
|
||||
* the parameter order for qsort_r.
|
||||
*/
|
||||
|
||||
#if HAVE_BSD_QSORT_R
|
||||
|
||||
/*
|
||||
* BSD qsort_r parameter order is as we have defined here.
|
||||
*/
|
||||
|
||||
void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
|
||||
int (*compar)(void*, const void* , const void*)) {
|
||||
qsort_r(base, nel, width, thunk, compar);
|
||||
}
|
||||
|
||||
#elif HAVE_GNU_QSORT_R
|
||||
|
||||
/*
|
||||
* GNU qsort_r parameter order places the thunk parameter last.
|
||||
*/
|
||||
|
||||
struct compar_data {
|
||||
void* thunk;
|
||||
int (*compar)(void*, const void* , const void*);
|
||||
};
|
||||
|
||||
static int compar_wrapper(const void* a, const void* b, void* data) {
|
||||
struct compar_data* compar_data = (struct compar_data*)data;
|
||||
return compar_data->compar(compar_data->thunk, a, b);
|
||||
}
|
||||
|
||||
void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
|
||||
int (*compar)(void*, const void* , const void*)) {
|
||||
struct compar_data compar_data;
|
||||
compar_data.thunk = thunk;
|
||||
compar_data.compar = compar;
|
||||
qsort_r(base, nel, width, compar_wrapper, &compar_data);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Emulate qsort_r using thread local storage to access the thunk data.
|
||||
*/
|
||||
|
||||
#include <cutils/threads.h>
|
||||
|
||||
static thread_store_t compar_data_key = THREAD_STORE_INITIALIZER;
|
||||
|
||||
struct compar_data {
|
||||
void* thunk;
|
||||
int (*compar)(void*, const void* , const void*);
|
||||
};
|
||||
|
||||
static int compar_wrapper(const void* a, const void* b) {
|
||||
struct compar_data* compar_data = (struct compar_data*)thread_store_get(&compar_data_key);
|
||||
return compar_data->compar(compar_data->thunk, a, b);
|
||||
}
|
||||
|
||||
void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
|
||||
int (*compar)(void*, const void* , const void*)) {
|
||||
struct compar_data compar_data;
|
||||
compar_data.thunk = thunk;
|
||||
compar_data.compar = compar;
|
||||
thread_store_set(&compar_data_key, &compar_data, NULL);
|
||||
qsort(base, nel, width, compar_wrapper);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Provides a portable version of qsort_r, called qsort_r_compat, which is a
|
||||
* reentrant variant of qsort that passes a user data pointer to its comparator.
|
||||
* This implementation follows the BSD parameter convention.
|
||||
*/
|
||||
|
||||
#ifndef ___QSORT_R_COMPAT_H
|
||||
#define ___QSORT_R_COMPAT_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
|
||||
int (*compar)(void*, const void* , const void* ));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ___QSORT_R_COMPAT_H
|
||||
@@ -1,97 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
#include <utils/String8.h>
|
||||
#include <iostream>
|
||||
#include <errno.h>
|
||||
|
||||
#include "CrunchCache.h"
|
||||
#include "FileFinder.h"
|
||||
#include "MockFileFinder.h"
|
||||
#include "CacheUpdater.h"
|
||||
#include "MockCacheUpdater.h"
|
||||
|
||||
using namespace android;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
void expectEqual(int got, int expected, const char* desc) {
|
||||
cout << "Checking " << desc << ": ";
|
||||
cout << "Got " << got << ", expected " << expected << "...";
|
||||
cout << ( (got == expected) ? "PASSED" : "FAILED") << endl;
|
||||
errno += ((got == expected) ? 0 : 1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
errno = 0;
|
||||
|
||||
String8 source("res");
|
||||
String8 dest("res2");
|
||||
|
||||
// Create data for MockFileFinder to feed to the cache
|
||||
KeyedVector<String8, time_t> sourceData;
|
||||
// This shouldn't be updated
|
||||
sourceData.add(String8("res/drawable/hello.png"),3);
|
||||
// This should be updated
|
||||
sourceData.add(String8("res/drawable/world.png"),5);
|
||||
// This should cause make directory to be called
|
||||
sourceData.add(String8("res/drawable-cool/hello.png"),3);
|
||||
|
||||
KeyedVector<String8, time_t> destData;
|
||||
destData.add(String8("res2/drawable/hello.png"),3);
|
||||
destData.add(String8("res2/drawable/world.png"),3);
|
||||
// this should call delete
|
||||
destData.add(String8("res2/drawable/dead.png"),3);
|
||||
|
||||
// Package up data and create mock file finder
|
||||
KeyedVector<String8, KeyedVector<String8,time_t> > data;
|
||||
data.add(source,sourceData);
|
||||
data.add(dest,destData);
|
||||
FileFinder* ff = new MockFileFinder(data);
|
||||
CrunchCache cc(source,dest,ff);
|
||||
|
||||
MockCacheUpdater* mcu = new MockCacheUpdater();
|
||||
CacheUpdater* cu(mcu);
|
||||
|
||||
cout << "Running Crunch...";
|
||||
int result = cc.crunch(cu);
|
||||
cout << ((result > 0) ? "PASSED" : "FAILED") << endl;
|
||||
errno += ((result > 0) ? 0 : 1);
|
||||
|
||||
const int EXPECTED_RESULT = 2;
|
||||
expectEqual(result, EXPECTED_RESULT, "number of files touched");
|
||||
|
||||
cout << "Checking calls to deleteFile and processImage:" << endl;
|
||||
const int EXPECTED_DELETES = 1;
|
||||
const int EXPECTED_PROCESSED = 2;
|
||||
// Deletes
|
||||
expectEqual(mcu->deleteCount, EXPECTED_DELETES, "deleteFile");
|
||||
// processImage
|
||||
expectEqual(mcu->processCount, EXPECTED_PROCESSED, "processImage");
|
||||
|
||||
const int EXPECTED_OVERWRITES = 3;
|
||||
result = cc.crunch(cu, true);
|
||||
expectEqual(result, EXPECTED_OVERWRITES, "number of files touched with overwrite");
|
||||
\
|
||||
|
||||
if (errno == 0)
|
||||
cout << "ALL TESTS PASSED!" << endl;
|
||||
else
|
||||
cout << errno << " TESTS FAILED" << endl;
|
||||
|
||||
delete ff;
|
||||
delete cu;
|
||||
|
||||
// TESTS BELOW WILL GO AWAY SOON
|
||||
|
||||
String8 source2("ApiDemos/res");
|
||||
String8 dest2("ApiDemos/res2");
|
||||
|
||||
FileFinder* sff = new SystemFileFinder();
|
||||
CacheUpdater* scu = new SystemCacheUpdater();
|
||||
|
||||
CrunchCache scc(source2,dest2,sff);
|
||||
|
||||
scc.crunch(scu);
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <utils/String8.h>
|
||||
#include <utility>
|
||||
|
||||
#include "DirectoryWalker.h"
|
||||
#include "MockDirectoryWalker.h"
|
||||
#include "FileFinder.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
using std::pair;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
cout << "\n\n STARTING FILE FINDER TESTS" << endl;
|
||||
String8 path("ApiDemos");
|
||||
|
||||
// Storage to pass to findFiles()
|
||||
KeyedVector<String8,time_t> testStorage;
|
||||
|
||||
// Mock Directory Walker initialization. First data, then sdw
|
||||
Vector< pair<String8,time_t> > data;
|
||||
data.push( pair<String8,time_t>(String8("hello.png"),3) );
|
||||
data.push( pair<String8,time_t>(String8("world.PNG"),3) );
|
||||
data.push( pair<String8,time_t>(String8("foo.pNg"),3) );
|
||||
// Neither of these should be found
|
||||
data.push( pair<String8,time_t>(String8("hello.jpg"),3) );
|
||||
data.push( pair<String8,time_t>(String8(".hidden.png"),3));
|
||||
|
||||
DirectoryWalker* sdw = new StringDirectoryWalker(path,data);
|
||||
|
||||
// Extensions to look for
|
||||
Vector<String8> exts;
|
||||
exts.push(String8(".png"));
|
||||
|
||||
errno = 0;
|
||||
|
||||
// Make sure we get a valid mock directory walker
|
||||
// Make sure we finish without errors
|
||||
cout << "Checking DirectoryWalker...";
|
||||
assert(sdw != NULL);
|
||||
cout << "PASSED" << endl;
|
||||
|
||||
// Make sure we finish without errors
|
||||
cout << "Running findFiles()...";
|
||||
bool findStatus = FileFinder::findFiles(path,exts, testStorage, sdw);
|
||||
assert(findStatus);
|
||||
cout << "PASSED" << endl;
|
||||
|
||||
const size_t SIZE_EXPECTED = 3;
|
||||
// Check to make sure we have the right number of things in our storage
|
||||
cout << "Running size comparison: Size is " << testStorage.size() << ", ";
|
||||
cout << "Expected " << SIZE_EXPECTED << "...";
|
||||
if(testStorage.size() == SIZE_EXPECTED)
|
||||
cout << "PASSED" << endl;
|
||||
else {
|
||||
cout << "FAILED" << endl;
|
||||
errno++;
|
||||
}
|
||||
|
||||
// Check to make sure that each of our found items has the right extension
|
||||
cout << "Checking Returned Extensions...";
|
||||
bool extsOkay = true;
|
||||
String8 wrongExts;
|
||||
for (size_t i = 0; i < SIZE_EXPECTED; ++i) {
|
||||
String8 testExt(testStorage.keyAt(i).getPathExtension());
|
||||
testExt.toLower();
|
||||
if (testExt != ".png") {
|
||||
wrongExts += testStorage.keyAt(i);
|
||||
wrongExts += "\n";
|
||||
extsOkay = false;
|
||||
}
|
||||
}
|
||||
if (extsOkay)
|
||||
cout << "PASSED" << endl;
|
||||
else {
|
||||
cout << "FAILED" << endl;
|
||||
cout << "The following extensions didn't check out" << endl << wrongExts;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
delete sdw;
|
||||
|
||||
if(errno == 0) {
|
||||
cout << "ALL TESTS PASSED" << endl;
|
||||
} else {
|
||||
cout << errno << " TESTS FAILED" << endl;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
#ifndef MOCKCACHEUPDATER_H
|
||||
#define MOCKCACHEUPDATER_H
|
||||
|
||||
#include <utils/String8.h>
|
||||
#include "CacheUpdater.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
class MockCacheUpdater : public CacheUpdater {
|
||||
public:
|
||||
|
||||
MockCacheUpdater()
|
||||
: deleteCount(0), processCount(0) { };
|
||||
|
||||
// Make sure all the directories along this path exist
|
||||
virtual void ensureDirectoriesExist(String8 path)
|
||||
{
|
||||
// Nothing to do
|
||||
};
|
||||
|
||||
// Delete a file
|
||||
virtual void deleteFile(String8 path) {
|
||||
deleteCount++;
|
||||
};
|
||||
|
||||
// Process an image from source out to dest
|
||||
virtual void processImage(String8 source, String8 dest) {
|
||||
processCount++;
|
||||
};
|
||||
|
||||
// DATA MEMBERS
|
||||
int deleteCount;
|
||||
int processCount;
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // MOCKCACHEUPDATER_H
|
||||
@@ -1,85 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
#ifndef MOCKDIRECTORYWALKER_H
|
||||
#define MOCKDIRECTORYWALKER_H
|
||||
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utility>
|
||||
#include "DirectoryWalker.h"
|
||||
|
||||
using namespace android;
|
||||
using std::pair;
|
||||
|
||||
// String8 Directory Walker
|
||||
// This is an implementation of the Directory Walker abstraction that is built
|
||||
// for testing.
|
||||
// Instead of system calls it queries a private data structure for the directory
|
||||
// entries. It takes a path and a map of filenames and their modification times.
|
||||
// functions are inlined since they are short and simple
|
||||
|
||||
class StringDirectoryWalker : public DirectoryWalker {
|
||||
public:
|
||||
StringDirectoryWalker(String8& path, Vector< pair<String8,time_t> >& data)
|
||||
: mPos(0), mBasePath(path), mData(data) {
|
||||
//fprintf(stdout,"StringDW built to mimic %s with %d files\n",
|
||||
// mBasePath.string());
|
||||
};
|
||||
// Default copy constructor, and destructor are fine
|
||||
|
||||
virtual bool openDir(String8 path) {
|
||||
// If the user is trying to query the "directory" that this
|
||||
// walker was initialized with, then return success. Else fail.
|
||||
return path == mBasePath;
|
||||
};
|
||||
virtual bool openDir(const char* path) {
|
||||
String8 p(path);
|
||||
openDir(p);
|
||||
return true;
|
||||
};
|
||||
// Advance to next entry in the Vector
|
||||
virtual struct dirent* nextEntry() {
|
||||
// Advance position and check to see if we're done
|
||||
if (mPos >= mData.size())
|
||||
return NULL;
|
||||
|
||||
// Place data in the entry descriptor. This class only returns files.
|
||||
mEntry.d_type = DT_REG;
|
||||
mEntry.d_ino = mPos;
|
||||
// Copy chars from the string name to the entry name
|
||||
size_t i = 0;
|
||||
for (i; i < mData[mPos].first.size(); ++i)
|
||||
mEntry.d_name[i] = mData[mPos].first[i];
|
||||
mEntry.d_name[i] = '\0';
|
||||
|
||||
// Place data in stats
|
||||
mStats.st_ino = mPos;
|
||||
mStats.st_mtime = mData[mPos].second;
|
||||
|
||||
// Get ready to move to the next entry
|
||||
mPos++;
|
||||
|
||||
return &mEntry;
|
||||
};
|
||||
// Get the stats for the current entry
|
||||
virtual struct stat* entryStats() {
|
||||
return &mStats;
|
||||
};
|
||||
// Nothing to do in clean up
|
||||
virtual void closeDir() {
|
||||
// Nothing to do
|
||||
};
|
||||
virtual DirectoryWalker* clone() {
|
||||
return new StringDirectoryWalker(*this);
|
||||
};
|
||||
private:
|
||||
// Current position in the Vector
|
||||
size_t mPos;
|
||||
// Base path
|
||||
String8 mBasePath;
|
||||
// Data to simulate a directory full of files.
|
||||
Vector< pair<String8,time_t> > mData;
|
||||
};
|
||||
|
||||
#endif // MOCKDIRECTORYWALKER_H
|
||||
@@ -1,55 +0,0 @@
|
||||
//
|
||||
// Copyright 2011 The Android Open Source Project
|
||||
//
|
||||
|
||||
#ifndef MOCKFILEFINDER_H
|
||||
#define MOCKFILEFINDER_H
|
||||
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include "DirectoryWalker.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
class MockFileFinder : public FileFinder {
|
||||
public:
|
||||
MockFileFinder (KeyedVector<String8, KeyedVector<String8,time_t> >& files)
|
||||
: mFiles(files)
|
||||
{
|
||||
// Nothing left to do
|
||||
};
|
||||
|
||||
/**
|
||||
* findFiles implementation for the abstraction.
|
||||
* PRECONDITIONS:
|
||||
* No checking is done, so there MUST be an entry in mFiles with
|
||||
* path matching basePath.
|
||||
*
|
||||
* POSTCONDITIONS:
|
||||
* fileStore is filled with a copy of the data in mFiles corresponding
|
||||
* to the basePath.
|
||||
*/
|
||||
|
||||
virtual bool findFiles(String8 basePath, Vector<String8>& extensions,
|
||||
KeyedVector<String8,time_t>& fileStore,
|
||||
DirectoryWalker* dw)
|
||||
{
|
||||
const KeyedVector<String8,time_t>* payload(&mFiles.valueFor(basePath));
|
||||
// Since KeyedVector doesn't implement swap
|
||||
// (who doesn't use swap??) we loop and add one at a time.
|
||||
for (size_t i = 0; i < payload->size(); ++i) {
|
||||
fileStore.add(payload->keyAt(i),payload->valueAt(i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Virtual mapping between "directories" and the "files" contained
|
||||
// in them
|
||||
KeyedVector<String8, KeyedVector<String8,time_t> > mFiles;
|
||||
};
|
||||
|
||||
|
||||
#endif // MOCKFILEFINDER_H
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.aapt.test.plurals">
|
||||
|
||||
</manifest>
|
||||
@@ -1,7 +0,0 @@
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="ok">OK</string>
|
||||
<plurals name="a_plural">
|
||||
<item quantity="one">A dog</item>
|
||||
<item quantity="other">Some dogs</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
@@ -1,16 +0,0 @@
|
||||
TEST_DIR=tools/aapt/tests/plurals
|
||||
TEST_OUT_DIR=out/plurals_test
|
||||
|
||||
rm -rf $TEST_OUT_DIR
|
||||
mkdir -p $TEST_OUT_DIR
|
||||
mkdir -p $TEST_OUT_DIR/java
|
||||
|
||||
#gdb --args \
|
||||
aapt package -v -x -m -z -J $TEST_OUT_DIR/java -M $TEST_DIR/AndroidManifest.xml \
|
||||
-I out/target/common/obj/APPS/framework-res_intermediates/package-export.apk \
|
||||
-P $TEST_OUT_DIR/public_resources.xml \
|
||||
-S $TEST_DIR/res
|
||||
|
||||
echo
|
||||
echo "==================== FILES CREATED ==================== "
|
||||
find $TEST_OUT_DIR -type f
|
||||
@@ -1,912 +0,0 @@
|
||||
#include "AST.h"
|
||||
#include "Type.h"
|
||||
|
||||
void
|
||||
WriteModifiers(FILE* to, int mod, int mask)
|
||||
{
|
||||
int m = mod & mask;
|
||||
|
||||
if (m & OVERRIDE) {
|
||||
fprintf(to, "@Override ");
|
||||
}
|
||||
|
||||
if ((m & SCOPE_MASK) == PUBLIC) {
|
||||
fprintf(to, "public ");
|
||||
}
|
||||
else if ((m & SCOPE_MASK) == PRIVATE) {
|
||||
fprintf(to, "private ");
|
||||
}
|
||||
else if ((m & SCOPE_MASK) == PROTECTED) {
|
||||
fprintf(to, "protected ");
|
||||
}
|
||||
|
||||
if (m & STATIC) {
|
||||
fprintf(to, "static ");
|
||||
}
|
||||
|
||||
if (m & FINAL) {
|
||||
fprintf(to, "final ");
|
||||
}
|
||||
|
||||
if (m & ABSTRACT) {
|
||||
fprintf(to, "abstract ");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WriteArgumentList(FILE* to, const vector<Expression*>& arguments)
|
||||
{
|
||||
size_t N = arguments.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
arguments[i]->Write(to);
|
||||
if (i != N-1) {
|
||||
fprintf(to, ", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClassElement::ClassElement()
|
||||
{
|
||||
}
|
||||
|
||||
ClassElement::~ClassElement()
|
||||
{
|
||||
}
|
||||
|
||||
Field::Field()
|
||||
:ClassElement(),
|
||||
modifiers(0),
|
||||
variable(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Field::Field(int m, Variable* v)
|
||||
:ClassElement(),
|
||||
modifiers(m),
|
||||
variable(v)
|
||||
{
|
||||
}
|
||||
|
||||
Field::~Field()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Field::GatherTypes(set<Type*>* types) const
|
||||
{
|
||||
types->insert(this->variable->type);
|
||||
}
|
||||
|
||||
void
|
||||
Field::Write(FILE* to)
|
||||
{
|
||||
if (this->comment.length() != 0) {
|
||||
fprintf(to, "%s\n", this->comment.c_str());
|
||||
}
|
||||
WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
|
||||
fprintf(to, "%s %s", this->variable->type->QualifiedName().c_str(),
|
||||
this->variable->name.c_str());
|
||||
if (this->value.length() != 0) {
|
||||
fprintf(to, " = %s", this->value.c_str());
|
||||
}
|
||||
fprintf(to, ";\n");
|
||||
}
|
||||
|
||||
Expression::~Expression()
|
||||
{
|
||||
}
|
||||
|
||||
LiteralExpression::LiteralExpression(const string& v)
|
||||
:value(v)
|
||||
{
|
||||
}
|
||||
|
||||
LiteralExpression::~LiteralExpression()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
LiteralExpression::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "%s", this->value.c_str());
|
||||
}
|
||||
|
||||
StringLiteralExpression::StringLiteralExpression(const string& v)
|
||||
:value(v)
|
||||
{
|
||||
}
|
||||
|
||||
StringLiteralExpression::~StringLiteralExpression()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
StringLiteralExpression::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "\"%s\"", this->value.c_str());
|
||||
}
|
||||
|
||||
Variable::Variable()
|
||||
:type(NULL),
|
||||
name(),
|
||||
dimension(0)
|
||||
{
|
||||
}
|
||||
|
||||
Variable::Variable(Type* t, const string& n)
|
||||
:type(t),
|
||||
name(n),
|
||||
dimension(0)
|
||||
{
|
||||
}
|
||||
|
||||
Variable::Variable(Type* t, const string& n, int d)
|
||||
:type(t),
|
||||
name(n),
|
||||
dimension(d)
|
||||
{
|
||||
}
|
||||
|
||||
Variable::~Variable()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Variable::GatherTypes(set<Type*>* types) const
|
||||
{
|
||||
types->insert(this->type);
|
||||
}
|
||||
|
||||
void
|
||||
Variable::WriteDeclaration(FILE* to)
|
||||
{
|
||||
string dim;
|
||||
for (int i=0; i<this->dimension; i++) {
|
||||
dim += "[]";
|
||||
}
|
||||
fprintf(to, "%s%s %s", this->type->QualifiedName().c_str(), dim.c_str(),
|
||||
this->name.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
Variable::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "%s", name.c_str());
|
||||
}
|
||||
|
||||
FieldVariable::FieldVariable(Expression* o, const string& n)
|
||||
:object(o),
|
||||
clazz(NULL),
|
||||
name(n)
|
||||
{
|
||||
}
|
||||
|
||||
FieldVariable::FieldVariable(Type* c, const string& n)
|
||||
:object(NULL),
|
||||
clazz(c),
|
||||
name(n)
|
||||
{
|
||||
}
|
||||
|
||||
FieldVariable::~FieldVariable()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FieldVariable::Write(FILE* to)
|
||||
{
|
||||
if (this->object != NULL) {
|
||||
this->object->Write(to);
|
||||
}
|
||||
else if (this->clazz != NULL) {
|
||||
fprintf(to, "%s", this->clazz->QualifiedName().c_str());
|
||||
}
|
||||
fprintf(to, ".%s", name.c_str());
|
||||
}
|
||||
|
||||
|
||||
Statement::~Statement()
|
||||
{
|
||||
}
|
||||
|
||||
StatementBlock::StatementBlock()
|
||||
{
|
||||
}
|
||||
|
||||
StatementBlock::~StatementBlock()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
StatementBlock::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "{\n");
|
||||
int N = this->statements.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
this->statements[i]->Write(to);
|
||||
}
|
||||
fprintf(to, "}\n");
|
||||
}
|
||||
|
||||
void
|
||||
StatementBlock::Add(Statement* statement)
|
||||
{
|
||||
this->statements.push_back(statement);
|
||||
}
|
||||
|
||||
void
|
||||
StatementBlock::Add(Expression* expression)
|
||||
{
|
||||
this->statements.push_back(new ExpressionStatement(expression));
|
||||
}
|
||||
|
||||
ExpressionStatement::ExpressionStatement(Expression* e)
|
||||
:expression(e)
|
||||
{
|
||||
}
|
||||
|
||||
ExpressionStatement::~ExpressionStatement()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ExpressionStatement::Write(FILE* to)
|
||||
{
|
||||
this->expression->Write(to);
|
||||
fprintf(to, ";\n");
|
||||
}
|
||||
|
||||
Assignment::Assignment(Variable* l, Expression* r)
|
||||
:lvalue(l),
|
||||
rvalue(r),
|
||||
cast(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Assignment::Assignment(Variable* l, Expression* r, Type* c)
|
||||
:lvalue(l),
|
||||
rvalue(r),
|
||||
cast(c)
|
||||
{
|
||||
}
|
||||
|
||||
Assignment::~Assignment()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Assignment::Write(FILE* to)
|
||||
{
|
||||
this->lvalue->Write(to);
|
||||
fprintf(to, " = ");
|
||||
if (this->cast != NULL) {
|
||||
fprintf(to, "(%s)", this->cast->QualifiedName().c_str());
|
||||
}
|
||||
this->rvalue->Write(to);
|
||||
}
|
||||
|
||||
MethodCall::MethodCall(const string& n)
|
||||
:obj(NULL),
|
||||
clazz(NULL),
|
||||
name(n)
|
||||
{
|
||||
}
|
||||
|
||||
MethodCall::MethodCall(const string& n, int argc = 0, ...)
|
||||
:obj(NULL),
|
||||
clazz(NULL),
|
||||
name(n)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, argc);
|
||||
init(argc, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
MethodCall::MethodCall(Expression* o, const string& n)
|
||||
:obj(o),
|
||||
clazz(NULL),
|
||||
name(n)
|
||||
{
|
||||
}
|
||||
|
||||
MethodCall::MethodCall(Type* t, const string& n)
|
||||
:obj(NULL),
|
||||
clazz(t),
|
||||
name(n)
|
||||
{
|
||||
}
|
||||
|
||||
MethodCall::MethodCall(Expression* o, const string& n, int argc = 0, ...)
|
||||
:obj(o),
|
||||
clazz(NULL),
|
||||
name(n)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, argc);
|
||||
init(argc, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
MethodCall::MethodCall(Type* t, const string& n, int argc = 0, ...)
|
||||
:obj(NULL),
|
||||
clazz(t),
|
||||
name(n)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, argc);
|
||||
init(argc, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
MethodCall::~MethodCall()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MethodCall::init(int n, va_list args)
|
||||
{
|
||||
for (int i=0; i<n; i++) {
|
||||
Expression* expression = (Expression*)va_arg(args, void*);
|
||||
this->arguments.push_back(expression);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MethodCall::Write(FILE* to)
|
||||
{
|
||||
if (this->obj != NULL) {
|
||||
this->obj->Write(to);
|
||||
fprintf(to, ".");
|
||||
}
|
||||
else if (this->clazz != NULL) {
|
||||
fprintf(to, "%s.", this->clazz->QualifiedName().c_str());
|
||||
}
|
||||
fprintf(to, "%s(", this->name.c_str());
|
||||
WriteArgumentList(to, this->arguments);
|
||||
fprintf(to, ")");
|
||||
}
|
||||
|
||||
Comparison::Comparison(Expression* l, const string& o, Expression* r)
|
||||
:lvalue(l),
|
||||
op(o),
|
||||
rvalue(r)
|
||||
{
|
||||
}
|
||||
|
||||
Comparison::~Comparison()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Comparison::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "(");
|
||||
this->lvalue->Write(to);
|
||||
fprintf(to, "%s", this->op.c_str());
|
||||
this->rvalue->Write(to);
|
||||
fprintf(to, ")");
|
||||
}
|
||||
|
||||
NewExpression::NewExpression(Type* t)
|
||||
:type(t)
|
||||
{
|
||||
}
|
||||
|
||||
NewExpression::NewExpression(Type* t, int argc = 0, ...)
|
||||
:type(t)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, argc);
|
||||
init(argc, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
NewExpression::~NewExpression()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NewExpression::init(int n, va_list args)
|
||||
{
|
||||
for (int i=0; i<n; i++) {
|
||||
Expression* expression = (Expression*)va_arg(args, void*);
|
||||
this->arguments.push_back(expression);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NewExpression::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "new %s(", this->type->InstantiableName().c_str());
|
||||
WriteArgumentList(to, this->arguments);
|
||||
fprintf(to, ")");
|
||||
}
|
||||
|
||||
NewArrayExpression::NewArrayExpression(Type* t, Expression* s)
|
||||
:type(t),
|
||||
size(s)
|
||||
{
|
||||
}
|
||||
|
||||
NewArrayExpression::~NewArrayExpression()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NewArrayExpression::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "new %s[", this->type->QualifiedName().c_str());
|
||||
size->Write(to);
|
||||
fprintf(to, "]");
|
||||
}
|
||||
|
||||
Ternary::Ternary()
|
||||
:condition(NULL),
|
||||
ifpart(NULL),
|
||||
elsepart(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Ternary::Ternary(Expression* a, Expression* b, Expression* c)
|
||||
:condition(a),
|
||||
ifpart(b),
|
||||
elsepart(c)
|
||||
{
|
||||
}
|
||||
|
||||
Ternary::~Ternary()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Ternary::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "((");
|
||||
this->condition->Write(to);
|
||||
fprintf(to, ")?(");
|
||||
this->ifpart->Write(to);
|
||||
fprintf(to, "):(");
|
||||
this->elsepart->Write(to);
|
||||
fprintf(to, "))");
|
||||
}
|
||||
|
||||
Cast::Cast()
|
||||
:type(NULL),
|
||||
expression(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Cast::Cast(Type* t, Expression* e)
|
||||
:type(t),
|
||||
expression(e)
|
||||
{
|
||||
}
|
||||
|
||||
Cast::~Cast()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Cast::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "((%s)", this->type->QualifiedName().c_str());
|
||||
expression->Write(to);
|
||||
fprintf(to, ")");
|
||||
}
|
||||
|
||||
VariableDeclaration::VariableDeclaration(Variable* l, Expression* r, Type* c)
|
||||
:lvalue(l),
|
||||
cast(c),
|
||||
rvalue(r)
|
||||
{
|
||||
}
|
||||
|
||||
VariableDeclaration::VariableDeclaration(Variable* l)
|
||||
:lvalue(l),
|
||||
cast(NULL),
|
||||
rvalue(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
VariableDeclaration::~VariableDeclaration()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
VariableDeclaration::Write(FILE* to)
|
||||
{
|
||||
this->lvalue->WriteDeclaration(to);
|
||||
if (this->rvalue != NULL) {
|
||||
fprintf(to, " = ");
|
||||
if (this->cast != NULL) {
|
||||
fprintf(to, "(%s)", this->cast->QualifiedName().c_str());
|
||||
}
|
||||
this->rvalue->Write(to);
|
||||
}
|
||||
fprintf(to, ";\n");
|
||||
}
|
||||
|
||||
IfStatement::IfStatement()
|
||||
:expression(NULL),
|
||||
statements(new StatementBlock),
|
||||
elseif(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
IfStatement::~IfStatement()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
IfStatement::Write(FILE* to)
|
||||
{
|
||||
if (this->expression != NULL) {
|
||||
fprintf(to, "if (");
|
||||
this->expression->Write(to);
|
||||
fprintf(to, ") ");
|
||||
}
|
||||
this->statements->Write(to);
|
||||
if (this->elseif != NULL) {
|
||||
fprintf(to, "else ");
|
||||
this->elseif->Write(to);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnStatement::ReturnStatement(Expression* e)
|
||||
:expression(e)
|
||||
{
|
||||
}
|
||||
|
||||
ReturnStatement::~ReturnStatement()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ReturnStatement::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "return ");
|
||||
this->expression->Write(to);
|
||||
fprintf(to, ";\n");
|
||||
}
|
||||
|
||||
TryStatement::TryStatement()
|
||||
:statements(new StatementBlock)
|
||||
{
|
||||
}
|
||||
|
||||
TryStatement::~TryStatement()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TryStatement::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "try ");
|
||||
this->statements->Write(to);
|
||||
}
|
||||
|
||||
CatchStatement::CatchStatement(Variable* e)
|
||||
:statements(new StatementBlock),
|
||||
exception(e)
|
||||
{
|
||||
}
|
||||
|
||||
CatchStatement::~CatchStatement()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CatchStatement::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "catch ");
|
||||
if (this->exception != NULL) {
|
||||
fprintf(to, "(");
|
||||
this->exception->WriteDeclaration(to);
|
||||
fprintf(to, ") ");
|
||||
}
|
||||
this->statements->Write(to);
|
||||
}
|
||||
|
||||
FinallyStatement::FinallyStatement()
|
||||
:statements(new StatementBlock)
|
||||
{
|
||||
}
|
||||
|
||||
FinallyStatement::~FinallyStatement()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FinallyStatement::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "finally ");
|
||||
this->statements->Write(to);
|
||||
}
|
||||
|
||||
Case::Case()
|
||||
:statements(new StatementBlock)
|
||||
{
|
||||
}
|
||||
|
||||
Case::Case(const string& c)
|
||||
:statements(new StatementBlock)
|
||||
{
|
||||
cases.push_back(c);
|
||||
}
|
||||
|
||||
Case::~Case()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Case::Write(FILE* to)
|
||||
{
|
||||
int N = this->cases.size();
|
||||
if (N > 0) {
|
||||
for (int i=0; i<N; i++) {
|
||||
string s = this->cases[i];
|
||||
if (s.length() != 0) {
|
||||
fprintf(to, "case %s:\n", s.c_str());
|
||||
} else {
|
||||
fprintf(to, "default:\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(to, "default:\n");
|
||||
}
|
||||
statements->Write(to);
|
||||
}
|
||||
|
||||
SwitchStatement::SwitchStatement(Expression* e)
|
||||
:expression(e)
|
||||
{
|
||||
}
|
||||
|
||||
SwitchStatement::~SwitchStatement()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SwitchStatement::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "switch (");
|
||||
this->expression->Write(to);
|
||||
fprintf(to, ")\n{\n");
|
||||
int N = this->cases.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
this->cases[i]->Write(to);
|
||||
}
|
||||
fprintf(to, "}\n");
|
||||
}
|
||||
|
||||
Break::Break()
|
||||
{
|
||||
}
|
||||
|
||||
Break::~Break()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Break::Write(FILE* to)
|
||||
{
|
||||
fprintf(to, "break;\n");
|
||||
}
|
||||
|
||||
Method::Method()
|
||||
:ClassElement(),
|
||||
modifiers(0),
|
||||
returnType(NULL), // (NULL means constructor)
|
||||
returnTypeDimension(0),
|
||||
statements(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Method::~Method()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Method::GatherTypes(set<Type*>* types) const
|
||||
{
|
||||
size_t N, i;
|
||||
|
||||
if (this->returnType) {
|
||||
types->insert(this->returnType);
|
||||
}
|
||||
|
||||
N = this->parameters.size();
|
||||
for (i=0; i<N; i++) {
|
||||
this->parameters[i]->GatherTypes(types);
|
||||
}
|
||||
|
||||
N = this->exceptions.size();
|
||||
for (i=0; i<N; i++) {
|
||||
types->insert(this->exceptions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Method::Write(FILE* to)
|
||||
{
|
||||
size_t N, i;
|
||||
|
||||
if (this->comment.length() != 0) {
|
||||
fprintf(to, "%s\n", this->comment.c_str());
|
||||
}
|
||||
|
||||
WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
|
||||
|
||||
if (this->returnType != NULL) {
|
||||
string dim;
|
||||
for (i=0; i<this->returnTypeDimension; i++) {
|
||||
dim += "[]";
|
||||
}
|
||||
fprintf(to, "%s%s ", this->returnType->QualifiedName().c_str(),
|
||||
dim.c_str());
|
||||
}
|
||||
|
||||
fprintf(to, "%s(", this->name.c_str());
|
||||
|
||||
N = this->parameters.size();
|
||||
for (i=0; i<N; i++) {
|
||||
this->parameters[i]->WriteDeclaration(to);
|
||||
if (i != N-1) {
|
||||
fprintf(to, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(to, ")");
|
||||
|
||||
N = this->exceptions.size();
|
||||
for (i=0; i<N; i++) {
|
||||
if (i == 0) {
|
||||
fprintf(to, " throws ");
|
||||
} else {
|
||||
fprintf(to, ", ");
|
||||
}
|
||||
fprintf(to, "%s", this->exceptions[i]->QualifiedName().c_str());
|
||||
}
|
||||
|
||||
if (this->statements == NULL) {
|
||||
fprintf(to, ";\n");
|
||||
} else {
|
||||
fprintf(to, "\n");
|
||||
this->statements->Write(to);
|
||||
}
|
||||
}
|
||||
|
||||
Class::Class()
|
||||
:modifiers(0),
|
||||
what(CLASS),
|
||||
type(NULL),
|
||||
extends(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Class::~Class()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Class::GatherTypes(set<Type*>* types) const
|
||||
{
|
||||
int N, i;
|
||||
|
||||
types->insert(this->type);
|
||||
if (this->extends != NULL) {
|
||||
types->insert(this->extends);
|
||||
}
|
||||
|
||||
N = this->interfaces.size();
|
||||
for (i=0; i<N; i++) {
|
||||
types->insert(this->interfaces[i]);
|
||||
}
|
||||
|
||||
N = this->elements.size();
|
||||
for (i=0; i<N; i++) {
|
||||
this->elements[i]->GatherTypes(types);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Class::Write(FILE* to)
|
||||
{
|
||||
size_t N, i;
|
||||
|
||||
if (this->comment.length() != 0) {
|
||||
fprintf(to, "%s\n", this->comment.c_str());
|
||||
}
|
||||
|
||||
WriteModifiers(to, this->modifiers, ALL_MODIFIERS);
|
||||
|
||||
if (this->what == Class::CLASS) {
|
||||
fprintf(to, "class ");
|
||||
} else {
|
||||
fprintf(to, "interface ");
|
||||
}
|
||||
|
||||
string name = this->type->Name();
|
||||
size_t pos = name.rfind('.');
|
||||
if (pos != string::npos) {
|
||||
name = name.c_str() + pos + 1;
|
||||
}
|
||||
|
||||
fprintf(to, "%s", name.c_str());
|
||||
|
||||
if (this->extends != NULL) {
|
||||
fprintf(to, " extends %s", this->extends->QualifiedName().c_str());
|
||||
}
|
||||
|
||||
N = this->interfaces.size();
|
||||
if (N != 0) {
|
||||
if (this->what == Class::CLASS) {
|
||||
fprintf(to, " implements");
|
||||
} else {
|
||||
fprintf(to, " extends");
|
||||
}
|
||||
for (i=0; i<N; i++) {
|
||||
fprintf(to, " %s", this->interfaces[i]->QualifiedName().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(to, "\n");
|
||||
fprintf(to, "{\n");
|
||||
|
||||
N = this->elements.size();
|
||||
for (i=0; i<N; i++) {
|
||||
this->elements[i]->Write(to);
|
||||
}
|
||||
|
||||
fprintf(to, "}\n");
|
||||
|
||||
}
|
||||
|
||||
Document::Document()
|
||||
{
|
||||
}
|
||||
|
||||
Document::~Document()
|
||||
{
|
||||
}
|
||||
|
||||
static string
|
||||
escape_backslashes(const string& str)
|
||||
{
|
||||
string result;
|
||||
const size_t I=str.length();
|
||||
for (size_t i=0; i<I; i++) {
|
||||
char c = str[i];
|
||||
if (c == '\\') {
|
||||
result += "\\\\";
|
||||
} else {
|
||||
result += c;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
Document::Write(FILE* to)
|
||||
{
|
||||
size_t N, i;
|
||||
|
||||
if (this->comment.length() != 0) {
|
||||
fprintf(to, "%s\n", this->comment.c_str());
|
||||
}
|
||||
fprintf(to, "/*\n"
|
||||
" * This file is auto-generated. DO NOT MODIFY.\n"
|
||||
" * Original file: %s\n"
|
||||
" */\n", escape_backslashes(this->originalSrc).c_str());
|
||||
if (this->package.length() != 0) {
|
||||
fprintf(to, "package %s;\n", this->package.c_str());
|
||||
}
|
||||
|
||||
N = this->classes.size();
|
||||
for (i=0; i<N; i++) {
|
||||
Class* c = this->classes[i];
|
||||
c->Write(to);
|
||||
}
|
||||
}
|
||||
|
||||
371
tools/aidl/AST.h
@@ -1,371 +0,0 @@
|
||||
#ifndef AIDL_AST_H
|
||||
#define AIDL_AST_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Type;
|
||||
|
||||
enum {
|
||||
PACKAGE_PRIVATE = 0x00000000,
|
||||
PUBLIC = 0x00000001,
|
||||
PRIVATE = 0x00000002,
|
||||
PROTECTED = 0x00000003,
|
||||
SCOPE_MASK = 0x00000003,
|
||||
|
||||
STATIC = 0x00000010,
|
||||
FINAL = 0x00000020,
|
||||
ABSTRACT = 0x00000040,
|
||||
|
||||
OVERRIDE = 0x00000100,
|
||||
|
||||
ALL_MODIFIERS = 0xffffffff
|
||||
};
|
||||
|
||||
// Write the modifiers that are set in both mod and mask
|
||||
void WriteModifiers(FILE* to, int mod, int mask);
|
||||
|
||||
struct ClassElement
|
||||
{
|
||||
ClassElement();
|
||||
virtual ~ClassElement();
|
||||
|
||||
virtual void GatherTypes(set<Type*>* types) const = 0;
|
||||
virtual void Write(FILE* to) = 0;
|
||||
};
|
||||
|
||||
struct Expression
|
||||
{
|
||||
virtual ~Expression();
|
||||
virtual void Write(FILE* to) = 0;
|
||||
};
|
||||
|
||||
struct LiteralExpression : public Expression
|
||||
{
|
||||
string value;
|
||||
|
||||
LiteralExpression(const string& value);
|
||||
virtual ~LiteralExpression();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
// TODO: also escape the contents. not needed for now
|
||||
struct StringLiteralExpression : public Expression
|
||||
{
|
||||
string value;
|
||||
|
||||
StringLiteralExpression(const string& value);
|
||||
virtual ~StringLiteralExpression();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Variable : public Expression
|
||||
{
|
||||
Type* type;
|
||||
string name;
|
||||
int dimension;
|
||||
|
||||
Variable();
|
||||
Variable(Type* type, const string& name);
|
||||
Variable(Type* type, const string& name, int dimension);
|
||||
virtual ~Variable();
|
||||
|
||||
virtual void GatherTypes(set<Type*>* types) const;
|
||||
void WriteDeclaration(FILE* to);
|
||||
void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct FieldVariable : public Expression
|
||||
{
|
||||
Expression* object;
|
||||
Type* clazz;
|
||||
string name;
|
||||
|
||||
FieldVariable(Expression* object, const string& name);
|
||||
FieldVariable(Type* clazz, const string& name);
|
||||
virtual ~FieldVariable();
|
||||
|
||||
void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Field : public ClassElement
|
||||
{
|
||||
string comment;
|
||||
int modifiers;
|
||||
Variable *variable;
|
||||
string value;
|
||||
|
||||
Field();
|
||||
Field(int modifiers, Variable* variable);
|
||||
virtual ~Field();
|
||||
|
||||
virtual void GatherTypes(set<Type*>* types) const;
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Statement
|
||||
{
|
||||
virtual ~Statement();
|
||||
virtual void Write(FILE* to) = 0;
|
||||
};
|
||||
|
||||
struct StatementBlock : public Statement
|
||||
{
|
||||
vector<Statement*> statements;
|
||||
|
||||
StatementBlock();
|
||||
virtual ~StatementBlock();
|
||||
virtual void Write(FILE* to);
|
||||
|
||||
void Add(Statement* statement);
|
||||
void Add(Expression* expression);
|
||||
};
|
||||
|
||||
struct ExpressionStatement : public Statement
|
||||
{
|
||||
Expression* expression;
|
||||
|
||||
ExpressionStatement(Expression* expression);
|
||||
virtual ~ExpressionStatement();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Assignment : public Expression
|
||||
{
|
||||
Variable* lvalue;
|
||||
Expression* rvalue;
|
||||
Type* cast;
|
||||
|
||||
Assignment(Variable* lvalue, Expression* rvalue);
|
||||
Assignment(Variable* lvalue, Expression* rvalue, Type* cast);
|
||||
virtual ~Assignment();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct MethodCall : public Expression
|
||||
{
|
||||
Expression* obj;
|
||||
Type* clazz;
|
||||
string name;
|
||||
vector<Expression*> arguments;
|
||||
vector<string> exceptions;
|
||||
|
||||
MethodCall(const string& name);
|
||||
MethodCall(const string& name, int argc, ...);
|
||||
MethodCall(Expression* obj, const string& name);
|
||||
MethodCall(Type* clazz, const string& name);
|
||||
MethodCall(Expression* obj, const string& name, int argc, ...);
|
||||
MethodCall(Type* clazz, const string& name, int argc, ...);
|
||||
virtual ~MethodCall();
|
||||
virtual void Write(FILE* to);
|
||||
|
||||
private:
|
||||
void init(int n, va_list args);
|
||||
};
|
||||
|
||||
struct Comparison : public Expression
|
||||
{
|
||||
Expression* lvalue;
|
||||
string op;
|
||||
Expression* rvalue;
|
||||
|
||||
Comparison(Expression* lvalue, const string& op, Expression* rvalue);
|
||||
virtual ~Comparison();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct NewExpression : public Expression
|
||||
{
|
||||
Type* type;
|
||||
vector<Expression*> arguments;
|
||||
|
||||
NewExpression(Type* type);
|
||||
NewExpression(Type* type, int argc, ...);
|
||||
virtual ~NewExpression();
|
||||
virtual void Write(FILE* to);
|
||||
|
||||
private:
|
||||
void init(int n, va_list args);
|
||||
};
|
||||
|
||||
struct NewArrayExpression : public Expression
|
||||
{
|
||||
Type* type;
|
||||
Expression* size;
|
||||
|
||||
NewArrayExpression(Type* type, Expression* size);
|
||||
virtual ~NewArrayExpression();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Ternary : public Expression
|
||||
{
|
||||
Expression* condition;
|
||||
Expression* ifpart;
|
||||
Expression* elsepart;
|
||||
|
||||
Ternary();
|
||||
Ternary(Expression* condition, Expression* ifpart, Expression* elsepart);
|
||||
virtual ~Ternary();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Cast : public Expression
|
||||
{
|
||||
Type* type;
|
||||
Expression* expression;
|
||||
|
||||
Cast();
|
||||
Cast(Type* type, Expression* expression);
|
||||
virtual ~Cast();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct VariableDeclaration : public Statement
|
||||
{
|
||||
Variable* lvalue;
|
||||
Type* cast;
|
||||
Expression* rvalue;
|
||||
|
||||
VariableDeclaration(Variable* lvalue);
|
||||
VariableDeclaration(Variable* lvalue, Expression* rvalue, Type* cast = NULL);
|
||||
virtual ~VariableDeclaration();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct IfStatement : public Statement
|
||||
{
|
||||
Expression* expression;
|
||||
StatementBlock* statements;
|
||||
IfStatement* elseif;
|
||||
|
||||
IfStatement();
|
||||
virtual ~IfStatement();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct ReturnStatement : public Statement
|
||||
{
|
||||
Expression* expression;
|
||||
|
||||
ReturnStatement(Expression* expression);
|
||||
virtual ~ReturnStatement();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct TryStatement : public Statement
|
||||
{
|
||||
StatementBlock* statements;
|
||||
|
||||
TryStatement();
|
||||
virtual ~TryStatement();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct CatchStatement : public Statement
|
||||
{
|
||||
StatementBlock* statements;
|
||||
Variable* exception;
|
||||
|
||||
CatchStatement(Variable* exception);
|
||||
virtual ~CatchStatement();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct FinallyStatement : public Statement
|
||||
{
|
||||
StatementBlock* statements;
|
||||
|
||||
FinallyStatement();
|
||||
virtual ~FinallyStatement();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Case
|
||||
{
|
||||
vector<string> cases;
|
||||
StatementBlock* statements;
|
||||
|
||||
Case();
|
||||
Case(const string& c);
|
||||
virtual ~Case();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct SwitchStatement : public Statement
|
||||
{
|
||||
Expression* expression;
|
||||
vector<Case*> cases;
|
||||
|
||||
SwitchStatement(Expression* expression);
|
||||
virtual ~SwitchStatement();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Break : public Statement
|
||||
{
|
||||
Break();
|
||||
virtual ~Break();
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Method : public ClassElement
|
||||
{
|
||||
string comment;
|
||||
int modifiers;
|
||||
Type* returnType;
|
||||
size_t returnTypeDimension;
|
||||
string name;
|
||||
vector<Variable*> parameters;
|
||||
vector<Type*> exceptions;
|
||||
StatementBlock* statements;
|
||||
|
||||
Method();
|
||||
virtual ~Method();
|
||||
|
||||
virtual void GatherTypes(set<Type*>* types) const;
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Class : public ClassElement
|
||||
{
|
||||
enum {
|
||||
CLASS,
|
||||
INTERFACE
|
||||
};
|
||||
|
||||
string comment;
|
||||
int modifiers;
|
||||
int what; // CLASS or INTERFACE
|
||||
Type* type;
|
||||
Type* extends;
|
||||
vector<Type*> interfaces;
|
||||
vector<ClassElement*> elements;
|
||||
|
||||
Class();
|
||||
virtual ~Class();
|
||||
|
||||
virtual void GatherTypes(set<Type*>* types) const;
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
struct Document
|
||||
{
|
||||
string comment;
|
||||
string package;
|
||||
string originalSrc;
|
||||
set<Type*> imports;
|
||||
vector<Class*> classes;
|
||||
|
||||
Document();
|
||||
virtual ~Document();
|
||||
|
||||
virtual void Write(FILE* to);
|
||||
};
|
||||
|
||||
#endif // AIDL_AST_H
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright 2007 The Android Open Source Project
|
||||
#
|
||||
# Copies files into the directory structure described by a manifest
|
||||
|
||||
# This tool is prebuilt if we're doing an app-only build.
|
||||
ifeq ($(TARGET_BUILD_APPS),)
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
aidl_language_l.l \
|
||||
aidl_language_y.y \
|
||||
aidl.cpp \
|
||||
aidl_language.cpp \
|
||||
options.cpp \
|
||||
search_path.cpp \
|
||||
AST.cpp \
|
||||
Type.cpp \
|
||||
generate_java.cpp \
|
||||
generate_java_binder.cpp \
|
||||
generate_java_rpc.cpp
|
||||
|
||||
LOCAL_CFLAGS := -g
|
||||
LOCAL_MODULE := aidl
|
||||
|
||||
include $(BUILD_HOST_EXECUTABLE)
|
||||
|
||||
endif # TARGET_BUILD_APPS
|
||||
@@ -1,190 +0,0 @@
|
||||
|
||||
Copyright (c) 2005-2008, The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
1440
tools/aidl/Type.cpp
@@ -1,542 +0,0 @@
|
||||
#ifndef AIDL_TYPE_H
|
||||
#define AIDL_TYPE_H
|
||||
|
||||
#include "AST.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Type
|
||||
{
|
||||
public:
|
||||
// kinds
|
||||
enum {
|
||||
BUILT_IN,
|
||||
USERDATA,
|
||||
INTERFACE,
|
||||
GENERATED
|
||||
};
|
||||
|
||||
// WriteToParcel flags
|
||||
enum {
|
||||
PARCELABLE_WRITE_RETURN_VALUE = 0x0001
|
||||
};
|
||||
|
||||
Type(const string& name, int kind, bool canWriteToParcel,
|
||||
bool canWriteToRpcData, bool canBeOut);
|
||||
Type(const string& package, const string& name,
|
||||
int kind, bool canWriteToParcel, bool canWriteToRpcData, bool canBeOut,
|
||||
const string& declFile = "", int declLine = -1);
|
||||
virtual ~Type();
|
||||
|
||||
inline string Package() const { return m_package; }
|
||||
inline string Name() const { return m_name; }
|
||||
inline string QualifiedName() const { return m_qualifiedName; }
|
||||
inline int Kind() const { return m_kind; }
|
||||
inline string DeclFile() const { return m_declFile; }
|
||||
inline int DeclLine() const { return m_declLine; }
|
||||
inline bool CanWriteToParcel() const { return m_canWriteToParcel; }
|
||||
inline bool CanWriteToRpcData() const { return m_canWriteToRpcData; }
|
||||
inline bool CanBeOutParameter() const { return m_canBeOut; }
|
||||
|
||||
virtual string ImportType() const;
|
||||
virtual string CreatorName() const;
|
||||
virtual string RpcCreatorName() const;
|
||||
virtual string InstantiableName() const;
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual bool CanBeArray() const;
|
||||
|
||||
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, int flags);
|
||||
virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, Variable** cl);
|
||||
|
||||
protected:
|
||||
void SetQualifiedName(const string& qualified);
|
||||
Expression* BuildWriteToParcelFlags(int flags);
|
||||
|
||||
private:
|
||||
Type();
|
||||
Type(const Type&);
|
||||
|
||||
string m_package;
|
||||
string m_name;
|
||||
string m_qualifiedName;
|
||||
string m_declFile;
|
||||
int m_declLine;
|
||||
int m_kind;
|
||||
bool m_canWriteToParcel;
|
||||
bool m_canWriteToRpcData;
|
||||
bool m_canBeOut;
|
||||
};
|
||||
|
||||
class BasicType : public Type
|
||||
{
|
||||
public:
|
||||
BasicType(const string& name,
|
||||
const string& marshallParcel,
|
||||
const string& unmarshallParcel,
|
||||
const string& writeArrayParcel,
|
||||
const string& createArrayParcel,
|
||||
const string& readArrayParcel,
|
||||
const string& marshallRpc,
|
||||
const string& unmarshallRpc,
|
||||
const string& writeArrayRpc,
|
||||
const string& createArrayRpc,
|
||||
const string& readArrayRpc);
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual bool CanBeArray() const;
|
||||
|
||||
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, int flags);
|
||||
virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, Variable** cl);
|
||||
|
||||
private:
|
||||
string m_marshallParcel;
|
||||
string m_unmarshallParcel;
|
||||
string m_writeArrayParcel;
|
||||
string m_createArrayParcel;
|
||||
string m_readArrayParcel;
|
||||
string m_marshallRpc;
|
||||
string m_unmarshallRpc;
|
||||
string m_writeArrayRpc;
|
||||
string m_createArrayRpc;
|
||||
string m_readArrayRpc;
|
||||
};
|
||||
|
||||
class BooleanType : public Type
|
||||
{
|
||||
public:
|
||||
BooleanType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual bool CanBeArray() const;
|
||||
|
||||
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, int flags);
|
||||
virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, Variable** cl);
|
||||
};
|
||||
|
||||
class CharType : public Type
|
||||
{
|
||||
public:
|
||||
CharType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual bool CanBeArray() const;
|
||||
|
||||
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, int flags);
|
||||
virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, Variable** cl);
|
||||
};
|
||||
|
||||
|
||||
class StringType : public Type
|
||||
{
|
||||
public:
|
||||
StringType();
|
||||
|
||||
virtual string CreatorName() const;
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual bool CanBeArray() const;
|
||||
|
||||
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, int flags);
|
||||
virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, Variable** cl);
|
||||
};
|
||||
|
||||
class CharSequenceType : public Type
|
||||
{
|
||||
public:
|
||||
CharSequenceType();
|
||||
|
||||
virtual string CreatorName() const;
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class RemoteExceptionType : public Type
|
||||
{
|
||||
public:
|
||||
RemoteExceptionType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class RuntimeExceptionType : public Type
|
||||
{
|
||||
public:
|
||||
RuntimeExceptionType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class IBinderType : public Type
|
||||
{
|
||||
public:
|
||||
IBinderType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class IInterfaceType : public Type
|
||||
{
|
||||
public:
|
||||
IInterfaceType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class BinderType : public Type
|
||||
{
|
||||
public:
|
||||
BinderType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class BinderProxyType : public Type
|
||||
{
|
||||
public:
|
||||
BinderProxyType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class ParcelType : public Type
|
||||
{
|
||||
public:
|
||||
ParcelType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class ParcelableInterfaceType : public Type
|
||||
{
|
||||
public:
|
||||
ParcelableInterfaceType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class MapType : public Type
|
||||
{
|
||||
public:
|
||||
MapType();
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
};
|
||||
|
||||
class ListType : public Type
|
||||
{
|
||||
public:
|
||||
ListType();
|
||||
|
||||
virtual string InstantiableName() const;
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, int flags);
|
||||
virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, Variable** cl);
|
||||
};
|
||||
|
||||
class UserDataType : public Type
|
||||
{
|
||||
public:
|
||||
UserDataType(const string& package, const string& name,
|
||||
bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
|
||||
const string& declFile = "", int declLine = -1);
|
||||
|
||||
virtual string CreatorName() const;
|
||||
virtual string RpcCreatorName() const;
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual bool CanBeArray() const;
|
||||
|
||||
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, int flags);
|
||||
virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, Variable** cl);
|
||||
};
|
||||
|
||||
class InterfaceType : public Type
|
||||
{
|
||||
public:
|
||||
InterfaceType(const string& package, const string& name,
|
||||
bool builtIn, bool oneway,
|
||||
const string& declFile, int declLine);
|
||||
|
||||
bool OneWay() const;
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
private:
|
||||
bool m_oneway;
|
||||
};
|
||||
|
||||
|
||||
class GenericType : public Type
|
||||
{
|
||||
public:
|
||||
GenericType(const string& package, const string& name,
|
||||
const vector<Type*>& args);
|
||||
|
||||
const vector<Type*>& GenericArgumentTypes() const;
|
||||
string GenericArguments() const;
|
||||
|
||||
virtual string ImportType() const;
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
private:
|
||||
string m_genericArguments;
|
||||
string m_importName;
|
||||
vector<Type*> m_args;
|
||||
};
|
||||
|
||||
class RpcDataType : public UserDataType
|
||||
{
|
||||
public:
|
||||
RpcDataType();
|
||||
|
||||
virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, int flags);
|
||||
virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, Variable** cl);
|
||||
};
|
||||
|
||||
class ClassLoaderType : public Type
|
||||
{
|
||||
public:
|
||||
ClassLoaderType();
|
||||
};
|
||||
|
||||
class GenericListType : public GenericType
|
||||
{
|
||||
public:
|
||||
GenericListType(const string& package, const string& name,
|
||||
const vector<Type*>& args);
|
||||
|
||||
virtual string CreatorName() const;
|
||||
virtual string InstantiableName() const;
|
||||
|
||||
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags);
|
||||
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl);
|
||||
|
||||
virtual void WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, int flags);
|
||||
virtual void CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
|
||||
Variable* data, Variable** cl);
|
||||
|
||||
private:
|
||||
string m_creator;
|
||||
};
|
||||
|
||||
class Namespace
|
||||
{
|
||||
public:
|
||||
Namespace();
|
||||
~Namespace();
|
||||
void Add(Type* type);
|
||||
|
||||
// args is the number of template types (what is this called?)
|
||||
void AddGenericType(const string& package, const string& name, int args);
|
||||
|
||||
// lookup a specific class name
|
||||
Type* Find(const string& name) const;
|
||||
Type* Find(const char* package, const char* name) const;
|
||||
|
||||
// try to search by either a full name or a partial name
|
||||
Type* Search(const string& name);
|
||||
|
||||
void Dump() const;
|
||||
|
||||
private:
|
||||
struct Generic {
|
||||
string package;
|
||||
string name;
|
||||
string qualified;
|
||||
int args;
|
||||
};
|
||||
|
||||
const Generic* search_generic(const string& name) const;
|
||||
|
||||
vector<Type*> m_types;
|
||||
vector<Generic> m_generics;
|
||||
};
|
||||
|
||||
extern Namespace NAMES;
|
||||
|
||||
extern Type* VOID_TYPE;
|
||||
extern Type* BOOLEAN_TYPE;
|
||||
extern Type* BYTE_TYPE;
|
||||
extern Type* CHAR_TYPE;
|
||||
extern Type* INT_TYPE;
|
||||
extern Type* LONG_TYPE;
|
||||
extern Type* FLOAT_TYPE;
|
||||
extern Type* DOUBLE_TYPE;
|
||||
extern Type* OBJECT_TYPE;
|
||||
extern Type* STRING_TYPE;
|
||||
extern Type* CHAR_SEQUENCE_TYPE;
|
||||
extern Type* TEXT_UTILS_TYPE;
|
||||
extern Type* REMOTE_EXCEPTION_TYPE;
|
||||
extern Type* RUNTIME_EXCEPTION_TYPE;
|
||||
extern Type* IBINDER_TYPE;
|
||||
extern Type* IINTERFACE_TYPE;
|
||||
extern Type* BINDER_NATIVE_TYPE;
|
||||
extern Type* BINDER_PROXY_TYPE;
|
||||
extern Type* PARCEL_TYPE;
|
||||
extern Type* PARCELABLE_INTERFACE_TYPE;
|
||||
|
||||
extern Type* CONTEXT_TYPE;
|
||||
|
||||
extern Type* RPC_DATA_TYPE;
|
||||
extern Type* RPC_ERROR_TYPE;
|
||||
extern Type* RPC_CONTEXT_TYPE;
|
||||
extern Type* EVENT_FAKE_TYPE;
|
||||
|
||||
extern Expression* NULL_VALUE;
|
||||
extern Expression* THIS_VALUE;
|
||||
extern Expression* SUPER_VALUE;
|
||||
extern Expression* TRUE_VALUE;
|
||||
extern Expression* FALSE_VALUE;
|
||||
|
||||
void register_base_types();
|
||||
|
||||
#endif // AIDL_TYPE_H
|
||||
1155
tools/aidl/aidl.cpp
@@ -1,20 +0,0 @@
|
||||
#include "aidl_language.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_MS_C_RUNTIME
|
||||
int isatty(int fd)
|
||||
{
|
||||
return (fd == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
ParserCallbacks k_parserCallbacks = {
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
ParserCallbacks* g_callbacks = NULL; // &k_parserCallbacks;
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
#ifndef DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
|
||||
#define DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
|
||||
|
||||
|
||||
typedef enum {
|
||||
NO_EXTRA_TEXT = 0,
|
||||
SHORT_COMMENT,
|
||||
LONG_COMMENT,
|
||||
COPY_TEXT,
|
||||
WHITESPACE
|
||||
} which_extra_text;
|
||||
|
||||
typedef struct extra_text_type {
|
||||
unsigned lineno;
|
||||
which_extra_text which;
|
||||
char* data;
|
||||
unsigned len;
|
||||
struct extra_text_type* next;
|
||||
} extra_text_type;
|
||||
|
||||
typedef struct buffer_type {
|
||||
unsigned lineno;
|
||||
unsigned token;
|
||||
char *data;
|
||||
extra_text_type* extra;
|
||||
} buffer_type;
|
||||
|
||||
typedef struct type_type {
|
||||
buffer_type type;
|
||||
buffer_type array_token;
|
||||
int dimension;
|
||||
} type_type;
|
||||
|
||||
typedef struct arg_type {
|
||||
buffer_type comma_token; // empty in the first one in the list
|
||||
buffer_type direction;
|
||||
type_type type;
|
||||
buffer_type name;
|
||||
struct arg_type *next;
|
||||
} arg_type;
|
||||
|
||||
enum {
|
||||
METHOD_TYPE
|
||||
};
|
||||
|
||||
typedef struct interface_item_type {
|
||||
unsigned item_type;
|
||||
struct interface_item_type* next;
|
||||
} interface_item_type;
|
||||
|
||||
typedef struct method_type {
|
||||
interface_item_type interface_item;
|
||||
type_type type;
|
||||
bool oneway;
|
||||
buffer_type oneway_token;
|
||||
buffer_type name;
|
||||
buffer_type open_paren_token;
|
||||
arg_type* args;
|
||||
buffer_type close_paren_token;
|
||||
bool hasId;
|
||||
buffer_type equals_token;
|
||||
buffer_type id;
|
||||
// XXX missing comments/copy text here
|
||||
buffer_type semicolon_token;
|
||||
buffer_type* comments_token; // points into this structure, DO NOT DELETE
|
||||
int assigned_id;
|
||||
} method_type;
|
||||
|
||||
enum {
|
||||
USER_DATA_TYPE = 12,
|
||||
INTERFACE_TYPE_BINDER,
|
||||
INTERFACE_TYPE_RPC
|
||||
};
|
||||
|
||||
typedef struct document_item_type {
|
||||
unsigned item_type;
|
||||
struct document_item_type* next;
|
||||
} document_item_type;
|
||||
|
||||
|
||||
// for user_data_type.flattening_methods
|
||||
enum {
|
||||
PARCELABLE_DATA = 0x1,
|
||||
RPC_DATA = 0x2
|
||||
};
|
||||
|
||||
typedef struct user_data_type {
|
||||
document_item_type document_item;
|
||||
buffer_type keyword_token; // only the first one
|
||||
char* package;
|
||||
buffer_type name;
|
||||
buffer_type semicolon_token;
|
||||
int flattening_methods;
|
||||
} user_data_type;
|
||||
|
||||
typedef struct interface_type {
|
||||
document_item_type document_item;
|
||||
buffer_type interface_token;
|
||||
bool oneway;
|
||||
buffer_type oneway_token;
|
||||
char* package;
|
||||
buffer_type name;
|
||||
buffer_type open_brace_token;
|
||||
interface_item_type* interface_items;
|
||||
buffer_type close_brace_token;
|
||||
buffer_type* comments_token; // points into this structure, DO NOT DELETE
|
||||
} interface_type;
|
||||
|
||||
typedef union lexer_type {
|
||||
buffer_type buffer;
|
||||
type_type type;
|
||||
arg_type *arg;
|
||||
method_type* method;
|
||||
interface_item_type* interface_item;
|
||||
interface_type* interface_obj;
|
||||
user_data_type* user_data;
|
||||
document_item_type* document_item;
|
||||
} lexer_type;
|
||||
|
||||
|
||||
#define YYSTYPE lexer_type
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int parse_aidl(char const *);
|
||||
|
||||
// strips off the leading whitespace, the "import" text
|
||||
// also returns whether it's a local or system import
|
||||
// we rely on the input matching the import regex from below
|
||||
char* parse_import_statement(const char* text);
|
||||
|
||||
// in, out or inout
|
||||
enum {
|
||||
IN_PARAMETER = 1,
|
||||
OUT_PARAMETER = 2,
|
||||
INOUT_PARAMETER = 3
|
||||
};
|
||||
int convert_direction(const char* direction);
|
||||
|
||||
// callbacks from within the parser
|
||||
// these functions all take ownership of the strings
|
||||
typedef struct ParserCallbacks {
|
||||
void (*document)(document_item_type* items);
|
||||
void (*import)(buffer_type* statement);
|
||||
} ParserCallbacks;
|
||||
|
||||
extern ParserCallbacks* g_callbacks;
|
||||
|
||||
// true if there was an error parsing, false otherwise
|
||||
extern int g_error;
|
||||
|
||||
// the name of the file we're currently parsing
|
||||
extern char const* g_currentFilename;
|
||||
|
||||
// the package name for our current file
|
||||
extern char const* g_currentPackage;
|
||||
|
||||
typedef enum {
|
||||
STATEMENT_INSIDE_INTERFACE
|
||||
} error_type;
|
||||
|
||||
void init_buffer_type(buffer_type* buf, int lineno);
|
||||
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
|
||||
@@ -1,214 +0,0 @@
|
||||
%{
|
||||
#include "aidl_language.h"
|
||||
#include "aidl_language_y.h"
|
||||
#include "search_path.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
// comment and whitespace handling
|
||||
// these functions save a copy of the buffer
|
||||
static void begin_extra_text(unsigned lineno, which_extra_text which);
|
||||
static void append_extra_text(char* text);
|
||||
static extra_text_type* get_extra_text(void); // you now own the object
|
||||
// this returns
|
||||
static void drop_extra_text(void);
|
||||
|
||||
// package handling
|
||||
static void do_package_statement(const char* importText);
|
||||
|
||||
#define SET_BUFFER(t) \
|
||||
do { \
|
||||
yylval.buffer.lineno = yylineno; \
|
||||
yylval.buffer.token = (t); \
|
||||
yylval.buffer.data = strdup(yytext); \
|
||||
yylval.buffer.extra = get_extra_text(); \
|
||||
} while(0)
|
||||
|
||||
%}
|
||||
|
||||
%option yylineno
|
||||
%option noyywrap
|
||||
|
||||
%x COPYING LONG_COMMENT
|
||||
|
||||
identifier [_a-zA-Z][_a-zA-Z0-9\.]*
|
||||
whitespace ([ \t\n\r]+)
|
||||
brackets \[{whitespace}?\]
|
||||
idvalue (0|[1-9][0-9]*)
|
||||
|
||||
%%
|
||||
|
||||
|
||||
\%\%\{ { begin_extra_text(yylineno, COPY_TEXT); BEGIN(COPYING); }
|
||||
<COPYING>\}\%\% { BEGIN(INITIAL); }
|
||||
<COPYING>.*\n { append_extra_text(yytext); }
|
||||
<COPYING>.* { append_extra_text(yytext); }
|
||||
<COPYING>\n+ { append_extra_text(yytext); }
|
||||
|
||||
|
||||
\/\* { begin_extra_text(yylineno, (which_extra_text)LONG_COMMENT);
|
||||
BEGIN(LONG_COMMENT); }
|
||||
<LONG_COMMENT>[^*]* { append_extra_text(yytext); }
|
||||
<LONG_COMMENT>\*+[^/] { append_extra_text(yytext); }
|
||||
<LONG_COMMENT>\n { append_extra_text(yytext); }
|
||||
<LONG_COMMENT>\**\/ { BEGIN(INITIAL); }
|
||||
|
||||
^{whitespace}?import{whitespace}[^ \t\r\n]+{whitespace}?; {
|
||||
SET_BUFFER(IMPORT);
|
||||
return IMPORT;
|
||||
}
|
||||
^{whitespace}?package{whitespace}[^ \t\r\n]+{whitespace}?; {
|
||||
do_package_statement(yytext);
|
||||
SET_BUFFER(PACKAGE);
|
||||
return PACKAGE;
|
||||
}
|
||||
<<EOF>> { yyterminate(); }
|
||||
|
||||
\/\/.*\n { begin_extra_text(yylineno, SHORT_COMMENT);
|
||||
append_extra_text(yytext); }
|
||||
|
||||
{whitespace} { /* begin_extra_text(yylineno, WHITESPACE);
|
||||
append_extra_text(yytext); */ }
|
||||
|
||||
; { SET_BUFFER(';'); return ';'; }
|
||||
\{ { SET_BUFFER('{'); return '{'; }
|
||||
\} { SET_BUFFER('}'); return '}'; }
|
||||
\( { SET_BUFFER('('); return '('; }
|
||||
\) { SET_BUFFER(')'); return ')'; }
|
||||
, { SET_BUFFER(','); return ','; }
|
||||
= { SET_BUFFER('='); return '='; }
|
||||
|
||||
/* keywords */
|
||||
parcelable { SET_BUFFER(PARCELABLE); return PARCELABLE; }
|
||||
interface { SET_BUFFER(INTERFACE); return INTERFACE; }
|
||||
flattenable { SET_BUFFER(FLATTENABLE); return FLATTENABLE; }
|
||||
rpc { SET_BUFFER(INTERFACE); return RPC; }
|
||||
in { SET_BUFFER(IN); return IN; }
|
||||
out { SET_BUFFER(OUT); return OUT; }
|
||||
inout { SET_BUFFER(INOUT); return INOUT; }
|
||||
oneway { SET_BUFFER(ONEWAY); return ONEWAY; }
|
||||
|
||||
{brackets}+ { SET_BUFFER(ARRAY); return ARRAY; }
|
||||
{idvalue} { SET_BUFFER(IDVALUE); return IDVALUE; }
|
||||
{identifier} { SET_BUFFER(IDENTIFIER); return IDENTIFIER; }
|
||||
{identifier}\<{whitespace}*{identifier}({whitespace}*,{whitespace}*{identifier})*{whitespace}*\> {
|
||||
SET_BUFFER(GENERIC); return GENERIC; }
|
||||
|
||||
/* syntax error! */
|
||||
. { printf("UNKNOWN(%s)", yytext);
|
||||
yylval.buffer.lineno = yylineno;
|
||||
yylval.buffer.token = IDENTIFIER;
|
||||
yylval.buffer.data = strdup(yytext);
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
// comment and whitespace handling
|
||||
// ================================================
|
||||
extra_text_type* g_extraText = NULL;
|
||||
extra_text_type* g_nextExtraText = NULL;
|
||||
|
||||
void begin_extra_text(unsigned lineno, which_extra_text which)
|
||||
{
|
||||
extra_text_type* text = (extra_text_type*)malloc(sizeof(extra_text_type));
|
||||
text->lineno = lineno;
|
||||
text->which = which;
|
||||
text->data = NULL;
|
||||
text->len = 0;
|
||||
text->next = NULL;
|
||||
if (g_nextExtraText == NULL) {
|
||||
g_extraText = text;
|
||||
} else {
|
||||
g_nextExtraText->next = text;
|
||||
}
|
||||
g_nextExtraText = text;
|
||||
}
|
||||
|
||||
void append_extra_text(char* text)
|
||||
{
|
||||
if (g_nextExtraText->data == NULL) {
|
||||
g_nextExtraText->data = strdup(text);
|
||||
g_nextExtraText->len = strlen(text);
|
||||
} else {
|
||||
char* orig = g_nextExtraText->data;
|
||||
unsigned oldLen = g_nextExtraText->len;
|
||||
unsigned len = strlen(text);
|
||||
g_nextExtraText->len += len;
|
||||
g_nextExtraText->data = (char*)malloc(g_nextExtraText->len+1);
|
||||
memcpy(g_nextExtraText->data, orig, oldLen);
|
||||
memcpy(g_nextExtraText->data+oldLen, text, len);
|
||||
g_nextExtraText->data[g_nextExtraText->len] = '\0';
|
||||
free(orig);
|
||||
}
|
||||
}
|
||||
|
||||
extra_text_type*
|
||||
get_extra_text(void)
|
||||
{
|
||||
extra_text_type* result = g_extraText;
|
||||
g_extraText = NULL;
|
||||
g_nextExtraText = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
void drop_extra_text(void)
|
||||
{
|
||||
extra_text_type* p = g_extraText;
|
||||
while (p) {
|
||||
extra_text_type* next = p->next;
|
||||
free(p->data);
|
||||
free(p);
|
||||
free(next);
|
||||
}
|
||||
g_extraText = NULL;
|
||||
g_nextExtraText = NULL;
|
||||
}
|
||||
|
||||
|
||||
// package handling
|
||||
// ================================================
|
||||
void do_package_statement(const char* importText)
|
||||
{
|
||||
if (g_currentPackage) free((void*)g_currentPackage);
|
||||
g_currentPackage = parse_import_statement(importText);
|
||||
}
|
||||
|
||||
|
||||
// main parse function
|
||||
// ================================================
|
||||
char const* g_currentFilename = NULL;
|
||||
char const* g_currentPackage = NULL;
|
||||
|
||||
int yyparse(void);
|
||||
|
||||
int parse_aidl(char const *filename)
|
||||
{
|
||||
yyin = fopen(filename, "r");
|
||||
if (yyin) {
|
||||
char const* oldFilename = g_currentFilename;
|
||||
char const* oldPackage = g_currentPackage;
|
||||
g_currentFilename = strdup(filename);
|
||||
|
||||
g_error = 0;
|
||||
yylineno = 1;
|
||||
int rv = yyparse();
|
||||
if (g_error != 0) {
|
||||
rv = g_error;
|
||||
}
|
||||
|
||||
free((void*)g_currentFilename);
|
||||
g_currentFilename = oldFilename;
|
||||
|
||||
if (g_currentPackage) free((void*)g_currentPackage);
|
||||
g_currentPackage = oldPackage;
|
||||
|
||||
return rv;
|
||||
} else {
|
||||
fprintf(stderr, "aidl: unable to open file for read: %s\n", filename);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,373 +0,0 @@
|
||||
%{
|
||||
#include "aidl_language.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int yyerror(char* errstr);
|
||||
int yylex(void);
|
||||
extern int yylineno;
|
||||
|
||||
static int count_brackets(const char*);
|
||||
|
||||
%}
|
||||
|
||||
%token IMPORT
|
||||
%token PACKAGE
|
||||
%token IDENTIFIER
|
||||
%token IDVALUE
|
||||
%token GENERIC
|
||||
%token ARRAY
|
||||
%token PARCELABLE
|
||||
%token INTERFACE
|
||||
%token FLATTENABLE
|
||||
%token RPC
|
||||
%token IN
|
||||
%token OUT
|
||||
%token INOUT
|
||||
%token ONEWAY
|
||||
|
||||
%%
|
||||
document:
|
||||
document_items { g_callbacks->document($1.document_item); }
|
||||
| headers document_items { g_callbacks->document($2.document_item); }
|
||||
;
|
||||
|
||||
headers:
|
||||
package { }
|
||||
| imports { }
|
||||
| package imports { }
|
||||
;
|
||||
|
||||
package:
|
||||
PACKAGE { }
|
||||
;
|
||||
|
||||
imports:
|
||||
IMPORT { g_callbacks->import(&($1.buffer)); }
|
||||
| IMPORT imports { g_callbacks->import(&($1.buffer)); }
|
||||
;
|
||||
|
||||
document_items:
|
||||
{ $$.document_item = NULL; }
|
||||
| document_items declaration {
|
||||
if ($2.document_item == NULL) {
|
||||
// error cases only
|
||||
$$ = $1;
|
||||
} else {
|
||||
document_item_type* p = $1.document_item;
|
||||
while (p && p->next) {
|
||||
p=p->next;
|
||||
}
|
||||
if (p) {
|
||||
p->next = (document_item_type*)$2.document_item;
|
||||
$$ = $1;
|
||||
} else {
|
||||
$$.document_item = (document_item_type*)$2.document_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
| document_items error {
|
||||
fprintf(stderr, "%s:%d: syntax error don't know what to do with \"%s\"\n", g_currentFilename,
|
||||
$2.buffer.lineno, $2.buffer.data);
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
declaration:
|
||||
parcelable_decl { $$.document_item = (document_item_type*)$1.user_data; }
|
||||
| interface_decl { $$.document_item = (document_item_type*)$1.interface_item; }
|
||||
;
|
||||
|
||||
parcelable_decl:
|
||||
PARCELABLE IDENTIFIER ';' {
|
||||
user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
|
||||
b->document_item.item_type = USER_DATA_TYPE;
|
||||
b->document_item.next = NULL;
|
||||
b->keyword_token = $1.buffer;
|
||||
b->name = $2.buffer;
|
||||
b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
|
||||
b->semicolon_token = $3.buffer;
|
||||
b->flattening_methods = PARCELABLE_DATA;
|
||||
$$.user_data = b;
|
||||
}
|
||||
| PARCELABLE ';' {
|
||||
fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
|
||||
g_currentFilename, $1.buffer.lineno);
|
||||
$$.user_data = NULL;
|
||||
}
|
||||
| PARCELABLE error ';' {
|
||||
fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n",
|
||||
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
|
||||
$$.user_data = NULL;
|
||||
}
|
||||
| FLATTENABLE IDENTIFIER ';' {
|
||||
user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
|
||||
b->document_item.item_type = USER_DATA_TYPE;
|
||||
b->document_item.next = NULL;
|
||||
b->keyword_token = $1.buffer;
|
||||
b->name = $2.buffer;
|
||||
b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
|
||||
b->semicolon_token = $3.buffer;
|
||||
b->flattening_methods = PARCELABLE_DATA | RPC_DATA;
|
||||
$$.user_data = b;
|
||||
}
|
||||
| FLATTENABLE ';' {
|
||||
fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name.\n",
|
||||
g_currentFilename, $1.buffer.lineno);
|
||||
$$.user_data = NULL;
|
||||
}
|
||||
| FLATTENABLE error ';' {
|
||||
fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name, saw \"%s\".\n",
|
||||
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
|
||||
$$.user_data = NULL;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
interface_header:
|
||||
INTERFACE {
|
||||
interface_type* c = (interface_type*)malloc(sizeof(interface_type));
|
||||
c->document_item.item_type = INTERFACE_TYPE_BINDER;
|
||||
c->document_item.next = NULL;
|
||||
c->interface_token = $1.buffer;
|
||||
c->oneway = false;
|
||||
memset(&c->oneway_token, 0, sizeof(buffer_type));
|
||||
c->comments_token = &c->interface_token;
|
||||
$$.interface_obj = c;
|
||||
}
|
||||
| ONEWAY INTERFACE {
|
||||
interface_type* c = (interface_type*)malloc(sizeof(interface_type));
|
||||
c->document_item.item_type = INTERFACE_TYPE_BINDER;
|
||||
c->document_item.next = NULL;
|
||||
c->interface_token = $2.buffer;
|
||||
c->oneway = true;
|
||||
c->oneway_token = $1.buffer;
|
||||
c->comments_token = &c->oneway_token;
|
||||
$$.interface_obj = c;
|
||||
}
|
||||
| RPC {
|
||||
interface_type* c = (interface_type*)malloc(sizeof(interface_type));
|
||||
c->document_item.item_type = INTERFACE_TYPE_RPC;
|
||||
c->document_item.next = NULL;
|
||||
c->interface_token = $1.buffer;
|
||||
c->oneway = false;
|
||||
memset(&c->oneway_token, 0, sizeof(buffer_type));
|
||||
c->comments_token = &c->interface_token;
|
||||
$$.interface_obj = c;
|
||||
}
|
||||
;
|
||||
|
||||
interface_keywords:
|
||||
INTERFACE
|
||||
| RPC
|
||||
;
|
||||
|
||||
interface_decl:
|
||||
interface_header IDENTIFIER '{' interface_items '}' {
|
||||
interface_type* c = $1.interface_obj;
|
||||
c->name = $2.buffer;
|
||||
c->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
|
||||
c->open_brace_token = $3.buffer;
|
||||
c->interface_items = $4.interface_item;
|
||||
c->close_brace_token = $5.buffer;
|
||||
$$.interface_obj = c;
|
||||
}
|
||||
| interface_keywords error '{' interface_items '}' {
|
||||
fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
|
||||
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
|
||||
$$.document_item = NULL;
|
||||
}
|
||||
| interface_keywords error '}' {
|
||||
fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
|
||||
g_currentFilename, $2.buffer.lineno, $2.buffer.data);
|
||||
$$.document_item = NULL;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
interface_items:
|
||||
{ $$.interface_item = NULL; }
|
||||
| interface_items method_decl {
|
||||
interface_item_type* p=$1.interface_item;
|
||||
while (p && p->next) {
|
||||
p=p->next;
|
||||
}
|
||||
if (p) {
|
||||
p->next = (interface_item_type*)$2.method;
|
||||
$$ = $1;
|
||||
} else {
|
||||
$$.interface_item = (interface_item_type*)$2.method;
|
||||
}
|
||||
}
|
||||
| interface_items error ';' {
|
||||
fprintf(stderr, "%s:%d: syntax error before ';' (expected method declaration)\n",
|
||||
g_currentFilename, $3.buffer.lineno);
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
method_decl:
|
||||
type IDENTIFIER '(' arg_list ')' ';' {
|
||||
method_type *method = (method_type*)malloc(sizeof(method_type));
|
||||
method->interface_item.item_type = METHOD_TYPE;
|
||||
method->interface_item.next = NULL;
|
||||
method->oneway = false;
|
||||
method->type = $1.type;
|
||||
memset(&method->oneway_token, 0, sizeof(buffer_type));
|
||||
method->name = $2.buffer;
|
||||
method->open_paren_token = $3.buffer;
|
||||
method->args = $4.arg;
|
||||
method->close_paren_token = $5.buffer;
|
||||
method->hasId = false;
|
||||
memset(&method->equals_token, 0, sizeof(buffer_type));
|
||||
memset(&method->id, 0, sizeof(buffer_type));
|
||||
method->semicolon_token = $6.buffer;
|
||||
method->comments_token = &method->type.type;
|
||||
$$.method = method;
|
||||
}
|
||||
| ONEWAY type IDENTIFIER '(' arg_list ')' ';' {
|
||||
method_type *method = (method_type*)malloc(sizeof(method_type));
|
||||
method->interface_item.item_type = METHOD_TYPE;
|
||||
method->interface_item.next = NULL;
|
||||
method->oneway = true;
|
||||
method->oneway_token = $1.buffer;
|
||||
method->type = $2.type;
|
||||
method->name = $3.buffer;
|
||||
method->open_paren_token = $4.buffer;
|
||||
method->args = $5.arg;
|
||||
method->close_paren_token = $6.buffer;
|
||||
method->hasId = false;
|
||||
memset(&method->equals_token, 0, sizeof(buffer_type));
|
||||
memset(&method->id, 0, sizeof(buffer_type));
|
||||
method->semicolon_token = $7.buffer;
|
||||
method->comments_token = &method->oneway_token;
|
||||
$$.method = method;
|
||||
}
|
||||
| type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';' {
|
||||
method_type *method = (method_type*)malloc(sizeof(method_type));
|
||||
method->interface_item.item_type = METHOD_TYPE;
|
||||
method->interface_item.next = NULL;
|
||||
method->oneway = false;
|
||||
memset(&method->oneway_token, 0, sizeof(buffer_type));
|
||||
method->type = $1.type;
|
||||
method->name = $2.buffer;
|
||||
method->open_paren_token = $3.buffer;
|
||||
method->args = $4.arg;
|
||||
method->close_paren_token = $5.buffer;
|
||||
method->hasId = true;
|
||||
method->equals_token = $6.buffer;
|
||||
method->id = $7.buffer;
|
||||
method->semicolon_token = $8.buffer;
|
||||
method->comments_token = &method->type.type;
|
||||
$$.method = method;
|
||||
}
|
||||
| ONEWAY type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';' {
|
||||
method_type *method = (method_type*)malloc(sizeof(method_type));
|
||||
method->interface_item.item_type = METHOD_TYPE;
|
||||
method->interface_item.next = NULL;
|
||||
method->oneway = true;
|
||||
method->oneway_token = $1.buffer;
|
||||
method->type = $2.type;
|
||||
method->name = $3.buffer;
|
||||
method->open_paren_token = $4.buffer;
|
||||
method->args = $5.arg;
|
||||
method->close_paren_token = $6.buffer;
|
||||
method->hasId = true;
|
||||
method->equals_token = $7.buffer;
|
||||
method->id = $8.buffer;
|
||||
method->semicolon_token = $9.buffer;
|
||||
method->comments_token = &method->oneway_token;
|
||||
$$.method = method;
|
||||
}
|
||||
;
|
||||
|
||||
arg_list:
|
||||
{ $$.arg = NULL; }
|
||||
| arg { $$ = $1; }
|
||||
| arg_list ',' arg {
|
||||
if ($$.arg != NULL) {
|
||||
// only NULL on error
|
||||
$$ = $1;
|
||||
arg_type *p = $1.arg;
|
||||
while (p && p->next) {
|
||||
p=p->next;
|
||||
}
|
||||
$3.arg->comma_token = $2.buffer;
|
||||
p->next = $3.arg;
|
||||
}
|
||||
}
|
||||
| error {
|
||||
fprintf(stderr, "%s:%d: syntax error in parameter list\n", g_currentFilename, $1.buffer.lineno);
|
||||
$$.arg = NULL;
|
||||
}
|
||||
;
|
||||
|
||||
arg:
|
||||
direction type IDENTIFIER {
|
||||
arg_type* arg = (arg_type*)malloc(sizeof(arg_type));
|
||||
memset(&arg->comma_token, 0, sizeof(buffer_type));
|
||||
arg->direction = $1.buffer;
|
||||
arg->type = $2.type;
|
||||
arg->name = $3.buffer;
|
||||
arg->next = NULL;
|
||||
$$.arg = arg;
|
||||
}
|
||||
;
|
||||
|
||||
type:
|
||||
IDENTIFIER {
|
||||
$$.type.type = $1.buffer;
|
||||
init_buffer_type(&$$.type.array_token, yylineno);
|
||||
$$.type.dimension = 0;
|
||||
}
|
||||
| IDENTIFIER ARRAY {
|
||||
$$.type.type = $1.buffer;
|
||||
$$.type.array_token = $2.buffer;
|
||||
$$.type.dimension = count_brackets($2.buffer.data);
|
||||
}
|
||||
| GENERIC {
|
||||
$$.type.type = $1.buffer;
|
||||
init_buffer_type(&$$.type.array_token, yylineno);
|
||||
$$.type.dimension = 0;
|
||||
}
|
||||
;
|
||||
|
||||
direction:
|
||||
{ init_buffer_type(&$$.buffer, yylineno); }
|
||||
| IN { $$.buffer = $1.buffer; }
|
||||
| OUT { $$.buffer = $1.buffer; }
|
||||
| INOUT { $$.buffer = $1.buffer; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int g_error = 0;
|
||||
|
||||
int yyerror(char* errstr)
|
||||
{
|
||||
fprintf(stderr, "%s:%d: %s\n", g_currentFilename, yylineno, errstr);
|
||||
g_error = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void init_buffer_type(buffer_type* buf, int lineno)
|
||||
{
|
||||
buf->lineno = lineno;
|
||||
buf->token = 0;
|
||||
buf->data = NULL;
|
||||
buf->extra = NULL;
|
||||
}
|
||||
|
||||
static int count_brackets(const char* s)
|
||||
{
|
||||
int n=0;
|
||||
while (*s) {
|
||||
if (*s == '[') n++;
|
||||
s++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
#include "generate_java.h"
|
||||
#include "Type.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// =================================================
|
||||
VariableFactory::VariableFactory(const string& base)
|
||||
:m_base(base),
|
||||
m_index(0)
|
||||
{
|
||||
}
|
||||
|
||||
Variable*
|
||||
VariableFactory::Get(Type* type)
|
||||
{
|
||||
char name[100];
|
||||
sprintf(name, "%s%d", m_base.c_str(), m_index);
|
||||
m_index++;
|
||||
Variable* v = new Variable(type, name);
|
||||
m_vars.push_back(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
Variable*
|
||||
VariableFactory::Get(int index)
|
||||
{
|
||||
return m_vars[index];
|
||||
}
|
||||
|
||||
// =================================================
|
||||
string
|
||||
gather_comments(extra_text_type* extra)
|
||||
{
|
||||
string s;
|
||||
while (extra) {
|
||||
if (extra->which == SHORT_COMMENT) {
|
||||
s += extra->data;
|
||||
}
|
||||
else if (extra->which == LONG_COMMENT) {
|
||||
s += "/*";
|
||||
s += extra->data;
|
||||
s += "*/";
|
||||
}
|
||||
extra = extra->next;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
string
|
||||
append(const char* a, const char* b)
|
||||
{
|
||||
string s = a;
|
||||
s += b;
|
||||
return s;
|
||||
}
|
||||
|
||||
// =================================================
|
||||
int
|
||||
generate_java(const string& filename, const string& originalSrc,
|
||||
interface_type* iface)
|
||||
{
|
||||
Class* cl;
|
||||
|
||||
if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
|
||||
cl = generate_binder_interface_class(iface);
|
||||
}
|
||||
else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
|
||||
cl = generate_rpc_interface_class(iface);
|
||||
}
|
||||
|
||||
Document* document = new Document;
|
||||
document->comment = "";
|
||||
if (iface->package) document->package = iface->package;
|
||||
document->originalSrc = originalSrc;
|
||||
document->classes.push_back(cl);
|
||||
|
||||
// printf("outputting... filename=%s\n", filename.c_str());
|
||||
FILE* to;
|
||||
if (filename == "-") {
|
||||
to = stdout;
|
||||
} else {
|
||||
/* open file in binary mode to ensure that the tool produces the
|
||||
* same output on all platforms !!
|
||||
*/
|
||||
to = fopen(filename.c_str(), "wb");
|
||||
if (to == NULL) {
|
||||
fprintf(stderr, "unable to open %s for write\n", filename.c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
document->Write(to);
|
||||
|
||||
fclose(to);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef GENERATE_JAVA_H
|
||||
#define GENERATE_JAVA_H
|
||||
|
||||
#include "aidl_language.h"
|
||||
#include "AST.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int generate_java(const string& filename, const string& originalSrc,
|
||||
interface_type* iface);
|
||||
|
||||
Class* generate_binder_interface_class(const interface_type* iface);
|
||||
Class* generate_rpc_interface_class(const interface_type* iface);
|
||||
|
||||
string gather_comments(extra_text_type* extra);
|
||||
string append(const char* a, const char* b);
|
||||
|
||||
class VariableFactory
|
||||
{
|
||||
public:
|
||||
VariableFactory(const string& base); // base must be short
|
||||
Variable* Get(Type* type);
|
||||
Variable* Get(int index);
|
||||
private:
|
||||
vector<Variable*> m_vars;
|
||||
string m_base;
|
||||
int m_index;
|
||||
};
|
||||
|
||||
#endif // GENERATE_JAVA_H
|
||||
|
||||
@@ -1,560 +0,0 @@
|
||||
#include "generate_java.h"
|
||||
#include "Type.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// =================================================
|
||||
class StubClass : public Class
|
||||
{
|
||||
public:
|
||||
StubClass(Type* type, Type* interfaceType);
|
||||
virtual ~StubClass();
|
||||
|
||||
Variable* transact_code;
|
||||
Variable* transact_data;
|
||||
Variable* transact_reply;
|
||||
Variable* transact_flags;
|
||||
SwitchStatement* transact_switch;
|
||||
private:
|
||||
void make_as_interface(Type* interfaceType);
|
||||
};
|
||||
|
||||
StubClass::StubClass(Type* type, Type* interfaceType)
|
||||
:Class()
|
||||
{
|
||||
this->comment = "/** Local-side IPC implementation stub class. */";
|
||||
this->modifiers = PUBLIC | ABSTRACT | STATIC;
|
||||
this->what = Class::CLASS;
|
||||
this->type = type;
|
||||
this->extends = BINDER_NATIVE_TYPE;
|
||||
this->interfaces.push_back(interfaceType);
|
||||
|
||||
// descriptor
|
||||
Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
|
||||
new Variable(STRING_TYPE, "DESCRIPTOR"));
|
||||
descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
|
||||
this->elements.push_back(descriptor);
|
||||
|
||||
// ctor
|
||||
Method* ctor = new Method;
|
||||
ctor->modifiers = PUBLIC;
|
||||
ctor->comment = "/** Construct the stub at attach it to the "
|
||||
"interface. */";
|
||||
ctor->name = "Stub";
|
||||
ctor->statements = new StatementBlock;
|
||||
MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
|
||||
2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
|
||||
ctor->statements->Add(attach);
|
||||
this->elements.push_back(ctor);
|
||||
|
||||
// asInterface
|
||||
make_as_interface(interfaceType);
|
||||
|
||||
// asBinder
|
||||
Method* asBinder = new Method;
|
||||
asBinder->modifiers = PUBLIC | OVERRIDE;
|
||||
asBinder->returnType = IBINDER_TYPE;
|
||||
asBinder->name = "asBinder";
|
||||
asBinder->statements = new StatementBlock;
|
||||
asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
|
||||
this->elements.push_back(asBinder);
|
||||
|
||||
// onTransact
|
||||
this->transact_code = new Variable(INT_TYPE, "code");
|
||||
this->transact_data = new Variable(PARCEL_TYPE, "data");
|
||||
this->transact_reply = new Variable(PARCEL_TYPE, "reply");
|
||||
this->transact_flags = new Variable(INT_TYPE, "flags");
|
||||
Method* onTransact = new Method;
|
||||
onTransact->modifiers = PUBLIC | OVERRIDE;
|
||||
onTransact->returnType = BOOLEAN_TYPE;
|
||||
onTransact->name = "onTransact";
|
||||
onTransact->parameters.push_back(this->transact_code);
|
||||
onTransact->parameters.push_back(this->transact_data);
|
||||
onTransact->parameters.push_back(this->transact_reply);
|
||||
onTransact->parameters.push_back(this->transact_flags);
|
||||
onTransact->statements = new StatementBlock;
|
||||
onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
|
||||
this->elements.push_back(onTransact);
|
||||
this->transact_switch = new SwitchStatement(this->transact_code);
|
||||
|
||||
onTransact->statements->Add(this->transact_switch);
|
||||
MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
|
||||
this->transact_code, this->transact_data,
|
||||
this->transact_reply, this->transact_flags);
|
||||
onTransact->statements->Add(new ReturnStatement(superCall));
|
||||
}
|
||||
|
||||
StubClass::~StubClass()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
StubClass::make_as_interface(Type *interfaceType)
|
||||
{
|
||||
Variable* obj = new Variable(IBINDER_TYPE, "obj");
|
||||
|
||||
Method* m = new Method;
|
||||
m->comment = "/**\n * Cast an IBinder object into an ";
|
||||
m->comment += interfaceType->QualifiedName();
|
||||
m->comment += " interface,\n";
|
||||
m->comment += " * generating a proxy if needed.\n */";
|
||||
m->modifiers = PUBLIC | STATIC;
|
||||
m->returnType = interfaceType;
|
||||
m->name = "asInterface";
|
||||
m->parameters.push_back(obj);
|
||||
m->statements = new StatementBlock;
|
||||
|
||||
IfStatement* ifstatement = new IfStatement();
|
||||
ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
|
||||
ifstatement->statements = new StatementBlock;
|
||||
ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
|
||||
m->statements->Add(ifstatement);
|
||||
|
||||
// IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
|
||||
MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
|
||||
queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
|
||||
IInterfaceType* iinType = new IInterfaceType();
|
||||
Variable *iin = new Variable(iinType, "iin");
|
||||
VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, NULL);
|
||||
m->statements->Add(iinVd);
|
||||
|
||||
// Ensure the instance type of the local object is as expected.
|
||||
// One scenario where this is needed is if another package (with a
|
||||
// different class loader) runs in the same process as the service.
|
||||
|
||||
// if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
|
||||
Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
|
||||
Comparison* instOfCheck = new Comparison(iin, " instanceof ",
|
||||
new LiteralExpression(interfaceType->QualifiedName()));
|
||||
IfStatement* instOfStatement = new IfStatement();
|
||||
instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
|
||||
instOfStatement->statements = new StatementBlock;
|
||||
instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
|
||||
m->statements->Add(instOfStatement);
|
||||
|
||||
string proxyType = interfaceType->QualifiedName();
|
||||
proxyType += ".Stub.Proxy";
|
||||
NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
|
||||
ne->arguments.push_back(obj);
|
||||
m->statements->Add(new ReturnStatement(ne));
|
||||
|
||||
this->elements.push_back(m);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================================================
|
||||
class ProxyClass : public Class
|
||||
{
|
||||
public:
|
||||
ProxyClass(Type* type, InterfaceType* interfaceType);
|
||||
virtual ~ProxyClass();
|
||||
|
||||
Variable* mRemote;
|
||||
bool mOneWay;
|
||||
};
|
||||
|
||||
ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
|
||||
:Class()
|
||||
{
|
||||
this->modifiers = PRIVATE | STATIC;
|
||||
this->what = Class::CLASS;
|
||||
this->type = type;
|
||||
this->interfaces.push_back(interfaceType);
|
||||
|
||||
mOneWay = interfaceType->OneWay();
|
||||
|
||||
// IBinder mRemote
|
||||
mRemote = new Variable(IBINDER_TYPE, "mRemote");
|
||||
this->elements.push_back(new Field(PRIVATE, mRemote));
|
||||
|
||||
// Proxy()
|
||||
Variable* remote = new Variable(IBINDER_TYPE, "remote");
|
||||
Method* ctor = new Method;
|
||||
ctor->name = "Proxy";
|
||||
ctor->statements = new StatementBlock;
|
||||
ctor->parameters.push_back(remote);
|
||||
ctor->statements->Add(new Assignment(mRemote, remote));
|
||||
this->elements.push_back(ctor);
|
||||
|
||||
// IBinder asBinder()
|
||||
Method* asBinder = new Method;
|
||||
asBinder->modifiers = PUBLIC | OVERRIDE;
|
||||
asBinder->returnType = IBINDER_TYPE;
|
||||
asBinder->name = "asBinder";
|
||||
asBinder->statements = new StatementBlock;
|
||||
asBinder->statements->Add(new ReturnStatement(mRemote));
|
||||
this->elements.push_back(asBinder);
|
||||
}
|
||||
|
||||
ProxyClass::~ProxyClass()
|
||||
{
|
||||
}
|
||||
|
||||
// =================================================
|
||||
static void
|
||||
generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel)
|
||||
{
|
||||
Variable* len = new Variable(INT_TYPE, v->name + "_length");
|
||||
addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
|
||||
IfStatement* lencheck = new IfStatement();
|
||||
lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
|
||||
lencheck->statements->Add(new Assignment(v, NULL_VALUE));
|
||||
lencheck->elseif = new IfStatement();
|
||||
lencheck->elseif->statements->Add(new Assignment(v,
|
||||
new NewArrayExpression(t, len)));
|
||||
addTo->Add(lencheck);
|
||||
}
|
||||
|
||||
static void
|
||||
generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, int flags)
|
||||
{
|
||||
if (v->dimension == 0) {
|
||||
t->WriteToParcel(addTo, v, parcel, flags);
|
||||
}
|
||||
if (v->dimension == 1) {
|
||||
t->WriteArrayToParcel(addTo, v, parcel, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl)
|
||||
{
|
||||
if (v->dimension == 0) {
|
||||
t->CreateFromParcel(addTo, v, parcel, cl);
|
||||
}
|
||||
if (v->dimension == 1) {
|
||||
t->CreateArrayFromParcel(addTo, v, parcel, cl);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
|
||||
Variable* parcel, Variable** cl)
|
||||
{
|
||||
if (v->dimension == 0) {
|
||||
t->ReadFromParcel(addTo, v, parcel, cl);
|
||||
}
|
||||
if (v->dimension == 1) {
|
||||
t->ReadArrayFromParcel(addTo, v, parcel, cl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
generate_method(const method_type* method, Class* interface,
|
||||
StubClass* stubClass, ProxyClass* proxyClass, int index)
|
||||
{
|
||||
arg_type* arg;
|
||||
int i;
|
||||
bool hasOutParams = false;
|
||||
|
||||
const bool oneway = proxyClass->mOneWay || method->oneway;
|
||||
|
||||
// == the TRANSACT_ constant =============================================
|
||||
string transactCodeName = "TRANSACTION_";
|
||||
transactCodeName += method->name.data;
|
||||
|
||||
char transactCodeValue[60];
|
||||
sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
|
||||
|
||||
Field* transactCode = new Field(STATIC | FINAL,
|
||||
new Variable(INT_TYPE, transactCodeName));
|
||||
transactCode->value = transactCodeValue;
|
||||
stubClass->elements.push_back(transactCode);
|
||||
|
||||
// == the declaration in the interface ===================================
|
||||
Method* decl = new Method;
|
||||
decl->comment = gather_comments(method->comments_token->extra);
|
||||
decl->modifiers = PUBLIC;
|
||||
decl->returnType = NAMES.Search(method->type.type.data);
|
||||
decl->returnTypeDimension = method->type.dimension;
|
||||
decl->name = method->name.data;
|
||||
|
||||
arg = method->args;
|
||||
while (arg != NULL) {
|
||||
decl->parameters.push_back(new Variable(
|
||||
NAMES.Search(arg->type.type.data), arg->name.data,
|
||||
arg->type.dimension));
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
|
||||
|
||||
interface->elements.push_back(decl);
|
||||
|
||||
// == the stub method ====================================================
|
||||
|
||||
Case* c = new Case(transactCodeName);
|
||||
|
||||
MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
|
||||
|
||||
// interface token validation is the very first thing we do
|
||||
c->statements->Add(new MethodCall(stubClass->transact_data,
|
||||
"enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
|
||||
|
||||
// args
|
||||
Variable* cl = NULL;
|
||||
VariableFactory stubArgs("_arg");
|
||||
arg = method->args;
|
||||
while (arg != NULL) {
|
||||
Type* t = NAMES.Search(arg->type.type.data);
|
||||
Variable* v = stubArgs.Get(t);
|
||||
v->dimension = arg->type.dimension;
|
||||
|
||||
c->statements->Add(new VariableDeclaration(v));
|
||||
|
||||
if (convert_direction(arg->direction.data) & IN_PARAMETER) {
|
||||
generate_create_from_parcel(t, c->statements, v,
|
||||
stubClass->transact_data, &cl);
|
||||
} else {
|
||||
if (arg->type.dimension == 0) {
|
||||
c->statements->Add(new Assignment(v, new NewExpression(v->type)));
|
||||
}
|
||||
else if (arg->type.dimension == 1) {
|
||||
generate_new_array(v->type, c->statements, v,
|
||||
stubClass->transact_data);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
realCall->arguments.push_back(v);
|
||||
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
// the real call
|
||||
Variable* _result = NULL;
|
||||
if (0 == strcmp(method->type.type.data, "void")) {
|
||||
c->statements->Add(realCall);
|
||||
|
||||
if (!oneway) {
|
||||
// report that there were no exceptions
|
||||
MethodCall* ex = new MethodCall(stubClass->transact_reply,
|
||||
"writeNoException", 0);
|
||||
c->statements->Add(ex);
|
||||
}
|
||||
} else {
|
||||
_result = new Variable(decl->returnType, "_result",
|
||||
decl->returnTypeDimension);
|
||||
c->statements->Add(new VariableDeclaration(_result, realCall));
|
||||
|
||||
if (!oneway) {
|
||||
// report that there were no exceptions
|
||||
MethodCall* ex = new MethodCall(stubClass->transact_reply,
|
||||
"writeNoException", 0);
|
||||
c->statements->Add(ex);
|
||||
}
|
||||
|
||||
// marshall the return value
|
||||
generate_write_to_parcel(decl->returnType, c->statements, _result,
|
||||
stubClass->transact_reply,
|
||||
Type::PARCELABLE_WRITE_RETURN_VALUE);
|
||||
}
|
||||
|
||||
// out parameters
|
||||
i = 0;
|
||||
arg = method->args;
|
||||
while (arg != NULL) {
|
||||
Type* t = NAMES.Search(arg->type.type.data);
|
||||
Variable* v = stubArgs.Get(i++);
|
||||
|
||||
if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
|
||||
generate_write_to_parcel(t, c->statements, v,
|
||||
stubClass->transact_reply,
|
||||
Type::PARCELABLE_WRITE_RETURN_VALUE);
|
||||
hasOutParams = true;
|
||||
}
|
||||
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
// return true
|
||||
c->statements->Add(new ReturnStatement(TRUE_VALUE));
|
||||
stubClass->transact_switch->cases.push_back(c);
|
||||
|
||||
// == the proxy method ===================================================
|
||||
Method* proxy = new Method;
|
||||
proxy->comment = gather_comments(method->comments_token->extra);
|
||||
proxy->modifiers = PUBLIC | OVERRIDE;
|
||||
proxy->returnType = NAMES.Search(method->type.type.data);
|
||||
proxy->returnTypeDimension = method->type.dimension;
|
||||
proxy->name = method->name.data;
|
||||
proxy->statements = new StatementBlock;
|
||||
arg = method->args;
|
||||
while (arg != NULL) {
|
||||
proxy->parameters.push_back(new Variable(
|
||||
NAMES.Search(arg->type.type.data), arg->name.data,
|
||||
arg->type.dimension));
|
||||
arg = arg->next;
|
||||
}
|
||||
proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
|
||||
proxyClass->elements.push_back(proxy);
|
||||
|
||||
// the parcels
|
||||
Variable* _data = new Variable(PARCEL_TYPE, "_data");
|
||||
proxy->statements->Add(new VariableDeclaration(_data,
|
||||
new MethodCall(PARCEL_TYPE, "obtain")));
|
||||
Variable* _reply = NULL;
|
||||
if (!oneway) {
|
||||
_reply = new Variable(PARCEL_TYPE, "_reply");
|
||||
proxy->statements->Add(new VariableDeclaration(_reply,
|
||||
new MethodCall(PARCEL_TYPE, "obtain")));
|
||||
}
|
||||
|
||||
// the return value
|
||||
_result = NULL;
|
||||
if (0 != strcmp(method->type.type.data, "void")) {
|
||||
_result = new Variable(proxy->returnType, "_result",
|
||||
method->type.dimension);
|
||||
proxy->statements->Add(new VariableDeclaration(_result));
|
||||
}
|
||||
|
||||
// try and finally
|
||||
TryStatement* tryStatement = new TryStatement();
|
||||
proxy->statements->Add(tryStatement);
|
||||
FinallyStatement* finallyStatement = new FinallyStatement();
|
||||
proxy->statements->Add(finallyStatement);
|
||||
|
||||
// the interface identifier token: the DESCRIPTOR constant, marshalled as a string
|
||||
tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
|
||||
1, new LiteralExpression("DESCRIPTOR")));
|
||||
|
||||
// the parameters
|
||||
arg = method->args;
|
||||
while (arg != NULL) {
|
||||
Type* t = NAMES.Search(arg->type.type.data);
|
||||
Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
|
||||
int dir = convert_direction(arg->direction.data);
|
||||
if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
|
||||
IfStatement* checklen = new IfStatement();
|
||||
checklen->expression = new Comparison(v, "==", NULL_VALUE);
|
||||
checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
|
||||
new LiteralExpression("-1")));
|
||||
checklen->elseif = new IfStatement();
|
||||
checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
|
||||
1, new FieldVariable(v, "length")));
|
||||
tryStatement->statements->Add(checklen);
|
||||
}
|
||||
else if (dir & IN_PARAMETER) {
|
||||
generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
|
||||
}
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
// the transact call
|
||||
MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
|
||||
new LiteralExpression("Stub." + transactCodeName),
|
||||
_data, _reply ? _reply : NULL_VALUE,
|
||||
new LiteralExpression(
|
||||
oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
|
||||
tryStatement->statements->Add(call);
|
||||
|
||||
// throw back exceptions.
|
||||
if (_reply) {
|
||||
MethodCall* ex = new MethodCall(_reply, "readException", 0);
|
||||
tryStatement->statements->Add(ex);
|
||||
}
|
||||
|
||||
// returning and cleanup
|
||||
if (_reply != NULL) {
|
||||
if (_result != NULL) {
|
||||
generate_create_from_parcel(proxy->returnType,
|
||||
tryStatement->statements, _result, _reply, &cl);
|
||||
}
|
||||
|
||||
// the out/inout parameters
|
||||
arg = method->args;
|
||||
while (arg != NULL) {
|
||||
Type* t = NAMES.Search(arg->type.type.data);
|
||||
Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
|
||||
if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
|
||||
generate_read_from_parcel(t, tryStatement->statements,
|
||||
v, _reply, &cl);
|
||||
}
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
|
||||
}
|
||||
finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
|
||||
|
||||
if (_result != NULL) {
|
||||
proxy->statements->Add(new ReturnStatement(_result));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
|
||||
{
|
||||
// the interface descriptor transaction handler
|
||||
Case* c = new Case("INTERFACE_TRANSACTION");
|
||||
c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
|
||||
1, new LiteralExpression("DESCRIPTOR")));
|
||||
c->statements->Add(new ReturnStatement(TRUE_VALUE));
|
||||
stub->transact_switch->cases.push_back(c);
|
||||
|
||||
// and the proxy-side method returning the descriptor directly
|
||||
Method* getDesc = new Method;
|
||||
getDesc->modifiers = PUBLIC;
|
||||
getDesc->returnType = STRING_TYPE;
|
||||
getDesc->returnTypeDimension = 0;
|
||||
getDesc->name = "getInterfaceDescriptor";
|
||||
getDesc->statements = new StatementBlock;
|
||||
getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
|
||||
proxy->elements.push_back(getDesc);
|
||||
}
|
||||
|
||||
Class*
|
||||
generate_binder_interface_class(const interface_type* iface)
|
||||
{
|
||||
InterfaceType* interfaceType = static_cast<InterfaceType*>(
|
||||
NAMES.Find(iface->package, iface->name.data));
|
||||
|
||||
// the interface class
|
||||
Class* interface = new Class;
|
||||
interface->comment = gather_comments(iface->comments_token->extra);
|
||||
interface->modifiers = PUBLIC;
|
||||
interface->what = Class::INTERFACE;
|
||||
interface->type = interfaceType;
|
||||
interface->interfaces.push_back(IINTERFACE_TYPE);
|
||||
|
||||
// the stub inner class
|
||||
StubClass* stub = new StubClass(
|
||||
NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
|
||||
interfaceType);
|
||||
interface->elements.push_back(stub);
|
||||
|
||||
// the proxy inner class
|
||||
ProxyClass* proxy = new ProxyClass(
|
||||
NAMES.Find(iface->package,
|
||||
append(iface->name.data, ".Stub.Proxy").c_str()),
|
||||
interfaceType);
|
||||
stub->elements.push_back(proxy);
|
||||
|
||||
// stub and proxy support for getInterfaceDescriptor()
|
||||
generate_interface_descriptors(stub, proxy);
|
||||
|
||||
// all the declared methods of the interface
|
||||
int index = 0;
|
||||
interface_item_type* item = iface->interface_items;
|
||||
while (item != NULL) {
|
||||
if (item->item_type == METHOD_TYPE) {
|
||||
method_type * method_item = (method_type*) item;
|
||||
generate_method(method_item, interface, stub, proxy, method_item->assigned_id);
|
||||
}
|
||||
item = item->next;
|
||||
index++;
|
||||
}
|
||||
|
||||
return interface;
|
||||
}
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: aidl OPTIONS INPUT [OUTPUT]\n"
|
||||
" aidl --preprocess OUTPUT INPUT...\n"
|
||||
"\n"
|
||||
"OPTIONS:\n"
|
||||
" -I<DIR> search path for import statements.\n"
|
||||
" -d<FILE> generate dependency file.\n"
|
||||
" -a generate dependency file next to the output file with the name based on the input file.\n"
|
||||
" -p<FILE> file created by --preprocess to import.\n"
|
||||
" -o<FOLDER> base output folder for generated files.\n"
|
||||
" -b fail when trying to compile a parcelable.\n"
|
||||
"\n"
|
||||
"INPUT:\n"
|
||||
" An aidl interface file.\n"
|
||||
"\n"
|
||||
"OUTPUT:\n"
|
||||
" The generated interface files.\n"
|
||||
" If omitted and the -o option is not used, the input filename is used, with the .aidl extension changed to a .java extension.\n"
|
||||
" If the -o option is used, the generated files will be placed in the base output folder, under their package folder\n"
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
parse_options(int argc, const char* const* argv, Options *options)
|
||||
{
|
||||
int i = 1;
|
||||
|
||||
if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) {
|
||||
if (argc < 4) {
|
||||
return usage();
|
||||
}
|
||||
options->outputFileName = argv[2];
|
||||
for (int i=3; i<argc; i++) {
|
||||
options->filesToPreprocess.push_back(argv[i]);
|
||||
}
|
||||
options->task = PREPROCESS_AIDL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
options->task = COMPILE_AIDL;
|
||||
options->failOnParcelable = false;
|
||||
options->autoDepFile = false;
|
||||
|
||||
// OPTIONS
|
||||
while (i < argc) {
|
||||
const char* s = argv[i];
|
||||
int len = strlen(s);
|
||||
if (s[0] == '-') {
|
||||
if (len > 1) {
|
||||
// -I<system-import-path>
|
||||
if (s[1] == 'I') {
|
||||
if (len > 2) {
|
||||
options->importPaths.push_back(s+2);
|
||||
} else {
|
||||
fprintf(stderr, "-I option (%d) requires a path.\n", i);
|
||||
return usage();
|
||||
}
|
||||
}
|
||||
else if (s[1] == 'd') {
|
||||
if (len > 2) {
|
||||
options->depFileName = s+2;
|
||||
} else {
|
||||
fprintf(stderr, "-d option (%d) requires a file.\n", i);
|
||||
return usage();
|
||||
}
|
||||
}
|
||||
else if (s[1] == 'a') {
|
||||
options->autoDepFile = true;
|
||||
}
|
||||
else if (s[1] == 'p') {
|
||||
if (len > 2) {
|
||||
options->preprocessedFiles.push_back(s+2);
|
||||
} else {
|
||||
fprintf(stderr, "-p option (%d) requires a file.\n", i);
|
||||
return usage();
|
||||
}
|
||||
}
|
||||
else if (s[1] == 'o') {
|
||||
if (len > 2) {
|
||||
options->outputBaseFolder = s+2;
|
||||
} else {
|
||||
fprintf(stderr, "-o option (%d) requires a path.\n", i);
|
||||
return usage();
|
||||
}
|
||||
}
|
||||
else if (len == 2 && s[1] == 'b') {
|
||||
options->failOnParcelable = true;
|
||||
}
|
||||
else {
|
||||
// s[1] is not known
|
||||
fprintf(stderr, "unknown option (%d): %s\n", i, s);
|
||||
return usage();
|
||||
}
|
||||
} else {
|
||||
// len <= 1
|
||||
fprintf(stderr, "unknown option (%d): %s\n", i, s);
|
||||
return usage();
|
||||
}
|
||||
} else {
|
||||
// s[0] != '-'
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// INPUT
|
||||
if (i < argc) {
|
||||
options->inputFileName = argv[i];
|
||||
i++;
|
||||
} else {
|
||||
fprintf(stderr, "INPUT required\n");
|
||||
return usage();
|
||||
}
|
||||
|
||||
// OUTPUT
|
||||
if (i < argc) {
|
||||
options->outputFileName = argv[i];
|
||||
i++;
|
||||
} else if (options->outputBaseFolder.length() == 0) {
|
||||
// copy input into output and change the extension from .aidl to .java
|
||||
options->outputFileName = options->inputFileName;
|
||||
string::size_type pos = options->outputFileName.size()-5;
|
||||
if (options->outputFileName.compare(pos, 5, ".aidl") == 0) { // 5 = strlen(".aidl")
|
||||
options->outputFileName.replace(pos, 5, ".java"); // 5 = strlen(".aidl")
|
||||
} else {
|
||||
fprintf(stderr, "INPUT is not an .aidl file.\n");
|
||||
return usage();
|
||||
}
|
||||
}
|
||||
|
||||
// anything remaining?
|
||||
if (i != argc) {
|
||||
fprintf(stderr, "unknown option%s:", (i==argc-1?(const char*)"":(const char*)"s"));
|
||||
for (; i<argc-1; i++) {
|
||||
fprintf(stderr, " %s", argv[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
return usage();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef DEVICE_TOOLS_AIDL_H
|
||||
#define DEVICE_TOOLS_AIDL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum {
|
||||
COMPILE_AIDL,
|
||||
PREPROCESS_AIDL
|
||||
};
|
||||
|
||||
// This struct is the parsed version of the command line options
|
||||
struct Options
|
||||
{
|
||||
int task;
|
||||
bool failOnParcelable;
|
||||
vector<string> importPaths;
|
||||
vector<string> preprocessedFiles;
|
||||
string inputFileName;
|
||||
string outputFileName;
|
||||
string outputBaseFolder;
|
||||
string depFileName;
|
||||
bool autoDepFile;
|
||||
|
||||
vector<string> filesToPreprocess;
|
||||
};
|
||||
|
||||
// takes the inputs from the command line and fills in the Options struct
|
||||
// Returns 0 on success, and nonzero on failure.
|
||||
// It also prints the usage statement on failure.
|
||||
int parse_options(int argc, const char* const* argv, Options *options);
|
||||
|
||||
#endif // DEVICE_TOOLS_AIDL_H
|
||||
@@ -1,291 +0,0 @@
|
||||
#include <iostream>
|
||||
#include "options.h"
|
||||
|
||||
const bool VERBOSE = false;
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Answer {
|
||||
const char* argv[8];
|
||||
int result;
|
||||
const char* systemSearchPath[8];
|
||||
const char* localSearchPath[8];
|
||||
const char* inputFileName;
|
||||
language_t nativeLanguage;
|
||||
const char* outputH;
|
||||
const char* outputCPP;
|
||||
const char* outputJava;
|
||||
};
|
||||
|
||||
bool
|
||||
match_arrays(const char* const*expected, const vector<string> &got)
|
||||
{
|
||||
int count = 0;
|
||||
while (expected[count] != NULL) {
|
||||
count++;
|
||||
}
|
||||
if (got.size() != count) {
|
||||
return false;
|
||||
}
|
||||
for (int i=0; i<count; i++) {
|
||||
if (got[i] != expected[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
print_array(const char* prefix, const char* const*expected)
|
||||
{
|
||||
while (*expected) {
|
||||
cout << prefix << *expected << endl;
|
||||
expected++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_array(const char* prefix, const vector<string> &got)
|
||||
{
|
||||
size_t count = got.size();
|
||||
for (size_t i=0; i<count; i++) {
|
||||
cout << prefix << got[i] << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
test(const Answer& answer)
|
||||
{
|
||||
int argc = 0;
|
||||
while (answer.argv[argc]) {
|
||||
argc++;
|
||||
}
|
||||
|
||||
int err = 0;
|
||||
|
||||
Options options;
|
||||
int result = parse_options(argc, answer.argv, &options);
|
||||
|
||||
// result
|
||||
if (((bool)result) != ((bool)answer.result)) {
|
||||
cout << "mismatch: result: got " << result << " expected " <<
|
||||
answer.result << endl;
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
// if it failed, everything is invalid
|
||||
return err;
|
||||
}
|
||||
|
||||
// systemSearchPath
|
||||
if (!match_arrays(answer.systemSearchPath, options.systemSearchPath)) {
|
||||
cout << "mismatch: systemSearchPath: got" << endl;
|
||||
print_array(" ", options.systemSearchPath);
|
||||
cout << " expected" << endl;
|
||||
print_array(" ", answer.systemSearchPath);
|
||||
err = 1;
|
||||
}
|
||||
|
||||
// localSearchPath
|
||||
if (!match_arrays(answer.localSearchPath, options.localSearchPath)) {
|
||||
cout << "mismatch: localSearchPath: got" << endl;
|
||||
print_array(" ", options.localSearchPath);
|
||||
cout << " expected" << endl;
|
||||
print_array(" ", answer.localSearchPath);
|
||||
err = 1;
|
||||
}
|
||||
|
||||
// inputFileName
|
||||
if (answer.inputFileName != options.inputFileName) {
|
||||
cout << "mismatch: inputFileName: got " << options.inputFileName
|
||||
<< " expected " << answer.inputFileName << endl;
|
||||
err = 1;
|
||||
}
|
||||
|
||||
// nativeLanguage
|
||||
if (answer.nativeLanguage != options.nativeLanguage) {
|
||||
cout << "mismatch: nativeLanguage: got " << options.nativeLanguage
|
||||
<< " expected " << answer.nativeLanguage << endl;
|
||||
err = 1;
|
||||
}
|
||||
|
||||
// outputH
|
||||
if (answer.outputH != options.outputH) {
|
||||
cout << "mismatch: outputH: got " << options.outputH
|
||||
<< " expected " << answer.outputH << endl;
|
||||
err = 1;
|
||||
}
|
||||
|
||||
// outputCPP
|
||||
if (answer.outputCPP != options.outputCPP) {
|
||||
cout << "mismatch: outputCPP: got " << options.outputCPP
|
||||
<< " expected " << answer.outputCPP << endl;
|
||||
err = 1;
|
||||
}
|
||||
|
||||
// outputJava
|
||||
if (answer.outputJava != options.outputJava) {
|
||||
cout << "mismatch: outputJava: got " << options.outputJava
|
||||
<< " expected " << answer.outputJava << endl;
|
||||
err = 1;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
const Answer g_tests[] = {
|
||||
|
||||
{
|
||||
/* argv */ { "test", "-i/moof", "-I/blah", "-Ibleh", "-imoo", "inputFileName.aidl_cpp", NULL, NULL },
|
||||
/* result */ 0,
|
||||
/* systemSearchPath */ { "/blah", "bleh", NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* localSearchPath */ { "/moof", "moo", NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* inputFileName */ "inputFileName.aidl_cpp",
|
||||
/* nativeLanguage */ CPP,
|
||||
/* outputH */ "",
|
||||
/* outputCPP */ "",
|
||||
/* outputJava */ ""
|
||||
},
|
||||
|
||||
{
|
||||
/* argv */ { "test", "inputFileName.aidl_cpp", "-oh", "outputH", NULL, NULL, NULL, NULL },
|
||||
/* result */ 0,
|
||||
/* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* inputFileName */ "inputFileName.aidl_cpp",
|
||||
/* nativeLanguage */ CPP,
|
||||
/* outputH */ "outputH",
|
||||
/* outputCPP */ "",
|
||||
/* outputJava */ ""
|
||||
},
|
||||
|
||||
{
|
||||
/* argv */ { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", NULL, NULL, NULL, NULL },
|
||||
/* result */ 0,
|
||||
/* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* inputFileName */ "inputFileName.aidl_cpp",
|
||||
/* nativeLanguage */ CPP,
|
||||
/* outputH */ "",
|
||||
/* outputCPP */ "outputCPP",
|
||||
/* outputJava */ ""
|
||||
},
|
||||
|
||||
{
|
||||
/* argv */ { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", NULL, NULL, NULL, NULL },
|
||||
/* result */ 0,
|
||||
/* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* inputFileName */ "inputFileName.aidl_cpp",
|
||||
/* nativeLanguage */ CPP,
|
||||
/* outputH */ "",
|
||||
/* outputCPP */ "",
|
||||
/* outputJava */ "outputJava"
|
||||
},
|
||||
|
||||
{
|
||||
/* argv */ { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-ocpp", "outputCPP", "-ojava", "outputJava" },
|
||||
/* result */ 0,
|
||||
/* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* inputFileName */ "inputFileName.aidl_cpp",
|
||||
/* nativeLanguage */ CPP,
|
||||
/* outputH */ "outputH",
|
||||
/* outputCPP */ "outputCPP",
|
||||
/* outputJava */ "outputJava"
|
||||
},
|
||||
|
||||
{
|
||||
/* argv */ { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-oh", "outputH1", NULL, NULL },
|
||||
/* result */ 1,
|
||||
/* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* inputFileName */ "",
|
||||
/* nativeLanguage */ CPP,
|
||||
/* outputH */ "",
|
||||
/* outputCPP */ "",
|
||||
/* outputJava */ ""
|
||||
},
|
||||
|
||||
{
|
||||
/* argv */ { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", "-ocpp", "outputCPP1", NULL, NULL },
|
||||
/* result */ 1,
|
||||
/* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* inputFileName */ "",
|
||||
/* nativeLanguage */ CPP,
|
||||
/* outputH */ "",
|
||||
/* outputCPP */ "",
|
||||
/* outputJava */ ""
|
||||
},
|
||||
|
||||
{
|
||||
/* argv */ { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", "-ojava", "outputJava1", NULL, NULL },
|
||||
/* result */ 1,
|
||||
/* systemSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* localSearchPath */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
|
||||
/* inputFileName */ "",
|
||||
/* nativeLanguage */ CPP,
|
||||
/* outputH */ "",
|
||||
/* outputCPP */ "",
|
||||
/* outputJava */ ""
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, const char** argv)
|
||||
{
|
||||
const int count = sizeof(g_tests)/sizeof(g_tests[0]);
|
||||
int matches[count];
|
||||
|
||||
int result = 0;
|
||||
for (int i=0; i<count; i++) {
|
||||
if (VERBOSE) {
|
||||
cout << endl;
|
||||
cout << "---------------------------------------------" << endl;
|
||||
const char* const* p = g_tests[i].argv;
|
||||
while (*p) {
|
||||
cout << " " << *p;
|
||||
p++;
|
||||
}
|
||||
cout << endl;
|
||||
cout << "---------------------------------------------" << endl;
|
||||
}
|
||||
matches[i] = test(g_tests[i]);
|
||||
if (VERBOSE) {
|
||||
if (0 == matches[i]) {
|
||||
cout << "passed" << endl;
|
||||
} else {
|
||||
cout << "failed" << endl;
|
||||
}
|
||||
result |= matches[i];
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
cout << "=============================================" << endl;
|
||||
cout << "options_test summary" << endl;
|
||||
cout << "=============================================" << endl;
|
||||
|
||||
if (!result) {
|
||||
cout << "passed" << endl;
|
||||
} else {
|
||||
cout << "failed the following tests:" << endl;
|
||||
for (int i=0; i<count; i++) {
|
||||
if (matches[i]) {
|
||||
cout << " ";
|
||||
const char* const* p = g_tests[i].argv;
|
||||
while (*p) {
|
||||
cout << " " << *p;
|
||||
p++;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include "search_path.h"
|
||||
#include "options.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_MS_C_RUNTIME
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
static vector<string> g_importPaths;
|
||||
|
||||
void
|
||||
set_import_paths(const vector<string>& importPaths)
|
||||
{
|
||||
g_importPaths = importPaths;
|
||||
}
|
||||
|
||||
char*
|
||||
find_import_file(const char* given)
|
||||
{
|
||||
string expected = given;
|
||||
|
||||
int N = expected.length();
|
||||
for (int i=0; i<N; i++) {
|
||||
char c = expected[i];
|
||||
if (c == '.') {
|
||||
expected[i] = OS_PATH_SEPARATOR;
|
||||
}
|
||||
}
|
||||
expected += ".aidl";
|
||||
|
||||
vector<string>& paths = g_importPaths;
|
||||
for (vector<string>::iterator it=paths.begin(); it!=paths.end(); it++) {
|
||||
string f = *it;
|
||||
if (f.size() == 0) {
|
||||
f = ".";
|
||||
f += OS_PATH_SEPARATOR;
|
||||
}
|
||||
else if (f[f.size()-1] != OS_PATH_SEPARATOR) {
|
||||
f += OS_PATH_SEPARATOR;
|
||||
}
|
||||
f.append(expected);
|
||||
|
||||
#ifdef HAVE_MS_C_RUNTIME
|
||||
/* check that the file exists and is not write-only */
|
||||
if (0 == _access(f.c_str(), 0) && /* mode 0=exist */
|
||||
0 == _access(f.c_str(), 4) ) { /* mode 4=readable */
|
||||
#else
|
||||
if (0 == access(f.c_str(), R_OK)) {
|
||||
#endif
|
||||
return strdup(f.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef DEVICE_TOOLS_AIDL_SEARCH_PATH_H
|
||||
#define DEVICE_TOOLS_AIDL_SEARCH_PATH_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if __cplusplus
|
||||
#include <vector>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// returns a FILE* and the char* for the file that it found
|
||||
// given is the class name we're looking for
|
||||
char* find_import_file(const char* given);
|
||||
|
||||
#if __cplusplus
|
||||
}; // extern "C"
|
||||
void set_import_paths(const vector<string>& importPaths);
|
||||
#endif
|
||||
|
||||
#endif // DEVICE_TOOLS_AIDL_SEARCH_PATH_H
|
||||
|
||||
1
tools/layoutlib/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
bin
|
||||
@@ -1,65 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2008 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
LOCAL_PATH := $(my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
#
|
||||
# Define rules to build temp_layoutlib.jar, which contains a subset of
|
||||
# the classes in framework.jar. The layoutlib_create tool is used to
|
||||
# transform the framework jar into the temp_layoutlib jar.
|
||||
#
|
||||
|
||||
# We need to process the framework classes.jar file, but we can't
|
||||
# depend directly on it (private vars won't be inherited correctly).
|
||||
# So, we depend on framework's BUILT file.
|
||||
built_framework_dep := $(call java-lib-deps,framework-base)
|
||||
built_framework_classes := $(call java-lib-files,framework-base)
|
||||
|
||||
built_core_dep := $(call java-lib-deps,core)
|
||||
built_core_classes := $(call java-lib-files,core)
|
||||
|
||||
built_layoutlib_create_jar := $(call intermediates-dir-for, \
|
||||
JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
|
||||
|
||||
# This is mostly a copy of config/host_java_library.mk
|
||||
LOCAL_MODULE := temp_layoutlib
|
||||
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
|
||||
LOCAL_MODULE_SUFFIX := $(COMMON_JAVA_PACKAGE_SUFFIX)
|
||||
LOCAL_IS_HOST_MODULE := true
|
||||
LOCAL_BUILT_MODULE_STEM := javalib.jar
|
||||
|
||||
#######################################
|
||||
include $(BUILD_SYSTEM)/base_rules.mk
|
||||
#######################################
|
||||
|
||||
$(LOCAL_BUILT_MODULE): $(built_core_dep) \
|
||||
$(built_framework_dep) \
|
||||
$(built_layoutlib_create_jar)
|
||||
$(hide) echo "host layoutlib_create: $@"
|
||||
$(hide) mkdir -p $(dir $@)
|
||||
$(hide) rm -f $@
|
||||
$(hide) ls -l $(built_framework_classes)
|
||||
$(hide) java -jar $(built_layoutlib_create_jar) \
|
||||
$@ \
|
||||
$(built_core_classes) \
|
||||
$(built_framework_classes)
|
||||
$(hide) ls -l $(built_framework_classes)
|
||||
|
||||
|
||||
#
|
||||
# Include the subdir makefiles.
|
||||
#
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||
@@ -1,4 +0,0 @@
|
||||
Layoutlib is a custom version of the android View framework designed to run inside Eclipse.
|
||||
The goal of the library is to provide layout rendering in Eclipse that are very very close to their rendering on devices.
|
||||
|
||||
None of the com.android.* or android.* classes in layoutlib run on devices.
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry excluding="org/kxml2/io/" kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
|
||||
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
|
||||
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
|
||||
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar"/>
|
||||
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>layoutlib_bridge</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -1,2 +0,0 @@
|
||||
Copy this in eclipse project as a .settings folder at the root.
|
||||
This ensure proper compilation compliance and warning/error levels.
|
||||
@@ -1,93 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnull=com.android.annotations.NonNull
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=com.android.annotations.NonNullByDefault
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled
|
||||
org.eclipse.jdt.core.compiler.annotation.nullable=com.android.annotations.Nullable
|
||||
org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deadCode=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error
|
||||
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
@@ -1,38 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2008 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under,src)
|
||||
LOCAL_JAVA_RESOURCE_DIRS := resources
|
||||
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := \
|
||||
kxml2-2.3.0 \
|
||||
layoutlib_api-prebuilt \
|
||||
tools-common-prebuilt
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
temp_layoutlib \
|
||||
ninepatch-prebuilt
|
||||
|
||||
LOCAL_MODULE := layoutlib
|
||||
|
||||
include $(BUILD_HOST_JAVA_LIBRARY)
|
||||
|
||||
# Build all sub-directories
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<include layout="@android:layout/action_bar_home" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</merge>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 711 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 774 B |
|
Before Width: | Height: | Size: 836 B |
|
Before Width: | Height: | Size: 591 B |
|
Before Width: | Height: | Size: 885 B |
|
Before Width: | Height: | Size: 204 B |
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
<ImageView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
<ImageView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
<ImageView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
</merge>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
<ImageView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
<ImageView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginLeft="3dip"
|
||||
android:layout_marginRight="5dip"/>
|
||||
</merge>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</merge>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 749 B |
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.animation;
|
||||
|
||||
import com.android.ide.common.rendering.api.IAnimationListener;
|
||||
import com.android.ide.common.rendering.api.RenderSession;
|
||||
import com.android.ide.common.rendering.api.Result;
|
||||
import com.android.ide.common.rendering.api.Result.Status;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Handler_Delegate;
|
||||
import android.os.Handler_Delegate.IHandlerCallback;
|
||||
import android.os.Message;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* Abstract animation thread.
|
||||
* <p/>
|
||||
* This does not actually start an animation, instead it fakes a looper that will play whatever
|
||||
* animation is sending messages to its own {@link Handler}.
|
||||
* <p/>
|
||||
* Classes should implement {@link #preAnimation()} and {@link #postAnimation()}.
|
||||
* <p/>
|
||||
* If {@link #preAnimation()} does not start an animation somehow then the thread doesn't do
|
||||
* anything.
|
||||
*
|
||||
*/
|
||||
public abstract class AnimationThread extends Thread {
|
||||
|
||||
private static class MessageBundle implements Comparable<MessageBundle> {
|
||||
final Handler mTarget;
|
||||
final Message mMessage;
|
||||
final long mUptimeMillis;
|
||||
|
||||
MessageBundle(Handler target, Message message, long uptimeMillis) {
|
||||
mTarget = target;
|
||||
mMessage = message;
|
||||
mUptimeMillis = uptimeMillis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MessageBundle bundle) {
|
||||
if (mUptimeMillis < bundle.mUptimeMillis) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private final RenderSessionImpl mSession;
|
||||
|
||||
private Queue<MessageBundle> mQueue = new PriorityQueue<MessageBundle>();
|
||||
private final IAnimationListener mListener;
|
||||
|
||||
public AnimationThread(RenderSessionImpl scene, String threadName,
|
||||
IAnimationListener listener) {
|
||||
super(threadName);
|
||||
mSession = scene;
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public abstract Result preAnimation();
|
||||
public abstract void postAnimation();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Bridge.prepareThread();
|
||||
try {
|
||||
/* FIXME: The ANIMATION_FRAME message no longer exists. Instead, the
|
||||
* animation timing loop is completely based on a Choreographer objects
|
||||
* that schedules animation and drawing frames. The animation handler is
|
||||
* no longer even a handler; it is just a Runnable enqueued on the Choreographer.
|
||||
Handler_Delegate.setCallback(new IHandlerCallback() {
|
||||
@Override
|
||||
public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
|
||||
if (msg.what == ValueAnimator.ANIMATION_START ||
|
||||
msg.what == ValueAnimator.ANIMATION_FRAME) {
|
||||
mQueue.add(new MessageBundle(handler, msg, uptimeMillis));
|
||||
} else {
|
||||
// just ignore.
|
||||
}
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
// call out to the pre-animation work, which should start an animation or more.
|
||||
Result result = preAnimation();
|
||||
if (result.isSuccess() == false) {
|
||||
mListener.done(result);
|
||||
}
|
||||
|
||||
// loop the animation
|
||||
RenderSession session = mSession.getSession();
|
||||
do {
|
||||
// check early.
|
||||
if (mListener.isCanceled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// get the next message.
|
||||
MessageBundle bundle = mQueue.poll();
|
||||
if (bundle == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
// sleep enough for this bundle to be on time
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (currentTime < bundle.mUptimeMillis) {
|
||||
try {
|
||||
sleep(bundle.mUptimeMillis - currentTime);
|
||||
} catch (InterruptedException e) {
|
||||
// FIXME log/do something/sleep again?
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// check after sleeping.
|
||||
if (mListener.isCanceled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// ready to do the work, acquire the scene.
|
||||
result = mSession.acquire(250);
|
||||
if (result.isSuccess() == false) {
|
||||
mListener.done(result);
|
||||
return;
|
||||
}
|
||||
|
||||
// process the bundle. If the animation is not finished, this will enqueue
|
||||
// the next message, so mQueue will have another one.
|
||||
try {
|
||||
// check after acquiring in case it took a while.
|
||||
if (mListener.isCanceled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
bundle.mTarget.handleMessage(bundle.mMessage);
|
||||
if (mSession.render(false /*freshRender*/).isSuccess()) {
|
||||
mListener.onNewFrame(session);
|
||||
}
|
||||
} finally {
|
||||
mSession.release();
|
||||
}
|
||||
} while (mListener.isCanceled() == false && mQueue.size() > 0);
|
||||
|
||||
mListener.done(Status.SUCCESS.createResult());
|
||||
|
||||
} catch (Throwable throwable) {
|
||||
// can't use Bridge.getLog() as the exception might be thrown outside
|
||||
// of an acquire/release block.
|
||||
mListener.done(Status.ERROR_UNKNOWN.createResult("Error playing animation", throwable));
|
||||
|
||||
} finally {
|
||||
postAnimation();
|
||||
Handler_Delegate.setCallback(null);
|
||||
Bridge.cleanupThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.animation;
|
||||
|
||||
import com.android.layoutlib.bridge.impl.DelegateManager;
|
||||
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
|
||||
|
||||
/**
|
||||
* Delegate implementing the native methods of android.animation.PropertyValuesHolder
|
||||
*
|
||||
* Through the layoutlib_create tool, the original native methods of PropertyValuesHolder have been
|
||||
* replaced by calls to methods of the same name in this delegate class.
|
||||
*
|
||||
* Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
|
||||
* around to map int to instance of the delegate.
|
||||
*
|
||||
* The main goal of this class' methods are to provide a native way to access setters and getters
|
||||
* on some object. In this case we want to default to using Java reflection instead so the native
|
||||
* methods do nothing.
|
||||
*
|
||||
*/
|
||||
/*package*/ class PropertyValuesHolder_Delegate {
|
||||
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static int nGetIntMethod(Class<?> targetClass, String methodName) {
|
||||
// return 0 to force PropertyValuesHolder to use Java reflection.
|
||||
return 0;
|
||||
}
|
||||
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static int nGetFloatMethod(Class<?> targetClass, String methodName) {
|
||||
// return 0 to force PropertyValuesHolder to use Java reflection.
|
||||
return 0;
|
||||
}
|
||||
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static void nCallIntMethod(Object target, int methodID, int arg) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static void nCallFloatMethod(Object target, int methodID, float arg) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app;
|
||||
|
||||
import com.android.ide.common.rendering.api.IProjectCallback;
|
||||
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* Delegate used to provide new implementation of a select few methods of {@link Fragment}
|
||||
*
|
||||
* Through the layoutlib_create tool, the original methods of Fragment have been replaced
|
||||
* by calls to methods of the same name in this delegate class.
|
||||
*
|
||||
* The methods being re-implemented are the ones responsible for instantiating Fragment objects.
|
||||
* Because the classes of these objects are found in the project, these methods need access to
|
||||
* {@link IProjectCallback} object. They are however static methods, so the callback is set
|
||||
* before the inflation through {@link #setProjectCallback(IProjectCallback)}.
|
||||
*/
|
||||
public class Fragment_Delegate {
|
||||
|
||||
private static IProjectCallback sProjectCallback;
|
||||
|
||||
/**
|
||||
* Sets the current {@link IProjectCallback} to be used to instantiate classes coming
|
||||
* from the project being rendered.
|
||||
*/
|
||||
public static void setProjectCallback(IProjectCallback projectCallback) {
|
||||
sProjectCallback = projectCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #instantiate(Context, String, Bundle)} but with a null
|
||||
* argument Bundle.
|
||||
*/
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static Fragment instantiate(Context context, String fname) {
|
||||
return instantiate(context, fname, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of a Fragment with the given class name. This is
|
||||
* the same as calling its empty constructor.
|
||||
*
|
||||
* @param context The calling context being used to instantiate the fragment.
|
||||
* This is currently just used to get its ClassLoader.
|
||||
* @param fname The class name of the fragment to instantiate.
|
||||
* @param args Bundle of arguments to supply to the fragment, which it
|
||||
* can retrieve with {@link #getArguments()}. May be null.
|
||||
* @return Returns a new fragment instance.
|
||||
* @throws InstantiationException If there is a failure in instantiating
|
||||
* the given fragment class. This is a runtime exception; it is not
|
||||
* normally expected to happen.
|
||||
*/
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static Fragment instantiate(Context context, String fname, Bundle args) {
|
||||
try {
|
||||
if (sProjectCallback != null) {
|
||||
Fragment f = (Fragment) sProjectCallback.loadView(fname,
|
||||
new Class[0], new Object[0]);
|
||||
|
||||
if (args != null) {
|
||||
args.setClassLoader(f.getClass().getClassLoader());
|
||||
f.mArguments = args;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
|
||||
+ ": make sure class name exists, is public, and has an"
|
||||
+ " empty constructor that is public", e);
|
||||
} catch (java.lang.InstantiationException e) {
|
||||
throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
|
||||
+ ": make sure class name exists, is public, and has an"
|
||||
+ " empty constructor that is public", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
|
||||
+ ": make sure class name exists, is public, and has an"
|
||||
+ " empty constructor that is public", e);
|
||||
} catch (Exception e) {
|
||||
throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
|
||||
+ ": make sure class name exists, is public, and has an"
|
||||
+ " empty constructor that is public", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content.res;
|
||||
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
public class BridgeAssetManager extends AssetManager {
|
||||
|
||||
/**
|
||||
* This initializes the static field {@link AssetManager#mSystem} which is used
|
||||
* by methods who get a global asset manager using {@link AssetManager#getSystem()}.
|
||||
* <p/>
|
||||
* They will end up using our bridge asset manager.
|
||||
* <p/>
|
||||
* {@link Bridge} calls this method after setting up a new bridge.
|
||||
*/
|
||||
public static AssetManager initSystem() {
|
||||
if (!(AssetManager.sSystem instanceof BridgeAssetManager)) {
|
||||
// Note that AssetManager() creates a system AssetManager and we override it
|
||||
// with our BridgeAssetManager.
|
||||
AssetManager.sSystem = new BridgeAssetManager();
|
||||
AssetManager.sSystem.makeStringBlocks(false);
|
||||
}
|
||||
return AssetManager.sSystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the static {@link AssetManager#sSystem} to make sure we don't leave objects
|
||||
* around that would prevent us from unloading the library.
|
||||
*/
|
||||
public static void clearSystem() {
|
||||
AssetManager.sSystem = null;
|
||||
}
|
||||
|
||||
private BridgeAssetManager() {
|
||||
}
|
||||
}
|
||||
@@ -1,695 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content.res;
|
||||
|
||||
import com.android.ide.common.rendering.api.IProjectCallback;
|
||||
import com.android.ide.common.rendering.api.LayoutLog;
|
||||
import com.android.ide.common.rendering.api.ResourceValue;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.BridgeConstants;
|
||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
|
||||
import com.android.layoutlib.bridge.impl.ParserFactory;
|
||||
import com.android.layoutlib.bridge.impl.ResourceHelper;
|
||||
import com.android.ninepatch.NinePatch;
|
||||
import com.android.resources.ResourceType;
|
||||
import com.android.util.Pair;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class BridgeResources extends Resources {
|
||||
|
||||
private BridgeContext mContext;
|
||||
private IProjectCallback mProjectCallback;
|
||||
private boolean[] mPlatformResourceFlag = new boolean[1];
|
||||
|
||||
/**
|
||||
* Simpler wrapper around FileInputStream. This is used when the input stream represent
|
||||
* not a normal bitmap but a nine patch.
|
||||
* This is useful when the InputStream is created in a method but used in another that needs
|
||||
* to know whether this is 9-patch or not, such as BitmapFactory.
|
||||
*/
|
||||
public class NinePatchInputStream extends FileInputStream {
|
||||
private boolean mFakeMarkSupport = true;
|
||||
public NinePatchInputStream(File file) throws FileNotFoundException {
|
||||
super(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
if (mFakeMarkSupport) {
|
||||
// this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.markSupported();
|
||||
}
|
||||
|
||||
public void disableFakeMarkSupport() {
|
||||
// disable fake mark support so that in case codec actually try to use them
|
||||
// we don't lie to them.
|
||||
mFakeMarkSupport = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This initializes the static field {@link Resources#mSystem} which is used
|
||||
* by methods who get global resources using {@link Resources#getSystem()}.
|
||||
* <p/>
|
||||
* They will end up using our bridge resources.
|
||||
* <p/>
|
||||
* {@link Bridge} calls this method after setting up a new bridge.
|
||||
*/
|
||||
public static Resources initSystem(BridgeContext context,
|
||||
AssetManager assets,
|
||||
DisplayMetrics metrics,
|
||||
Configuration config,
|
||||
IProjectCallback projectCallback) {
|
||||
return Resources.mSystem = new BridgeResources(context,
|
||||
assets,
|
||||
metrics,
|
||||
config,
|
||||
projectCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the static {@link Resources#mSystem} to make sure we don't leave objects
|
||||
* around that would prevent us from unloading the library.
|
||||
*/
|
||||
public static void disposeSystem() {
|
||||
if (Resources.mSystem instanceof BridgeResources) {
|
||||
((BridgeResources)(Resources.mSystem)).mContext = null;
|
||||
((BridgeResources)(Resources.mSystem)).mProjectCallback = null;
|
||||
}
|
||||
Resources.mSystem = null;
|
||||
}
|
||||
|
||||
private BridgeResources(BridgeContext context, AssetManager assets, DisplayMetrics metrics,
|
||||
Configuration config, IProjectCallback projectCallback) {
|
||||
super(assets, metrics, config);
|
||||
mContext = context;
|
||||
mProjectCallback = projectCallback;
|
||||
}
|
||||
|
||||
public BridgeTypedArray newTypeArray(int numEntries, boolean platformFile) {
|
||||
return new BridgeTypedArray(this, mContext, numEntries, platformFile);
|
||||
}
|
||||
|
||||
private Pair<String, ResourceValue> getResourceValue(int id, boolean[] platformResFlag_out) {
|
||||
// first get the String related to this id in the framework
|
||||
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
|
||||
|
||||
if (resourceInfo != null) {
|
||||
platformResFlag_out[0] = true;
|
||||
String attributeName = resourceInfo.getSecond();
|
||||
|
||||
return Pair.of(attributeName, mContext.getRenderResources().getFrameworkResource(
|
||||
resourceInfo.getFirst(), attributeName));
|
||||
}
|
||||
|
||||
// didn't find a match in the framework? look in the project.
|
||||
if (mProjectCallback != null) {
|
||||
resourceInfo = mProjectCallback.resolveResourceId(id);
|
||||
|
||||
if (resourceInfo != null) {
|
||||
platformResFlag_out[0] = false;
|
||||
String attributeName = resourceInfo.getSecond();
|
||||
|
||||
return Pair.of(attributeName, mContext.getRenderResources().getProjectResource(
|
||||
resourceInfo.getFirst(), attributeName));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getDrawable(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
return ResourceHelper.getDrawable(value.getSecond(), mContext);
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
try {
|
||||
return ResourceHelper.getColor(value.getSecond().getValue());
|
||||
} catch (NumberFormatException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e,
|
||||
null /*data*/);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorStateList getColorStateList(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> resValue = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (resValue != null) {
|
||||
ColorStateList stateList = ResourceHelper.getColorStateList(resValue.getSecond(),
|
||||
mContext);
|
||||
if (stateList != null) {
|
||||
return stateList;
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getText(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
ResourceValue resValue = value.getSecond();
|
||||
|
||||
assert resValue != null;
|
||||
if (resValue != null) {
|
||||
String v = resValue.getValue();
|
||||
if (v != null) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlResourceParser getLayout(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (v != null) {
|
||||
ResourceValue value = v.getSecond();
|
||||
XmlPullParser parser = null;
|
||||
|
||||
try {
|
||||
// check if the current parser can provide us with a custom parser.
|
||||
if (mPlatformResourceFlag[0] == false) {
|
||||
parser = mProjectCallback.getParser(value);
|
||||
}
|
||||
|
||||
// create a new one manually if needed.
|
||||
if (parser == null) {
|
||||
File xml = new File(value.getValue());
|
||||
if (xml.isFile()) {
|
||||
// we need to create a pull parser around the layout XML file, and then
|
||||
// give that to our XmlBlockParser
|
||||
parser = ParserFactory.create(xml);
|
||||
}
|
||||
}
|
||||
|
||||
if (parser != null) {
|
||||
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
|
||||
}
|
||||
} catch (XmlPullParserException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
|
||||
"Failed to configure parser for " + value.getValue(), e, null /*data*/);
|
||||
// we'll return null below.
|
||||
} catch (FileNotFoundException e) {
|
||||
// this shouldn't happen since we check above.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlResourceParser getAnimation(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (v != null) {
|
||||
ResourceValue value = v.getSecond();
|
||||
XmlPullParser parser = null;
|
||||
|
||||
try {
|
||||
File xml = new File(value.getValue());
|
||||
if (xml.isFile()) {
|
||||
// we need to create a pull parser around the layout XML file, and then
|
||||
// give that to our XmlBlockParser
|
||||
parser = ParserFactory.create(xml);
|
||||
|
||||
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
|
||||
}
|
||||
} catch (XmlPullParserException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
|
||||
"Failed to configure parser for " + value.getValue(), e, null /*data*/);
|
||||
// we'll return null below.
|
||||
} catch (FileNotFoundException e) {
|
||||
// this shouldn't happen since we check above.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
|
||||
return mContext.obtainStyledAttributes(set, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedArray obtainTypedArray(int id) throws NotFoundException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public float getDimension(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
ResourceValue resValue = value.getSecond();
|
||||
|
||||
assert resValue != null;
|
||||
if (resValue != null) {
|
||||
String v = resValue.getValue();
|
||||
if (v != null) {
|
||||
if (v.equals(BridgeConstants.MATCH_PARENT) ||
|
||||
v.equals(BridgeConstants.FILL_PARENT)) {
|
||||
return LayoutParams.MATCH_PARENT;
|
||||
} else if (v.equals(BridgeConstants.WRAP_CONTENT)) {
|
||||
return LayoutParams.WRAP_CONTENT;
|
||||
}
|
||||
|
||||
if (ResourceHelper.parseFloatAttribute(
|
||||
value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
|
||||
mTmpValue.type == TypedValue.TYPE_DIMENSION) {
|
||||
return mTmpValue.getDimension(getDisplayMetrics());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDimensionPixelOffset(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
ResourceValue resValue = value.getSecond();
|
||||
|
||||
assert resValue != null;
|
||||
if (resValue != null) {
|
||||
String v = resValue.getValue();
|
||||
if (v != null) {
|
||||
if (ResourceHelper.parseFloatAttribute(
|
||||
value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
|
||||
mTmpValue.type == TypedValue.TYPE_DIMENSION) {
|
||||
return TypedValue.complexToDimensionPixelOffset(mTmpValue.data,
|
||||
getDisplayMetrics());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDimensionPixelSize(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
ResourceValue resValue = value.getSecond();
|
||||
|
||||
assert resValue != null;
|
||||
if (resValue != null) {
|
||||
String v = resValue.getValue();
|
||||
if (v != null) {
|
||||
if (ResourceHelper.parseFloatAttribute(
|
||||
value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
|
||||
mTmpValue.type == TypedValue.TYPE_DIMENSION) {
|
||||
return TypedValue.complexToDimensionPixelSize(mTmpValue.data,
|
||||
getDisplayMetrics());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInteger(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
ResourceValue resValue = value.getSecond();
|
||||
|
||||
assert resValue != null;
|
||||
if (resValue != null) {
|
||||
String v = resValue.getValue();
|
||||
if (v != null) {
|
||||
int radix = 10;
|
||||
if (v.startsWith("0x")) {
|
||||
v = v.substring(2);
|
||||
radix = 16;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(v, radix);
|
||||
} catch (NumberFormatException e) {
|
||||
// return exception below
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
ResourceValue resValue = value.getSecond();
|
||||
|
||||
assert resValue != null;
|
||||
if (resValue != null) {
|
||||
String v = resValue.getValue();
|
||||
if (v != null) {
|
||||
return Boolean.parseBoolean(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceEntryName(int resid) throws NotFoundException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceName(int resid) throws NotFoundException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceTypeName(int resid) throws NotFoundException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(int id, Object... formatArgs) throws NotFoundException {
|
||||
String s = getString(id);
|
||||
if (s != null) {
|
||||
return String.format(s, formatArgs);
|
||||
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null && value.getSecond().getValue() != null) {
|
||||
return value.getSecond().getValue();
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getValue(int id, TypedValue outValue, boolean resolveRefs)
|
||||
throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
String v = value.getSecond().getValue();
|
||||
|
||||
if (v != null) {
|
||||
if (ResourceHelper.parseFloatAttribute(value.getFirst(), v, outValue,
|
||||
false /*requireUnit*/)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// else it's a string
|
||||
outValue.type = TypedValue.TYPE_STRING;
|
||||
outValue.string = v;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getValue(String name, TypedValue outValue, boolean resolveRefs)
|
||||
throws NotFoundException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlResourceParser getXml(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
String v = value.getSecond().getValue();
|
||||
|
||||
if (v != null) {
|
||||
// check this is a file
|
||||
File f = new File(v);
|
||||
if (f.isFile()) {
|
||||
try {
|
||||
XmlPullParser parser = ParserFactory.create(f);
|
||||
|
||||
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
|
||||
} catch (XmlPullParserException e) {
|
||||
NotFoundException newE = new NotFoundException();
|
||||
newE.initCause(e);
|
||||
throw newE;
|
||||
} catch (FileNotFoundException e) {
|
||||
NotFoundException newE = new NotFoundException();
|
||||
newE.initCause(e);
|
||||
throw newE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlResourceParser loadXmlResourceParser(String file, int id,
|
||||
int assetCookie, String type) throws NotFoundException {
|
||||
// even though we know the XML file to load directly, we still need to resolve the
|
||||
// id so that we can know if it's a platform or project resource.
|
||||
// (mPlatformResouceFlag will get the result and will be used later).
|
||||
getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
File f = new File(file);
|
||||
try {
|
||||
XmlPullParser parser = ParserFactory.create(f);
|
||||
|
||||
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
|
||||
} catch (XmlPullParserException e) {
|
||||
NotFoundException newE = new NotFoundException();
|
||||
newE.initCause(e);
|
||||
throw newE;
|
||||
} catch (FileNotFoundException e) {
|
||||
NotFoundException newE = new NotFoundException();
|
||||
newE.initCause(e);
|
||||
throw newE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InputStream openRawResource(int id) throws NotFoundException {
|
||||
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
|
||||
|
||||
if (value != null) {
|
||||
String path = value.getSecond().getValue();
|
||||
|
||||
if (path != null) {
|
||||
// check this is a file
|
||||
File f = new File(path);
|
||||
if (f.isFile()) {
|
||||
try {
|
||||
// if it's a nine-patch return a custom input stream so that
|
||||
// other methods (mainly bitmap factory) can detect it's a 9-patch
|
||||
// and actually load it as a 9-patch instead of a normal bitmap
|
||||
if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
|
||||
return new NinePatchInputStream(f);
|
||||
}
|
||||
return new FileInputStream(f);
|
||||
} catch (FileNotFoundException e) {
|
||||
NotFoundException newE = new NotFoundException();
|
||||
newE.initCause(e);
|
||||
throw newE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// id was not found or not resolved. Throw a NotFoundException.
|
||||
throwException(id);
|
||||
|
||||
// this is not used since the method above always throws
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
|
||||
getValue(id, value, true);
|
||||
|
||||
String path = value.string.toString();
|
||||
|
||||
File f = new File(path);
|
||||
if (f.isFile()) {
|
||||
try {
|
||||
// if it's a nine-patch return a custom input stream so that
|
||||
// other methods (mainly bitmap factory) can detect it's a 9-patch
|
||||
// and actually load it as a 9-patch instead of a normal bitmap
|
||||
if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
|
||||
return new NinePatchInputStream(f);
|
||||
}
|
||||
return new FileInputStream(f);
|
||||
} catch (FileNotFoundException e) {
|
||||
NotFoundException exception = new NotFoundException();
|
||||
exception.initCause(e);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetFileDescriptor openRawResourceFd(int id) throws NotFoundException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and throws a {@link Resources.NotFoundException} based on a resource id and a resource type.
|
||||
* @param id the id of the resource
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
private void throwException(int id) throws NotFoundException {
|
||||
// first get the String related to this id in the framework
|
||||
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
|
||||
|
||||
// if the name is unknown in the framework, get it from the custom view loader.
|
||||
if (resourceInfo == null && mProjectCallback != null) {
|
||||
resourceInfo = mProjectCallback.resolveResourceId(id);
|
||||
}
|
||||
|
||||
String message = null;
|
||||
if (resourceInfo != null) {
|
||||
message = String.format(
|
||||
"Could not find %1$s resource matching value 0x%2$X (resolved name: %3$s) in current configuration.",
|
||||
resourceInfo.getFirst(), id, resourceInfo.getSecond());
|
||||
} else {
|
||||
message = String.format(
|
||||
"Could not resolve resource value: 0x%1$X.", id);
|
||||
}
|
||||
|
||||
throw new NotFoundException(message);
|
||||
}
|
||||
}
|
||||
@@ -1,908 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content.res;
|
||||
|
||||
import com.android.ide.common.rendering.api.AttrResourceValue;
|
||||
import com.android.ide.common.rendering.api.LayoutLog;
|
||||
import com.android.ide.common.rendering.api.RenderResources;
|
||||
import com.android.ide.common.rendering.api.ResourceValue;
|
||||
import com.android.ide.common.rendering.api.StyleResourceValue;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.BridgeConstants;
|
||||
import com.android.layoutlib.bridge.android.BridgeContext;
|
||||
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
|
||||
import com.android.layoutlib.bridge.impl.ParserFactory;
|
||||
import com.android.layoutlib.bridge.impl.ResourceHelper;
|
||||
import com.android.resources.ResourceType;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater_Delegate;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Custom implementation of TypedArray to handle non compiled resources.
|
||||
*/
|
||||
public final class BridgeTypedArray extends TypedArray {
|
||||
|
||||
private final BridgeResources mBridgeResources;
|
||||
private final BridgeContext mContext;
|
||||
private final boolean mPlatformFile;
|
||||
|
||||
private ResourceValue[] mResourceData;
|
||||
private String[] mNames;
|
||||
private boolean[] mIsFramework;
|
||||
|
||||
public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
|
||||
boolean platformFile) {
|
||||
super(null, null, null, 0);
|
||||
mBridgeResources = resources;
|
||||
mContext = context;
|
||||
mPlatformFile = platformFile;
|
||||
mResourceData = new ResourceValue[len];
|
||||
mNames = new String[len];
|
||||
mIsFramework = new boolean[len];
|
||||
}
|
||||
|
||||
/**
|
||||
* A bridge-specific method that sets a value in the type array
|
||||
* @param index the index of the value in the TypedArray
|
||||
* @param name the name of the attribute
|
||||
* @param isFramework whether the attribute is in the android namespace.
|
||||
* @param value the value of the attribute
|
||||
*/
|
||||
public void bridgeSetValue(int index, String name, boolean isFramework, ResourceValue value) {
|
||||
mResourceData[index] = value;
|
||||
mNames[index] = name;
|
||||
mIsFramework[index] = isFramework;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seals the array after all calls to {@link #bridgeSetValue(int, String, ResourceValue)} have
|
||||
* been done.
|
||||
* <p/>This allows to compute the list of non default values, permitting
|
||||
* {@link #getIndexCount()} to return the proper value.
|
||||
*/
|
||||
public void sealArray() {
|
||||
// fills TypedArray.mIndices which is used to implement getIndexCount/getIndexAt
|
||||
// first count the array size
|
||||
int count = 0;
|
||||
for (ResourceValue data : mResourceData) {
|
||||
if (data != null) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate the table with an extra to store the size
|
||||
mIndices = new int[count+1];
|
||||
mIndices[0] = count;
|
||||
|
||||
// fill the array with the indices.
|
||||
int index = 1;
|
||||
for (int i = 0 ; i < mResourceData.length ; i++) {
|
||||
if (mResourceData[i] != null) {
|
||||
mIndices[index++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of values in this array.
|
||||
*/
|
||||
@Override
|
||||
public int length() {
|
||||
return mResourceData.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Resources object this array was loaded from.
|
||||
*/
|
||||
@Override
|
||||
public Resources getResources() {
|
||||
return mBridgeResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the styled string value for the attribute at <var>index</var>.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return CharSequence holding string data. May be styled. Returns
|
||||
* null if the attribute is not defined.
|
||||
*/
|
||||
@Override
|
||||
public CharSequence getText(int index) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mResourceData[index] != null) {
|
||||
// FIXME: handle styled strings!
|
||||
return mResourceData[index].getValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the string value for the attribute at <var>index</var>.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return String holding string data. Any styling information is
|
||||
* removed. Returns null if the attribute is not defined.
|
||||
*/
|
||||
@Override
|
||||
public String getString(int index) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mResourceData[index] != null) {
|
||||
return mResourceData[index].getValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the boolean value for the attribute at <var>index</var>.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param defValue Value to return if the attribute is not defined.
|
||||
*
|
||||
* @return Attribute boolean value, or defValue if not defined.
|
||||
*/
|
||||
@Override
|
||||
public boolean getBoolean(int index, boolean defValue) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
String s = mResourceData[index].getValue();
|
||||
if (s != null) {
|
||||
return XmlUtils.convertValueToBoolean(s, defValue);
|
||||
}
|
||||
|
||||
return defValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the integer value for the attribute at <var>index</var>.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param defValue Value to return if the attribute is not defined.
|
||||
*
|
||||
* @return Attribute int value, or defValue if not defined.
|
||||
*/
|
||||
@Override
|
||||
public int getInt(int index, int defValue) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
String s = mResourceData[index].getValue();
|
||||
|
||||
if (RenderResources.REFERENCE_NULL.equals(s)) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (s == null || s.length() == 0) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
try {
|
||||
return XmlUtils.convertValueToInt(s, defValue);
|
||||
} catch (NumberFormatException e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
// Field is not null and is not an integer.
|
||||
// Check for possible constants and try to find them.
|
||||
// Get the map of attribute-constant -> IntegerValue
|
||||
Map<String, Integer> map = null;
|
||||
if (mIsFramework[index]) {
|
||||
map = Bridge.getEnumValues(mNames[index]);
|
||||
} else {
|
||||
// get the styleable matching the resolved name
|
||||
RenderResources res = mContext.getRenderResources();
|
||||
ResourceValue attr = res.getProjectResource(ResourceType.ATTR, mNames[index]);
|
||||
if (attr instanceof AttrResourceValue) {
|
||||
map = ((AttrResourceValue) attr).getAttributeValues();
|
||||
}
|
||||
}
|
||||
|
||||
if (map != null) {
|
||||
// accumulator to store the value of the 1+ constants.
|
||||
int result = 0;
|
||||
|
||||
// split the value in case this is a mix of several flags.
|
||||
String[] keywords = s.split("\\|");
|
||||
for (String keyword : keywords) {
|
||||
Integer i = map.get(keyword.trim());
|
||||
if (i != null) {
|
||||
result |= i.intValue();
|
||||
} else {
|
||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
String.format(
|
||||
"\"%s\" in attribute \"%2$s\" is not a valid value",
|
||||
keyword, mNames[index]), null /*data*/);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return defValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the float value for the attribute at <var>index</var>.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return Attribute float value, or defValue if not defined..
|
||||
*/
|
||||
@Override
|
||||
public float getFloat(int index, float defValue) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
String s = mResourceData[index].getValue();
|
||||
|
||||
if (s != null) {
|
||||
try {
|
||||
return Float.parseFloat(s);
|
||||
} catch (NumberFormatException e) {
|
||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
String.format(
|
||||
"\"%s\" in attribute \"%2$s\" cannot be converted to float.",
|
||||
s, mNames[index]), null /*data*/);
|
||||
|
||||
// we'll return the default value below.
|
||||
}
|
||||
}
|
||||
return defValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the color value for the attribute at <var>index</var>. If
|
||||
* the attribute references a color resource holding a complex
|
||||
* {@link android.content.res.ColorStateList}, then the default color from
|
||||
* the set is returned.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param defValue Value to return if the attribute is not defined or
|
||||
* not a resource.
|
||||
*
|
||||
* @return Attribute color value, or defValue if not defined.
|
||||
*/
|
||||
@Override
|
||||
public int getColor(int index, int defValue) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
ColorStateList colorStateList = ResourceHelper.getColorStateList(
|
||||
mResourceData[index], mContext);
|
||||
if (colorStateList != null) {
|
||||
return colorStateList.getDefaultColor();
|
||||
}
|
||||
|
||||
return defValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the ColorStateList for the attribute at <var>index</var>.
|
||||
* The value may be either a single solid color or a reference to
|
||||
* a color or complex {@link android.content.res.ColorStateList} description.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return ColorStateList for the attribute, or null if not defined.
|
||||
*/
|
||||
@Override
|
||||
public ColorStateList getColorStateList(int index) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ResourceValue resValue = mResourceData[index];
|
||||
String value = resValue.getValue();
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (RenderResources.REFERENCE_NULL.equals(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// let the framework inflate the ColorStateList from the XML file.
|
||||
File f = new File(value);
|
||||
if (f.isFile()) {
|
||||
try {
|
||||
XmlPullParser parser = ParserFactory.create(f);
|
||||
|
||||
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
|
||||
parser, mContext, resValue.isFramework());
|
||||
try {
|
||||
return ColorStateList.createFromXml(mContext.getResources(), blockParser);
|
||||
} finally {
|
||||
blockParser.ensurePopped();
|
||||
}
|
||||
} catch (XmlPullParserException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
|
||||
"Failed to configure parser for " + value, e, null /*data*/);
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
// this is an error and not warning since the file existence is checked before
|
||||
// attempting to parse it.
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
|
||||
"Failed to parse file " + value, e, null /*data*/);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
int color = ResourceHelper.getColor(value);
|
||||
return ColorStateList.valueOf(color);
|
||||
} catch (NumberFormatException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null /*data*/);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the integer value for the attribute at <var>index</var>.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param defValue Value to return if the attribute is not defined or
|
||||
* not a resource.
|
||||
*
|
||||
* @return Attribute integer value, or defValue if not defined.
|
||||
*/
|
||||
@Override
|
||||
public int getInteger(int index, int defValue) {
|
||||
return getInt(index, defValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a dimensional unit attribute at <var>index</var>. Unit
|
||||
* conversions are based on the current {@link DisplayMetrics}
|
||||
* associated with the resources this {@link TypedArray} object
|
||||
* came from.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param defValue Value to return if the attribute is not defined or
|
||||
* not a resource.
|
||||
*
|
||||
* @return Attribute dimension value multiplied by the appropriate
|
||||
* metric, or defValue if not defined.
|
||||
*
|
||||
* @see #getDimensionPixelOffset
|
||||
* @see #getDimensionPixelSize
|
||||
*/
|
||||
@Override
|
||||
public float getDimension(int index, float defValue) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
String s = mResourceData[index].getValue();
|
||||
|
||||
if (s == null) {
|
||||
return defValue;
|
||||
} else if (s.equals(BridgeConstants.MATCH_PARENT) ||
|
||||
s.equals(BridgeConstants.FILL_PARENT)) {
|
||||
return LayoutParams.MATCH_PARENT;
|
||||
} else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
|
||||
return LayoutParams.WRAP_CONTENT;
|
||||
} else if (RenderResources.REFERENCE_NULL.equals(s)) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true /*requireUnit*/)) {
|
||||
return mValue.getDimension(mBridgeResources.getDisplayMetrics());
|
||||
}
|
||||
|
||||
// looks like we were unable to resolve the dimension value
|
||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
String.format(
|
||||
"\"%1$s\" in attribute \"%2$s\" is not a valid format.",
|
||||
s, mNames[index]), null /*data*/);
|
||||
|
||||
return defValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a dimensional unit attribute at <var>index</var> for use
|
||||
* as an offset in raw pixels. This is the same as
|
||||
* {@link #getDimension}, except the returned value is converted to
|
||||
* integer pixels for you. An offset conversion involves simply
|
||||
* truncating the base value to an integer.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param defValue Value to return if the attribute is not defined or
|
||||
* not a resource.
|
||||
*
|
||||
* @return Attribute dimension value multiplied by the appropriate
|
||||
* metric and truncated to integer pixels, or defValue if not defined.
|
||||
*
|
||||
* @see #getDimension
|
||||
* @see #getDimensionPixelSize
|
||||
*/
|
||||
@Override
|
||||
public int getDimensionPixelOffset(int index, int defValue) {
|
||||
return (int) getDimension(index, defValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a dimensional unit attribute at <var>index</var> for use
|
||||
* as a size in raw pixels. This is the same as
|
||||
* {@link #getDimension}, except the returned value is converted to
|
||||
* integer pixels for use as a size. A size conversion involves
|
||||
* rounding the base value, and ensuring that a non-zero base value
|
||||
* is at least one pixel in size.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param defValue Value to return if the attribute is not defined or
|
||||
* not a resource.
|
||||
*
|
||||
* @return Attribute dimension value multiplied by the appropriate
|
||||
* metric and truncated to integer pixels, or defValue if not defined.
|
||||
*
|
||||
* @see #getDimension
|
||||
* @see #getDimensionPixelOffset
|
||||
*/
|
||||
@Override
|
||||
public int getDimensionPixelSize(int index, int defValue) {
|
||||
try {
|
||||
return getDimension(index);
|
||||
} catch (RuntimeException e) {
|
||||
if (mResourceData[index] != null) {
|
||||
String s = mResourceData[index].getValue();
|
||||
|
||||
if (s != null) {
|
||||
// looks like we were unable to resolve the dimension value
|
||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
String.format(
|
||||
"\"%1$s\" in attribute \"%2$s\" is not a valid format.",
|
||||
s, mNames[index]), null /*data*/);
|
||||
}
|
||||
}
|
||||
|
||||
return defValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special version of {@link #getDimensionPixelSize} for retrieving
|
||||
* {@link android.view.ViewGroup}'s layout_width and layout_height
|
||||
* attributes. This is only here for performance reasons; applications
|
||||
* should use {@link #getDimensionPixelSize}.
|
||||
*
|
||||
* @param index Index of the attribute to retrieve.
|
||||
* @param name Textual name of attribute for error reporting.
|
||||
*
|
||||
* @return Attribute dimension value multiplied by the appropriate
|
||||
* metric and truncated to integer pixels.
|
||||
*/
|
||||
@Override
|
||||
public int getLayoutDimension(int index, String name) {
|
||||
try {
|
||||
// this will throw an exception
|
||||
return getDimension(index);
|
||||
} catch (RuntimeException e) {
|
||||
|
||||
if (LayoutInflater_Delegate.sIsInInclude) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
"You must supply a " + name + " attribute.", null);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayoutDimension(int index, int defValue) {
|
||||
return getDimensionPixelSize(index, defValue);
|
||||
}
|
||||
|
||||
private int getDimension(int index) {
|
||||
if (mResourceData[index] == null) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
String s = mResourceData[index].getValue();
|
||||
|
||||
if (s == null) {
|
||||
throw new RuntimeException();
|
||||
} else if (s.equals(BridgeConstants.MATCH_PARENT) ||
|
||||
s.equals(BridgeConstants.FILL_PARENT)) {
|
||||
return LayoutParams.MATCH_PARENT;
|
||||
} else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
|
||||
return LayoutParams.WRAP_CONTENT;
|
||||
} else if (RenderResources.REFERENCE_NULL.equals(s)) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true /*requireUnit*/)) {
|
||||
float f = mValue.getDimension(mBridgeResources.getDisplayMetrics());
|
||||
|
||||
final int res = (int)(f+0.5f);
|
||||
if (res != 0) return res;
|
||||
if (f == 0) return 0;
|
||||
if (f > 0) return 1;
|
||||
}
|
||||
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a fractional unit attribute at <var>index</var>.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param base The base value of this fraction. In other words, a
|
||||
* standard fraction is multiplied by this value.
|
||||
* @param pbase The parent base value of this fraction. In other
|
||||
* words, a parent fraction (nn%p) is multiplied by this
|
||||
* value.
|
||||
* @param defValue Value to return if the attribute is not defined or
|
||||
* not a resource.
|
||||
*
|
||||
* @return Attribute fractional value multiplied by the appropriate
|
||||
* base value, or defValue if not defined.
|
||||
*/
|
||||
@Override
|
||||
public float getFraction(int index, int base, int pbase, float defValue) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
String value = mResourceData[index].getValue();
|
||||
if (value == null) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (ResourceHelper.parseFloatAttribute(mNames[index], value, mValue,
|
||||
false /*requireUnit*/)) {
|
||||
return mValue.getFraction(base, pbase);
|
||||
}
|
||||
|
||||
// looks like we were unable to resolve the fraction value
|
||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
String.format(
|
||||
"\"%1$s\" in attribute \"%2$s\" cannot be converted to a fraction.",
|
||||
value, mNames[index]), null /*data*/);
|
||||
|
||||
return defValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the resource identifier for the attribute at
|
||||
* <var>index</var>. Note that attribute resource as resolved when
|
||||
* the overall {@link TypedArray} object is retrieved. As a
|
||||
* result, this function will return the resource identifier of the
|
||||
* final resource value that was found, <em>not</em> necessarily the
|
||||
* original resource that was specified by the attribute.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param defValue Value to return if the attribute is not defined or
|
||||
* not a resource.
|
||||
*
|
||||
* @return Attribute resource identifier, or defValue if not defined.
|
||||
*/
|
||||
@Override
|
||||
public int getResourceId(int index, int defValue) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
// get the Resource for this index
|
||||
ResourceValue resValue = mResourceData[index];
|
||||
|
||||
// no data, return the default value.
|
||||
if (resValue == null) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
// check if this is a style resource
|
||||
if (resValue instanceof StyleResourceValue) {
|
||||
// get the id that will represent this style.
|
||||
return mContext.getDynamicIdByStyle((StyleResourceValue)resValue);
|
||||
}
|
||||
|
||||
if (RenderResources.REFERENCE_NULL.equals(resValue.getValue())) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
// if the attribute was a reference to a resource, and not a declaration of an id (@+id),
|
||||
// then the xml attribute value was "resolved" which leads us to a ResourceValue with a
|
||||
// valid getType() and getName() returning a resource name.
|
||||
// (and getValue() returning null!). We need to handle this!
|
||||
if (resValue.getResourceType() != null) {
|
||||
// if this is a framework id
|
||||
if (mPlatformFile || resValue.isFramework()) {
|
||||
// look for idName in the android R classes
|
||||
return mContext.getFrameworkResourceValue(
|
||||
resValue.getResourceType(), resValue.getName(), defValue);
|
||||
}
|
||||
|
||||
// look for idName in the project R class.
|
||||
return mContext.getProjectResourceValue(
|
||||
resValue.getResourceType(), resValue.getName(), defValue);
|
||||
}
|
||||
|
||||
// else, try to get the value, and resolve it somehow.
|
||||
String value = resValue.getValue();
|
||||
if (value == null) {
|
||||
return defValue;
|
||||
}
|
||||
|
||||
// if the value is just an integer, return it.
|
||||
try {
|
||||
int i = Integer.parseInt(value);
|
||||
if (Integer.toString(i).equals(value)) {
|
||||
return i;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// pass
|
||||
}
|
||||
|
||||
// Handle the @id/<name>, @+id/<name> and @android:id/<name>
|
||||
// We need to return the exact value that was compiled (from the various R classes),
|
||||
// as these values can be reused internally with calls to findViewById().
|
||||
// There's a trick with platform layouts that not use "android:" but their IDs are in
|
||||
// fact in the android.R and com.android.internal.R classes.
|
||||
// The field mPlatformFile will indicate that all IDs are to be looked up in the android R
|
||||
// classes exclusively.
|
||||
|
||||
// if this is a reference to an id, find it.
|
||||
if (value.startsWith("@id/") || value.startsWith("@+") ||
|
||||
value.startsWith("@android:id/")) {
|
||||
|
||||
int pos = value.indexOf('/');
|
||||
String idName = value.substring(pos + 1);
|
||||
|
||||
// if this is a framework id
|
||||
if (mPlatformFile || value.startsWith("@android") || value.startsWith("@+android")) {
|
||||
// look for idName in the android R classes
|
||||
return mContext.getFrameworkResourceValue(ResourceType.ID, idName, defValue);
|
||||
}
|
||||
|
||||
// look for idName in the project R class.
|
||||
return mContext.getProjectResourceValue(ResourceType.ID, idName, defValue);
|
||||
}
|
||||
|
||||
// not a direct id valid reference? resolve it
|
||||
Integer idValue = null;
|
||||
|
||||
if (resValue.isFramework()) {
|
||||
idValue = Bridge.getResourceId(resValue.getResourceType(),
|
||||
resValue.getName());
|
||||
} else {
|
||||
idValue = mContext.getProjectCallback().getResourceId(
|
||||
resValue.getResourceType(), resValue.getName());
|
||||
}
|
||||
|
||||
if (idValue != null) {
|
||||
return idValue.intValue();
|
||||
}
|
||||
|
||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
|
||||
String.format(
|
||||
"Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index]),
|
||||
resValue);
|
||||
|
||||
return defValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Drawable for the attribute at <var>index</var>. This
|
||||
* gets the resource ID of the selected attribute, and uses
|
||||
* {@link Resources#getDrawable Resources.getDrawable} of the owning
|
||||
* Resources object to retrieve its Drawable.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return Drawable for the attribute, or null if not defined.
|
||||
*/
|
||||
@Override
|
||||
public Drawable getDrawable(int index) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ResourceValue value = mResourceData[index];
|
||||
String stringValue = value.getValue();
|
||||
if (stringValue == null || RenderResources.REFERENCE_NULL.equals(stringValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ResourceHelper.getDrawable(value, mContext);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the CharSequence[] for the attribute at <var>index</var>.
|
||||
* This gets the resource ID of the selected attribute, and uses
|
||||
* {@link Resources#getTextArray Resources.getTextArray} of the owning
|
||||
* Resources object to retrieve its String[].
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return CharSequence[] for the attribute, or null if not defined.
|
||||
*/
|
||||
@Override
|
||||
public CharSequence[] getTextArray(int index) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String value = mResourceData[index].getValue();
|
||||
if (value != null) {
|
||||
if (RenderResources.REFERENCE_NULL.equals(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new CharSequence[] { value };
|
||||
}
|
||||
|
||||
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
|
||||
String.format(
|
||||
String.format("Unknown value for getTextArray(%d) => %s", //DEBUG
|
||||
index, mResourceData[index].getName())), null /*data*/);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw TypedValue for the attribute at <var>index</var>.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
* @param outValue TypedValue object in which to place the attribute's
|
||||
* data.
|
||||
*
|
||||
* @return Returns true if the value was retrieved, else false.
|
||||
*/
|
||||
@Override
|
||||
public boolean getValue(int index, TypedValue outValue) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mResourceData[index] == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String s = mResourceData[index].getValue();
|
||||
|
||||
return ResourceHelper.parseFloatAttribute(mNames[index], s, outValue,
|
||||
false /*requireUnit*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether there is an attribute at <var>index</var>.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return True if the attribute has a value, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasValue(int index) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mResourceData[index] != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw TypedValue for the attribute at <var>index</var>
|
||||
* and return a temporary object holding its data. This object is only
|
||||
* valid until the next call on to {@link TypedArray}.
|
||||
*
|
||||
* @param index Index of attribute to retrieve.
|
||||
*
|
||||
* @return Returns a TypedValue object if the attribute is defined,
|
||||
* containing its data; otherwise returns null. (You will not
|
||||
* receive a TypedValue whose type is TYPE_NULL.)
|
||||
*/
|
||||
@Override
|
||||
public TypedValue peekValue(int index) {
|
||||
if (index < 0 || index >= mResourceData.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (getValue(index, mValue)) {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a message about the parser state suitable for printing error messages.
|
||||
*/
|
||||
@Override
|
||||
public String getPositionDescription() {
|
||||
return "<internal -- stub if needed>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Give back a previously retrieved TypedArray, for later re-use.
|
||||
*/
|
||||
@Override
|
||||
public void recycle() {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Arrays.toString(mResourceData);
|
||||
}
|
||||
}
|
||||