#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#ifdef _WIN32
# include <direct.h>
# define mkdir(path,flags) _mkdir(path)
const char separator = '\\';
#else
const char separator = '/';
#endif
bool outdir_opt = false;
char outdir[FILENAME_MAX];
#define UNUSED(x) (void)(x)
#ifndef min
# define min(a, b) ((a) < (b) ? (a) : (b))
#endif
"Success",
"Generic error",
"Wrong function parameter",
"Corrupted data",
"File not found",
"Document is encrypted",
"Unsupported document format",
"Memory allocation error",
"Initialization error",
"Buffer error",
"XML error",
"Invalid DRM pid",
"DRM key not found",
"DRM support not included",
"Write failed",
"DRM expired"
};
#define LIBMOBI_MSG_COUNT ARRAYSIZE(libmobi_messages)
size_t index = ret;
if (index < LIBMOBI_MSG_COUNT) {
}
return "Unknown error";
}
void split_fullpath(
const char *fullpath,
char *dirname,
char *basename,
const size_t buf_len) {
if (buf_len == 0) {
return;
}
char *p = strrchr(fullpath, separator);
if (p) {
p += 1;
if (dirname) {
size_t dirlen = min(buf_len - 1, (size_t) (p - fullpath));
strncpy(dirname, fullpath, dirlen);
dirname[dirlen] = '\0';
}
if (basename) {
strncpy(basename, p, buf_len - 1);
basename[buf_len - 1] = '\0';
}
}
else {
if (dirname) {
dirname[0] = '\0';
}
if (basename) {
strncpy(basename, fullpath, buf_len - 1);
basename[buf_len - 1] = '\0';
}
}
if (basename) {
p = strrchr(basename, '.');
if (p) {
*p = '\0';
}
}
}
errno = 0;
if (mkdir(path, S_IRWXU) != 0 && errno != EEXIST) {
int errsv = errno;
printf("Creating directory \"%s\" failed (%s)\n", path, strerror(errsv));
return ERROR;
}
return SUCCESS;
}
int create_subdir(
char *newdir,
const size_t buf_len,
const char *parent_dir,
const char *subdir_name) {
int n = snprintf(newdir, buf_len, "%s%c%s", parent_dir, separator, subdir_name);
if (n < 0) {
printf("Creating file name failed\n");
return ERROR;
}
if ((size_t) n >= buf_len) {
printf("File name too long: %s\n", newdir);
return ERROR;
}
}
int write_file(
const unsigned char *buffer,
const size_t len,
const char *path) {
errno = 0;
FILE *file = fopen(path, "wb");
if (file == NULL) {
int errsv = errno;
printf("Could not open file for writing: %s (%s)\n", path, strerror(errsv));
return ERROR;
}
size_t n = fwrite(buffer, 1, len, file);
if (n != len) {
int errsv = errno;
printf("Error writing to file: %s (%s)\n", path, strerror(errsv));
fclose(file);
return ERROR;
}
fclose(file);
return SUCCESS;
}
int write_to_dir(
const char *dir,
const char *name,
const unsigned char *buffer,
const size_t len) {
char path[FILENAME_MAX];
int n = snprintf(path, sizeof(path), "%s%c%s", dir, separator, name);
if (n < 0) {
printf("Creating file name failed\n");
return ERROR;
}
if ((size_t) n >= sizeof(path)) {
printf("File name too long\n");
return ERROR;
}
}
struct stat sb;
if (stat(path, &sb) != 0) {
int errsv = errno;
printf("Path \"%s\" is not accessible (%s)\n", path, strerror(errsv));
return false;
}
if (!S_ISDIR(sb.st_mode)) {
printf("Path \"%s\" is not a directory\n", path);
return false;
}
return true;
}
#ifdef _WIN32
if (path != NULL) {
for (size_t i = 0; i <= strlen(path); i++) {
if (path[i] == '/') {
path[i] = separator;
}
}
}
#else
UNUSED(path);
#endif
}
if (title) {
printf("Title: %s\n", title);
free(title);
}
if (author) {
printf("Author: %s\n", author);
free(author);
}
uint32_t major = 0, minor = 0, build = 0;
bool is_calibre = false;
if (contributor) {
const char *calibre_contributor = "calibre (";
if (strncmp(contributor, calibre_contributor, strlen(calibre_contributor)) == 0) {
is_calibre = true;
sscanf(contributor, "calibre (%u.%u.%u)", &major, &minor, &build);
} else {
printf("Contributor: %s\n", contributor);
}
free(contributor);
}
if (subject) {
printf("Subject: %s\n", subject);
free(subject);
}
if (publisher) {
printf("Publisher: %s\n", publisher);
free(publisher);
}
if (date) {
printf("Publishing date: %s\n", date);
free(date);
}
if (description) {
printf("Description: %s\n", description);
free(description);
}
if (review) {
printf("Review: %s\n", review);
free(review);
}
if (imprint) {
printf("Imprint: %s\n", imprint);
free(imprint);
}
if (copyright) {
printf("Copyright: %s\n", copyright);
free(copyright);
}
if (isbn) {
printf("ISBN: %s\n", isbn);
free(isbn);
}
if (asin) {
printf("ASIN: %s\n", asin);
free(asin);
}
if (language) {
printf("Language: %s", language);
free(language);
printf(" (cp1252)");
printf(" (utf8)");
}
}
printf("\n");
}
printf("Dictionary");
printf(": %s => %s", locale_in ? locale_in : "unknown", locale_out ? locale_out : "unknown");
}
printf("\n");
}
printf("__\n");
if (strcmp(m->
ph->
type,
"TEXt") == 0) {
printf("TealDoc\n");
} else {
printf("PalmDoc\n");
}
} else {
printf(" (hybrid with version %zu)", version);
}
}
printf("\n");
}
printf("Print Replica\n");
}
printf("Document is encrypted\n");
}
if (is_calibre) {
printf("Creator software: calibre %u.%u.%u\n", major, minor, build);
} else {
if (exth) {
printf("Creator software: ");
if (exth) {
}
if (exth) {
}
if (exth) {
}
if (major == 2 && minor == 9 && build == 0 && exth) {
if (rev) {
if (strcmp(rev, "0730-890adc2") == 0) {
is_calibre = true;
}
free(rev);
}
}
switch (creator) {
case 0:
printf("mobipocket reader %u.%u.%u", major, minor, build);
break;
case 1:
case 101:
printf("mobigen %u.%u.%u", major, minor, build);
break;
case 2:
printf("mobipocket creator %u.%u.%u", major, minor, build);
break;
case 200:
printf("kindlegen %u.%u.%u (windows)", major, minor, build);
if (is_calibre) {
printf(" or calibre");
}
break;
case 201:
printf("kindlegen %u.%u.%u (linux)", major, minor, build);
if ((major == 1 && minor == 2 && build == 33307) ||
(major == 2 && minor == 0 && build == 101) ||
is_calibre) {
printf(" or calibre");
}
break;
case 202:
printf("kindlegen %u.%u.%u (mac)", major, minor, build);
if (is_calibre) {
printf(" or calibre");
}
break;
default:
printf("unknown");
break;
}
printf("\n");
}
}
}
return;
}
if (curr != NULL) {
printf("\nEXTH records:\n");
}
uint32_t val32;
while (curr != NULL) {
char *str = malloc(curr->
size + 1);
if (!str) {
printf("Memory allocation failed\n");
exit(1);
}
unsigned i = 0;
unsigned char *p = curr->
data;
while (i < curr->size && isprint(*p)) {
str[i] = (char)*p++;
i++;
}
str[i] = '\0';
printf(
"Unknown (%i): %s (%u)\n", curr->
tag, str, val32);
free(str);
} else {
size_t size = curr->
size;
unsigned char *data = curr->
data;
case EXTH_NUMERIC:
printf(
"%s (%i): %u\n", tag.
name, tag.
tag, val32);
break;
case EXTH_STRING:
{
if (exth_string) {
printf(
"%s (%i): %s\n", tag.
name, tag.
tag, exth_string);
free(exth_string);
}
break;
}
case EXTH_BINARY:
{
unsigned i = 0;
const size_t str_len = 2 * size + 1;
char *str = malloc(str_len);
if (!str) {
printf("Memory allocation failed\n");
exit(1);
}
str[0] = '\0';
while (size) {
uint8_t val8 = *data++;
snprintf(&str[i], str_len - i, "%02x", val8);
i += 2;
size--;
}
printf(
"%s (%i): 0x%s\n", tag.
name, tag.
tag, str);
free(str);
break;
}
default:
break;
}
}
}
}
printf("\nVerifying PID %s...", pid);
return (int) mobi_ret;
}
printf("ok\n");
return SUCCESS;
}
printf("\nVerifying serial %s... ", serial);
return (int) mobi_ret;
}
printf("ok\n");
return SUCCESS;
}
if (!pid && !serial) {
return SUCCESS;
}
printf("\nDocument is not encrypted, ignoring PID/serial\n");
return SUCCESS;
}
printf("\nEncryption type 1, ignoring PID/serial\n");
return SUCCESS;
}
int ret = SUCCESS;
return SUCCESS;
}
if (serial) {
}
return ret;
}
char outfile[FILENAME_MAX];
char basename[FILENAME_MAX];
char dirname[FILENAME_MAX];
int n;
if (outdir_opt) {
n = snprintf(outfile, sizeof(outfile), "%s%s-%s.%s", outdir, basename, suffix, ext);
} else {
n = snprintf(outfile, sizeof(outfile), "%s%s-%s.%s", dirname, basename, suffix, ext);
}
if (n < 0) {
printf("Creating file name failed\n");
return ERROR;
}
if ((size_t) n >= sizeof(outfile)) {
printf("File name too long\n");
return ERROR;
}
printf("Saving %s...\n", outfile);
FILE *file_out = fopen(outfile, "wb");
if (file_out == NULL) {
int errsv = errno;
printf("Error opening file: %s (%s)\n", outfile, strerror(errsv));
return ERROR;
}
fclose(file_out);
printf(
"Error writing file (%s)\n",
libmobi_msg(mobi_ret));
return ERROR;
}
return SUCCESS;
}
const char * libmobi_messages[]
Messages for libmobi return codes For reference see enum MOBI_RET in mobi.h.
Definition: common.c:42
void print_exth(const MOBIData *m)
Print all loaded EXTH record tags.
Definition: common.c:433
int write_to_dir(const char *dir, const char *name, const unsigned char *buffer, const size_t len)
Write content to file in directory.
Definition: common.c:188
int set_decryption_key(MOBIData *m, const char *serial, const char *pid)
Set key for decryption. Use user supplied pid or device serial number.
Definition: common.c:554
const char * libmobi_msg(const MOBI_RET ret)
Return message for given libmobi return code.
Definition: common.c:68
bool dir_exists(const char *path)
Check whether given path exists and is a directory.
Definition: common.c:207
void split_fullpath(const char *fullpath, char *dirname, char *basename, const size_t buf_len)
Parse file name into file path and base name. Dirname or basename can be skipped by setting to null.
Definition: common.c:84
void print_summary(const MOBIData *m)
Print summary meta information.
Definition: common.c:244
int create_subdir(char *newdir, const size_t buf_len, const char *parent_dir, const char *subdir_name)
Create subfolder in directory.
Definition: common.c:141
int write_file(const unsigned char *buffer, const size_t len, const char *path)
Open file descriptor and write buffer to it.
Definition: common.c:161
int set_decryption_serial(MOBIData *m, const char *serial)
Set device serial number for decryption.
Definition: common.c:536
int save_mobi(MOBIData *m, const char *fullpath, const char *suffix)
Save mobi file.
Definition: common.c:585
int make_directory(const char *path)
Make directory.
Definition: common.c:123
int set_decryption_pid(MOBIData *m, const char *pid)
Set PID for decryption.
Definition: common.c:519
void normalize_path(char *path)
Make sure we use consistent separators on Windows builds.
Definition: common.c:225
MOBI_RET
Error codes returned by functions.
Definition: mobi.h:59
@ MOBI_SUCCESS
Definition: mobi.h:60
@ MOBI_CP1252
Definition: mobi.h:216
@ MOBI_UTF8
Definition: mobi.h:217
char * mobi_meta_get_contributor(const MOBIData *m)
Get document contributor metadata.
Definition: meta.c:502
char * mobi_meta_get_author(const MOBIData *m)
Get document author metadata.
Definition: meta.c:160
char * mobi_meta_get_publishdate(const MOBIData *m)
Get document publishing date metadata.
Definition: meta.c:331
MOBI_EXPORT bool mobi_is_replica(const MOBIData *m)
Check if loaded document is Print Replica type.
Definition: util.c:2787
char * mobi_meta_get_description(const MOBIData *m)
Get document description metadata.
Definition: meta.c:388
MOBI_EXPORT char * mobi_decode_exthstring(const MOBIData *m, const unsigned char *data, const size_t size)
Decode string stored in EXTH record.
Definition: util.c:1689
MOBI_EXPORT bool mobi_is_dictionary(const MOBIData *m)
Check if loaded document is dictionary.
Definition: util.c:2709
MOBI_EXPORT uint32_t mobi_decode_exthvalue(const unsigned char *data, const size_t size)
Decode big-endian value stored in EXTH record.
Definition: util.c:1558
char * mobi_meta_get_asin(const MOBIData *m)
Get document ASIN metadata.
Definition: meta.c:730
MOBI_EXPORT bool mobi_is_encrypted(const MOBIData *m)
Check if loaded document is encrypted.
Definition: util.c:2728
MOBI_EXPORT const char * mobi_get_locale_string(const uint32_t locale)
Get pointer to locale tag for a given Mobipocket locale number.
Definition: util.c:646
char * mobi_meta_get_copyright(const MOBIData *m)
Get document copyright metadata.
Definition: meta.c:616
char * mobi_meta_get_imprint(const MOBIData *m)
Get document imprint metadata.
Definition: meta.c:445
MOBI_EXPORT MOBI_RET mobi_write_file(FILE *file, MOBIData *m)
Write mobi document to file.
Definition: write.c:511
char * mobi_meta_get_title(const MOBIData *m)
Get document title metadata.
Definition: meta.c:72
char * mobi_meta_get_publisher(const MOBIData *m)
Get document publisher metadata.
Definition: meta.c:274
MOBI_EXPORT size_t mobi_get_fileversion(const MOBIData *m)
Get mobi file version.
Definition: util.c:2807
MOBI_EXPORT MOBIExthHeader * mobi_get_exthrecord_by_tag(const MOBIData *m, const MOBIExthTag tag)
Get EXTH record with given MOBIExthTag tag.
Definition: util.c:1219
MOBI_EXPORT MOBI_RET mobi_drm_setkey_serial(MOBIData *m, const char *serial)
Store PID for encryption in MOBIData stucture. PID will be calculated from device serial number.
Definition: util.c:3442
MOBI_EXPORT bool mobi_is_hybrid(const MOBIData *m)
Check if loaded MOBI data is KF7/KF8 hybrid file.
Definition: util.c:2656
char * mobi_meta_get_review(const MOBIData *m)
Get document review metadata.
Definition: meta.c:559
char * mobi_meta_get_isbn(const MOBIData *m)
Get document ISBN metadata.
Definition: meta.c:673
char * mobi_meta_get_language(const MOBIData *m)
Get document language code metadata.
Definition: meta.c:790
MOBI_EXPORT MOBIExthMeta mobi_get_exthtagmeta_by_tag(const MOBIExthTag tag)
Get MOBIExthMeta tag structure by MOBIExthTag tag id.
Definition: util.c:1538
MOBI_EXPORT MOBI_RET mobi_drm_setkey(MOBIData *m, const char *pid)
Store PID for encryption in MOBIData stucture.
Definition: util.c:3495
char * mobi_meta_get_subject(const MOBIData *m)
Get document subject metadata.
Definition: meta.c:217
Libmobi main header file.
#define MOBI_ENCRYPTION_V1
Definition: mobi.h:40
#define MOBI_NOTSET
Usually 32-bit values in mobi records with value 0xffffffff mean "value not set".
Definition: mobi.h:37
Main structure holding all metadata and unparsed records data.
Definition: mobi.h:381
MOBIRecord0Header * rh
Definition: mobi.h:386
MOBIMobiHeader * mh
Definition: mobi.h:387
struct MOBIData * next
Definition: mobi.h:390
MOBIExthHeader * eh
Definition: mobi.h:388
MOBIPdbHeader * ph
Definition: mobi.h:385