]> icculus.org git repositories - icculus/xz.git/blob - src/lzma/suffix.c
Imported to git.
[icculus/xz.git] / src / lzma / suffix.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       suffix.c
4 /// \brief      Checks filename suffix and creates the destination filename
5 //
6 //  Copyright (C) 2007 Lasse Collin
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "private.h"
21
22
23 static const struct {
24         const char *compressed;
25         const char *uncompressed;
26 } suffixes[] = {
27         { ".lzma",  "" },
28         { ".tlz",   ".tar" },
29         { ".ylz",   ".yar" },
30         { NULL,     NULL }
31 };
32
33
34 /// \brief      Checks if src_name has given compressed_suffix
35 ///
36 /// \param      suffix      Filename suffix to look for
37 /// \param      src_name    Input filename
38 /// \param      src_len     strlen(src_name)
39 ///
40 /// \return     If src_name has the suffix, src_len - strlen(suffix) is
41 ///             returned. It's always a positive integer. Otherwise zero
42 ///             is returned.
43 static size_t
44 test_suffix(const char *suffix, const char *src_name, size_t src_len)
45 {
46         const size_t suffix_len = strlen(suffix);
47
48         // The filename must have at least one character in addition to
49         // the suffix. src_name may contain path to the filename, so we
50         // need to check for directory separator too.
51         if (src_len <= suffix_len || src_name[src_len - suffix_len - 1] == '/')
52                 return 0;
53
54         if (strcmp(suffix, src_name + src_len - suffix_len) == 0)
55                 return src_len - suffix_len;
56
57         return 0;
58 }
59
60
61 /// \brief      Removes the filename suffix of the compressed file
62 ///
63 /// \return     Name of the uncompressed file, or NULL if file has unknown
64 ///             suffix.
65 static char *
66 uncompressed_name(const char *src_name)
67 {
68         const char *new_suffix = "";
69         const size_t src_len = strlen(src_name);
70         size_t new_len = 0;
71
72         for (size_t i = 0; suffixes[i].compressed != NULL; ++i) {
73                 new_len = test_suffix(suffixes[i].compressed,
74                                 src_name, src_len);
75                 if (new_len != 0) {
76                         new_suffix = suffixes[i].uncompressed;
77                         break;
78                 }
79         }
80
81         if (new_len == 0 && opt_suffix != NULL)
82                 new_len = test_suffix(opt_suffix, src_name, src_len);
83
84         if (new_len == 0) {
85                 errmsg(V_WARNING, _("%s: Filename has an unknown suffix, "
86                                 "skipping"), src_name);
87                 return NULL;
88         }
89
90         const size_t new_suffix_len = strlen(new_suffix);
91         char *dest_name = malloc(new_len + new_suffix_len + 1);
92         if (dest_name == NULL) {
93                 out_of_memory();
94                 return NULL;
95         }
96
97         memcpy(dest_name, src_name, new_len);
98         memcpy(dest_name + new_len, new_suffix, new_suffix_len);
99         dest_name[new_len + new_suffix_len] = '\0';
100
101         return dest_name;
102 }
103
104
105 /// \brief      Appends suffix to src_name
106 static char *
107 compressed_name(const char *src_name)
108 {
109         const size_t src_len = strlen(src_name);
110
111         for (size_t i = 0; suffixes[i].compressed != NULL; ++i) {
112                 if (test_suffix(suffixes[i].compressed, src_name, src_len)
113                                 != 0) {
114                         errmsg(V_WARNING, _("%s: File already has `%s' "
115                                         "suffix, skipping"), src_name,
116                                         suffixes[i].compressed);
117                         return NULL;
118                 }
119         }
120
121         const char *suffix = opt_suffix != NULL
122                         ? opt_suffix : suffixes[0].compressed;
123         const size_t suffix_len = strlen(suffix);
124
125         char *dest_name = malloc(src_len + suffix_len + 1);
126         if (dest_name == NULL) {
127                 out_of_memory();
128                 return NULL;
129         }
130
131         memcpy(dest_name, src_name, src_len);
132         memcpy(dest_name + src_len, suffix, suffix_len);
133         dest_name[src_len + suffix_len] = '\0';
134
135         return dest_name;
136 }
137
138
139 extern char *
140 get_dest_name(const char *src_name)
141 {
142         return opt_mode == MODE_COMPRESS
143                         ? compressed_name(src_name)
144                         : uncompressed_name(src_name);
145 }