☆잉여놀이
- [libcurl] How to use objective c methods in c code 2011.01.12
- [libcurl] http, ftp 등 사용 시 써보세요 curl 라이브러리!! 2011.01.10
- [ XCode ] writeToPList & getDictionaryFromPList 2010.12.14
- [XCode 4.2] 허억!! IAP 테스트 해보기 2010.11.29
- [JSon] Xcode에 JSon 세팅하기 +_+ 2010.10.12
- [XCode] Entitlements.plist is missing 2010.09.05 2
- [ Xcode + SVN ] trunk, tags, branches 의 용도 2010.07.12
- [XCode] wait_fences: failed to receive reply: 2010.07.09
- [XCode] How to change .wav to .caf (AVAudioPlayer) 2010.07.08
- [XCode] To Change The Project Name Safety 2010.06.24
[libcurl] How to use objective c methods in c code
[libcurl] http, ftp 등 사용 시 써보세요 curl 라이브러리!!
1 Curl에 대해서
- HTTP GET : URL로 부터 내용을 가져온다.
- Anonymous FTP 다운로드 : FTP서버에 접속해서 파일을 가져온다.
- HTTP POST: Web Form을 흉내내어서 데이터를 전송한다.
- Authenticated FTP Upload : ID+Password로 접속해서 파일을 Upload한다.
2 Curl 사용 기초
- clinet는 server로 연결을 시도한다.
- 연결이 되었다면 client는 GET, POST를 이용해서 데이터를 보낼 것이다.
- server는 요청을 받고 요청에 대한 응답을 보낸다.(HTML페이지 혹은 에러 메시지)
- client는 server로의 연결을 종료한다.
- curl_blogal_init : curl 라이브러리를 초기화 한다.
- curl_easy_init : context를 생성한다.
- curl_easy_setopt : context 설정
- curl_easy_perform : 요청을 초기화 하고 callback함수를 대기시킨다.
- curl_easy_cleanup : context를 없앤다.
- curl_global_cleanup : curl 라이브러리를 없앤다.
curl_easy_setopt(CURL *ctx, CURLoption key, value)
3 HTTP GET:웹 페이지 긁어오기
CURL *ctx = curl_easy_init ();curl_easy_setopt 를 이용해서 context객체를 설정한다. CURLOPT_URL은 목표 URL이다.
curl_easy_setopt(ctx, CURLOPT_URL, argv[1]);curl_easy_setopt를 이용하면 이외에도 몇 가지 설정을 더 해줄 수 있다.
curl_easy_setiopt(ctx, CURLOPT_WRITEHEADER, stderr); curl_easy_setiopt(ctx, CURLOPT_WRITEDATA, stdout);header 정보는 표준에러로, body정보는 표준출력으로 가져오도록 설정을 했다.
const CURLcode rc = curl_easy_perform(ctx); if (CURLE_OK != rc) { std::cerr << "Error from cURL: " << curl_easy_strerror(rc) std::endl; } else { // 데이터 처리 }
long statLong; curl_easy_getinfo(ctx, CURLINFO_HTTP_CODE, &statLong); std::cout << "HTTP response code: " << statLong << std::endl;원하는 값을 가져오기 위해서는 데이터의 타입에 맞는 인자를 써야 한다. 200이나 404와 같은 HTTP 응답코드를 가져오길 원한다면 CURLINFO_HTTP_CODE를 전송받은 문서의 크기를 알아내길 원한다면 CURLINFO_SIZE_DOWNLOAD를 사용하는 식이다.
/* sample for O'ReillyNet article on libcURL: {TITLE} {URL} AUTHOR: Ethan McCallum Scenario: use http/GET to fetch a webpage 이 코드는 Ubuntu 리눅스 Kernel 2.6.15에서 libcURL 버젼 7.15.1로 테스트 되었다. 2006년 8월 3일 */ #include<iostream> extern "C" { #include<curl/curl.h> } // - - - - - - - - - - - - - - - - - - - - enum { ERROR_ARGS = 1 , ERROR_CURL_INIT = 2 } ; enum { OPTION_FALSE = 0 , OPTION_TRUE = 1 } ; enum { FLAG_DEFAULT = 0 } ; // - - - - - - - - - - - - - - - - - - - - int main( const int argc , const char** argv ){ if( argc != 2 ){ std::cerr << " Usage: ./" << argv[0] << " {url} [debug]" << std::endl ; return( ERROR_ARGS ) ; } const char* url = argv[1] ; // lubcURL 초기화 curl_global_init( CURL_GLOBAL_ALL ) ; // context객체의 생성 CURL* ctx = curl_easy_init() ; if( NULL == ctx ){ std::cerr << "Unable to initialize cURL interface" << std::endl ; return( ERROR_CURL_INIT ) ; } // context 객체를 설정한다. // 긁어올 url을 명시하고, url이 URL정보임을 알려준다. curl_easy_setopt( ctx , CURLOPT_URL, url ) ; // no progress bar: curl_easy_setopt( ctx , CURLOPT_NOPROGRESS , OPTION_TRUE ) ; /* By default, headers are stripped from the output. They can be: - passed through a separate FILE* (CURLOPT_WRITEHEADER) - included in the body's output (CURLOPT_HEADER -> nonzero value) (here, the headers will be passed to whatever function processes the body, along w/ the body) - handled with separate callbacks (CURLOPT_HEADERFUNCTION) (in this case, set CURLOPT_WRITEHEADER to a matching struct for the function) */ // 헤더는 표준에러로 출력하도록 하다. curl_easy_setopt( ctx , CURLOPT_WRITEHEADER , stderr ) ; // body 데이터는 표준출력 하도록 한다. curl_easy_setopt( ctx , CURLOPT_WRITEDATA , stdout ) ; // context 객체의 설정 종료 // 웹페이지를 긁어온다. const CURLcode rc = curl_easy_perform( ctx ) ; if( CURLE_OK != rc ){ std::cerr << "Error from cURL: " << curl_easy_strerror( rc ) << std::endl ; }else{ // get some info about the xfer: double statDouble ; long statLong ; char* statString = NULL ; // HTTP 응답코드를 얻어온다. if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_HTTP_CODE , &statLong ) ){ std::cout << "Response code: " << statLong << std::endl ; } // Content-Type 를 얻어온다. if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_CONTENT_TYPE , &statString ) ){ std::cout << "Content type: " << statString << std::endl ; } // 다운로드한 문서의 크기를 얻어온다. if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_SIZE_DOWNLOAD , &statDouble ) ){ std::cout << "Download size: " << statDouble << "bytes" << std::endl ; } // if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_SPEED_DOWNLOAD , &statDouble ) ){ std::cout << "Download speed: " << statDouble << "bytes/sec" << std::endl ; } } // cleanup curl_easy_cleanup( ctx ) ; curl_global_cleanup() ; return( 0 ) ; } // main()
4 FTP Download: FTP 데이터 다운로드
size_t showSize(...); curl_esay_setopt(ctx, CURLOPT_WRITEFUNCTION, showSize);CURLOPT_WRITEFUNCTION은 원격지 파일을 다운로드 할께 호출할 함수를 정의하기 위해서 사용한다.
class XferInfo { void add(int more); int getBytesTransferred(); int getTimesCalled(); }; ... XferInfo info; curl_easy_setopt(ctx, CURLOPT_WRITEDATA, &info);
extern "C" size_t showSize { void *source, size_t size, size_t nmemb, void *userData }
extern "C" size_t showSize(...) { XferInfo *info = static_cast<XferInfo *>(userData); const int bufferSize = size * nmemb; info->add(bufferSize); }이제 우리가 만든 콜백함수는 읽어들인 파일의 크기를 (size*nmemb)로 계산해서 되돌려줄 것이다. 또한 이 함수는 bufferSize를 되돌려주게 되는데, libCURL은 콜백함수의 리턴값과 전송받은 실제 데이터의 크기를 비교해서 틀릴경우 0을 리턴해주게 된다. 이런식으로 데이터를 정상적으로 받았는지를 체크할 수 있다.
/* sample for O'ReillyNet article on libcURL: {TITLE} {URL} AUTHOR: Ethan McCallum anon ftp/download (scenario: fetch remote file) 이 코드는 Ubuntu 리눅스 Kernel 2.6.15에서 libcURL 버젼 7.15.1로 테스트 되었다. 2006년 8월 3일 */ #include<iostream> #include<string> #include<sstream> #include<list> extern "C" { #include<curl/curl.h> } // - - - - - - - - - - - - - - - - - - - - typedef std::list< std::string > FileList ; enum { ERROR_ARGS = 1 , ERROR_CURL_INIT = 2 } ; enum { OPTION_FALSE = 0 , OPTION_TRUE = 1 } ; // - - - - - - - - - - - - - - - - - - - - // 콜백함수에서 사용할 사용자 정의 객체 class XferInfo { private: int bytesTransferred_ ; int invocations_ ; protected: // empty public: XferInfo(){ reset() ; } // ctor /// reset counters void reset(){ bytesTransferred_ = 0 ; invocations_ = 0 ; return ; } // reset() /// add the number of bytes transferred in this call void add( int more ){ bytesTransferred_ += more ; ++invocations_ ; return ; } // add() /// get the amount of data transferred, in bytes int getBytesTransferred() const { return( bytesTransferred_ ) ; } // getBytesTransferred() /// get the number of times add() has been called int getTimesCalled(){ return( invocations_ ) ; } // getTimesCalled() } ; // - - - - - - - - - - - - - - - - - - - - // C++ 에서 C함수를 링크시키기 위해서는, "extern C"를 이용해야 한다. extern "C" size_t showSize( void *source , size_t size , size_t nmemb , void *userData ){ // this function may be called any number of times for even a single // transfer; be sure to write it accordingly. // source is the actual data fetched by libcURL; cast it to whatever // type you need (usually char*). It has NO terminating NULL byte. // we don't touch the data here, so the cast is commented out // const char* data = static_cast< const char* >( source ) ; // userData is called "stream" in the docs, which is misleading: // that parameter can be _any_ data type, not necessarily a FILE* // Here, we use it to save state between calls to this function // and track number of times this callback is invoked. XferInfo* info = static_cast< XferInfo* >( userData ) ; const int bufferSize = size * nmemb ; std::cout << '\t' << "showSize() called: " << bufferSize << " bytes passed" << std::endl ; // ... pretend real data processing on *source happens here ... info->add( bufferSize ) ; /* return some number less than bufferSize to indicate an error (xfer abort) nicer code would also set a status var (in userData) for the calling function */ return( bufferSize ) ; } // showSize() // - - - - - - - - - - - - - - - - - - - - int main( const int argc , const char** argv ){ if( argc < 3 ){ std::cerr << "test of libcURL: anonymous FTP" << std::endl ; std::cerr << " Usage: " << argv[0] << " {server} {file1} [{file2} ...]" << std::endl ; return( ERROR_ARGS ) ; } // remote FTP server const char* server = argv[1] ; const int totalTargets = argc - 2 ; std::cout << "Attempting to download " << totalTargets << " files from " << server << std::endl ; curl_global_init( CURL_GLOBAL_ALL ) ; CURL* ctx = curl_easy_init() ; if( NULL == ctx ){ std::cerr << "Unable to initialize cURL interface" << std::endl ; return( ERROR_CURL_INIT ) ; } /* BEGIN: global handle options */ // handy for debugging: see *everything* that goes on // curl_easy_setopt( ctx , CURLOPT_VERBOSE, OPTION_TRUE ) ; // no progress bar: curl_easy_setopt( ctx , CURLOPT_NOPROGRESS , OPTION_TRUE ) ; // what to do with returned data curl_easy_setopt( ctx , CURLOPT_WRITEFUNCTION , showSize ) ; XferInfo info ; for( int ix = 2 ; ix < argc ; ++ix ){ const char* item = argv[ ix ] ; // zero counters for each file info.reset() ; // target url: concatenate the server and target file name urlBuffer.str( "" ) ; urlBuffer << "ftp://" << server << "/" << item << std::flush ; std::cout << "Trying " << urlBuffer.str() << std::endl ; const std::string url = urlBuffer.str() ; curl_easy_setopt( ctx , CURLOPT_URL, url.c_str() ) ; // set the write function's user-data (state data) curl_easy_setopt( ctx , CURLOPT_WRITEDATA , &info ) ; // action! const CURLcode rc = curl_easy_perform( ctx ) ; // for curl v7.11.x and earlier, look into // curl_easy_setopt( ctx , CURLOPT_ERRORBUFFER , /* char array */ ) ; if( CURLE_OK == rc ){ std::cout << '\t' << "xfer size: " << info.getBytesTransferred() << " bytes" << std::endl ; std::cout << '\t' << "Callback was invoked " << info.getTimesCalled() << " times for this file" << std::endl ; } else { std::cerr << "Error from cURL: " << curl_easy_strerror( rc ) << std::endl ; } std::cout << std::endl ; } // cleanup curl_easy_cleanup( ctx ) ; curl_global_cleanup() ; return( 0 ) ; } // main()
5 FTP 업로드
ftp://host/file
login:password
ftp://login:password@host/file
struct curl_slist *command=NULL; command = curl_slist_append( commands, "mkdir /some/path"); command = curl_slist_append( commands, "mkdir /another/path");물론 이들 명령이 실행하기 위해서는 로그인 과정을 우선 거쳐야 할 것이다. 이제 CURLOPT_QUOTE를 이용해서 명령을 등록시키면 된다.
curl_easy_setopt(ctx, CURLPOST_QUOTE, commands); // curl_easy_perform을 이용해서 ftp 세션을 시작하고 // 명령을 실행한다. curl_slist_free_all(command);
6 HTTP POST
const char* postData="param1=value1¶m2=value2&...";POST 데이터 전송을 위해서 CURLOPT_POSTFIELDS옵션을 설정하면 된다.
curl_easy_setopt(ctx, CURLOPT_POSTFIELDS, postData);
curl_sist * responseHeaders=NULL; responseHeaders = curl_slist_append( responseHeaders, "Expect: 100-continue" ); curl_easy_setopt(ctx, CURLOPT_HTTPHEADER, responseHeaders);주의 할것은 libCURL은 hidden 필드나 JavaScript와 같은 클라이언트측의 기술들을 사용하지 못한다는 점이다. 예를들어 폼입력을 하고나서 submit버튼을 클릭하면 폼의 각 필드를 검사하는 등의 자바스크립트등은 처리할 수 없다.
/* sample for O'ReillyNet article on libcURL: {TITLE} {URL} AUTHOR: Ethan McCallum HTTP POST (e.g. form processing or REST web services) 이 코드는 Ubuntu 6.06 Dapper Drake, libcURL This code was built/tested under Fedora Core 3, libcURL version 7.12.3 환경에서 테스트 되었다. */ #include<cstdio> #include<iostream> #include<string> #include<sstream> extern "C" { #include<curl/curl.h> } // - - - - - - - - - - - - - - - - - - - - enum { ERROR_ARGS = 1 , ERROR_CURL_INIT = 2 } ; enum { OPTION_FALSE = 0 , OPTION_TRUE = 1 } ; enum { FLAG_DEFAULT = 0 } ; const char* targetUrl ; // - - - - - - - - - - - - - - - - - - - - int main( int argc , char** argv ){ if( argc != 2 ){ std::cerr << "test of libcURL: test an HTTP post" << std::endl ; std::cerr << "(post data is canned)" << std::endl ; std::cerr << " Usage: " << argv[0] << " {post url}" << std::endl ; std::exit( ERROR_ARGS ) ; } targetUrl = argv[1] ; curl_global_init( CURL_GLOBAL_ALL ) ; CURL* ctx = curl_easy_init() ; if( NULL == ctx ){ std::cerr << "Unable to initialize cURL interface" << std::endl ; return( ERROR_CURL_INIT ) ; } /* BEGIN: configure the handle: */ // Target URL: curl_easy_setopt( ctx , CURLOPT_URL, targetUrl ) ; // no progress bar: curl_easy_setopt( ctx , CURLOPT_NOPROGRESS , OPTION_TRUE ) ; // 응답데이터를 표준출력으로 보낸다. curl_easy_setopt( ctx , CURLOPT_WRITEDATA , stdout ) ; // 사용자 정의 HTTP 헤더: create a linked list and assign curl_slist* responseHeaders = NULL ; responseHeaders = curl_slist_append( responseHeaders , "Expect: 100-continue" ) ; responseHeaders = curl_slist_append( responseHeaders , "User-Agent: Some Custom App" ) ; curl_easy_setopt( ctx , CURLOPT_HTTPHEADER , responseHeaders ) ; // POST Data 설정 // notice the URL-unfriendly characters (such as "%" and "&") // URL에서는 '%', '&', ' '와 같은 문자를 URL encoding 시켜줘야 한다. // curl_escape 함수를 이용해서 인코딩할 수 있다. const char* postParams[] = { "One" , "this has % and & symbols" , "Dos" , "value with spaces" , "Trois" , "plus+signs+will+be+escaped" , "Chetirye" , "fourth param..." , NULL } ; // buffer for the POST params std::ostringstream postBuf ; const char** postParamsPtr = postParams ; while( NULL != *postParamsPtr ) { // curl_escape( {string} , 0 ): replace special characters // (such as space, "&", "+", "%") with HTML entities. // ( 0 => "use strlen to find string length" ) // remember to call curl_free() on the strings on the way out char* key = curl_escape( postParamsPtr[0] , FLAG_DEFAULT ) ; char* val = curl_escape( postParamsPtr[1] , FLAG_DEFAULT ) ; std::cout << "Setting POST param: \"" << key << "\" => \"" << val << "\"" << std::endl ; postBuf << key << "=" << val << "&" ; postParamsPtr += 2 ; // the cURL lib allocated the escaped versions of the // param strings; we must free them here curl_free( key ) ; curl_free( val ) ; } postBuf << std::flush ; // We can't really call "postBuf.str().c_str()" here, because // the std::string created in the middle is a temporary. In turn, // the char* buf from its c_str() operation isn't guaranteed to // be around after the function call. // The solution: explicitly create the string. // Larger (and/or better) code would use std::string::copy() to create // a const char* pointer to pass to cURL, then clean it up later. // e.g.: // const char* postData = new char*[ 1 + postBuf.tellg() ] ; // postBuf.str().copy( postData , std::string::npos ) ; // postData[ postBuf.tellg() ] == '\0' ; const std::string postData = postBuf.str() ; std::cout << "post data: " << postData << std::endl ; curl_easy_setopt( ctx , CURLOPT_POSTFIELDS , postData.c_str() ) ; // do a standard HTTP POST op // in theory, this is automatically set for us by setting // CURLOPT_POSTFIELDS... curl_easy_setopt( ctx , CURLOPT_POST , OPTION_TRUE ) ; /* END: configure the handle */ // action! std::cout << "- - - BEGIN: response - - -" << std::endl ; CURLcode rc = curl_easy_perform( ctx ) ; std::cout << "- - - END: response - - -" << std::endl ; // "curl_easy_strerror()" available in curl v7.12.x and later if( CURLE_OK != rc ){ std::cerr << '\t' << "Error from cURL: " << curl_easy_strerror( rc ) << std::endl ; } // cleanup curl_slist_free_all( responseHeaders ) ; curl_easy_cleanup( ctx ) ; curl_global_cleanup() ; std::exit( 0 ) ; } // main()
[ XCode ] writeToPList & getDictionaryFromPList
- (NSDictionary*)getDataFromPlist {
NSString *fileName = @"AppInfo.plist";
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:fileName];
NSDictionary *plistData = [[NSDictionary alloc] initWithContentsOfFile:finalPath];
NSLog(@"[getDataFromPlist] %@ content :: %@", fileName, plistData);
return plistData;
}
- (NSUInteger)writeToPlist:(NSUInteger)level withRow:(NSUInteger)row {
NSLog(@"[ writeToPlist ]");
NSString *fileName = @"AppInfo.plist";
NSArray *keys = [[NSArray alloc] initWithObjects:@"Elem", @"Pre", @"Inter", nil];
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:fileName];
NSMutableDictionary *plistData = [[NSMutableDictionary alloc] initWithContentsOfFile:finalPath];
NSMutableArray *contentArray = [plistData objectForKey:[keys objectAtIndex:level]];
[contentArray replaceObjectAtIndex:row withObject:@"1"];
[plistData setValue:contentArray forKey:[keys objectAtIndex:level]];
[plistData writeToFile:finalPath atomically:YES];
return 0;
}
[XCode 4.2] 허억!! IAP 테스트 해보기
[JSon] Xcode에 JSon 세팅하기 +_+
[XCode] Entitlements.plist is missing
[ Xcode + SVN ] trunk, tags, branches 의 용도
trunk
- 기본적으로 개발을 시작할 때 사용하는 디렉토리
- main, mainline, production의 의미로 사용됨
branches
- release 버전과 유지보수 버전을 분리하고 싶을 때 사용
- customizing이나 hot fix 목적으로 분리하여 수정함
- 수정이 계속해서 발생하다가 궁극적으로는 trunk에 merge 되는 것이 일반적임
tags
- 한번 만들면 수정하지 않음
- releases, snapshots, baselines의 의미로 사용됨
[출처] [SVN] trunk, tags, branches의 용도|작성자 밤바
[XCode] wait_fences: failed to receive reply:
[XCode] How to change .wav to .caf (AVAudioPlayer)
[XCode] To Change The Project Name Safety
so I've found a solution on internet.
- Close the project in Xcode
- Duplicate the project directory in the Finder by pressing Command-D.
- Rename the folder
- Open the folder and rename the “.xcodeproject” file
- Delete the “Build” sub folder, if there is one
- Open the renamed .xcodeproject file
- On the left in the “Groups&Files” list, expand the “Targets” group, double click on the target that still has your old project filename. Rename it under the “General”-tab in the window that opens.
- Select “Clean all targets” from the “Build” menu, keep the boxes checked, and click “Clean”.
- Build and run your project.
How about you ?
[From :
http://drjunker.org/2008/04/10/xcode-rename-project-and-application-change-copyright-and-version-number/]