void CDocument::LoadFromURL( const std::string& inURL, std::function<void(CDocument*)> inCompletionBlock ) { if( mLoaded ) { inCompletionBlock( this ); return; } mLoadCompletionBlocks.push_back( inCompletionBlock ); if( mLoading ) // We'll call you, too, once we have finished loading. return; mLoading = true; size_t slashOffset = inURL.rfind( '/' ); if( slashOffset == std::string::npos ) slashOffset = 0; mURL = inURL.substr(0,slashOffset); mMediaCache.SetURL( mURL ); slashOffset = mURL.rfind( '/' ); if( slashOffset == std::string::npos ) slashOffset = 0; mName = mURL.substr(slashOffset+1,std::string::npos); slashOffset = mName.rfind( '.' ); if( slashOffset == std::string::npos ) slashOffset = 0; mName = mName.substr(0,slashOffset); CURLRequest request( inURL ); CURLConnection::SendRequestWithCompletionHandler( request, [inURL,this](CURLResponse inResponse, const char* inData, size_t inDataLength) { if( inURL.find("file://") != 0 ) // Not a local file? SetWriteProtected(true); // Can't write changes to it to disk. CAutoreleasePool pool; tinyxml2::XMLDocument document; if( tinyxml2::XML_SUCCESS == document.Parse( inData, inDataLength ) ) { //document.Print(); tinyxml2::XMLElement * root = document.RootElement(); // Load read/written version numbers so we can conditionally react to them: mCreatedByVersion.clear(); CTinyXMLUtils::GetStringNamed( root, "createdByVersion", mCreatedByVersion ); mLastCompactedVersion.clear(); CTinyXMLUtils::GetStringNamed( root, "lastCompactedVersion", mLastCompactedVersion ); mFirstEditedVersion.clear(); CTinyXMLUtils::GetStringNamed( root, "firstEditedVersion", mFirstEditedVersion ); mLastEditedVersion.clear(); CTinyXMLUtils::GetStringNamed( root, "lastEditedVersion", mLastEditedVersion ); mUserLevel = CTinyXMLUtils::GetIntNamed( root, "userLevel", 5 ); mPrivateAccess = CTinyXMLUtils::GetBoolNamed( root, "privateAccess", false ); mCantPeek = CTinyXMLUtils::GetBoolNamed( root, "cantPeek", false ); mMediaCache.LoadStandardResources(); // Load media table of this document so others can access it: (ICONs, PICTs, CURSs and SNDs) // Load style table so others can access it: mMediaCache.LoadMediaTableFromElementAsBuiltIn( root, false ); // Load media from this stack. LoadUserPropertiesFromElement( root ); mScript.clear(); CTinyXMLUtils::GetStringNamed( root, "script", mScript ); // Load stacks: tinyxml2::XMLElement * currStackElem = root->FirstChildElement( "stack" ); while( currStackElem ) { std::string fileName( currStackElem->Attribute("file") ); std::string stackURL = mURL; if( stackURL[stackURL.length()-1] != '/' ) stackURL.append( 1, '/' ); stackURL.append( fileName ); ObjectID stackID = CTinyXMLUtils::GetLongLongAttributeNamed( currStackElem, "id" ); const char* theName = currStackElem->Attribute("name"); const char* theThumbnail = currStackElem->Attribute("thumbnail"); CStack * theStack = NewStackWithURLIDNameForDocument( stackURL, stackID, (theName ? theName : ""), fileName, this ); theStack->Autorelease(); mStacks.push_back( theStack ); if( theThumbnail ) theStack->SetThumbnailName( theThumbnail ); currStackElem = currStackElem->NextSiblingElement( "stack" ); } // Load menus: tinyxml2::XMLElement * currMenuElem = root->FirstChildElement( "menu" ); while( currMenuElem ) { NewMenuWithElement( currMenuElem, EMenuDontMarkChanged ); currMenuElem = currMenuElem->NextSiblingElement( "menu" ); } } mChangeCount = 0; CallAllCompletionBlocks(); } ); }