X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/21248c0f00ee71412dbadc6ebf84011cf974346d..0cfec3ab589c6309bf284438d2148c7742cdaf10:/apt-pkg/contrib/strutl.cc diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 0db4c57b2..fba1e3306 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -21,16 +21,19 @@ #include #include +#include +#include +#include +#include +#include +#include + #include #include #include -#include -#include #include #include -#include #include -#include #include #include #include @@ -71,14 +74,14 @@ bool Endswith(const std::string &s, const std::string &end) { if (end.size() > s.size()) return false; - return (s.substr(s.size() - end.size(), s.size()) == end); + return (s.compare(s.size() - end.size(), end.size(), end) == 0); } bool Startswith(const std::string &s, const std::string &start) { if (start.size() > s.size()) return false; - return (s.substr(0, start.size()) == start); + return (s.compare(0, start.size(), start) == 0); } } @@ -331,7 +334,7 @@ string QuoteString(const string &Str, const char *Bad) *I == 0x25 || // percent '%' char *I <= 0x20 || *I >= 0x7F) // control chars { - ioprintf(Res,"%%%02x",(int)*I); + ioprintf(Res, "%%%02hhx", *I); } else Res << *I; @@ -464,7 +467,9 @@ string SubstVar(const string &Str,const string &Subst,const string &Contents) if (OldPos >= Str.length()) return Temp; - return Temp + string(Str,OldPos); + + Temp.append(Str, OldPos, string::npos); + return Temp; } string SubstVar(string Str,const struct SubstVar *Vars) { @@ -690,9 +695,9 @@ string LookupTag(const string &Message,const char *Tag,const char *Default) // Find the end of line and strip the leading/trailing spaces string::const_iterator J; I += Length + 1; - for (; isspace(*I) != 0 && I < Message.end(); ++I); + for (; isspace_ascii(*I) != 0 && I < Message.end(); ++I); for (J = I; *J != '\n' && J < Message.end(); ++J); - for (; J > I && isspace(J[-1]) != 0; --J); + for (; J > I && isspace_ascii(J[-1]) != 0; --J); return string(I,J); } @@ -749,15 +754,11 @@ string TimeRFC1123(time_t Date) if (gmtime_r(&Date, &Conv) == NULL) return ""; - char Buf[300]; - const char *Day[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; - const char *Month[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul", - "Aug","Sep","Oct","Nov","Dec"}; - - snprintf(Buf, sizeof(Buf), "%s, %02i %s %i %02i:%02i:%02i GMT",Day[Conv.tm_wday], - Conv.tm_mday,Month[Conv.tm_mon],Conv.tm_year+1900,Conv.tm_hour, - Conv.tm_min,Conv.tm_sec); - return Buf; + auto const posix = std::locale("C.UTF-8"); + std::ostringstream datestr; + datestr.imbue(posix); + datestr << std::put_time(&Conv, "%a, %d %b %Y %H:%M:%S GMT"); + return datestr.str(); } /*}}}*/ // ReadMessages - Read messages from the FD /*{{{*/ @@ -788,7 +789,11 @@ bool ReadMessages(int Fd, vector &List) return false; // No data +#if EAGAIN != EWOULDBLOCK if (Res < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) +#else + if (Res < 0 && errno == EAGAIN) +#endif return true; if (Res < 0) return false; @@ -915,29 +920,56 @@ static time_t timegm(struct tm *t) } #endif /*}}}*/ -// FullDateToTime - Converts a HTTP1.1 full date strings into a time_t /*{{{*/ +// RFC1123StrToTime - Converts a HTTP1.1 full date strings into a time_t /*{{{*/ // --------------------------------------------------------------------- -/* tries to parses a full date as specified in RFC2616 Section 3.3.1 - with one exception: All timezones (%Z) are accepted but the protocol - says that it MUST be GMT, but this one is equal to UTC which we will - encounter from time to time (e.g. in Release files) so we accept all - here and just assume it is GMT (or UTC) later on */ +/* tries to parses a full date as specified in RFC7231 §7.1.1.1 + with one exception: HTTP/1.1 valid dates need to have GMT as timezone. + As we encounter dates from UTC or with a numeric timezone in other places, + we allow them here to to be able to reuse the method. Either way, a date + must be in UTC or parsing will fail. Previous implementations of this + method used to ignore the timezone and assume always UTC. */ bool RFC1123StrToTime(const char* const str,time_t &time) { - struct tm Tm; - setlocale (LC_ALL,"C"); - bool const invalid = - // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 - (strptime(str, "%a, %d %b %Y %H:%M:%S %Z", &Tm) == NULL && - // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 - strptime(str, "%A, %d-%b-%y %H:%M:%S %Z", &Tm) == NULL && - // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format - strptime(str, "%a %b %d %H:%M:%S %Y", &Tm) == NULL); - setlocale (LC_ALL,""); - if (invalid == true) + struct tm t; + auto const &posix = std::locale("C.UTF-8"); + auto const parse_time = [&](char const * const s, bool const has_timezone) { + std::istringstream ss(str); + ss.imbue(posix); + ss >> std::get_time(&t, s); + if (has_timezone && ss.fail() == false) + { + std::string timezone; + ss >> timezone; + if (timezone.empty()) + return false; + if (timezone != "GMT" && timezone != "UTC" && timezone != "Z") // RFC 822 + { + // numeric timezones as a should of RFC 1123 and generally preferred + try { + size_t pos; + auto const zone = std::stoi(timezone, &pos); + if (zone != 0 || pos != timezone.length()) + return false; + } catch (...) { + return false; + } + } + } + t.tm_isdst = 0; + return ss.fail() == false; + }; + + bool const good = + // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + parse_time("%a, %d %b %Y %H:%M:%S", true) || + // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + parse_time("%A, %d-%b-%y %H:%M:%S", true) || + // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + parse_time("%c", false); // "%a %b %d %H:%M:%S %Y" + if (good == false) return false; - time = timegm(&Tm); + time = timegm(&t); return true; } /*}}}*/ @@ -1106,26 +1138,36 @@ static int HexDigit(int c) return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; - return 0; + return -1; } /*}}}*/ // 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 string &Str,unsigned char *Num,unsigned int Length) +{ + return Hex2Num(APT::StringView(Str), Num, Length); +} + +bool Hex2Num(const APT::StringView Str,unsigned char *Num,unsigned int Length) { if (Str.length() != Length*2) return false; // Convert each digit. We store it in the same order as the string int J = 0; - for (string::const_iterator I = Str.begin(); I != Str.end();J++, I += 2) + for (auto I = Str.begin(); I != Str.end();J++, I += 2) { - if (isxdigit(*I) == 0 || isxdigit(I[1]) == 0) + int first_half = HexDigit(I[0]); + int second_half; + if (first_half < 0) return false; - Num[J] = HexDigit(I[0]) << 4; - Num[J] += HexDigit(I[1]); + second_half = HexDigit(I[1]); + if (second_half < 0) + return false; + Num[J] = first_half << 4; + Num[J] += second_half; } return true; @@ -1201,7 +1243,7 @@ vector StringSplit(std::string const &s, std::string const &sep, vector split; size_t start, pos; - // no seperator given, this is bogus + // no separator given, this is bogus if(sep.size() == 0) return split; @@ -1308,7 +1350,7 @@ void ioprintf(ostream &out,const char *format,...) va_list args; ssize_t size = 400; while (true) { - bool ret = false; + bool ret; va_start(args,format); ret = iovprintf(out, format, args, size); va_end(args); @@ -1322,7 +1364,7 @@ void strprintf(string &out,const char *format,...) ssize_t size = 400; std::ostringstream outstr; while (true) { - bool ret = false; + bool ret; va_start(args,format); ret = iovprintf(outstr, format, args, size); va_end(args); @@ -1364,17 +1406,32 @@ string StripEpoch(const string &VerStr) return VerStr.substr(i+1); } /*}}}*/ + // tolower_ascii - tolower() function that ignores the locale /*{{{*/ // --------------------------------------------------------------------- /* This little function is the most called method we have and tries therefore to do the absolut minimum - and is notable faster than standard tolower/toupper and as a bonus avoids problems with different locales - we only operate on ascii chars anyway. */ +#undef tolower_ascii +int tolower_ascii(int const c) APT_CONST APT_COLD; int tolower_ascii(int const c) { - if (c >= 'A' && c <= 'Z') - return c + 32; - return c; + return tolower_ascii_inline(c); +} + /*}}}*/ + +// isspace_ascii - isspace() function that ignores the locale /*{{{*/ +// --------------------------------------------------------------------- +/* This little function is one of the most called methods we have and tries + therefore to do the absolut minimum - and is notable faster than + standard isspace() and as a bonus avoids problems with different + locales - we only operate on ascii chars anyway. */ +#undef isspace_ascii +int isspace_ascii(int const c) APT_CONST APT_COLD; +int isspace_ascii(int const c) +{ + return isspace_ascii_inline(c); } /*}}}*/ @@ -1622,7 +1679,7 @@ URI::operator string() Res << Host; if (Port != 0) - Res << ':' << Port; + Res << ':' << std::to_string(Port); } if (Path.empty() == false) @@ -1637,8 +1694,6 @@ URI::operator string() } /*}}}*/ // URI::SiteOnly - Return the schema and site for the URI /*{{{*/ -// --------------------------------------------------------------------- -/* */ string URI::SiteOnly(const string &URI) { ::URI U(URI); @@ -1648,9 +1703,18 @@ string URI::SiteOnly(const string &URI) return U; } /*}}}*/ +// URI::ArchiveOnly - Return the schema, site and cleaned path for the URI /*{{{*/ +string URI::ArchiveOnly(const string &URI) +{ + ::URI U(URI); + U.User.clear(); + U.Password.clear(); + if (U.Path.empty() == false && U.Path[U.Path.length() - 1] == '/') + U.Path.erase(U.Path.length() - 1); + return U; +} + /*}}}*/ // URI::NoUserPassword - Return the schema, site and path for the URI /*{{{*/ -// --------------------------------------------------------------------- -/* */ string URI::NoUserPassword(const string &URI) { ::URI U(URI);