ripnews/encode/yenc.rb

330 lines
7.9 KiB
Ruby
Raw Permalink Normal View History

2003-07-20 20:32:24 +00:00
#
# Copyright (c) 2002, 2003, 2014 Ward Wouts <ward@wouts.nl>
2003-04-18 22:53:25 +00:00
#
2003-07-20 20:32:24 +00:00
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
2003-04-18 22:53:25 +00:00
#
2003-07-20 20:32:24 +00:00
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2003-04-18 22:53:25 +00:00
#
require 'tempfile'
class YencError < RuntimeError; end
2003-04-20 18:31:17 +00:00
class YEnc
class << self
2003-04-18 22:53:25 +00:00
Encoding.default_external="ISO-8859-1"
Encoding.default_internal="ISO-8859-1"
#Encoding.default_external="ASCII-8BIT"
#Encoding.default_internal="ASCII-8BIT"
2016-01-21 21:12:10 +00:00
Debuglevel = 1
@@ymap = {}
2003-04-18 22:53:25 +00:00
def ydecode(data, outfile=nil)
if @@ymap.empty?
(-106..255).each do |b|
@@ymap[b]=((b-42)%256)
end
2003-04-18 22:53:25 +00:00
end
2004-06-16 08:17:48 +00:00
case data.class.to_s
2003-04-18 22:53:25 +00:00
when "Array"
2008-02-06 15:50:19 +00:00
puts "Calling _ydecode_array" if Debuglevel>0
2003-04-18 22:53:25 +00:00
mode, filename, body = _ydecode_array(data)
when "File", "Tempfile"
unless outfile
2008-02-06 15:50:19 +00:00
puts "ydecode: need outfile"
2003-04-18 22:53:25 +00:00
exit
end
2008-02-06 15:50:19 +00:00
puts "Calling _ydecode_file" if Debuglevel>0
2003-04-18 22:53:25 +00:00
mode, filename, body = _ydecode_file(data, outfile)
else
2008-02-06 15:50:19 +00:00
puts "Funny stuff in ydecode. Data of class \"#{data.class.to_s}\""
2003-04-18 22:53:25 +00:00
end
return mode, filename, body
end
def _ydecode_line(line)
i = 0
ostr = ''
esc = false
line.each_byte do |c|
next if c == 13 or c == 10
if c == 61 and not esc #escape character hit goto the next one
esc = true
next
else
if esc
esc = false
c = c - 64
end
if c.between?(0,41)
decoded = c + 214
2004-10-18 08:13:47 +00:00
else
decoded = c - 42
2004-10-18 08:13:47 +00:00
end
2003-04-18 22:53:25 +00:00
end
ostr << decoded
2003-04-18 22:53:25 +00:00
end
2003-04-20 18:31:17 +00:00
return ostr
2003-04-18 22:53:25 +00:00
end
def _ydecode_file(file, outfile)
2003-04-20 18:31:17 +00:00
mode = 0600 # mode is a bit stupid with yencoding... it don't get it
2003-04-18 22:53:25 +00:00
filename = "unknown"
lines = file.pos
file.pos = 0
bytes = 0
total = 0
2003-04-20 21:31:12 +00:00
oldpartbegin = 0
2003-04-18 22:53:25 +00:00
oldpartend = 0
search_begin = false
2003-04-20 21:31:12 +00:00
skip = false
closure = true
2003-04-18 22:53:25 +00:00
while (! file.eof)
line = file.gets
2016-01-21 21:12:10 +00:00
print "line: #{line}" if Debuglevel > 1
2014-10-31 19:33:29 +00:00
if line.match(/^\=ybegin\s+(.*line\=.*)/)
2003-04-18 22:53:25 +00:00
m = $1
2016-01-21 21:12:10 +00:00
puts " #{Thread.current.inspect} ybegin match; rest: #{m}" if Debuglevel > 0
2014-10-31 19:33:29 +00:00
if m.match(/^\s*(part\=(\d+)\s+)?(total\=(\d+)\s+)?(line\=(\d+))(\s*size\=(\d+))(\s*name=(.*?\S))\s*$/)
2003-04-18 22:53:25 +00:00
part = $2.to_i
total = $4.to_i
linesize = $6.to_i
totalsize = $8.to_i
filename = $10
2003-04-20 18:31:17 +00:00
if Debuglevel > 0
print "found beginning"
if part != nil
print " of part #{part}"
end
if total != nil
print " of #{total}"
end
2008-02-06 15:50:19 +00:00
puts ", linesize = #{linesize}, size = #{totalsize}, filename = #{filename}"
2003-04-18 22:53:25 +00:00
end
break
else
2008-02-06 15:50:19 +00:00
puts "not a valid yenc begin line"
2003-04-18 22:53:25 +00:00
end
end
end
if file.eof
2008-02-06 15:50:19 +00:00
puts "Not yencoded!"
2003-04-18 22:53:25 +00:00
return false
end
while (! file.eof)
2008-02-06 15:50:19 +00:00
puts "at #{file.pos} need to go to #{lines}" if Debuglevel > 1
2003-04-18 22:53:25 +00:00
line = file.gets
line.chop!
# if ! line.valid_encoding?
# line = line.encode("UTF-16be", :invalid=>:replace, :replace=>"?").encode('UTF-8')
# end
2014-10-31 19:33:29 +00:00
if line.match(/^=yend\s+(.*)\Z/)
closure = true
2003-04-18 22:53:25 +00:00
m = $1
2014-10-31 19:33:29 +00:00
m.match(/(\s*size=(\d+)\s+)(\s*part=(\d+))?(\s+crc32=(\S+))?/)
2003-04-18 22:53:25 +00:00
size = $2.to_i
part = $4.to_i
crc = $6
if size != bytes
2008-02-06 15:50:19 +00:00
puts "#{Thread.current.inspect} part size mismatch, is #{bytes}, should be #{size}"
2003-04-18 22:53:25 +00:00
end
if part == nil
return mode, filename
end
total += bytes
if total >= totalsize
if total != totalsize
2008-02-06 15:50:19 +00:00
puts "#{Thread.current.inspect} total size mismatch, is #{total}, should be #{totalsize}"
2003-04-18 22:53:25 +00:00
end
return mode, filename
end
search_begin = true
bytes = 0
2016-01-21 21:12:10 +00:00
puts " #{Thread.current.inspect} yended" if Debuglevel > 0
2003-04-18 22:53:25 +00:00
next
end
2014-10-31 19:33:29 +00:00
if search_begin && line.match(/^\=ybegin\s+(.*)\Z/)
closure = false
2003-04-18 22:53:25 +00:00
m = $1
search_begin = false
2014-10-31 19:33:29 +00:00
if m.match(/^\s*(part\=(\d+)\s+)?(total\=(\d+)\s+)?(line\=(\d+))(\s*size\=(\d+))(\s*name=(.*?\S))\s*$/)
2003-04-18 22:53:25 +00:00
part = $2.to_i
total = $4.to_i
linesize = $6.to_i
totalsize = $8.to_i
filename = $10
2008-02-06 15:50:19 +00:00
puts "found beginning of part #{part}, linesize = #{linesize}, size = #{totalsize}, filename = #{filename}" if Debuglevel > 0
2003-04-18 22:53:25 +00:00
end
next
end
if search_begin == true
next
end
2014-10-31 19:33:29 +00:00
if line.match(/^=ypart\s+(\s*begin=(\d+))(\s+end=(\d+))/)
closure = false
2003-04-20 21:31:12 +00:00
skip = false
2003-04-18 22:53:25 +00:00
b = $2
e = $4
2008-02-06 15:50:19 +00:00
puts " #{Thread.current.inspect} next part begin #{b}, end #{e}"
2003-04-20 21:31:12 +00:00
if b.to_i == oldpartbegin && e.to_i == oldpartend
2008-02-06 15:50:19 +00:00
puts "Skipping duplicate part"
2003-04-20 21:31:12 +00:00
skip = true
next
end
2003-04-18 22:53:25 +00:00
if b.to_i == oldpartend + 1
oldpartend = e.to_i
2003-04-20 21:31:12 +00:00
oldpartbegin = b.to_i
2003-04-18 22:53:25 +00:00
else
raise PermError, "#{Thread.current.inspect} Parts not continuous! last end #{oldpartend}, begin #{b}"
2003-04-18 22:53:25 +00:00
end
next
end
# This seems to be a common 'error' - maybe I misunderstand the spec or
# something
# if line.length != linesize
2008-02-06 15:50:19 +00:00
# puts "linesize mismatch, was #{line.length}, should be #{linesize}..."
2003-04-18 22:53:25 +00:00
# end
2003-04-20 21:31:12 +00:00
if !skip
2016-01-21 21:12:10 +00:00
puts "line: #{line}" if Debuglevel > 1
2003-04-20 21:31:12 +00:00
ostr = _ydecode_line(line)
2016-01-21 21:12:10 +00:00
puts "ostr: #{ostr}" if Debuglevel > 1
2003-04-20 21:31:12 +00:00
outfile << ostr
bytes += ostr.length
end
2003-04-18 22:53:25 +00:00
end
puts "No \"=yend\" found!!!" if ! closure
2003-04-18 22:53:25 +00:00
return mode, filename, outfile
end
def _ydecode_array(data)
decode = ""
mode = 0600
filename = "unknown"
2003-04-21 19:45:38 +00:00
oldpartend = 0
oldpartbegin = 0
2003-04-18 22:53:25 +00:00
c = 0
lines = data.length
bytes = 0
percent = 0
mark = lines/100
i = 0
while (i < data.length)
2014-10-31 19:33:29 +00:00
if data[i].match(/^\=ybegin\s+(.*line\=.*)/)
2003-04-18 22:53:25 +00:00
m = $1
2016-01-21 21:12:10 +00:00
puts " #{Thread.current.inspect} ybegin match; rest: #{m}" if Debuglevel > 0
2014-10-31 19:33:29 +00:00
if m.match(/^\s*(part\=(\d+)\s+)?(total\=(\d+)\s+)?(line\=(\d+))(\s*size\=(\d+))(\s*name=(.*?\S))\s*$/)
2003-04-18 22:53:25 +00:00
part = $2.to_i
total = $4.to_i
linesize = $6.to_i
size = $8.to_i
filename = $10
2016-01-21 21:12:10 +00:00
puts " #{Thread.current.inspect} found beginning, linesize = #{linesize}, size = #{size}, filename = #{filename}" if Debuglevel > 0
2003-04-18 22:53:25 +00:00
i += 1
break
else
2008-02-06 15:50:19 +00:00
puts "not a valid yenc begin line"
2003-04-18 22:53:25 +00:00
end
end
i += 1
end
unless (i < data.length)
2008-02-06 15:50:19 +00:00
puts "Not yencoded!"
2003-04-18 22:53:25 +00:00
return false
end
while (i < data.length)
line = data[i]
line.chomp!("\n")
line.chomp!("\r")
2008-02-06 15:50:19 +00:00
puts "at #{i} need to go to #{data.length}" if Debuglevel > 1
2016-01-21 21:12:10 +00:00
print "line: #{line}" if Debuglevel > 1
2003-04-18 22:53:25 +00:00
i += 1
2014-10-31 19:33:29 +00:00
if line.match(/^\=yend(\s+size=(\d+))(\s+crc32=(\S+))?/)
2003-04-18 22:53:25 +00:00
size = $2.to_i
crc = $4
if size != decode.length
2016-01-21 21:12:10 +00:00
puts " #{Thread.current.inspect} size mismatch, was #{decode.length}, should be #{size}"
2003-04-18 22:53:25 +00:00
end
dec = [ decode ]
return mode, filename, dec
end
2014-10-31 19:33:29 +00:00
if line.match(/^=ypart\s+(\s*begin=(\d+))(\s+end=(\d+))/)
2003-04-20 21:31:12 +00:00
skip = false
b = $2
e = $4
2008-02-06 15:50:19 +00:00
puts " #{Thread.current.inspect} next part begin #{b}, end #{e}"
2003-04-20 21:31:12 +00:00
if b.to_i == oldpartbegin && e.to_i == oldpartend
2008-02-06 15:50:19 +00:00
puts "Skipping duplicate part"
2003-04-20 21:31:12 +00:00
skip = true
next
end
if b.to_i == oldpartend + 1
oldpartend = e.to_i
oldpartbegin = b.to_i
else
raise PermError, "#{Thread.current.inspect} Parts not continuous! last end #{oldpartend}, begin #{b}"
2003-04-20 21:31:12 +00:00
end
2003-04-18 22:53:25 +00:00
next
end
# This seems to be a common 'error' - maybe I misunderstand the spec or
# something
# if line.length != linesize
2008-02-06 15:50:19 +00:00
# puts "#{i}: linesize mismatch, was #{line.length}, should be #{linesize}..."
2003-04-18 22:53:25 +00:00
# end
2003-04-20 21:31:12 +00:00
if !skip
2016-01-21 21:12:10 +00:00
print "line: #{line}" if Debuglevel > 1
2003-04-20 21:31:12 +00:00
ostr = _ydecode_line(line)
decode << ostr
bytes += ostr.length
end
2003-04-18 22:53:25 +00:00
end
2008-02-06 15:50:19 +00:00
puts "${i}: no \"=yend\" found!!!"
2003-04-18 22:53:25 +00:00
dec = [ decode ]
return mode, filename, dec
end
2003-04-20 18:31:17 +00:00
def is_yencoded(data)
if data.to_s =~ /=ybegin/m
return true
2003-04-18 22:53:25 +00:00
else
return false
end
end
2003-04-20 18:31:17 +00:00
def get_filename(data)
2003-04-20 20:15:34 +00:00
i = 0
while i < data.length
line = data[i]
2014-10-31 19:33:29 +00:00
if line.match(/=ybegin\s*(part\=(\d+)\s+)?(total\=(\d+)\s+)?(line\=(\d+))(\s*size\=(\d+))(\s*name=(.*?\S))\s*$/m)
2003-04-20 20:15:34 +00:00
return $10
end
i += 1
2003-04-18 22:53:25 +00:00
end
2003-04-20 20:15:34 +00:00
return false
2003-04-18 22:53:25 +00:00
end
end # class
2003-04-20 18:31:17 +00:00
end