From 57025a614d3d893cb05be011e48870be80a8ee6a Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Thu, 17 Jan 2008 00:15:42 +0100 Subject: [PATCH] Support for reading ISO-9660:1999 images. --- demo/iso_ms.c | 1 + demo/iso_read.c | 1 + src/fs_image.c | 103 +++++++++++++++++++++++++++++++++++++----------- src/libisofs.h | 7 ++++ src/util.c | 42 ++++++++++++++++++++ src/util.h | 3 ++ 6 files changed, 135 insertions(+), 22 deletions(-) diff --git a/demo/iso_ms.c b/demo/iso_ms.c index fccc759..6fc5896 100644 --- a/demo/iso_ms.c +++ b/demo/iso_ms.c @@ -59,6 +59,7 @@ int main(int argc, char **argv) 0, /* block */ 0, /* norock */ 0, /* nojoliet */ + 0, /* noiso1999 */ 0, /* preferjoliet */ 0, /* uid; */ 0, /* gid; */ diff --git a/demo/iso_read.c b/demo/iso_read.c index 95844eb..f5a528a 100644 --- a/demo/iso_read.c +++ b/demo/iso_read.c @@ -116,6 +116,7 @@ int main(int argc, char **argv) 0, /* block */ 0, /* norock */ 0, /* nojoliet */ + 0, /* noiso1999 */ 0, /* preferjoliet */ 0, /* uid; */ 0, /* gid; */ diff --git a/src/fs_image.c b/src/fs_image.c index c3bff96..72902ed 100644 --- a/src/fs_image.c +++ b/src/fs_image.c @@ -91,19 +91,18 @@ typedef struct */ uint32_t svd_root_block; + /** + * Will be filled with the block lba of the extend for the root directory, + * as read from the enhanced volume descriptor (ISO 9660:1999) + */ + uint32_t evd_root_block; + /** * If we need to read RR extensions. i.e., if the image contains RR * extensions, and the user wants to read them. */ enum read_rr_ext rr; - /** - * The function used to read the name from a directoy record. For ISO, - * the name is in US-ASCII. For Joliet, in UCS-2BE. Thus, we need - * different functions for both. - */ - char *(*get_name)(const char *, size_t); - /** * Bytes skipped within the System Use field of a directory record, before * the beginning of the SUSP system user entries. See IEEE 1281, SUSP. 5.3. @@ -131,6 +130,9 @@ typedef struct /** If Joliet extensions are available on image */ unsigned int joliet : 1; + + /** If ISO 9660:1999 is available on image */ + unsigned int iso1999 : 1; /** * Number of blocks of the volume, as reported in the PVM. @@ -695,6 +697,40 @@ IsoFileSourceIface ifs_class = { ifs_free }; +/** + * Read a file name from a directory record, doing the needed charset + * conversion + */ +static +char *get_name(_ImageFsData *fsdata, const char *str, size_t len) +{ + int ret; + char *name = NULL; + if (strcmp(fsdata->local_charset, fsdata->input_charset)) { + /* charset conversion needed */ + ret = strnconv(str, fsdata->input_charset, fsdata->local_charset, len, + &name); + if (ret == 1) { + return name; + } else { + iso_msg_sorry(fsdata->messenger, LIBISO_CHARSET_ERROR, + "Charset conversion error. Can't convert %s from %s to %s", + str, fsdata->input_charset, fsdata->local_charset); + /* fallback */ + } + } + + /* we reach here when the charset conversion is not needed or has failed */ + + name = malloc(len + 1); + if (name == NULL) { + return NULL; + } + memcpy(name, str, len); + name[len] = '\0'; + return name; +} + /** * * @return @@ -991,7 +1027,8 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, return ISO_WRONG_ECMA119; } } else { - name = fsdata->get_name((char*)record->file_id, record->len_fi[0]); + + name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]); if (name == NULL) { iso_msg_sorry(fsdata->messenger, LIBISO_WRONG_IMG, "Can't retrieve file name"); @@ -1625,15 +1662,6 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, ret = ISO_MEM_ERROR; goto fs_cleanup; } - if (opts->input_charset != NULL) { - data->input_charset = strdup(opts->input_charset); - } else { - data->input_charset = strdup(data->local_charset); - } - if (data->input_charset == NULL) { - ret = ISO_MEM_ERROR; - goto fs_cleanup; - } ifs->open = ifs_fs_open; ifs->close = ifs_fs_close; @@ -1701,15 +1729,30 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, sup->esc_sequences[2] == 0x45) ) { /* it's a Joliet Sup. Vol. Desc. */ + iso_msg_debug(data->messenger, "Found Joliet extensions"); data->joliet = 1; root = (struct ecma119_dir_record*)sup->root_dir_record; data->svd_root_block = iso_read_bb(root->block, 4, NULL); //TODO maybe we can set the IsoImage attribs from this //descriptor + //TODO a joliet tree can also have RR extensions. What + //about this? + + } else if (sup->vol_desc_version[0] == 2) { + /* + * It is an Enhanced Volume Descriptor, image is an + * ISO 9660:1999 + */ + iso_msg_debug(data->messenger, "Found ISO 9660:1999"); + data->iso1999 = 1; + root = (struct ecma119_dir_record*)sup->root_dir_record; + data->evd_root_block = iso_read_bb(root->block, 4, NULL); + //TODO an ISO 9660:1999 tree can also have RR extensions. + // What about this? } else { iso_msg_hint(data->messenger, LIBISO_UNSUPPORTED_VD, - "Unsupported (not Joliet) Sup. Vol. Desc found."); + "Unsupported Sup. Vol. Desc found."); } } break; @@ -1746,30 +1789,45 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, if (!opts->nojoliet && opts->preferjoliet && data->joliet) { /* if user prefers joliet, that is used */ iso_msg_debug(data->messenger, "Reading Joliet extensions."); - data->get_name = ucs2str; + data->input_charset = strdup("UCS-2BE"); data->rr = RR_EXT_NO; data->iso_root_block = data->svd_root_block; } else { /* RR will be used */ iso_msg_debug(data->messenger, "Reading Rock Ridge extensions."); data->iso_root_block = data->pvd_root_block; - data->get_name = strcopy; } } else { /* RR extensions are not available */ if (!opts->nojoliet && data->joliet) { /* joliet will be used */ iso_msg_debug(data->messenger, "Reading Joliet extensions."); - data->get_name = ucs2str; + data->input_charset = strdup("UCS-2BE"); data->iso_root_block = data->svd_root_block; + } else if (!opts->noiso1999 && data->iso1999) { + /* we will read ISO 9660:1999 */ + iso_msg_debug(data->messenger, "Reading ISO-9660:1999 tree."); + data->iso_root_block = data->evd_root_block; } else { /* default to plain iso */ iso_msg_debug(data->messenger, "Reading plain ISO-9660 tree."); data->iso_root_block = data->pvd_root_block; - data->get_name = strcopy; + data->input_charset = strdup("ASCII"); } } + if (data->input_charset == NULL) { + if (opts->input_charset != NULL) { + data->input_charset = strdup(opts->input_charset); + } else { + data->input_charset = strdup(data->local_charset); + } + } + if (data->input_charset == NULL) { + ret = ISO_MEM_ERROR; + goto fs_cleanup; + } + /* and finally return. Note that we keep the DataSource opened */ *fs = ifs; @@ -2203,6 +2261,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, if (features != NULL) { features->hasJoliet = data->joliet; features->hasRR = data->rr_version != 0; + features->hasIso1999 = data->iso1999; features->hasElTorito = data->eltorito; features->size = data->nblocks; } diff --git a/src/libisofs.h b/src/libisofs.h index 5b28a48..99d86cb 100644 --- a/src/libisofs.h +++ b/src/libisofs.h @@ -350,6 +350,7 @@ struct iso_read_opts unsigned int norock : 1; /*< Do not read Rock Ridge extensions */ unsigned int nojoliet : 1; /*< Do not read Joliet extensions */ + unsigned int noiso1999 : 1; /*< Do not read ISO 9660:1999 enhanced tree */ /** * When both Joliet and RR extensions are present, the RR tree is used. @@ -382,6 +383,12 @@ struct iso_read_image_features /** It will be set to 1 if Joliet extensions are present, to 0 if not. */ unsigned int hasJoliet :1; + /** + * It will be set to 1 if the image is an ISO 9660:1999, i.e. it ha + * a version 2 Enhanced Volume Descriptor. + */ + unsigned int hasIso1999 :1; + /** It will be set to 1 if El-Torito boot record is present, to 0 if not.*/ unsigned int hasElTorito :1; diff --git a/src/util.c b/src/util.c index 8b7f4f1..bca124f 100644 --- a/src/util.c +++ b/src/util.c @@ -86,6 +86,48 @@ int strconv(const char *str, const char *icharset, const char *ocharset, return ISO_SUCCESS; } +int strnconv(const char *str, const char *icharset, const char *ocharset, + size_t len, char **output) +{ + size_t inbytes; + size_t outbytes; + size_t n; + iconv_t conv; + char *out; + char *src; + char *ret; + + inbytes = len; + outbytes = (inbytes + 1) * MB_LEN_MAX; + out = alloca(outbytes); + if (out == NULL) { + return ISO_MEM_ERROR; + } + + conv = iconv_open(ocharset, icharset); + if (conv == (iconv_t)(-1)) { + return ISO_CHARSET_CONV_ERROR; + } + src = (char *)str; + ret = (char *)out; + + n = iconv(conv, &src, &inbytes, &ret, &outbytes); + if (n == -1) { + /* error */ + iconv_close(conv); + return ISO_CHARSET_CONV_ERROR; + } + *ret = '\0'; + iconv_close(conv); + + *output = malloc(ret - out + 1); + if (*output == NULL) { + return ISO_MEM_ERROR; + } + memcpy(*output, out, ret - out + 1); + return ISO_SUCCESS; +} + /** * Convert a str in a specified codeset to WCHAR_T. * The result must be free() when no more needed diff --git a/src/util.h b/src/util.h index 376326f..cba87bb 100644 --- a/src/util.h +++ b/src/util.h @@ -42,6 +42,9 @@ int int_pow(int base, int power); int strconv(const char *input, const char *icharset, const char *ocharset, char **output); +int strnconv(const char *str, const char *icharset, const char *ocharset, + size_t len, char **output); + /** * Convert a given string from any input charset to ASCII *