source: trunk/zoo-kernel/service.h @ 263

Last change on this file since 263 was 254, checked in by djay, 13 years ago

Fixing session storage for fastcgi.

File size: 17.4 KB
Line 
1/**
2 * Author : Gérald FENOY
3 *
4 * Copyright (c) 2009-2010 GeoLabs SARL
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#ifndef ZOO_SERVICE_H
26#define ZOO_SERVICE_H 1
27
28#pragma once
29
30#ifdef WIN32
31#define strncasecmp strnicmp
32#define strcasecmp stricmp
33#define snprintf sprintf_s
34#endif
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40#include <stdlib.h>
41#include <ctype.h>
42#include <stdio.h>
43#include <string.h>
44
45#define bool int
46#define true 1
47#define false -1
48
49#define SERVICE_ACCEPTED 0
50#define SERVICE_STARTED 1
51#define SERVICE_PAUSED 2
52#define SERVICE_SUCCEEDED 3
53#define SERVICE_FAILED 4
54
55#define ELEMENTS_SIZE (sizeof(char*)+(((2*sizeof(char*))+sizeof(maps*))*2)+sizeof(char*)+(((2*sizeof(char*))+sizeof(iotype*))*2)+sizeof(elements*))
56#define MAP_SIZE (2*sizeof(char*))+sizeof(NULL)
57#define IOTYPE_SIZE MAP_SIZE+sizeof(NULL)
58#define MAPS_SIZE (2*sizeof(char*))+sizeof(map*)+MAP_SIZE
59#define SERVICE_SIZE (ELEMENTS_SIZE*2)+(MAP_SIZE*2)+sizeof(char*)
60
61#define SHMSZ     27
62
63
64  /**
65   * \struct map
66   * \brief KVP linked list
67   *
68   * Deal with WPS KVP (name,value).
69   * A map is defined as:
70   *  - name : a key,
71   *  - value: a value,
72   *  - next : a pointer to the next map if any.
73   */
74  typedef struct map{
75    char* name;
76    char* value;
77    struct map* next;
78  } map;
79
80#ifdef WIN32
81#define NULLMAP ((map*) 0)
82#else
83#define NULLMAP NULL
84#endif
85
86  /**
87   * \struct maps
88   * \brief linked list of map pointer
89   *
90   * Small object to store WPS KVP set.
91   * Maps is defined as:
92   *  - a name,
93   *  - a content map,
94   *  - a pointer to the next maps if any.
95   */
96  typedef struct maps{
97    char* name;         
98    struct map* content; 
99    struct maps* next;   
100  } maps;
101
102  /**
103   * \brief Dump a map on stderr
104   */
105  static void _dumpMap(map* t){
106    if(t!=NULL){
107      fprintf(stderr,"[%s] => [%s] \n",t->name,t->value);
108      fflush(stderr);
109    }else{
110      fprintf(stderr,"NULL\n");
111      fflush(stderr);
112    }
113  }
114
115  static void dumpMap(map* t){
116    map* tmp=t;
117    while(tmp!=NULL){
118      _dumpMap(tmp);
119      tmp=tmp->next;
120    }
121  }
122
123  static void dumpMapToFile(map* t,FILE* file){
124    map* tmp=t;
125    while(tmp!=NULL){
126      fprintf(stderr,"%s = %s\n",tmp->name,tmp->value);
127      fprintf(file,"%s = %s\n",tmp->name,tmp->value);
128      tmp=tmp->next;
129    }
130  }
131
132  static void dumpMaps(maps* m){
133    maps* tmp=m;
134    while(tmp!=NULL){
135      fprintf(stderr,"MAP => [%s] \n",tmp->name);
136      dumpMap(tmp->content);
137      tmp=tmp->next;
138    }
139  }
140
141  static void dumpMapsToFile(maps* m,char* file_path){
142    FILE* file=fopen(file_path,"w");
143    maps* tmp=m;
144    if(tmp!=NULL){
145      fprintf(file,"[%s]\n",tmp->name);
146      dumpMapToFile(tmp->content,file);
147      fflush(file);
148    }
149    fclose(file);
150  }
151
152  static map* createMap(const char* name,const char* value){
153    map* tmp=(map *)malloc(MAP_SIZE);
154    tmp->name=strdup(name);
155    tmp->value=strdup(value);
156    tmp->next=NULL;
157    return tmp;
158  }
159
160  static int count(map* m){
161    map* tmp=m;
162    int c=0;
163    while(tmp!=NULL){
164      c++;
165      tmp=tmp->next;
166    }
167    return c;
168  }
169   
170  static bool hasKey(map* m,const char *key){
171    map* tmp=m;
172    while(tmp!=NULL){
173      if(strcasecmp(tmp->name,key)==0)
174        return true;
175      tmp=tmp->next;
176    }
177#ifdef DEBUG_MAP
178    fprintf(stderr,"NOT FOUND \n");
179#endif
180    return false;
181  }
182
183  static maps* getMaps(maps* m,const char *key){
184    maps* tmp=m;
185    while(tmp!=NULL){
186      if(strcasecmp(tmp->name,key)==0){
187        return tmp;
188      }
189      tmp=tmp->next;
190    }
191    return NULL;
192  }
193
194  static map* getMap(map* m,const char *key){
195    map* tmp=m;
196    while(tmp!=NULL){
197      if(strcasecmp(tmp->name,key)==0){
198        return tmp;
199      }
200      tmp=tmp->next;
201    }
202    return NULL;
203  }
204
205  static map* getLastMap(map* m){
206    map* tmp=m;
207    while(tmp!=NULL){
208      if(tmp->next==NULL){
209        return tmp;
210      }
211      tmp=tmp->next;
212    }
213    return NULL;
214  }
215
216  static map* getMapFromMaps(maps* m,const char* key,const char* subkey){
217    maps* _tmpm=getMaps(m,key);
218    if(_tmpm!=NULL){
219      map* _ztmpm=getMap(_tmpm->content,subkey);
220      return _ztmpm;
221    }
222    else return NULL;
223  }
224
225  static char* getMapsAsKVP(maps* m,int length,int type){
226    char *dataInputsKVP=(char*) malloc(length*sizeof(char));
227    maps* curs=m;
228    int i=0;
229    while(curs!=NULL){
230      if(i==0)
231        if(type==0)
232          sprintf(dataInputsKVP,"%s=",curs->name);
233        else
234          sprintf(dataInputsKVP,"%s",curs->name);
235      else{
236        char *temp=strdup(dataInputsKVP);
237        if(type==0)
238          sprintf(dataInputsKVP,"%s;%s=",temp,curs->name);
239        else
240          sprintf(dataInputsKVP,"%s;%s",temp,curs->name);
241        free(temp);
242      }
243      map* icurs=curs->content;
244      if(type==0){
245        map* tmp=getMap(curs->content,"value");
246        char *temp=strdup(dataInputsKVP);
247        if(getMap(m->content,"xlink:href")!=NULL)
248          sprintf(dataInputsKVP,"%sReference",temp);
249        else
250          sprintf(dataInputsKVP,"%s%s",temp,icurs->value);
251        free(temp);
252      }
253      int j=0;
254      while(icurs!=NULL){
255        if(strcasecmp(icurs->name,"value")!=0 &&
256           strcasecmp(icurs->name,"Reference")!=0 &&
257           strcasecmp(icurs->name,"minOccurs")!=0 &&
258           strcasecmp(icurs->name,"maxOccurs")!=0 &&
259           strcasecmp(icurs->name,"inRequest")!=0){
260          char *itemp=strdup(dataInputsKVP);
261          sprintf(dataInputsKVP,"%s@%s=%s",itemp,icurs->name,icurs->value);
262          free(itemp);
263        }
264        icurs=icurs->next;
265      }
266      curs=curs->next;
267      i++;
268    }
269    return dataInputsKVP;
270  }
271
272
273  static void freeMap(map** mo){
274    map* _cursor=*mo;
275    if(_cursor!=NULL){
276#ifdef DEBUG
277      fprintf(stderr,"freeMap\n");
278#endif
279      free(_cursor->name);
280      free(_cursor->value);
281      if(_cursor->next!=NULL){
282        freeMap(&_cursor->next);
283        free(_cursor->next);
284      }
285    }
286  }
287
288  static void freeMaps(maps** mo){
289    maps* _cursor=*mo;
290    fflush(stderr);
291    if(_cursor && _cursor!=NULL){
292#ifdef DEBUG
293      fprintf(stderr,"freeMaps\n");
294#endif
295      free(_cursor->name);
296      if(_cursor->content!=NULL){
297        freeMap(&_cursor->content);
298        free(_cursor->content);
299      }
300      if(_cursor->next!=NULL){
301        freeMaps(&_cursor->next);
302        free(_cursor->next);
303      }
304    }
305  }
306
307  /**
308   * \brief Not named linked list
309   *
310   * Used to store informations about formats, such as mimeType, encoding ...
311   *
312   * An iotype is defined as :
313   *  - a content map,
314   *  - a pointer to the next iotype if any.
315   */
316  typedef struct iotype{
317    struct map* content;
318    struct iotype* next;
319  } iotype;
320
321  /**
322   * \brief Metadata information about input or output.
323   *
324   * The elements are used to store metadata informations defined in the ZCFG.
325   *
326   * An elements is defined as :
327   *  - a name,
328   *  - a content map,
329   *  - a metadata map,
330   *  - a format (possible values are LiteralData, ComplexData or
331   * BoundingBoxData),
332   *  - a default iotype,
333   *  - a pointer to the next elements id any.
334   */
335  typedef struct elements{
336    char* name;
337    struct map* content;
338    struct map* metadata;
339    char* format;
340    struct iotype* defaults;
341    struct iotype* supported;
342    struct elements* next;
343  } elements;
344
345  typedef struct service{
346    char* name;
347    struct map* content;
348    struct map* metadata;
349    struct elements* inputs;
350    struct elements* outputs; 
351  } service;
352
353  typedef struct services{
354    struct service* content; 
355    struct services* next; 
356  } services;
357
358  static bool hasElement(elements* e,const char* key){
359    elements* tmp=e;
360    while(tmp!=NULL){
361      if(strcasecmp(key,tmp->name)==0)
362        return true;
363      tmp=tmp->next;
364    }
365    return false;
366  }
367
368  static elements* getElements(elements* m,char *key){
369    elements* tmp=m;
370    while(tmp!=NULL){
371      if(strcasecmp(tmp->name,key)==0)
372        return tmp;
373      tmp=tmp->next;
374    }
375    return NULL;
376  }
377
378
379  static void freeIOType(iotype** i){
380    iotype* _cursor=*i;
381    if(_cursor!=NULL){
382      if(_cursor->next!=NULL){
383        freeIOType(&_cursor->next);
384        free(_cursor->next);
385      }
386      freeMap(&_cursor->content);
387      free(_cursor->content);
388    }
389  }
390
391  static void freeElements(elements** e){
392    elements* tmp=*e;
393    if(tmp!=NULL){
394      if(tmp->name!=NULL)
395        free(tmp->name);
396      freeMap(&tmp->content);
397      if(tmp->content!=NULL)
398        free(tmp->content);
399      freeMap(&tmp->metadata);
400      if(tmp->metadata!=NULL)
401        free(tmp->metadata);
402      if(tmp->format!=NULL)
403        free(tmp->format);
404      freeIOType(&tmp->defaults);
405      if(tmp->defaults!=NULL)
406        free(tmp->defaults);
407      freeIOType(&tmp->supported);
408      if(tmp->supported!=NULL){
409        free(tmp->supported);
410      }
411      freeElements(&tmp->next);
412      if(tmp->next!=NULL)
413        free(tmp->next);
414    }
415  }
416
417  static void freeService(service** s){
418    service* tmp=*s;
419    if(tmp!=NULL){
420      if(tmp->name!=NULL)
421        free(tmp->name);
422      freeMap(&tmp->content);
423      if(tmp->content!=NULL)
424        free(tmp->content);
425      freeMap(&tmp->metadata);
426      if(tmp->metadata!=NULL)
427        free(tmp->metadata);
428      freeElements(&tmp->inputs);
429      if(tmp->inputs!=NULL)
430        free(tmp->inputs);
431      freeElements(&tmp->outputs);
432      if(tmp->outputs!=NULL)
433        free(tmp->outputs);
434    }
435  }
436
437  static void addToMap(map* m,const char* n,const char* v){
438    if(hasKey(m,n)==false){
439      map* _cursor=m;
440      while(_cursor->next!=NULL)
441        _cursor=_cursor->next;
442      _cursor->next=createMap(n,v);
443    }
444    else{
445      map *tmp=getMap(m,n);
446      if(tmp->value!=NULL)
447        free(tmp->value);
448      tmp->value=strdup(v);
449    }
450  }
451
452  static void addMapToMap(map** mo,map* mi){
453    map* tmp=mi;
454    map* _cursor=*mo;
455    if(tmp==NULL){
456      if(_cursor!=NULL){
457        while(_cursor!=NULL)
458          _cursor=_cursor->next;
459        _cursor=NULL;
460      }else
461        *mo=NULL;
462    }
463    while(tmp!=NULL){
464      if(_cursor==NULL){
465        if(*mo==NULL)
466          *mo=createMap(tmp->name,tmp->value);
467        else
468          addToMap(*mo,tmp->name,tmp->value);
469      }
470      else{
471#ifdef DEBUG
472        fprintf(stderr,"_CURSOR\n");
473        dumpMap(_cursor);
474#endif
475        while(_cursor!=NULL)
476          _cursor=_cursor->next;
477        _cursor=createMap(tmp->name,tmp->value);
478        _cursor->next=NULL;
479      }
480      tmp=tmp->next;
481#ifdef DEBUG
482      fprintf(stderr,"MO\n");
483      dumpMap(*mo);
484#endif
485    }
486  }
487
488  static void addMapToIoType(iotype** io,map* mi){
489    iotype* tmp=*io;
490    while(tmp->next!=NULL){
491      tmp=tmp->next;
492    }
493    tmp->next=(iotype*)malloc(IOTYPE_SIZE);
494    tmp->next->content=NULL;
495    addMapToMap(&tmp->next->content,mi);
496    tmp->next->next=NULL;
497  }
498
499  static bool contains(map* m,map* i){
500    while(i!=NULL){     
501      if(strcasecmp(i->name,"value")!=0 &&
502         strcasecmp(i->name,"xlink:href")!=0){
503        map *tmp;
504        if(hasKey(m,i->name) && (tmp=getMap(m,i->name))!=NULL && 
505           strcasecmp(i->value,tmp->value)!=0)
506          return false;
507      }
508      i=i->next;
509    }
510    return true;
511  }
512
513  static iotype* getIoTypeFromElement(elements* e,char *name, map* values){
514    elements* cursor=e;
515    while(cursor!=NULL){
516      if(strcasecmp(cursor->name,name)==0){
517        if(contains(cursor->defaults->content,values)==true)
518          return cursor->defaults;
519        else{
520          iotype* tmp=cursor->supported;
521          while(tmp!=NULL){
522            if(contains(tmp->content,values)==true)
523              return tmp;           
524            tmp=tmp->next;
525          }
526        }
527      }
528      cursor=cursor->next;
529    }
530    return NULL;
531  }
532
533  static maps* dupMaps(maps** mo){
534    maps* _cursor=*mo;
535    maps* res=NULL;
536    if(_cursor!=NULL){
537      res=(maps*)malloc(MAPS_SIZE);
538      res->name=strdup(_cursor->name);
539      res->content=NULL;
540      res->next=NULL;
541      map* mc=_cursor->content;
542      map* tmp=getMap(mc,"size");
543      char* tmpSized=NULL;
544      if(tmp!=NULL){
545        map* tmpV=getMap(mc,"value");
546        tmpSized=(char*)malloc((atoi(tmp->value)+1)*sizeof(char));
547        memmove(tmpSized,tmpV->value,atoi(tmp->value)*sizeof(char));
548      }
549      if(mc!=NULL){
550        addMapToMap(&res->content,mc);
551      }
552      if(tmp!=NULL){
553        map* tmpV=getMap(res->content,"value");
554        free(tmpV->value);
555        tmpV->value=(char*)malloc((atoi(tmp->value)+1)*sizeof(char));
556        memmove(tmpV->value,tmpSized,atoi(tmp->value)*sizeof(char));
557        tmpV->value[atoi(tmp->value)]=0;
558        free(tmpSized);
559      }
560      res->next=dupMaps(&_cursor->next);
561    }
562    return res;
563  }
564
565  static void addMapsToMaps(maps** mo,maps* mi){
566    maps* tmp=mi;
567    maps* _cursor=*mo;
568    while(tmp!=NULL){
569      if(_cursor==NULL){
570        *mo=dupMaps(&mi);
571        (*mo)->next=NULL;
572      }
573      else{
574        while(_cursor->next!=NULL)
575          _cursor=_cursor->next;
576        _cursor->next=dupMaps(&tmp);
577      }
578      tmp=tmp->next;
579    }
580  }
581
582
583  static void setMapInMaps(maps* m,const char* key,const char* subkey,const char *value){
584    maps* _tmpm=getMaps(m,key);
585    if(_tmpm!=NULL){
586      map* _ztmpm=getMap(_tmpm->content,subkey);
587      if(_ztmpm!=NULL){
588        if(_ztmpm->value!=NULL)
589          free(_ztmpm->value);
590        _ztmpm->value=strdup(value);
591      }else{
592        addToMap(_tmpm->content,subkey,value);
593      }
594    }
595  }
596
597
598  static void dumpElements(elements* e){
599    elements* tmp=e;
600    while(tmp!=NULL){
601      fprintf(stderr,"ELEMENT [%s]\n",tmp->name);
602      fprintf(stderr," > CONTENT [%s]\n",tmp->name);
603      dumpMap(tmp->content);
604      fprintf(stderr," > METADATA [%s]\n",tmp->name);
605      dumpMap(tmp->metadata);
606      fprintf(stderr," > FORMAT [%s]\n",tmp->format);
607      iotype* tmpio=tmp->defaults;
608      int ioc=0;
609      while(tmpio!=NULL){
610        fprintf(stderr," > DEFAULTS [%s] (%i)\n",tmp->name,ioc);
611        dumpMap(tmpio->content);
612        tmpio=tmpio->next;
613        ioc++;
614      }
615      tmpio=tmp->supported;
616      ioc=0;
617      while(tmpio!=NULL){
618        fprintf(stderr," > SUPPORTED [%s] (%i)\n",tmp->name,ioc);
619        dumpMap(tmpio->content);
620        tmpio=tmpio->next;
621        ioc++;
622      }
623      fprintf(stderr,"------------------\n");
624      tmp=tmp->next;
625    }
626  }
627
628  static elements* dupElements(elements* e){
629    elements* cursor=e;
630    elements* tmp=NULL;
631    if(cursor!=NULL){
632#ifdef DEBUG
633      fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
634      dumpElements(e);
635      fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
636#endif
637      tmp=(elements*)malloc(ELEMENTS_SIZE);
638      tmp->name=strdup(e->name);
639      tmp->content=NULL;
640      addMapToMap(&tmp->content,e->content);
641      tmp->metadata=NULL;
642      addMapToMap(&tmp->metadata,e->metadata);
643      tmp->format=strdup(e->format);
644      if(e->defaults!=NULL){
645        tmp->defaults=(iotype*)malloc(IOTYPE_SIZE);
646        tmp->defaults->content=NULL;
647        addMapToMap(&tmp->defaults->content,e->defaults->content);
648        tmp->defaults->next=NULL;
649#ifdef DEBUG
650        fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
651        dumpMap(tmp->defaults->content);
652#endif
653      }else
654        tmp->defaults=NULL;
655      if(e->supported!=NULL){
656        tmp->supported=(iotype*)malloc(IOTYPE_SIZE);
657        tmp->supported->content=NULL;
658        addMapToMap(&tmp->supported->content,e->supported->content);
659        tmp->supported->next=NULL;
660        iotype *tmp2=e->supported->next;
661        while(tmp2!=NULL){
662          addMapToIoType(&tmp->supported,tmp2->content);
663#ifdef DEBUG
664          fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
665          dumpMap(tmp->defaults->content);
666#endif
667          tmp2=tmp2->next;
668        }
669      }
670      else
671        tmp->supported=NULL;
672      tmp->next=dupElements(cursor->next);
673    }
674    return tmp;
675  }
676
677  static void addToElements(elements** m,elements* e){
678    elements* tmp=e;
679    if(*m==NULL){
680      *m=dupElements(tmp);
681    }else{
682      addToElements(&(*m)->next,tmp);
683    }
684  }
685
686  static void dumpService(service* s){
687    fprintf(stderr,"++++++++++++++++++\nSERVICE [%s]\n++++++++++++++++++\n",s->name);
688    if(s->content!=NULL){
689      fprintf(stderr,"CONTENT MAP\n");
690      dumpMap(s->content);
691      fprintf(stderr,"CONTENT METADATA\n");
692      dumpMap(s->metadata);
693    }
694    if(s->inputs!=NULL){
695      fprintf(stderr,"INPUT ELEMENTS [%s]\n------------------\n",s->name);
696      dumpElements(s->inputs);
697    }
698    if(s->outputs!=NULL){
699      fprintf(stderr,"OUTPUT ELEMENTS [%s]\n------------------\n",s->name);
700      dumpElements(s->outputs);
701    }
702    fprintf(stderr,"++++++++++++++++++\n");
703  }
704
705  static void mapsToCharXXX(maps* m,char*** c){
706    maps* tm=m;
707    int i=0;
708    int j=0;
709    char tmp[10][30][1024];
710    memset(tmp,0,1024*10*10);
711    while(tm!=NULL){
712      if(i>=10)
713        break;
714      strcpy(tmp[i][j],"name");
715      j++;
716      strcpy(tmp[i][j],tm->name);
717      j++;
718      map* tc=tm->content;
719      while(tc!=NULL){
720        if(j>=30)
721          break;
722        strcpy(tmp[i][j],tc->name);
723        j++;
724        strcpy(tmp[i][j],tc->value);
725        j++;
726        tc=tc->next;
727      }
728      tm=tm->next;
729      j=0;
730      i++;
731    }
732    memcpy(c,tmp,10*10*1024);
733  }
734
735  static void charxxxToMaps(char*** c,maps**m){
736    maps* trorf=*m;
737    int i,j;
738    char tmp[10][30][1024];
739    memcpy(tmp,c,10*30*1024);
740    for(i=0;i<10;i++){
741      if(strlen(tmp[i][1])==0)
742        break;
743      trorf->name=tmp[i][1];
744      trorf->content=NULL;
745      trorf->next=NULL;
746      for(j=2;j<29;j+=2){
747        if(strlen(tmp[i][j+1])==0)
748          break;
749        if(trorf->content==NULL)
750          trorf->content=createMap(tmp[i][j],tmp[i][j+1]);
751        else
752          addToMap(trorf->content,tmp[i][j],tmp[i][j+1]);
753      }
754      trorf=trorf->next;
755    }
756    m=&trorf;
757  }
758
759#ifdef __cplusplus
760}
761#endif
762
763#endif
Note: See TracBrowser for help on using the repository browser.

Search

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png