You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
470 lines
11 KiB
470 lines
11 KiB
/*
|
|
* $Id: pilot-file.c,v 1.39 2006/10/12 14:21:21 desrod Exp $
|
|
*
|
|
* pilot-file.c - Palm File dump utility
|
|
*
|
|
* Pace Willisson <pace@blitz.com> December 1996
|
|
* Additions by Kenneth Albanowski
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
* Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
|
|
#include "pi-header.h"
|
|
#include "pi-source.h"
|
|
#include "pi-file.h"
|
|
#include "pi-userland.h"
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: iso_time_str
|
|
*
|
|
* Summary: Build an ISO-compliant date string
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
***********************************************************************/
|
|
static char *iso_time_str(time_t t)
|
|
{
|
|
struct tm tm;
|
|
static char buf[50];
|
|
|
|
tm = *localtime(&t);
|
|
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
|
|
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
|
return (buf);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: dump
|
|
*
|
|
* Summary: Dump data as requested by other functions
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
***********************************************************************/
|
|
static void dump(void *buf, int n)
|
|
{
|
|
int ch,
|
|
i,
|
|
j;
|
|
|
|
for (i = 0; i < n; i += 16) {
|
|
printf("%04x: ", i);
|
|
for (j = 0; j < 16; j++) {
|
|
if (i + j < n)
|
|
printf("%02x ",
|
|
((unsigned char *) buf)[i + j]);
|
|
else
|
|
printf(" ");
|
|
}
|
|
printf(" ");
|
|
for (j = 0; j < 16 && i + j < n; j++) {
|
|
ch = ((unsigned char *) buf)[i + j] & 0x7f;
|
|
if (ch < ' ' || ch >= 0x7f)
|
|
putchar('.');
|
|
else
|
|
putchar(ch);
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: dump_header
|
|
*
|
|
* Summary: Dump the header section of the database
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
***********************************************************************/
|
|
static void dump_header(struct pi_file *pf, struct DBInfo *ip)
|
|
{
|
|
printf("Name..........: %s\n", ip->name);
|
|
printf("flags.........: 0x%x", ip->flags);
|
|
if (ip->flags & dlpDBFlagNewer)
|
|
printf(" NEWER");
|
|
|
|
if (ip->flags & dlpDBFlagReset)
|
|
printf(" RESET");
|
|
|
|
if (ip->flags & dlpDBFlagResource)
|
|
printf(" RESOURCE");
|
|
|
|
if (ip->flags & dlpDBFlagReadOnly)
|
|
printf(" READ_ONLY");
|
|
|
|
if (ip->flags & dlpDBFlagAppInfoDirty)
|
|
printf(" APP-INFO-DIRTY");
|
|
|
|
if (ip->flags & dlpDBFlagBackup)
|
|
printf(" BACKUP");
|
|
|
|
if (ip->flags & dlpDBFlagCopyPrevention)
|
|
printf(" COPY-PREVENTION");
|
|
|
|
if (ip->flags & dlpDBFlagStream)
|
|
printf(" STREAM");
|
|
|
|
if (ip->flags & dlpDBFlagOpen)
|
|
printf(" OPEN");
|
|
|
|
printf("\n");
|
|
printf("version.......: %d\n", ip->version);
|
|
printf("creation_time.: %s\n", iso_time_str(ip->createDate));
|
|
printf("modified_time.: %s\n", iso_time_str(ip->modifyDate));
|
|
printf("backup_time...: %s\n", iso_time_str(ip->backupDate));
|
|
printf("mod_number....: %ld\n", ip->modnum);
|
|
printf("type..........: %s\n", printlong(ip->type));
|
|
printf("CreatorID.....: %s\n", printlong(ip->creator));
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: dump_app_info
|
|
*
|
|
* Summary: Dump the AppInfo segment of the database(s)
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
***********************************************************************/
|
|
static void dump_app_info(struct pi_file *pf, struct DBInfo *ip)
|
|
{
|
|
size_t app_info_size;
|
|
void *app_info;
|
|
|
|
pi_file_get_app_info(pf, &app_info, &app_info_size);
|
|
|
|
printf("app_info_size %zu\n", app_info_size);
|
|
dump(app_info, app_info_size);
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: dump_sort_info
|
|
*
|
|
* Summary: Dump the SortInfo block of the database(s)
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
***********************************************************************/
|
|
static void dump_sort_info(struct pi_file *pf, struct DBInfo *ip)
|
|
{
|
|
size_t sort_info_size;
|
|
void *sort_info;
|
|
|
|
|
|
pi_file_get_sort_info(pf, &sort_info, &sort_info_size);
|
|
|
|
printf("sort_info_size %zu\n", sort_info_size);
|
|
dump(sort_info, sort_info_size);
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: list_records
|
|
*
|
|
* Summary: List all records in the database(s)
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
***********************************************************************/
|
|
static void list_records(struct pi_file *pf, struct DBInfo *ip, int filedump, int verbose)
|
|
{
|
|
int attrs,
|
|
cat,
|
|
entnum, /* Number of the entry record */
|
|
id_,
|
|
nentries; /* Number of entries in the list */
|
|
size_t size;
|
|
void *buf;
|
|
unsigned long type, uid;
|
|
|
|
pi_file_get_entries(pf, &nentries);
|
|
|
|
if (ip->flags & dlpDBFlagResource) {
|
|
printf("entries\n");
|
|
printf("index\tsize\ttype\tid\n");
|
|
for (entnum = 0; entnum < nentries; entnum++) {
|
|
if (pi_file_read_resource
|
|
(pf, entnum, &buf, &size, &type, &id_) < 0) {
|
|
printf("error reading %d\n\n", entnum);
|
|
return;
|
|
}
|
|
printf("%d\t%zu\t%s\t%d\n", entnum, size,
|
|
printlong(type), id_);
|
|
if (verbose) {
|
|
dump(buf, size);
|
|
printf("\n");
|
|
if (filedump) {
|
|
FILE *fp;
|
|
char name[64];
|
|
|
|
sprintf(name, "%4s%04x.bin",
|
|
printlong(type), id_);
|
|
fp = fopen(name, "w");
|
|
fwrite(buf, size, 1, fp);
|
|
fclose(fp);
|
|
printf("(written to %s)\n", name);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
printf("entries\n");
|
|
printf("index\tsize\tattrs\tcat\tuid\n");
|
|
for (entnum = 0; entnum < nentries; entnum++) {
|
|
if (pi_file_read_record(pf, entnum, &buf, &size,
|
|
&attrs, &cat, &uid) < 0) {
|
|
printf("error reading %d\n\n", entnum);
|
|
return;
|
|
}
|
|
printf("%d\t%zu\t0x%x\t%d\t0x%lx\n", entnum, size,
|
|
attrs, cat, uid);
|
|
if (verbose) {
|
|
dump(buf, size);
|
|
printf("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: dump_record
|
|
*
|
|
* Summary: Dump a record
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
***********************************************************************/
|
|
static void dump_record(struct pi_file *pf, struct DBInfo *ip, char *rkey, int filedump)
|
|
{
|
|
int attrs,
|
|
cat,
|
|
id_,
|
|
record;
|
|
size_t size;
|
|
void *buf;
|
|
unsigned long type;
|
|
unsigned long uid;
|
|
|
|
|
|
if (ip->flags & dlpDBFlagResource) {
|
|
printf("entries\n");
|
|
printf("index\tsize\ttype\tid\n");
|
|
if (sscanf(rkey, "%d", &record) == 1) {
|
|
if (pi_file_read_resource
|
|
(pf, record, &buf, &size, &type, &id_) < 0) {
|
|
printf("error reading resource #%d\n\n",
|
|
record);
|
|
return;
|
|
}
|
|
} else {
|
|
type = makelong(rkey);
|
|
id_ = 0;
|
|
sscanf(&rkey[4], "%d", &id_);
|
|
if (pi_file_read_resource_by_type_id
|
|
(pf, type, id_, &buf, &size, &record) < 0) {
|
|
printf
|
|
("error reading resource %s' #%d (0x%x)\n\n",
|
|
printlong(type), id_, id_);
|
|
return;
|
|
}
|
|
}
|
|
|
|
printf("%d\t%zu\t%s\t%d\n", record, size, printlong(type),
|
|
id_);
|
|
dump(buf, size);
|
|
if (filedump) {
|
|
FILE *fp;
|
|
char name[64];
|
|
|
|
sprintf(name, "%4s%04x.bin", printlong(type), id_);
|
|
fp = fopen(name, "w");
|
|
fwrite(buf, size, 1, fp);
|
|
fclose(fp);
|
|
printf("(written to %s)\n", name);
|
|
}
|
|
} else {
|
|
printf("entries\n");
|
|
printf("index\tsize\tattrs\tcat\tuid\n");
|
|
if (sscanf(rkey, "0x%lx", &uid) == 1) {
|
|
if (pi_file_read_record_by_id(pf, uid, &buf, &size,
|
|
&record, &attrs,
|
|
&cat) < 0) {
|
|
printf
|
|
("error reading record uid 0x%lx\n\n",
|
|
uid);
|
|
return;
|
|
}
|
|
} else {
|
|
record = 0;
|
|
sscanf(rkey, "%d", &record);
|
|
if (pi_file_read_record(pf, record, &buf, &size,
|
|
&attrs, &cat, &uid) < 0) {
|
|
printf("error reading record #%d\n\n",
|
|
record);
|
|
return;
|
|
}
|
|
}
|
|
printf("%d\t%zu\t0x%x\t%d\t0x%lx\n", record, size, attrs,
|
|
cat, uid);
|
|
dump(buf, size);
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, const char **argv)
|
|
{
|
|
int c, /* switch */
|
|
hflag = 0,
|
|
aflag = 0,
|
|
sflag = 0,
|
|
dflag = 0,
|
|
lflag = 0,
|
|
rflag = 0,
|
|
filedump = 0;
|
|
|
|
char *rkey = NULL;
|
|
|
|
const char **rargv = NULL;
|
|
|
|
struct pi_file *pf;
|
|
struct DBInfo info;
|
|
|
|
poptContext po;
|
|
|
|
struct poptOption options[] = {
|
|
USERLAND_RESERVED_OPTIONS
|
|
{"header", 'H', POPT_ARG_NONE, &hflag, 0, "Dump the header of the database(s)"},
|
|
{"appinfo", 'a', POPT_ARG_NONE, &aflag, 0, "Dump app_info segment of the database(s)"},
|
|
{"sortinfo", 's', POPT_ARG_NONE, &sflag, 0, "Dump sort_info block of database(s)"},
|
|
{"list", 'l', POPT_ARG_NONE, &lflag, 0, "List all records in the database(s)"},
|
|
{"record", 'r', POPT_ARG_STRING, &rkey, 0, "Dump a record by index ('code0') or uid ('1234')"},
|
|
{"to-file", 'f', POPT_ARG_NONE, &filedump, 0, "Same as above but also dump records to files"},
|
|
{"dump", 'd', POPT_ARG_NONE, &dflag, 0, "Dump all data and all records, very verbose"},
|
|
POPT_TABLEEND
|
|
};
|
|
|
|
po = poptGetContext("pilot-file", argc, argv, options, 0);
|
|
poptSetOtherOptionHelp(po,"<filename> ...\n\n"
|
|
" Dump application and header information from your local PRC/PDB files\n\n"
|
|
" Example arguments:\n"
|
|
" -l Foo.prc\n"
|
|
" -H -a Bar.pdb\n\n");
|
|
|
|
plu_popt_alias(po,"dump-rec",0,"--bad-option --to-file --record");
|
|
plu_popt_alias(po,NULL,'R',"--bad-option --to-file --record");
|
|
plu_popt_alias(po,"dump-res",0,"--bad-option --to-file --dump");
|
|
plu_popt_alias(po,NULL,'D',"--bad-option --to-file --dump");
|
|
|
|
if (argc < 2) {
|
|
poptPrintUsage(po,stderr,0);
|
|
return 1;
|
|
}
|
|
|
|
while ((c = poptGetNextOpt(po)) >= 0) {
|
|
fprintf(stderr," ERROR: Unhandled option %d.\n",c);
|
|
return 1;
|
|
}
|
|
|
|
if (c < -1) {
|
|
plu_badoption(po,c);
|
|
}
|
|
|
|
if (rkey) {
|
|
rflag = 1;
|
|
}
|
|
|
|
rargv = poptGetArgs(po);
|
|
if (!rargv || !rargv[0]) {
|
|
fprintf(stderr," ERROR: Must provide one or more filenames.\n");
|
|
return 1;
|
|
}
|
|
|
|
while (*rargv) {
|
|
const char *name = *rargv++;
|
|
|
|
if ((pf = pi_file_open(name)) == NULL) {
|
|
fprintf(stderr, " ERROR: Can't open '%s' Does '%s' exist?\n\n",
|
|
name, name);
|
|
continue;
|
|
}
|
|
|
|
pi_file_get_info(pf, &info);
|
|
|
|
if (hflag || dflag)
|
|
dump_header(pf, &info);
|
|
|
|
if (aflag || dflag)
|
|
dump_app_info(pf, &info);
|
|
|
|
if (sflag || dflag)
|
|
dump_sort_info(pf, &info);
|
|
|
|
if (lflag || dflag)
|
|
list_records(pf, &info, filedump, dflag);
|
|
|
|
if (rflag)
|
|
dump_record(pf, &info, rkey, filedump);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */
|
|
/* ex: set tabstop=4 expandtab: */
|
|
/* Local Variables: */
|
|
/* indent-tabs-mode: t */
|
|
/* c-basic-offset: 8 */
|
|
/* End: */
|