OSDN Git Service

* src/prototypes.h (str_safe_copy): newly added.
[lha/lha.git] / src / header.c
index 9fa4da9..5620619 100644 (file)
@@ -211,8 +211,8 @@ convert_filename(name, len, size,
                  from_delim, to_delim,
                  case_to)
     char *name;
-    int len;
-    int size;
+    int len;                    /* length of name */
+    int size;                   /* size of name buffer */
     int from_code, to_code, case_to;
     char *from_delim, *to_delim;
 
@@ -220,6 +220,20 @@ convert_filename(name, len, size,
     int i;
 #ifdef MULTIBYTE_FILENAME
     char tmp[FILENAME_LENGTH];
+    int to_code_save = NONE;
+
+    if (from_code == CODE_CAP) {
+        len = cap_to_sjis(tmp, name, sizeof(tmp));
+        strncpy(name, tmp, size);
+        name[size-1] = 0;
+        len = strlen(name);
+        from_code = CODE_SJIS;
+    }
+
+    if (to_code == CODE_CAP) {
+        to_code_save = CODE_CAP;
+        to_code = CODE_SJIS;
+    }
 
     if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
         for (i = 0; i < len; i++)
@@ -343,6 +357,15 @@ convert_filename(name, len, size,
             continue;
         }
     }
+
+#ifdef MULTIBYTE_FILENAME
+    if (to_code_save == CODE_CAP) {
+        len = sjis_to_cap(tmp, name, sizeof(tmp));
+        strncpy(name, tmp, size);
+        name[size-1] = 0;
+        len = strlen(name);
+    }
+#endif /* MULTIBYTE_FILENAME */
 }
 
 /*
@@ -401,7 +424,8 @@ wintime_to_unix_stamp()
 {
 #if HAVE_UINT64_T
     uint64_t t;
-    uint64_t epoch = 0x019db1ded53e8000; /* 1970-01-01 00:00:00 (UTC) */
+    uint64_t epoch = ((uint64_t)0x019db1de << 32) + 0xd53e8000;
+                     /* 0x019db1ded53e8000ULL: 1970-01-01 00:00:00 (UTC) */
 
     t = (unsigned long)get_longword();
     t |= (uint64_t)(unsigned long)get_longword() << 32;
@@ -591,8 +615,8 @@ get_extended_header(fp, hdr, header_size, hcrc)
             name_length = sizeof(hdr->name) - dir_length - 1;
             hdr->name[name_length] = 0;
         }
-        strcat(dirname, hdr->name);
-        strcpy(hdr->name, dirname);
+        strcat(dirname, hdr->name); /* ok */
+        strcpy(hdr->name, dirname); /* ok */
         name_length += dir_length;
     }
 
@@ -1103,7 +1127,7 @@ get_header(fp, hdr)
             /* hdr->name is symbolic link name */
             /* hdr->realname is real name */
             *p = 0;
-            strncpy(hdr->realname, p+1, sizeof(hdr->realname));
+            strcpy(hdr->realname, p+1); /* ok */
         }
         else
             error("unknown symlink name \"%s\"", hdr->name);
@@ -1132,7 +1156,7 @@ seek_lha_header(fp)
         if ((p[I_HEADER_LEVEL] == 0 || p[I_HEADER_LEVEL] == 1)
             && p[I_HEADER_SIZE] > 20
             && p[I_HEADER_CHECKSUM] == calc_sum(p+2, p[I_HEADER_SIZE])) {
-            if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
+            if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
                 fatal_error("cannot seek header");
             return 0;
         }
@@ -1141,13 +1165,13 @@ seek_lha_header(fp)
         if (p[I_HEADER_LEVEL] == 2
             && p[I_HEADER_SIZE] >= 24
             && p[I_ATTRIBUTE] == 0x20) {
-            if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
+            if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
                 fatal_error("cannot seek header");
             return 0;
         }
     }
 
-    if (fseek(fp, -n, SEEK_CUR) == -1)
+    if (fseeko(fp, -n, SEEK_CUR) == -1)
         fatal_error("cannot seek header");
     return -1;
 }
@@ -1170,8 +1194,7 @@ init_header(name, v_stat, hdr)
     hdr->original_size = v_stat->st_size;
     hdr->attribute = GENERIC_ATTRIBUTE;
     hdr->header_level = header_level;
-    strcpy(hdr->name, name);
-    len = strlen(name);
+    len = str_safe_copy(hdr->name, name, sizeof(hdr->name));
     hdr->crc = 0x0000;
     hdr->extend_type = EXTEND_UNIX;
     hdr->unix_last_modified_stamp = v_stat->st_mtime;
@@ -1213,8 +1236,13 @@ init_header(name, v_stat, hdr)
         memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
         hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
         hdr->original_size = 0;
-        if (len > 0 && hdr->name[len - 1] != '/')
-            strcpy(&hdr->name[len++], "/");
+        if (len > 0 && hdr->name[len - 1] != '/') {
+            if (len < sizeof(hdr->name)-1)
+                strcpy(&hdr->name[len++], "/"); /* ok */
+            else
+                warning("the length of dirname \"%s\" is too long.",
+                        hdr->name);
+        }
     }
 
 #ifdef S_IFLNK
@@ -1492,11 +1520,11 @@ write_header_level2(data, hdr, pathname)
         header_size++;
     }
 
-    /* put hader size */
+    /* put header size */
     setup_put(data + I_HEADER_SIZE);
     put_word(header_size);
 
-    /* put hader CRC in extended header */
+    /* put header CRC in extended header */
     INITIALIZE_CRC(hcrc);
     hcrc = calccrc(hcrc, data, (unsigned int) header_size);
     setup_put(headercrc_ptr);
@@ -1784,4 +1812,106 @@ sjis2euc(int *p1, int *p2)
     *p1 |= 0x80;
     *p2 |= 0x80;
 }
+
+static int
+hex2int(int c)
+{
+    switch (c) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+        return c - '0';
+
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+        return c - 'a' + 10;
+
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+        return c - 'A' + 10;
+    default:
+        return -1;
+    }
+}
+
+static int
+int2hex(int c)
+{
+    switch (c) {
+    case 0: case 1: case 2: case 3: case 4:
+    case 5: case 6: case 7: case 8: case 9:
+        return c + '0';
+
+    case 10: case 11: case 12: case 13: case 14: case 15:
+        return c + 'a' - 10;
+
+    default:
+        return -1;
+    }
+}
+
+int
+cap_to_sjis(char *dst, const char *src, size_t dstsize)
+{
+    int i, j;
+    size_t len = strlen(src);
+    int a, b;
+
+    for (i = j = 0; i < len && i < dstsize; i++) {
+        if (src[i] != ':') {
+            dst[j++] = src[i];
+            continue;
+        }
+
+        i++;
+        a = hex2int((unsigned char)src[i]);
+        b = hex2int((unsigned char)src[i+1]);
+
+        if (a == -1 || b == -1) {
+            /* leave as it */
+            dst[j++] = ':';
+            strncpy(dst+j, src+i, dstsize-j);
+            dst[dstsize-1] = 0;
+            return strlen(dst);
+        }
+
+        i++;
+
+        dst[j++] = a * 16 + b;
+    }
+    dst[j] = 0;
+    return j;
+}
+
+int
+sjis_to_cap(char *dst, const char *src, size_t dstsize)
+{
+    int i, j;
+    size_t len = strlen(src);
+    int a, b;
+
+    for (i = j = 0; i < len && i < dstsize; i++) {
+        if (src[i] == ':') {
+            strncpy(dst+j, ":3a", dstsize-j);
+            dst[dstsize-1] = 0;
+            j = strlen(dst);
+            continue;
+        }
+        if (isprint(src[i])) {
+            dst[j++] = src[i];
+            continue;
+        }
+
+        if (j + 3 >= dstsize) {
+            dst[j] = 0;
+            return j;
+        }
+
+        a = int2hex((unsigned char)src[i] / 16);
+        b = int2hex((unsigned char)src[i] % 16);
+
+        dst[j++] = ':';
+        dst[j++] = a;
+        dst[j++] = b;
+    }
+    dst[j] = 0;
+    return j;
+}
 #endif /* MULTIBYTE_FILENAME */