2023年
3月
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

setup diary

2007|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|06|08|11|
2015|01|02|03|04|05|06|07|08|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|

2023-03-01 dataの抽出

_ 古いKaleidaGraphから

かなり古いKaleidaGraphから数値dataを抽出したいという話を聞いたので,そのデータをもらって,構造を解析してみた.それなりに単純な構造をしていたので,データ抽出プログラムをrubyで書いてみた.それがこんな感じ.
qda=ARGV[0]
dat=qda.sub(/\.qda$/i,"_.dat")
d=open(qda,"rb"){|f|f.read}
n=d[0,16].unpack("n*")
c=n[8] # byte size of the last comment
n=n[1] # the number of data
sz=d[0x200,2*n].unpack("n*") # size of each data
tp=d[0x200+2*n,2*n].unpack("n*") # type
names=d[0x200+4*n,40*n].unpack("a40"*n).map(&:strip)
r=d[(0x200+4*n+40*n)..-1]
sz=sz.zip(tp).map{|s,t|
  a,b="g","" # big endian float
  a,b="N","Z21" if t==1 # string
  a,b="G","" if t==2 # big endian 64bit float
  *data,r=r.unpack(a*s+"n"*s+b*s+"a*")
  msk=data[s,s] # mask
  str=data[2*s,s] # string
  data=data[0,s] # numeric
  if t==2 # date or time
    td=r[0,8].unpack("C*")[3]
    data=data.map{|l|(Time.gm(l>3e9?1904:2000)+l).getutc.strftime("%d-%m-%Y")} if td==0 #date
    data=data.map{|l|Time.at(l).getutc.strftime("%H:%M:%S")} if td==1 #12:34:56
    data=data.map{|l|["%02d"]*2*":"%l.divmod(60)} if td==2 #12:34
  end
  r=r[136..-1]
  data=str if t==1
  data
}
mx=sz.map(&:size).max
sz=sz.map{|l|l.fill(0,l.size...mx)}.transpose
open(dat,"w"){|f|
  f.puts "# "+r.gsub(/\x0d\x0a?/,"\n# ") if r.size>0
  f.puts names*", "
  sz.each{|l|f.puts l*", "}
}
まず,引数として与えたファイルを読み込むが,2バイト目からdataの数を,14バイト目からがコメントのサイズを表すようなので,それを取り込む.200hバイトから,それぞれのdataの長さがあり,その次に型だと思われるdataがある.その後に,40バイトずつのdataの名前があり,そのあとにdata本体とマスクだと思われるdataと文字列の場合には21バイドずつの文字列があり,その後にはdataの名前と良くわからないdataが合計136バイトあるようだ.ちなみに,それぞれはbig endianである.さらに,日付の表記は日月年の順番で,内部では秒単位の倍精度浮動小数点で表されているようである.時刻も同様である.ただ,文字列のdataの場合に,data本体には何が保存されているかはよく調べなかった.まあ,特定のversionのKaleidaGraphでセーブしたdataしか変換できないかも知れないが,今回の目的は達成したので,良しとしよう.