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

Last change on this file since 248 was 229, checked in by djay, 14 years ago

Remove the '<' char supported in zcfg. Fixing dupMaps memory allocation size. Many thanks to Luca Delucchi for pointing us to this issue.

File size: 17.3 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(file,"%s = %s\n",t->name,t->value);
127      tmp=tmp->next;
128    }
129  }
130
131  static void dumpMaps(maps* m){
132    maps* tmp=m;
133    while(tmp!=NULL){
134      fprintf(stderr,"MAP => [%s] \n",tmp->name);
135      dumpMap(tmp->content);
136      tmp=tmp->next;
137    }
138  }
139
140  static void dumpMapsToFile(maps* m,FILE* file){
141    maps* tmp=m;
142    if(tmp!=NULL){
143      fprintf(file,"[%s]\n",tmp->name);
144      dumpMapToFile(tmp->content,file);
145    }
146  }
147
148  static map* createMap(const char* name,const char* value){
149    map* tmp=(map *)malloc(MAP_SIZE);
150    tmp->name=strdup(name);
151    tmp->value=strdup(value);
152    tmp->next=NULL;
153    return tmp;
154  }
155
156  static int count(map* m){
157    map* tmp=m;
158    int c=0;
159    while(tmp!=NULL){
160      c++;
161      tmp=tmp->next;
162    }
163    return c;
164  }
165   
166  static bool hasKey(map* m,const char *key){
167    map* tmp=m;
168    while(tmp!=NULL){
169      if(strcasecmp(tmp->name,key)==0)
170        return true;
171      tmp=tmp->next;
172    }
173#ifdef DEBUG_MAP
174    fprintf(stderr,"NOT FOUND \n");
175#endif
176    return false;
177  }
178
179  static maps* getMaps(maps* m,const char *key){
180    maps* tmp=m;
181    while(tmp!=NULL){
182      if(strcasecmp(tmp->name,key)==0){
183        return tmp;
184      }
185      tmp=tmp->next;
186    }
187    return NULL;
188  }
189
190  static map* getMap(map* m,const char *key){
191    map* tmp=m;
192    while(tmp!=NULL){
193      if(strcasecmp(tmp->name,key)==0){
194        return tmp;
195      }
196      tmp=tmp->next;
197    }
198    return NULL;
199  }
200
201  static map* getLastMap(map* m){
202    map* tmp=m;
203    while(tmp!=NULL){
204      if(tmp->next==NULL){
205        return tmp;
206      }
207      tmp=tmp->next;
208    }
209    return NULL;
210  }
211
212  static map* getMapFromMaps(maps* m,const char* key,const char* subkey){
213    maps* _tmpm=getMaps(m,key);
214    if(_tmpm!=NULL){
215      map* _ztmpm=getMap(_tmpm->content,subkey);
216      return _ztmpm;
217    }
218    else return NULL;
219  }
220
221  static char* getMapsAsKVP(maps* m,int length,int type){
222    char *dataInputsKVP=(char*) malloc(length*sizeof(char));
223    maps* curs=m;
224    int i=0;
225    while(curs!=NULL){
226      if(i==0)
227        if(type==0)
228          sprintf(dataInputsKVP,"%s=",curs->name);
229        else
230          sprintf(dataInputsKVP,"%s",curs->name);
231      else{
232        char *temp=strdup(dataInputsKVP);
233        if(type==0)
234          sprintf(dataInputsKVP,"%s;%s=",temp,curs->name);
235        else
236          sprintf(dataInputsKVP,"%s;%s",temp,curs->name);
237        free(temp);
238      }
239      map* icurs=curs->content;
240      if(type==0){
241        map* tmp=getMap(curs->content,"value");
242        char *temp=strdup(dataInputsKVP);
243        if(getMap(m->content,"xlink:href")!=NULL)
244          sprintf(dataInputsKVP,"%sReference",temp);
245        else
246          sprintf(dataInputsKVP,"%s%s",temp,icurs->value);
247        free(temp);
248      }
249      int j=0;
250      while(icurs!=NULL){
251        if(strcasecmp(icurs->name,"value")!=0 &&
252           strcasecmp(icurs->name,"Reference")!=0 &&
253           strcasecmp(icurs->name,"minOccurs")!=0 &&
254           strcasecmp(icurs->name,"maxOccurs")!=0 &&
255           strcasecmp(icurs->name,"inRequest")!=0){
256          char *itemp=strdup(dataInputsKVP);
257          sprintf(dataInputsKVP,"%s@%s=%s",itemp,icurs->name,icurs->value);
258          free(itemp);
259        }
260        icurs=icurs->next;
261      }
262      curs=curs->next;
263      i++;
264    }
265    return dataInputsKVP;
266  }
267
268
269  static void freeMap(map** mo){
270    map* _cursor=*mo;
271    if(_cursor!=NULL){
272#ifdef DEBUG
273      fprintf(stderr,"freeMap\n");
274#endif
275      free(_cursor->name);
276      free(_cursor->value);
277      if(_cursor->next!=NULL){
278        freeMap(&_cursor->next);
279        free(_cursor->next);
280      }
281    }
282  }
283
284  static void freeMaps(maps** mo){
285    maps* _cursor=*mo;
286    fflush(stderr);
287    if(_cursor && _cursor!=NULL){
288#ifdef DEBUG
289      fprintf(stderr,"freeMaps\n");
290#endif
291      free(_cursor->name);
292      if(_cursor->content!=NULL){
293        freeMap(&_cursor->content);
294        free(_cursor->content);
295      }
296      if(_cursor->next!=NULL){
297        freeMaps(&_cursor->next);
298        free(_cursor->next);
299      }
300    }
301  }
302
303  /**
304   * \brief Not named linked list
305   *
306   * Used to store informations about formats, such as mimeType, encoding ...
307   *
308   * An iotype is defined as :
309   *  - a content map,
310   *  - a pointer to the next iotype if any.
311   */
312  typedef struct iotype{
313    struct map* content;
314    struct iotype* next;
315  } iotype;
316
317  /**
318   * \brief Metadata information about input or output.
319   *
320   * The elements are used to store metadata informations defined in the ZCFG.
321   *
322   * An elements is defined as :
323   *  - a name,
324   *  - a content map,
325   *  - a metadata map,
326   *  - a format (possible values are LiteralData, ComplexData or
327   * BoundingBoxData),
328   *  - a default iotype,
329   *  - a pointer to the next elements id any.
330   */
331  typedef struct elements{
332    char* name;
333    struct map* content;
334    struct map* metadata;
335    char* format;
336    struct iotype* defaults;
337    struct iotype* supported;
338    struct elements* next;
339  } elements;
340
341  typedef struct service{
342    char* name;
343    struct map* content;
344    struct map* metadata;
345    struct elements* inputs;
346    struct elements* outputs; 
347  } service;
348
349  typedef struct services{
350    struct service* content; 
351    struct services* next; 
352  } services;
353
354  static bool hasElement(elements* e,const char* key){
355    elements* tmp=e;
356    while(tmp!=NULL){
357      if(strcasecmp(key,tmp->name)==0)
358        return true;
359      tmp=tmp->next;
360    }
361    return false;
362  }
363
364  static elements* getElements(elements* m,char *key){
365    elements* tmp=m;
366    while(tmp!=NULL){
367      if(strcasecmp(tmp->name,key)==0)
368        return tmp;
369      tmp=tmp->next;
370    }
371    return NULL;
372  }
373
374
375  static void freeIOType(iotype** i){
376    iotype* _cursor=*i;
377    if(_cursor!=NULL){
378      if(_cursor->next!=NULL){
379        freeIOType(&_cursor->next);
380        free(_cursor->next);
381      }
382      freeMap(&_cursor->content);
383      free(_cursor->content);
384    }
385  }
386
387  static void freeElements(elements** e){
388    elements* tmp=*e;
389    if(tmp!=NULL){
390      if(tmp->name!=NULL)
391        free(tmp->name);
392      freeMap(&tmp->content);
393      if(tmp->content!=NULL)
394        free(tmp->content);
395      freeMap(&tmp->metadata);
396      if(tmp->metadata!=NULL)
397        free(tmp->metadata);
398      if(tmp->format!=NULL)
399        free(tmp->format);
400      freeIOType(&tmp->defaults);
401      if(tmp->defaults!=NULL)
402        free(tmp->defaults);
403      freeIOType(&tmp->supported);
404      if(tmp->supported!=NULL){
405        free(tmp->supported);
406      }
407      freeElements(&tmp->next);
408      if(tmp->next!=NULL)
409        free(tmp->next);
410    }
411  }
412
413  static void freeService(service** s){
414    service* tmp=*s;
415    if(tmp!=NULL){
416      if(tmp->name!=NULL)
417        free(tmp->name);
418      freeMap(&tmp->content);
419      if(tmp->content!=NULL)
420        free(tmp->content);
421      freeMap(&tmp->metadata);
422      if(tmp->metadata!=NULL)
423        free(tmp->metadata);
424      freeElements(&tmp->inputs);
425      if(tmp->inputs!=NULL)
426        free(tmp->inputs);
427      freeElements(&tmp->outputs);
428      if(tmp->outputs!=NULL)
429        free(tmp->outputs);
430    }
431  }
432
433  static void addToMap(map* m,const char* n,const char* v){
434    if(hasKey(m,n)==false){
435      map* _cursor=m;
436      while(_cursor->next!=NULL)
437        _cursor=_cursor->next;
438      _cursor->next=createMap(n,v);
439    }
440    else{
441      map *tmp=getMap(m,n);
442      if(tmp->value!=NULL)
443        free(tmp->value);
444      tmp->value=strdup(v);
445    }
446  }
447
448  static void addMapToMap(map** mo,map* mi){
449    map* tmp=mi;
450    map* _cursor=*mo;
451    if(tmp==NULL){
452      if(_cursor!=NULL){
453        while(_cursor!=NULL)
454          _cursor=_cursor->next;
455        _cursor=NULL;
456      }else
457        *mo=NULL;
458    }
459    while(tmp!=NULL){
460      if(_cursor==NULL){
461        if(*mo==NULL)
462          *mo=createMap(tmp->name,tmp->value);
463        else
464          addToMap(*mo,tmp->name,tmp->value);
465      }
466      else{
467#ifdef DEBUG
468        fprintf(stderr,"_CURSOR\n");
469        dumpMap(_cursor);
470#endif
471        while(_cursor!=NULL)
472          _cursor=_cursor->next;
473        _cursor=createMap(tmp->name,tmp->value);
474        _cursor->next=NULL;
475      }
476      tmp=tmp->next;
477#ifdef DEBUG
478      fprintf(stderr,"MO\n");
479      dumpMap(*mo);
480#endif
481    }
482  }
483
484  static void addMapToIoType(iotype** io,map* mi){
485    iotype* tmp=*io;
486    while(tmp->next!=NULL){
487      tmp=tmp->next;
488    }
489    tmp->next=(iotype*)malloc(IOTYPE_SIZE);
490    tmp->next->content=NULL;
491    addMapToMap(&tmp->next->content,mi);
492    tmp->next->next=NULL;
493  }
494
495  static bool contains(map* m,map* i){
496    while(i!=NULL){     
497      if(strcasecmp(i->name,"value")!=0 &&
498         strcasecmp(i->name,"xlink:href")!=0){
499        map *tmp;
500        if(hasKey(m,i->name) && (tmp=getMap(m,i->name))!=NULL && 
501           strcasecmp(i->value,tmp->value)!=0)
502          return false;
503      }
504      i=i->next;
505    }
506    return true;
507  }
508
509  static iotype* getIoTypeFromElement(elements* e,char *name, map* values){
510    elements* cursor=e;
511    while(cursor!=NULL){
512      if(strcasecmp(cursor->name,name)==0){
513        if(contains(cursor->defaults->content,values)==true)
514          return cursor->defaults;
515        else{
516          iotype* tmp=cursor->supported;
517          while(tmp!=NULL){
518            if(contains(tmp->content,values)==true)
519              return tmp;           
520            tmp=tmp->next;
521          }
522        }
523      }
524      cursor=cursor->next;
525    }
526    return NULL;
527  }
528
529  static maps* dupMaps(maps** mo){
530    maps* _cursor=*mo;
531    maps* res=NULL;
532    if(_cursor!=NULL){
533      res=(maps*)malloc(MAPS_SIZE);
534      res->name=strdup(_cursor->name);
535      res->content=NULL;
536      res->next=NULL;
537      map* mc=_cursor->content;
538      map* tmp=getMap(mc,"size");
539      char* tmpSized=NULL;
540      if(tmp!=NULL){
541        map* tmpV=getMap(mc,"value");
542        tmpSized=(char*)malloc((atoi(tmp->value)+1)*sizeof(char));
543        memmove(tmpSized,tmpV->value,atoi(tmp->value)*sizeof(char));
544      }
545      if(mc!=NULL){
546        addMapToMap(&res->content,mc);
547      }
548      if(tmp!=NULL){
549        map* tmpV=getMap(res->content,"value");
550        free(tmpV->value);
551        tmpV->value=(char*)malloc((atoi(tmp->value)+1)*sizeof(char));
552        memmove(tmpV->value,tmpSized,atoi(tmp->value)*sizeof(char));
553        tmpV->value[atoi(tmp->value)]=0;
554        free(tmpSized);
555      }
556      res->next=dupMaps(&_cursor->next);
557    }
558    return res;
559  }
560
561  static void addMapsToMaps(maps** mo,maps* mi){
562    maps* tmp=mi;
563    maps* _cursor=*mo;
564    while(tmp!=NULL){
565      if(_cursor==NULL){
566        *mo=dupMaps(&mi);
567        (*mo)->next=NULL;
568      }
569      else{
570        while(_cursor->next!=NULL)
571          _cursor=_cursor->next;
572        _cursor->next=dupMaps(&tmp);
573      }
574      tmp=tmp->next;
575    }
576  }
577
578
579  static void setMapInMaps(maps* m,const char* key,const char* subkey,const char *value){
580    maps* _tmpm=getMaps(m,key);
581    if(_tmpm!=NULL){
582      map* _ztmpm=getMap(_tmpm->content,subkey);
583      if(_ztmpm!=NULL){
584        if(_ztmpm->value!=NULL)
585          free(_ztmpm->value);
586        _ztmpm->value=strdup(value);
587      }else{
588        addToMap(_tmpm->content,subkey,value);
589      }
590    }
591  }
592
593
594  static void dumpElements(elements* e){
595    elements* tmp=e;
596    while(tmp!=NULL){
597      fprintf(stderr,"ELEMENT [%s]\n",tmp->name);
598      fprintf(stderr," > CONTENT [%s]\n",tmp->name);
599      dumpMap(tmp->content);
600      fprintf(stderr," > METADATA [%s]\n",tmp->name);
601      dumpMap(tmp->metadata);
602      fprintf(stderr," > FORMAT [%s]\n",tmp->format);
603      iotype* tmpio=tmp->defaults;
604      int ioc=0;
605      while(tmpio!=NULL){
606        fprintf(stderr," > DEFAULTS [%s] (%i)\n",tmp->name,ioc);
607        dumpMap(tmpio->content);
608        tmpio=tmpio->next;
609        ioc++;
610      }
611      tmpio=tmp->supported;
612      ioc=0;
613      while(tmpio!=NULL){
614        fprintf(stderr," > SUPPORTED [%s] (%i)\n",tmp->name,ioc);
615        dumpMap(tmpio->content);
616        tmpio=tmpio->next;
617        ioc++;
618      }
619      fprintf(stderr,"------------------\n");
620      tmp=tmp->next;
621    }
622  }
623
624  static elements* dupElements(elements* e){
625    elements* cursor=e;
626    elements* tmp=NULL;
627    if(cursor!=NULL){
628#ifdef DEBUG
629      fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
630      dumpElements(e);
631      fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
632#endif
633      tmp=(elements*)malloc(ELEMENTS_SIZE);
634      tmp->name=strdup(e->name);
635      tmp->content=NULL;
636      addMapToMap(&tmp->content,e->content);
637      tmp->metadata=NULL;
638      addMapToMap(&tmp->metadata,e->metadata);
639      tmp->format=strdup(e->format);
640      if(e->defaults!=NULL){
641        tmp->defaults=(iotype*)malloc(IOTYPE_SIZE);
642        tmp->defaults->content=NULL;
643        addMapToMap(&tmp->defaults->content,e->defaults->content);
644        tmp->defaults->next=NULL;
645#ifdef DEBUG
646        fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
647        dumpMap(tmp->defaults->content);
648#endif
649      }else
650        tmp->defaults=NULL;
651      if(e->supported!=NULL){
652        tmp->supported=(iotype*)malloc(IOTYPE_SIZE);
653        tmp->supported->content=NULL;
654        addMapToMap(&tmp->supported->content,e->supported->content);
655        tmp->supported->next=NULL;
656        iotype *tmp2=e->supported->next;
657        while(tmp2!=NULL){
658          addMapToIoType(&tmp->supported,tmp2->content);
659#ifdef DEBUG
660          fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
661          dumpMap(tmp->defaults->content);
662#endif
663          tmp2=tmp2->next;
664        }
665      }
666      else
667        tmp->supported=NULL;
668      tmp->next=dupElements(cursor->next);
669    }
670    return tmp;
671  }
672
673  static void addToElements(elements** m,elements* e){
674    elements* tmp=e;
675    if(*m==NULL){
676      *m=dupElements(tmp);
677    }else{
678      addToElements(&(*m)->next,tmp);
679    }
680  }
681
682  static void dumpService(service* s){
683    fprintf(stderr,"++++++++++++++++++\nSERVICE [%s]\n++++++++++++++++++\n",s->name);
684    if(s->content!=NULL){
685      fprintf(stderr,"CONTENT MAP\n");
686      dumpMap(s->content);
687      fprintf(stderr,"CONTENT METADATA\n");
688      dumpMap(s->metadata);
689    }
690    if(s->inputs!=NULL){
691      fprintf(stderr,"INPUT ELEMENTS [%s]\n------------------\n",s->name);
692      dumpElements(s->inputs);
693    }
694    if(s->outputs!=NULL){
695      fprintf(stderr,"OUTPUT ELEMENTS [%s]\n------------------\n",s->name);
696      dumpElements(s->outputs);
697    }
698    fprintf(stderr,"++++++++++++++++++\n");
699  }
700
701  static void mapsToCharXXX(maps* m,char*** c){
702    maps* tm=m;
703    int i=0;
704    int j=0;
705    char tmp[10][30][1024];
706    memset(tmp,0,1024*10*10);
707    while(tm!=NULL){
708      if(i>=10)
709        break;
710      strcpy(tmp[i][j],"name");
711      j++;
712      strcpy(tmp[i][j],tm->name);
713      j++;
714      map* tc=tm->content;
715      while(tc!=NULL){
716        if(j>=30)
717          break;
718        strcpy(tmp[i][j],tc->name);
719        j++;
720        strcpy(tmp[i][j],tc->value);
721        j++;
722        tc=tc->next;
723      }
724      tm=tm->next;
725      j=0;
726      i++;
727    }
728    memcpy(c,tmp,10*10*1024);
729  }
730
731  static void charxxxToMaps(char*** c,maps**m){
732    maps* trorf=*m;
733    int i,j;
734    char tmp[10][30][1024];
735    memcpy(tmp,c,10*30*1024);
736    for(i=0;i<10;i++){
737      if(strlen(tmp[i][1])==0)
738        break;
739      trorf->name=tmp[i][1];
740      trorf->content=NULL;
741      trorf->next=NULL;
742      for(j=2;j<29;j+=2){
743        if(strlen(tmp[i][j+1])==0)
744          break;
745        if(trorf->content==NULL)
746          trorf->content=createMap(tmp[i][j],tmp[i][j+1]);
747        else
748          addToMap(trorf->content,tmp[i][j],tmp[i][j+1]);
749      }
750      trorf=trorf->next;
751    }
752    m=&trorf;
753  }
754
755#ifdef __cplusplus
756}
757#endif
758
759#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