bool CCurlFile::Download(const CStdString& strURL, const CStdString& strFileName, LPDWORD pdwSize) { CLog::Log(LOGINFO, "Download: %s->%s", strURL.c_str(), strFileName.c_str()); CStdString strData; if (!Get(strURL, strData)) return false; XFILE::CFile file; if (!file.OpenForWrite(strFileName, true)) { CLog::Log(LOGERROR, "Unable to open file %s: %u", strFileName.c_str(), GetLastError()); return false; } if (strData.size()) file.Write(strData.c_str(), strData.size()); file.Close(); if (pdwSize != NULL) { *pdwSize = strData.size(); } return true; }
void CKaraokeLyricsText::saveLyrics() { XFILE::CFile file; CStdString out; for ( unsigned int i = 0; i < m_lyrics.size(); i++ ) { CStdString timing; timing.Format( "%02d:%02d.%d", m_lyrics[i].timing / 600, (m_lyrics[i].timing % 600) / 10, (m_lyrics[i].timing % 10) ); if ( (m_lyrics[i].flags & LYRICS_NEW_PARAGRAPH) != 0 ) out += "\n\n"; if ( (m_lyrics[i].flags & LYRICS_NEW_LINE) != 0 ) out += "\n"; out += "[" + timing + "]" + m_lyrics[i].text; } out += "\n"; if ( !file.OpenForWrite( "special://temp/tmp.lrc", true ) ) return; file.Write( out, out.size() ); }
bool COMXImage::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height, unsigned int format, unsigned int pitch, const CStdString& destFile) { if(format != XB_FMT_A8R8G8B8 || !buffer) { CLog::Log(LOGDEBUG, "%s::%s : %s failed format=0x%x\n", CLASSNAME, __func__, destFile.c_str(), format); return false; } if(!Encode(buffer, height * pitch, width, height, pitch)) { CLog::Log(LOGDEBUG, "%s::%s : %s encode failed\n", CLASSNAME, __func__, destFile.c_str()); return false; } XFILE::CFile file; if (file.OpenForWrite(destFile, true)) { CLog::Log(LOGDEBUG, "%s::%s : %s width %d height %d\n", CLASSNAME, __func__, destFile.c_str(), width, height); file.Write(GetEncodedData(), GetEncodedSize()); file.Close(); return true; } return false; }
void CAirTunesServer::SetCoverArtFromBuffer(const char *buffer, unsigned int size) { XFILE::CFile tmpFile; const char *tmpFileName = "special://temp/airtunes_album_thumb.jpg"; if(!size) return; if (tmpFile.OpenForWrite(tmpFileName, true)) { int writtenBytes=0; writtenBytes = tmpFile.Write(buffer, size); tmpFile.Close(); if(writtenBytes) { //reset to empty before setting the new one //else it won't get refreshed because the name didn't change g_infoManager.SetCurrentAlbumThumb(""); g_infoManager.SetCurrentAlbumThumb(tmpFileName); //update the ui CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_REFRESH_THUMBS); g_windowManager.SendThreadMessage(msg); } } }
TEST(TestFile, Write) { XFILE::CFile *file; const char str[] = "TestFile.Write test string\n"; char buf[30]; memset(&buf, 0, sizeof(buf)); ASSERT_TRUE((file = XBMC_CREATETEMPFILE("")) != NULL); file->Close(); ASSERT_TRUE(file->OpenForWrite(XBMC_TEMPFILEPATH(file), true)); EXPECT_EQ((int)sizeof(str), file->Write(str, sizeof(str))); file->Flush(); EXPECT_EQ(0, file->GetPosition()); file->Close(); ASSERT_TRUE(file->Open(XBMC_TEMPFILEPATH(file))); EXPECT_EQ(0, file->GetPosition()); EXPECT_EQ((int64_t)sizeof(str), file->Seek(0, SEEK_END)); EXPECT_EQ(0, file->Seek(0, SEEK_SET)); EXPECT_EQ((int64_t)sizeof(str), file->GetLength()); EXPECT_EQ(sizeof(str), file->Read(buf, sizeof(buf))); file->Flush(); EXPECT_EQ((int64_t)sizeof(str), file->GetPosition()); EXPECT_TRUE(!memcmp(str, buf, sizeof(str))); file->Close(); EXPECT_TRUE(XBMC_DELETETEMPFILE(file)); }
bool CPicture::CreateThumbnailFromSurface(const unsigned char *buffer, int width, int height, int stride, const std::string &thumbFile) { CLog::Log(LOGDEBUG, "cached image '%s' size %dx%d", CURL::GetRedacted(thumbFile).c_str(), width, height); if (URIUtils::HasExtension(thumbFile, ".jpg")) { #if defined(HAS_OMXPLAYER) if (COMXImage::CreateThumbnailFromSurface((BYTE *)buffer, width, height, XB_FMT_A8R8G8B8, stride, thumbFile.c_str())) return true; #endif } unsigned char *thumb = NULL; unsigned int thumbsize=0; IImage* pImage = ImageFactory::CreateLoader(thumbFile); if(pImage == NULL || !pImage->CreateThumbnailFromSurface((BYTE *)buffer, width, height, XB_FMT_A8R8G8B8, stride, thumbFile.c_str(), thumb, thumbsize)) { CLog::Log(LOGERROR, "Failed to CreateThumbnailFromSurface for %s", CURL::GetRedacted(thumbFile).c_str()); delete pImage; return false; } XFILE::CFile file; const bool ret = file.OpenForWrite(thumbFile, true) && file.Write(thumb, thumbsize) == thumbsize; pImage->ReleaseThumbnailBuffer(); delete pImage; return ret; }
bool CScraperUrl::Get(const SUrlEntry& scrURL, string& strHTML, CHTTP& http) { CURL url(scrURL.m_url); http.SetReferer(scrURL.m_spoof); CStdString strCachePath; if (!scrURL.m_cache.IsEmpty()) { CUtil::AddFileToFolder(g_advancedSettings.m_cachePath,"scrapers\\"+scrURL.m_cache,strCachePath); if (XFILE::CFile::Exists(strCachePath)) { XFILE::CFile file; file.Open(strCachePath); char* temp = new char[(int)file.GetLength()]; file.Read(temp,file.GetLength()); strHTML.append(temp,temp+file.GetLength()); file.Close(); delete[] temp; return true; } } if (scrURL.m_post) { CStdString strOptions = url.GetOptions(); strOptions = strOptions.substr(1); url.SetOptions(""); CStdString strUrl; url.GetURL(strUrl); if (!http.Post(strUrl, strOptions, strHTML)) return false; } else if (!http.Get(scrURL.m_url, strHTML)) return false; if (scrURL.m_url.Find(".zip") > -1) { XFILE::CFileZip file; CStdString strBuffer; int iSize = file.UnpackFromMemory(strBuffer,strHTML); if (iSize) { strHTML.clear(); strHTML.append(strBuffer.c_str(),strBuffer.data()+iSize); } } if (!scrURL.m_cache.IsEmpty()) { CStdString strCachePath; CUtil::AddFileToFolder(g_advancedSettings.m_cachePath,"scrapers\\"+scrURL.m_cache,strCachePath); XFILE::CFile file; if (file.OpenForWrite(strCachePath,true,true)) file.Write(strHTML.data(),strHTML.size()); file.Close(); } return true; }
bool CXBMCTinyXML::SaveFile(const std::string& filename) const { XFILE::CFile file; if (file.OpenForWrite(filename, true)) { TiXmlPrinter printer; Accept(&printer); return file.Write(printer.CStr(), printer.Size()) == static_cast<ssize_t>(printer.Size()); } return false; }
bool COMXImage::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height, unsigned int format, unsigned int pitch, const CStdString& destFile) { if(format != XB_FMT_A8R8G8B8 || !buffer) return false; // the omx encoder needs alligned sizes if(width%16 || height%16) { unsigned int new_width = (width + 15)&~15; unsigned int new_height = (height + 15)&~15; unsigned int new_pitch = new_width * 4; unsigned int size = new_height * new_pitch; unsigned char *dstBuffer = (unsigned char *)malloc(size); unsigned char *dst = dstBuffer; unsigned char *src = buffer; if(!dstBuffer) return false; memset(dst, 0x0, size); for(unsigned int y = 0; y < height; y++) { memcpy(dst, src, pitch); src += pitch; dst += new_pitch; } if(!Encode(dstBuffer, size, new_width, new_height)) { free(dstBuffer); return false; } free(dstBuffer); } else { if(!Encode(buffer, height * pitch, width, height)) return false; } XFILE::CFile file; if (file.OpenForWrite(destFile, true)) { CLog::Log(LOGDEBUG, "%s::%s : %s width %d height %d\n", CLASSNAME, __func__, destFile.c_str(), width, height); file.Write(GetEncodedData(), GetEncodedSize()); file.Close(); return true; } return false; }
bool CXBMCTinyXML::SaveFile(const CStdString &filename) const { XFILE::CFile file; if (file.OpenForWrite(filename, true)) { TiXmlPrinter printer; Accept(&printer); file.Write(printer.CStr(), printer.Size()); return true; } return false; }
//------------------------------------------------------------------------------------------------------------------- bool Xcddb::writeCacheFile( const char* pBuffer, uint32_t discid ) { if (cCacheDir.size() == 0) return false; XFILE::CFile file; if (file.OpenForWrite(GetCacheFile(discid), true)) { const bool ret = ( (size_t) file.Write((void*)pBuffer, strlen(pBuffer) + 1) == strlen(pBuffer) + 1); file.Close(); return ret; } return false; }
//------------------------------------------------------------------------------------------------------------------- bool Xcddb::writeCacheFile( const char* pBuffer, uint32_t discid ) { if (cCacheDir.size() == 0) return false; XFILE::CFile file; if (file.OpenForWrite(GetCacheFile(discid), true)) { OutputDebugString ( "Current cd saved to local cddb.\n" ); file.Write( (void*) pBuffer, strlen( pBuffer ) + 1 ); file.Close(); return true; } return false; }
bool fileOps::writeToFile ( CStdString filePath, char* writeBuffer, int writeLength ) { XFILE::CFile file; if (file.OpenForWrite(filePath)) { file.Write((const void*)writeBuffer,writeLength); file.Close(); return true; } else { return false; } }
bool COpenSubtitlesSearch::Download(const CFileItem *subItem,std::vector<std::string> &items) { ulxr::MethodCall methodcall(ULXR_PCHAR("DownloadSubtitles")); ulxr::Array subtitleIDlist; ulxr::RpcString ID = subItem->GetProperty("IDSubtitleFile").asString(); subtitleIDlist.addItem(ID); ulxr::RpcString token = m_strToken; methodcall.addParam(token); methodcall.addParam(subtitleIDlist); ulxr::MethodResponse response = ServerChat(methodcall); ulxr::Struct cap = response.getResult(); if (response.isOK() && cap.hasMember(ULXR_PCHAR("status"))) { ulxr::RpcString status = cap.getMember(ULXR_PCHAR("status")); CLog::Log(LOGDEBUG, "%s - response - %s", __PRETTY_FUNCTION__, status.getString().c_str()); if (status.getString() == "200 OK") { if (cap.hasMember(ULXR_PCHAR("data"))) { ulxr::Array subs = cap.getMember(ULXR_PCHAR("data")); for (unsigned i = 0; i < subs.size(); ++i) { ulxr::Struct entry = subs.getItem(i); ulxr::RpcString data = entry.getMember(ULXR_PCHAR("data")); std::string zipdata = data.getString(); std::string zipdata64Decoded = Base64::Decode(zipdata); std::string zipdata64DecodedInflated; CSubtitleUtilities::gzipInflate(zipdata64Decoded,zipdata64DecodedInflated); XFILE::CFile file; std::string destination = StringUtils::Format("special://temp/%s.%s", StringUtils::CreateUUID().c_str(), subItem->GetProperty("SubFormat").asString().c_str() ); file.OpenForWrite(destination); file.Write(zipdata64DecodedInflated.c_str(), zipdata64DecodedInflated.size()); items.push_back(destination); } CLog::Log(LOGDEBUG, "%s - OpenSubitles subfile downloaded", __PRETTY_FUNCTION__); return true; } } } return false; }
void CAirTunesServer::SetCoverArtFromBuffer(const char *buffer, unsigned int size) { XFILE::CFile tmpFile; if(!size) return; CSingleLock lock(m_metadataLock); if (tmpFile.OpenForWrite(TMP_COVERART_PATH, true)) { int writtenBytes=0; writtenBytes = tmpFile.Write(buffer, size); tmpFile.Close(); if (writtenBytes > 0) RefreshCoverArt(); } }
void CGameClientInGameSaves::Save(GAME_MEMORY memoryType) { uint8_t *gameMemory = nullptr; size_t size = 0; try { m_dllStruct->GetMemory(memoryType, &gameMemory, &size); } catch (...) { CLog::Log(LOGERROR, "GAME: %s: Exception caught in GetMemory()", m_gameClient->ID().c_str()); } if (size > 0) { const std::string path = GetPath(memoryType); XFILE::CFile file; if (file.OpenForWrite(path, true)) { ssize_t written = 0; written = file.Write(gameMemory, size); file.Close(); if (written == static_cast<ssize_t>(size)) { CLog::Log(LOGINFO, "GAME: In-game saves (%s) written to %s", CGameClientTranslator::ToString(memoryType), path.c_str()); } else { CLog::Log(LOGERROR, "GAME: Failed to write in-game saves (%s): %ld/%ld bytes written", CGameClientTranslator::ToString(memoryType), written, size); } } else { CLog::Log(LOGERROR, "GAME: Unable to open in-game saves (%s) from file %s", CGameClientTranslator::ToString(memoryType), path.c_str()); } } else { CLog::Log(LOGDEBUG, "GAME: No in-game saves (%s) to save", CGameClientTranslator::ToString(memoryType)); } }
void SxThumb::thumbLoaded(sp_image *image) { if (m_dll-> sp_image_error(image) != SP_ERROR_OK) { Logger::printOut("creating image error"); m_file = ""; //well its loaded but without image m_isLoaded = true; return; } XFILE::CFile file; if (file.OpenForWrite(m_file, true)) { const void *buffer; size_t len; buffer = m_dll->sp_image_data(image, &len); file.Write((const char*) buffer, len); file.Close(); } m_isLoaded = true; //Logger::printOut("thumb downloaded"); }
bool CPicture::CreateThumbnailFromSurface(const unsigned char *buffer, int width, int height, int stride, const CStdString &thumbFile) { CLog::Log(LOGDEBUG, "cached image '%s' size %dx%d", thumbFile.c_str(), width, height); if (URIUtils::GetExtension(thumbFile).Equals(".jpg")) { #if defined(HAS_OMXPLAYER) COMXImage *omxImage = new COMXImage(); if (omxImage && omxImage->CreateThumbnailFromSurface((BYTE *)buffer, width, height, XB_FMT_A8R8G8B8, stride, thumbFile.c_str())) { delete omxImage; return true; } delete omxImage; #endif } unsigned char *thumb = NULL; unsigned int thumbsize=0; IImage* pImage = ImageFactory::CreateLoader(thumbFile); if(pImage == NULL || !pImage->CreateThumbnailFromSurface((BYTE *)buffer, width, height, XB_FMT_A8R8G8B8, stride, thumbFile.c_str(), thumb, thumbsize)) { CLog::Log(LOGERROR, "Failed to CreateThumbnailFromSurface for %s", thumbFile.c_str()); delete pImage; return false; } XFILE::CFile file; if (file.OpenForWrite(thumbFile, true)) { file.Write(thumb, thumbsize); file.Close(); pImage->ReleaseThumbnailBuffer(); delete pImage; return true; } pImage->ReleaseThumbnailBuffer(); delete pImage; return false; }
void CAirTunesServer::SetCoverArtFromBuffer(const char *buffer, unsigned int size) { XFILE::CFile tmpFile; std::string tmpFilename = TMP_COVERART_PATH_PNG; if(!size) return; CSingleLock lock(m_metadataLock); if (IsJPEG(buffer, size)) tmpFilename = TMP_COVERART_PATH_JPG; if (tmpFile.OpenForWrite(tmpFilename, true)) { int writtenBytes=0; writtenBytes = tmpFile.Write(buffer, size); tmpFile.Close(); if (writtenBytes > 0) RefreshCoverArt(tmpFilename.c_str()); } }
bool CScraperUrl::Get(const SUrlEntry& scrURL, std::string& strHTML, XFILE::CCurlFile& http, const CStdString& cacheContext) { CURL url(scrURL.m_url); http.SetReferer(scrURL.m_spoof); CStdString strCachePath; if (scrURL.m_isgz) http.SetContentEncoding("gzip"); if (!scrURL.m_cache.empty()) { strCachePath = URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath, "scrapers/" + cacheContext + "/" + scrURL.m_cache); if (XFILE::CFile::Exists(strCachePath)) { XFILE::CFile file; XFILE::auto_buffer buffer; if (file.LoadFile(strCachePath, buffer)) { strHTML.assign(buffer.get(), buffer.length()); return true; } } } CStdString strHTML1(strHTML); if (scrURL.m_post) { CStdString strOptions = url.GetOptions(); strOptions = strOptions.substr(1); url.SetOptions(""); if (!http.Post(url.Get(), strOptions, strHTML1)) return false; } else if (!http.Get(url.Get(), strHTML1)) return false; strHTML = strHTML1; std::string mimeType(http.GetMimeType()); CMime::EFileType ftype = CMime::GetFileTypeFromMime(mimeType); if (ftype == CMime::FileTypeUnknown) ftype = CMime::GetFileTypeFromContent(strHTML); if (ftype == CMime::FileTypeZip || ftype == CMime::FileTypeGZip) { XFILE::CZipFile file; std::string strBuffer; int iSize = file.UnpackFromMemory(strBuffer,strHTML,scrURL.m_isgz); // FIXME: use FileTypeGZip instead of scrURL.m_isgz? if (iSize > 0) { strHTML = strBuffer; CLog::Log(LOGDEBUG, "%s: Archive \"%s\" was unpacked in memory", __FUNCTION__, scrURL.m_url.c_str()); } else CLog::Log(LOGWARNING, "%s: \"%s\" looks like archive, but cannot be unpacked", __FUNCTION__, scrURL.m_url.c_str()); } std::string reportedCharset(http.GetServerReportedCharset()); if (ftype == CMime::FileTypeHtml) { std::string realHtmlCharset, converted; if (!CCharsetDetection::ConvertHtmlToUtf8(strHTML, converted, reportedCharset, realHtmlCharset)) CLog::Log(LOGWARNING, "%s: Can't find precise charset for HTML \"%s\", using \"%s\" as fallback", __FUNCTION__, scrURL.m_url.c_str(), realHtmlCharset.c_str()); else CLog::Log(LOGDEBUG, "%s: Using \"%s\" charset for HTML \"%s\"", __FUNCTION__, realHtmlCharset.c_str(), scrURL.m_url.c_str()); strHTML = converted; } else if (ftype == CMime::FileTypeXml) { CXBMCTinyXML xmlDoc; xmlDoc.Parse(strHTML, reportedCharset); std::string realXmlCharset(xmlDoc.GetUsedCharset()); if (!realXmlCharset.empty()) { CLog::Log(LOGDEBUG, "%s: Using \"%s\" charset for XML \"%s\"", __FUNCTION__, realXmlCharset.c_str(), scrURL.m_url.c_str()); std::string converted; g_charsetConverter.ToUtf8(realXmlCharset, strHTML, converted); strHTML = converted; } } else if (ftype == CMime::FileTypePlainText || StringUtils::CompareNoCase(mimeType.substr(0, 5), "text/") == 0) { std::string realTextCharset, converted; CCharsetDetection::ConvertPlainTextToUtf8(strHTML, converted, reportedCharset, realTextCharset); strHTML = converted; if (reportedCharset != realTextCharset) CLog::Log(LOGWARNING, "%s: Using \"%s\" charset for plain text \"%s\" instead of server reported \"%s\" charset", __FUNCTION__, realTextCharset.c_str(), scrURL.m_url.c_str(), reportedCharset.c_str()); else CLog::Log(LOGDEBUG, "%s: Using \"%s\" charset for plain text \"%s\"", __FUNCTION__, realTextCharset.c_str(), scrURL.m_url.c_str()); } else if (!reportedCharset.empty()) { CLog::Log(LOGDEBUG, "%s: Using \"%s\" charset for \"%s\"", __FUNCTION__, reportedCharset.c_str(), scrURL.m_url.c_str()); if (reportedCharset != "UTF-8") { std::string converted; g_charsetConverter.ToUtf8(reportedCharset, strHTML, converted); strHTML = converted; } } else CLog::Log(LOGDEBUG, "%s: Using content of \"%s\" as binary or text with \"UTF-8\" charset", __FUNCTION__, scrURL.m_url.c_str()); if (!scrURL.m_cache.empty()) { CStdString strCachePath = URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath, "scrapers/" + cacheContext + "/" + scrURL.m_cache); XFILE::CFile file; if (file.OpenForWrite(strCachePath,true)) file.Write(strHTML.data(),strHTML.size()); file.Close(); } return true; }
bool CFileCurl::Service(const CStdString& strURL, const CStdString& strPostData, CStdString& strHTML, bool bCloseConnection) { XBMC::HttpCacheHandle cacheHandle = g_application.GetHttpCacheManager().Open(); XBMC::CHttpCacheHandleGuard guard(cacheHandle); m_postdata = strPostData; std::string strLocalCacheName; m_etag.clear(); m_httpTimeModified = 0; if (m_postdata.empty()) { XBMC::HttpCacheReturnCode rc = g_application.GetHttpCacheManager().StartCachingURL(cacheHandle, strURL.c_str(), strLocalCacheName, m_etag, m_httpTimeModified); if (rc == XBMC::HTTP_CACHE_ALREADY_IN_PROGRESS) { if ( g_application.GetHttpCacheManager().WaitForURL(cacheHandle, strURL.c_str(), strLocalCacheName, 5000) == XBMC::HTTP_CACHE_OK ) rc = XBMC::HTTP_CACHE_ALREADY_EXISTS; else rc = g_application.GetHttpCacheManager().StartCachingURL(cacheHandle, strURL.c_str(), strLocalCacheName, m_etag, m_httpTimeModified); } if (rc == XBMC::HTTP_CACHE_ALREADY_EXISTS) { if (ReadFile(strLocalCacheName, strHTML)) return true; strLocalCacheName.clear(); } else if (rc != XBMC::HTTP_CACHE_OK) { strLocalCacheName.clear(); cacheHandle = NULL; m_etag.clear(); m_httpTimeModified = 0; } } if (Open(strURL)) { if (ReadData(strHTML)) { long nLastCode=200; g_curlInterface.easy_getinfo(m_state->m_easyHandle, CURLINFO_RESPONSE_CODE, &nLastCode); if (bCloseConnection) Close(); if (nLastCode == 304) { ReadFile(strLocalCacheName, strHTML); strLocalCacheName.clear(); } if (!strLocalCacheName.empty() && strHTML.size() && cacheHandle) { XFILE::CFile file; if (file.OpenForWrite(strLocalCacheName, true)) { file.Write(strHTML.data(), strHTML.size()); file.Close(); XBMC::HttpCacheHeaders headers; const char **ptr = g_application.GetHttpCacheManager().GetUsedReponseHeaders(); while (ptr && *ptr) { std::string strHeader = m_state->m_httpheader.GetValue(*ptr).c_str(); if (!strHeader.empty()) headers[*ptr] = strHeader; ptr++; } g_application.GetHttpCacheManager().DoneCachingURL(cacheHandle, strURL.c_str(), nLastCode, headers); } } return true; } } Close(); return false; }
bool CScraperUrl::Get(const SUrlEntry& scrURL, std::string& strHTML, XFILE::CCurlFile& http, const CStdString& cacheContext) { CURL url(scrURL.m_url); http.SetReferer(scrURL.m_spoof); CStdString strCachePath; if (scrURL.m_isgz) http.SetContentEncoding("gzip"); if (!scrURL.m_cache.IsEmpty()) { strCachePath = URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath, "scrapers/" + cacheContext + "/" + scrURL.m_cache); if (XFILE::CFile::Exists(strCachePath)) { XFILE::CFile file; XFILE::auto_buffer buffer; if (file.LoadFile(strCachePath, buffer)) { strHTML.assign(buffer.get(), buffer.length()); return true; } } } CStdString strHTML1(strHTML); if (scrURL.m_post) { CStdString strOptions = url.GetOptions(); strOptions = strOptions.substr(1); url.SetOptions(""); if (!http.Post(url.Get(), strOptions, strHTML1)) return false; } else if (!http.Get(url.Get(), strHTML1)) return false; strHTML = strHTML1; std::string fileCharset(http.GetServerReportedCharset()); if (scrURL.m_url.Find(".zip") > -1 ) { XFILE::CZipFile file; CStdString strBuffer; int iSize = file.UnpackFromMemory(strBuffer,strHTML,scrURL.m_isgz); if (iSize) { fileCharset.clear(); strHTML.clear(); strHTML.append(strBuffer.c_str(),strBuffer.data()+iSize); } } if (!fileCharset.empty() && fileCharset != "UTF-8") { std::string converted; if (g_charsetConverter.ToUtf8(fileCharset, strHTML, converted) && !converted.empty()) strHTML = converted; } if (!scrURL.m_cache.IsEmpty()) { CStdString strCachePath = URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath, "scrapers/" + cacheContext + "/" + scrURL.m_cache); XFILE::CFile file; if (file.OpenForWrite(strCachePath,true)) file.Write(strHTML.data(),strHTML.size()); file.Close(); } return true; }
CStdString fileOps::GetFileFromBackend ( CStdString filenameToGet, CStdString fromStorageGroup ) { XBMC->Log(LOG_DEBUG,"%s - Getting File via Myth Protocol - %s", __FUNCTION__,filenameToGet.c_str()); if (filenameToGet.Left(1).compare("/") != 0) { filenameToGet = "/" + filenameToGet; } MythFile theFile; if (fromStorageGroup.CompareNoCase("channels")==0) { CStdString chanFilename = "/channels" + filenameToGet; CStdString chanSG = "c"; theFile=mythConP.ConnectPath((char*)chanFilename.c_str(),(char*)chanSG.c_str()); } else { theFile=mythConP.ConnectPath((char*)filenameToGet.c_str(),(char*)fromStorageGroup.c_str()); } if (theFile.IsNull()) { return ""; } int theFilesLength = theFile.Duration(); if (theFilesLength <= 0) { return ""; } CStdString writeFilePath = baseLocalCachepath + fromStorageGroup + filenameToGet; checkDirectory(writeFilePath,true); XFILE::CFile writeFile; if (writeFile.OpenForWrite(writeFilePath)) { //char* theFileBuff = new char[theFilesLength]; int totalRead = 0; while (totalRead < theFilesLength) { char* theFileTmpBuff = new char[theFilesLength]; int readData = theFile.Read(theFileTmpBuff,theFilesLength-totalRead); if (readData <= 0) { break; } writeFile.Write((const void*)theFileTmpBuff,readData); /*char *filePntr = theFileBuff; if (totalRead > 0) { filePntr += (totalRead); } if (readData > (theFilesLength-totalRead)) { readData = (theFilesLength-totalRead); } memcpy((void*)filePntr,(void*)theFileTmpBuff,readData); */ totalRead += readData; } writeFile.Close(); if (totalRead < theFilesLength) { XBMC->Log(LOG_DEBUG,"%s - Did not Read all data - %s - %d - %d", __FUNCTION__,filenameToGet.c_str(),totalRead,theFilesLength); } return writeFilePath; } else { return ""; } }
int CAirPlayServer::CTCPClient::ProcessRequest( std::string& responseHeader, std::string& responseBody) { std::string method = m_httpParser->getMethod() ? m_httpParser->getMethod() : ""; std::string uri = m_httpParser->getUri() ? m_httpParser->getUri() : ""; std::string queryString = m_httpParser->getQueryString() ? m_httpParser->getQueryString() : ""; std::string body = m_httpParser->getBody() ? m_httpParser->getBody() : ""; std::string contentType = m_httpParser->getValue("content-type") ? m_httpParser->getValue("content-type") : ""; m_sessionId = m_httpParser->getValue("x-apple-session-id") ? m_httpParser->getValue("x-apple-session-id") : ""; std::string authorization = m_httpParser->getValue("authorization") ? m_httpParser->getValue("authorization") : ""; std::string photoAction = m_httpParser->getValue("x-apple-assetaction") ? m_httpParser->getValue("x-apple-assetaction") : ""; std::string photoCacheId = m_httpParser->getValue("x-apple-assetkey") ? m_httpParser->getValue("x-apple-assetkey") : ""; int status = AIRPLAY_STATUS_OK; bool needAuth = false; if (m_sessionId.empty()) m_sessionId = "00000000-0000-0000-0000-000000000000"; if (ServerInstance->m_usePassword && !m_bAuthenticated) { needAuth = true; } size_t startQs = uri.find('?'); if (startQs != std::string::npos) { uri.erase(startQs); } // This is the socket which will be used for reverse HTTP // negotiate reverse HTTP via upgrade if (uri == "/reverse") { status = AIRPLAY_STATUS_SWITCHING_PROTOCOLS; responseHeader = "Upgrade: PTTH/1.0\r\nConnection: Upgrade\r\n"; } // The rate command is used to play/pause media. // A value argument should be supplied which indicates media should be played or paused. // 0.000000 => pause // 1.000000 => play else if (uri == "/rate") { const char* found = strstr(queryString.c_str(), "value="); int rate = found ? (int)(atof(found + strlen("value=")) + 0.5f) : 0; CLog::Log(LOGDEBUG, "AIRPLAY: got request %s with rate %i", uri.c_str(), rate); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (rate == 0) { if (g_application.GetAppPlayer().IsPlaying() && !g_application.GetAppPlayer().IsPaused()) { CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_PAUSE); } } else { if (g_application.GetAppPlayer().IsPausedPlayback()) { CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_PAUSE); } } } // The volume command is used to change playback volume. // A value argument should be supplied which indicates how loud we should get. // 0.000000 => silent // 1.000000 => loud else if (uri == "/volume") { const char* found = strstr(queryString.c_str(), "volume="); float volume = found ? (float)strtod(found + strlen("volume="), NULL) : 0; CLog::Log(LOGDEBUG, "AIRPLAY: got request %s with volume %f", uri.c_str(), volume); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (volume >= 0 && volume <= 1) { float oldVolume = g_application.GetVolume(); volume *= 100; if(oldVolume != volume && CServiceBroker::GetSettings().GetBool(CSettings::SETTING_SERVICES_AIRPLAYVOLUMECONTROL)) { backupVolume(); g_application.SetVolume(volume); CApplicationMessenger::GetInstance().PostMsg(TMSG_VOLUME_SHOW, oldVolume < volume ? ACTION_VOLUME_UP : ACTION_VOLUME_DOWN); } } } // Contains a header like format in the request body which should contain a // Content-Location and optionally a Start-Position else if (uri == "/play") { std::string location; float position = 0.0; bool startPlayback = true; m_lastEvent = EVENT_NONE; CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (contentType == "application/x-apple-binary-plist") { CAirPlayServer::m_isPlaying++; if (m_pLibPlist->Load()) { m_pLibPlist->EnableDelayedUnload(false); const char* bodyChr = m_httpParser->getBody(); plist_t dict = NULL; m_pLibPlist->plist_from_bin(bodyChr, m_httpParser->getContentLength(), &dict); if (m_pLibPlist->plist_dict_get_size(dict)) { plist_t tmpNode = m_pLibPlist->plist_dict_get_item(dict, "Start-Position"); if (tmpNode) { double tmpDouble = 0; m_pLibPlist->plist_get_real_val(tmpNode, &tmpDouble); position = (float)tmpDouble; } tmpNode = m_pLibPlist->plist_dict_get_item(dict, "Content-Location"); if (tmpNode) { location = getStringFromPlist(m_pLibPlist, tmpNode); tmpNode = NULL; } tmpNode = m_pLibPlist->plist_dict_get_item(dict, "rate"); if (tmpNode) { double rate = 0; m_pLibPlist->plist_get_real_val(tmpNode, &rate); if (rate == 0.0) { startPlayback = false; } tmpNode = NULL; } // in newer protocol versions the location is given // via host and path where host is ip:port and path is /path/file.mov if (location.empty()) tmpNode = m_pLibPlist->plist_dict_get_item(dict, "host"); if (tmpNode) { location = "http://"; location += getStringFromPlist(m_pLibPlist, tmpNode); tmpNode = m_pLibPlist->plist_dict_get_item(dict, "path"); if (tmpNode) { location += getStringFromPlist(m_pLibPlist, tmpNode); } } if (dict) { m_pLibPlist->plist_free(dict); } } else { CLog::Log(LOGERROR, "Error parsing plist"); } m_pLibPlist->Unload(); } } else { CAirPlayServer::m_isPlaying++; // Get URL to play std::string contentLocation = "Content-Location: "; size_t start = body.find(contentLocation); if (start == std::string::npos) return AIRPLAY_STATUS_NOT_IMPLEMENTED; start += contentLocation.size(); int end = body.find('\n', start); location = body.substr(start, end - start); std::string startPosition = "Start-Position: "; start = body.find(startPosition); if (start != std::string::npos) { start += startPosition.size(); int end = body.find('\n', start); std::string positionStr = body.substr(start, end - start); position = (float)atof(positionStr.c_str()); } } if (status != AIRPLAY_STATUS_NEED_AUTH) { std::string userAgent(CURL::Encode("AppleCoreMedia/1.0.0.8F455 (AppleTV; U; CPU OS 4_3 like Mac OS X; de_de)")); location += "|User-Agent=" + userAgent; CFileItem fileToPlay(location, false); fileToPlay.SetProperty("StartPercent", position*100.0f); ServerInstance->AnnounceToClients(EVENT_LOADING); CFileItemList *l = new CFileItemList; //don't delete, l->Add(std::make_shared<CFileItem>(fileToPlay)); CApplicationMessenger::GetInstance().PostMsg(TMSG_MEDIA_PLAY, -1, -1, static_cast<void*>(l)); // allow starting the player paused in ios8 mode (needed by camera roll app) if (!startPlayback) { CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_PAUSE); g_application.GetAppPlayer().SeekPercentage(position * 100.0f); } } } // Used to perform seeking (POST request) and to retrieve current player position (GET request). // GET scrub seems to also set rate 1 - strange but true else if (uri == "/scrub") { if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (method == "GET") { CLog::Log(LOGDEBUG, "AIRPLAY: got GET request %s", uri.c_str()); if (g_application.GetAppPlayer().GetTotalTime()) { float position = ((float) g_application.GetAppPlayer().GetTime()) / 1000; responseBody = StringUtils::Format("duration: %.6f\r\nposition: %.6f\r\n", (float)g_application.GetAppPlayer().GetTotalTime() / 1000, position); } else { status = AIRPLAY_STATUS_METHOD_NOT_ALLOWED; } } else { const char* found = strstr(queryString.c_str(), "position="); if (found && g_application.GetAppPlayer().HasPlayer()) { int64_t position = (int64_t) (atof(found + strlen("position=")) * 1000.0); g_application.GetAppPlayer().SeekTime(position); CLog::Log(LOGDEBUG, "AIRPLAY: got POST request %s with pos %" PRId64, uri.c_str(), position); } } } // Sent when media playback should be stopped else if (uri == "/stop") { CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else { if (IsPlaying()) //only stop player if we started him { CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_STOP); CAirPlayServer::m_isPlaying--; } else //if we are not playing and get the stop request - we just wanna stop picture streaming { CApplicationMessenger::GetInstance().SendMsg(TMSG_GUI_ACTION, WINDOW_SLIDESHOW, -1, static_cast<void*>(new CAction(ACTION_STOP))); } } ClearPhotoAssetCache(); } // RAW JPEG data is contained in the request body else if (uri == "/photo") { CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (m_httpParser->getContentLength() > 0 || photoAction == "displayCached") { XFILE::CFile tmpFile; std::string tmpFileName = "special://temp/airplayasset"; bool showPhoto = true; bool receivePhoto = true; if (photoAction == "cacheOnly") showPhoto = false; else if (photoAction == "displayCached") { receivePhoto = false; if (photoCacheId.length()) CLog::Log(LOGDEBUG, "AIRPLAY: Trying to show from cache asset: %s", photoCacheId.c_str()); } if (photoCacheId.length()) tmpFileName += photoCacheId; else tmpFileName += "airplay_photo"; if( receivePhoto && m_httpParser->getContentLength() > 3 && m_httpParser->getBody()[1] == 'P' && m_httpParser->getBody()[2] == 'N' && m_httpParser->getBody()[3] == 'G') { tmpFileName += ".png"; } else { tmpFileName += ".jpg"; } int writtenBytes=0; if (receivePhoto) { if (tmpFile.OpenForWrite(tmpFileName, true)) { writtenBytes = tmpFile.Write(m_httpParser->getBody(), m_httpParser->getContentLength()); tmpFile.Close(); } if (photoCacheId.length()) CLog::Log(LOGDEBUG, "AIRPLAY: Cached asset: %s", photoCacheId.c_str()); } if (showPhoto) { if ((writtenBytes > 0 && (unsigned int)writtenBytes == m_httpParser->getContentLength()) || !receivePhoto) { if (!receivePhoto && !XFILE::CFile::Exists(tmpFileName)) { status = AIRPLAY_STATUS_PRECONDITION_FAILED; //image not found in the cache if (photoCacheId.length()) CLog::Log(LOGWARNING, "AIRPLAY: Asset %s not found in our cache.", photoCacheId.c_str()); } else CApplicationMessenger::GetInstance().PostMsg(TMSG_PICTURE_SHOW, -1, -1, nullptr, tmpFileName); } else { CLog::Log(LOGERROR,"AirPlayServer: Error writing tmpFile."); } } } } else if (uri == "/playback-info") { float position = 0.0f; float duration = 0.0f; float cachePosition = 0.0f; bool playing = false; CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (g_application.GetAppPlayer().HasPlayer()) { if (g_application.GetAppPlayer().GetTotalTime()) { position = ((float) g_application.GetAppPlayer().GetTime()) / 1000; duration = ((float) g_application.GetAppPlayer().GetTotalTime()) / 1000; playing = !g_application.GetAppPlayer().IsPaused(); cachePosition = position + (duration * g_application.GetAppPlayer().GetCachePercentage() / 100.0f); } responseBody = StringUtils::Format(PLAYBACK_INFO, duration, cachePosition, position, (playing ? 1 : 0), duration); responseHeader = "Content-Type: text/x-apple-plist+xml\r\n"; if (g_application.GetAppPlayer().IsCaching()) { CAirPlayServer::ServerInstance->AnnounceToClients(EVENT_LOADING); } } else { responseBody = StringUtils::Format(PLAYBACK_INFO_NOT_READY); responseHeader = "Content-Type: text/x-apple-plist+xml\r\n"; } } else if (uri == "/server-info") { CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); responseBody = StringUtils::Format(SERVER_INFO, CServiceBroker::GetNetwork().GetFirstConnectedInterface()->GetMacAddress().c_str()); responseHeader = "Content-Type: text/x-apple-plist+xml\r\n"; } else if (uri == "/slideshow-features") { // Ignore for now. } else if (uri == "/authorize") { // DRM, ignore for now. } else if (uri == "/setProperty") { status = AIRPLAY_STATUS_NOT_FOUND; } else if (uri == "/getProperty") { status = AIRPLAY_STATUS_NOT_FOUND; } else if (uri == "/fp-setup") { status = AIRPLAY_STATUS_PRECONDITION_FAILED; } else if (uri == "200") //response OK from the event reverse message { status = AIRPLAY_STATUS_NO_RESPONSE_NEEDED; } else { CLog::Log(LOGERROR, "AIRPLAY Server: unhandled request [%s]\n", uri.c_str()); status = AIRPLAY_STATUS_NOT_IMPLEMENTED; } if (status == AIRPLAY_STATUS_NEED_AUTH) { ComposeAuthRequestAnswer(responseHeader, responseBody); } return status; }
bool CEventClient::OnPacketHELO(CEventPacket *packet) { // TODO: check it last HELO packet was received less than 5 minutes back // if so, do not show notification of connection. if (Greeted()) return false; unsigned char *payload = (unsigned char *)packet->Payload(); int psize = (int)packet->PayloadSize(); // parse device name if (!ParseString(payload, psize, m_deviceName)) return false; CLog::Log(LOGNOTICE, "ES: Incoming connection from %s", m_deviceName.c_str()); // icon type unsigned char ltype; if (!ParseByte(payload, psize, ltype)) return false; m_eLogoType = (LogoType)ltype; // client's port (if any) unsigned short dport; if (!ParseUInt16(payload, psize, dport)) return false; m_iRemotePort = (unsigned int)dport; // 2 x reserved uint32 (8 bytes) unsigned int reserved; ParseUInt32(payload, psize, reserved); ParseUInt32(payload, psize, reserved); // image data if any string iconfile = "special://temp/helo"; if (m_eLogoType != LT_NONE && psize>0) { switch (m_eLogoType) { case LT_JPEG: iconfile += ".jpg"; break; case LT_GIF: iconfile += ".gif"; break; default: iconfile += ".png"; break; } XFILE::CFile file; if (file.OpenForWrite(iconfile, true)) { file.Write((const void *)payload, psize); file.Close(); } else { CLog::Log(LOGERROR, "ES: Could not write icon file"); m_eLogoType = LT_NONE; } } m_bGreeted = true; if (m_eLogoType == LT_NONE) { CGUIDialogKaiToast::QueueNotification(g_localizeStrings.Get(33200), m_deviceName.c_str()); } else { CGUIDialogKaiToast::QueueNotification(iconfile.c_str(), g_localizeStrings.Get(33200), m_deviceName.c_str()); } return true; }
bool CScraperUrl::Get(const SUrlEntry& scrURL, std::string& strHTML, XFILE::CCurlFile& http, const CStdString& cacheContext) { CURL url(scrURL.m_url); http.SetReferer(scrURL.m_spoof); CStdString strCachePath; if (scrURL.m_isgz) http.SetContentEncoding("gzip"); if (!scrURL.m_cache.IsEmpty()) { URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath, "scrapers/"+cacheContext+"/"+scrURL.m_cache, strCachePath); if (XFILE::CFile::Exists(strCachePath)) { XFILE::CFile file; if (file.Open(strCachePath)) { char* temp = new char[(int)file.GetLength()]; file.Read(temp,file.GetLength()); strHTML.clear(); strHTML.append(temp,temp+file.GetLength()); file.Close(); delete[] temp; return true; } } } CStdString strHTML1(strHTML); if (scrURL.m_post) { CStdString strOptions = url.GetOptions(); strOptions = strOptions.substr(1); url.SetOptions(""); if (!http.Post(url.Get(), strOptions, strHTML1)) return false; } else if (!http.Get(url.Get(), strHTML1)) return false; strHTML = strHTML1; if (scrURL.m_url.Find(".zip") > -1 ) { XFILE::CZipFile file; CStdString strBuffer; int iSize = file.UnpackFromMemory(strBuffer,strHTML,scrURL.m_isgz); if (iSize) { strHTML.clear(); strHTML.append(strBuffer.c_str(),strBuffer.data()+iSize); } } if (!scrURL.m_cache.IsEmpty()) { CStdString strCachePath; URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath, "scrapers/"+cacheContext+"/"+scrURL.m_cache, strCachePath); XFILE::CFile file; if (file.OpenForWrite(strCachePath,true)) file.Write(strHTML.data(),strHTML.size()); file.Close(); } return true; }
int CAirPlayServer::CTCPClient::ProcessRequest( std::string& responseHeader, std::string& responseBody) { std::string method = m_httpParser->getMethod() ? m_httpParser->getMethod() : ""; std::string uri = m_httpParser->getUri() ? m_httpParser->getUri() : ""; std::string queryString = m_httpParser->getQueryString() ? m_httpParser->getQueryString() : ""; std::string body = m_httpParser->getBody() ? m_httpParser->getBody() : ""; std::string contentType = m_httpParser->getValue("content-type") ? m_httpParser->getValue("content-type") : ""; m_sessionId = m_httpParser->getValue("x-apple-session-id") ? m_httpParser->getValue("x-apple-session-id") : ""; std::string authorization = m_httpParser->getValue("authorization") ? m_httpParser->getValue("authorization") : ""; int status = AIRPLAY_STATUS_OK; bool needAuth = false; if (m_sessionId.empty()) m_sessionId = "00000000-0000-0000-0000-000000000000"; if (ServerInstance->m_usePassword && !m_bAuthenticated) { needAuth = true; } size_t startQs = uri.find('?'); if (startQs != std::string::npos) { uri.erase(startQs); } // This is the socket which will be used for reverse HTTP // negotiate reverse HTTP via upgrade if (uri == "/reverse") { status = AIRPLAY_STATUS_SWITCHING_PROTOCOLS; responseHeader = "Upgrade: PTTH/1.0\r\nConnection: Upgrade\r\n"; } // The rate command is used to play/pause media. // A value argument should be supplied which indicates media should be played or paused. // 0.000000 => pause // 1.000000 => play else if (uri == "/rate") { const char* found = strstr(queryString.c_str(), "value="); int rate = found ? (int)(atof(found + strlen("value=")) + 0.5f) : 0; CLog::Log(LOGDEBUG, "AIRPLAY: got request %s with rate %i", uri.c_str(), rate); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (rate == 0) { if (g_application.m_pPlayer->IsPlaying() && !g_application.m_pPlayer->IsPaused()) { CApplicationMessenger::Get().MediaPause(); } } else { if (g_application.m_pPlayer->IsPausedPlayback()) { CApplicationMessenger::Get().MediaPause(); } } } // The volume command is used to change playback volume. // A value argument should be supplied which indicates how loud we should get. // 0.000000 => silent // 1.000000 => loud else if (uri == "/volume") { const char* found = strstr(queryString.c_str(), "volume="); float volume = found ? (float)strtod(found + strlen("volume="), NULL) : 0; CLog::Log(LOGDEBUG, "AIRPLAY: got request %s with volume %f", uri.c_str(), volume); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (volume >= 0 && volume <= 1) { float oldVolume = g_application.GetVolume(); volume *= 100; if(oldVolume != volume && CSettings::Get().GetBool("services.airplayvolumecontrol")) { backupVolume(); g_application.SetVolume(volume); CApplicationMessenger::Get().ShowVolumeBar(oldVolume < volume); } } } // Contains a header like format in the request body which should contain a // Content-Location and optionally a Start-Position else if (uri == "/play") { std::string location; float position = 0.0; m_lastEvent = EVENT_NONE; CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (contentType == "application/x-apple-binary-plist") { CAirPlayServer::m_isPlaying++; if (m_pLibPlist->Load()) { m_pLibPlist->EnableDelayedUnload(false); const char* bodyChr = m_httpParser->getBody(); plist_t dict = NULL; m_pLibPlist->plist_from_bin(bodyChr, m_httpParser->getContentLength(), &dict); if (m_pLibPlist->plist_dict_get_size(dict)) { plist_t tmpNode = m_pLibPlist->plist_dict_get_item(dict, "Start-Position"); if (tmpNode) { double tmpDouble = 0; m_pLibPlist->plist_get_real_val(tmpNode, &tmpDouble); position = (float)tmpDouble; } tmpNode = m_pLibPlist->plist_dict_get_item(dict, "Content-Location"); if (tmpNode) { char *tmpStr = NULL; m_pLibPlist->plist_get_string_val(tmpNode, &tmpStr); location=tmpStr; #ifdef TARGET_WINDOWS m_pLibPlist->plist_free_string_val(tmpStr); #else free(tmpStr); #endif } if (dict) { m_pLibPlist->plist_free(dict); } } else { CLog::Log(LOGERROR, "Error parsing plist"); } m_pLibPlist->Unload(); } } else { CAirPlayServer::m_isPlaying++; // Get URL to play std::string contentLocation = "Content-Location: "; size_t start = body.find(contentLocation); if (start == std::string::npos) return AIRPLAY_STATUS_NOT_IMPLEMENTED; start += contentLocation.size(); int end = body.find('\n', start); location = body.substr(start, end - start); std::string startPosition = "Start-Position: "; start = body.find(startPosition); if (start != std::string::npos) { start += startPosition.size(); int end = body.find('\n', start); std::string positionStr = body.substr(start, end - start); position = (float)atof(positionStr.c_str()); } } if (status != AIRPLAY_STATUS_NEED_AUTH) { std::string userAgent(CURL::Encode("AppleCoreMedia/1.0.0.8F455 (AppleTV; U; CPU OS 4_3 like Mac OS X; de_de)")); location += "|User-Agent=" + userAgent; CFileItem fileToPlay(location, false); fileToPlay.SetProperty("StartPercent", position*100.0f); ServerInstance->AnnounceToClients(EVENT_LOADING); // froce to internal dvdplayer cause it is the only // one who will work well with airplay g_application.m_eForcedNextPlayer = EPC_DVDPLAYER; CApplicationMessenger::Get().MediaPlay(fileToPlay); } } // Used to perform seeking (POST request) and to retrieve current player position (GET request). // GET scrub seems to also set rate 1 - strange but true else if (uri == "/scrub") { if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (method == "GET") { CLog::Log(LOGDEBUG, "AIRPLAY: got GET request %s", uri.c_str()); if (g_application.m_pPlayer->GetTotalTime()) { float position = ((float) g_application.m_pPlayer->GetTime()) / 1000; responseBody = StringUtils::Format("duration: %.6f\r\nposition: %.6f\r\n", (float)g_application.m_pPlayer->GetTotalTime() / 1000, position); } else { status = AIRPLAY_STATUS_METHOD_NOT_ALLOWED; } } else { const char* found = strstr(queryString.c_str(), "position="); if (found && g_application.m_pPlayer->HasPlayer()) { int64_t position = (int64_t) (atof(found + strlen("position=")) * 1000.0); g_application.m_pPlayer->SeekTime(position); CLog::Log(LOGDEBUG, "AIRPLAY: got POST request %s with pos %" PRId64, uri.c_str(), position); } } } // Sent when media playback should be stopped else if (uri == "/stop") { CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else { if (IsPlaying()) //only stop player if we started him { CApplicationMessenger::Get().MediaStop(); CAirPlayServer::m_isPlaying--; } else //if we are not playing and get the stop request - we just wanna stop picture streaming { CApplicationMessenger::Get().SendAction(ACTION_PREVIOUS_MENU); } } } // RAW JPEG data is contained in the request body else if (uri == "/photo") { CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (m_httpParser->getContentLength() > 0) { XFILE::CFile tmpFile; std::string tmpFileName = "special://temp/airplay_photo.jpg"; if( m_httpParser->getContentLength() > 3 && m_httpParser->getBody()[1] == 'P' && m_httpParser->getBody()[2] == 'N' && m_httpParser->getBody()[3] == 'G') { tmpFileName = "special://temp/airplay_photo.png"; } if (tmpFile.OpenForWrite(tmpFileName, true)) { int writtenBytes=0; writtenBytes = tmpFile.Write(m_httpParser->getBody(), m_httpParser->getContentLength()); tmpFile.Close(); if (writtenBytes > 0 && (unsigned int)writtenBytes == m_httpParser->getContentLength()) { CApplicationMessenger::Get().PictureShow(tmpFileName); } else { CLog::Log(LOGERROR,"AirPlayServer: Error writing tmpFile."); } } } } else if (uri == "/playback-info") { float position = 0.0f; float duration = 0.0f; float cachePosition = 0.0f; bool playing = false; CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (g_application.m_pPlayer->HasPlayer()) { if (g_application.m_pPlayer->GetTotalTime()) { position = ((float) g_application.m_pPlayer->GetTime()) / 1000; duration = ((float) g_application.m_pPlayer->GetTotalTime()) / 1000; playing = !g_application.m_pPlayer->IsPaused(); cachePosition = position + (duration * g_application.m_pPlayer->GetCachePercentage() / 100.0f); } responseBody = StringUtils::Format(PLAYBACK_INFO, duration, cachePosition, position, (playing ? 1 : 0), duration); responseHeader = "Content-Type: text/x-apple-plist+xml\r\n"; if (g_application.m_pPlayer->IsCaching()) { CAirPlayServer::ServerInstance->AnnounceToClients(EVENT_LOADING); } } else { responseBody = StringUtils::Format(PLAYBACK_INFO_NOT_READY); responseHeader = "Content-Type: text/x-apple-plist+xml\r\n"; } } else if (uri == "/server-info") { CLog::Log(LOGDEBUG, "AIRPLAY: got request %s", uri.c_str()); responseBody = StringUtils::Format(SERVER_INFO, g_application.getNetwork().GetFirstConnectedInterface()->GetMacAddress().c_str()); responseHeader = "Content-Type: text/x-apple-plist+xml\r\n"; } else if (uri == "/slideshow-features") { // Ignore for now. } else if (uri == "/authorize") { // DRM, ignore for now. } else if (uri == "/setProperty") { status = AIRPLAY_STATUS_NOT_FOUND; } else if (uri == "/getProperty") { status = AIRPLAY_STATUS_NOT_FOUND; } else if (uri == "200") //response OK from the event reverse message { status = AIRPLAY_STATUS_NO_RESPONSE_NEEDED; } else { CLog::Log(LOGERROR, "AIRPLAY Server: unhandled request [%s]\n", uri.c_str()); status = AIRPLAY_STATUS_NOT_IMPLEMENTED; } if (status == AIRPLAY_STATUS_NEED_AUTH) { ComposeAuthRequestAnswer(responseHeader, responseBody); } return status; }
int CAirPlayServer::CTCPClient::ProcessRequest( CStdString& responseHeader, CStdString& responseBody, CStdString& reverseHeader, CStdString& reverseBody, CStdString& sessionId) { CStdString method = m_httpParser->getMethod(); CStdString uri = m_httpParser->getUri(); CStdString queryString = m_httpParser->getQueryString(); CStdString body = m_httpParser->getBody(); CStdString contentType = m_httpParser->getValue("content-type"); sessionId = m_httpParser->getValue("x-apple-session-id"); CStdString authorization = m_httpParser->getValue("authorization"); int status = AIRPLAY_STATUS_OK; bool needAuth = false; if (ServerInstance->m_usePassword && !m_bAuthenticated) { needAuth = true; } int startQs = uri.Find('?'); if (startQs != -1) { uri = uri.Left(startQs); } // This is the socket which will be used for reverse HTTP // negotiate reverse HTTP via upgrade if (uri == "/reverse") { status = AIRPLAY_STATUS_SWITCHING_PROTOCOLS; responseHeader = "Upgrade: PTTH/1.0\r\nConnection: Upgrade\r\n"; } // The rate command is used to play/pause media. // A value argument should be supplied which indicates media should be played or paused. // 0.000000 => pause // 1.000000 => play else if (uri == "/rate") { const char* found = strstr(queryString.c_str(), "value="); int rate = found ? (int)(atof(found + strlen("value=")) + 0.5f) : 0; if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (rate == 0) { if (g_application.m_pPlayer && g_application.m_pPlayer->IsPlaying() && !g_application.m_pPlayer->IsPaused()) { g_application.getApplicationMessenger().MediaPause(); } } else { if (g_application.m_pPlayer && g_application.m_pPlayer->IsPlaying() && g_application.m_pPlayer->IsPaused()) { g_application.getApplicationMessenger().MediaPause(); } } } // Contains a header like format in the request body which should contain a // Content-Location and optionally a Start-Position else if (uri == "/play") { CStdString location; float position = 0.0; if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (contentType == "application/x-apple-binary-plist") { if (m_pLibPlist->Load()) { m_pLibPlist->EnableDelayedUnload(false); const char* bodyChr = m_httpParser->getBody(); plist_t dict = NULL; m_pLibPlist->plist_from_bin(bodyChr, m_httpParser->getContentLength(), &dict); if (m_pLibPlist->plist_dict_get_size(dict)) { plist_t tmpNode = m_pLibPlist->plist_dict_get_item(dict, "Start-Position"); if (tmpNode) { double tmpDouble = 0; m_pLibPlist->plist_get_real_val(tmpNode, &tmpDouble); position = tmpDouble; } tmpNode = m_pLibPlist->plist_dict_get_item(dict, "Content-Location"); if (tmpNode) { char *tmpStr = NULL; m_pLibPlist->plist_get_string_val(tmpNode, &tmpStr); location=tmpStr; free(tmpStr); } if (dict) { m_pLibPlist->plist_free(dict); } } else { CLog::Log(LOGERROR, "Error parsing plist"); } m_pLibPlist->Unload(); } } else { // Get URL to play int start = body.Find("Content-Location: "); if (start == -1) return AIRPLAY_STATUS_NOT_IMPLEMENTED; start += strlen("Content-Location: "); int end = body.Find('\n', start); location = body.Mid(start, end - start); start = body.Find("Start-Position"); if (start != -1) { start += strlen("Start-Position: "); int end = body.Find('\n', start); CStdString positionStr = body.Mid(start, end - start); position = atof(positionStr.c_str()); } } if (status != AIRPLAY_STATUS_NEED_AUTH) { CFileItem fileToPlay(location, false); fileToPlay.SetProperty("StartPercent", position*100.0f); g_application.getApplicationMessenger().MediaPlay(fileToPlay); } } // Used to perform seeking (POST request) and to retrieve current player position (GET request). else if (uri == "/scrub") { if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (method == "GET") { if (g_application.m_pPlayer && g_application.m_pPlayer->GetTotalTime()) { float position = ((float) g_application.m_pPlayer->GetTime()) / 1000; responseBody.Format("duration: %d\r\nposition: %f", g_application.m_pPlayer->GetTotalTime(), position); } } else { const char* found = strstr(queryString.c_str(), "position="); if (found && g_application.m_pPlayer) { __int64 position = (__int64) (atof(found + strlen("position=")) * 1000.0); g_application.m_pPlayer->SeekTime(position); } } } // Sent when media playback should be stopped else if (uri == "/stop") { if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else { g_application.getApplicationMessenger().MediaStop(); } } // RAW JPEG data is contained in the request body else if (uri == "/photo") { if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (m_httpParser->getContentLength() > 0) { XFILE::CFile tmpFile; if (tmpFile.OpenForWrite("special://temp/airplay_photo.jpg", true)) { int writtenBytes=0; writtenBytes = tmpFile.Write(m_httpParser->getBody(), m_httpParser->getContentLength()); tmpFile.Close(); if (writtenBytes > 0 && (unsigned int)writtenBytes == m_httpParser->getContentLength()) { g_application.getApplicationMessenger().PictureShow("special://temp/airplay_photo.jpg"); } else { CLog::Log(LOGERROR,"AirPlayServer: Error writing tmpFile."); } } } } else if (uri == "/playback-info") { float position = 0.0f; float duration = 0.0f; float cacheDuration = 0.0f; bool playing = false; if (needAuth && !checkAuthorization(authorization, method, uri)) { status = AIRPLAY_STATUS_NEED_AUTH; } else if (g_application.m_pPlayer) { if (g_application.m_pPlayer->GetTotalTime()) { position = ((float) g_application.m_pPlayer->GetTime()) / 1000; duration = (float) g_application.m_pPlayer->GetTotalTime(); playing = g_application.m_pPlayer ? !g_application.m_pPlayer->IsPaused() : false; cacheDuration = (float) g_application.m_pPlayer->GetTotalTime() * g_application.GetCachePercentage()/100.0f; } responseBody.Format(PLAYBACK_INFO, duration, cacheDuration, position, (playing ? 1 : 0), duration); responseHeader = "Content-Type: text/x-apple-plist+xml\r\n"; if (g_application.m_pPlayer->IsCaching()) { ComposeReverseEvent(reverseHeader, reverseBody, sessionId, EVENT_LOADING); } else if (playing) { ComposeReverseEvent(reverseHeader, reverseBody, sessionId, EVENT_PLAYING); } else { ComposeReverseEvent(reverseHeader, reverseBody, sessionId, EVENT_PAUSED); } } } else if (uri == "/server-info") { responseBody.Format(SERVER_INFO, g_application.getNetwork().GetFirstConnectedInterface()->GetMacAddress()); responseHeader = "Content-Type: text/x-apple-plist+xml\r\n"; } else if (uri == "/slideshow-features") { // Ignore for now. } else if (uri == "/authorize") { // DRM, ignore for now. } else if (uri == "200") //response OK from the event reverse message { status = AIRPLAY_STATUS_NO_RESPONSE_NEEDED; } else { CLog::Log(LOGERROR, "AIRPLAY Server: unhandled request [%s]\n", uri.c_str()); status = AIRPLAY_STATUS_NOT_IMPLEMENTED; } if (status == AIRPLAY_STATUS_NEED_AUTH) { ComposeAuthRequestAnswer(responseHeader, responseBody); } return status; }
bool CEventClient::OnPacketNOTIFICATION(CEventPacket *packet) { unsigned char *payload = (unsigned char *)packet->Payload(); int psize = (int)packet->PayloadSize(); string title, message; // parse caption if (!ParseString(payload, psize, title)) return false; // parse message if (!ParseString(payload, psize, message)) return false; // icon type unsigned char ltype; if (!ParseByte(payload, psize, ltype)) return false; m_eLogoType = (LogoType)ltype; // reserved uint32 unsigned int reserved; ParseUInt32(payload, psize, reserved); // image data if any string iconfile = "special://temp/notification"; if (m_eLogoType != LT_NONE && psize>0) { switch (m_eLogoType) { case LT_JPEG: iconfile += ".jpg"; break; case LT_GIF: iconfile += ".gif"; break; default: iconfile += ".png"; break; } XFILE::CFile file; if (file.OpenForWrite(iconfile, true)) { file.Write((const void *)payload, psize); file.Close(); } else { CLog::Log(LOGERROR, "ES: Could not write icon file"); m_eLogoType = LT_NONE; } } if (m_eLogoType == LT_NONE) { CGUIDialogKaiToast::QueueNotification(title.c_str(), message.c_str()); } else { CGUIDialogKaiToast::QueueNotification(iconfile.c_str(), title.c_str(), message.c_str()); } return true; }
bool CJpegIO::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height, unsigned int format, unsigned int pitch, const CStdString& destFile) { //Encode raw data from buffer, save to destFile struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; JSAMPROW row_pointer[1]; long unsigned int outBufSize = width * height; unsigned char* result; unsigned char* src = buffer; unsigned char* rgbbuf, *src2, *dst2; if(buffer == NULL) { CLog::Log(LOGERROR, "JpegIO::CreateThumbnailFromSurface no buffer"); return false; } result = (unsigned char*) malloc(outBufSize); //Initial buffer. Grows as-needed. if (result == NULL) { CLog::Log(LOGERROR, "JpegIO::CreateThumbnailFromSurface error allocating memory for image buffer"); return false; } if(format == XB_FMT_RGB8) { rgbbuf = buffer; } else if(format == XB_FMT_A8R8G8B8) { // create a copy for bgra -> rgb. rgbbuf = new unsigned char [(width * height * 3)]; unsigned char* dst = rgbbuf; for (unsigned int y = 0; y < height; y++) { dst2 = dst; src2 = src; for (unsigned int x = 0; x < width; x++, src2 += 4) { *dst2++ = src2[2]; *dst2++ = src2[1]; *dst2++ = src2[0]; } dst += width * 3; src += pitch; } } else { CLog::Log(LOGWARNING, "JpegIO::CreateThumbnailFromSurface Unsupported format"); free(result); return false; } cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = jpeg_error_exit; jpeg_create_compress(&cinfo); if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&cinfo); free(result); if(format != XB_FMT_RGB8) delete [] rgbbuf; return false; } else { #if JPEG_LIB_VERSION < 80 x_jpeg_mem_dest(&cinfo, &result, &outBufSize); #else jpeg_mem_dest(&cinfo, &result, &outBufSize); #endif cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 90, TRUE); jpeg_start_compress(&cinfo, TRUE); while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &rgbbuf[cinfo.next_scanline * width * 3]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); } if(format != XB_FMT_RGB8) delete [] rgbbuf; XFILE::CFile file; if (file.OpenForWrite(destFile, true)) { file.Write(result, outBufSize); file.Close(); free(result); return true; } free(result); return false; }