static int Open(vlc_object_t *object) { access_t *access = (access_t*)object; if (!strchr(access->psz_location, '|')) return VLC_EGENERIC; char *base = strdup(access->psz_location); if (!base) return VLC_EGENERIC; char *name = strchr(base, '|'); *name++ = '\0'; decode_URI(base); stream_t *s = stream_UrlNew(access, base); if (!s) goto error; int count; rar_file_t **files; if (RarProbe(s) || RarParse(s, &count, &files) || count <= 0) goto error; rar_file_t *file = NULL; for (int i = 0; i < count; i++) { if (!file && !strcmp(files[i]->name, name)) file = files[i]; else RarFileDelete(files[i]); } free(files); if (!file) goto error; access_sys_t *sys = access->p_sys = malloc(sizeof(*sys)); sys->s = s; sys->file = file; access->pf_read = Read; access->pf_block = NULL; access->pf_control = Control; access->pf_seek = Seek; access_InitFields(access); access->info.i_size = file->size; rar_file_chunk_t dummy = { .mrl = base, }; sys->chunk = &dummy; Seek(access, 0); free(base); return VLC_SUCCESS; error: if (s) stream_Delete(s); free(base); return VLC_EGENERIC; }
static int open_file(struct demuxer *demuxer, enum demux_check check) { if (!demuxer->access_references) return -1; if (RarProbe(demuxer->stream)) return -1; int count; rar_file_t **files; if (RarParse(demuxer->stream, &count, &files)) return -1; void *tmp = talloc_new(NULL); talloc_steal(tmp, files); struct playlist *pl = talloc_zero(demuxer, struct playlist); demuxer->playlist = pl; // make it load rar:// pl->disable_safety = true; char *prefix = mp_url_escape(tmp, demuxer->stream->url, "~|"); for (int n = 0; n < count; n++) { // stream_rar.c does the real work playlist_add_file(pl, talloc_asprintf(tmp, "rar://%s|%s", prefix, files[n]->name)); RarFileDelete(files[n]); } demuxer->filetype = "rar"; demuxer->fully_read = true; talloc_free(tmp); return 0; }
int RarStreamOpen(vlc_object_t *object) { stream_t *s = (stream_t*)object; if (RarProbe(s->p_source)) return VLC_EGENERIC; int count; rar_file_t **files; const int64_t position = stream_Tell(s->p_source); if ((RarParse(s->p_source, &count, &files, false) && RarParse(s->p_source, &count, &files, true )) || count == 0 ) { stream_Seek(s->p_source, position); msg_Info(s, "Invalid or unsupported RAR archive"); free(files); return VLC_EGENERIC; } /* TODO use xspf to have node for directories * Reusing WriteXSPF from the zip access is probably a good idea * (becareful about '\' and '/'. */ char *mrl; if (asprintf(&mrl, "%s://%s", s->psz_access, s->psz_path)< 0) mrl = NULL; char *base; char *encoded = mrl ? encode_URI_component(mrl) : NULL; free(mrl); if (!encoded || asprintf(&base, "rar://%s", encoded) < 0) base = NULL; free(encoded); char *data = strdup("#EXTM3U\n"); for (int i = 0; i < count; i++) { rar_file_t *f = files[i]; char *next; if (base && data && asprintf(&next, "%s" "#EXTINF:,,%s\n" "%s|%s\n", data, f->name, base, f->name) >= 0) { free(data); data = next; } RarFileDelete(f); } free(base); free(files); if (!data) return VLC_EGENERIC; stream_t *payload = stream_MemoryNew(s, (uint8_t*)data, strlen(data), false); if (!payload) { free(data); return VLC_EGENERIC; } s->pf_read = Read; s->pf_peek = Peek; s->pf_control = Control; stream_sys_t *sys = s->p_sys = malloc(sizeof(*sys)); if (!sys) { stream_Delete(payload); return VLC_ENOMEM; } sys->payload = payload; char *tmp; if (asprintf(&tmp, "%s.m3u", s->psz_path) < 0) { RarStreamClose(object); return VLC_ENOMEM; } free(s->psz_path); s->psz_path = tmp; return VLC_SUCCESS; }
int RarAccessOpen(vlc_object_t *object) { access_t *access = (access_t*)object; const char *name = strchr(access->psz_location, '|'); if (name == NULL) return VLC_EGENERIC; char *base = strndup(access->psz_location, name - access->psz_location); if (unlikely(base == NULL)) return VLC_ENOMEM; name++; decode_URI(base); stream_t *s = stream_UrlNew(access, base); if (!s || RarProbe(s)) goto error; struct { int filescount; rar_file_t **files; unsigned int i_nbvols; } newscheme = { 0, NULL, 0 }, oldscheme = { 0, NULL, 0 }, *p_scheme; if (RarParse(s, &newscheme.filescount, &newscheme.files, &newscheme.i_nbvols, false) || newscheme.filescount < 1 || newscheme.i_nbvols < 2 ) { /* We might want to lookup old naming scheme, could be a part1.rar,part1.r00 */ stream_Seek(s, 0); RarParse(s, &oldscheme.filescount, &oldscheme.files, &oldscheme.i_nbvols, true); } if (oldscheme.filescount >= newscheme.filescount && oldscheme.i_nbvols > newscheme.i_nbvols) { for (int i = 0; i < newscheme.filescount; i++) RarFileDelete(newscheme.files[i]); free(newscheme.files); p_scheme = &oldscheme; msg_Dbg(s, "using rar old naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols); } else if (newscheme.filescount) { for (int i = 0; i < oldscheme.filescount; i++) RarFileDelete(oldscheme.files[i]); free(oldscheme.files); p_scheme = &newscheme; msg_Dbg(s, "using rar new naming for %d files nbvols %u", p_scheme->filescount, oldscheme.i_nbvols); } else { msg_Info(s, "Invalid or unsupported RAR archive"); for (int i = 0; i < oldscheme.filescount; i++) RarFileDelete(oldscheme.files[i]); free(oldscheme.files); for (int i = 0; i < newscheme.filescount; i++) RarFileDelete(newscheme.files[i]); free(newscheme.files); goto error; } rar_file_t *file = NULL; for (int i = 0; i < p_scheme->filescount; i++) { if (!file && !strcmp(p_scheme->files[i]->name, name)) file = p_scheme->files[i]; else RarFileDelete(p_scheme->files[i]); } free(p_scheme->files); if (!file) goto error; access_sys_t *sys = access->p_sys = malloc(sizeof(*sys)); sys->s = s; sys->file = file; access->pf_read = Read; access->pf_block = NULL; access->pf_control = Control; access->pf_seek = Seek; access_InitFields(access); rar_file_chunk_t dummy = { .mrl = base, }; sys->chunk = &dummy; Seek(access, 0); free(base); return VLC_SUCCESS; error: if (s) stream_Delete(s); free(base); return VLC_EGENERIC; }