Move frameworks/base/tools/ to frameworks/tools/

Change-Id: I3ffafdab27cc4aca256c3a5806b630795b75d5c8
This commit is contained in:
Mike Lockwood
2013-08-28 09:44:17 -07:00
parent 647b6f5ed2
commit 9f6a119c8a
291 changed files with 0 additions and 67426 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -1 +0,0 @@
bin

View File

@@ -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))

View File

@@ -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.

View File

@@ -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>

View File

@@ -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>

View File

@@ -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.

View File

@@ -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

View File

@@ -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))

View File

@@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 B

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 B

View File

@@ -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();
}
}
}

View File

@@ -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
}
}

View File

@@ -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);
}
}
}

View File

@@ -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() {
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

Some files were not shown because too many files have changed in this diff Show More