📄 flickr.cpp
字号:
/*
cppFlickr
Copyright (c) 2005, Gareth Simpson (http://www.xurble.org/)
All rights reserved.
See License.txt for terms and conditions.
*/
#include "stdafx.h"
#include "Flickr.h"
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>
#include <libxml/nanohttp.h>
#include "iconv.h"
#include <sstream>
#include <vector>
#include <algorithm>
namespace cppFlickr
{
static const char DEFAULT_URL[] = "http://www.flickr.com/services/rest/";
//------------------------------------------------------------------------------------------
//Ctor
Flickr::Flickr()
{
m_baseURL = DEFAULT_URL;
}
//------------------------------------------------------------------------------------------
//Ctor
Flickr::Flickr(const std::wstring& apikey,const std::wstring& email,const std::wstring& password)
{
m_baseURL = DEFAULT_URL;
m_email = urlEncode(makeUTF(email));
m_password = urlEncode(makeUTF(password));
m_emailRaw = makeUTF(email);
m_passwordRaw =makeUTF(password);
m_apiKey = makeUTF(apikey);
// uncomment if using fiddler
//xmlNanoHTTPScanProxy("http://127.0.0.1:8888/");
}
//------------------------------------------------------------------------------------------
// Ascii to wide
std::wstring Flickr::makeWide(const std::string& in)
{
// TODO: Use iconv here for cross platformness
std::wstring retStr = L"UTF Conversion Failure"; // TODO: Something better here!
int len = (int)in.length() + 1;
if(len > 0)
{
wchar_t* wideBuffer = new wchar_t[len+1];
memset(wideBuffer,0,(sizeof(wchar_t) * (len+1)));
int ret = MultiByteToWideChar(CP_UTF8,0,in.c_str(),(int)in.length()+1,wideBuffer,len);
if(ret > 0)
{
retStr = wideBuffer;
}
delete[] wideBuffer;
}
return retStr;
}
//------------------------------------------------------------------------------------------
// convert wide to ascii
std::string Flickr::makeUTF(const std::wstring& str)
{
int l =static_cast<int>(str.length());
int sz=::WideCharToMultiByte(CP_UTF8,0,str.c_str(),l,0,0,0,0);
std::vector<char> buffer;
buffer.resize(sz);
::WideCharToMultiByte(CP_UTF8,0,str.c_str(),l,&buffer[0],sz,0,0);
return std::string(buffer.begin(),buffer.end());
}
//------------------------------------------------------------------------------------------
//Add a note at the specified co-ordinates
int Flickr::addNote(int photoID,int x,int y, int width, int height, const std::wstring& text,int& retID)
{
int ret = -1;
std::stringstream url;
url << m_baseURL << "?";
// Build the request string
url << "method=flickr.photos.notes.add&api_key=" << m_apiKey << "&photo_id=" << photoID;
// params
url << "¬e_x=" << x << "¬e_y=" << y << "¬e_w=" << width << "¬e_h=" << height << "¬e_text=" << urlEncode(makeUTF(text));
// authentication
url << "&email=" << m_email << "&password=" << m_password;
xmlDocPtr doc = (xmlDocPtr)doGet(url.str());
if(doc)
{
// make sure that document is not an error
ret = checkError(doc);
if(ret == 0)
{
xmlNodePtr root = xmlDocGetRootElement(doc);
xmlNodePtr idNode = root->xmlChildrenNode->next;
xmlChar* id = xmlGetProp(idNode,(const xmlChar *)"id");
retID = atoi((const char*)id);
xmlFree(id);
}
xmlFreeDoc(doc);
/*
*Free the global variables that may
*have been allocated by the parser.
*/
xmlCleanupParser();
}
return ret;
}
//------------------------------------------------------------------------------------------
// Add tags to the photo
int Flickr::addTags(int photoID, const std::wstring& tags)
{
std::stringstream url;
url << m_baseURL << "?";
// Build the request string
url << "method=flickr.photos.addTags&api_key=" << m_apiKey << "&photo_id=" << photoID << "&tags=" << urlEncode(makeUTF(tags));
// authentication
url << "&email=" << m_email << "&password=" << m_password;
return simpleUpdate(url.str());
}
//------------------------------------------------------------------------------------------
// replace the tags on the photo with a new set
int Flickr::setTags(int photoID, const std::wstring& tags)
{
std::stringstream url;
url << m_baseURL << "?";
// Build the request string
url << "method=flickr.photos.setTags&api_key=" << m_apiKey << "&photo_id=" << photoID << "&tags=" << urlEncode(makeUTF(tags));
// authentication
url << "&email=" << m_email << "&password=" << m_password;
return simpleUpdate(url.str());
}
//------------------------------------------------------------------------------------------
// This function will check if the passed in document is a fail response
// if it is, we parse out the error message and response code
int Flickr::checkError(void* doc)
{
int ret = 0;
xmlDocPtr xmlDoc = (xmlDocPtr)doc;
xmlNodePtr root = xmlDocGetRootElement(xmlDoc);
xmlChar* stat = xmlGetProp(root,(const xmlChar *)"stat");
if(xmlStrcmp(stat,(const xmlChar *)"ok"))
{
xmlNodePtr codeNode = root->xmlChildrenNode->next;
xmlChar* msg = xmlGetProp(codeNode,(const xmlChar *)"msg");
xmlChar* code = xmlGetProp(codeNode,(const xmlChar *)"code");
m_errorMsg = makeWide((char*)msg);
ret = atoi((const char*)code);
if (ret == 0) ret = -2;
xmlFree(msg);
xmlFree(code);
}
else
{
// It was OK!
m_errorMsg = L"OK";
}
xmlFree(stat);
return ret;
}
//------------------------------------------------------------------------------------------
// performs the passed in get operation and returns the XML result
void* Flickr::doGet(const std::string& url)
{
xmlDocPtr doc = 0;
// send it
void* ctx = xmlNanoHTTPMethod(url.c_str(),"GET",0,0,0,0);
if(ctx)
{
// some kind of response
std::stringstream response;
// get the XML that is returned
while(true)
{
char buf[1024];
int read = xmlNanoHTTPRead(ctx,buf,1023);
if(read > 0)
{
buf[read] = 0;
response << buf;
}
if (read < 1023)
break;
}
xmlNanoHTTPClose(ctx);
// parse it into a document
doc = xmlReadMemory(response.str().c_str(),(int)response.str().length(),m_baseURL.c_str(),0, XML_PARSE_NONET );
if(!doc)
{
m_errorMsg = L"Server response was invalid";
}
}
else
{
m_errorMsg = L"Could not connect to the server";
}
return doc;
}
//------------------------------------------------------------------------------------------
// Performs simple sets which don't retrieve results
int Flickr::simpleUpdate(const std::string& url)
{
int ret = -1;
xmlDocPtr doc = (xmlDocPtr)doGet(url);
if(doc)
{
// make sure that document is not an error
ret = checkError(doc);
xmlFreeDoc(doc);
/*
*Free the global variables that may
*have been allocated by the parser.
*/
xmlCleanupParser();
}
return ret;
}
//------------------------------------------------------------------------------------------
// replace with something standard ???
std::string Flickr::urlEncode(const std::string& str)
{
std::stringstream ret;
for(size_t i =0; i < str.length(); ++i)
{
char c = str[i];
if((c >= 48 && c <= 57) ||
(c >= 65 && c <= 90) ||
(c >= 97 && c <= 122))
{
ret << c;
}
else if(c == 32)
{
ret << "+";
}
else
{
char buf[5];
sprintf(buf,"%%%00x",c);
ret << buf;
}
}
return ret.str();
}
//------------------------------------------------------------------------------------------
// This is the heart of it
// default jpeg version
int Flickr::uploadFile(const std::wstring& path,const std::wstring& title,const std::wstring& description, const std::wstring& tags, bool isPublic, bool isFriend,bool isFamily,int& retID)
{
return uploadFile(path,title,description,tags,isPublic,isFriend,isFamily,L"image/jpeg",retID);
}
// Full on version
int Flickr::uploadFile(const std::wstring& path,const std::wstring& title,const std::wstring& description, const std::wstring& tags, bool isPublic, bool isFriend,bool isFamily,const std::wstring& imgMime, int& retID)
{
const char targetURL[] = "http://www.flickr.com/tools/uploader_go.gne";
//const char targetURL[] = "http://www.flickr.com/tools/uploader_test.gne";
char* contentType = "multipart/form-data; boundary=\"cppFlickrBoundry\"";
std::stringstream header;
header << "--cppFlickrBoundry\r\n";
header << "Content-Disposition: form-data; name=\"email\"\r\n\r\n" << m_emailRaw << "\r\n";
header << "--cppFlickrBoundry\r\n";
header << "Content-Disposition: form-data; name=\"password\"\r\n\r\n" << m_passwordRaw << "\r\n";
if(title.length())
{
header << "--cppFlickrBoundry\r\n";
header << "Content-Disposition: form-data; name=\"title\"\r\n\r\n" << makeUTF(title) << "\r\n";
}
if(description.length())
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -