I will commit this patch shortly if nobody objects

Problem
-------
The method -[NSCalendarDate descriptionWithCalendarFormat:locale:]
has the following problems:

* potential buffer overrun (statically allocated result on stack)
* if an unrecognized character follows the % sign in the format
  the result is not correct, it will miss the character following
  the unrecognized character.   For example:
  "%8Hallo" will result in something like "%8allo".
* the format string "%b %B" does not work, it is treated as
  "%b %b".  Reason is that a flag is set upon the first
  %b which is not reset.  Same problem occurs with 
  %Y and a few others
* %c, %x and %X are not recognized

Solution
--------
The following patch will solve all these problems EXCEPT 
the first.  It will introduce a strcpy of the format string
which is in most cases not necessary, but I do not
think this is a critical problem. 
Also the %c %X %x conversion are not really efficient.
And it bothers me a little that the buffer overrun is
still there, but getting rid of that requires siginificantly
more work.

Index: base/Source/NSCalendarDate.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/base/Source/NSCalendarDate.m,v
retrieving revision 1.90
diff -c -r1.90 NSCalendarDate.m
*** base/Source/NSCalendarDate.m	25 Oct 2003 05:54:39 -0000	1.90
--- base/Source/NSCalendarDate.m	25 Feb 2004 13:12:32 -0000
***************
*** 1565,1570 ****
--- 1565,1573 ----
   *     %b   abbreviated month name according to locale
   *   </item>
   *   <item>
+  *     %c   this is the same as %X %x
+  *   </item>
+  *   <item>
   *     %B   full month name according to locale
   *   </item>
   *   <item>
***************
*** 1607,1612 ****
--- 1610,1621 ----
   *     %w   day of the week as decimal number (Sunday = 0)
   *   </item>
   *   <item>
+  *     %x   date formatted according to the locale
+  *   </item>
+  *   <item>
+  *     %X   time formatted according to the locale
+  *   </item>
+  *   <item>
   *     %y   year as a decimal number without century (minimum 0)
   *   </item>
   *   <item>
***************
*** 1627,1636 ****
  				     locale: (NSDictionary*)locale
  {
    char buf[1024];
!   const char *f;
    int lf;
-   BOOL mtag = NO, dtag = NO, ycent = NO;
-   BOOL mname = NO, dname = NO;
    double s;
    int yd = 0, md = 0, mnd = 0, sd = 0, dom = -1, dow = -1, doy = -1;
    int hd = 0, nhd, mil;
--- 1636,1643 ----
  				     locale: (NSDictionary*)locale
  {
    char buf[1024];
!   char f [1024];
    int lf;
    double s;
    int yd = 0, md = 0, mnd = 0, sd = 0, dom = -1, dow = -1, doy = -1;
    int hd = 0, nhd, mil;
***************
*** 1645,1651 ****
    if (!format)
      return @"";
  
!   f = [format cString];
    lf = strlen(f);
  
    GSBreakTime(_seconds_since_ref + offset(_time_zone, self),
--- 1652,1658 ----
    if (!format)
      return @"";
  
!   strcpy (f, [format cString]);
    lf = strlen(f);
  
    GSBreakTime(_seconds_since_ref + offset(_time_zone, self),
***************
*** 1655,1667 ****
    // Find the order of date elements
    // and translate format string into printf ready string
    j = 0;
!   for (i = 0;i < lf; ++i)
      {
        // Only care about a format specifier
        if (f[i] == '%')
  	{
  	  // check the character that comes after
! 	  switch (f[i+1])
  	    {
  	      // literal %
  	    case '%':
--- 1662,1681 ----
    // Find the order of date elements
    // and translate format string into printf ready string
    j = 0;
!   i = 0;
!   
!   while (i < lf)
      {
+       BOOL mtag = NO, dtag = NO, ycent = NO;
+       BOOL mname = NO, dname = NO;
+       const char *insertionString = NULL;
+       
        // Only care about a format specifier
        if (f[i] == '%')
  	{
+           ++i;
  	  // check the character that comes after
! 	  switch (f[i])
  	    {
  	      // literal %
  	    case '%':
***************
*** 1670,1675 ****
--- 1684,1723 ----
  	      ++j;
  	      break;
  
+             case 'c':
+               insertionString = [[NSString stringWithFormat: @"%@ %@",
+                                            [locale objectForKey: NSTimeFormatString],
+                                            [locale objectForKey: NSDateFormatString]]
+                                   cString];
+             case 'X':
+               if (insertionString == NULL)
+                 {
+                   insertionString = [[locale objectForKey: NSTimeFormatString] cString];
+                 }
+             case 'x':
+               {
+                 int lengthOfInsertion;
+                 if (insertionString == NULL)
+                   {
+                     insertionString = [[locale objectForKey: NSDateFormatString] cString];
+                   }
+                 lengthOfInsertion = strlen (insertionString);
+                 // Insert the insertion string in the format 
+                 // + 1 for the nul byte terminating the string
+                 // Note: i is pointing to the x in %x, we remove %x and insert
+                 // the string.  The +1 for the length is there to copy the string
+                 // terminator.
+                 memmove (f + i - 1 + lengthOfInsertion, f + i + 1,
+                          strlen (f + i + 1) + 1);
+                 memcpy (f + i - 1, insertionString, lengthOfInsertion);
+                 // update the lvar containing the length
+                 lf += lengthOfInsertion;
+                 // update the reader position, we removed %x and the i was pointing to
+                 // the x.
+                 --i;
+                 break;
+               }
+                     
  	      // is it the year
  	    case 'Y':
  	      ycent = YES;
***************
*** 1850,1857 ****
  
  	      // Anything else is unknown so just copy
  	    default:
! 	      buf[j] = f[i];
! 	      ++i;
  	      ++j;
  	      buf[j] = f[i];
  	      ++i;
--- 1898,1904 ----
  
  	      // Anything else is unknown so just copy
  	    default:
! 	      buf[j] = f[i - 1];
  	      ++j;
  	      buf[j] = f[i];
  	      ++i;
***************
*** 1863,1868 ****
--- 1910,1916 ----
  	{
  	  buf[j] = f[i];
  	  ++j;
+           ++i;
  	}
      }
    buf[j] = '\0';

Wim Oudshoorn.
_______________________________________________
Bug-gnustep mailing list
[EMAIL PROTECTED]
http://mail.gnu.org/mailman/listinfo/bug-gnustep

Reply via email to