Tools for working with Cidco Mailstations

Add script to convert an XPM to a mailstation icon

+100 -2
+3 -2
util/app_extractor.rb
··· 124 124 puts "icon#{i}:" 125 125 126 126 icons[i][:width] = read(2) 127 - puts "\t.dw\t##{x icons[i][:width], 4}\t\t; icon width" 127 + puts "\t.dw\t##{x icons[i][:width], 4}\t\t; icon width (#{icons[i][:width]})" 128 128 icons[i][:height] = read(1) 129 - puts "\t.db\t##{x icons[i][:height], 2}\t\t; icon height" 129 + puts "\t.db\t##{x icons[i][:height], 2}\t\t; icon height " << 130 + "(#{icons[i][:height]})" 130 131 131 132 puts "" 132 133
+97
util/xpm_to_icon.rb
··· 1 + #!/usr/bin/env ruby 2 + # 3 + # Copyright (c) 2019 joshua stein <jcs@jcs.org> 4 + # 5 + # Permission to use, copy, modify, and distribute this software for any 6 + # purpose with or without fee is hereby granted, provided that the above 7 + # copyright notice and this permission notice appear in all copies. 8 + # 9 + # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 + # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 + # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 + # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 + # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 + # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 + # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 + # 17 + 18 + # 19 + # Convert a 1-bit XPM to a Mailstation icon data structure 20 + # 21 + # Usage: xpm_to_icon.rb -f <xpm file> 22 + # 23 + 24 + require "getoptlong" 25 + 26 + opts = GetoptLong.new( 27 + [ "--file", "-f", GetoptLong::REQUIRED_ARGUMENT ], 28 + ) 29 + 30 + icon = nil 31 + opts.each do |opt,arg| 32 + case opt 33 + when "--file" 34 + icon = arg 35 + end 36 + end 37 + 38 + if !icon 39 + puts "usage: #{$0} -f <xpm file>" 40 + exit 1 41 + end 42 + 43 + xpm = File.open(icon, "r") 44 + if !(line = xpm.gets).match(/^\/\* XPM/) 45 + raise "unexpected line: #{line.inspect}" 46 + end 47 + 48 + if !(line = xpm.gets).match(/^static char/) 49 + raise "unexpected line: #{line.inspect}" 50 + end 51 + 52 + if !(m = (line = xpm.gets).match(/^\"(\d+) (\d+) /)) 53 + raise "unexpected line: #{line.inspect}" 54 + end 55 + width = m[1].to_i 56 + height = m[2].to_i 57 + 58 + if width != 34 || height != 34 59 + raise "image should be 34x34, not #{width}x#{height}" 60 + end 61 + 62 + line = xpm.gets 63 + if line.match(/^\" \tc None/) 64 + # skip 65 + line = xpm.gets 66 + end 67 + 68 + if !(m = line.match(/^\"(.)\tc #FFFFFF/)) 69 + raise "unexpected line: #{line.inspect}" 70 + end 71 + blank = m[1] 72 + 73 + if !(m = (line = xpm.gets).match(/^\"(.)\tc #000000/)) 74 + raise "unexpected line: #{line.inspect}" 75 + end 76 + black = m[1] 77 + 78 + puts "icon0:" 79 + puts "\t.dw\t##{sprintf("0x%02x", width)}\t\t\t; icon width (#{width})" 80 + puts "\t.db\t##{sprintf("0x%02x", height)}\t\t\t; icon height (#{height})" 81 + puts "" 82 + 83 + while !xpm.eof? 84 + if !(m = (line = xpm.gets).match(/^\"(.{#{width}})"[,\}]/)) 85 + raise "unexpected data line: #{line.inspect}" 86 + end 87 + 88 + if m[1].length != width 89 + raise "unexpected line length: #{m[1].length} != #{width}" 90 + end 91 + 92 + bits = m[1].split("").map{|b| b == black ? 1 : 0 } 93 + dbs = bits.each_slice(8).map{|byte| byte.reverse.join("").to_i(2) } 94 + 95 + puts "\t.db\t" << dbs.map{|i| sprintf("#0x%02x", i) }.join(", ") << 96 + "\t; " << bits.map{|b| b == 1 ? "#" : "." }.join("") 97 + end