1/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
3/*
4 * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Authors:
26 *    Rob Clark <robclark@freedesktop.org>
27 */
28
29#include <archive.h>
30#include <fcntl.h>
31#include <stdlib.h>
32#include <string.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include <archive_entry.h>
36
37#include "io.h"
38
39struct io {
40   struct archive *a;
41   struct archive_entry *entry;
42   unsigned offset;
43};
44
45static void
46io_error(struct io *io)
47{
48   fprintf(stderr, "%s\n", archive_error_string(io->a));
49   io_close(io);
50}
51
52static struct io *
53io_new(void)
54{
55   struct io *io = calloc(1, sizeof(*io));
56   int ret;
57
58   if (!io)
59      return NULL;
60
61   io->a = archive_read_new();
62   ret = archive_read_support_filter_gzip(io->a);
63   if (ret != ARCHIVE_OK) {
64      io_error(io);
65      return NULL;
66   }
67
68   ret = archive_read_support_filter_none(io->a);
69   if (ret != ARCHIVE_OK) {
70      io_error(io);
71      return NULL;
72   }
73
74   ret = archive_read_support_format_all(io->a);
75   if (ret != ARCHIVE_OK) {
76      io_error(io);
77      return NULL;
78   }
79
80   ret = archive_read_support_format_raw(io->a);
81   if (ret != ARCHIVE_OK) {
82      io_error(io);
83      return NULL;
84   }
85
86   return io;
87}
88
89struct io *
90io_open(const char *filename)
91{
92   struct io *io = io_new();
93   int ret;
94
95   if (!io)
96      return NULL;
97
98   ret = archive_read_open_filename(io->a, filename, 10240);
99   if (ret != ARCHIVE_OK) {
100      io_error(io);
101      return NULL;
102   }
103
104   ret = archive_read_next_header(io->a, &io->entry);
105   if (ret != ARCHIVE_OK) {
106      io_error(io);
107      return NULL;
108   }
109
110   return io;
111}
112
113struct io *
114io_openfd(int fd)
115{
116   struct io *io = io_new();
117   int ret;
118
119   if (!io)
120      return NULL;
121
122   ret = archive_read_open_fd(io->a, fd, 10240);
123   if (ret != ARCHIVE_OK) {
124      io_error(io);
125      return NULL;
126   }
127
128   ret = archive_read_next_header(io->a, &io->entry);
129   if (ret != ARCHIVE_OK) {
130      io_error(io);
131      return NULL;
132   }
133
134   return io;
135}
136
137void
138io_close(struct io *io)
139{
140   archive_read_free(io->a);
141   free(io);
142}
143
144unsigned
145io_offset(struct io *io)
146{
147   return io->offset;
148}
149
150#include <assert.h>
151int
152io_readn(struct io *io, void *buf, int nbytes)
153{
154   char *ptr = buf;
155   int ret = 0;
156   while (nbytes > 0) {
157      int n = archive_read_data(io->a, ptr, nbytes);
158      if (n < 0) {
159         fprintf(stderr, "%s\n", archive_error_string(io->a));
160         return n;
161      }
162      if (n == 0)
163         break;
164      ptr += n;
165      nbytes -= n;
166      ret += n;
167      io->offset += n;
168   }
169   return ret;
170}
171