Url.cpp

00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: Url.cpp * 00006 * * 00007 * * 00008 * * 00009 * ITEC institute of the University of Klagenfurt (Austria) * 00010 * http://www.itec.uni-klu.ac.at * 00011 * * 00012 * * 00013 * For more information visit the ViTooKi homepage: * 00014 * http://ViTooKi.sourceforge.net * 00015 * vitooki-user@lists.sourceforge.net * 00016 * vitooki-devel@lists.sourceforge.net * 00017 * * 00018 * This file is part of ViTooKi, a free video toolkit. * 00019 * ViTooKi is free software; you can redistribute it and/or * 00020 * modify it under the terms of the GNU General Public License * 00021 * as published by the Free Software Foundation; either version 2 * 00022 * of the License, or (at your option) any later version. * 00023 * * 00024 * This program is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU General Public License * 00030 * along with this program; if not, write to the Free Software * 00031 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00032 * MA 02111-1307, USA. * 00033 * * 00034 ***********************************************************************/ 00035 00036 /*********************************************************************** 00037 * * 00038 * REVISION HISTORY: * 00039 * * 00040 * * 00041 * * 00042 ***********************************************************************/ 00043 00044 #include "Url.hpp" 00045 #include <cstring> 00046 #include <cstdio> 00047 #include "debug.hpp" 00048 #include <assert.h> 00049 00050 #ifndef WINCE 00051 #include <errno.h> 00052 #endif 00053 00054 #include "global.hpp" 00055 00056 #ifndef WIN32 00057 #include <arpa/inet.h> 00058 #include <sys/types.h> 00059 #include <sys/socket.h> 00060 #include <netdb.h> 00061 #else 00062 #include <winsock2.h> 00063 #include <ws2tcpip.h> 00064 #ifndef WINCE 00065 #include <direct.h> 00066 #include <Wspiapi.h> 00067 #endif 00068 #endif 00069 00070 #ifndef NI_MAXHOST 00071 #define NI_MAXHOST 1025 00072 #endif 00073 00074 00075 00076 Url::Url(const char* url) 00077 { 00078 serverName=NULL; 00079 path=NULL; 00080 protocol=NULL; 00081 port=0; 00082 this->url=NULL; 00083 00084 dprintf_full("Url::Url parsing XXX%sXXX\n",url); 00085 if(url) { 00086 const char* pServerStart=url; 00087 if(url[0]=='/' || 00088 (strlen(url)>1 && url[1]==':') || 00089 strncmp(url,"file",4)==0 || 00090 strncmp(url,"FILE",4)==0) { 00091 handleLocalFile(url); 00092 return; 00093 } 00094 00095 pServerStart=strstr(pServerStart,"://"); 00096 if(pServerStart) { 00097 protocol=new char[pServerStart-url+1]; 00098 strncpy(protocol,url,pServerStart-url); 00099 protocol[pServerStart-url]='\0'; 00100 toLowerString(protocol); 00101 pServerStart+=3;// skip the :// 00102 } 00103 else { 00104 handleLocalFile(url); 00105 return; 00106 } 00107 00108 00109 const char* pPortStart=pServerStart; 00110 pPortStart=strchr(pPortStart,':'); 00111 if(pPortStart) { 00112 // we have a port 00113 // now extract the server name 00114 serverName=new char[pPortStart-pServerStart+1]; 00115 strncpy(serverName,pServerStart,pPortStart-pServerStart); 00116 serverName[pPortStart-pServerStart]='\0'; 00117 00118 pPortStart++; // go after the : 00119 00120 if(1!=sscanf(pPortStart,"%i",&port)) { 00121 port=-1; //invalid port 00122 pPortStart=pServerStart; 00123 } 00124 // search for a path after the (optional) port 00125 if(!strchr(pPortStart,'/')) { 00126 goto resolve; 00127 } 00128 } 00129 00130 else { 00131 pPortStart=pServerStart; 00132 } 00133 00134 // to get the servername find a / 00135 // if none -> there is no path 00136 pPortStart=strchr(pServerStart,'/'); 00137 if(!pPortStart && !serverName) { 00138 // we have no path 00139 serverName=new char[strlen(pServerStart)+1]; 00140 strcpy(serverName,pServerStart); 00141 } else { 00142 // we have a path 00143 // is it a trivial one -> just one / at end 00144 if(strlen(pPortStart)==1 && !serverName) { 00145 serverName=new char[strlen(pServerStart)]; 00146 // remove the / 00147 strncpy(serverName,pServerStart,strlen(pServerStart)-1); 00148 serverName[strlen(pServerStart)-1]='\0'; 00149 } else { 00150 if( !serverName ) { 00151 serverName=new char[pPortStart-pServerStart+1]; 00152 strncpy(serverName,pServerStart,pPortStart-pServerStart); 00153 serverName[pPortStart-pServerStart]='\0'; 00154 } 00155 // now get the path 00156 00157 path=new char[strlen(pPortStart)+1]; 00158 00159 strcpy(path,pPortStart); 00160 // remove \n or spaces from end 00161 char* pPath=path+strlen(path)-1; 00162 while( (*pPath)==' ' || (*pPath)=='\n' || (*pPath)=='\r') { 00163 *pPath='\0'; 00164 pPath--; 00165 } 00166 if(pPath <= path) { 00167 delete[] path; 00168 path=NULL; 00169 } 00170 } 00171 } 00172 00173 resolve: 00174 00175 /* 00176 //depricated gethostbyname+gethostbyaddr 00177 struct hostent *ipAddr; 00178 struct in_addr *in_a; 00179 00180 if(serverName) { 00181 dprintf_full("Url::Url resolving hostname for #%s#\n",serverName); 00182 00183 if ( (ipAddr = gethostbyname(serverName)) == NULL) { 00184 dprintf_err("Url::Url gethostbyname of server #%s# failed\n",serverName); 00185 } else { 00186 dprintf_full("Url::Url resolving hostbyaddr for #%s#\n",serverName); 00187 in_a = (struct in_addr *) ipAddr->h_addr; 00188 if ( (ipAddr = gethostbyaddr((char *) &in_a->s_addr, sizeof(unsigned long),AF_INET)) == NULL) { 00189 dprintf_err("Url::Url gethostbyaddr of server #%s# failed\n",serverName); 00190 } else { //set FQDN 00191 delete[] serverName; 00192 serverName = new char[NI_MAXHOST]; 00193 strcpy(serverName,ipAddr->h_name); 00194 dprintf_full("Url::constructor real server name: #%s#\n",serverName); 00195 } 00196 } 00197 } 00198 */ 00199 00200 00201 if(serverName) { 00202 dprintf_full("Url::Url resolving hostname for #%s#\n",serverName); 00203 struct addrinfo ai, *res_ai = NULL; 00204 int ret =0; 00205 00206 memset(&ai,0,sizeof(struct addrinfo)); 00207 ai.ai_flags = AI_CANONNAME; 00208 ai.ai_family = PF_UNSPEC; 00209 ai.ai_socktype = 0; 00210 ai.ai_protocol = 0; 00211 if ((ret = getaddrinfo(serverName, NULL, &ai, &res_ai)) < 0) 00212 { 00213 dprintf_err("ERROR %s\n",gai_strerror(ret)); 00214 ::exit(1); 00215 } 00216 //used for wince (there is no canonname) 00217 if (res_ai->ai_canonname != NULL) { 00218 delete[] serverName; 00219 serverName = new char[strlen(res_ai->ai_canonname)+1]; 00220 strcpy(serverName, res_ai->ai_canonname); 00221 } 00222 freeaddrinfo(res_ai); 00223 dprintf_full("Url::constructor real server name: #%s#\n",serverName); 00224 } 00225 makeUrl(); 00226 00227 } //if (url) 00228 } 00229 00230 Url::~Url() { 00231 if(serverName) delete[] serverName; 00232 if(path) delete[] path; 00233 if(protocol) delete[] protocol; 00234 if(url) delete[] url; 00235 }; 00236 00237 int Url::getPort() const { 00238 return port; 00239 } 00240 00241 void Url::setPort(int port) { 00242 this->port = port; 00243 makeUrl(); 00244 } 00245 00246 const char* Url::getPath() const { 00247 return path; 00248 }; 00249 00250 const char* Url::getFileName() const { 00251 const char *c; 00252 if ( !path ) 00253 return NULL; 00254 00255 if ((c=strrchr(path,'/')) == NULL) 00256 return NULL; 00257 else { 00258 if(c==(path+strlen(path)-1)) { // last char is a / 00259 return NULL; // no filename present 00260 } 00261 if(c[0]=='\\' || c[0]=='/') // absolute Linux&Windows path 00262 return c+1; 00263 } 00264 return NULL; 00265 }; 00266 00267 const char* Url::getServerName() const { 00268 return serverName; 00269 }; 00270 00271 const char* Url::getProtocol() const { 00272 return protocol; 00273 }; 00274 00275 bool Url::hasPort() const { 00276 return port>0; 00277 } 00278 00279 bool Url::hasServerName() const { 00280 return serverName!=NULL; 00281 }; 00282 00283 bool Url::hasPath() const { 00284 return path!=NULL; 00285 }; 00286 00287 bool Url::hasProtocol() const { 00288 return protocol!=NULL; 00289 }; 00290 00292 const char* Url::toString() const 00293 { 00294 return url; 00295 }; 00296 00297 void Url::makeUrl() 00298 { 00299 int len=20;// max size of itoa(int)+"://"+optional '/' and ":" 00300 if(!serverName) 00301 return; 00302 if(url) 00303 delete url; 00304 00305 if(protocol && hasPort() && hasPath()) { 00306 len+=strlen(protocol)+strlen(serverName)+strlen(path); 00307 url=new char[len]; 00308 len=snprintf(url,len,"%s://%s:%i%s",protocol,serverName,port,path); 00309 } 00310 else if(protocol && hasPort() && !hasPath()) { 00311 len+=strlen(protocol)+strlen(serverName); 00312 url=new char[len]; 00313 len=snprintf(url,len,"%s://%s:%i/",protocol,serverName,port); 00314 } 00315 else if(protocol && !hasPort() && hasPath()) { 00316 len+=strlen(protocol)+strlen(serverName)+strlen(path); 00317 url=new char[len]; 00318 if(path[1]==':' && isalpha(path[0])) 00319 len=snprintf(url,len,"%s://%s/%s",protocol,serverName,path); 00320 else 00321 len=snprintf(url,len,"%s://%s%s",protocol,serverName,path); 00322 } 00323 else if(protocol && !hasPort() && !hasPath()) { 00324 len+=strlen(protocol)+strlen(serverName); 00325 url=new char[len]; 00326 len=snprintf(url,512,"%s://%s/",protocol,serverName); 00327 } 00328 else if(!protocol && !hasPort() && hasPath()) { 00329 len+=strlen(path); 00330 url=new char[len]; 00331 len=snprintf(url,len,"%s",path); 00332 } 00333 else 00334 len=-1; 00335 00336 if(len<0) { 00337 dprintf_err("Url::toString: string overflow\n"); 00338 dprintf_small("%s",url); 00339 delete url;url=NULL; 00340 } 00341 00342 dprintf_full("Url::makeUrl %s\n",url); 00343 } 00344 00345 00346 char* Url::transformUrlToLocalFile(const Url* uri) 00347 { 00348 assert(uri); 00349 00350 const char* url=uri->toString(); 00351 if(!url) 00352 return NULL; 00353 00354 char* nUrl=new char[strlen(url)+1]; 00355 00356 for(uint i=0;i<strlen(url);i++) { 00357 if(isalnum(url[i]) || url[i]=='.') 00358 nUrl[i]=url[i]; 00359 else 00360 nUrl[i]='_'; 00361 } 00362 nUrl[strlen(url)]='\0'; 00363 dprintf_full("Url::transformUrl %s to LocalFile %s\r\n",url,nUrl); 00364 return nUrl; 00365 }; 00366 char* Url::transformPathToLocalFile(const Url* uri) 00367 { 00368 assert(uri); 00369 const char* url=uri->getPath(); 00370 if(!url) 00371 return NULL; 00372 uint i=0; 00373 if(!isalnum(url[i])) 00374 url++; 00375 00376 char* nUrl=new char[strlen(url)+1]; 00377 00378 for(i=0;i<strlen(url);i++) { 00379 if(isalnum(url[i]) || url[i]=='.') 00380 nUrl[i]=url[i]; 00381 else 00382 nUrl[i]='_'; 00383 } 00384 nUrl[strlen(url)]='\0'; 00385 dprintf_full("Url::transformPath %s to LocalFile %s\r\n",url,nUrl); 00386 return nUrl; 00387 } 00388 00389 bool Url::convertUrlToSocket(const char* serverName, const int port, 00390 struct sockaddr_in *server,int &outSocket) 00391 { 00392 if(!serverName) 00393 return false; 00394 assert(server); 00395 if(server==NULL) { 00396 dprintf_err("Url::convertUrlToSocket: NULL param passed for server\n"); 00397 return false; 00398 } 00399 outSocket=::socket(AF_INET,SOCK_STREAM,0); 00400 00401 if(outSocket<0) { 00402 dprintf_full("Url::convertUrlToSocket: Couldn't create socket for server %s\r\n",serverName); 00403 #ifdef WINCE 00404 dprintf_full("Url::convertUrlToSocket:: error numer: %d\n", WSAGetLastError()); 00405 #endif 00406 return false; 00407 } 00408 struct hostent *ipAddr; 00409 ipAddr=gethostbyname(serverName); 00410 if(!ipAddr) { 00411 dprintf_err("Url::convertUrlToSocket: DNS resolution failed for serverName %s\r\n",serverName); 00412 return false; 00413 } 00414 else { 00415 dprintf_full("Url::convertUrlToSocket: DNS returned %s for serverName %s\r\n", 00416 inet_ntoa( *((struct in_addr*)ipAddr->h_addr)),serverName); 00417 } 00418 00419 server->sin_port=htons(port); 00420 server->sin_addr.s_addr=inet_addr(ipAddr->h_addr); 00421 //memset(&(server->sin_zero),0,8); 00422 server->sin_family=AF_INET; 00423 memcpy((char *)&server->sin_addr, ipAddr->h_addr, ipAddr->h_length); 00424 00425 00426 if (::connect(outSocket,(struct sockaddr *)(server),sizeof(struct sockaddr)) != 0) { 00427 #ifdef WINCE 00428 dprintf_full("Url::convertUrlToSocket: Connect Failed for server %s Errno %i\r\n", 00429 serverName,WSAGetLastError()); 00430 #else 00431 dprintf_full("Url::convertUrlToSocket: Connect Failed for server %s Errno %i\r\n", 00432 serverName,errno); fflush(stdout); 00433 00434 perror("connect"); 00435 #endif 00436 00437 return false; 00438 } 00439 return true; 00440 }; 00441 bool Url::isEqual(const Url* uri,bool ignoreServerName) const 00442 { 00443 if(hasPath() && uri->hasPath() && 00444 getServerName() && uri->getServerName()) { 00445 bool ret=true; 00446 ret= (strcmp(uri->getPath(),getPath())==0); 00447 if(!ignoreServerName) 00448 ret&=(strcmp(getServerName(),uri->getServerName())==0); 00449 return ret; 00450 } 00451 00452 return false; 00453 }; 00454 00455 void Url::toLowerString(char* str) 00456 { 00457 if(str) { 00458 for(uint i=0;i<strlen(str);i++) { 00459 str[i]=(char)tolower(str[i]); 00460 } 00461 } 00462 } 00463 00464 void Url::handleLocalFile(const char* &url) 00465 { 00466 // valid input: file:// | /dummy/vid.mp4 | e:/ | E:backslash | dummy/test.mp4 00467 //resolves relative paths to absolute ones 00468 //also cuts off trailing (back)slash eg. /dummy/vid.mp4/ 00469 00470 if(!url) 00471 return; 00472 00473 const char* pPathBegin=url; 00474 pPathBegin=strchr(pPathBegin,'/'); 00475 if(!pPathBegin) { 00476 pPathBegin=strchr(url,'\\'); 00477 } 00478 if(!pPathBegin) 00479 pPathBegin=url; 00480 // e:/ or e:backslash 00481 if(pPathBegin && pPathBegin-url==2 && pPathBegin[-1]==':' && isalpha(pPathBegin[-2])) 00482 pPathBegin-=2; 00483 // file:// 00484 else if(strncmp(url,"FILE://",7)==0 || strncmp(url,"file://",7)==0) 00485 pPathBegin=url+7; 00486 else { 00487 // else pPathBegin==url for /dummy.mp4 and dummy/test.mp4 00488 // check for relative path 00489 if(url[0]=='/' || url[0]=='\\') 00490 pPathBegin=url; // probably redundant but better make sure 00491 else { // invalid relative path, so make absolute path.... 00492 char *cwd = new char[MAX_STR_LEN]; 00493 cwd[0] = 0; 00494 #ifndef WIN32 00495 assert(getcwd(cwd,MAX_STR_LEN - strlen(url) - 2 )); //if NULL, there was not enough buffer! 00496 #else 00497 #ifdef WINCE 00498 GetModuleFileName(NULL, (unsigned short*)cwd, MAX_STR_LEN); 00499 #else 00500 assert(_getcwd(cwd,MAX_STR_LEN - strlen(url) - 2 )); //if NULL, there was not enough buffer! 00501 #endif 00502 #endif 00503 strcat(cwd,"/"); 00504 strcat(cwd,url); 00505 dprintf_full("Url::handleLocalFile: make absolute file path #%s#\n",cwd); 00506 pPathBegin=cwd; 00507 } 00508 } 00509 // protocol is always file 00510 protocol=new char[5]; 00511 strcpy(protocol,"file"); 00512 // now detect the path end 00513 const char* pPathEnd=pPathBegin+strlen(pPathBegin); 00514 00515 00516 if(pPathBegin && pPathEnd && pPathEnd-pPathBegin>1) { 00517 //we have a path 00518 path=new char[pPathEnd-pPathBegin+2]; 00519 strncpy(path,pPathBegin,pPathEnd-pPathBegin+1); 00520 path[pPathEnd-pPathBegin+1]='\0'; 00521 00522 // we have a local file, thus we correct all '\' to '/' in the path 00523 for(uint i=0;i<strlen(path);i++) { 00524 if(path[i]=='\\') 00525 path[i]='/'; 00526 } 00527 if ( (path[strlen(path)-1] == '/') || 00528 (path[strlen(path)-1] == '\\')) //cut off trailing (back)slash 00529 path[strlen(path)-1] = '\0'; 00530 00531 } 00532 serverName=new char[10]; 00533 //strcpy(serverName,"localhost"); 00534 strcpy(serverName,""); 00535 makeUrl(); 00536 } 00537 00538 00539 void Url::doTest() 00540 { 00541 Url u1("file://e:/test.mp4"); 00542 assert(u1.toString()); 00543 assert(strcmp(u1.getPath(),"e:/test.mp4")==0); 00544 printf("FileName of %s is %s\n",u1.toString(),u1.getFileName()); 00545 assert(strcmp(u1.getFileName(),"test.mp4")==0); 00546 00547 Url u2("FILE://e:\\test.mp4"); 00548 assert(u2.toString()); 00549 assert(strcmp(u2.getPath(),"e:/test.mp4")==0); 00550 assert(strcmp(u2.getFileName(),"test.mp4")==0); 00551 00552 Url u3("file://e:/dummy/dir/test.mp4"); 00553 assert(u3.toString()); 00554 Url u4("FILE://e:\\dummy\\dir\\test.mp4"); 00555 assert(u4.toString()); 00556 Url u5("test.mp4"); 00557 assert(u5.toString()==NULL); 00558 Url u6("/test.mp4"); 00559 assert(u6.toString()); 00560 printf("%s\n",u1.toString()); 00561 printf("%s\n",u2.toString()); 00562 printf("%s\n",u3.toString()); 00563 printf("%s\n",u4.toString()); 00564 printf("%s\n",u5.toString()); 00565 printf("%s\n",u6.toString()); 00566 00567 assert(strcmp(u1.toString(),u2.toString())==0); 00568 assert(strcmp(u3.toString(),u4.toString())==0); 00569 } 00570 00571