lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I reverted the "cn" change in my version because I decided the failure of the following assertion (without some other error) was unacceptable:
    assert(("c8"):unpack(("c8"):pack(input_string)) == input_string)

Implementing "z[n]" instead gives a very similar behaviour but with the assertion either holding or else an error being produced while packing (substituting "z8" in place of "c8").

Following is the patch generated from my changes, for anyone who is interested.

Regards,

Duane.

@@ -1209,7 +1209,13 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
       if (*size == -1)
         luaL_error(h->L, "missing size for format option 'c'");
       return Kchar;
-    case 'z': return Kzstr;
+    case 'z':
+      *size = getnum(fmt, -1);
+      if (*size == 0)
+        luaL_error(h->L, "illegal 0 size for format option 'z'");
+      if (*size == -1)
+        *size = 0;
+      return Kzstr;
     case 'x': *size = 1; return Kpadding;
     case 'X': return Kpaddalign;
     case ' ': break;
@@ -1237,10 +1243,12 @@ static KOption getdetails (Header *h, size_t totalsize,
   KOption opt = getoption(h, fmt, psize);
   int align = *psize;  /* usually, alignment follows size */
   if (opt == Kpaddalign) {  /* 'X' gets alignment from following option */
-    if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
+    KOption alopt;
+    if (**fmt == '\0' || (alopt = getoption(h, fmt, &align)) == Kchar
+        || alopt == Kzstr || align == 0)
       luaL_argerror(h->L, 1, "invalid next option for option 'X'");
   }
-  if (align <= 1 || opt == Kchar)  /* need no alignment? */
+  if (align <= 1 || opt == Kchar || opt == Kzstr)  /* need no alignment? */
     *ntoalign = 0;
   else {
     if (align > h->maxalign)  /* enforce maximum alignment */
@@ -1343,13 +1351,8 @@ static int str_pack (lua_State *L) {
       case Kchar: {  /* fixed-size string */
         size_t len;
         const char *s = luaL_checklstring(L, arg, &len);
-        if ((size_t)size <= len)  /* string larger than (or equal to) needed? */
-          luaL_addlstring(&b, s, size);  /* truncate string to asked size */
-        else {  /* string smaller than needed */
-          luaL_addlstring(&b, s, len);  /* add it all */
-          while (len++ < (size_t)size)  /* pad extra space */
-            luaL_addchar(&b, LUA_PACKPADBYTE);
-        }
+        luaL_argcheck(L, len == (size_t)size, arg, "wrong length");
+        luaL_addlstring(&b, s, size);
         break;
       }
       case Kstring: {  /* strings with length count */
@@ -1367,9 +1370,12 @@ static int str_pack (lua_State *L) {
         size_t len;
         const char *s = luaL_checklstring(L, arg, &len);
         luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros");
+        luaL_argcheck(L, size == 0 || len < (size_t)size, arg, "string is too long");
         luaL_addlstring(&b, s, len);
-        luaL_addchar(&b, '\0');  /* add zero at the end */
-        totalsize += len + 1;
+        do {
+          luaL_addchar(&b, '\0'); len++;  /* add zero at the end */
+        } while (len < (size_t)size);  /* pad extra space */
+        totalsize += len;
         break;
       }
       case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE);  /* FALLTHROUGH */
@@ -1395,13 +1401,8 @@ static int str_packsize (lua_State *L) {
     luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
                      "format result too large");
     totalsize += size;
-    switch (opt) {
-      case Kstring:  /* strings with length count */
-      case Kzstr:    /* zero-terminated string */
-        luaL_argerror(L, 1, "variable-length format");
-        /* call never return, but to avoid warnings: *//* FALLTHROUGH */
-      default:  break;
-    }
+    if (opt == Kstring || (opt == Kzstr && size == 0))
+      luaL_argerror(L, 1, "variable-length format");
   }
   lua_pushinteger(L, (lua_Integer)totalsize);
   return 1;
@@ -1492,7 +1493,10 @@ static int str_unpack (lua_State *L) {
       case Kzstr: {
         size_t len = (int)strlen(data + pos);
         lua_pushlstring(L, data + pos, len);
-        pos += len + 1;  /* skip string plus final '\0' */
+        if (size != 0)
+          pos += size;
+        else
+          pos += len + 1;  /* skip string plus final '\0' */
         break;
       }
       case Kpaddalign: case Kpadding: case Knop: