snbhsmt_log

ネットワークとコンピュータ、その他いろいろ

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Palm Desktop の予定データを読む Ruby スクリプト

先日の Palm Desktop の Todo データを読む Ruby スクリプト に続いて、今回は Palm Desktop の予定データをエクスポートすると出来る *.dba ファイルを Ruby で読んでみた。

dba ファイルのフォーマットは以下のページを参考にしました。
Palm Pilot Desktop Software DATEBOOK.DAT and DATEBOOK.DBA File Structure

今回のスクリプトも tdareader.rb と同じく StreamReader を使ってる。

dbareader.rb
#!/usr/bin/ruby
# vi: ts=2

# Palm の予定データ (databook.dat/*.dba) を読む

$KCODE = 'u'
require 'streamreader'

module Palm
  class Datebook
    def self.read_dba(filename)
      sr = StreamReader.new(File.open(filename, 'rb'))
      dba = {}

      dba[:version_tag] = sr.read_n32
      raise "illegal data format" unless dba[:version_tag] == 0x00014244

      dba[:file_name] = sr.read_cstring
      dba[:table_string] = sr.read_cstring
      dba[:next_free] = sr.read_long
      dba[:category_count] = sr.read_long

      # Category Entry
      dba[:category_entries] = []
      dba[:category_count].times {
        category = {}
        category[:index] = sr.read_long
        category[:id] = sr.read_long
        category[:dirty_flag] = sr.read_long
        category[:long_name] = sr.read_cstring   # カテゴリ名
        category[:short_name] = sr.read_cstring  # カテゴリ名 (8byte)
        dba[:category_entries] << category
      }

      dba[:resource_id] = sr.read_long
      dba[:fields_per_row] = sr.read_long
      dba[:rec_id_pos] = sr.read_long
      dba[:rec_status_pos] = sr.read_long
      dba[:placement_pos] = sr.read_long
      dba[:field_count] = sr.read_short

      dba[:field_entry] = []
      dba[:field_count].times {
        dba[:field_entry] << sr.read_short
      }

      dba[:num_entries] = sr.read_long

      # Datebook Entry
      dba[:datebook_entry] = []
      (dba[:num_entries] / dba[:field_count]).times {
        datebook = {}
        datebook[:field_type_1] = sr.read_long
        datebook[:record_id] = sr.read_long
        datebook[:field_type_2] = sr.read_long
        datebook[:status_field] = sr.read_ulong
        datebook[:field_type_3] = sr.read_long
        datebook[:position] = sr.read_long
        datebook[:field_type_4] = sr.read_long

        # 開始日時 (終日の予定は時間が0:00)
        datebook[:start_time] = sr.read_ulong

        datebook[:field_type_5] = sr.read_long

        # 終了日時 (終日の予定は時間が0:00)
        datebook[:end_time] = sr.read_ulong

        datebook[:field_type_6] = sr.read_long
        datebook[:padding_6] = sr.read_long

        # 予定名
        datebook[:description] = sr.read_cstring

        datebook[:field_type_7] = sr.read_long
        datebook[:duration] = sr.read_ulong                     # ?
        datebook[:field_type_8] = sr.read_long
        datebook[:padding_8] = sr.read_long

        # メモ
        datebook[:note] = sr.read_cstring

        datebook[:field_type_9] = sr.read_long

        # 1=終日の予定
        datebook[:untimed] = sr.read_ulong

        datebook[:field_type_10] = sr.read_long

        # 1=プライベート
        datebook[:private] = sr.read_long

        datebook[:field_type_11] = sr.read_long
        datebook[:category] = sr.read_long
        datebook[:field_type_12] = sr.read_long

        # 1=アラーム指定あり (0の時 alarm_adv_* は無意味)
        datebook[:alarm_set] = sr.read_long

        datebook[:field_type_13] = sr.read_long

        # 何(分/時間/日)かを表す数値
        datebook[:alarm_adv_units] = sr.read_long

        datebook[:field_type_14] = sr.read_long

        # 0=分前に知らせる, 1=時間前, 2=日前
        datebook[:alarm_adv_type] = sr.read_long

        datebook[:field_type_15] = sr.read_long

        # Repeat Event start
        datebook[:date_exceptions] = sr.read_ushort
        datebook[:exception_entry] = []
        datebook[:date_exceptions].times {
          # 繰り返しイベントの中で例外的に変更のある日付
          datebook[:exception_entry] << sr.read_long
        }

        # 1=繰り返しの予定
        datebook[:repeat_event_flag] = sr.read_ushort

        # Class Entry
        if datebook[:repeat_event_flag] == 0xFFFF
          datebook[:constant] = sr.read_short
          datebook[:length] = sr.read_short
          datebook[:class_name] = sr.read_string(datebook[:length])
        end

        if datebook[:repeat_event_flag] != 0

          # 繰り返しの種類 1=日毎 2=週毎 3=月毎(曜日) 4=月毎(日) 5=年毎
          datebook[:brand] = sr.read_long

          # 繰り返し間隔
          datebook[:interval] = sr.read_long

          # 繰り返し終了日付 (1956495599=未指定)
          datebook[:end_date] = sr.read_long

          # 週の始まりを何曜日とするか (0=日曜)
          datebook[:first_day_of_week] = sr.read_long

          # Brand Data
          if (1..3) === datebook[:brand]
            # 0=日曜 1=月曜 .. 6=土曜
            datebook[:day_index] = sr.read_long
          end
          if 2 == datebook[:brand]
            # 曜日のビットマスク 0x01=日曜 0x02=月 .. 0x40=土
            datebook[:days_mask] = sr.read_ubyte
          end
          if 3 == datebook[:brand]
            # 第何番目の曜日か (0から)
            datebook[:week_index] = sr.read_long
          end
          if (4..5) === datebook[:brand]
            # 繰り返す日にち
            datebook[:day_number] = sr.read_long
          end
          if 5 == datebook[:brand]
            # 繰り返す月-1
            datebook[:month_index] = sr.read_long
          end
        end

        dba[:datebook_entry] << datebook
      }

      sr.close
      dba
    end
  end # class Datebook
end

if $0 == __FILE__
  require 'kconv'
  require 'pp'

  def print_event(event)
    #print '        record_id ', event[:record_id], "\n"
    #print '     status_field ', event[:status_field], "\n"
    #print '         position ', event[:position], "\n"
    print '       start_time ', Time.at(event[:start_time]), "\n"
    print '         end_time ', Time.at(event[:end_time]), "\n"
    print '      description ', event[:description].toutf8, "\n"
    #print '         duration ', event[:duration], "\n"
    print '             note ', event[:note].toutf8, "\n"
    print '          untimed ', event[:untimed], "\n"
    print '          private ', event[:private], "\n"
    #print '         category ', event[:category], "\n"
    print '        alarm_set ', event[:alarm_set], "\n"
    print '  alarm_adv_units ', event[:alarm_adv_units], "\n"
    print '   alarm_adv_type ', event[:alarm_adv_type], "\n"

    puts '*** Repeat Event ***'
    print '  date_exceptions ', event[:date_exceptions], "\n"
    print '  exception_entry [ ', "\n"
    event[:exception_entry].each do |entry|
      print '                  ', Time.at(entry), "\n"
    end
    print '                  ]', "\n"
    print 'repeat_event_flag ', event[:repeat_event_flag], "\n"

    #puts '*** Class Entry ***'
    #if event[:repeat_event_flag] == 0xFFFF
    #   print '         constant ', event[:constant], "\n"
    #   print '           length ', event[:length], "\n"
    #   print '       class_name ', event[:class_name], "\n"
    #end
    #puts '***'

    if event[:repeat_event_flag] != 0
      print '            brand ', event[:brand], "\n"
      print '         interval ', event[:interval], "\n"
      print '         end_date ', Time.at(event[:end_date]), "\n"
      print 'first_day_of_week ', event[:first_day_of_week], "\n"

      # Brand Data
      if (1..3) === event[:brand]
        print '        day_index ', event[:day_index], "\n"
      end
      if 2 == event[:brand]
        print '        days_mask ', event[:days_mask], "\n"
      end
      if 3 == event[:brand]
        print '       week_index ', event[:week_index], "\n"
      end
      if (4..5) === event[:brand]
        print '       day_number ', event[:day_number], "\n"
      end
      if 5 == event[:brand]
        print '      month_index ', event[:month_index], "\n"
      end
    end
  end

  filename = ARGV.shift || exit(63)
  dba = Palm::Datebook.read_dba(filename)

  #$KCODE = 's'
  #pp dba

  dba[:datebook_entry].each { |event|
    print_event event
  }
end
スポンサーサイト

« Ruby で iCalendar の予定データを読む|Top|Palm Desktop の Todo データを読む Ruby スクリプト »

コメント

コメントの投稿

管理者にだけ表示を許可する

トラックバック

http://snbhsmt.blog110.fc2.com/tb.php/113-79aea23c

Top

HOME

Author:snbhsmt
Google Profiles

http://www.ksky.ne.jp/~snbhsmt/

全ての記事を表示する

この人とブロともになる

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。