/** * ======================== legal notice ====================== * * File: Url.cc * Created: 4. Juli 2012, 05 * Author: Geronimo * Project: libutil - base classes used by other libraries * * CMP - compound media player * * is a client/server mediaplayer intended to play any media from any workstation * without the need to export or mount shares. cmps is an easy to use backend * with a (ready to use) HTML-interface. Additionally the backend supports * authentication via HTTP-digest authorization. * cmpc is a client with vdr-like osd-menues. * * Copyright (c) 2012 Reinhard Mantey, some rights reserved! * published under Creative Commons by-sa * For details see http://creativecommons.org/licenses/by-sa/3.0/ * * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp * * -------------------------------------------------------------- */ #include #include #include #ifdef DEBUG #include #endif #include #include #include static cURLEncoder * encoder = NULL; static cURLDecoder * decoder = NULL; cUrl::cUrl(const char* RawURL) : path(NULL) { ParseURL(RawURL); } cUrl::~cUrl() { FREE(path); } cURLDecoder* cUrl::Decoder(void) { if (!decoder) decoder = new cURLDecoder(); return decoder; } cURLEncoder* cUrl::Encoder(void) { if (!encoder) encoder = new cURLEncoder(); return encoder; } const char *cUrl::Parameter(const char* Name) { std::tr1::unordered_map::iterator found = parameters.find(Name); if (found != parameters.end()) return found->second.c_str(); return NULL; } void cUrl::SetParameter(const char* Name, const char* Value) { std::string name = Name; std::string value = Value ? Value : " "; parameters[name] = value; } size_t cUrl::EstimatedSize(void ) const { size_t rv = parameters.size() * 3; if (path) rv += strlen(path) + 4; ParameterMap::const_iterator pm = parameters.begin(); while (pm != parameters.end()) { rv += pm->first.length() * 3; rv += pm->second.length() * 3; ++pm; } return rv; } void cUrl::ParseURL(const char *URL) { FREE(path); parameters.clear(); if (!URL) return; const char *q = strchr(URL, '?'); // divider between url and querystring // char *realURL; // size_t l; if (!q) q = URL + strlen(URL); // l = q - URL; // realURL = (char *)malloc(l + 2); // if (!realURL) return; // strncpy(realURL, URL, l); // realURL[l] = 0; path = Decoder()->Decode(URL, q - URL); if (*q) ParseQueryString(++q); } void cUrl::ParseQueryString(const char* QueryString) { if (!(QueryString && *QueryString)) return; const char *start, *last; char *scratch = strdup(QueryString); char *p, *end; size_t srcLen = strlen(QueryString); for (start = (const char *)scratch, end = (char *) start, last = scratch + srcLen; end && start < last; start = (const char *)++end) { end = (char *) strchr(start, '&'); if (!end) end = (char *)start + strlen(start); *end = 0; p = (char *) strchr(start, '='); if (p) { *p++ = 0; char *pn = p ? Decoder()->Decode(start) : NULL; char *pv = p ? Decoder()->Decode(p) : NULL; std::string name = pn; std::string value = pv ? pv : " "; parameters[name] = value; free(pn); free(pv); } else { char *pn = Decoder()->Decode(start); std::string name = pn; parameters[name] = " "; free(pn); } } free(scratch); } char* cUrl::ToString(void) const ///< returns the address of the newly allocated buffer { size_t bufSize = EstimatedSize(); char *rv = (char *)malloc(bufSize); if (!rv) return NULL; int n = WriteBuf(rv, bufSize); if (n < 0) { bufSize += 128; rv = (char *) realloc(rv, bufSize); WriteBuf(rv, bufSize); } return rv; } int cUrl::WriteBuf(char* buf, size_t bufSize) const ///< returns the characters written. -1 as return value indicates a buffer overrun. { char *p, *tmp; bool first = true; int n = 0; if (path) n += snprintf(buf + n, bufSize - n, "%s", path); p = buf + n; ParameterMap::const_iterator pm = parameters.begin(); while (pm != parameters.end()) { tmp = Encoder()->Encode(pm->first.c_str()); if (p - buf + strlen(tmp) + 2 > bufSize) return -1; if (first) { first = false; *p++ = '?'; } else *p++ = '&'; strcpy(p, tmp); p += strlen(p); FREE(tmp); if (strcmp(pm->second.c_str(), " ")) { tmp = Encoder()->Encode(pm->second.c_str()); if (p - buf + strlen(tmp) + 2 > bufSize) return -1; *p++ = '='; strcpy(p, tmp); p += strlen(p); FREE(tmp); } ++pm; } p += strlen(p); return p - buf; } #ifdef DEBUG void cUrl::Dump(void ) { ParameterMap::const_iterator pm = parameters.begin(); while (pm != parameters.end()) { std::cout << "parameter [" << pm->first << "]"; if (strcmp(pm->second.c_str(), " ")) std::cout << " has value <|" << pm->second << "|>" << std::endl; else std::cout << " has NO value!" << std::endl; ++pm; } } #endif void cUrl::Cleanup(void ) { if (encoder) { delete encoder; encoder = NULL; } if (decoder) { delete decoder; decoder = NULL; } }