2 * List files and extract file from rars by using external executable unrar.
4 * Copyright (C) 2005 Jindrich Makovicka <makovick gmail com>
5 * Copyright (C) 2007 Ulion <ulion2002 gmail com>
7 * This file is part of MPlayer.
9 * MPlayer is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * MPlayer is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with MPlayer; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32 #include "unrar_exec.h"
37 #define UNRAR_EXTRACT 2
39 char* unrar_executable
= NULL
;
41 static FILE* launch_pipe(pid_t
*apid
, const char *executable
, int action
,
42 const char *archive
, const char *filename
)
44 if (!executable
|| access(executable
, R_OK
| X_OK
)) return NULL
;
45 if (access(archive
, R_OK
)) return NULL
;
51 mp_msg(MSGT_GLOBAL
, MSGL_ERR
, "UnRAR: Cannot create pipe.\n");
57 /* This is the child process. Execute the unrar executable. */
59 // Close MPlayer's stdin, stdout and stderr so the unrar binary
60 // can not mess them up.
61 // TODO: Close all other files except the pipe.
62 close(0); close(1); close(2);
63 // Assign new stdin, stdout and stderr and check they actually got the
65 if (open("/dev/null", O_RDONLY
) != 0 || dup(mypipe
[1]) != 1
66 || open("/dev/null", O_WRONLY
) != 2)
68 if (action
== UNRAR_LIST
)
69 execl(executable
, executable
, "v", archive
, NULL
);
70 else if (action
== UNRAR_EXTRACT
)
71 execl(executable
, executable
, "p", "-inul", "-p-",
72 archive
,filename
,NULL
);
73 mp_msg(MSGT_GLOBAL
, MSGL_ERR
, "UnRAR: Cannot execute %s\n", executable
);
77 /* The fork failed. Report failure. */
78 mp_msg(MSGT_GLOBAL
, MSGL_ERR
, "UnRAR: Fork failed\n");
81 /* This is the parent process. Prepare the pipe stream. */
84 if (action
== UNRAR_LIST
)
85 mp_msg(MSGT_GLOBAL
, MSGL_V
,
86 "UnRAR: call unrar with command line: %s v %s\n",
88 else if (action
== UNRAR_EXTRACT
)
89 mp_msg(MSGT_GLOBAL
, MSGL_V
,
90 "UnRAR: call unrar with command line: %s p -inul -p- %s %s\n",
91 executable
, archive
, filename
);
92 return fdopen(mypipe
[0], "r");
96 #define ALLOC_INCR 1 * 1024 * 1024
97 int unrar_exec_get(unsigned char **output
, unsigned long *size
,
98 const char *filename
, const char *rarfile
)
100 int bufsize
= ALLOC_INCR
, bytesread
;
105 rar_pipe
=launch_pipe(&pid
,unrar_executable
,UNRAR_EXTRACT
,rarfile
,filename
);
106 if (!rar_pipe
) return 0;
110 *output
= malloc(bufsize
);
113 bytesread
=fread(*output
+*size
, 1, bufsize
-*size
, rar_pipe
);
117 if (*size
== bufsize
) {
119 bufsize
+= ALLOC_INCR
;
120 p
= realloc(*output
, bufsize
);
127 pid
= waitpid(pid
, &status
, 0);
128 if (!*output
|| !*size
|| (pid
== -1 && errno
!= ECHILD
) ||
129 (pid
> 0 && status
)) {
135 if (bufsize
> *size
) {
136 char *p
= realloc(*output
, *size
);
140 mp_msg(MSGT_GLOBAL
, MSGL_V
, "UnRAR: got file %s len %lu\n", filename
,*size
);
145 #define PARSE_PROPS 1
147 int unrar_exec_list(const char *rarfile
, ArchiveList_struct
**list
)
149 char buf
[1024], fname
[1024];
152 int status
= 0, file_num
= -1, ignore_next_line
= 0, state
= PARSE_NAME
;
154 ArchiveList_struct
*alist
= NULL
, *current
= NULL
, *new;
156 rar_pipe
= launch_pipe(&pid
, unrar_executable
, UNRAR_LIST
, rarfile
, NULL
);
157 if (!rar_pipe
) return -1;
158 while (fgets(buf
, sizeof(buf
), rar_pipe
)) {
159 int packsize
, unpsize
, ratio
, day
, month
, year
, hour
, min
;
160 int llen
= strlen(buf
);
161 // If read nothing, we got a file_num -1.
164 if (buf
[llen
-1] != '\n')
165 // The line is too long, ignore it.
166 ignore_next_line
= 2;
167 if (ignore_next_line
) {
173 while (llen
> 0 && strchr(" \t\n\r\v\f", buf
[llen
-1]))
177 while (*p
&& strchr(" \t\n\r\v\f", *p
))
184 if (state
== PARSE_PROPS
&& sscanf(p
, "%d %d %d%% %d-%d-%d %d:%d",
185 &unpsize
, &packsize
, &ratio
, &day
,
186 &month
, &year
, &hour
, &min
) == 8) {
187 new = calloc(1, sizeof(ArchiveList_struct
));
197 current
->item
.Name
= strdup(fname
);
199 if (!current
->item
.Name
) {
203 current
->item
.PackSize
= packsize
;
204 current
->item
.UnpSize
= unpsize
;
212 pid
= waitpid(pid
, &status
, 0);
213 if (file_num
< 0 || (pid
== -1 && errno
!= ECHILD
) ||
214 (pid
> 0 && status
)) {
215 unrar_exec_freelist(alist
);
221 mp_msg(MSGT_GLOBAL
, MSGL_V
, "UnRAR: list got %d files\n", file_num
);
225 void unrar_exec_freelist(ArchiveList_struct
*list
)
227 ArchiveList_struct
* tmp
;
231 free(list
->item
.Name
);