Osmium
0.1
|
00001 #ifndef OSMIUM_HANDLER_JAVASCRIPT_HPP 00002 #define OSMIUM_HANDLER_JAVASCRIPT_HPP 00003 00004 /* 00005 00006 Copyright 2011 Jochen Topf <jochen@topf.org> and others (see README). 00007 00008 This file is part of Osmium (https://github.com/joto/osmium). 00009 00010 Osmium is free software: you can redistribute it and/or modify it under the 00011 terms of the GNU Lesser General Public License or (at your option) the GNU 00012 General Public License as published by the Free Software Foundation, either 00013 version 3 of the Licenses, or (at your option) any later version. 00014 00015 Osmium is distributed in the hope that it will be useful, but WITHOUT ANY 00016 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 00017 PARTICULAR PURPOSE. See the GNU Lesser General Public License and the GNU 00018 General Public License for more details. 00019 00020 You should have received a copy of the Licenses along with Osmium. If not, see 00021 <http://www.gnu.org/licenses/>. 00022 00023 */ 00024 00025 #include <fstream> 00026 #include <iostream> 00027 #include <v8.h> 00028 00029 extern v8::Persistent<v8::Context> global_context; 00030 00031 namespace Osmium { 00032 00033 namespace Handler { 00034 00035 class Javascript : public Base { 00036 00037 /*** 00038 * Load Javascript file into string 00039 */ 00040 static std::string load_file(const char* filename) { 00041 std::ifstream javascript_file(filename, std::ifstream::in); 00042 if (javascript_file.fail()) { 00043 std::cerr << "Can't open file " << filename << std::endl; 00044 exit(1); 00045 } 00046 std::stringstream buffer; 00047 buffer << javascript_file.rdbuf(); 00048 return buffer.str(); 00049 } 00050 00051 static const char* ToCString(const v8::String::Utf8Value& value) { 00052 return *value ? *value : "<string conversion failed>"; 00053 } 00054 00058 static void report_exception(v8::TryCatch* try_catch) { 00059 v8::HandleScope handle_scope; 00060 v8::String::Utf8Value exception(try_catch->Exception()); 00061 const char* exception_string = ToCString(exception); 00062 00063 v8::Handle<v8::Message> message = try_catch->Message(); 00064 if (message.IsEmpty()) { 00065 std::cerr << exception_string << std::endl; 00066 } else { 00067 v8::String::Utf8Value filename(message->GetScriptResourceName()); 00068 std::cerr << *filename << ":" << message->GetLineNumber() << ": " << exception_string << std::endl; 00069 00070 v8::String::Utf8Value sourceline(message->GetSourceLine()); 00071 std::cerr << *sourceline << std::endl; 00072 00073 int start = message->GetStartColumn(); 00074 int end = message->GetEndColumn(); 00075 for (int i = 0; i < start; i++) { 00076 std::cerr << " "; 00077 } 00078 for (int i = start; i < end; i++) { 00079 std::cerr << "^"; 00080 } 00081 std::cerr << std::endl; 00082 } 00083 } 00084 00085 00086 v8::Persistent<v8::Object> callbacks_object; 00087 v8::Persistent<v8::Object> osmium_object; 00088 00089 struct js_cb { 00090 v8::Handle<v8::Function> init; 00091 v8::Handle<v8::Function> node; 00092 v8::Handle<v8::Function> way; 00093 v8::Handle<v8::Function> relation; 00094 v8::Handle<v8::Function> area; 00095 v8::Handle<v8::Function> end; 00096 } cb; 00097 00098 public: 00099 00100 static v8::Handle<v8::Value> Print(const v8::Arguments& args) { 00101 v8::HandleScope handle_scope; 00102 00103 for (int i = 0; i < args.Length(); i++) { 00104 Osmium::v8_String_to_ostream(args[i]->ToString(), std::cout); 00105 std::cout << "\n"; 00106 } 00107 00108 return handle_scope.Close(v8::Integer::New(1)); 00109 } 00110 00111 static v8::Handle<v8::Value> Include(const v8::Arguments& args) { 00112 for (int i=0; i < args.Length(); i++) { 00113 v8::String::Utf8Value filename(args[i]); 00114 00115 std::string javascript_source = load_file(*filename); 00116 00117 if (javascript_source.length() > 0) { 00118 v8::TryCatch tryCatch; 00119 00120 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(javascript_source.c_str()), v8::String::New(*filename)); 00121 if (script.IsEmpty()) { 00122 std::cerr << "Compiling included script failed:" << std::endl; 00123 report_exception(&tryCatch); 00124 exit(1); 00125 } 00126 00127 v8::Handle<v8::Value> result = script->Run(); 00128 if (result.IsEmpty()) { 00129 std::cerr << "Running included script failed:" << std::endl; 00130 report_exception(&tryCatch); 00131 exit(1); 00132 } 00133 } 00134 } 00135 return v8::Undefined(); 00136 } 00137 00138 static v8::Handle<v8::Value> OutputCSVOpen(const v8::Arguments& args) { 00139 if (args.Length() != 1) { 00140 return v8::Undefined(); 00141 } else { 00142 v8::String::Utf8Value str(args[0]); 00143 Osmium::Export::CSV* oc = new Osmium::Export::CSV(*str); 00144 return oc->js_instance(); 00145 } 00146 } 00147 00148 #ifdef OSMIUM_WITH_SHPLIB 00149 static v8::Handle<v8::Value> OutputShapefileOpen(const v8::Arguments& args) { 00150 if (args.Length() != 2) { 00151 return v8::Undefined(); 00152 } else { 00153 v8::String::Utf8Value str(args[0]); 00154 v8::String::AsciiValue type(args[1]); 00155 std::string filename(*str); 00156 Osmium::Export::Shapefile* oc; 00157 if (!strcmp(*type, "point")) { 00158 oc = new Osmium::Export::PointShapefile(filename); 00159 } else if (!strcmp(*type, "line")) { 00160 oc = new Osmium::Export::LineStringShapefile(filename); 00161 } else if (!strcmp(*type, "polygon")) { 00162 oc = new Osmium::Export::PolygonShapefile(filename); 00163 } else { 00164 throw std::runtime_error("unknown shapefile type"); 00165 } 00166 00167 return oc->js_instance(); 00168 } 00169 } 00170 #endif // OSMIUM_WITH_SHPLIB 00171 00172 Javascript(std::vector<std::string> include_files, const char* filename) : Base() { 00173 // v8::HandleScope handle_scope; 00174 v8::Handle<v8::String> init_source = v8::String::New("Osmium = { Callbacks: {}, Output: { } };"); 00175 v8::Handle<v8::Script> init_script = v8::Script::Compile(init_source); 00176 osmium_object = v8::Persistent<v8::Object>::New(init_script->Run()->ToObject()); 00177 v8::Handle<v8::Object> output_object = osmium_object->Get(v8::String::NewSymbol("Output"))->ToObject(); 00178 00179 osmium_object->Set(v8::String::NewSymbol("debug"), v8::Boolean::New(Osmium::debug())); 00180 00181 v8::Handle<v8::ObjectTemplate> output_csv_template = v8::ObjectTemplate::New(); 00182 output_csv_template->Set(v8::String::NewSymbol("open"), v8::FunctionTemplate::New(OutputCSVOpen)); 00183 output_object->Set(v8::String::NewSymbol("CSV"), output_csv_template->NewInstance()); 00184 00185 #ifdef OSMIUM_WITH_SHPLIB 00186 v8::Handle<v8::ObjectTemplate> output_shapefile_template = v8::ObjectTemplate::New(); 00187 output_shapefile_template->Set(v8::String::NewSymbol("open"), v8::FunctionTemplate::New(OutputShapefileOpen)); 00188 output_object->Set(v8::String::NewSymbol("Shapefile"), output_shapefile_template->NewInstance()); 00189 #endif // OSMIUM_WITH_SHPLIB 00190 00191 v8::Handle<v8::Object> callbacks_object = osmium_object->Get(v8::String::NewSymbol("Callbacks"))->ToObject(); 00192 00193 v8::TryCatch tryCatch; 00194 00195 for (std::vector<std::string>::const_iterator vi(include_files.begin()); vi != include_files.end(); vi++) { 00196 if (Osmium::debug()) { 00197 std::cerr << "include javascript file: " << *vi << std::endl; 00198 } 00199 std::string javascript_source = load_file((*vi).c_str()); 00200 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(javascript_source.c_str()), v8::String::New((*vi).c_str())); 00201 if (script.IsEmpty()) { 00202 std::cerr << "Compiling script failed:" << std::endl; 00203 report_exception(&tryCatch); 00204 exit(1); 00205 } 00206 00207 v8::Handle<v8::Value> result = script->Run(); 00208 if (result.IsEmpty()) { 00209 std::cerr << "Running script failed:" << std::endl; 00210 report_exception(&tryCatch); 00211 exit(1); 00212 } 00213 } 00214 00215 std::string javascript_source = load_file(filename); 00216 if (javascript_source.length() == 0) { 00217 std::cerr << "Javascript file " << filename << " is empty" << std::endl; 00218 exit(1); 00219 } 00220 00221 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(javascript_source.c_str()), v8::String::New(filename)); 00222 if (script.IsEmpty()) { 00223 std::cerr << "Compiling script failed:" << std::endl; 00224 report_exception(&tryCatch); 00225 exit(1); 00226 } 00227 00228 v8::Handle<v8::Value> result = script->Run(); 00229 if (result.IsEmpty()) { 00230 std::cerr << "Running script failed:" << std::endl; 00231 report_exception(&tryCatch); 00232 exit(1); 00233 } 00234 00235 v8::Handle<v8::Value> cc; 00236 00237 cc = callbacks_object->Get(v8::String::NewSymbol("init")); 00238 if (cc->IsFunction()) { 00239 cb.init = v8::Handle<v8::Function>::Cast(cc); 00240 } 00241 cc = callbacks_object->Get(v8::String::NewSymbol("node")); 00242 if (cc->IsFunction()) { 00243 cb.node = v8::Handle<v8::Function>::Cast(cc); 00244 } 00245 cc = callbacks_object->Get(v8::String::NewSymbol("way")); 00246 if (cc->IsFunction()) { 00247 cb.way = v8::Handle<v8::Function>::Cast(cc); 00248 } 00249 cc = callbacks_object->Get(v8::String::NewSymbol("relation")); 00250 if (cc->IsFunction()) { 00251 cb.relation = v8::Handle<v8::Function>::Cast(cc); 00252 } 00253 cc = callbacks_object->Get(v8::String::NewSymbol("area")); 00254 if (cc->IsFunction()) { 00255 cb.area = v8::Handle<v8::Function>::Cast(cc); 00256 } 00257 cc = callbacks_object->Get(v8::String::NewSymbol("end")); 00258 if (cc->IsFunction()) { 00259 cb.end = v8::Handle<v8::Function>::Cast(cc); 00260 } 00261 } 00262 00263 ~Javascript() { 00264 callbacks_object.Dispose(); 00265 } 00266 00267 void init(Osmium::OSM::Meta&) { 00268 if (!cb.init.IsEmpty()) { 00269 (void) cb.init->Call(cb.init, 0, 0); 00270 } 00271 } 00272 00273 void node(const shared_ptr<Osmium::OSM::Node const>& node) { 00274 if (!cb.node.IsEmpty()) { 00275 (void) cb.node->Call(node->get_instance(), 0, 0); 00276 } 00277 #ifdef OSMIUM_V8_FORCE_GC 00278 while (!v8::V8::IdleNotification()) { }; 00279 #endif // OSMIUM_V8_FORCE_GC 00280 } 00281 00282 void way(const shared_ptr<Osmium::OSM::Way const>& way) { 00283 if (!cb.way.IsEmpty()) { 00284 (void) cb.way->Call(way->get_instance(), 0, 0); 00285 } 00286 #ifdef OSMIUM_V8_FORCE_GC 00287 while (!v8::V8::IdleNotification()) { }; 00288 #endif // OSMIUM_V8_FORCE_GC 00289 } 00290 00291 void relation(const shared_ptr<Osmium::OSM::Relation const>& relation) { 00292 if (!cb.relation.IsEmpty()) { 00293 (void) cb.relation->Call(relation->get_instance(), 0, 0); 00294 } 00295 #ifdef OSMIUM_V8_FORCE_GC 00296 while (!v8::V8::IdleNotification()) { }; 00297 #endif // OSMIUM_V8_FORCE_GC 00298 } 00299 00300 void area(Osmium::OSM::Area* area) { 00301 if (!cb.area.IsEmpty()) { 00302 (void) cb.area->Call(area->get_instance(), 0, 0); 00303 } 00304 #ifdef OSMIUM_V8_FORCE_GC 00305 while (!v8::V8::IdleNotification()) { }; 00306 #endif // OSMIUM_V8_FORCE_GC 00307 } 00308 00309 void final() { 00310 if (!cb.end.IsEmpty()) { 00311 (void) cb.end->Call(cb.end, 0, 0); 00312 } 00313 } 00314 00315 }; // class Javascript 00316 00317 } // namespace Handler 00318 00319 } // namespace Osmium 00320 00321 #endif // OSMIUM_HANDLER_JAVASCRIPT_HPP