datebook to CSV and me
This script converts Palm datebook file to CSV format. Data stored in a file is simply output to STDOUT in order.
I wrote this script 2 years ago and had forgotten it. There aren't many people to need this now, but I cannot find any other place to put it on. You can do the opposite(csv2dbk) of this with Perl, but I have not finished to brush it up.
This script conform to GPL V2.
Related link: Palm Desktop Software DATEBOOK.DAT and DATEBOOK.DBA File Structure
#!/usr/bin/perl -w #$Id: dbk2csv.pl,v 1.2 2006/03/12 22:52:40 osamu Exp osamu $ my $version = '1.2'; my $reldate = '12/Mar/2006'; use strict; use warnings; use Getopt::Std; #my $palmpath = 'c:\Program Files\Palm'; #my $username = 'USERNAME'; my $filepath = 'datebook\datebook.dat'; my $timezone = +9; #JST my $chr = 1; my $short = 2; my $long = $short * 2; our($opt_h, $opt_v, $opt_i, $opt_t); getopts('hvit:'); $opt_h and &help(); $opt_v and &version(); $opt_t and $opt_t != 1 and $opt_t != 2 and $opt_t != 3 and die "Bad -t switch...\n"; my $datfname = shift; #$datfname = "$palmpath\\$username\\$filepath" unless $datfname; $datfname or &help(); chop $datfname if (substr($datfname, -1) eq '\\'); $datfname .= "\\$filepath" if -d $datfname; open(DAT, $datfname) or die "Can't open $datfname: $!\n"; binmode(DAT); read(DAT, my $buf, $chr*4) or die "Can't read: $!\n"; die "This file doesn't seem datebook dat file.\n" if($buf ne "\x00\x01\x42\x44"); &readstr('DAT'); #File Name &readstr('DAT'); #Table String seek(DAT, $long, 1); #Next Free $buf = &readnum('DAT', $long); #Category Count while($buf) { #Category Entries seek(DAT, $long*3, 1); &readstr('DAT'); &readstr('DAT'); $buf--; } seek(DAT, $long, 1); #Resource ID my $fieldperrow = &readnum('DAT', $long); #Field per Row seek(DAT, $long*3 ,1); #Rec Positions,etc. my $fieldcount = &readnum('DAT', $short); #Field Count my @fieldentry; while($fieldcount) { push(@fieldentry, &readnum('DAT', $short)); #Field Entry $fieldcount--; } my $numentries = &readnum('DAT', $long); #Num Entries print "Record ID,Status Feild,Position,Start Time,End Time,Description,Duration,Note,Untimed,Private,Category,Alarm Set,Alarm Adv Units,Alarm Adv Type,Date Exceptions,Exception entry,Repeat Event Flag,Class entry,Brand,Interval,End Date,First Day of Week,Day Index,Days Mask,Week Index,Day Number,Month Index\n" if $opt_i; my $i = 0; my $flag = 0; while ($numentries) { my $type = &readnum('DAT', $long); if ($flag or $type == 3) { print &readtime('DAT').','; $flag = !$flag; } elsif ($type == 1) { print &readnum('DAT', $long).','; } elsif ($type == 5) { seek(DAT, $long, 1); print &readstr('DAT').','; } elsif ($type == 6) { print &readnum('DAT', $long).','; } elsif ($type == 8) { &rep_event; } else { die "impossible field type: $type"; } if ($i == 14) { print "\n"; $i = 0; } else { $i++; } $numentries--; } close(DAT); exit(0); sub rep_event { my $buf = &readnum('DAT', $short); #Date Exceptions print "$buf,"; while ($buf) { print &readtime('DAT'); #Exception entry $buf--; print ';' if $buf; } print ','; my $rep_ev = &readnum('DAT', $short); #Repeat Event Flag print "$rep_ev,"; return unless $rep_ev; my $str; if ($rep_ev == hex('ffff')) { seek(DAT, $short, 1); #Constant $buf = &readnum('DAT', $short); #Length read(DAT, $str, $buf); print "$str"; #Class Name } print ','; if ($rep_ev <= hex('8000')) { print &readnum('DAT', $long); print ','; print &readnum('DAT', $long); print ','; } my $brand = &readnum('DAT', $long); #Brand print "$brand,"; print &readnum('DAT', $long).','; #Interval print &readtime('DAT').','; #End Date print &readnum('DAT', $long).','; #First Day of Week #Brand-Data die "Brand-Data error: $brand" if ($brand <= 0 or $brand > 6); return if $brand == 6; if ($brand <= 3) { print &readnum('DAT', $long); } print ','; #Day Index if ($brand == 2) { print &readnum('DAT', $chr); } print ','; #Day Mask if ($brand == 3) { print &readnum('DAT', $long); } print ','; #Week Index if ($brand >= 4) { print &readnum('DAT', $long); } print ','; #Day Number if ($brand == 5) { print &readnum('DAT', $long); } #Month Index } sub readstr { my $fh = shift; my $str; read($fh, my $buf, $chr); return '' if $buf eq "\x00"; if($buf eq "\xff") { $buf = &readnum($fh, $short); read($fh, $str, $buf); } else { read($fh, $str, vec($buf,0,8)); } $str =~ s/\,/\./g; return $str; } sub readnum { my $fh = shift; my $byte = shift; my @bytes; my $i = $byte; while ($i) { read($fh, my $buf, 1); unshift(@bytes, $buf); $i--; } return vec(join('', @bytes), 0, $byte*8); } sub readtime { my $fh = shift; my $buf = &readnum($fh, $long); return $buf unless $opt_t; my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($buf); if($opt_t == 1) { return sprintf ("%04d/%02d/%02d\(%s\) %02d:%02d:%02d", $year + 1900, $mon + 1, $mday, ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')[$wday], $hour, $min, $sec); } elsif($opt_t == 2) { return sprintf ("%02d:%02d:%02d %s.%02d/%s/%04d", $hour, $min, $sec, ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')[$wday], $mday, ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')[$mon], $year + 1900); } elsif($opt_t == 3) { return $buf/86400+25569+$timezone/24; } else { print "\nSomething strange..."; exit(1); } } sub help { print <<EOF; Usage $0 [-t [date_format_type] -i -h -v] target_datebook_file This script converts Palm datebook file to CSV format. Data stored in a file is simply output to STDOUT in order. Switches t: Outputs date and time data in easy-to-read format. date_format_type: 1 yyyy/mm/dd(www) hh:mm:ss date_format_type: 2 hh:mm:ss www.dd/mmm/yyyy i: Outputs index at the first line. h: Outputs this help. v: Outputs version infomation. If 'target_datebook_file' looks like a directory, '/datebook/datebook.dat' string is automatically appended at the tail. So in many cases, it is only necessary to set this '"C:\\Program Files\\Palm\\(USERNAME)"'. EOF exit(0); } sub version { print "\n$0 Ver.$version $reldate by Ken \"OSAMU\" Sugii\n"; exit(0); }