31 #include <system_threads.h>
34 #include <libFreeWRL.h>
36 #include "vrml_parser/Structs.h"
37 #include "input/InputFunctions.h"
38 #include "opengl/OpenGL_Utils.h"
39 #include "opengl/Textures.h"
40 #include "opengl/LoadTextures.h"
61 void *resources_constructor()
67 void resources_init(
struct tresources* t)
72 t->prv = resources_constructor();
75 void resources_clear(
struct tresources* t)
81 deleteVector(
void *,p->resStack);
92 item->media_type = resm_unknown;
93 item->type = rest_invalid;
94 item->status = ress_invalid;
96 item->actual_file = NULL;
97 item->cached_files = NULL;
118 pthread_mutex_lock( &gglobal()->threads.mutex_resource_tree );
120 if (!gglobal()->resources.root_res) {
122 gglobal()->resources.root_res = (
void*)item;
123 DEBUG_RES(
"setting root_res in resource_create_single for file %s\n",request);
126 ((
resource_item_t*)gglobal()->resources.root_res)->children = ml_append(((
resource_item_t*)gglobal()->resources.root_res)->children, ml_new(item));
131 pthread_mutex_unlock( &gglobal()->threads.mutex_resource_tree );
137 DEBUG_RES(
"creating resource: SINGLE: %s\n", request);
139 item = newResourceItem();
140 item->URLrequest = STRDUP(request);
141 item->_loadThread = NULL;
148 resource_tree_append(item);
162 DEBUG_RES(
"creating resource: MULTI: %d, %s ...\n", request->n, request->p[0]->strptr);
163 item = newResourceItem();
166 item->type = rest_multi;
170 for (i = 0; i < request->n; i++) {
171 char *url = STRDUP(request->p[i]->strptr);
173 item->m_request = ml_append(item->m_request, ml_new(url));
180 resource_tree_append(item);
192 DEBUG_RES(
"creating resource: STRING: %s\n",
string);
193 item = newResourceItem();
196 item->URLrequest = STRDUP(
string);
197 item->type = rest_string;
198 item->status = ress_loaded;
200 resource_tree_append(item);
214 bool checkNetworkFile(
const char *fn)
220 ConsoleMessage (
"checkNetworkFile, got a NULL here");
232 if ((strncmp(fn,
"ftp://", strlen(
"ftp://"))) &&
233 (strncmp(fn,
"FTP://", strlen(
"FTP://"))) &&
234 (strncmp(fn,
"http://", strlen(
"http://"))) &&
235 (strncmp(fn,
"HTTP://", strlen(
"HTTP://"))) &&
236 (strncmp(fn,
"https://", strlen(
"https://"))) &&
237 (strncmp(fn,
"HTTPS://", strlen(
"HTTPS://"))) &&
242 (strncmp(fn,
"urn://", strlen(
"urn://"))) &&
243 (strncmp(fn,
"URN://", strlen(
"URN://")))
274 static int res_id_error_once = 0;
283 DEBUG_RES(
"resource_identify, we have resource %s ptrs %p and %p\n",res->URLrequest,baseResource,baseResource);
286 DEBUG_RES(
" base specified, taking the base values.\n");
287 defaults = baseResource;
288 res->parent = baseResource;
291 DEBUG_RES(
" no base specified, taking parent's values.\n");
292 defaults = res->parent;
294 DEBUG_RES(
" no base neither parent, no default values.\n");
299 DEBUG_RES(
" default values: network=%s type=%s status=%s"
300 " URLrequest=<%s> URLbase=<%s>parsed_request=<%s> [parent %p, %s]\n",
301 BOOL_STR(defaults->network), resourceTypeToString(defaults->type),
302 resourceStatusToString(defaults->status), defaults->URLrequest,
303 defaults->URLbase, defaults->parsed_request,
304 defaults->parent, (defaults->parent ? defaults->parent->URLbase :
"N/A")
308 if (res->type == rest_multi) {
310 if (res->m_request) {
314 FREE_IF_NZ(res->URLrequest);
315 res->URLrequest = (
char *) l->elem;
317 res->m_request = res->m_request->next;
321 if(!res_id_error_once)
322 ERROR_MSG(
"resource_identify: ERROR: empty multi string as input\n");
330 network = defaults->network;
336 pound = strchr(res->URLrequest,
'#');
341 res->afterPoundCharacters = STRDUP(pound);
345 res->network = checkNetworkFile(res->URLrequest);
347 DEBUG_RES(
"resource_identify: base network / resource network: %s/%s\n",
349 BOOL_STR(res->network));
352 if (res->network || network) {
357 res->type = rest_url;
358 res->status = ress_starts_good;
359 url = STRDUP(res->URLrequest);
371 cleanedURL = stripLocalFileName(res->URLrequest);
374 IF_cleanedURL_IS_ABSOLUTE {
377 url = STRDUP(cleanedURL);
380 cwd = STRDUP(defaults->URLbase);
381 url = concat_path(cwd, cleanedURL);
385 res->type = rest_url;
386 res->status = ress_starts_good;
388 res->type = rest_invalid;
389 ERROR_MSG(
"resource_identify: can't handle relative url without base: %s\n", res->URLrequest);
395 DEBUG_RES(
"resource_identify, we may have a local file for resource %s\n", res->URLrequest);
398 len = strlen(res->URLrequest);
399 if (len > PATH_MAX) {
401 res->type = rest_invalid;
403 ERROR_MSG(
"resource_identify: path too long: %s\n", res->URLrequest);
406 char *cleanedURL = NULL;
410 cleanedURL = stripLocalFileName(res->URLrequest);
415 IF_cleanedURL_IS_ABSOLUTE {
418 res->type = rest_file;
419 res->status = ress_starts_good;
420 url = STRDUP(cleanedURL);
423 cwd = STRDUP(defaults->URLbase);
424 res->type = rest_file;
425 res->status = ress_starts_good;
426 url = concat_path(cwd, cleanedURL);
433 IF_cleanedURL_IS_ABSOLUTE {
436 res->type = rest_file;
437 res->status = ress_starts_good;
438 url = STRDUP(cleanedURL);
444 cwd = get_current_dir();
445 removeFilenameFromPath(cwd);
450 url = concat_path(cwd, res->URLrequest);
451 res->type = rest_file;
452 res->status = ress_starts_good;
459 FREE_IF_NZ(res->parsed_request);
460 res->parsed_request = url;
461 FREE_IF_NZ(res->URLbase);
462 res->URLbase = STRDUP(url);
463 removeFilenameFromPath(res->URLbase);
467 DEBUG_RES(
"resource_identify (end): network=%s type=%s status=%s"
468 " request=<%s> base=<%s> url=<%s> [parent %p, %s]\n",
469 BOOL_STR(res->network), resourceTypeToString(res->type),
470 resourceStatusToString(res->status), res->URLrequest,
471 res->URLbase, res->parsed_request,
472 res->parent, (res->parent ? res->parent->URLbase :
"N/A"));
480 textureNumber = res->textureNumber;
481 if(res->status == ress_downloaded){
482 entry = getTableIndex(textureNumber);
484 if (texture_load_from_file(entry, res->actual_file)) {
485 entry->status = TEX_READ;
486 res->status = ress_loaded;
491 res->status = ress_not_loaded;
504 DEBUG_RES(
"loading resource: %s, %s\n", resourceTypeToString(res->type), resourceStatusToString(res->status));
508 switch (res->status) {
510 case ress_starts_good:
513 ERROR_MSG(
"resource_load: can't load not available resource: %s\n", res->URLrequest);
518 case ress_downloaded:
520 of = load_file(res->actual_file);
523 res->status = ress_loaded;
525 res->openned_files = of;
528 if (res->media_type == resm_unknown) {
529 resource_identify_type(res);
534 res->status = ress_not_loaded;
535 ERROR_MSG(
"resource_load: can't load file: %s\n", res->actual_file);
541 ERROR_MSG(
"resource_load: MISTAKE: can't load already loaded resource: %s\n", res->URLrequest);
544 case ress_not_loaded:
545 ERROR_MSG(
"resource_load: loader already failed for this resource: %s\n", res->URLrequest);
549 ERROR_MSG(
"resource_load: MISTAKE: can't load resource already parsed: %s\n", res->URLrequest);
552 case ress_not_parsed:
553 ERROR_MSG(
"resource_load: MISTAKE: can't load resource already parsed (and failed): %s\n", res->URLrequest);
565 char *test_it = NULL;
572 if (res->media_type != resm_unknown)
576 switch (res->status) {
580 ERROR_MSG(
"can't identify type for invalid resource: %s\n", res->URLrequest);
584 test_it = (
char*)res->URLrequest;
585 ConsoleMessage (
"test_it is :%s:",test_it);
586 test_it_len = (int)strlen(res->URLrequest);
598 of = res->openned_files;
605 char *sourcename = (
char *)of->fileFileName;
606 if(res->type == rest_url) sourcename = res->URLrequest;
607 if(!strcmp(&sourcename[strlen(sourcename)-4],
".x3z")){
608 res->media_type = resm_x3z;
614 test_it = of->fileData;
615 test_it_len = of->fileDataSize;
621 t = determineFileType(test_it,test_it_len);
626 #if defined (INCLUDE_STL_FILES)
627 case IS_TYPE_BINARY_STL:
case IS_TYPE_ASCII_STL:
628 #endif //INCLUDE_STL_FILES
631 res->media_type = resm_vrml;
634 #if defined (INCLUDE_NON_WEB3D_FORMATS)
635 case IS_TYPE_COLLADA:
637 case IS_TYPE_SKETCHUP:
638 #endif //INCLUDE_NON_WEB3D_FORMATS
640 case IS_TYPE_XML_X3D:
641 res->media_type = resm_x3d;
655 void remove_file_or_folder(
const char *path);
657 void resource_remove_cached_file(
s_list_t *cfe)
659 const char *cached_file;
660 cached_file = (
const char *) cfe->elem;
663 remove_file_or_folder(cached_file);
672 void _resourceFreeCallback(
void *resource);
679 DEBUG_RES(
"destroying resource: %d, %d\n", res->type, res->status);
688 switch (res->status) {
690 case ress_starts_good:
695 case ress_downloaded:
698 case ress_not_loaded:
700 case ress_not_parsed:
711 cf = (
s_list_t *) res->cached_files;
716 ml_foreach(cf, resource_remove_cached_file(__l));
720 FREE_IF_NZ(res->actual_file);
725 FREE_IF_NZ(res->parsed_request);
729 switch (res->status) {
731 case ress_starts_good:
736 case ress_downloaded:
739 case ress_not_loaded:
741 case ress_not_parsed:
749 FREE(res->actual_file);
754 FREE_IF_NZ(res->parsed_request);
767 ml_delete_all2(res->m_request, (void (*)(
void *))ml_free);
768 res->m_request = NULL;
770 FREE_IF_NZ(res->URLbase);
771 FREE_IF_NZ(res->afterPoundCharacters);
772 FREE_IF_NZ(res->openned_files);
781 FREE_IF_NZ(res->URLrequest);
790 DEBUG_RES(
"destroying resource: %d, %d\n", res->type, res->status);
795 cf = (
s_list_t *) res->cached_files;
800 ml_foreach(cf, resource_remove_cached_file(__l));
809 DEBUG_RES(
"closing resource file: %d, %d\n", res->type, res->status);
829 cf = ml_find_elem(parent->children, child);
832 ml_delete(parent->children, cf);
839 void destroy_root_res()
842 gglobal()->resources.root_res = NULL;
845 void resource_tree_destroy()
850 ml_foreach(root->children,resource_close_files((
resource_item_t*)ml_elem(__l)));
851 ml_foreach(root->children,resource_unlink_cachedfiles((
resource_item_t*)ml_elem(__l)));
852 ml_foreach(root->children,resource_destroy((
resource_item_t*)ml_elem(__l)));
853 ml_foreach(root->children,resource_remove_child(root,(
resource_item_t*)ml_elem(__l)));
854 ml_foreach(root->children,ml_free(__l));
855 resource_close_files(root);
856 resource_unlink_cachedfiles(root);
871 PRINTF (
"resource_dump: %p\n"
873 "parsed request: %s\n"
876 res, res->URLrequest, res->parsed_request, res->actual_file);
878 cf = (
s_list_t *) res->cached_files;
880 ml_foreach(cf, PRINTF(
"%s ", (
char *) ml_elem(__l)));
884 PRINTF(
"\nopenned files: ");
887 ofv = res->openned_files;
890 PRINTF(
"%s ", of->fileFileName);
896 void splitpath_local_suffix(
const char *url,
char **local_name,
char **suff);
900 void fwl_resource_push_single_request(
const char *request)
907 res = resource_create_single(request);
909 resitem_enqueue(ml_new(res));
915 char* local_name = NULL;
916 splitpath_local_suffix(request, &local_name, &suff);
917 tg->Mainloop.scene_name = local_name;
918 tg->Mainloop.scene_suff = suff;
926 void resource_push_multi_request(
struct Multi_String *request)
933 res = resource_create_multi(request);
934 resitem_enqueue(ml_new(res));
945 #define spacer for (lc=0; lc<level; lc++) printf ("\t");
950 if (root == NULL)
return;
951 if (level == 0) printf(
"\nResource tree:\n\n");
954 spacer printf(
"==> request:\t %s\n\n", root->URLrequest);
955 spacer printf(
"this:\t %p\n", root);
956 spacer printf(
"parent:\t %p\n", root->parent);
957 spacer printf(
"network:\t %s\n", BOOL_STR(root->network));
958 spacer printf(
"new_root:\t %s\n", BOOL_STR(root->new_root));
959 spacer printf(
"type:\t %u\n", root->type);
960 spacer printf(
"status:\t %u\n", root->status);
961 spacer printf(
"complete:\t %s\n", BOOL_STR(root->complete));
962 spacer printf(
"where:\t %p\n", root->whereToPlaceData);
963 spacer printf(
"offsetFromWhere:\t %d\n", root->offsetFromWhereToPlaceData);
964 spacer printf(
"m_request:\t %p\n", root->m_request);
965 spacer printf(
"base:\t %s\n", root->URLbase);
966 spacer printf(
"temp_dir:\t %s\n", root->temp_dir);
967 spacer printf(
"parsed_request:\t %s\n", root->parsed_request);
968 spacer printf(
"actual_file:\t %s\n", root->actual_file);
969 spacer printf(
"cached_files:\t %p\n", root->cached_files);
975 spacer printf(
"four_first_bytes:\t %c %c %c %c\n", root->four_first_bytes[0], root->four_first_bytes[1], root->four_first_bytes[2], root->four_first_bytes[3]);
976 spacer printf(
"media_type:\t %u\n", root->media_type);
978 children = root->children;
980 ml_foreach(children, resource_tree_dump(level + 1, ml_elem(__l)));
987 if (root == NULL)
return;
989 ml_foreach(root->children, resource_tree_count_files(count, ml_elem(__l)));
991 void printStatsResources()
994 resource_tree_count_files(&count, gglobal()->resources.root_res);
995 ConsoleMessage(
"%25s %d\n",
"resource file count", count);
1004 #define spacer for (lc=0; lc<level; lc++) printf ("\t");
1007 if (root == NULL)
return;
1008 if (level == 0) printf(
"\nResource file list:\n");
1010 spacer printf(
"%s\n", root->actual_file);
1011 ml_foreach(root->children, resource_tree_list_files(-1, ml_elem(__l)));
1014 char *resourceTypeToString(
int type) {
1016 case rest_invalid:
return "rest_invalid";
1017 case rest_url:
return "rest_url";
1018 case rest_file:
return "rest_file";
1019 case rest_multi:
return "rest_multi";
1020 case rest_string :
return "rest_string ";
1021 default:
return "resource OUT OF RANGE";
1026 char *resourceStatusToString(
int status) {
1028 case ress_none:
return "ress_none";
1029 case ress_starts_good:
return "ress_starts_good";
1030 case ress_invalid:
return "ress_invalid";
1031 case ress_downloaded:
return "ress_downloaded";
1032 case ress_failed:
return "ress_failed";
1033 case ress_loaded:
return "ress_loaded";
1034 case ress_not_loaded:
return "ress_not_loaded";
1035 case ress_parsed:
return "ress_parsed";
1036 case ress_not_parsed:
return "ress_not_parsed";
1037 default:
return "resource OUT OF RANGE";
1041 char *resourceMediaTypeToString (
int mt) {
1043 case resm_unknown:
return " resm_unknown";
1044 case resm_vrml:
return " resm_vrml";
1045 case resm_x3d:
return " resm_x3d";
1046 case resm_image:
return " resm_image";
1047 case resm_movie:
return " resm_movie";
1048 case resm_pshader:
return " resm_pshader";
1049 case resm_fshader:
return " resm_fshader";
1050 case resm_x3z:
return " resm_x3z";
1051 default:
return "resource OUT OF RANGE";
1057 #define SLASHDOTDOTSLASH "/../"
1058 #if defined(_MSC_VER) || defined(_ANDROID) || defined(ANDROIDNDK)
1059 #define rindex strrchr
1061 void removeFilenameFromPath (
char *path) {
1063 char *slashDotDotSlash;
1066 slashindex = (
char *) rindex(path, ((
int)
'/'));
1067 if (slashindex != NULL) {
1070 }
else {path[0] = 0;}
1074 slashDotDotSlash = strstr(path, SLASHDOTDOTSLASH);
1075 while (slashDotDotSlash != NULL) {
1079 *slashDotDotSlash =
'\0';
1082 slashindex = (
char *)rindex(path, ((
int)
'/'));
1083 if (slashindex != NULL) {
1087 slashDotDotSlash += strlen(SLASHDOTDOTSLASH);
1088 strcpy(tmpline,path);
1090 strcat (tmpline, slashDotDotSlash);
1092 strcpy (path, tmpline);
1093 slashDotDotSlash = strstr(path, SLASHDOTDOTSLASH);
1104 #if !(defined(IPHONE) || defined(_ANDROID))
1105 if (of->fileData == NULL)
return;
1106 if (of->fileData[0] ==
'\0')
return;
1107 if (of->fileData[1] ==
'\0')
return;
1108 if (((
unsigned char) of->fileData[0] == 0x1f) && ((
unsigned char) of->fileData[1] == 0x8b)) {
1109 #define GZIP_BUFF_SIZE 2048
1113 char buffer[GZIP_BUFF_SIZE];
1121 tempname = tempnam(gglobal()->Mainloop.tmpFileLocation,
"freewrl_tmp");
1124 source = gzopen(of->fileFileName,
"rb");
1125 dest = fopen(tempname,
"wb");
1127 if (!source || !source) {
1128 ConsoleMessage (
"unable to unzip this file: %s\n",of->fileFileName);
1129 printf (
"wow - problem\n");
1132 while ((num_read = gzread(source, buffer, GZIP_BUFF_SIZE)) > 0) {
1133 fwrite(buffer, 1, num_read, dest);
1140 newFile = load_file((
const char *) tempname);
1143 if (newFile->fileData == NULL) {
1144 ConsoleMessage (
"problem re-reading gunzipped text file");
1149 FREE_IF_NZ(of->fileData);
1150 of->fileData = newFile->fileData;
1153 FREE_IF_NZ(newFile);
1159 bool resource_is_root_loaded()
1161 return ((gglobal()->resources.root_res != NULL) && (((
resource_item_t*)gglobal()->resources.root_res)->status == ress_parsed));
1176 DEBUG_MSG(
"pushInputResource current Resource is %s", url->parsed_request);
1181 if (p->resStack==NULL) {
1194 DEBUG_MSG(
"pushInputResource, after push, stack size %d",vectorSize(p->resStack));
1197 void popInputResource() {
1202 DEBUG_MSG(
"popInputResource, stack size %d",vectorSize(p->resStack));
1209 if (stack_empty(p->resStack)) {
1210 DEBUG_MSG (
"popInputResource, stack now empty and we have saved the last resource\n");
1211 p->lastBaseResource = cwu;
1214 DEBUG_MSG(
"popInputResource, cwu = %p",cwu);
1215 DEBUG_MSG(
"popInputResource before pop, current Resource is %s\n", cwu->parsed_request);
1225 DEBUG_MSG(
"getInputResource \n");
1226 if (p->resStack==NULL) {
1227 DEBUG_MSG(
"getInputResource, stack NULL\n");
1232 if (stack_empty(p->resStack)) {
1233 if (p->lastBaseResource == NULL) {
1234 ConsoleMessage (
"stacking error - looking for input resource, but it is null");
1236 DEBUG_MSG(
"so, returning %s\n",p->lastBaseResource->parsed_request);
1238 return p->lastBaseResource;
1243 DEBUG_MSG(
"getInputResource current Resource is %lu %lx %s\n", (
unsigned long int) cwu, (
unsigned long int) cwu, cwu->parsed_request);
1248 char* fwl_resitem_getURL(
void *resp){
1250 return res->parsed_request;
1252 void fwl_resitem_setActualFile(
void *resp,
char *fname){
1254 res->actual_file = STRDUP(fname);
1255 if(strcmp(res->actual_file,res->parsed_request)){
1258 item = ml_new(res->actual_file);
1259 if (!res->cached_files)
1260 res->cached_files = (
void *)item;
1262 res->cached_files = ml_append(res->cached_files,item);
1265 char* fwl_resitem_getTempDir(
void *resp){
1267 return res->temp_dir;
1269 void fwl_resitem_enqueuNextMulti(
void *resp){
1271 int more_multi = (res->status == ress_failed) && (res->m_request != NULL);
1274 res->status = ress_invalid;
1275 res->type = rest_multi;
1278 resource_identify(res->parent, res);
1279 frontenditem_enqueue(ml_new(res));
1282 char *strBackslash2fore(
char *);
1284 void fwl_resitem_setLocalPath(
void *resp,
char* path){
1285 int delete_after_load;
1287 res->status = ress_downloaded;
1288 res->actual_file = strBackslash2fore(STRDUP(path));
1289 delete_after_load = 1;
1290 if (delete_after_load){
1294 item = ml_new(res->actual_file);
1295 if (!res->cached_files)
1296 res->cached_files = (
void *)item;
1298 res->cached_files = ml_append(res->cached_files, item);
1300 res->_loadFunc = (
void *)file2blob;
1302 int fwl_resitem_getStatus(
void *resp){
1306 void fwl_resitem_setStatus(
void *resp,
int status) {
1308 res->status = status;
1311 int fwl_resitem_getType(
void *resp){
1315 int fwl_resitem_getMediaType(
void *resp){
1317 return res->media_type;
1319 void fwl_resitem_setDownloadThread(
void *resp,
void *thread){
1321 res->_loadThread = (pthread_t*)thread;
1323 void * fwl_resitem_getDownloadThread(
void *resp){
1325 return res->_loadThread;
1327 void * fwl_resitem_getGlobal(
void *resp){