From a9e0723b71cf861a3cb7aca6b97482de06bad677 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 19 Sep 2006 17:07:21 +0000 Subject: [PATCH] Backported fix for charset warning and memory leaks --- branches/0.2.2/libisofs/ecma119.c | 8 +- branches/0.2.2/libisofs/joliet.c | 9 +- branches/0.2.2/libisofs/tree.c | 6 +- branches/0.2.2/libisofs/tree.h | 2 +- branches/0.2.2/libisofs/util.c | 215 +++++++++++++++++++++--------- branches/0.2.2/libisofs/util.h | 18 +-- branches/0.2.2/libisofs/volume.c | 8 +- branches/0.2.2/libisofs/volume.h | 8 +- 8 files changed, 179 insertions(+), 95 deletions(-) diff --git a/branches/0.2.2/libisofs/ecma119.c b/branches/0.2.2/libisofs/ecma119.c index 5a2b2fc5..53e4e7bd 100755 --- a/branches/0.2.2/libisofs/ecma119.c +++ b/branches/0.2.2/libisofs/ecma119.c @@ -429,10 +429,10 @@ write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf) { struct ecma119_pri_vol_desc *vol = (struct ecma119_pri_vol_desc*)buf; struct iso_volume *volume = t->volset->volume[t->volnum]; - char *vol_id = wcstoascii(volume->volume_id); - char *pub_id = wcstoascii(volume->publisher_id); - char *data_id = wcstoascii(volume->data_preparer_id); - char *volset_id = wcstoascii(t->volset->volset_id); + char *vol_id = str2ascii(volume->volume_id); + char *pub_id = str2ascii(volume->publisher_id); + char *data_id = str2ascii(volume->data_preparer_id); + char *volset_id = str2ascii(t->volset->volset_id); vol->vol_desc_type[0] = 1; memcpy(vol->std_identifier, "CD001", 5); diff --git a/branches/0.2.2/libisofs/joliet.c b/branches/0.2.2/libisofs/joliet.c index 82ec0ff3..d1ddad97 100644 --- a/branches/0.2.2/libisofs/joliet.c +++ b/branches/0.2.2/libisofs/joliet.c @@ -129,6 +129,7 @@ joliet_calc_dir_pos(struct ecma119_write_target *t, root->block = t->curblock; t->curblock += div_up(root->len, t->block_size); + t->dirlist_joliet[t->curfile++] = root; for (i = 0; i < root->nchildren; i++) { ch = root->children[i]; @@ -231,10 +232,10 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf) { struct ecma119_sup_vol_desc *vol = (struct ecma119_sup_vol_desc*)buf; struct iso_volume *volume = t->volset->volume[t->volnum]; - uint16_t *vol_id = wcstoucs(volume->volume_id); - uint16_t *pub_id = wcstoucs(volume->publisher_id); - uint16_t *data_id = wcstoucs(volume->data_preparer_id); - uint16_t *volset_id = wcstoucs(t->volset->volset_id); + uint16_t *vol_id = str2ucs(volume->volume_id); + uint16_t *pub_id = str2ucs(volume->publisher_id); + uint16_t *data_id = str2ucs(volume->data_preparer_id); + uint16_t *volset_id = str2ucs(t->volset->volset_id); int vol_id_len = MIN(32, ucslen(vol_id) * 2); int pub_id_len = MIN(128, ucslen(pub_id) * 2); int data_id_len = MIN(128, ucslen(data_id) * 2); diff --git a/branches/0.2.2/libisofs/tree.c b/branches/0.2.2/libisofs/tree.c index 08a1bbf3..57aa0dfd 100755 --- a/branches/0.2.2/libisofs/tree.c +++ b/branches/0.2.2/libisofs/tree.c @@ -86,7 +86,7 @@ iso_tree_add_new_file(struct iso_tree_node *parent, const char *name) f->volume = parent ? parent->volume : NULL; f->parent = parent; - f->name = parent ? towcs(name) : NULL; + f->name = parent ? strdup(name) : NULL; f->attrib = get_attrib(parent); f->attrib.st_mode = 0777 | S_IFREG; f->loc.type = LIBISO_NONE; @@ -192,7 +192,7 @@ iso_tree_print(const struct iso_tree_node *root, int spaces) memset(sp, ' ', spaces); sp[spaces] = '\0'; - printf("%s%ls\n", sp, root->name); + printf("%s%sn", sp, root->name); for (i=0; i < root->nchildren; i++) { iso_tree_print(root->children[i], spaces+2); } @@ -219,5 +219,5 @@ void iso_tree_node_set_name(struct iso_tree_node *file, const char *name) { free(file->name); - file->name = towcs(name); + file->name = strdup(name); } diff --git a/branches/0.2.2/libisofs/tree.h b/branches/0.2.2/libisofs/tree.h index db215f86..e0e04609 100755 --- a/branches/0.2.2/libisofs/tree.h +++ b/branches/0.2.2/libisofs/tree.h @@ -51,7 +51,7 @@ struct iso_tree_node { struct iso_volume *volume; struct iso_tree_node *parent; - wchar_t *name; + char *name; struct stat attrib; /**< The POSIX attributes of this node as * documented in "man 2 stat". */ struct iso_file_location loc; diff --git a/branches/0.2.2/libisofs/util.c b/branches/0.2.2/libisofs/util.c index 44bb928b..186c7951 100755 --- a/branches/0.2.2/libisofs/util.c +++ b/branches/0.2.2/libisofs/util.c @@ -13,9 +13,15 @@ #include #include #include +#include #include "util.h" +/* avoids warning and names in iso, joliet and rockridge can't be > 255 bytes + * anyway. There are at most 31 characters in iso level 1, 255 for rockridge, + * 64 characters (* 2 since UCS) for joliet. */ +#define NAME_BUFFER_SIZE 255 + int div_up(int n, int div) { return (n + div - 1) / div; @@ -26,85 +32,162 @@ int round_up(int n, int mul) return div_up(n, mul) * mul; } -wchar_t *towcs(const char *str) +/* this function must always return a name + * since the caller never checks if a NULL + * is returned. It also avoids some warnings. */ +char *str2ascii(const char *src_arg) { - size_t len = strlen(str); - wchar_t *ret = malloc(sizeof(wchar_t) * (len + 1)); - mbstate_t ps; + wchar_t wsrc_[NAME_BUFFER_SIZE]; + char *src = (char*)wsrc_; + char *ret_; + char *ret; + mbstate_t state; + iconv_t conv; + size_t numchars; + size_t outbytes; + size_t inbytes; size_t n; - memset(&ps, 0, sizeof(ps)); - n = mbsrtowcs(ret, &str, len, &ps); - ret[len] = '\0'; - - if (n != len) { - free(ret); - return NULL; - } - return ret; -} - -char *wcstoascii(const wchar_t *wsrc) -{ - if (!wsrc) + if (!src_arg) return NULL; - iconv_t conv = iconv_open("ASCII", "WCHAR_T"); - size_t outbytes = wcslen(wsrc); - size_t inbytes = outbytes * sizeof(wchar_t); - char src_[inbytes + sizeof(wchar_t)]; - char *src = src_; - char *ret_, *ret; - size_t n; + /* convert the string to a wide character string. Note: outbytes + * is in fact the number of characters in the string and doesn't + * include the last NULL character. */ + memset(&state, 0, sizeof(state)); + numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state); + if (numchars < 0) + return NULL; + inbytes = numchars * sizeof(wchar_t); + + ret_ = malloc(numchars+1); + outbytes = numchars; + ret = ret_; + + /* initialize iconv */ + conv = iconv_open("ASCII", "WCHAR_T"); if (conv == (iconv_t)-1) return NULL; - memcpy(src, wsrc, inbytes + sizeof(wchar_t)); - ret = malloc(outbytes+1); - ret[outbytes] = '\0'; - ret_ = ret; - n = iconv(conv, &src, &inbytes, &ret, &outbytes); - if (n == -1) { - free(ret_); - return NULL; + while(n == -1) { + /* The destination buffer is too small. Stops here. */ + if(errno == E2BIG) + break; + + /* An incomplete multi bytes sequence was found. We + * can't do anything here. That's quite unlikely. */ + if(errno == EINVAL) + break; + + /* The last possible error is an invalid multi bytes + * sequence. Just replace the character with a "_". + * Probably the character doesn't exist in ascii like + * "é, è, à, ç, ..." in French. */ + *ret++ = '_'; + outbytes--; + + if(!outbytes) + break; + + /* There was an error with one character but some other remain + * to be converted. That's probably a multibyte character. + * See above comment. */ + src += sizeof(wchar_t); + inbytes -= sizeof(wchar_t); + + if(!inbytes) + break; + + n = iconv(conv, &src, &inbytes, &ret, &outbytes); } + + iconv_close(conv); + + *ret='\0'; return ret_; } /* FIXME: C&P */ -uint16_t *wcstoucs(const wchar_t *wsrc) +uint16_t *str2ucs(const char *src_arg) { - if (!wsrc) - return calloc(2, 1); /* empty UCS string */ - - iconv_t conv = iconv_open("UCS-2BE", "WCHAR_T"); - size_t outbytes = wcslen(wsrc) * 2; - size_t inbytes = outbytes * sizeof(wchar_t) / 2; - char src_[inbytes + sizeof(wchar_t)]; - char *src = src_; - char *ret_, *ret; + wchar_t wsrc_[NAME_BUFFER_SIZE]; + char *src = (char*)wsrc_; + char *ret_; + char *ret; + mbstate_t state; + iconv_t conv; + size_t outbytes; + size_t numchars; + size_t inbytes; size_t n; - if (conv == (iconv_t)-1) - return calloc(2, 1); + if (!src_arg) + return calloc(2, 1); /* empty UCS string */ - memcpy(src, wsrc, inbytes + sizeof(wchar_t)); - ret = malloc(outbytes + sizeof(wchar_t)); - ret[outbytes] = 0; - ret[outbytes+1] = 0; - ret_ = ret; + /* convert the string to a wide character string. Note: outbytes + * is in fact the number of characters in the string and doesn't + * include the last NULL character. */ + memset(&state, 0, sizeof(state)); + numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state); + if (numchars < 0) + return calloc(2, 1); /* empty UCS string */ + + inbytes = numchars * sizeof(wchar_t); + + outbytes = numchars * sizeof(uint16_t); + ret_ = malloc ((numchars+1) * sizeof(uint16_t)); + ret = ret_; + + /* initialize iconv */ + conv = iconv_open("UCS-2BE", "WCHAR_T"); + if (conv == (iconv_t)-1) + return calloc(2, 1); /* empty UCS string */ n = iconv(conv, &src, &inbytes, &ret, &outbytes); - if (n == -1) { - perror ("error in iconv conversion"); - free(ret_); - return calloc(2, 1); + while(n == -1) { + /* The destination buffer is too small. Stops here. */ + if(errno == E2BIG) + break; + + /* An incomplete multi bytes sequence was found. We + * can't do anything here. That's quite unlikely. */ + if(errno == EINVAL) + break; + + /* The last possible error is an invalid multi bytes + * sequence. Just replace the character with a "_". + * Probably the character doesn't exist in ascii like + * "é, è, à, ç, ..." in French. */ + *((uint16_t*) ret) = '_'; + ret += sizeof(uint16_t); + outbytes -= sizeof(uint16_t); + + if(!outbytes) + break; + + /* There was an error with one character but some other remain + * to be converted. That's probably a multibyte character. + * See above comment. */ + src += sizeof(wchar_t); + inbytes -= sizeof(wchar_t); + + if(!inbytes) + break; + + n = iconv(conv, &src, &inbytes, &ret, &outbytes); } + + iconv_close(conv); + + /* close the ucs string */ + *((uint16_t*) ret) = 0; + return (uint16_t*)ret_; } + static int valid_d_char(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_'); @@ -132,9 +215,9 @@ static int valid_p_char(char c) || (c == '.') || (c == '_') || (c == '-'); } -static char *iso_dirid(const wchar_t *src, int size) +static char *iso_dirid(const char *src, int size) { - char *ret = wcstoascii(src); + char *ret = str2ascii(src); size_t len, i; if (!ret) @@ -153,19 +236,19 @@ static char *iso_dirid(const wchar_t *src, int size) return ret; } -char *iso_1_dirid(const wchar_t *src) +char *iso_1_dirid(const char *src) { return iso_dirid(src, 8); } -char *iso_2_dirid(const wchar_t *src) +char *iso_2_dirid(const char *src) { return iso_dirid(src, 31); } -char *iso_1_fileid(const wchar_t *wsrc) +char *iso_1_fileid(const char *src_arg) { - char *src = wcstoascii(wsrc); + char *src = str2ascii(src_arg); char *dest; char *dot; /* Position of the last dot in the filename, will be used to calculate @@ -214,9 +297,9 @@ char *iso_1_fileid(const wchar_t *wsrc) return dest; } -char *iso_2_fileid(const wchar_t *wsrc) +char *iso_2_fileid(const char *src_arg) { - char *src = wcstoascii(wsrc); + char *src = str2ascii(src_arg); char *dest; char *dot; int lname, lext, lnname, lnext, pos, i; @@ -274,9 +357,9 @@ char *iso_2_fileid(const wchar_t *wsrc) } char * -iso_p_fileid(const wchar_t *src) +iso_p_fileid(const char *src) { - char *ret = wcstoascii(src); + char *ret = str2ascii(src); size_t i, len; if (!ret) @@ -291,9 +374,9 @@ iso_p_fileid(const wchar_t *src) } uint16_t * -iso_j_id(const wchar_t *src) +iso_j_id(const char *src_arg) { - uint16_t *j_str = wcstoucs(src); + uint16_t *j_str = str2ucs(src_arg); size_t len = ucslen(j_str); size_t n; diff --git a/branches/0.2.2/libisofs/util.h b/branches/0.2.2/libisofs/util.h index 03099fae..c8736aca 100755 --- a/branches/0.2.2/libisofs/util.h +++ b/branches/0.2.2/libisofs/util.h @@ -31,18 +31,18 @@ extern inline int round_up(int n, int mul) } wchar_t *towcs(const char *); -char *wcstoascii(const wchar_t *); -uint16_t *wcstoucs(const wchar_t*); +char *str2ascii(const char*); +uint16_t *str2ucs(const char*); /** * Create a level 1 directory identifier. */ -char *iso_1_dirid(const wchar_t *src); +char *iso_1_dirid(const char *src); /** * Create a level 2 directory identifier. */ -char *iso_2_dirid(const wchar_t *src); +char *iso_2_dirid(const char *src); /** * Create a level 1 file identifier that consists of a name, extension and @@ -51,7 +51,7 @@ char *iso_2_dirid(const wchar_t *src); * length 3, followed by a separator (;) and a version number (digit 1). * @return NULL if the original name and extension both are of length 0. */ -char *iso_1_fileid(const wchar_t *src); +char *iso_1_fileid(const char *src); /** * Create a level 2 file identifier that consists of a name, extension and @@ -60,7 +60,7 @@ char *iso_1_fileid(const wchar_t *src); * followed by a separator (;) and a version number (digit 1). * @return NULL if the original name and extension both are of length 0. */ -char *iso_2_fileid(const wchar_t *src); +char *iso_2_fileid(const char *src); /** * Create a Joliet file or directory identifier that consists of a name, @@ -73,7 +73,7 @@ char *iso_2_fileid(const wchar_t *src); * @param size will be set to the size (in bytes) of the identifier. * @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available. */ -uint16_t *iso_j_id(const wchar_t *src); +uint16_t *iso_j_id(const char *src); /** * FIXME: what are the requirements for these next two? Is this for RR? @@ -82,14 +82,14 @@ uint16_t *iso_j_id(const wchar_t *src); * The resulting file name will not exceed 250 characters. * @return NULL if the original name and extension both are of length 0. */ -char *iso_p_fileid(const wchar_t *src); +char *iso_p_fileid(const char *src); /** * Create a POSIX portable directory name. * The resulting directory name will not exceed 250 characters. * @return NULL if the original name is of length 0. */ -char *iso_p_dirid(const wchar_t *src); +char *iso_p_dirid(const char *src); void iso_lsb(uint8_t *buf, uint32_t num, int bytes); void iso_msb(uint8_t *buf, uint32_t num, int bytes); diff --git a/branches/0.2.2/libisofs/volume.c b/branches/0.2.2/libisofs/volume.c index 4ed756bf..65cbbbf9 100755 --- a/branches/0.2.2/libisofs/volume.c +++ b/branches/0.2.2/libisofs/volume.c @@ -19,7 +19,7 @@ iso_volset_new(struct iso_volume *vol, const char *id) volset->refcount = 1; volset->volume = malloc(sizeof(void *)); volset->volume[0] = vol; - volset->volset_id = towcs(id); + volset->volset_id = strdup(id); vol->refcount++; return volset; @@ -63,11 +63,11 @@ iso_volume_new_with_root(const char *volume_id, volume->root = root ? root : iso_tree_new_root(volume); if (volume_id != NULL) - volume->volume_id = towcs(volume_id); + volume->volume_id = strdup(volume_id); if (publisher_id != NULL) - volume->publisher_id = towcs(publisher_id); + volume->publisher_id = strdup(publisher_id); if (data_preparer_id != NULL) - volume->data_preparer_id = towcs(data_preparer_id); + volume->data_preparer_id = strdup(data_preparer_id); return volume; } diff --git a/branches/0.2.2/libisofs/volume.h b/branches/0.2.2/libisofs/volume.h index d310df6b..89031860 100755 --- a/branches/0.2.2/libisofs/volume.h +++ b/branches/0.2.2/libisofs/volume.h @@ -21,9 +21,9 @@ struct iso_volume struct iso_tree_node *root; /**< Root of the directory tree for the volume. */ - wchar_t *volume_id; /**< Volume identifier. */ - wchar_t *publisher_id; /**< Volume publisher. */ - wchar_t *data_preparer_id; /**< Volume data preparer. */ + char *volume_id; /**< Volume identifier. */ + char *publisher_id; /**< Volume publisher. */ + char *data_preparer_id; /**< Volume data preparer. */ }; /** @@ -38,7 +38,7 @@ struct iso_volset int volset_size; /**< The number of volumes in this volume set. */ - wchar_t *volset_id; /**< The id of this volume set, encoded + char *volset_id; /**< The id of this volume set, encoded in the current locale. */ };