home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 June / PCWorld_2003-06_cd.bin / KOMUNIK / MIRRORIT / SRC / URL.CPP < prev    next >
C/C++ Source or Header  |  1997-12-27  |  9KB  |  478 lines

  1. // URL.cpp : implementation file
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "URL.h"
  6.  
  7. #ifdef _DEBUG
  8. #define new DEBUG_NEW
  9. #undef THIS_FILE
  10. static char THIS_FILE[] = __FILE__;
  11. #endif
  12.  
  13. #define SAFE            "$-_.+"
  14. #define EXTRA           "!*'(),"
  15. #define NATIONAL        "{}|\\^~[]`"
  16. #define RESERVED        ";/?:@&="
  17. #define PUNCTUATION     "<>#%\""
  18. #define DIGIT           "0123456789"
  19. #define HEX             DIGIT "ABCDEF"
  20. #define ESCAPE          HEX "%"
  21. #define LOWALPHA        "abcdefghijklmnopqrstuvwxyz"
  22. #define HIGHALPHA       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  23. #define ALPHA           LOWALPHA HIGHALPHA
  24. #define UNRESERVED      ALPHA SAFE EXTRA NATIONAL
  25. #define UCHAR           UNRESERVED ESCAPE
  26. #define PCHAR           UCHAR ":@&="
  27.  
  28. #define SCHEME          ALPHA DIGIT "+-."
  29. #define _ABSOLUTE       UCHAR RESERVED
  30. #define NET_LOC         PCHAR ";?"
  31. #define PARAM           PCHAR "/"
  32. #define QUERY           UCHAR RESERVED
  33.  
  34. LPCSTR const null = "";
  35.  
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CURL
  38.  
  39. CURL::CURL()
  40. {
  41.     urltype = URL_EMPTY;
  42.     setschemetype();
  43. }
  44.  
  45. CURL::~CURL()
  46. {
  47. }
  48.  
  49. // Do not edit the following lines, which are needed by ClassWizard.
  50. #if 0
  51. BEGIN_MESSAGE_MAP(CURL, CSocket)
  52. //{{AFX_MSG_MAP(CURL)
  53. //}}AFX_MSG_MAP
  54. END_MESSAGE_MAP()
  55. #endif    // 0
  56.  
  57. /////////////////////////////////////////////////////////////////////////////
  58. // CURL member functions
  59.  
  60. CURL::CURL(int aurltype, CString ascheme, CString anet_loc, CString apath, CString aparams, CString aquery, CString afragment)
  61. {
  62.     urltype = aurltype;
  63.     scheme = ascheme;
  64.     path = apath;
  65.     net_loc = anet_loc;
  66.     path = apath;
  67.     params = aparams;
  68.     query = aquery;
  69.     fragment = afragment;
  70.     setschemetype();
  71. }
  72.  
  73. int CURL::rel_path(LPCSTR s, LPCSTR & spath, LPCSTR & sparams, LPCSTR & squery)
  74. {
  75.     LPTSTR s1 = NULL;
  76.     LPTSTR s2 = NULL;
  77.     
  78.     if (*s && (*s == '/' || strchr(PCHAR, *s)))
  79.     {
  80.         spath = s++;
  81.         while (*s)
  82.         {
  83.             while (*s && strchr(PCHAR, *s)) s++;
  84.             if (*s == '/')
  85.                 s++;
  86.             else
  87.                 break;
  88.         }
  89.     }
  90.     s1 = (LPTSTR)s;
  91.     if (*s == ';')
  92.     {
  93.         sparams = ++s;
  94.         while (*s)
  95.         {
  96.             while (*s && strchr(PARAM, *s)) s++;
  97.             if (*s == ';')
  98.                 s++;
  99.             else
  100.                 break;
  101.         }
  102.     }
  103.     s2 = (LPTSTR)s;
  104.     if (*s == '?')
  105.     {
  106.         squery = ++s;
  107.         while (*s && strchr(QUERY, *s)) s++;
  108.     }
  109.     if (!*s)
  110.     {
  111.         *s1 = 0;
  112.         *s2 = 0;
  113.     }
  114.     return !*s;
  115. }
  116.  
  117. int CURL::abs_path(LPCSTR s, LPCSTR & spath, LPCSTR & sparams, LPCSTR & squery)
  118. {
  119.     return *s == '/' && rel_path(s + 1, spath, sparams, squery);
  120. }
  121.  
  122. LPCSTR CURL::build(CString & url)
  123. {
  124.     url = path;
  125.     
  126.     if (!params.IsEmpty())
  127.         url += ";" + params;
  128.     
  129.     if (!query.IsEmpty())
  130.         url += "?" + query;
  131.     
  132.     if (!fragment.IsEmpty())
  133.         url += "#" + fragment;
  134.  
  135.     if (!net_loc.IsEmpty())
  136.     {
  137.         if (!url.IsEmpty() && url[0] != '/') url = '/' + url;
  138.         url = "//" + net_loc + url;
  139.     }
  140.     
  141.     if (!scheme.IsEmpty())
  142.         url = scheme + ":" + url;
  143.     
  144.     return (LPCSTR) url;
  145. }
  146.  
  147. CURL * CURL::expand(CURL * base)
  148. {
  149.     LPCSTR sscheme;
  150.     LPCSTR snet_loc;
  151.     LPCSTR spath;
  152.     LPCSTR sparams;
  153.     LPCSTR squery;
  154.     LPCSTR sfragment;
  155.     LPTSTR buf;
  156.     LPTSTR buf2;
  157.     LPTSTR s1;
  158.     LPTSTR s2;
  159.     LPTSTR s3;
  160.     LPTSTR s4;
  161.     int surltype = URL_NOERROR;
  162.     
  163.     //step 1 and 2b
  164.     if (base -> urltype == URL_EMPTY || !scheme.IsEmpty())
  165.         return new CURL(urltype, scheme, net_loc, path, params, query, fragment);
  166.     
  167.     //step 2a
  168.     if (urltype == URL_EMPTY)
  169.         return new CURL(base -> urltype, base -> scheme, base -> net_loc,
  170.         base -> path, base -> params, base -> query, base -> fragment);
  171.     
  172.     CString sbuf, sbuf2;
  173.     
  174.     buf = sbuf.GetBuffer(path.GetLength() + base -> path.GetLength());
  175.     buf2 = sbuf2.GetBuffer(path.GetLength() + base -> path.GetLength());
  176.     
  177.     //step 2c
  178.     sscheme = (LPCSTR) base -> scheme;
  179.     
  180.     snet_loc = (LPCSTR) net_loc;
  181.     sparams = (LPCSTR) params;
  182.     squery = (LPCSTR) query;
  183.     spath = (LPCSTR) path;
  184.     sfragment = (LPCSTR) fragment;
  185.     
  186.     //step 3
  187.     if (net_loc.IsEmpty())
  188.     {
  189.         snet_loc = (LPCSTR) base -> net_loc;
  190.         
  191.         //step 4
  192.         if (* (LPCSTR) path != '/')
  193.         {
  194.             //step 5
  195.             if (path.IsEmpty())
  196.             {
  197.                 spath = (LPCSTR) base -> path;
  198.                 if (params.IsEmpty())
  199.                 {
  200.                     sparams = (LPCSTR) base -> params;
  201.                     if (query.IsEmpty())
  202.                         squery = (LPCSTR) base -> query;
  203.                 }
  204.                 
  205.             }
  206.             else
  207.             {
  208.                 strcpy(buf, (LPCSTR) base -> path);
  209.                 spath = buf;
  210.                 
  211.                 //step 6
  212.                 if ((s1 = strrchr(buf, '/')) != NULL)
  213.                     *(++s1) = 0;
  214.                 strcat(buf, (LPCSTR) path);
  215.                 
  216.                 //step 6a
  217.                 s4 = s1 = buf;
  218.                 s2 = buf2;
  219.                 
  220.                 while (*s1)
  221.                 {
  222.                     s3 = (LPTSTR) nextsegment(s1);
  223.                     if (strncmp(s1, "./", 2))
  224.                     {
  225.                         strncpy(s2, s1, s3 - s1);
  226.                         s2 += s3 - s1;
  227.                         s4 = s1;
  228.                     }
  229.                     s1 = s3;
  230.                 }
  231.                 *s2 = 0;
  232.                 
  233.                 //step 6b
  234.                 if (!strcmp(s4, "."))
  235.                     *(--s2) = 0;
  236.                 
  237.                 //step 6c
  238.                 s1 = buf2;
  239.                 s2 = buf;
  240.                 
  241.                 while (*s1)
  242.                 {
  243.                     s3 = (LPTSTR) nextsegment(s1);
  244.                     s4 = (LPTSTR) prevsegment(buf, s2);
  245.                     if (strncmp(s1, "../", 3) || !s4 || !strncmp(s4, "../", 3))
  246.                     {
  247.                         strncpy(s2, s1, s3 - s1);
  248.                         s2 += s3 - s1;
  249.                     }
  250.                     else
  251.                     {
  252.                         //remove prev segment if exists
  253.                         s2 = s4;
  254.                     }
  255.                     s1 = s3;
  256.                 }
  257.                 *s2 = 0;
  258.                 
  259.                 //step 6c
  260.                 s1 = buf + strlen(buf);
  261.                 while (s1 > buf)
  262.                 {
  263.                     if (*s1 == '/') s1--;
  264.                     for (s2 = s1; s2 > buf && *(s2 - 1) != '/'; s2--);
  265.                     if (!strncmp(s2, "..", 3) && s2 >= buf)
  266.                     {
  267.                         for (s3 = s2 - 2; s3 > buf && *(s3 - 1) != '/'; s3--);
  268.                         s1 = s3;
  269.                     }
  270.                     else
  271.                         break;
  272.                 }
  273.                 *s1 = 0;
  274.                 spath = buf;
  275.             }
  276.         }
  277.         else
  278.             spath = (LPCSTR) path;
  279.     }
  280.     else
  281.     {
  282.         snet_loc = (LPCSTR) net_loc;
  283.     }
  284.     //step 7
  285.     if (!fragment.IsEmpty())
  286.         sfragment = (LPCSTR) fragment;
  287.     
  288.     CURL *res = new CURL(surltype, sscheme, snet_loc, spath, sparams, squery, sfragment);
  289.     // res -> slash = sslash;
  290.     sbuf.ReleaseBuffer();
  291.     sbuf2.ReleaseBuffer();
  292.     return res;
  293. }
  294.  
  295. LPCSTR CURL::prevsegment(LPCSTR base, LPCSTR s)
  296. {
  297.     if (s < base + 2) return NULL;
  298.     s -= 2;
  299.     while (s > base && *s != '/') s--;
  300.     if (*s == '/') s++;
  301.     return s;
  302. }
  303.  
  304. LPCSTR CURL::nextsegment(LPCSTR s)
  305. {
  306.     while (*s && *s != '/') s++;
  307.     if (*s == '/') s++;
  308.     return s;
  309. }
  310.  
  311. CURL::CURL(LPCSTR url)
  312. {
  313.     parse(url);
  314. }
  315.  
  316. LPCSTR CURL::relbuild(CString & relurl)
  317. {
  318.     relurl = path;
  319.     
  320.     if (!params.IsEmpty())
  321.         relurl += ";" + params;
  322.     
  323.     if (!query.IsEmpty())
  324.         relurl += "?" + query;
  325.     
  326.     if (!fragment.IsEmpty())
  327.         relurl += "#" + fragment;
  328.  
  329.     if (relurl.IsEmpty()) relurl = "/";
  330.     return (LPCSTR) relurl;
  331. }
  332.  
  333. void CURL::setschemetype()
  334. {
  335.     CString sch(scheme);
  336.     
  337.     sch.MakeLower();
  338.     
  339.     if (!sch.Compare("file"))
  340.         schemetype = SCHEME_FILE;
  341.     else
  342.     if (!sch.Compare("http"))
  343.         schemetype = SCHEME_HTTP;
  344.     else
  345.         schemetype = SCHEME_UNKNOWN;
  346. }
  347.  
  348. void CURL::topath(CString & res)
  349. {
  350.     res = path;
  351.     if (res[0] == '/')
  352.         res = res.Mid(1);
  353.     LPTSTR s = res.GetBuffer(res.GetLength());
  354.  
  355.     for (; *s; s++)
  356.     {
  357.         if (*s == '/')
  358.             *s = SEPCHAR;
  359.         else
  360.         if (*s == '|')
  361.             *s = ':';
  362.     }
  363.  
  364.     res.ReleaseBuffer();
  365. }
  366.  
  367. void CURL::getdir(CString & dir)
  368. {
  369.     dir = path.Mid(1);
  370.     if (dir[dir.GetLength() - 1] != '/')
  371.     {
  372.         int i = dir.ReverseFind('/');
  373.         if (i == -1)
  374.             dir.Empty();
  375.         else
  376.             dir = dir.Left(i);
  377.     }
  378. }
  379.  
  380. void CURL::getname(CString & name)
  381. {
  382.     int i = path.ReverseFind('/');
  383.     if (i == -1)
  384.         name = path;
  385.     else
  386.         name = path.Mid(i + 1);
  387. }
  388.  
  389. void CURL::parse(LPCSTR url)
  390. {
  391.     LPTSTR s;
  392.     LPTSTR s1;
  393.     LPTSTR s2;
  394.     LPCSTR sfragment;
  395.     LPCSTR sscheme;
  396.     LPCSTR snet_loc;
  397.     LPCSTR spath;
  398.     LPCSTR squery;
  399.     LPCSTR sparams;
  400.     int relative, slash = 0;
  401.     CString copy(url);
  402.     
  403.     s = copy.GetBuffer(copy.GetLength());
  404.     
  405.     sfragment = null;
  406.     sscheme = null;
  407.     snet_loc = null;
  408.     spath = null;
  409.     squery = null;
  410.     sparams = null;
  411.     
  412.     urltype = URL_EMPTY;
  413.     
  414.     if (*s)
  415.     {
  416.         urltype = URL_NOERROR;
  417.         //fragment
  418.         sfragment = strchr(s, '#');
  419.         if (sfragment)
  420.             *((LPTSTR)sfragment++) = 0;
  421.         else
  422.             sfragment = null;
  423.         
  424.         //scheme
  425.         s1 = s;
  426.         while (*s1 && strchr(SCHEME, *s1)) s1++;
  427.         if (*s1 == ':' && s1 > s)
  428.         {
  429.             sscheme = s;
  430.             if (*s1)
  431.                 *(s1++) = 0;
  432.         }
  433.         else
  434.         {
  435.             sscheme = null;
  436.             s1 = s;
  437.         }
  438.         
  439.         //net_loc
  440.         s2 = s1;
  441.         if (s1[0] == '/' && s1[1] == '/')
  442.         {
  443.             s1 += 2;
  444.             while (*s1 && strchr(NET_LOC, *s1)) s1++;
  445.             snet_loc = s2 + 2;
  446.             slash = *s1 == '/';
  447.             if (*s1)
  448.                 *(s1++) = 0;
  449.         }
  450.         
  451.         relative = abs_path(s1, spath, sparams, squery);
  452.         if (!relative)
  453.             relative = rel_path(s1, spath, sparams, squery);
  454.         else
  455.             slash = 1;
  456.         
  457.         if (!relative)
  458.         {
  459.             while (*s1 && strchr(_ABSOLUTE, *s1)) s1++;
  460.             if (!*s1) urltype = URL_INVALID;
  461.         }
  462.     }
  463.     
  464.     scheme = sscheme;
  465.     scheme.MakeLower();
  466.     net_loc = snet_loc;
  467.     if (slash)
  468.         path = _T("/") + CString(spath);
  469.     else
  470.         path = spath;
  471.     params = sparams;
  472.     query = squery;
  473.     fragment = sfragment;
  474.     
  475.     copy.ReleaseBuffer();
  476.     setschemetype();
  477. }
  478.