| /////////////////////////////////////////////////////////////////////////////// |
| // |
| /// \file suffix.c |
| /// \brief Checks filename suffix and creates the destination filename |
| // |
| // Copyright (C) 2007 Lasse Collin |
| // |
| // This program is free software; you can redistribute it and/or |
| // modify it under the terms of the GNU Lesser General Public |
| // License as published by the Free Software Foundation; either |
| // version 2.1 of the License, or (at your option) any later version. |
| // |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| // Lesser General Public License for more details. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "private.h" |
| |
| |
| static const struct { |
| const char *compressed; |
| const char *uncompressed; |
| } suffixes[] = { |
| { ".lzma", "" }, |
| { ".tlz", ".tar" }, |
| { ".ylz", ".yar" }, |
| { NULL, NULL } |
| }; |
| |
| |
| /// \brief Checks if src_name has given compressed_suffix |
| /// |
| /// \param suffix Filename suffix to look for |
| /// \param src_name Input filename |
| /// \param src_len strlen(src_name) |
| /// |
| /// \return If src_name has the suffix, src_len - strlen(suffix) is |
| /// returned. It's always a positive integer. Otherwise zero |
| /// is returned. |
| static size_t |
| test_suffix(const char *suffix, const char *src_name, size_t src_len) |
| { |
| const size_t suffix_len = strlen(suffix); |
| |
| // The filename must have at least one character in addition to |
| // the suffix. src_name may contain path to the filename, so we |
| // need to check for directory separator too. |
| if (src_len <= suffix_len || src_name[src_len - suffix_len - 1] == '/') |
| return 0; |
| |
| if (strcmp(suffix, src_name + src_len - suffix_len) == 0) |
| return src_len - suffix_len; |
| |
| return 0; |
| } |
| |
| |
| /// \brief Removes the filename suffix of the compressed file |
| /// |
| /// \return Name of the uncompressed file, or NULL if file has unknown |
| /// suffix. |
| static char * |
| uncompressed_name(const char *src_name) |
| { |
| const char *new_suffix = ""; |
| const size_t src_len = strlen(src_name); |
| size_t new_len = 0; |
| |
| for (size_t i = 0; suffixes[i].compressed != NULL; ++i) { |
| new_len = test_suffix(suffixes[i].compressed, |
| src_name, src_len); |
| if (new_len != 0) { |
| new_suffix = suffixes[i].uncompressed; |
| break; |
| } |
| } |
| |
| if (new_len == 0 && opt_suffix != NULL) |
| new_len = test_suffix(opt_suffix, src_name, src_len); |
| |
| if (new_len == 0) { |
| errmsg(V_WARNING, _("%s: Filename has an unknown suffix, " |
| "skipping"), src_name); |
| return NULL; |
| } |
| |
| const size_t new_suffix_len = strlen(new_suffix); |
| char *dest_name = malloc(new_len + new_suffix_len + 1); |
| if (dest_name == NULL) { |
| out_of_memory(); |
| return NULL; |
| } |
| |
| memcpy(dest_name, src_name, new_len); |
| memcpy(dest_name + new_len, new_suffix, new_suffix_len); |
| dest_name[new_len + new_suffix_len] = '\0'; |
| |
| return dest_name; |
| } |
| |
| |
| /// \brief Appends suffix to src_name |
| static char * |
| compressed_name(const char *src_name) |
| { |
| const size_t src_len = strlen(src_name); |
| |
| for (size_t i = 0; suffixes[i].compressed != NULL; ++i) { |
| if (test_suffix(suffixes[i].compressed, src_name, src_len) |
| != 0) { |
| errmsg(V_WARNING, _("%s: File already has `%s' " |
| "suffix, skipping"), src_name, |
| suffixes[i].compressed); |
| return NULL; |
| } |
| } |
| |
| const char *suffix = opt_suffix != NULL |
| ? opt_suffix : suffixes[0].compressed; |
| const size_t suffix_len = strlen(suffix); |
| |
| char *dest_name = malloc(src_len + suffix_len + 1); |
| if (dest_name == NULL) { |
| out_of_memory(); |
| return NULL; |
| } |
| |
| memcpy(dest_name, src_name, src_len); |
| memcpy(dest_name + src_len, suffix, suffix_len); |
| dest_name[src_len + suffix_len] = '\0'; |
| |
| return dest_name; |
| } |
| |
| |
| extern char * |
| get_dest_name(const char *src_name) |
| { |
| return opt_mode == MODE_COMPRESS |
| ? compressed_name(src_name) |
| : uncompressed_name(src_name); |
| } |