FreeWRL/FreeX3D  3.0.0
io_files.c
1 //[s release];
2 /*
3 
4  FreeWRL support library.
5  IO with files.
6 
7 */
8 
9 /****************************************************************************
10  This file is part of the FreeWRL/FreeX3D Distribution.
11 
12  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13 
14  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15  it under the terms of the GNU Lesser Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  GNU General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26 ****************************************************************************/
27 
28 #include <config.h>
29 
30 #include <system.h>
31 #include <display.h>
32 #include <internal.h>
33 #include <libFreeWRL.h>
34 #include <resources.h>
35 
36 #include <list.h> /* internal use only */
37 #include <io_files.h>
38 #include <io_http.h>
39 
40 #include <sys/stat.h>
41 
42 #include <threads.h> /* for freewrlSystem */
43 
44 #if HAVE_DIRENT_H
45 # include <dirent.h>
46 #endif
47 
48 #ifndef _MSC_VER
49 #include <sys/mman.h> /* mmap */
50 #else
51 #include <direct.h> //for getcwd
52 #define getcwd _getcwd
53 #define mkdir _mkdir
54 #endif
55 #include <limits.h> /* SSIZE_MAX */
56 
57 #include "main/ProdCon.h"
58 #if !defined(IPHONE) && !defined(_ANDROID)
59 #include "input/InputFunctions.h"
60 #include "plugin/pluginUtils.h"
61 #include "plugin/PluginSocket.h"
62 #endif
63 #include <stdio.h>
64 #include <fcntl.h>
65 #if defined (INCLUDE_STL_FILES)
66 #include "input/convertSTL.h"
67 #endif //INCLUDE_STL_FILES
68 
69 #define UNUSED(v) ((void) v)
70 
71 /* Internal function prototypes */
72 void append_openned_file(s_list_t *list, const char *filename, int fd, char *text);
73 
74 int inputFileType = IS_TYPE_UNKNOWN;
75 int inputFileVersion[3] = {0,0,0};
76 
77 
78 int fw_mkdir(const char* path){
79 #ifdef _MSC_VER
80  return mkdir(path);
81 #else
82  return mkdir(path,0755);
83 #endif
84 }
85 
89 char* concat_path(const char *a, const char *b)
90 {
91  size_t la, lb;
92  char *tmp;
93 
94  if (!a) {
95  if (!b) return NULL;
96  /* returns "/b" */
97  lb = strlen(b);
98  tmp = MALLOC(char *, 2+lb); /* why 2? room for the slash and the trailing NULL */
99  sprintf(tmp, "/%s", b);
100  return tmp;
101  } else {
102  if (!b) {
103  /* returns "a/" */
104  la = strlen(a);
105  tmp = MALLOC(char *, la+2); /* why 2? room for the slash and the trailing NULL */
106  sprintf(tmp, "%s/", a);
107  return tmp;
108  }
109  }
110 
111  la = strlen(a);
112  lb = strlen(b);
113 
114  if (a[la-1] == '/') {
115  tmp = MALLOC(char *, la + lb + 1); /* why 1? room for the trailing NULL */
116  sprintf(tmp, "%s%s", a, b);
117  } else {
118  tmp = MALLOC(char *, la + lb + 2); /* why 2? room for the slash and the trailing NULL */
119  sprintf(tmp, "%s/%s", a, b);
120  }
121 
122  return tmp;
123 }
124 
128 char* remove_filename_from_path(const char *path)
129 {
130  char *rv = NULL;
131  char *slash;
132 
133  slash = strrchr(path, '/');
134  if (slash) {
135 #ifdef DEBUG_MALLOC
136 printf ("remove_filename_from_path going to copy %d\n", ((int)slash-(int)path)+1);
137  rv = strndup(path, ((int)slash-(int)path)+1);
138  rv = STRDUP(path);
139  slash = strrchr(rv,'/');
140  *slash = '\0';
141 printf ("remove_filename_from_path, returning :%s:\n",rv);
142 #else
143  rv = STRNDUP(path, (size_t)slash - (size_t)path + 1);
144 #endif
145 
146  }
147  return rv;
148 }
149 char *strBackslash2fore(char *str)
150 {
151 #ifdef _MSC_VER
152  int jj;
153  for( jj=0;jj<(int)strlen(str);jj++)
154  if(str[jj] == '\\' ) str[jj] = '/';
155 #endif
156  return str;
157 }
158 
159 char *get_current_dir()
160 {
161  char *cwd , *retvar;
162  cwd = MALLOC(char *, PATH_MAX);
163  retvar = getcwd(cwd, PATH_MAX);
164  if (NULL != retvar) {
165  size_t ll;
166  ll = strlen(cwd);
167  cwd = strBackslash2fore(cwd);
168  cwd[ll] = '/'; /* put / ending to match posix version which puts local file name on end*/
169  cwd[ll+1] = '\0';
170  } else {
171  printf("Unable to establish current working directory in %s,%d errno=%d",__FILE__,__LINE__,errno) ;
172  FREE_IF_NZ(cwd);
173  cwd = STRDUP("./"); // "/tmp/";
174  }
175  return cwd;
176 }
177 
178 /*
179  NOTES: temp dir
180 
181  tmp_dir=/tmp/freewrl-YYYY-MM-DD-$PID/<main_world>/ must then
182  add <relative path> at the end.
183 
184  input request: url "tex.jpg" => $tmp_dir/tex.jpg
185  url "images/tex.jpg" => create images subdir, => $tmp_dir/images/tex.jpg
186 */
187 
188 
192 bool do_file_exists(const char *filename)
193 {
194  struct stat ss;
195  if (stat(filename, &ss) == 0) {
196  return TRUE;
197  }
198  return FALSE;
199 }
200 
204 bool do_file_readable(const char *filename)
205 {
206  if (access(filename, R_OK) == 0) {
207  return TRUE;
208  }
209  return FALSE;
210 }
211 
212 
216 bool do_dir_exists(const char *dir)
217 {
218  struct stat ss;
219 
220 #if defined(_MSC_VER)
221  /* TODO: Remove any trailing backslash from *dir */
222 #endif
223 
224  if (stat(dir, &ss) == 0) {
225  if (access(dir,X_OK) == 0) {
226  return TRUE;
227  } else {
228  WARN_MSG("directory '%s' exists but is not accessible\n", dir);
229  }
230  }
231  return FALSE;
232 }
233 
234 
238 void of_dump(openned_file_t *of)
239 {
240  static char first_ten[11];
241  if (of->fileData) {
242  int len = of->fileDataSize;
243  if (len>10)len=10;
244  memcpy(first_ten, of->fileData, len);
245  }
246  printf("{%s, %d, %d, %s%s}\n", of->fileFileName, of->fileDescriptor, of->fileDataSize, (of->fileData ? first_ten : "(null)"), (of->fileData ? "..." : ""));
247 }
248 
254 static openned_file_t* create_openned_file(const char *filename, int fd, int dataSize, char *data, int imageHeight, int imageWidth, bool imageAlpha)
255 {
256  openned_file_t *of;
257 #ifdef DISABLER
258  char *fileData = NULL;
259  if (dataSize > 0 && data)
260  {
261  fileData = MALLOC (char *, dataSize+1);
262  if (NULL != fileData)
263  {
264  memcpy (fileData, data, dataSize);
265  fileData[dataSize] = '\0';
266  data = fileData;
267  }
268  }
269 #endif
270  of = XALLOC(openned_file_t);
271  of->fileFileName = filename;
272  of->fileDescriptor = fd;
273  of->fileData = data; // XXXX FREE_IF_NZ this after use.
274  of->fileDataSize = dataSize;
275  of->imageHeight = imageHeight;
276  of->imageWidth = imageWidth;
277  of->imageAlpha = imageAlpha;
278  //printf ("create_openned_file, datasize %d file %s\n",dataSize,filename);
279  //if (dataSize <4000) printf ("create_openned_file, stringlen of data %ld\n",strlen(data));
280  return of;
281 }
282 
283 
284 
288 #if defined(FW_USE_MMAP)
289 static void* load_file_mmap(const char *filename)
290 {
291  struct stat ss;
292  char *text;
293  int fd;
294 
295  if (stat(filename, &ss) < 0) {
296  PERROR_MSG("load_file_mmap: could not stat: %s\n", filename);
297  return NULL;
298  }
299  fd = open(filename, O_RDONLY | O_NONBLOCK);
300  if (fd < 0) {
301  PERROR_MSG("load_file_mmap: could not open: %s\n", filename);
302  return NULL;
303  }
304  if (!ss.st_size) {
305  ERROR_MSG("load_file_mmap: file is empty %s\n", filename);
306  close(fd);
307  return NULL;
308  }
309  text = mmap(NULL, ss.st_size, PROT_READ, MAP_SHARED, fd, 0);
310  if ((text == MAP_FAILED) || (!text)) {
311  PERROR_MSG("load_file_mmap: could not mmap: %s\n", filename);
312  close(fd);
313  return NULL;
314  }
315  return create_openned_file(filename, fd, text,0,0,FALSE);
316 }
317 #endif
318 
319 
323  int load_file_blob(const char *filename, char **blob, int *len){
324  struct stat ss;
325  int fd;
326  char *text, *current;
327  int left2read; //need signed int for math below
328 #ifdef _MSC_VER
329  size_t blocksz, readsz; //, left2read;
330 #else
331  ssize_t blocksz, readsz; //, left2read;
332 #endif
333 
334  if (stat(filename, &ss) < 0) {
335  PERROR_MSG("load_file_read: could not stat: %s\n", filename);
336  return 0;
337  }
338 #ifdef _MSC_VER
339  fd = open(filename, O_RDONLY | O_BINARY);
340 #else
341  fd = open(filename, O_RDONLY | O_NONBLOCK);
342 #endif
343  if (fd < 0) {
344  PERROR_MSG("load_file_read: could not open: %s\n", filename);
345  return 0;
346  }
347  if (!ss.st_size) {
348  ERROR_MSG("load_file_read: file is empty %s\n", filename);
349  close(fd);
350  return 0;
351  }
352 
353  text = current = MALLOC(char *, ss.st_size +1); /* include space for a null terminating character */
354  if (!text) {
355  ERROR_MSG("load_file_read: cannot allocate memory to read file %s\n", filename);
356  close(fd);
357  return 0;
358  }
359 
360  if (ss.st_size > SSIZE_MAX) {
361  /* file is greater that read's max block size: we must make a loop */
362  blocksz = SSIZE_MAX;
363  } else {
364  blocksz = ss.st_size+1;
365  }
366 
367  left2read = ss.st_size; //+1;
368  readsz = 0;
369 
370  while (left2read > 0) {
371  readsz = read(fd, current, blocksz);
372  if (readsz > 0) {
373  /* ok, we have read a block, continue */
374  current += blocksz;
375  left2read -= blocksz;
376  } else {
377  /* is this the end of the file ? */
378  if (readsz == 0) {
379  /* yes */
380  break;
381  } else {
382  /* error */
383  PERROR_MSG("load_file_read: error reading file %s\n", filename);
384  /* cleanup */
385  FREE(text);
386  close(fd);
387  return 0;
388  }
389  }
390  }
391  /* null terminate this string */
392  text[ss.st_size] = '\0';
393  close(fd);
394  fd = 0; //NULL;
395  *blob = text;
396  *len = ss.st_size+1;
397  return 1;
398 }
399 static openned_file_t* load_file_read(const char *filename)
400 {
401  char *blob;
402  int len;
403  openned_file_t *retval = NULL;
404  if( load_file_blob(filename, &blob, &len))
405  {
406  retval = create_openned_file(filename, 0, len, blob,0,0,FALSE);
407  }
408  return retval;
409 }
410 #ifdef OLDCODE
411 OLDCODEstatic openned_file_t* load_file_read_old(const char *filename)
412 OLDCODE{
413 OLDCODE struct stat ss;
414 OLDCODE int fd;
415 OLDCODE unsigned char *text, *current;
416 OLDCODE int left2read; //need signed int for math below
417 OLDCODE#ifdef _MSC_VER
418 OLDCODE size_t blocksz, readsz; //, left2read;
419 OLDCODE#else
420 OLDCODE ssize_t blocksz, readsz; //, left2read;
421 OLDCODE#endif
422 OLDCODE
423 OLDCODE if (stat(filename, &ss) < 0) {
424 OLDCODE PERROR_MSG("load_file_read: could not stat: %s\n", filename);
425 OLDCODE return NULL;
426 OLDCODE }
427 OLDCODE#ifdef _MSC_VER
428 OLDCODE fd = open(filename, O_RDONLY | O_BINARY);
429 OLDCODE#else
430 OLDCODE fd = open(filename, O_RDONLY | O_NONBLOCK);
431 OLDCODE#endif
432 OLDCODE if (fd < 0) {
433 OLDCODE PERROR_MSG("load_file_read: could not open: %s\n", filename);
434 OLDCODE return NULL;
435 OLDCODE }
436 OLDCODE if (!ss.st_size) {
437 OLDCODE ERROR_MSG("load_file_read: file is empty %s\n", filename);
438 OLDCODE close(fd);
439 OLDCODE return NULL;
440 OLDCODE }
441 OLDCODE
442 OLDCODE text = current = MALLOC(unsigned char *, ss.st_size +1); /* include space for a null terminating character */
443 OLDCODE if (!text) {
444 OLDCODE ERROR_MSG("load_file_read: cannot allocate memory to read file %s\n", filename);
445 OLDCODE close(fd);
446 OLDCODE return NULL;
447 OLDCODE }
448 OLDCODE
449 OLDCODE if (ss.st_size > SSIZE_MAX) {
450 OLDCODE /* file is greater that read's max block size: we must make a loop */
451 OLDCODE blocksz = SSIZE_MAX;
452 OLDCODE } else {
453 OLDCODE blocksz = ss.st_size+1;
454 OLDCODE }
455 OLDCODE
456 OLDCODE left2read = ss.st_size; //+1;
457 OLDCODE readsz = 0;
458 OLDCODE
459 OLDCODE while (left2read > 0) {
460 OLDCODE readsz = read(fd, current, blocksz);
461 OLDCODE if (readsz > 0) {
462 OLDCODE /* ok, we have read a block, continue */
463 OLDCODE current += blocksz;
464 OLDCODE left2read -= blocksz;
465 OLDCODE } else {
466 OLDCODE /* is this the end of the file ? */
467 OLDCODE if (readsz == 0) {
468 OLDCODE /* yes */
469 OLDCODE break;
470 OLDCODE } else {
471 OLDCODE /* error */
472 OLDCODE PERROR_MSG("load_file_read: error reading file %s\n", filename);
473 OLDCODE /* cleanup */
474 OLDCODE FREE(text);
475 OLDCODE close(fd);
476 OLDCODE return NULL;
477 OLDCODE }
478 OLDCODE }
479 OLDCODE }
480 OLDCODE /* null terminate this string */
481 OLDCODE text[ss.st_size] = '\0';
482 OLDCODE close(fd);
483 OLDCODE fd = 0; //NULL;
484 OLDCODE return create_openned_file(filename, fd, ss.st_size+1, text,0,0,FALSE);
485 OLDCODE}
486 #endif //OLDCODE
487 
488 
489 
490 
491 char *fwg_frontEndWantsFileName() {return NULL;}
492 void fwg_frontEndReturningData(char* fileData,int length,int width,int height,bool hasAlpha) {}
493 
494 
498 openned_file_t* load_file(const char *filename)
499 {
500  openned_file_t *of;
501  if (NULL == filename) {
502  return NULL;
503  }
504 
505  of = NULL;
506 
507 
508 
509 
510 
511  DEBUG_RES("loading file: %s pthread %p\n", filename,pthread_self());
512  //printf ("load_file, fileToGet %s, load_file %s thread %ld\n",fileToGet,filename,pthread_self());
513 
514 
515 #if defined(FW_USE_MMAP)
516 #if !defined(_MSC_VER)
517  /* UNIX mmap */
518  of = load_file_mmap(filename);
519 #else
520  /* Windows CreateFileMapping / MapViewOfFile */
521  of = load_file_win32_mmap(filename);
522 #endif
523 #else
524  /* Standard read */
525  of = load_file_read(filename);
526 #endif
527  DEBUG_RES("%s loading status: %s\n", filename, BOOL_STR((of!=NULL)));
528  return of;
529 
530 }
531 
532 
536 int determineFileType(const char *buffer, const int len)
537 {
538  const char *rv;
539  int count;
540  int foundStart = FALSE;
541 
542  for (count = 0; count < 3; count ++) inputFileVersion[count] = 0;
543 
544  /* is this an XML file? see also further down for < detection*/
545  if (strncmp((const char*)buffer,"<?xml version",12) == 0){
546  rv = buffer;
547 
548  /* skip past the header; we will look for lines like:
549  <?xml version="1.0" encoding="UTF-8"?>
550  <!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "http://www.web3d.org/specifications/x3d-3.0.dtd">
551  <X3D
552  */
553  rv++;
554  while (!foundStart) {
555  while ((*rv != '<') && (*rv != '\0')) rv++;
556  if (*rv == '<') {
557  rv++;
558  if (*rv != '!') foundStart = TRUE;
559  } else if (*rv == '\0') foundStart = TRUE;
560  }
561  if (strncmp((const char*)rv,"X3D",3) == 0) {
562  /* the full version number will be found by the parser */
563  inputFileVersion[0] = 3;
564  return IS_TYPE_XML_X3D;
565  }
566 
567 #if defined (INCLUDE_NON_WEB3D_FORMATS)
568  if (strncmp((const char*)rv,"COLLADA",7) == 0) {
569  return IS_TYPE_COLLADA;
570  }
571  if (strncmp((const char*)rv,"kml",3) == 0) {
572  return IS_TYPE_KML;
573  }
574 #endif //INCLUDE_NON_WEB3D_FORMATS
575 
576  } else {
577  if (strncmp((const char*)buffer,"#VRML V2.0 utf8",15) == 0) {
578  inputFileVersion[0] = 2;
579  return IS_TYPE_VRML;
580  }
581 
582  if (strncmp ((const char*)buffer, "#X3D",4) == 0) {
583  inputFileVersion[0] = 3;
584  /* ok, have X3D here, what version? */
585 
586  if (strncmp ((const char*)buffer,"#X3D V3.0 utf8",14) == 0) {
587  return IS_TYPE_VRML;
588  }
589  if (strncmp ((const char*)buffer,"#X3D V3.1 utf8",14) == 0) {
590  inputFileVersion[1] = 1;
591  return IS_TYPE_VRML;
592  }
593  if (strncmp ((const char*)buffer,"#X3D V3.2 utf8",14) == 0) {
594  inputFileVersion[1] = 2;
595  return IS_TYPE_VRML;
596  }
597  if (strncmp ((const char*)buffer,"#X3D V3.3 utf8",14) == 0) {
598  inputFileVersion[1] = 3;
599  return IS_TYPE_VRML;
600  }
601  if (strncmp ((const char*)buffer,"#X3D V3.4 utf8",14) == 0) {
602  inputFileVersion[1] = 4;
603  return IS_TYPE_VRML;
604  }
605  /* if we fall off the end, we just assume X3D 3.0 */
606  }
607 
608  /* VRML V1? */
609  if (strncmp((const char*)buffer,"#VRML V1.0 asc",10) == 0) {
610  return IS_TYPE_VRML1;
611  }
612 
613 
614  }
615  /* try simple x3d ie when its a partial string from createX3DfromString */
616  rv = buffer;
617  while(rv && *rv != '\0'){
618  if(*rv == '<') return IS_TYPE_XML_X3D;
619  if (*rv == '{') return IS_TYPE_VRML;
620  rv++;
621  }
622 
623  #if defined (INCLUDE_STL_FILES)
624  return stlDTFT(buffer,len);
625  #endif //INCLUDE_STL_FILES
626 
627  return IS_TYPE_UNKNOWN;
628 }
629 
630 /*
631  * FIXME: what are the possible return codes for this function ???
632  *
633  * FIXME: refactor this function, too :)
634  *
635  */
636 #if !defined( _MSC_VER) && !defined(_ANDROID) && !defined(ANDROIDNDK) && !defined(IOS)
637 int freewrlSystem (const char *sysline)
638 {
639 
640 //#ifdef _MSC_VER
641 // return system(sysline);
642 //#else
643 #define MAXEXECPARAMS 10
644 #define EXECBUFSIZE 2000
645  char *paramline[MAXEXECPARAMS];
646  char buf[EXECBUFSIZE];
647  char *internbuf;
648  int count;
649  /* pid_t childProcess[lastchildProcess]; */
650  pid_t child;
651  int pidStatus;
652  int waitForChild;
653  int haveXmessage;
654 
655 
656  /* initialize the paramline... */
657  memset(paramline, 0, sizeof(paramline));
658 
659  waitForChild = TRUE;
660  haveXmessage = !strncmp(sysline, FREEWRL_MESSAGE_WRAPPER, strlen(FREEWRL_MESSAGE_WRAPPER));
661 
662  internbuf = buf;
663 
664  /* bounds check */
665  if (strlen(sysline)>=EXECBUFSIZE) return FALSE;
666  strcpy (buf,sysline);
667 
668  /* printf ("freewrlSystem, have %s here\n",internbuf); */
669  count = 0;
670 
671  /* do we have a console message - (which is text with spaces) */
672  if (haveXmessage) {
673  paramline[0] = FREEWRL_MESSAGE_WRAPPER;
674  paramline[1] = strchr(internbuf,' ');
675  count = 2;
676  } else {
677  /* split the command off of internbuf, for execing. */
678  while (internbuf != NULL) {
679  /* printf ("freewrlSystem: looping, count is %d\n",count); */
680  paramline[count] = internbuf;
681  internbuf = strchr(internbuf,' ');
682  if (internbuf != NULL) {
683  /* printf ("freewrlSystem: more strings here! :%s:\n",internbuf); */
684  *internbuf = '\0';
685  /* printf ("param %d is :%s:\n",count,paramline[count]); */
686  internbuf++;
687  count ++;
688  if (count >= MAXEXECPARAMS) return -1; /* never...*/
689  }
690  }
691  }
692 
693  /* printf ("freewrlSystem: finished while loop, count %d\n",count);
694 
695  { int xx;
696  for (xx=0; xx<MAXEXECPARAMS;xx++) {
697  printf ("item %d is :%s:\n",xx,paramline[xx]);
698  }} */
699 
700  if (haveXmessage) {
701  waitForChild = FALSE;
702  } else {
703  /* is the last string "&"? if so, we don't need to wait around */
704  if (strncmp(paramline[count],"&",strlen(paramline[count])) == 0) {
705  waitForChild=FALSE;
706  paramline[count] = '\0'; /* remove the ampersand.*/
707  }
708  }
709 
710  if (count > 0) {
711 /* switch (childProcess[lastchildProcess]=fork()) { */
712  child = fork();
713  switch (child) {
714  case -1:
715  perror ("fork");
716  exit(1);
717  break;
718 
719  case 0:
720  {
721  int Xrv;
722 
723  /* child process */
724  /* printf ("freewrlSystem: child execing, pid %d %d\n",childProcess[lastchildProcess], getpid()); */
725  Xrv = execl((const char *)paramline[0],
726  (const char *)paramline[0],paramline[1], paramline[2],
727  paramline[3],paramline[4],paramline[5],
728  paramline[6],paramline[7], NULL);
729  printf ("FreeWRL: Fatal problem execing %s\n",paramline[0]);
730  perror("FreeWRL: ");
731  exit (Xrv);
732  }
733  break;
734 
735  default:
736  {
737  /* parent process */
738  /* printf ("freewrlSystem: parent waiting for child %d\n",childProcess[lastchildProcess]); */
739 
740  /* do we have to wait around? */
741  if (!waitForChild) {
742  /* printf ("freewrlSystem - do not have to wait around\n"); */
743  return TRUE;
744  }
745 /* waitpid (childProcess[lastchildProcess],&pidStatus,0); */
746  waitpid(child, &pidStatus, 0);
747 
748  /* printf ("freewrlSystem: parent - child finished - pidStatus %d \n",
749  pidStatus); */
750 
751  /* printf ("freewrlSystem: WIFEXITED is %d\n",WIFEXITED(pidStatus)); */
752 
753  /* if (WIFEXITED(pidStatus) == TRUE) printf ("returned ok\n"); else printf ("problem with return\n"); */
754  }
755  }
756  return (WIFEXITED(pidStatus) == TRUE);
757  } else {
758  printf ("System call failed :%s:\n",sysline);
759  }
760  return -1; /* should we return FALSE or -1 ??? */
761 //#endif
762 }
763 #endif
764 //goal: remove a directory and its contents - used for removing the temp unzip folder for .z3z / .zip file processing
765 #ifdef _MSC_VER
766 //http://msdn.microsoft.com/en-us/windows/desktop/aa365488
767 
768 #include <TCHAR.H>
769 #ifdef UNICODE
770 static TCHAR *singleDot = L".";
771 static TCHAR *doubleDot = L"..";
772 static TCHAR *backslash = L"\\";
773 static TCHAR *star = L"*";
774 
775 #else
776 static TCHAR *singleDot = ".";
777 static TCHAR *doubleDot = "..";
778 static TCHAR *backslash = "\\";
779 static TCHAR *star = "*";
780 #endif
781 
782 // http://www.codeproject.com/Articles/9089/Deleting-a-directory-along-with-sub-folders
783 BOOL IsDots(const TCHAR* str) {
784  if(_tcscmp(str,singleDot) && _tcscmp(str,doubleDot))
785  return FALSE;
786  return TRUE;
787 }
788 BOOL DeleteDirectory0(const TCHAR* sPath) {
789  HANDLE hFind; // file handle
790  WIN32_FIND_DATA FindFileData;
791  TCHAR DirPath[MAX_PATH];
792  TCHAR FileName[MAX_PATH];
793  BOOL bSearch;
794 
795  _tcscpy(DirPath,sPath);
796  _tcscat(DirPath,backslash); // searching all files
797  _tcscat(DirPath,star);
798  _tcscpy(FileName,sPath);
799  _tcscat(FileName,backslash);
800 
801 #if _MSC_VER > 1500
802  hFind = FindFirstFileEx(DirPath, FindExInfoStandard, &FindFileData, FindExSearchNameMatch, NULL, 0); // find the first file - requires windows XP or later
803 #else
804  //
805  hFind = FindFirstFile(DirPath,&FindFileData); // find the first file
806 #endif
807  if(hFind == INVALID_HANDLE_VALUE)
808  return FALSE;
809  _tcscpy(DirPath,FileName);
810 
811  bSearch = TRUE;
812  while(bSearch) { // until we finds an entry
813  if(FindNextFile(hFind,&FindFileData)) {
814  if(IsDots(FindFileData.cFileName)) continue;
815  _tcscat(FileName,FindFileData.cFileName);
816  if((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
817  // we have found a directory, recurse
818  if(!DeleteDirectory0(FileName)) {
819  FindClose(hFind);
820  return FALSE; // directory couldn't be deleted
821  }
822  RemoveDirectory(FileName); // remove the empty directory
823  _tcscpy(FileName,DirPath);
824  }
825  else {
826  if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
827  _tchmod(FileName, 777); //_S_IWRITE); // change read-only file mode
828  if(!DeleteFile(FileName)) { // delete the file
829  /*
830  DWORD err = GetLastError();
831  if (err == ERROR_FILE_NOT_FOUND)
832  printf("file not found\n");
833  else if (err == ERROR_ACCESS_DENIED)
834  printf("access denied\n");
835  else if (err == ERROR_SHARING_VIOLATION)
836  printf("sharing violation\n");
837  else
838  printf("other erro\n");
839  */
840  FindClose(hFind);
841  return FALSE;
842  }
843  _tcscpy(FileName,DirPath);
844  }
845  }
846  else {
847  if(GetLastError() == ERROR_NO_MORE_FILES) // no more files there
848  bSearch = FALSE;
849  else {
850  // some error occured, close the handle and return FALSE
851  FindClose(hFind);
852  return FALSE;
853  }
854  }
855  }
856  FindClose(hFind); // closing file handle
857  return RemoveDirectory(sPath); // remove the empty directory
858 }
859 
860 BOOL tdirectory_remove_all(TCHAR *sPath){
861  BOOL retval;
862  retval = DeleteDirectory0(sPath);
863  return retval;
864 }
865 void tremove_file_or_folder(TCHAR *path){
866  int isDir; //iret,
867  DWORD finfo; //, err;
868 #if _MSC_VER > 1500
869  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364946(v=vs.85).aspx
870  WIN32_FILE_ATTRIBUTE_DATA fad;
871  finfo = GetFileAttributesEx(path, GetFileExInfoStandard, &fad);
872  if (!finfo){
873  DWORD err;
874  err = GetLastError();
875  //FormatMessage()
876  ConsoleMessage("GetFileAttribuesEx err=%d maxpath%d pathlen%d", (int)err,MAX_PATH,_tcslen(path)); //http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
877  isDir = ! _tcsstr(path, singleDot);
878  return;
879  }else
880  isDir = finfo && (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
881 #else
882  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364944%28v=vs.85%29.aspx
883  // http://msdn.microsoft.com/en-us/library/windows/desktop/gg258117%28v=vs.85%29.aspx
884  finfo = GetFileAttributes(path);
885  isDir = FILE_ATTRIBUTE_DIRECTORY & finfo;
886 #endif
887  if(isDir)
888  tdirectory_remove_all(path);
889  else
890  DeleteFile(path);
891 }
892 void remove_file_or_folder(const char *path){
893  //libfreewrl uses ascii or multibyte string functions, like strcpy, that look for a '\0' as end of string
894  //when sending something into freewrl thats 2-byte wide string, first convert it to multibyte
895  //when coming out, if you want to go back to wide-string then you need to convert to wide string
896  //tchar functions are supposed to be agnostic -they compile either way
897  int jj;
898  size_t convertedChars = 0;
899  TCHAR wcstring[MAX_PATH];
900  char fname2[MAX_PATH];
901  size_t origsize; //= strlen(fname) + 1;
902  //BOOL retval;
903  origsize = strlen(path) + 1;
904  strcpy(fname2,path);
905  for(jj=0;jj<(int)strlen(fname2);jj++)
906  if(fname2[jj] == '/' ) fname2[jj] = '\\';
907 
908 #ifdef _UNICODE
909 #if _MSC_VER >= 1500
910  mbstowcs_s(&convertedChars, wcstring, origsize, fname2, _TRUNCATE);
911 #else
912  mbstowcs(wcstring, fname2, MB_CUR_MAX);
913 #endif
914 #else
915  _tcscpy(wcstring,fname2);
916 #endif
917  tremove_file_or_folder(wcstring);
918 }
919 #else // POSIX and OSX - WARNING UNTESTED as of Sept 7, 2013
920 //according to boost, unlike posix OSX must do separate rmdir for directory and unlink for file
921 //goal: remove a directory and its contents - used for removing the temp unzip folder for .z3z / .zip file processing
922 int directory_remove_all(const char *path)
923 {
924  DIR *d = opendir(path);
925  size_t path_len = strlen(path);
926  int r = -1;
927 
928  if (d)
929  {
930  struct dirent *p;
931  r = 0;
932 
933  while (!r && (p=readdir(d)))
934  {
935  int r2 = -1;
936  char *buf;
937  size_t len;
938 
939  /* Skip the names "." and ".." as we don't want to recurse on them. */
940  if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
941  {
942  continue;
943  }
944  len = path_len + strlen(p->d_name) + 2;
945  buf = MALLOC(void *, len);
946  if (buf)
947  {
948  struct stat statbuf;
949  snprintf(buf, len, "%s/%s", path, p->d_name);
950  if (!stat(buf, &statbuf))
951  {
952  if (S_ISDIR(statbuf.st_mode))
953  {
954  r2 = directory_remove_all(buf);
955  }
956  else
957  {
958  r2 = unlink(buf);
959  }
960  }
961  FREE(buf);
962  }
963  r = r2;
964  }
965  closedir(d);
966  }
967  if (!r)
968  {
969  r = rmdir(path);
970  }
971  return r;
972 }
973 void remove_file_or_folder(const char * path){
974  struct stat statbuf;
975  if (!stat(path, &statbuf))
976  {
977  int r2;
978  UNUSED (r2);
979 
980  if (S_ISDIR(statbuf.st_mode))
981  {
982  r2 = directory_remove_all(path);
983  }
984  else
985  {
986  r2 = unlink(path);
987  }
988  }
989 }
990 #endif
991 
992 
993 
994 //could maybe be in a separate C file?
995 #ifdef HAVE_UNZIP_H
996 #include <unzip.h>
997 #define WRITEBUFFERSIZE (8192)
998 
999 
1000 int unzip_archive_to_temp_folder(const char *zipfilename, const char* tempfolderpath)
1001 {
1002 
1003  const char *filename_to_extract=NULL;
1004  int ret_value=0;
1005  const char *dirname=NULL;
1006  char temppath[256];
1007  char *fullpath = NULL;
1008  unzFile uf=NULL;
1009 
1010  uf = unzOpen(zipfilename);
1011  if (uf==NULL)
1012  {
1013  printf("Cannot open %s \n",zipfilename);
1014  return 1;
1015  }
1016  printf("%s opened\n",zipfilename);
1017  temppath[0] = '\0';
1018  if(tempfolderpath){
1019  fw_mkdir(tempfolderpath);
1020  }
1021 
1022  {
1023  uLong i;
1024  unz_global_info gi;
1025  int err;
1026  FILE* fout=NULL;
1027 
1028  err = unzGetGlobalInfo(uf,&gi);
1029  if (err!=UNZ_OK){
1030  printf("error %d with zipfile in unzGetGlobalInfo \n",err);
1031  return err;
1032  }
1033 
1034  for (i=0;i<gi.number_entry;i++)
1035  {
1036  {
1037  char filename_inzip[256];
1038  char* filename_withoutpath;
1039  char* p;
1040  int err=UNZ_OK;
1041  FILE *fout=NULL;
1042  void* buf;
1043  uInt size_buf;
1044 
1045  unz_file_info file_info;
1046  uLong ratio=0;
1047  err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
1048 
1049  if (err!=UNZ_OK)
1050  {
1051  printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
1052  return err;
1053  }
1054 
1055  size_buf = WRITEBUFFERSIZE;
1056  buf = (void*)MALLOC(void *, size_buf);
1057  if (buf==NULL)
1058  {
1059  printf("Error allocating memory\n");
1060  return UNZ_INTERNALERROR;
1061  }
1062 
1063  p = filename_withoutpath = filename_inzip;
1064  while ((*p) != '\0')
1065  {
1066  if (((*p)=='/') || ((*p)=='\\'))
1067  filename_withoutpath = p+1;
1068  p++;
1069  }
1070 
1071  if ((*filename_withoutpath)=='\0')
1072  {
1073  printf("creating directory: %s\n",filename_inzip);
1074  strcpy(temppath,tempfolderpath);
1075  strcat(temppath,"/");
1076  strcat(temppath,filename_inzip);
1077  //fw_mkdir(filename_inzip);
1078  fw_mkdir(temppath);
1079  }
1080  else
1081  {
1082  const char* write_filename;
1083  int skip=0;
1084 
1085  write_filename = filename_inzip;
1086 
1087  err = unzOpenCurrentFile(uf);
1088  if (err!=UNZ_OK)
1089  {
1090  printf("error %d with zipfile in unzOpenCurrentFile\n",err);
1091  }
1092 
1093  if (err==UNZ_OK)
1094  {
1095  strcpy(temppath,tempfolderpath);
1096  strcat(temppath,"/");
1097  strcat(temppath,write_filename);
1098  //fout=fopen(write_filename,"wb");
1099  fout=fopen(temppath,"wb");
1100  }
1101 
1102  if (fout!=NULL)
1103  {
1104  printf(" extracting: %s\n",write_filename);
1105 
1106  do
1107  {
1108  err = unzReadCurrentFile(uf,buf,size_buf);
1109  if (err<0)
1110  {
1111  printf("error %d with zipfile in unzReadCurrentFile\n",err);
1112  break;
1113  }
1114  if (err>0)
1115  if (fwrite(buf,err,1,fout)!=1)
1116  {
1117  printf("error in writing extracted file\n");
1118  err=UNZ_ERRNO;
1119  break;
1120  }
1121  }
1122  while (err>0);
1123  if (fout)
1124  fclose(fout);
1125 
1126  }
1127 
1128  if (err==UNZ_OK)
1129  {
1130  err = unzCloseCurrentFile (uf);
1131  if (err!=UNZ_OK)
1132  {
1133  printf("error %d with zipfile in unzCloseCurrentFile\n",err);
1134  }
1135  }
1136  else
1137  unzCloseCurrentFile(uf); /* don't lose the error */
1138  }
1139 
1140  FREE(buf);
1141  }
1142  if(err) break;
1143 
1144  if ((i+1)<gi.number_entry)
1145  {
1146  err = unzGoToNextFile(uf);
1147  if (err!=UNZ_OK)
1148  {
1149  printf("error %d with zipfile in unzGoToNextFile\n",err);
1150  break;
1151  }
1152  }
1153  }
1154 
1155  }
1156 
1157  unzClose(uf);
1158  return ret_value;
1159 }
1160 
1161 char* remove_filename_from_path(const char *path);
1162 char *strBackslash2fore(char *str);
1163 void resitem_enqueue(s_list_t *item);
1164 void process_x3z(resource_item_t *res){
1165  int err;
1166  char request[256];
1167  char* tempfolderpath;
1168  if (1){
1169  tempfolderpath = tempnam(gglobal()->Mainloop.tmpFileLocation, "freewrl_download_XXXXXXXX");
1170  }else{
1171  //for debugging if you need to have the temp unzip files in your working folder where your data files are
1172  tempfolderpath = STRDUP(res->URLrequest);
1173  tempfolderpath = strBackslash2fore(tempfolderpath);
1174  tempfolderpath = remove_filename_from_path(tempfolderpath);
1175  tempfolderpath = tempnam(tempfolderpath, "freewrl_download_XXXXXXXX");
1176  }
1177  err = unzip_archive_to_temp_folder(res->actual_file, tempfolderpath);
1178  if(!err){
1179  resource_item_t *docx3d;
1180  //I need a resource just for cleaning up the temp folder in one shot
1181  strcpy(request,tempfolderpath);
1182  strcat(request,"/doc.x3d");
1183  docx3d = resource_create_single(request);
1184  docx3d->parent = NULL; //divorce so it doesn't inherit rest_url
1185  docx3d->type = rest_file;
1186  docx3d->media_type = resm_x3d;
1187  docx3d->treat_as_root = 1;
1188  //docx3d->temp_dir = tempfolderpath;
1189  resitem_enqueue(ml_new(docx3d));
1190  // clean up temp folder via resource with opennedfile entry
1191  res->cached_files = ml_append(res->cached_files,ml_new(tempfolderpath));
1192  ConsoleMessage("unzip folder:%s\n", tempfolderpath);
1193  }
1194  else{
1195  ConsoleMessage("unzip failed to folder:%s\n", tempfolderpath);
1196  }
1197 }
1198 
1199 #else
1200 void process_x3z(resource_item_t *res){
1201 }
1202 #endif
1203 
1204 
1205 
1206 enum {
1207  file2blob_task_chain,
1208  file2blob_task_spawn,
1209  file2blob_task_enqueue,
1210 } file2blob_task_tactic;
1211 
1212 void resource_remove_cached_file(s_list_t *cfe);
1213 void delete_temp_file(resource_item_t *res){
1214  /*we delete a temp file immediately after it's loaded (ie after FILE2BLOB)
1215  (versus cleaning up on program exit. Bombing, killing and some configurations of mobile don't exit cleanly).
1216  stub this function if you want to see the temp files being created during a run.
1217  .x3z files need to hang around longer, for unzipping, and get cleaned up hopefully on exit.
1218  */
1219  s_list_t *cf;
1220  if(res->media_type != resm_x3z){
1221  cf = (s_list_t *)res->cached_files;
1222  if (cf) {
1223  ml_foreach(cf, resource_remove_cached_file(__l));
1224  //should clean up list items (but are contained strings constants/used elsewhere or strduped)
1225  ml_foreach(cf, ml_free(__l));
1226  res->cached_files = NULL;
1227  }
1228  }
1229 }
1230 
1231 int file2blob(void *resp){
1232  resource_item_t *res;
1233  int retval;
1234 
1235  res = (resource_item_t*)resp;
1236  if(res->media_type == resm_image){
1237 #ifdef DISABLER
1238  printf("FREEWRL LOADING IMAGERY: %s", res->actual_file);
1239 #endif
1240  retval = imagery_load(res); //FILE2TEXBLOB
1241  }else if(res->media_type == resm_movie){
1242  retval = movie_load(res);
1243  }else{
1244  retval = resource_load(res); //FILE2BLOB
1245  }
1246  delete_temp_file(res);
1247  return retval;
1248 }
1249 int async_thread_count = 0;
1250 static void *thread_load_async (void *args){
1251  int loaded;
1252  resource_item_t *res = (resource_item_t *)args;
1253  async_thread_count++;
1254  printf("[%d]",async_thread_count);
1255  loaded = file2blob(res);
1256  //enqueue BLOB to BE
1257  if(loaded)
1258  resitem_enqueue_tg(ml_new(res),res->tg);
1259  async_thread_count--;
1260  return NULL;
1261 }
1262 void loadAsync (resource_item_t *res) {
1263  if(!res->_loadThread) res->_loadThread = malloc(sizeof(pthread_t));
1264  pthread_create ((pthread_t*)res->_loadThread, NULL,&thread_load_async, (void *)res);
1265 }
1266 void file2blob_task(s_list_t *item){
1267  //chain, spawn async/thread, or re-enqueue FILE2BLOB to some work thread
1268  resource_item_t *res = item->elem;
1269  int tactic = file2blob_task_enqueue; // linux>imlib2 likes to stay on same thread //file2blob_task_chain; //file2blob_task_spawn;
1270  if(tactic == file2blob_task_chain){
1271  //chain FILE2BLOB
1272  if(res->media_type == resm_image){
1273 #ifdef DISABLER
1274  printf("FREEWRL LOADING IMAGERY: %s", res->actual_file);
1275 #endif
1276  imagery_load(res); //FILE2TEXBLOB
1277  }else{
1278  resource_load(res); //FILE2BLOB
1279  }
1280  //enqueue BLOB to BE
1281  delete_temp_file(res);
1282  resitem_enqueue(item);
1283  }else if(tactic == file2blob_task_enqueue){
1284  //set BE load function to non-null
1285  //a) res->load_func = imagery_load or resource_load or file2blob
1286  res->_loadFunc = (int(*)(void*))file2blob; //msvc can also do &file2blob
1287  //b) backend_setloadfunction(file2blob) or backend_setimageryloadfunction(imagery_load) and backend_setresourceloadfunction(resource_load)
1288  //enqueue downloaded FILE
1289  resitem_enqueue(item);
1290  }else if(tactic == file2blob_task_spawn){
1291  //spawn thread
1292  loadAsync(res); //res already has res->tg with global context
1293  ml_free(item);
1294  }
1295 }
Definition: list.h:37