trunk: exiv2 v0.25
This commit is contained in:
+345
-29
@@ -29,13 +29,8 @@
|
||||
#include "rcsid_int.hpp"
|
||||
EXIV2_RCSID("@(#) $Id$")
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#ifdef _MSC_VER
|
||||
# include "exv_msvc.h"
|
||||
#else
|
||||
# include "exv_conf.h"
|
||||
#endif
|
||||
#include "config.h"
|
||||
|
||||
#include "futils.hpp"
|
||||
|
||||
@@ -52,6 +47,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||
#include <cerrno>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined EXV_HAVE_STRERROR_R && !defined EXV_HAVE_DECL_STRERROR_R
|
||||
# ifdef EXV_STRERROR_R_CHAR_P
|
||||
@@ -62,14 +58,237 @@ extern int strerror_r(int errnum, char *buf, size_t n);
|
||||
#endif
|
||||
|
||||
namespace Exiv2 {
|
||||
|
||||
const char* ENVARDEF[] = {"/exiv2.php", "40"};
|
||||
const char* ENVARKEY[] = {"EXIV2_HTTP_POST", "EXIV2_TIMEOUT"};
|
||||
// *****************************************************************************
|
||||
// free functions
|
||||
std::string getEnv(EnVar var) {
|
||||
return getenv(ENVARKEY[var]) ? getenv(ENVARKEY[var]) : ENVARDEF[var];
|
||||
} // getEnv
|
||||
|
||||
char to_hex(char code) {
|
||||
static char hex[] = "0123456789abcdef";
|
||||
return hex[code & 15];
|
||||
} // to_hex
|
||||
|
||||
char from_hex(char ch) {
|
||||
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
|
||||
} // from_hex
|
||||
|
||||
char* urlencode(char* str) {
|
||||
char* pstr = str;
|
||||
char* buf = (char*)malloc(strlen(str) * 3 + 1);
|
||||
char* pbuf = buf;
|
||||
while (*pstr) {
|
||||
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
|
||||
*pbuf++ = *pstr;
|
||||
else if (*pstr == ' ')
|
||||
*pbuf++ = '+';
|
||||
else
|
||||
*pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
|
||||
pstr++;
|
||||
}
|
||||
*pbuf = '\0';
|
||||
return buf;
|
||||
} // urlencode
|
||||
|
||||
char* urldecode(const char* str) {
|
||||
const char* pstr = str;
|
||||
char* buf = (char*)malloc(strlen(str) + 1);
|
||||
char* pbuf = buf;
|
||||
while (*pstr) {
|
||||
if (*pstr == '%') {
|
||||
if (pstr[1] && pstr[2]) {
|
||||
*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
|
||||
pstr += 2;
|
||||
}
|
||||
} else if (*pstr == '+') {
|
||||
*pbuf++ = ' ';
|
||||
} else {
|
||||
*pbuf++ = *pstr;
|
||||
}
|
||||
pstr++;
|
||||
}
|
||||
*pbuf = '\0';
|
||||
return buf;
|
||||
} // urldecode
|
||||
|
||||
void urldecode(std::string& str) {
|
||||
char* decodeStr = Exiv2::urldecode(str.c_str());
|
||||
str = std::string(decodeStr);
|
||||
free(decodeStr);
|
||||
} // urldecode(const std::string& str)
|
||||
|
||||
int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize) {
|
||||
const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
const uint8_t* data = (const uint8_t*)data_buf;
|
||||
size_t resultIndex = 0;
|
||||
size_t x;
|
||||
uint32_t n = 0;
|
||||
size_t padCount = dataLength % 3;
|
||||
uint8_t n0, n1, n2, n3;
|
||||
|
||||
/* increment over the length of the string, three characters at a time */
|
||||
for (x = 0; x < dataLength; x += 3)
|
||||
{
|
||||
/* these three 8-bit (ASCII) characters become one 24-bit number */
|
||||
n = data[x] << 16;
|
||||
|
||||
if((x+1) < dataLength)
|
||||
n += data[x+1] << 8;
|
||||
|
||||
if((x+2) < dataLength)
|
||||
n += data[x+2];
|
||||
|
||||
/* this 24-bit number gets separated into four 6-bit numbers */
|
||||
n0 = (uint8_t)(n >> 18) & 63;
|
||||
n1 = (uint8_t)(n >> 12) & 63;
|
||||
n2 = (uint8_t)(n >> 6) & 63;
|
||||
n3 = (uint8_t)n & 63;
|
||||
|
||||
/*
|
||||
* if we have one byte available, then its encoding is spread
|
||||
* out over two characters
|
||||
*/
|
||||
if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */
|
||||
result[resultIndex++] = base64chars[n0];
|
||||
if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */
|
||||
result[resultIndex++] = base64chars[n1];
|
||||
|
||||
/*
|
||||
* if we have only two bytes available, then their encoding is
|
||||
* spread out over three chars
|
||||
*/
|
||||
if((x+1) < dataLength)
|
||||
{
|
||||
if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */
|
||||
result[resultIndex++] = base64chars[n2];
|
||||
}
|
||||
|
||||
/*
|
||||
* if we have all three bytes available, then their encoding is spread
|
||||
* out over four characters
|
||||
*/
|
||||
if((x+2) < dataLength)
|
||||
{
|
||||
if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */
|
||||
result[resultIndex++] = base64chars[n3];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* create and add padding that is required if we did not have a multiple of 3
|
||||
* number of characters available
|
||||
*/
|
||||
if (padCount > 0)
|
||||
{
|
||||
for (; padCount < 3; padCount++)
|
||||
{
|
||||
if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */
|
||||
result[resultIndex++] = '=';
|
||||
}
|
||||
}
|
||||
if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */
|
||||
result[resultIndex] = 0;
|
||||
return 1; /* indicate success */
|
||||
} // base64encode
|
||||
|
||||
long base64decode(const char *in, char *out, size_t out_size) {
|
||||
static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW"
|
||||
"$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
|
||||
long len;
|
||||
long i;
|
||||
long done = 0;
|
||||
unsigned char v;
|
||||
unsigned char quad[4];
|
||||
|
||||
while (*in) {
|
||||
len = 0;
|
||||
for (i = 0; i < 4 && *in; i++) {
|
||||
v = 0;
|
||||
while (*in && !v) {
|
||||
v = *in++;
|
||||
v = (v < 43 || v > 122) ? 0 : decode[v - 43];
|
||||
if (v)
|
||||
v = (v == '$') ? 0 : v - 61;
|
||||
if (*in) {
|
||||
len++;
|
||||
if (v)
|
||||
quad[i] = v - 1;
|
||||
} else
|
||||
quad[i] = 0;
|
||||
}
|
||||
}
|
||||
if (!len)
|
||||
continue;
|
||||
if (out_size < (size_t) (done + len - 1))
|
||||
/* out buffer is too small */
|
||||
return -1;
|
||||
if (len >= 2)
|
||||
*out++ = quad[0] << 2 | quad[1] >> 4;
|
||||
if (len >= 3)
|
||||
*out++ = quad[1] << 4 | quad[2] >> 2;
|
||||
if (len >= 4)
|
||||
*out++ = ((quad[2] << 6) & 0xc0) | quad[3];
|
||||
done += len - 1;
|
||||
}
|
||||
if ((size_t)(done + 1) >= out_size)
|
||||
return -1;
|
||||
*out++ = '\0';
|
||||
return done;
|
||||
} // base64decode
|
||||
|
||||
Protocol fileProtocol(const std::string& path) {
|
||||
Protocol result = pFile ;
|
||||
static Exiv2::protDict_t protDict;
|
||||
if (!protDict.size()) {
|
||||
protDict["http://" ] = pHttp;
|
||||
protDict["ftp://" ] = pFtp;
|
||||
protDict["https://"] = pHttps;
|
||||
protDict["sftp://" ] = pSftp;
|
||||
protDict["ssh://" ] = pSsh;
|
||||
protDict["file://" ] = pFileUri;
|
||||
protDict["data:" ] = pDataUri;
|
||||
protDict["-" ] = pStdin;
|
||||
}
|
||||
for (Exiv2::protDict_i it = protDict.begin(); it != protDict.end(); it++) {
|
||||
if (path.find(it->first) == 0)
|
||||
result = it->second;
|
||||
}
|
||||
return result;
|
||||
} // fileProtocol
|
||||
#ifdef EXV_UNICODE_PATH
|
||||
Protocol fileProtocol(const std::wstring& wpath) {
|
||||
Protocol result = pFile ;
|
||||
static wprotDict_t protDict;
|
||||
if (!protDict.size()) {
|
||||
protDict[L"http://" ] = pHttp;
|
||||
protDict[L"ftp://" ] = pFtp;
|
||||
protDict[L"https://" ] = pHttps;
|
||||
protDict[L"sftp://" ] = pSftp;
|
||||
protDict[L"ssh://" ] = pSsh;
|
||||
protDict[L"file:///" ] = pFileUri;
|
||||
protDict[L"data:" ] = pDataUri;
|
||||
protDict[L"-" ] = pStdin;
|
||||
}
|
||||
for (wprotDict_i it = protDict.begin(); it != protDict.end(); it++) {
|
||||
if (wpath.find(it->first) == 0) {
|
||||
result = it->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} // fileProtocol
|
||||
#endif
|
||||
bool fileExists(const std::string& path, bool ct)
|
||||
{
|
||||
// special case: accept "-" (means stdin)
|
||||
if (path.compare("-") == 0 || fileProtocol(path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct stat buf;
|
||||
int ret = ::stat(path.c_str(), &buf);
|
||||
int ret = ::stat(path.c_str(), &buf);
|
||||
if (0 != ret) return false;
|
||||
if (ct && !S_ISREG(buf.st_mode)) return false;
|
||||
return true;
|
||||
@@ -78,6 +297,11 @@ namespace Exiv2 {
|
||||
#ifdef EXV_UNICODE_PATH
|
||||
bool fileExists(const std::wstring& wpath, bool ct)
|
||||
{
|
||||
// special case: accept "-" (means stdin)
|
||||
if (wpath.compare(L"-") == 0 || fileProtocol(wpath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct _stat buf;
|
||||
int ret = _wstat(wpath.c_str(), &buf);
|
||||
if (0 != ret) return false;
|
||||
@@ -86,32 +310,37 @@ namespace Exiv2 {
|
||||
} // fileExists
|
||||
|
||||
#endif
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
// Linux GCC 4.8 appears to be confused about strerror_r
|
||||
#ifndef EXV_STRERROR_R_CHAR_P
|
||||
#ifdef __gnu_linux__
|
||||
#define EXV_STRERROR_R_CHAR_P
|
||||
std::string pathOfFileUrl(const std::string& url) {
|
||||
std::string path = url.substr(7);
|
||||
size_t found = path.find('/');
|
||||
if (found == std::string::npos) return path;
|
||||
else return path.substr(found);
|
||||
}
|
||||
#ifdef EXV_UNICODE_PATH
|
||||
std::wstring pathOfFileUrl(const std::wstring& wurl) {
|
||||
std::wstring path = wurl.substr(7);
|
||||
int found = path.find('/');
|
||||
if (found == std::wstring::npos) return path;
|
||||
else return path.substr(found);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::string strError()
|
||||
{
|
||||
int error = errno;
|
||||
int error = errno;
|
||||
std::ostringstream os;
|
||||
#ifdef EXV_HAVE_STRERROR_R
|
||||
#ifdef EXV_HAVE_STRERROR_R
|
||||
const size_t n = 1024;
|
||||
char buff[n];
|
||||
std::memset(buff, 0x0, n);
|
||||
// _GNU_SOURCE: See Debian bug #485135
|
||||
#ifdef EXV_STRERROR_R_CHAR_P
|
||||
char* buf = strerror_r(error, buff, n);
|
||||
#else
|
||||
char* buf = buff;
|
||||
int dummy = strerror_r(error, buff, n);
|
||||
UNUSED(dummy);
|
||||
#endif
|
||||
// _GNU_SOURCE: See Debian bug #485135
|
||||
# if defined EXV_STRERROR_R_CHAR_P && defined _GNU_SOURCE
|
||||
char *buf = 0;
|
||||
char buf2[n];
|
||||
std::memset(buf2, 0x0, n);
|
||||
buf = strerror_r(error, buf2, n);
|
||||
# else
|
||||
char buf[n];
|
||||
std::memset(buf, 0x0, n);
|
||||
strerror_r(error, buf, n);
|
||||
# endif
|
||||
os << buf;
|
||||
// Issue# 908.
|
||||
// report strerror() if strerror_r() returns empty
|
||||
@@ -123,4 +352,91 @@ namespace Exiv2 {
|
||||
return os.str();
|
||||
} // strError
|
||||
|
||||
void Uri::Decode(Uri& uri)
|
||||
{
|
||||
urldecode(uri.QueryString);
|
||||
urldecode(uri.Path);
|
||||
urldecode(uri.Host);
|
||||
urldecode(uri.Username);
|
||||
urldecode(uri.Password);
|
||||
}
|
||||
|
||||
Uri Uri::Parse(const std::string &uri)
|
||||
{
|
||||
Uri result;
|
||||
|
||||
typedef std::string::const_iterator iterator_t;
|
||||
|
||||
if ( !uri.length() ) return result;
|
||||
|
||||
iterator_t uriEnd = uri.end();
|
||||
|
||||
// get query start
|
||||
iterator_t queryStart = std::find(uri.begin(), uriEnd, '?');
|
||||
|
||||
// protocol
|
||||
iterator_t protocolStart = uri.begin();
|
||||
iterator_t protocolEnd = std::find(protocolStart, uriEnd, ':'); //"://");
|
||||
|
||||
if (protocolEnd != uriEnd)
|
||||
{
|
||||
std::string prot = &*(protocolEnd);
|
||||
if ((prot.length() > 3) && (prot.substr(0, 3) == "://"))
|
||||
{
|
||||
result.Protocol = std::string(protocolStart, protocolEnd);
|
||||
protocolEnd += 3; // ://
|
||||
}
|
||||
else
|
||||
protocolEnd = uri.begin(); // no protocol
|
||||
}
|
||||
else
|
||||
protocolEnd = uri.begin(); // no protocol
|
||||
|
||||
//username & password
|
||||
iterator_t authStart = protocolEnd;
|
||||
iterator_t authEnd = std::find(protocolEnd, uriEnd, '@');
|
||||
if (authEnd != uriEnd) {
|
||||
iterator_t userStart = authStart;
|
||||
iterator_t userEnd = std::find(authStart, authEnd, ':');
|
||||
if (userEnd != authEnd) {
|
||||
result.Username = std::string(userStart, userEnd);
|
||||
userEnd++;
|
||||
result.Password = std::string(userEnd, authEnd);
|
||||
} else {
|
||||
result.Username = std::string(authStart, authEnd);
|
||||
}
|
||||
authEnd++;
|
||||
} else {
|
||||
authEnd = protocolEnd;
|
||||
}
|
||||
|
||||
// host
|
||||
iterator_t hostStart = authEnd;
|
||||
iterator_t pathStart = std::find(hostStart, uriEnd, '/'); // get pathStart
|
||||
|
||||
iterator_t hostEnd = std::find(authEnd,
|
||||
(pathStart != uriEnd) ? pathStart : queryStart,
|
||||
':'); // check for port
|
||||
|
||||
result.Host = std::string(hostStart, hostEnd);
|
||||
|
||||
// port
|
||||
if ((hostEnd != uriEnd) && ((&*(hostEnd))[0] == ':')) // we have a port
|
||||
{
|
||||
hostEnd++;
|
||||
iterator_t portEnd = (pathStart != uriEnd) ? pathStart : queryStart;
|
||||
result.Port = std::string(hostEnd, portEnd);
|
||||
}
|
||||
if ( !result.Port.length() && result.Protocol == "http" ) result.Port = "80";
|
||||
|
||||
// path
|
||||
if (pathStart != uriEnd)
|
||||
result.Path = std::string(pathStart, queryStart);
|
||||
|
||||
// query
|
||||
if (queryStart != uriEnd)
|
||||
result.QueryString = std::string(queryStart, uri.end());
|
||||
|
||||
return result;
|
||||
} // Uri::Parse
|
||||
} // namespace Exiv2
|
||||
|
||||
Reference in New Issue
Block a user