1248590Smm/*-
2248590Smm * Copyright (c) 2003-2012 Tim Kientzle
3248590Smm * All rights reserved.
4248590Smm *
5248590Smm * Redistribution and use in source and binary forms, with or without
6248590Smm * modification, are permitted provided that the following conditions
7248590Smm * are met:
8248590Smm * 1. Redistributions of source code must retain the above copyright
9248590Smm *    notice, this list of conditions and the following disclaimer.
10248590Smm * 2. Redistributions in binary form must reproduce the above copyright
11248590Smm *    notice, this list of conditions and the following disclaimer in the
12248590Smm *    documentation and/or other materials provided with the distribution.
13248590Smm *
14248590Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15248590Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16248590Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17248590Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18248590Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19248590Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20248590Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21248590Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22248590Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23248590Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24248590Smm */
25248590Smm
26248590Smm#include "archive_platform.h"
27248590Smm__FBSDID("$FreeBSD$");
28248590Smm
29248590Smm#ifdef HAVE_ERRNO_H
30248590Smm#include <errno.h>
31248590Smm#endif
32248590Smm
33248590Smm#include "archive.h"
34248590Smm#include "archive_private.h"
35248590Smm#include "archive_read_private.h"
36248590Smm
37248590Smmint
38248590Smmarchive_read_append_filter(struct archive *_a, int code)
39248590Smm{
40248590Smm  int r1, r2, number_bidders, i;
41248590Smm  char str[20];
42248590Smm  struct archive_read_filter_bidder *bidder;
43248590Smm  struct archive_read_filter *filter;
44248590Smm  struct archive_read *a = (struct archive_read *)_a;
45248590Smm
46248590Smm  r1 = r2 = (ARCHIVE_OK);
47248590Smm  switch (code)
48248590Smm  {
49248590Smm    case ARCHIVE_FILTER_NONE:
50248590Smm      /* No filter to add, so do nothing.
51248590Smm       * NOTE: An initial "NONE" type filter is always set at the end of the
52248590Smm       * filter chain.
53248590Smm       */
54248590Smm      r1 = (ARCHIVE_OK);
55248590Smm      break;
56248590Smm    case ARCHIVE_FILTER_GZIP:
57248590Smm      strcpy(str, "gzip");
58248590Smm      r1 = archive_read_support_filter_gzip(_a);
59248590Smm      break;
60248590Smm    case ARCHIVE_FILTER_BZIP2:
61248590Smm      strcpy(str, "bzip2");
62248590Smm      r1 = archive_read_support_filter_bzip2(_a);
63248590Smm      break;
64248590Smm    case ARCHIVE_FILTER_COMPRESS:
65248590Smm      strcpy(str, "compress (.Z)");
66248590Smm      r1 = archive_read_support_filter_compress(_a);
67248590Smm      break;
68248590Smm    case ARCHIVE_FILTER_PROGRAM:
69248590Smm      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
70248590Smm          "Cannot append program filter using archive_read_append_filter");
71248590Smm      return (ARCHIVE_FATAL);
72248590Smm    case ARCHIVE_FILTER_LZMA:
73248590Smm      strcpy(str, "lzma");
74248590Smm      r1 = archive_read_support_filter_lzma(_a);
75248590Smm      break;
76248590Smm    case ARCHIVE_FILTER_XZ:
77248590Smm      strcpy(str, "xz");
78248590Smm      r1 = archive_read_support_filter_xz(_a);
79248590Smm      break;
80248590Smm    case ARCHIVE_FILTER_UU:
81248590Smm      strcpy(str, "uu");
82248590Smm      r1 = archive_read_support_filter_uu(_a);
83248590Smm      break;
84248590Smm    case ARCHIVE_FILTER_RPM:
85248590Smm      strcpy(str, "rpm");
86248590Smm      r1 = archive_read_support_filter_rpm(_a);
87248590Smm      break;
88248590Smm    case ARCHIVE_FILTER_LZIP:
89248590Smm      strcpy(str, "lzip");
90248590Smm      r1 = archive_read_support_filter_lzip(_a);
91248590Smm      break;
92248590Smm    case ARCHIVE_FILTER_LRZIP:
93248590Smm      strcpy(str, "lrzip");
94248590Smm      r1 = archive_read_support_filter_lrzip(_a);
95248590Smm      break;
96248590Smm    default:
97248590Smm      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
98248590Smm          "Invalid filter code specified");
99248590Smm      return (ARCHIVE_FATAL);
100248590Smm  }
101248590Smm
102248590Smm  if (code != ARCHIVE_FILTER_NONE)
103248590Smm  {
104248590Smm    number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
105248590Smm
106248590Smm    bidder = a->bidders;
107248590Smm    for (i = 0; i < number_bidders; i++, bidder++)
108248590Smm    {
109248590Smm      if (!bidder->name || !strcmp(bidder->name, str))
110248590Smm        break;
111248590Smm    }
112248590Smm    if (!bidder->name || strcmp(bidder->name, str))
113248590Smm    {
114248590Smm      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
115248590Smm          "Internal error: Unable to append filter");
116248590Smm      return (ARCHIVE_FATAL);
117248590Smm    }
118248590Smm
119248590Smm    filter
120248590Smm        = (struct archive_read_filter *)calloc(1, sizeof(*filter));
121248590Smm    if (filter == NULL)
122248590Smm    {
123248590Smm      archive_set_error(&a->archive, ENOMEM, "Out of memory");
124248590Smm      return (ARCHIVE_FATAL);
125248590Smm    }
126248590Smm    filter->bidder = bidder;
127248590Smm    filter->archive = a;
128248590Smm    filter->upstream = a->filter;
129248590Smm    a->filter = filter;
130248590Smm    r2 = (bidder->init)(a->filter);
131248590Smm    if (r2 != ARCHIVE_OK) {
132248590Smm      __archive_read_close_filters(a);
133248590Smm      __archive_read_free_filters(a);
134248590Smm      return (ARCHIVE_FATAL);
135248590Smm    }
136248590Smm  }
137248590Smm
138248590Smm  a->bypass_filter_bidding = 1;
139248590Smm  return (r1 < r2) ? r1 : r2;
140248590Smm}
141248590Smm
142248590Smmint
143248590Smmarchive_read_append_filter_program(struct archive *_a, const char *cmd)
144248590Smm{
145248590Smm  return (archive_read_append_filter_program_signature(_a, cmd, NULL, 0));
146248590Smm}
147248590Smm
148248590Smmint
149248590Smmarchive_read_append_filter_program_signature(struct archive *_a,
150248590Smm  const char *cmd, const void *signature, size_t signature_len)
151248590Smm{
152248590Smm  int r, number_bidders, i;
153248590Smm  struct archive_read_filter_bidder *bidder;
154248590Smm  struct archive_read_filter *filter;
155248590Smm  struct archive_read *a = (struct archive_read *)_a;
156248590Smm
157248590Smm  if (archive_read_support_filter_program_signature(_a, cmd, signature,
158248590Smm    signature_len) != (ARCHIVE_OK))
159248590Smm    return (ARCHIVE_FATAL);
160248590Smm
161248590Smm  number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
162248590Smm
163248590Smm  bidder = a->bidders;
164248590Smm  for (i = 0; i < number_bidders; i++, bidder++)
165248590Smm  {
166248590Smm    /* Program bidder name set to filter name after initialization */
167248590Smm    if (bidder->data && !bidder->name)
168248590Smm      break;
169248590Smm  }
170248590Smm  if (!bidder->data)
171248590Smm  {
172248590Smm    archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
173248590Smm        "Internal error: Unable to append program filter");
174248590Smm    return (ARCHIVE_FATAL);
175248590Smm  }
176248590Smm
177248590Smm  filter
178248590Smm      = (struct archive_read_filter *)calloc(1, sizeof(*filter));
179248590Smm  if (filter == NULL)
180248590Smm  {
181248590Smm    archive_set_error(&a->archive, ENOMEM, "Out of memory");
182248590Smm    return (ARCHIVE_FATAL);
183248590Smm  }
184248590Smm  filter->bidder = bidder;
185248590Smm  filter->archive = a;
186248590Smm  filter->upstream = a->filter;
187248590Smm  a->filter = filter;
188248590Smm  r = (bidder->init)(a->filter);
189248590Smm  if (r != ARCHIVE_OK) {
190248590Smm    __archive_read_close_filters(a);
191248590Smm    __archive_read_free_filters(a);
192248590Smm    return (ARCHIVE_FATAL);
193248590Smm  }
194248590Smm  bidder->name = a->filter->name;
195248590Smm
196248590Smm  a->bypass_filter_bidding = 1;
197248590Smm  return r;
198248590Smm}
199