// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: strutl.cc,v 1.26 1999/06/27 04:55:54 jgg Exp $
+// $Id: strutl.cc,v 1.33 2000/01/14 06:26:37 jgg Exp $
/* ######################################################################
String Util - Some usefull string functions.
file name should be unique and never occur again for a different file */
string URItoFileName(string URI)
{
- string::const_iterator I = URI.begin() + URI.find(':') + 1;
- for (; I < URI.end() && *I == '/'; I++);
-
+ // Nuke 'sensitive' items
+ ::URI U(URI);
+ U.User = string();
+ U.Password = string();
+ U.Access = "";
+
// "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
- URI = QuoteString(string(I,URI.end() - I),"\\|{}[]<>\"^~_=!@#$%^&*");
+ URI = QuoteString(U,"\\|{}[]<>\"^~_=!@#$%^&*");
string::iterator J = URI.begin();
for (; J != URI.end(); J++)
if (*J == '/')
/* This handles all 3 populare time formats including RFC 1123, RFC 1036
and the C library asctime format. It requires the GNU library function
'timegm' to convert a struct tm in UTC to a time_t. For some bizzar
- reason the C library does not provide any such function :<*/
+ reason the C library does not provide any such function :< This also
+ handles the weird, but unambiguous FTP time format*/
bool StrToTime(string Val,time_t &Result)
{
struct tm Tm;
for (;*I != 0 && *I != ' '; I++);
// Handle RFC 1123 time
+ Month[0] = 0;
if (sscanf(I," %d %3s %d %d:%d:%d GMT",&Tm.tm_mday,Month,&Tm.tm_year,
&Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec) != 6)
{
// asctime format
if (sscanf(I," %3s %d %d:%d:%d %d",Month,&Tm.tm_mday,
&Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec,&Tm.tm_year) != 6)
- return false;
+ {
+ // 'ftp' time
+ if (sscanf(Val.c_str(),"%4d%2d%2d%2d%2d%2d",&Tm.tm_year,&Tm.tm_mon,
+ &Tm.tm_mday,&Tm.tm_hour,&Tm.tm_min,&Tm.tm_sec) != 6)
+ return false;
+ Tm.tm_mon--;
+ }
}
}
Tm.tm_isdst = 0;
- Tm.tm_mon = MonthConv(Month);
+ if (Month[0] != 0)
+ Tm.tm_mon = MonthConv(Month);
Tm.tm_year -= 1900;
// Convert to local time and then to GMT
return true;
}
/*}}}*/
+// StrToNum - Convert a fixed length string to a number /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used in decoding the crazy fixed length string headers in
+ tar and ar files. */
+bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base)
+{
+ char S[30];
+ if (Len >= sizeof(S))
+ return false;
+ memcpy(S,Str,Len);
+ S[Len] = 0;
+
+ // All spaces is a zero
+ Res = 0;
+ unsigned I;
+ for (I = 0; S[I] == ' '; I++);
+ if (S[I] == 0)
+ return true;
+
+ char *End;
+ Res = strtoul(S,&End,Base);
+ if (End == S)
+ return false;
+
+ return true;
+}
+ /*}}}*/
+// HexDigit - Convert a hex character into an integer /*{{{*/
+// ---------------------------------------------------------------------
+/* Helper for Hex2Num */
+static int HexDigit(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0;
+}
+ /*}}}*/
+// Hex2Num - Convert a long hex number into a buffer /*{{{*/
+// ---------------------------------------------------------------------
+/* The length of the buffer must be exactly 1/2 the length of the string. */
+bool Hex2Num(const char *Start,const char *End,unsigned char *Num,
+ unsigned int Length)
+{
+ if (End - Start != (signed)(Length*2))
+ return false;
+
+ // Convert each digit. We store it in the same order as the string
+ int J = 0;
+ for (const char *I = Start; I < End;J++, I += 2)
+ {
+ if (isxdigit(*I) == 0 || isxdigit(I[1]) == 0)
+ return false;
+
+ Num[J] = HexDigit(I[0]) << 4;
+ Num[J] += HexDigit(I[1]);
+ }
+
+ return true;
+}
+ /*}}}*/
// URI::CopyFrom - Copy from an object /*{{{*/
// ---------------------------------------------------------------------
string::const_iterator SingleSlash = I;
if (I + 3 < U.end() && I[1] == '/' && I[2] == '/')
SingleSlash += 3;
- for (; SingleSlash < U.end() && *SingleSlash != '/'; SingleSlash++);
+
+ /* Find the / indicating the end of the hostname, ignoring /'s in the
+ square brackets */
+ bool InBracket = false;
+ for (; SingleSlash < U.end() && (*SingleSlash != '/' || InBracket == true); SingleSlash++)
+ {
+ if (*SingleSlash == '[')
+ InBracket = true;
+ if (InBracket == true && *SingleSlash == ']')
+ InBracket = false;
+ }
+
if (SingleSlash > U.end())
SingleSlash = U.end();
Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1);
}
+ // Now we parse the RFC 2732 [] hostnames.
+ unsigned long PortEnd = 0;
+ InBracket = false;
+ for (unsigned I = 0; I != Host.length();)
+ {
+ if (Host[I] == '[')
+ {
+ InBracket = true;
+ Host.erase(I,1);
+ continue;
+ }
+
+ if (InBracket == true && Host[I] == ']')
+ {
+ InBracket = false;
+ Host.erase(I,1);
+ PortEnd = I;
+ continue;
+ }
+ I++;
+ }
+
+ // Tsk, weird.
+ if (InBracket == true)
+ {
+ Host = string();
+ return;
+ }
+
// Now we parse off a port number from the hostname
Port = 0;
string::size_type Pos = Host.rfind(':');
- if (Pos == string::npos)
+ if (Pos == string::npos || Pos < PortEnd)
return;
Port = atoi(string(Host,Pos+1).c_str());
/* */
URI::operator string()
{
- string Res = Access + ':';
+ string Res;
+
+ if (Access.empty() == false)
+ Res = Access + ':';
+
if (Host.empty() == false)
{
- Res += "//";
+ if (Access.empty() == false)
+ Res += "//";
+
if (User.empty() == false)
{
- Res += "//" + User;
+ Res += User;
if (Password.empty() == false)
Res += ":" + Password;
Res += "@";
}
+
Res += Host;
if (Port != 0)
{