libarchive/test/test_read_format_isorr_rr_moved.c \
libarchive/test/test_read_format_isozisofs_bz2.c \
libarchive/test/test_read_format_lha.c \
+ libarchive/test/test_read_format_lha_filename.c \
libarchive/test/test_read_format_mtree.c \
libarchive/test/test_read_format_pax_bz2.c \
libarchive/test/test_read_format_raw.c \
libarchive/test/test_read_format_lha_lh6.lzh.uu \
libarchive/test/test_read_format_lha_lh7.lzh.uu \
libarchive/test/test_read_format_lha_withjunk.lzh.uu \
+ libarchive/test/test_read_format_lha_cp932.lzh.uu \
libarchive/test/test_read_format_mtree.mtree.uu \
libarchive/test/test_read_format_mtree_nomagic.mtree.uu \
libarchive/test/test_read_format_raw.data.Z.uu \
/*-
- * Copyright (c) 2008-2010 Michihiro NAKAJIMA
+ * Copyright (c) 2008-2011 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
struct archive_string gname;
uint16_t header_crc;
uint16_t crc;
+ struct archive_string opt_charset;
+ const char *charset;
struct archive_string dirname;
struct archive_string filename;
};
static int archive_read_format_lha_bid(struct archive_read *);
+static int archive_read_format_lha_options(struct archive_read *,
+ const char *, const char *);
static int archive_read_format_lha_read_header(struct archive_read *,
struct archive_entry *);
static int archive_read_format_lha_read_data(struct archive_read *,
static int archive_read_format_lha_read_data_skip(struct archive_read *);
static int archive_read_format_lha_cleanup(struct archive_read *);
+static void lha_replace_path_separator(struct archive_read *, struct lha *,
+ struct archive_string *);
static int lha_read_file_header_0(struct archive_read *, struct lha *);
static int lha_read_file_header_1(struct archive_read *, struct lha *);
static int lha_read_file_header_2(struct archive_read *, struct lha *);
lha,
"lha",
archive_read_format_lha_bid,
- NULL,
+ archive_read_format_lha_options,
archive_read_format_lha_read_header,
archive_read_format_lha_read_data,
archive_read_format_lha_read_data_skip,
return (0);
}
+static int
+archive_read_format_lha_options(struct archive_read *a,
+ const char *key, const char *val)
+{
+ struct lha *lha;
+ int ret = ARCHIVE_FAILED;
+
+ lha = (struct lha *)(a->format->data);
+ if (strcmp(key, "charset") == 0) {
+ if (val == NULL || val[0] == 0)
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "lha: charset option needs a character-set name");
+ else {
+ archive_strcpy(&lha->opt_charset, val);
+ ret = ARCHIVE_OK;
+ }
+ } else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "lha: unknown keyword ``%s''", key);
+
+ return (ret);
+}
+
static int
lha_skip_sfx(struct archive_read *a)
{
archive_string_empty(&lha->dirname);
archive_string_empty(&lha->filename);
lha->dos_attr = 0;
+ if (archive_strlen(&lha->opt_charset) > 0)
+ lha->charset = lha->opt_charset.s;
+ else
+ lha->charset = NULL;
switch (p[H_LEVEL_OFFSET]) {
case 0:
/*
* Make a pathname from a dirname and a filename.
*/
+ archive_string_concat(&lha->dirname, &lha->filename);
archive_string_init(&pathname);
- archive_string_copy(&pathname, &lha->dirname);
- archive_string_concat(&pathname, &lha->filename);
+ archive_strncpy_from_specific_locale(&a->archive, &pathname,
+ lha->dirname.s, lha->dirname.length, lha->charset);
+
+ /*
+ * When a header level is 0, there is a possibilty that
+ * a pathname has '\' character, a directory separator in
+ * DOS/Windows. So we should convert it to '/'.
+ */
+ if (p[H_LEVEL_OFFSET] == 0)
+ lha_replace_path_separator(a, lha, &pathname);
if ((lha->mode & AE_IFMT) == AE_IFLNK) {
/*
* set for a filename in an archive.
*/
static void
-lha_replace_path_separator(struct archive_read *a, struct lha *lha, struct archive_string *fn)
+lha_replace_path_separator(struct archive_read *a, struct lha *lha,
+ struct archive_string *fn)
{
size_t i;
*/
/* If converting to wide character failed, force a replacement. */
- if (!archive_wstring_append_from_mbs(&a->archive, &(lha->ws), fn->s, fn->length)) {
+ if (!archive_wstring_append_from_mbs(&a->archive, &(lha->ws),
+ fn->s, fn->length)) {
for (i = 0; i < archive_strlen(fn); i++) {
if (fn->s[i] == '\\')
fn->s[i] = '/';
* Sanity check that we surely did not break a filename.
*/
archive_string_empty(&(lha->mbs));
- archive_string_append_from_unicode_to_mbs(&a->archive, &(lha->mbs), lha->ws.s, lha->ws.length);
+ archive_string_append_from_unicode_to_mbs(&a->archive, &(lha->mbs),
+ lha->ws.s, lha->ws.length);
/* If mbs length is different to fn, we broke the
* filename and we shouldn't use it. */
if (archive_strlen(&(lha->mbs)) == archive_strlen(fn))
return (truncated_error(a));
archive_strncpy(&lha->filename, p + H0_FILE_NAME_OFFSET, namelen);
- lha_replace_path_separator(a, lha, &lha->filename);
lha->crc = archive_le16dec(p + H0_FILE_NAME_OFFSET + namelen);
sum_calculated = lha_calcsum(0, p, 2, lha->header_size - 2);
lha->origsize = archive_le64dec(extdheader);
}
break;
+ case EXT_CODEPAGE:
+ /* Get a archived filename charset from codepage,
+ * but you cannot overwrite a specified charset. */
+ if (datasize == sizeof(uint32_t) &&
+ lha->charset == NULL) {
+ switch (archive_le32dec(extdheader)) {
+ case 932:
+ lha->charset = "CP932";
+ break;
+ case 65001: /* UTF-8 */
+ lha->charset = "UTF-8";
+ break;
+ default:
+ break;
+ }
+ }
+ break;
case EXT_UNIX_MODE:
if (datasize == sizeof(uint16_t)) {
lha->mode = archive_le16dec(extdheader);
case EXT_TIMEZONE: /* Not supported */
case EXT_UTF16_FILENAME: /* Not supported */
case EXT_UTF16_DIRECTORY: /* Not supported */
- case EXT_CODEPAGE: /* Not supported */
default:
break;
}
lzh_decode_free(&(lha->strm));
free(lha->uncompressed_buffer);
+ archive_string_free(&(lha->opt_charset));
archive_string_free(&(lha->dirname));
archive_string_free(&(lha->filename));
archive_string_free(&(lha->uname));
test_read_format_isorr_rr_moved.c
test_read_format_isozisofs_bz2.c
test_read_format_lha.c
+ test_read_format_lha_filename.c
test_read_format_mtree.c
test_read_format_pax_bz2.c
test_read_format_raw.c
--- /dev/null
+begin 644 test_read_format_lha_cp932.lzh
+M30`M;&@P+0@````(````*:2#32`"&4A-!P!&I`,```L``8J_CIHN='AT&P!!
+M-'"`))KERP%TJNDQFN7+`72JZ3&:Y<L!!@``T2,'``"*OXZ:@JF"R$L`+6QH
+M,"T$````!````#RD@TT@`NA;30<`1J0#```)``&57"YT>'0;`$&:91,VFN7+
+>`:#K$3V:Y<L!H.L1/9KERP$&``#L+0<``&QI<W0`
+`
+end
--- /dev/null
+/*-
+ * Copyright (c) 2011 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD");
+
+#include <locale.h>
+
+DEFINE_TEST(test_read_format_lha_filename)
+{
+ struct archive *a;
+ struct archive_entry *ae;
+
+ /* A sample file was created with LHA32.EXE through UNLHA.DLL. */
+ const char *refname = "test_read_format_lha_cp932.lzh";
+
+ /*
+ * Read LHA filename in ja_JP.eucJP.
+ */
+ if (NULL == setlocale(LC_ALL, "ja_JP.eucJP")) {
+ skipping("ja_JP.eucJP locale not available on this system.");
+ return;
+ }
+
+ extract_reference_file(refname);
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ /* Verify regular file. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("\xB4\xC1\xBB\xFA\x2E\x74\x78\x74",
+ archive_entry_pathname(ae));
+ assertEqualInt(8, archive_entry_size(ae));
+
+ /* Verify regular file. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("\xC9\xBD\x2E\x74\x78\x74", archive_entry_pathname(ae));
+ assertEqualInt(4, archive_entry_size(ae));
+
+
+ /* End of archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ /* Verify archive format. */
+ assertEqualIntA(a, ARCHIVE_COMPRESSION_NONE, archive_compression(a));
+ assertEqualIntA(a, ARCHIVE_FORMAT_LHA, archive_format(a));
+
+ /* Close the archive. */
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+
+ /*
+ * Read LHA filename in ja_JP.UTF-8.
+ */
+ if (NULL == setlocale(LC_ALL, "ja_JP.UTF-8")) {
+ skipping("ja_JP.UTF-8 locale not available on this system.");
+ return;
+ }
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ /* Verify regular file. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("\xE6\xBC\xA2\xE5\xAD\x97\x2E\x74\x78\x74",
+ archive_entry_pathname(ae));
+ assertEqualInt(8, archive_entry_size(ae));
+
+ /* Verify regular file. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("\xE8\xA1\xA8\x2E\x74\x78\x74",
+ archive_entry_pathname(ae));
+ assertEqualInt(4, archive_entry_size(ae));
+
+
+ /* End of archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ /* Verify archive format. */
+ assertEqualIntA(a, ARCHIVE_COMPRESSION_NONE, archive_compression(a));
+ assertEqualIntA(a, ARCHIVE_FORMAT_LHA, archive_format(a));
+
+ /* Close the archive. */
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+