00001 #ifdef HAVE_CONFIG_H 00002 #include <config.h> 00003 #endif 00004 00005 #include <iostream> 00006 #include <cstdlib> 00007 #include <iterator> 00008 #include <algorithm> 00009 #include <list> 00010 00011 #include <fstream> 00012 00013 #include <sys/types.h> 00014 #include <sys/stat.h> 00015 00016 #include <cerrno> 00017 #include <cstring> 00018 00019 #include "chmxx.h" 00020 00021 using namespace std; 00022 using namespace chm; 00023 00024 namespace { 00025 00026 void print_topics_tree (const chm_topics_tree *tree, int level = 0) 00027 { 00028 if ( level != 0 ) 00029 cout << string(level * 4, ' ') << tree->title << endl; 00030 00031 for_each (tree->children.begin(), tree->children.end(), 00032 bind2nd(ptr_fun(print_topics_tree), level + 1)); 00033 } 00034 00035 void error (const string& pname, const string& err = "") { 00036 if ( err == "" ) { 00037 cerr << pname << ": Usage: " << pname << " <file.chm> list|get|listall|export|stats|topics|index|indexall [<path|text>]" << endl; 00038 } else { 00039 cerr << pname << ": " << err << endl; 00040 } 00041 exit(1); 00042 } 00043 00044 void do_export (const string& pname, const chmfile& chm, const string& root, const string& p) 00045 { 00046 if ( mkdir(root.c_str(), 0755) == -1 && errno != EEXIST) 00047 error (pname, string() + "Unable to create the target directory [" + root + "]: " + strerror(errno)); 00048 00049 list<string> dirs; 00050 chm.readdir(p, dirs, chmfile::dirs); 00051 00052 list<string> files; 00053 chm.readdir(p, files, chmfile::files); 00054 00055 for ( list<string>::iterator it = dirs.begin(); it != dirs.end(); it++ ) { 00056 do_export (pname, chm, root + *it, p + *it); 00057 } 00058 00059 for ( list<string>::iterator it = files.begin(); it != files.end(); it++ ) { 00060 string path = root + *it; 00061 ofstream out(path.c_str()); 00062 if ( !out ) 00063 error (pname, string() + "Unable to open export file for writing: " + strerror (errno)); 00064 chm.read (p + *it, out); 00065 out.close(); 00066 } 00067 } 00068 00069 void list_all (const string& pname, const chmfile& chm, const string& root = "/") 00070 { 00071 list<string> l; 00072 chm.readdir (root, l); 00073 for (list<string>::iterator it = l.begin(); it != l.end(); it++ ) { 00074 string& n = *it; 00075 cout << root << n << endl; 00076 if ( n[n.size()-1] == '/' ) list_all (pname, chm, root + n); 00077 } 00078 } 00079 00080 } 00081 00082 int main(int argc, char *argv[]) 00083 { 00084 if ( argc < 3 ) error(argv[0]); 00085 00086 chmfile chm(argv[1]); 00087 if ( !chm ) error (argv[0], "Invalid chm file"); 00088 00089 string cmd = argv[2]; 00090 00091 if ( cmd == "list" ) { 00092 if ( argc != 4 ) error(argv[0]); 00093 list<string> dc; 00094 chm.readdir (argv[3], dc); 00095 ostream_iterator<string> out(cout, "\n"); 00096 copy(dc.begin(), dc.end(), out); 00097 return 0; 00098 } else if ( cmd == "get" ) { 00099 if ( argc != 4 ) error(argv[0]); 00100 streambuf *sb = chm.open(argv[3]); 00101 if ( !sb ) 00102 error (argv[0], "Could not find given path inside the archive"); 00103 cout << sb; 00104 delete sb; 00105 return 0; 00106 } else if ( cmd == "listall" ) { 00107 list_all (argv[0], chm); 00108 return 0; 00109 } else if ( cmd == "stats" ) { 00110 cout << "---Statistics---" << endl; 00111 cout << " Title: " << chm.get_title() << endl; 00112 cout << " Generator: " << chm.get_generator() << endl; 00113 cout << " Home: " << chm.get_home_file() << endl; 00114 cout << " Topics: " << chm.get_topics_file() << endl; 00115 cout << " Index: " << chm.get_index_file() << endl; 00116 return 0; 00117 } else if ( cmd == "topics" ) { 00118 if ( chm.get_topics_tree() ) { 00119 cout << "Topics tree:" << endl; 00120 print_topics_tree (chm.get_topics_tree()); 00121 } else { 00122 cout << "No topics tree found" << endl; 00123 } 00124 return 0; 00125 } else if ( cmd == "export" ) { 00126 if ( argc != 4 ) error(argv[0]); 00127 cout << "Exporting.." << endl; 00128 string w = argv[3]; 00129 if ( !w.empty() && w[w.size() - 1] != '/' ) w += '/'; 00130 do_export (argv[0], chm, w, "/"); 00131 return 0; 00132 } else if ( cmd == "index" ) { 00133 if ( argc != 4 ) error(argv[0]); 00134 00135 list<chm_search_match> f; 00136 chm.cache_search_database(); 00137 chm.search_index(argv[3], f); 00138 00139 for ( list<chm_search_match>::iterator it = f.begin(); it != f.end(); it++ ) 00140 for ( size_t i = 0; i < it->documents.size(); i++ ) 00141 cout << it->key << "|" << it->is_title << "|" << it->documents[i].offsets.size() << "|" 00142 << it->documents[i].path << "|" << it->documents[i].title << endl; 00143 00144 return 0; 00145 } else if ( cmd == "indexall" ) { 00146 if ( argc != 4 ) error(argv[0]); 00147 00148 list<chm_search_match> f; 00149 chm.cache_search_database(); 00150 chm.search_index(argv[3], f, false, false); 00151 00152 for ( list<chm_search_match>::iterator it = f.begin(); it != f.end(); it++ ) 00153 for ( size_t i = 0; i < it->documents.size(); i++ ) 00154 cout << it->key << "|" << it->is_title << "|" << it->documents[i].offsets.size() << "|" 00155 << it->documents[i].path << "|" << it->documents[i].title << endl; 00156 00157 return 0; 00158 } 00159 00160 error (argv[0], "Invalid second argument"); 00161 }