2012-05-31 07:51:33 +08:00
|
|
|
#include "CCBReader.h"
|
|
|
|
|
2012-06-14 06:25:59 +08:00
|
|
|
#include <algorithm>
|
|
|
|
|
2012-05-31 02:28:50 +08:00
|
|
|
#include "CCNodeLoader.h"
|
2012-06-06 08:15:28 +08:00
|
|
|
#include "CCNodeLoaderLibrary.h"
|
2012-06-13 02:59:49 +08:00
|
|
|
#include "CCNodeLoaderListener.h"
|
|
|
|
#include "CCBMemberVariableAssigner.h"
|
|
|
|
#include "CCBSelectorResolver.h"
|
2012-05-31 02:28:50 +08:00
|
|
|
|
2012-06-05 07:16:42 +08:00
|
|
|
#ifdef __CC_PLATFORM_IOS
|
2012-06-13 02:59:49 +08:00
|
|
|
#include <UIKit/UIDevice.h>
|
2012-06-05 07:16:42 +08:00
|
|
|
#endif
|
|
|
|
|
2012-06-14 05:19:13 +08:00
|
|
|
USING_NS_CC;
|
|
|
|
USING_NS_CC_EXT;
|
2012-05-31 02:28:50 +08:00
|
|
|
|
2012-06-13 02:59:49 +08:00
|
|
|
CCBReader::CCBReader(CCNodeLoaderLibrary * pCCNodeLoaderLibrary, CCBMemberVariableAssigner * pCCBMemberVariableAssigner, CCBSelectorResolver * pCCBSelectorResolver, CCNodeLoaderListener * pCCNodeLoaderListener) {
|
2012-06-06 08:15:28 +08:00
|
|
|
this->mRootNode = NULL;
|
|
|
|
this->mRootCCBReader = true;
|
|
|
|
|
|
|
|
this->mCCNodeLoaderLibrary = pCCNodeLoaderLibrary;
|
2012-06-13 02:59:49 +08:00
|
|
|
this->mCCNodeLoaderLibrary->retain();
|
2012-06-05 06:52:49 +08:00
|
|
|
this->mCCBMemberVariableAssigner = pCCBMemberVariableAssigner;
|
|
|
|
this->mCCBSelectorResolver = pCCBSelectorResolver;
|
2012-06-13 02:59:49 +08:00
|
|
|
this->mCCNodeLoaderListener = pCCNodeLoaderListener;
|
2012-06-05 06:52:49 +08:00
|
|
|
|
2012-06-05 07:16:42 +08:00
|
|
|
this->mResolutionScale = 1;
|
2012-06-06 08:15:28 +08:00
|
|
|
|
2012-06-05 07:16:42 +08:00
|
|
|
#ifdef __CC_PLATFORM_IOS
|
|
|
|
/* iPad */
|
|
|
|
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
|
|
|
this->mResolutionScale = 2;
|
|
|
|
}
|
|
|
|
#endif
|
2012-06-01 05:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CCBReader::~CCBReader() {
|
2012-06-06 08:15:28 +08:00
|
|
|
if(this->mBytes != NULL) {
|
2012-06-01 05:57:13 +08:00
|
|
|
delete this->mBytes;
|
|
|
|
this->mBytes = NULL;
|
|
|
|
}
|
|
|
|
|
2012-06-13 02:59:49 +08:00
|
|
|
this->mCCNodeLoaderLibrary->release();
|
|
|
|
|
2012-06-06 08:15:28 +08:00
|
|
|
/* Clear string cache. */
|
|
|
|
this->mStringCache.clear();
|
|
|
|
|
|
|
|
if(this->mRootCCBReader) {
|
|
|
|
/* Clear loaded spritesheets. */
|
|
|
|
this->mLoadedSpriteSheets.clear();
|
|
|
|
}
|
|
|
|
|
2012-06-14 05:33:39 +08:00
|
|
|
CC_SAFE_RELEASE(this->mRootNode);
|
2012-06-01 05:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CCBReader::CCBReader(CCBReader * pCCBReader) {
|
2012-06-06 08:15:28 +08:00
|
|
|
this->mRootNode = NULL;
|
|
|
|
this->mRootCCBReader = false;
|
|
|
|
|
|
|
|
/* Borrow data from the 'parent' CCBReader. */
|
2012-06-05 07:16:42 +08:00
|
|
|
this->mResolutionScale = pCCBReader->mResolutionScale;
|
2012-06-01 05:57:13 +08:00
|
|
|
this->mLoadedSpriteSheets = pCCBReader->mLoadedSpriteSheets;
|
2012-06-06 08:15:28 +08:00
|
|
|
this->mCCNodeLoaderLibrary = pCCBReader->mCCNodeLoaderLibrary;
|
2012-06-14 05:19:13 +08:00
|
|
|
this->mCCNodeLoaderLibrary->retain();
|
|
|
|
|
2012-06-05 06:52:49 +08:00
|
|
|
this->mCCBMemberVariableAssigner = pCCBReader->mCCBMemberVariableAssigner;
|
|
|
|
this->mCCBSelectorResolver = pCCBReader->mCCBSelectorResolver;
|
2012-06-13 02:59:49 +08:00
|
|
|
this->mCCNodeLoaderListener = pCCBReader->mCCNodeLoaderListener;
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
2012-06-12 09:31:11 +08:00
|
|
|
std::string CCBReader::getCCBRootPath() {
|
|
|
|
return this->mCCBRootPath;
|
|
|
|
}
|
|
|
|
|
2012-06-05 06:52:49 +08:00
|
|
|
CCBMemberVariableAssigner * CCBReader::getCCBMemberVariableAssigner() {
|
|
|
|
return this->mCCBMemberVariableAssigner;
|
|
|
|
}
|
|
|
|
|
|
|
|
CCBSelectorResolver * CCBReader::getCCBSelectorResolver() {
|
|
|
|
return this->mCCBSelectorResolver;
|
|
|
|
}
|
|
|
|
|
2012-06-05 07:16:42 +08:00
|
|
|
float CCBReader::getResolutionScale() {
|
|
|
|
return this->mResolutionScale;
|
|
|
|
}
|
|
|
|
|
2012-06-12 09:31:11 +08:00
|
|
|
CCNode * CCBReader::readNodeGraphFromFile(const char * pCCBRootPath, const char * pCCBFileName, CCObject * pOwner) {
|
|
|
|
return this->readNodeGraphFromFile(pCCBRootPath, pCCBFileName, pOwner, CCDirector::sharedDirector()->getWinSize());
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
2012-06-12 09:31:11 +08:00
|
|
|
CCNode * CCBReader::readNodeGraphFromFile(const char * pCCBRootPath, const char * pCCBFileName, CCObject * pOwner, CCSize pRootContainerSize) {
|
|
|
|
this->mCCBRootPath = pCCBRootPath;
|
|
|
|
|
|
|
|
char ccbFullFilePath[strlen(pCCBRootPath) + strlen(pCCBFileName) + 1];
|
|
|
|
strcpy(ccbFullFilePath, pCCBRootPath);
|
|
|
|
strcat(ccbFullFilePath, pCCBFileName);
|
|
|
|
|
|
|
|
const char * path = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(ccbFullFilePath);
|
2012-06-06 08:15:28 +08:00
|
|
|
|
2012-06-01 05:57:13 +08:00
|
|
|
unsigned long size = 0;
|
2012-06-14 05:33:39 +08:00
|
|
|
this->mBytes = CCFileUtils::sharedFileUtils()->getFileData(path, "rb", &size);
|
2012-05-31 02:28:50 +08:00
|
|
|
|
|
|
|
this->mCurrentByte = 0;
|
|
|
|
this->mCurrentBit = 0;
|
|
|
|
this->mOwner = pOwner;
|
2012-06-05 06:52:49 +08:00
|
|
|
this->mRootContainerSize = pRootContainerSize;
|
2012-06-06 08:15:28 +08:00
|
|
|
|
2012-05-31 02:28:50 +08:00
|
|
|
if(!this->readHeader()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-06-06 08:15:28 +08:00
|
|
|
|
2012-05-31 02:28:50 +08:00
|
|
|
if(!this->readStringCache()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-06-06 08:15:28 +08:00
|
|
|
|
2012-05-31 02:28:50 +08:00
|
|
|
return this->readNodeGraph();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCBReader::readHeader() {
|
|
|
|
/* If no bytes loaded, don't crash about it. */
|
|
|
|
if(this->mBytes == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read magic bytes */
|
|
|
|
int magicBytes = *((int*)(this->mBytes + this->mCurrentByte));
|
|
|
|
this->mCurrentByte += 4;
|
|
|
|
|
2012-06-14 05:33:39 +08:00
|
|
|
if(CC_SWAP_INT32_LITTLE_TO_HOST(magicBytes) != 'ccbi') {
|
2012-05-31 02:28:50 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read version. */
|
|
|
|
int version = this->readInt(false);
|
|
|
|
if(version != kCCBVersion) {
|
|
|
|
CCLog("WARNING! Incompatible ccbi file version (file: %d reader: %d)", version, kCCBVersion);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCBReader::readStringCache() {
|
|
|
|
int numStrings = this->readInt(false);
|
|
|
|
|
|
|
|
for(int i = 0; i < numStrings; i++) {
|
2012-06-05 08:45:25 +08:00
|
|
|
this->readStringCacheEntry();
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-06-05 08:45:25 +08:00
|
|
|
void CCBReader::readStringCacheEntry() {
|
2012-05-31 02:28:50 +08:00
|
|
|
int b0 = this->readByte();
|
|
|
|
int b1 = this->readByte();
|
|
|
|
|
|
|
|
int numBytes = b0 << 8 | b1;
|
|
|
|
|
2012-06-05 08:45:25 +08:00
|
|
|
const char * src = (const char *) (this->mBytes + this->mCurrentByte);
|
2012-06-06 08:15:28 +08:00
|
|
|
std::string string(src, numBytes);
|
2012-05-31 02:28:50 +08:00
|
|
|
|
|
|
|
this->mCurrentByte += numBytes;
|
|
|
|
|
2012-06-06 08:15:28 +08:00
|
|
|
this->mStringCache.push_back(string);
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char CCBReader::readByte() {
|
|
|
|
unsigned char byte = this->mBytes[this->mCurrentByte];
|
|
|
|
this->mCurrentByte++;
|
|
|
|
return byte;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCBReader::readBool() {
|
|
|
|
return this->readByte();
|
|
|
|
}
|
|
|
|
|
|
|
|
int CCBReader::readInt(bool pSign) {
|
|
|
|
int numBits = 0;
|
|
|
|
while(!this->getBit()) {
|
|
|
|
numBits++;
|
|
|
|
}
|
|
|
|
|
|
|
|
long long current = 0;
|
|
|
|
for(int a = numBits - 1; a >= 0; a--) {
|
|
|
|
if(this->getBit()) {
|
|
|
|
current |= 1 << a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
current |= 1 << numBits;
|
|
|
|
|
|
|
|
int num;
|
|
|
|
if(pSign) {
|
|
|
|
int s = current % 2;
|
|
|
|
if(s) {
|
|
|
|
num = (int)(current / 2);
|
|
|
|
} else {
|
|
|
|
num = (int)(-current / 2);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
num = current - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->alignBits();
|
|
|
|
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float CCBReader::readFloat() {
|
|
|
|
unsigned char type = this->readByte();
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case kCCBFloat0:
|
|
|
|
return 0;
|
|
|
|
case kCCBFloat1:
|
|
|
|
return 1;
|
|
|
|
case kCCBFloatMinus1:
|
|
|
|
return -1;
|
|
|
|
case kCCBFloat05:
|
|
|
|
return 0.5f;
|
|
|
|
case kCCBFloatInteger:
|
|
|
|
return this->readInt(true);
|
|
|
|
default:
|
|
|
|
/* using a memcpy since the compiler isn't
|
|
|
|
* doing the float ptr math correctly on device.
|
|
|
|
* TODO still applies in C++ ? */
|
|
|
|
float * pF = (float*)(this->mBytes + this->mCurrentByte);
|
|
|
|
float f = 0;
|
|
|
|
memcpy(&f, pF, sizeof(float));
|
|
|
|
this->mCurrentByte += 4;
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CCBReader::getBit() {
|
|
|
|
bool bit;
|
|
|
|
unsigned char byte = *(this->mBytes + this->mCurrentByte);
|
|
|
|
if(byte & (1 << this->mCurrentBit)) {
|
|
|
|
bit = true;
|
|
|
|
} else {
|
|
|
|
bit = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->mCurrentBit++;
|
|
|
|
|
|
|
|
if(this->mCurrentBit >= 8) {
|
|
|
|
this->mCurrentBit = 0;
|
|
|
|
this->mCurrentByte++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCBReader::alignBits() {
|
|
|
|
if(this->mCurrentBit) {
|
|
|
|
this->mCurrentBit = 0;
|
|
|
|
this->mCurrentByte++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-12 09:31:11 +08:00
|
|
|
std::string CCBReader::readCachedString() {
|
2012-05-31 02:28:50 +08:00
|
|
|
int i = this->readInt(false);
|
2012-06-12 09:31:11 +08:00
|
|
|
return this->mStringCache[i];
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CCNode * CCBReader::readNodeGraph(CCNode * pParent) {
|
2012-06-05 06:52:49 +08:00
|
|
|
/* Read class name. */
|
2012-06-12 09:31:11 +08:00
|
|
|
const char * className = this->readCachedString().c_str();
|
2012-05-31 02:28:50 +08:00
|
|
|
|
|
|
|
int memberVarAssignmentType = this->readInt(false);
|
2012-06-05 08:45:25 +08:00
|
|
|
const char * memberVarAssignmentName;
|
2012-06-05 06:52:49 +08:00
|
|
|
if(memberVarAssignmentType != kCCBTargetTypeNone) {
|
2012-06-12 09:31:11 +08:00
|
|
|
memberVarAssignmentName = this->readCachedString().c_str();
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
2012-06-05 06:52:49 +08:00
|
|
|
|
2012-06-06 08:15:28 +08:00
|
|
|
CCNodeLoader * ccNodeLoader = this->mCCNodeLoaderLibrary->getCCNodeLoader(className);
|
2012-05-31 02:28:50 +08:00
|
|
|
CCNode * node = ccNodeLoader->loadCCNode(pParent, this);
|
2012-06-05 06:52:49 +08:00
|
|
|
|
|
|
|
/* Set root node, if not set yet. */
|
|
|
|
if(this->mRootNode == NULL) {
|
2012-06-06 08:15:28 +08:00
|
|
|
this->mRootNode = node;
|
|
|
|
this->mRootNode->retain();
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
2012-06-05 06:52:49 +08:00
|
|
|
if(memberVarAssignmentType != kCCBTargetTypeNone) {
|
|
|
|
CCObject * target = NULL;
|
|
|
|
if(memberVarAssignmentType == kCCBTargetTypeDocumentRoot) {
|
2012-06-06 08:15:28 +08:00
|
|
|
target = this->mRootNode;
|
|
|
|
} else if(memberVarAssignmentType == kCCBTargetTypeOwner) {
|
|
|
|
target = this->mOwner;
|
2012-06-05 06:52:49 +08:00
|
|
|
}
|
|
|
|
|
2012-06-06 08:15:28 +08:00
|
|
|
if(target != NULL) {
|
2012-06-14 05:19:13 +08:00
|
|
|
bool assigned = false;
|
|
|
|
|
|
|
|
CCBMemberVariableAssigner * targetAsCCBMemberVariableAssigner = dynamic_cast<CCBMemberVariableAssigner *>(target);
|
|
|
|
|
|
|
|
if(targetAsCCBMemberVariableAssigner != NULL) {
|
|
|
|
assigned = targetAsCCBMemberVariableAssigner->onAssignCCBMemberVariable(target, memberVarAssignmentName, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!assigned && this->mCCBMemberVariableAssigner != NULL) {
|
2012-06-05 06:52:49 +08:00
|
|
|
this->mCCBMemberVariableAssigner->onAssignCCBMemberVariable(target, memberVarAssignmentName, node);
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-06-05 06:52:49 +08:00
|
|
|
|
|
|
|
/* Read and add children. */
|
2012-05-31 02:28:50 +08:00
|
|
|
int numChildren = this->readInt(false);
|
|
|
|
for(int i = 0; i < numChildren; i++) {
|
|
|
|
CCNode * child = this->readNodeGraph(node);
|
|
|
|
node->addChild(child);
|
|
|
|
}
|
2012-06-06 08:15:28 +08:00
|
|
|
|
2012-06-14 05:19:13 +08:00
|
|
|
CCNodeLoaderListener * nodeAsCCNodeLoaderListener = dynamic_cast<CCNodeLoaderListener *>(node);
|
|
|
|
if(nodeAsCCNodeLoaderListener != NULL) {
|
|
|
|
nodeAsCCNodeLoaderListener->onNodeLoaded(node, ccNodeLoader);
|
|
|
|
} else if(this->mCCNodeLoaderListener != NULL) {
|
2012-06-13 02:59:49 +08:00
|
|
|
this->mCCNodeLoaderListener->onNodeLoaded(node, ccNodeLoader);
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
CCNode * CCBReader::readNodeGraph() {
|
|
|
|
return this->readNodeGraph(NULL);
|
|
|
|
}
|
|
|
|
|
2012-06-05 06:52:49 +08:00
|
|
|
CCObject * CCBReader::getOwner() {
|
2012-05-31 02:28:50 +08:00
|
|
|
return this->mOwner;
|
|
|
|
}
|
|
|
|
|
2012-06-05 06:52:49 +08:00
|
|
|
CCNode * CCBReader::getRootNode() {
|
|
|
|
return this->mRootNode;
|
|
|
|
}
|
|
|
|
|
2012-05-31 02:28:50 +08:00
|
|
|
CCSize CCBReader::getContainerSize(CCNode * pNode) {
|
|
|
|
if(pNode) {
|
|
|
|
return pNode->getContentSize();
|
|
|
|
} else {
|
|
|
|
return this->mRootContainerSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-05 08:45:25 +08:00
|
|
|
bool CCBReader::isSpriteSheetLoaded(const char * pSpriteSheet) {
|
|
|
|
return this->mLoadedSpriteSheets.find(pSpriteSheet) != this->mLoadedSpriteSheets.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCBReader::addLoadedSpriteSheet(const char * pSpriteSheet) {
|
|
|
|
this->mLoadedSpriteSheets.insert(pSpriteSheet);
|
|
|
|
}
|
|
|
|
|
2012-06-12 09:31:11 +08:00
|
|
|
std::string CCBReader::lastPathComponent(const char * pPath) {
|
2012-06-05 08:45:25 +08:00
|
|
|
std::string path(pPath);
|
|
|
|
int slashPos = path.find_last_of("/");
|
2012-06-06 08:15:28 +08:00
|
|
|
if(slashPos != std::string::npos) {
|
2012-06-12 09:31:11 +08:00
|
|
|
return path.substr(slashPos + 1, path.length() - slashPos);
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
2012-06-12 09:31:11 +08:00
|
|
|
return path;
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
2012-06-12 09:31:11 +08:00
|
|
|
std::string CCBReader::deletePathExtension(const char * pPath) {
|
2012-06-05 08:45:25 +08:00
|
|
|
std::string path(pPath);
|
|
|
|
int dotPos = path.find_last_of(".");
|
2012-06-06 08:15:28 +08:00
|
|
|
if(dotPos != std::string::npos) {
|
2012-06-12 09:31:11 +08:00
|
|
|
return path.substr(0, dotPos);
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
2012-06-12 09:31:11 +08:00
|
|
|
return path;
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
2012-06-12 09:31:11 +08:00
|
|
|
std::string CCBReader::toLowerCase(const char * pString) {
|
2012-05-31 02:28:50 +08:00
|
|
|
std::string copy(pString);
|
|
|
|
std::transform(copy.begin(), copy.end(), copy.begin(), ::tolower);
|
2012-06-12 09:31:11 +08:00
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string CCBReader::concat(const char * pStringA, const char * pStringB) {
|
|
|
|
std::string stringA(pStringA);
|
|
|
|
std::string stringB(pStringB);
|
|
|
|
|
|
|
|
std::string string = stringA + stringB;
|
|
|
|
return string;
|
2012-05-31 02:28:50 +08:00
|
|
|
}
|
|
|
|
|
2012-06-05 08:45:25 +08:00
|
|
|
bool CCBReader::endsWith(const char * pString, const char * pEnding) {
|
|
|
|
std::string string(pString);
|
|
|
|
std::string ending(pEnding);
|
2012-06-06 08:15:28 +08:00
|
|
|
if(string.length() >= ending.length()) {
|
2012-06-05 08:45:25 +08:00
|
|
|
return (string.compare(string.length() - ending.length(), ending.length(), ending) == 0);
|
2012-05-31 02:28:50 +08:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|