/*--[clit18.c]---------------------------------------------------------------- | Copyright (C) 2002, 2003 Dan A. Jackson | | This file is part of the "clit" (Convert LIT) program. | | Convert LIT 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., 675 Mass Ave, Cambridge, MA 02139, USA. | | The GNU General Public License may also be available at the following | URL: http://www.gnu.org/licenses/gpl.html */ #ifdef _MSC_VER #include #include #endif #include #include #include #include #include #include #include #ifndef _MSC_VER #include #endif #include "litlib.h" extern int drm5_callback(void *, U8 *, int size); #ifdef _MSC_VER #include #define mkdir(x,y) _mkdir(x) #define stat _stat #endif #ifndef MAX_PATH #include #define MAX_PATH PATH_MAX #endif extern int display_lit(lit_file * litfile, int public_only); extern int explode_lit(lit_file * litfile, char * litName, char * pathOutput); extern int transmute_lit(lit_file * litfile, char * newlitfile, char * ); static U8 * readat(void * v, U32 offset, int size); /* Must not be static, linked into litlib */ void lit_error(int what, char * fmt, ...); static int windowed_mode; static int printed_error = 0; char * readingFilename = NULL; char * writingFilename = NULL; int disable_directory_support = 0; char dir_program[MAX_PATH]; char dir_lit_file[MAX_PATH]; char * key_file = NULL; const char * sTitle = "+---[ ConvertLIT (Version 1.8) ]---------------"\ "[ Copyright (c) 2002,2003 ]---\n"\ "ConvertLIT comes with ABSOLUTELY NO WARRANTY; for details\n"\ "see the COPYING file or visit \"http://www.gnu.org/license/gpl.html\". \n"\ "This is free software, and you are welcome to redistribute it under \n"\ "certain conditions. See the GPL license for details.\n"; const char * sUsage = \ "\nThis program has three modes of operation: \n"\ "First, is ** EXPLOSION **, or the expanding of a .LIT file into an \n"\ "OEBPS compliant package. \n"\ "To explode, you type: clit \\\n"\ "For Example:\n"\ "\tclit ebook-propietary.lit ebook-oebps\\ \n"\ "If the directory does not exist, you MUST put a trailing \\ or / after it!\n"\ "\nTo disable creating multiple subdirectories, use the \"-d\" flag.\n"\ "\nSecond, is the DOWNCONVERTING of a .LIT file down to \"Sealed\", \n"\ "or DRM1 format for reading on handheld devices. \n"\ "To downconvert, you type: clit \n"\ "For Example:\n"\ "\tclit \"drm5 ebook.lit\" ebook-open.lit\n"\ "\nThird, is the INSCRIBING of a .LIT file which allows you to label \n"\ "your ebooks. This is very similar to downconverting, you just add \n"\ "a third argument: clit \n"\ "For example: \n"\ "\tclit ebook.lit inscribed.lit \"the Library of Basil "\ "Frankweiler\"\n"\ "\nDRM5 is supported if you have a \"keys.txt\" file that contains\n"\ "the private key(s) for your passport(s) in either the CLIT program\n"\ "directory or the current directory. \n"\ "Use the -k flag to force the location of your keys.txt\n\n"\ "This is a tool for **YOUR OWN FAIR USE** and not for stealing \n"\ "other people's ebooks.\n"\ "\nPlease do not use this program to distrbute illegal copies of ebooks.\n"\ "\t... that would make Baby Jesus sad.\n"; int main(int argc, char ** argv) { int status; char * path = NULL; lit_file lit; char * filename, * output, * inscription, c; FILE * fh; struct stat statbuf; int task = 0; int base, i; int done_args = 0; /* Save the current directory for later */ strncpy(dir_program, argv[0], MAX_PATH-1); dir_program[MAX_PATH] = '\0'; for (i = strlen(dir_program); i >= 0; i--) { if ((dir_program[i] == '/') || (dir_program[i] == '\\')) { dir_program[i+1] = '\0'; break; } } printf(sTitle); if (argc < 3) { printf(sUsage); return -1; } base = 1; while ((argv[base][0] == '-') && (!done_args)) { int i; for (i = 1; i < (int)strlen(argv[base]); i++) { switch (argv[base][i]) { case 'd': case 'D': disable_directory_support = 1; break; case 'k': case 'K': key_file = &argv[base][i+1]; i = 0; break; case '-': done_args = 1; } if (!i) break; } base++; } base--; inscription = NULL; if (argc == (4+base)) { inscription = argv[base+3]; } filename = argv[base+1]; strncpy(dir_lit_file, filename, MAX_PATH-1); dir_lit_file[MAX_PATH-1] = '\0'; for (i = strlen(dir_lit_file); i >= 0; i--) { if ((dir_lit_file[i] == '/') || (dir_lit_file[i] == '\\')) { dir_lit_file[i+1] = '\0'; break; } } output = argv[base+2]; readingFilename = filename; fh = fopen(filename, "rb"); if (!fh) { lit_error(ERR_LIBC|ERR_R,"Unable to open file."); return -1; } memset(&lit, 0, sizeof(lit)); lit.file_pointer = (void *)fh; lit.readat = readat; lit.drm5_callback= drm5_callback; lit.drm5_data = (void *)&lit; (void)fseek(fh, 0, SEEK_END); lit.filesize = ftell(fh); status = lit_read_from_file(&lit); if ((status) && (status != E_LIT_DRM_ERROR)) { lit_close(&lit); exit(-1); } printf("LIT INFORMATION.........\n"); if (lit.drmlevel >= 0) printf("DRM = %d \n", lit.drmlevel); printf("Timestamp = %08lx \n", lit.timestamp); printf("Creator = %08lx \n", lit.creator_id); printf("Language = %08lx \n", lit.language_id); if (strlen(output) == 0) { if (status) display_lit(&lit, 1); else display_lit(&lit, 0); lit_close(&lit); exit(-1); } else if (status) { printf("\nDECRYPTION FAILED - No keys available for this title.\n"); lit_close(&lit); exit(-1); } status = stat(output, &statbuf); if (status < 0) { if (errno == ENOENT) { c = output[strlen(output) - 1]; if ((c == '/') || (c == '\\')) { status = mkdir(output,0755); if (!status) { task = 1; } else { lit_error(ERR_LIBC, "Unable to create directory \"%s\"!", output); } } else { task = 2; } } else if (errno == ENOTDIR) { fprintf(stderr,"Cannot make directory \"%s\" -- " " a file already exists!\n", output); exit(-1); }else { lit_error(ERR_LIBC,"stat() failed unexpectedly"); exit(-1); } } else { if (statbuf.st_mode & S_IFDIR) { c = output[strlen(output) - 1]; if ( (c != '/') && (c != '\\')) { path = malloc(strlen(output) + 1); if (!path) { fprintf(stderr,"Malloc(%d) failed!\n", strlen(output) + 1); exit(-1); } strcpy(path, output); strcat(path, "/"); output = path; } task = 1; } else { status = -1; fprintf(stderr,"Output file \"%s\" already exists. " "Delete it first!\n", output); task = 0; } } if (task == 1) { status = explode_lit(&lit, filename, output); if (status != 0) { if (status > 0) { printf("Finished exploding \"%s\", but with errors.", filename); } } else { printf("Exploded \"%s\" into \"%s\".\n", filename, output); } } else if (task == 2) { status = transmute_lit(&lit, output, inscription); if (status != 0) { printf("<><><><><> FAILED TO %s \"%s\"!", (inscription)?"INSCRIBE":"CONVERT",filename); } else { printf("Converted \"%s\" --> \"%s\".\n", filename, output); } } if (task && status) { if (!printed_error) { lit_error(ERR_R, "Encountered an error, but didn't print a message! Bad programmer!"); } } lit_close(&lit); if (path) free(path); return status; } U8 * readat(void * v, U32 offset, int size) { U8 *mem; int read_size; FILE * f; f = (FILE *)v; if (!f) { lit_error(0,"No filehandle passed in!"); return NULL; } mem = malloc(size); if (!mem) { lit_error(ERR_LIBC,"malloc(%d) failed.", size); return NULL; } memset(mem, 0, size); if (fseek(f, offset, SEEK_SET) != 0) { free(mem); lit_error(ERR_LIBC|ERR_R,"fseek() failed."); return NULL; } read_size = fread(mem, 1, size, f); if (read_size != size) { if (feof(f)) { fprintf(stderr, "\nWARNING: Read went past the end of file by %d bytes. \n"\ "If the conversion process doesn't work, try to redownload the file.\n", size - read_size); return mem; } free(mem); lit_error(ERR_LIBC|ERR_R,"Unable to read %d chars at position %ld.", size, offset); return NULL; } return mem; } void show_information(char * fmt, ...) { va_list ap; if (!windowed_mode) { va_start(ap, fmt); vprintf(fmt, ap); printf("\n"); } else { #ifdef _MSC_VER #endif } } #ifdef _MSC_VER void DisplayErrorText( DWORD dwLastError ) { LPSTR MessageBuffer; DWORD dwBufferLength; DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM; if(dwBufferLength = FormatMessageA(dwFormatFlags, NULL, dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &MessageBuffer, 0, NULL)) { DWORD dwBytesWritten; WriteFile( GetStdHandle(STD_ERROR_HANDLE), MessageBuffer, dwBufferLength, &dwBytesWritten, NULL); LocalFree(MessageBuffer); } } #endif void lit_error(int what, char * fmt, ...) { va_list ap; unsigned long int w32err; va_start(ap, fmt); printed_error++; w32err = 0; #ifdef _MSC_VER w32err = GetLastError(); #endif if (!windowed_mode) { if (((what & ERR_RW) == ERR_R) && readingFilename) fprintf(stderr,"Error reading file \"%s\" -- \n\t", readingFilename); if (((what & ERR_RW) == ERR_W) && writingFilename) fprintf(stderr,"Error writing file \"%s\" -- \n\t", writingFilename); vfprintf(stderr,fmt, ap); printf("\n"); if (what & ERR_LIBC) perror("\tLIBC reports"); #ifdef _MSC_VER if (what & ERR_WIN32) DisplayErrorText(w32err); #endif } else { #ifdef _MSC_VER #endif } }