Subject: Add support for xz-compressed debs
Author: Jakub Wilk <jwilk@debian.org>
Bug-Debian: http://bugs.debian.org/644172

---
 autoload/deb.vim |   41 +++++++++++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 6 deletions(-)

--- a/autoload/deb.vim
+++ b/autoload/deb.vim
@@ -26,25 +26,24 @@
 
     let l:archmember = s:dataFileName(a:debfile) " default archive member to extract
     if l:archmember == ""
-        echohl WarningMsg | echo "***error*** (deb#read) no valid data file found in debian archive"
+        echohl WarningMsg | echo "***error*** (deb#read) no valid data member found in debian archive"
         return
-    elseif l:archmember == "data.tar.gz"
-        let l:unpcmp = "tar zxfO "
-    elseif l:archmember == "data.tar.bz2"
-        let l:unpcmp = "tar jxfO "
-    elseif l:archmember == "data.tar.lzma"
-        if !s:hascmd("lzma")
+    else
+        let l:unpcmp = s:uncmp(l:archmember) . 'xfO '
+        if l:unpcmp =~# '^lzma' && !s:hascmd("lzma")
             return
         endif
-        let l:unpcmp = "lzma -d | tar xfO "
-    elseif l:archmember == "data.tar"
-        let l:unpcmp = "tar xfO "
     endif
 
     if a:member =~ '^\* ' " information control file
-        let l:archmember = "control.tar.gz"
         let l:target = substitute(l:target, "^\* ", "", "")
-        let l:unpcmp = "tar zxfO "
+        let l:archmember = s:controlFileName(a:debfile)
+        if l:archmember == ""
+            echohl WarningMsg | echo "***error*** (deb#read) no valid control member found in debian archive"
+            return
+        else
+            let l:unpcmp = s:uncmp(l:archmember) . 'xfO '
+        endif
     elseif a:member =~ ' -> ' " symbolic link
         let l:target = split(a:member,' -> ')[0]
         let l:linkname = split(a:member,' -> ')[1]
@@ -151,7 +150,17 @@
 
     " display information control files
     let l:infopos = line(".")
-    exe "silent read! ar p " . s:QuoteFile(a:file) . " control.tar.gz | tar zt"
+    let l:ctrlmember = s:controlFileName(a:file)
+    if l:ctrlmember == ""
+       echohl WarningMsg | echo "***error*** (deb#Browser) no valid control member found in debian archive"
+       return
+    endif
+
+    let l:unpcmp = s:uncmp(l:ctrlmember)
+    if l:unpcmp =~# '^lzma' && !s:hascmd('lzma')
+        return
+    endif
+    exe "silent read! ar p " . s:QuoteFile(a:file) . " " . l:ctrlmember . ' | ' . l:unpcmp . 't'
 
     $put=''
 
@@ -227,16 +236,41 @@
 
 endfun
 
+" return control file name for debian package. This can be either control.tar,
+" control.tar.gz or control.tar.xz
+fun s:controlFileName(deb)
+    return s:findFileName(a:deb, ["control.tar.gz", "control.tar.xz", "control.tar"])
+endfun
+
 " return data file name for debian package. This can be either data.tar.gz,
 " data.tar.bz2 or data.tar.lzma
 fun s:dataFileName(deb)
-    for fn in ["data.tar.gz", "data.tar.bz2", "data.tar.lzma", "data.tar"]
+    return s:findFileName(a:deb, ["data.tar.gz", "data.tar.bz2", "data.tar.lzma", "data.tar.xz", "data.tar"])
+endfun
+
+" return string which is the base command for uncompressing the given
+" archive member.  Further tar options can be appended to the string to view
+" or extract the contents.
+fun s:uncmp(member)
+    return {
+        \ 'gz': 'tar z',
+        \ 'bz2': 'tar j',
+        \ 'lzma': 'lzma -d | tar ',
+        \ 'xz': 'tar J',
+        \ 'tar': 'tar ',
+        \}[fnamemodify(a:member, ':e')]
+endfun
+
+" return a file name for debian package. This will be the first match from
+" the files passed as arguments.
+fun s:findFileName(deb, list)
+    for fn in a:list
         " [0:-2] is to remove trailing null character from command output
         if (system("ar t " . "'" . a:deb . "'" . " " . fn))[0:-2] == fn
             return fn
         endif
     endfor
-    return "" " no debian data format in this archive
+    return "" " cannot find file in this debian archive
 endfun
 
 fun s:QuoteFile(file)
