source: trunk/zoo-project/zoo-kernel/service.c @ 790

Last change on this file since 790 was 790, checked in by djay, 4 years ago

Add support for nested inputs and outputs.

  • Property svn:keywords set to Id
File size: 35.9 KB
Line 
1/*
2 * Author : Gérald FENOY
3 *
4 * Copyright (c) 2015 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#include "service.h"
26
27
28#if defined(_MSC_VER) && _MSC_VER < 1800
29#include <stdarg.h>
30/**
31 * snprintf for Visual Studio compiler.
32 *
33 * See https://dxr.mozilla.org/mozilla-central/source/media/mtransport/third_party/nrappkit/src/util/util.c
34 */
35int snprintf(char *buffer, size_t n, const char *format, ...)
36{
37  va_list argp;
38  int ret;
39  va_start(argp, format);
40  ret = _vscprintf(format, argp);
41  vsnprintf_s(buffer, n, _TRUNCATE, format, argp);
42  va_end(argp);
43  return ret;
44}
45#endif
46
47/**
48 * Dump a map on stderr
49 *
50 * @param t the map to dump
51 */
52void _dumpMap(map* t){
53  if(t!=NULL){
54    fprintf(stderr,"%s: %s\n",t->name,t->value);
55    fflush(stderr);
56  }else{
57    fprintf(stderr,"NULL\n");
58    fflush(stderr);
59  }
60}
61
62/**
63 * Dump a map on stderr, see _dumpMap()
64 *
65 * @param t the map to dump
66 */
67void dumpMap(map* t){
68  map* tmp=t;
69  while(tmp!=NULL){
70    _dumpMap(tmp);
71    tmp=tmp->next;
72  }
73}
74
75/**
76 * Dump a map to a file
77 *
78 * @param t the map to dump to file
79 * @param file the file pointer to store the map
80 */
81void dumpMapToFile(map* t,FILE* file){
82  map* tmp=t;
83  while(tmp!=NULL){
84    fprintf(file,"%s = %s\n",tmp->name,tmp->value);
85    tmp=tmp->next;
86  }
87}
88
89/**
90 * Dump a maps on stderr, see dumpMap().
91 *
92 * @param m the map to dump
93 */
94void dumpMaps(maps* m){
95  maps* tmp=m;
96  while(tmp!=NULL){
97    fprintf(stderr,"MAP => [%s] \n",tmp->name);
98    fprintf(stderr," * CONTENT [%s] \n",tmp->name);
99    dumpMap(tmp->content);
100    fprintf(stderr," * CHILD [%s] \n",tmp->name);
101    dumpMaps(tmp->child);
102    tmp=tmp->next;
103  }
104}
105
106/**
107 * Dump a maps to a file, see dumpMapToFile().
108 *
109 * @param m the map to dump
110 * @param file the the file pointer to store the map
111 */
112void _dumpMapsToFile(maps* m,FILE* file,int limit){
113  maps* tmp=m;
114  int cnt=0;
115  while(tmp!=NULL){
116    fprintf(file,"[%s]\n",tmp->name);
117    if(tmp->child!=NULL){
118      _dumpMapsToFile(tmp->child,file,limit);
119    }else
120      dumpMapToFile(tmp->content,file);
121    fflush(file);
122    tmp=tmp->next;
123    cnt++;
124    if(limit>=0 && cnt==limit)
125      tmp=NULL;
126  }
127  fflush(file);
128}
129
130/**
131 * Dump a maps to a file, see _dumpMapsToFile().
132 *
133 * @param m the map to dump
134 * @param file_path the full path to the file name to store the map
135 * @param limit the number limiting the maps to be dumped
136 */
137void dumpMapsToFile(maps* m,char* file_path,int limit){
138  FILE* file=fopen(file_path,"w+");
139  _dumpMapsToFile(m,file,limit);
140  fflush(file);
141  fclose(file);
142}
143
144/**
145 * Create a new map
146 *
147 * @param name the key to add to the map
148 * @param value the corresponding value to add to the map
149 * @return a pointer to the allocated map
150 */
151map* createMap(const char* name,const char* value){
152  map* tmp=(map *)malloc(MAP_SIZE);
153  tmp->name=zStrdup(name);
154  tmp->value=zStrdup(value);
155  tmp->next=NULL;
156  return tmp;
157}
158
159/**
160 * Create a new maps with the given name
161 *
162 * @param name of the maps
163 * @return the allocated map
164 */
165maps* createMaps(const char* name){
166  maps* tmp = (maps *) malloc (MAPS_SIZE);
167  tmp->name = zStrdup (name);
168  tmp->content = NULL;
169  tmp->child = NULL;
170  tmp->next = NULL;
171  return tmp;
172}
173
174/**
175 * Count number of map in a map
176 *
177 * @param m the maps to count
178 * @return number of map in a map
179 */
180int count(map* m){
181  map* tmp=m;
182  int c=0;
183  while(tmp!=NULL){
184    c++;
185    tmp=tmp->next;
186  }
187  return c;
188}
189
190/**
191 * Verify if a key exist in a map
192 *
193 * @param m the map to search for the key
194 * @param key the key to search in the map
195 * @return true if the key wwas found, false in other case
196 */
197bool hasKey(map* m,const char *key){
198  map* tmp=m;
199  while(tmp!=NULL){
200    if(strcasecmp(tmp->name,key)==0)
201      return true;
202    tmp=tmp->next;
203  }
204#ifdef DEBUG_MAP
205  fprintf(stderr,"NOT FOUND \n");
206#endif
207  return false;
208}
209
210/**
211 * Access a specific maps
212 *
213 * @param m the maps to search for the key
214 * @param key the key to search in the maps
215 * @return a pointer on the maps found or NULL if not found
216 */
217maps* getMaps(maps* m,const char *key){
218  maps* tmp=m;
219  while(tmp!=NULL){
220    if(strcasecmp(tmp->name,key)==0){
221      return tmp;
222    }
223    tmp=tmp->next;
224  }
225  return NULL;
226}
227
228/**
229 * Access a specific map
230 *
231 * @param m the map to search for the key
232 * @param key the key to search in the map
233 * @return a pointer on the map found or NULL if not found
234 */
235map* getMap(map* m,const char *key){
236  map* tmp=m;
237  while(tmp!=NULL){
238    if(strcasecmp(tmp->name,key)==0){
239      return tmp;
240    }
241    tmp=tmp->next;
242  }
243  return NULL;
244}
245
246
247/**
248 * Access the last map
249 *
250 * @param m the map to search for the lastest map
251 * @return a pointer on the lastest map found or NULL if not found
252 */
253map* getLastMap(map* m){
254  map* tmp=m;
255  while(tmp!=NULL){
256    if(tmp->next==NULL){
257      return tmp;
258    }
259    tmp=tmp->next;
260  }
261  return NULL;
262}
263
264/**
265 * Access a specific map from a maps
266 *
267 * @param m the maps to search for the key
268 * @param key the key to search in the maps
269 * @param subkey the key to search in the map (found for the key, if any)
270 * @return a pointer on the map found or NULL if not found
271 */
272map* getMapFromMaps(maps* m,const char* key,const char* subkey){
273  maps* _tmpm=getMaps(m,key);
274  if(_tmpm!=NULL){
275    map* _ztmpm=getMap(_tmpm->content,subkey);
276    return _ztmpm;
277  }
278  else return NULL;
279}
280
281/**
282 * Free allocated memory of a map.
283 * Require to call free on mo after calling this function.
284 *
285 * @param mo the map to free
286 */
287void freeMap(map** mo){
288  map* _cursor=*mo;
289  if(_cursor!=NULL){
290#ifdef DEBUG
291    fprintf(stderr,"freeMap\n");
292#endif
293    free(_cursor->name);
294    free(_cursor->value);
295    if(_cursor->next!=NULL){
296      freeMap(&_cursor->next);
297      free(_cursor->next);
298    }
299  }
300}
301
302/**
303 * Free allocated memory of a maps.
304 * Require to call free on mo after calling this function.
305 *
306 * @param mo the maps to free
307 */
308void freeMaps(maps** mo){
309  maps* _cursor=*mo;
310  if(_cursor && _cursor!=NULL){
311#ifdef DEBUG
312    fprintf(stderr,"freeMaps\n");
313#endif
314    free(_cursor->name);
315    if(_cursor->content!=NULL){
316      freeMap(&_cursor->content);
317      free(_cursor->content);
318    }
319    if(_cursor->child!=NULL){
320      freeMaps(&_cursor->child);
321      free(_cursor->child);
322    }
323    if(_cursor->next!=NULL){
324      freeMaps(&_cursor->next);
325      free(_cursor->next);
326    }
327  }
328}
329
330/**
331 * Verify if an elements contains a name equal to the given key.
332 *
333 * @param e the elements to search for the key
334 * @param key the elements name to search
335 * @return true if the elements contains the name, false in other cases.
336 */ 
337bool hasElement(elements* e,const char* key){
338  elements* tmp=e;
339  while(tmp!=NULL){
340    if(strcasecmp(key,tmp->name)==0)
341      return true;
342    tmp=tmp->next;
343  }
344  return false;
345}
346
347/**
348 * Access a specific elements named key.
349 *
350 * @param m the elements to search
351 * @param key the elements name to search
352 * @return a pointer to the specific element if found, NULL in other case.
353 */ 
354elements* getElements(elements* m,char *key){
355  elements* tmp=m;
356  while(tmp!=NULL){
357    if(strcasecmp(tmp->name,key)==0)
358      return tmp;
359    tmp=tmp->next;
360  }
361  return NULL;
362}
363
364/**
365 * Free allocated memory of an iotype.
366 * Require to call free on i after calling this function.
367 *
368 * @param i the iotype to free
369 */
370void freeIOType(iotype** i){
371  iotype* _cursor=*i;
372  if(_cursor!=NULL){
373    if(_cursor->next!=NULL){
374      freeIOType(&_cursor->next);
375      free(_cursor->next);
376    }
377    freeMap(&_cursor->content);
378    free(_cursor->content);
379  }
380}
381
382/**
383 * Free allocated memory of an elements.
384 * Require to call free on e after calling this function.
385 *
386 * @param e the iotype to free
387 */
388void freeElements(elements** e){
389  elements* tmp=*e;
390  if(tmp!=NULL){
391    if(tmp->name!=NULL)
392      free(tmp->name);
393    freeMap(&tmp->content);
394    if(tmp->content!=NULL)
395      free(tmp->content);
396    freeMap(&tmp->metadata);
397    if(tmp->metadata!=NULL)
398      free(tmp->metadata);
399    if(tmp->format!=NULL)
400      free(tmp->format);
401    if(tmp->child!=NULL){
402      freeElements(&tmp->child);
403      free(tmp->child);
404    }
405    freeIOType(&tmp->defaults);
406    if(tmp->defaults!=NULL)
407      free(tmp->defaults);
408    freeIOType(&tmp->supported);
409    if(tmp->supported!=NULL){
410      free(tmp->supported);
411    }
412    freeElements(&tmp->next);
413    if(tmp->next!=NULL)
414      free(tmp->next);
415  }
416}
417
418/**
419 * Free allocated memory of a service.
420 * Require to call free on e after calling this function.
421 *
422 * @param s the service to free
423 */
424void freeService(service** s){
425  service* tmp=*s;
426  if(tmp!=NULL){
427    if(tmp->name!=NULL)
428      free(tmp->name);
429    freeMap(&tmp->content);
430    if(tmp->content!=NULL)
431      free(tmp->content);
432    freeMap(&tmp->metadata);
433    if(tmp->metadata!=NULL)
434      free(tmp->metadata);
435    freeElements(&tmp->inputs);
436    if(tmp->inputs!=NULL)
437      free(tmp->inputs);
438    freeElements(&tmp->outputs);
439    if(tmp->outputs!=NULL)
440      free(tmp->outputs);
441  }
442}
443
444/**
445 * Add key value pair to an existing map.
446 *
447 * @param m the map to add the KVP
448 * @param n the key to add
449 * @param v the corresponding value to add
450 */
451void addToMap(map* m,const char* n,const char* v){
452  if(hasKey(m,n)==false){
453    map* _cursor=m;
454    while(_cursor->next!=NULL){
455      _cursor=_cursor->next;
456    }
457    _cursor->next=createMap(n,v);
458  }
459  else{
460    map *tmp=getMap(m,n);
461    if(tmp->value!=NULL)
462      free(tmp->value);
463    tmp->value=zStrdup(v);
464  }
465}
466
467/**
468 * Add a key and an integer value to an existing map.
469 *
470 * @param m the map to add the KVP
471 * @param n the key to add
472 * @param v the corresponding value to add
473 */
474void addIntToMap(map* m,const char* n,const int v){
475  char svalue[10];
476  sprintf(svalue,"%d",v);
477  if(hasKey(m,n)==false){
478    map* _cursor=m;
479    while(_cursor->next!=NULL){
480      _cursor=_cursor->next;
481    }
482    _cursor->next=createMap(n,svalue);
483  }
484  else{
485    map *tmp=getMap(m,n);
486    if(tmp->value!=NULL)
487      free(tmp->value);
488    tmp->value=zStrdup(svalue);
489  }
490}
491
492/**
493 * Add a key and a binary value to an existing map.
494 *
495 * @param m the map to add the KVP
496 * @param n the key to add
497 * @param v the corresponding value to add
498 * @param size the size of the given value
499 * @return a pointer to the updated map m
500 */
501map* addToMapWithSize(map* m,const char* n,const char* v,int size){
502  if(hasKey(m,n)==false){
503    map* _cursor=m;
504    if(_cursor!=NULL){
505      addToMap(m,n,"");
506    }else{
507      m=createMap(n,"");
508    }
509  }
510  char sname[10]="size";
511  if(strlen(n)>5)
512    sprintf(sname,"size_%s",n+6);
513  map *tmp=getMap(m,n);
514  if(tmp->value!=NULL)
515    free(tmp->value);
516  tmp->value=(char*)malloc((size+1)*sizeof(char));
517  memmove(tmp->value,v,size*sizeof(char));
518  tmp->value[size]=0;
519  char sin[128];
520  sprintf(sin,"%d",size);
521  addToMap(m,sname,sin);
522  return m;
523}
524
525/**
526 * Add a map at the end of another map.
527 *
528 * @param mo the map to add mi
529 * @param mi the map to add to mo
530 */
531void addMapToMap(map** mo,map* mi){
532  map* tmp=mi;
533  map* _cursor=*mo;
534  while(tmp!=NULL){
535    if(_cursor==NULL){
536      *mo=createMap(tmp->name,tmp->value);
537      (*mo)->next=NULL;
538    }
539    else{
540#ifdef DEBUG
541      fprintf(stderr,"_CURSOR\n");
542      dumpMap(_cursor);
543#endif
544      while(_cursor->next!=NULL)
545        _cursor=_cursor->next;
546      map* tmp1=getMap(*mo,tmp->name);
547      if(tmp1==NULL){
548        _cursor->next=createMap(tmp->name,tmp->value);
549      }
550      else{
551        addToMap(*mo,tmp->name,tmp->value);
552      }
553    }
554    _cursor=*mo;
555    tmp=tmp->next;
556#ifdef DEBUG
557    fprintf(stderr,"MO\n");
558    dumpMap(*mo);
559#endif
560  }
561}
562
563/**
564 * Add a map to iotype.
565 *
566 * @param io the iotype to add the map
567 * @param mi the map to add to io
568 */
569void addMapToIoType(iotype** io,map* mi){
570  iotype* tmp=*io;
571  while(tmp->next!=NULL){
572    tmp=tmp->next;
573  }
574  tmp->next=(iotype*)malloc(IOTYPE_SIZE);
575  tmp->next->content=NULL;
576  addMapToMap(&tmp->next->content,mi);
577  tmp->next->next=NULL;
578}
579
580/**
581 * Access a specific map or set its value.
582 *
583 * @param m the map to search for the key
584 * @param key the key to search/add in the map
585 * @param value the value to add if the key does not exist
586 * @return a pointer on the map found or NULL if not found
587 */
588map* getMapOrFill(map** m,const char *key,const char* value){
589  map* tmp=*m;
590  map* tmpMap=getMap(tmp,key);
591  if(tmpMap==NULL){
592    if(tmp!=NULL){
593      addToMap((*m),key,value);
594    }
595    else
596      (*m)=createMap(key,value);
597    tmpMap=getMap(*m,key);
598  }
599  return tmpMap;
600}
601
602/**
603 * Verify if a map is contained in another map.
604 *
605 * @param m the map to search for i
606 * @param i the map to search in m
607 * @return true if i was found in m, false in other case
608 */
609bool contains(map* m,map* i){
610  while(i!=NULL){     
611    if(strcasecmp(i->name,"value")!=0 &&
612       strcasecmp(i->name,"xlink:href")!=0 &&
613       strcasecmp(i->name,"useMapServer")!=0 &&
614       strcasecmp(i->name,"asReference")!=0){
615      map *tmp;
616      if(hasKey(m,i->name) && (tmp=getMap(m,i->name))!=NULL && 
617         strcasecmp(i->value,tmp->value)!=0)
618        return false;
619    }
620    i=i->next;
621  }
622  return true;
623}
624
625/**
626 * Access a specific iotype from an elements.
627 *
628 * @param e the elements to search for the name
629 * @param name the name to search in the elements e
630 * @param values the map to verify it was contained in the defaults or
631 *  supported content of the elements e
632 * @return a pointer on the iotype found or NULL if not found
633 */
634iotype* getIoTypeFromElement(elements* e,char *name, map* values){
635  elements* cursor=e;
636  if(values!=NULL)
637    while(cursor!=NULL){
638      if(strcasecmp(cursor->name,name)==0 && (cursor->defaults!=NULL || cursor->supported!=NULL)){
639        if(contains(cursor->defaults->content,values)==true)
640          return cursor->defaults;
641        else{
642          iotype* tmp=cursor->supported;
643          while(tmp!=NULL){
644            if(contains(tmp->content,values)==true)
645              return tmp;           
646            tmp=tmp->next;
647          }
648        }
649      }
650      cursor=cursor->next;
651    }
652  return NULL;
653}
654
655/**
656 * Load binary values from a map (in) and add them to another map (out)
657 *
658 * @param out the map to add binaries values
659 * @param in the map containing the binary values to add ti out
660 * @param pos index of the binary in an array (in case of "MapArray")
661 */
662void loadMapBinary(map** out,map* in,int pos){
663  map* size=getMap(in,"size");
664  map *lout=*out;
665  if(size!=NULL && pos>0){
666    char tmp[11];
667    sprintf(tmp,"size_%d",pos);
668    size=getMap(in,tmp);
669    sprintf(tmp,"value_%d",pos);
670    map* tmpVin=getMap(in,tmp);
671    map* tmpVout=getMap(lout,tmp);
672    free(tmpVout->value);
673    tmpVout->value=(char*)malloc((atoi(size->value)+1)*sizeof(char));
674    memmove(tmpVout->value,tmpVin->value,atoi(size->value)*sizeof(char));
675    tmpVout->value[atoi(size->value)]=0;
676  }else{
677    if(size!=NULL){
678      map* tmpVin=getMap(in,"value");
679      map* tmpVout=getMap(lout,"value");
680      free(tmpVout->value);
681      tmpVout->value=(char*)malloc((atoi(size->value)+1)*sizeof(char));
682      memmove(tmpVout->value,tmpVin->value,atoi(size->value)*sizeof(char));
683      tmpVout->value[atoi(size->value)]=0;
684    }
685  }
686}
687 
688/**
689 * Load binary values from a map (in) and add them to another map (out).
690 * This function will take care of MapArray.
691 * @see loadMapBinary
692 *
693 * @param out the map to add binaries values
694 * @param in the map containing the binary values to add ti out
695 */
696void loadMapBinaries(map** out,map* in){
697  map* size=getMap(in,"size");
698  map* length=getMap(in,"length");
699  if(length!=NULL){
700    int len=atoi(length->value);
701    int i=0;
702    for(i=0;i<len;i++){
703      loadMapBinary(out,in,i);
704    }
705  }
706  else
707    if(size!=NULL)
708      loadMapBinary(out,in,-1);
709}
710
711/**
712 * Duplicate a Maps
713 *
714 * @param mo the maps to clone
715 * @return the allocated maps containing a copy of the mo maps
716 */
717maps* dupMaps(maps** mo){
718  maps* _cursor=*mo;
719  maps* res=NULL;
720  if(_cursor!=NULL){
721    res=createMaps(_cursor->name);
722    map* mc=_cursor->content;
723    if(mc!=NULL){
724      addMapToMap(&res->content,mc);
725      loadMapBinaries(&res->content,mc);
726    }
727    maps* mcs=_cursor->child;
728    if(mcs!=NULL){
729      res->child=dupMaps(&mcs);
730    }
731    res->next=dupMaps(&_cursor->next);
732  }
733  return res;
734}
735
736/**
737 * Add a maps at the end of another maps.
738 *
739 * @see addMapToMap, dupMaps, getMaps
740 * @param mo the maps to add mi
741 * @param mi the maps to add to mo
742 */
743void addMapsToMaps(maps** mo,maps* mi){
744  maps* tmp=mi;
745  maps* _cursor=*mo;
746  while(tmp!=NULL){
747    if(_cursor==NULL){
748      *mo=dupMaps(&mi);
749    }
750    else{
751      while(_cursor->next!=NULL)
752        _cursor=_cursor->next;
753      maps* tmp1=getMaps(*mo,tmp->name);
754      if(tmp1==NULL){
755        _cursor->next=dupMaps(&tmp);
756        if(tmp->child!=NULL)
757          _cursor->next->child=dupMaps(&tmp->child);
758        else
759          _cursor->next->child=NULL;
760      }
761      else{
762        addMapToMap(&tmp1->content,tmp->content);
763        if(tmp->child!=NULL)
764          tmp1->child=dupMaps(&tmp->child);
765        else
766          tmp1->child=NULL;
767      }
768      _cursor=*mo;
769    }
770    tmp=tmp->next;
771  }
772}
773
774/**
775 * Access a specific map array element
776 *
777 * @param m the map to search for the key
778 * @param key the key to search in the map
779 * @param index of the MapArray
780 * @return a pointer on the map found or NULL if not found
781 */
782map* getMapArray(map* m,const char* key,int index){
783  char tmp[1024];
784  if(index>0)
785    sprintf(tmp,"%s_%d",key,index);
786  else
787    sprintf(tmp,"%s",key);
788#ifdef DEBUG
789  fprintf(stderr,"** KEY %s\n",tmp);
790#endif
791  map* tmpMap=getMap(m,tmp);
792#ifdef DEBUG
793  if(tmpMap!=NULL)
794    dumpMap(tmpMap);
795#endif
796  return tmpMap;
797}
798
799/**
800 * Add a key value in a MapArray for a specific index
801 *
802 * @param m the map to search for the key
803 * @param key the key to search in the map
804 * @param index the index of the MapArray
805 * @param value the value to set in the MapArray
806 * @return a pointer on the map found or NULL if not found
807 */
808void setMapArray(map* m,const char* key,int index,const char* value){
809  char tmp[1024];
810  if(index>0){
811    sprintf(tmp,"%s_%d",key,index);
812    map* len=getMap(m,"length");
813    if((len!=NULL && atoi(len->value)<index+1) || len==NULL){
814      char tmp0[5];
815      sprintf(tmp0,"%d",index+1);
816      addToMap(m,"length",tmp0);
817    }
818  }
819  else
820    sprintf(tmp,"%s",key);
821  map* tmpSize=getMapArray(m,"size",index);
822  if(tmpSize!=NULL && strncasecmp(key,"value",5)==0){
823#ifdef DEBUG
824    fprintf(stderr,"%s\n",tmpSize->value);
825#endif
826    map* ptr=getMapOrFill(&m,tmp,(char *)"");
827    free(ptr->value);
828    ptr->value=(char*)malloc((atoi(tmpSize->value)+1)*sizeof(char));
829    memcpy(ptr->value,value,atoi(tmpSize->value)); 
830  }
831  else
832    addToMap(m,tmp,value);
833}
834
835/**
836 * Access the map "type"
837 *
838 * @param mt the map
839 * @return a pointer on the map for mimeType/dataType/CRS if found, NULL in
840 *  other case
841 */
842map* getMapType(map* mt){
843  map* tmap=getMap(mt,(char *)"mimeType");
844  if(tmap==NULL){
845    tmap=getMap(mt,"dataType");
846    if(tmap==NULL){
847      tmap=getMap(mt,"CRS");
848    }
849  }
850#ifdef DEBUG
851  dumpMap(tmap);
852#endif
853  return tmap;
854}
855
856/**
857 * Add a Maps containing a MapArray to a Maps
858 *
859 * @see getMapType
860 * @param mo the maps
861 * @param mi the maps
862 * @param typ the map "type"
863 * @return
864 */
865int addMapsArrayToMaps(maps** mo,maps* mi,char* typ){
866  maps* tmp=mi;   
867  maps* _cursor=getMaps(*mo,tmp->name);
868
869  if(_cursor==NULL)
870    return -1;
871
872  map* tmpLength=getMap(_cursor->content,"length");
873  char tmpLen[10];
874  int len=1;
875  if(tmpLength!=NULL){
876    len=atoi(tmpLength->value);
877  }
878
879  char *tmpV[12]={
880    (char*)"size",
881    (char*)"value",
882    (char*)"uom",
883    (char*)"Reference",
884    (char*)"Order",
885    (char*)"cache_file",
886    (char*)"fmimeType",
887    (char*)"xlink:href",
888    typ,
889    (char*)"schema",
890    (char*)"encoding",
891    (char*)"isCached"
892  };
893  sprintf(tmpLen,"%d",len+1);
894  addToMap(_cursor->content,"length",tmpLen);
895  int i=0;
896  for(i=0;i<12;i++){
897    map* tmpVI=getMap(tmp->content,tmpV[i]);
898    if(tmpVI!=NULL){
899#ifdef DEBUG
900      fprintf(stderr,"%s = %s\n",tmpV[i],tmpVI->value);
901#endif
902      setMapArray(_cursor->content,tmpV[i],len,tmpVI->value);
903    }
904  }
905   
906  addToMap(_cursor->content,"isArray","true");
907  return 0;
908}
909
910/**
911 * Set a key value pair to a map contained in a Maps
912 *
913 * @param m the maps
914 * @param key the maps name
915 * @param subkey the map name included in the maps corresponding to key
916 * @param value the corresponding value to add in the map
917 */
918void setMapInMaps(maps* m,const char* key,const char* subkey,const char *value){
919  maps* _tmpm=getMaps(m,key);
920  if(_tmpm!=NULL){
921    map* _ztmpm=getMap(_tmpm->content,subkey);
922    if(_ztmpm!=NULL){
923      if(_ztmpm->value!=NULL)
924        free(_ztmpm->value);
925      _ztmpm->value=zStrdup(value);
926    }else{
927      maps *tmp=createMaps(key);
928      tmp->content=createMap(subkey,value);
929      addMapsToMaps(&_tmpm,tmp);
930      freeMaps(&tmp);
931      free(tmp);
932    }
933  }else{
934    maps *tmp=createMaps(key);
935    tmp->content=createMap(subkey,value);
936    addMapsToMaps(&m,tmp);
937    freeMaps(&tmp);
938    free(tmp);
939  }
940}
941
942/**
943 * Create an empty elements
944 *
945 * @return a pointer to the allocated elements
946 */
947elements* createEmptyElements(){
948  elements* res=(elements*)malloc(ELEMENTS_SIZE);
949  res->name=NULL;
950  res->content=NULL;
951  res->metadata=NULL;
952  res->format=NULL;
953  res->defaults=NULL;
954  res->supported=NULL;
955  res->child=NULL;
956  res->next=NULL;
957  return res;
958}
959
960/**
961 * Create a named elements
962 *
963 * @param name the elements name
964 * @return a pointer to the allocated elements
965 */
966elements* createElements(char* name){
967  elements* res=(elements*)malloc(ELEMENTS_SIZE);
968  res->name=zStrdup(name);
969  res->content=NULL;
970  res->metadata=NULL;
971  res->format=NULL;
972  res->defaults=NULL;
973  res->supported=NULL;
974  res->child=NULL;
975  res->next=NULL;
976  return res;
977}
978
979/**
980 * Set the name of an elements
981 *
982 * @param name the elements name
983 * @return a pointer to the allocated elements
984 */
985void setElementsName(elements** elem,char* name){
986  elements* res=*elem;
987  res->name=zStrdup(name);
988  res->content=NULL;
989  res->metadata=NULL;
990  res->format=NULL;
991  res->defaults=NULL;
992  res->supported=NULL;
993  res->child=NULL;
994  res->next=NULL;
995}
996
997/**
998 * Dump an elements on stderr
999 *
1000 * @param e the elements to dump
1001 */
1002void dumpElements(elements* e){
1003  elements* tmp=e;
1004  while(tmp!=NULL){
1005    fprintf(stderr,"ELEMENT [%s]\n",tmp->name);
1006    fprintf(stderr," > CONTENT [%s]\n",tmp->name);
1007    dumpMap(tmp->content);
1008    fprintf(stderr," > METADATA [%s]\n",tmp->name);
1009    dumpMap(tmp->metadata);
1010    fprintf(stderr," > FORMAT [%s]\n",tmp->format);
1011    iotype* tmpio=tmp->defaults;
1012    int ioc=0;
1013    while(tmpio!=NULL){
1014      fprintf(stderr," > DEFAULTS [%s] (%i)\n",tmp->name,ioc);
1015      dumpMap(tmpio->content);
1016      tmpio=tmpio->next;
1017      ioc++;
1018    }
1019    tmpio=tmp->supported;
1020    ioc=0;
1021    while(tmpio!=NULL){
1022      fprintf(stderr," > SUPPORTED [%s] (%i)\n",tmp->name,ioc);
1023      dumpMap(tmpio->content);
1024      tmpio=tmpio->next;
1025      ioc++;
1026    }
1027    if(tmp->child!=NULL){
1028      fprintf(stderr," > CHILD \n");
1029      dumpElements(tmp->child);
1030    }
1031    fprintf(stderr,"------------------\n");
1032    tmp=tmp->next;
1033  }
1034}
1035
1036/**
1037 * Dump an elements on stderr using the YAML syntaxe
1038 *
1039 * @param e the elements to dump
1040 */
1041void dumpElementsAsYAML(elements* e,int level){
1042  elements* tmp=e;
1043  int i;
1044  while(tmp!=NULL){
1045    for(i=0;i<2+(4*level);i++)
1046      fprintf(stderr," ");
1047    fprintf(stderr,"%s:\n",tmp->name);
1048    map* mcurs=tmp->content;
1049    while(mcurs!=NULL){
1050      for(i=0;i<4+(4*level);i++)
1051        fprintf(stderr," ");
1052      _dumpMap(mcurs);
1053      mcurs=mcurs->next;
1054    }
1055    mcurs=tmp->metadata;
1056    if(mcurs!=NULL){
1057      for(i=0;i<4+(4*level);i++)
1058        fprintf(stderr," ");
1059      fprintf(stderr,"MetaData:\n");
1060      while(mcurs!=NULL){
1061        for(i=0;i<6+(4*level);i++)
1062          fprintf(stderr," ");
1063        _dumpMap(mcurs);
1064        mcurs=mcurs->next;
1065      }
1066    }
1067    for(i=0;i<4+(4*level);i++)
1068      fprintf(stderr," ");
1069    if(tmp->format!=NULL)
1070      fprintf(stderr,"%s:\n",tmp->format);
1071    else{
1072      fprintf(stderr,"Child:\n");
1073      if(tmp->child!=NULL)
1074        dumpElementsAsYAML(tmp->child,level+1);
1075    }
1076    iotype* tmpio=tmp->defaults;
1077    int ioc=0;
1078    while(tmpio!=NULL){
1079      for(i=0;i<6+(4*level);i++)
1080        fprintf(stderr," ");
1081      fprintf(stderr,"default:\n");
1082      mcurs=tmpio->content;
1083      while(mcurs!=NULL){
1084        for(i=0;i<8+(4*level);i++)
1085          fprintf(stderr," ");
1086        if(strcasecmp(mcurs->name,"range")==0){
1087          fprintf(stderr,"range: \"%s\"\n",mcurs->value);
1088        }else
1089          _dumpMap(mcurs);
1090        mcurs=mcurs->next;
1091      }
1092      tmpio=tmpio->next;
1093      ioc++;
1094    }
1095    tmpio=tmp->supported;
1096    ioc=0;
1097    while(tmpio!=NULL){
1098      for(i=0;i<6+(4*level);i++)
1099        fprintf(stderr," ");
1100      fprintf(stderr,"supported:\n");
1101      mcurs=tmpio->content;
1102      while(mcurs!=NULL){
1103        for(i=0;i<8+(4*level);i++)
1104          fprintf(stderr," ");
1105        if(strcasecmp(mcurs->name,"range")==0){
1106          fprintf(stderr,"range: \"%s\"\n",mcurs->value);
1107        }else
1108          _dumpMap(mcurs);
1109        mcurs=mcurs->next;
1110      }
1111      tmpio=tmpio->next;
1112      ioc++;
1113    }
1114    tmp=tmp->next;
1115  }
1116}
1117
1118/**
1119 * Duplicate an elements
1120 *
1121 * @param e the elements to clone
1122 * @return the allocated elements containing a copy of the elements e
1123 */
1124elements* dupElements(elements* e){
1125  elements* cursor=e;
1126  elements* tmp=NULL;
1127  if(cursor!=NULL){
1128#ifdef DEBUG
1129    fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
1130    dumpElements(e);
1131    fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
1132#endif
1133    tmp=(elements*)malloc(ELEMENTS_SIZE);
1134    tmp->name=zStrdup(e->name);
1135    tmp->content=NULL;
1136    addMapToMap(&tmp->content,e->content);
1137    tmp->metadata=NULL;
1138    addMapToMap(&tmp->metadata,e->metadata);
1139    if(e->format!=NULL)
1140      tmp->format=zStrdup(e->format);
1141    else
1142      tmp->format=NULL;
1143    if(e->defaults!=NULL){
1144      tmp->defaults=(iotype*)malloc(IOTYPE_SIZE);
1145      tmp->defaults->content=NULL;
1146      addMapToMap(&tmp->defaults->content,e->defaults->content);
1147      tmp->defaults->next=NULL;
1148#ifdef DEBUG
1149      fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
1150      dumpMap(tmp->defaults->content);
1151#endif
1152    }else
1153      tmp->defaults=NULL;
1154    if(e->supported!=NULL){
1155      tmp->supported=(iotype*)malloc(IOTYPE_SIZE);
1156      tmp->supported->content=NULL;
1157      addMapToMap(&tmp->supported->content,e->supported->content);
1158      tmp->supported->next=NULL;
1159      iotype *tmp2=e->supported->next;
1160      while(tmp2!=NULL){
1161        addMapToIoType(&tmp->supported,tmp2->content);
1162#ifdef DEBUG
1163        fprintf(stderr,">> %s %i\n",__FILE__,__LINE__);
1164        dumpMap(tmp->defaults->content);
1165#endif
1166        tmp2=tmp2->next;
1167      }
1168    }
1169    else
1170      tmp->supported=NULL;
1171    if(cursor->child!=NULL)
1172      tmp->child=dupElements(cursor->child);
1173    else
1174      tmp->child=NULL;
1175    tmp->next=dupElements(cursor->next);
1176  }
1177  return tmp;
1178}
1179
1180/**
1181 * Add an elements to another elements.
1182 *
1183 * @see dupElements
1184 * @param m the elements to add the e
1185 * @param e the elements to be added to m
1186 */
1187void addToElements(elements** m,elements* e){
1188  elements* tmp=e;
1189  if(*m==NULL){
1190    *m=dupElements(tmp);
1191  }else{
1192    addToElements(&(*m)->next,tmp);
1193  }
1194}
1195
1196/**
1197 * Set the name of a service
1198 *
1199 * @param name the service name
1200 */
1201void setServiceName(service** serv,char* name){
1202  service* res=*serv;
1203  res->name=zStrdup(name);
1204  res->content=NULL;
1205  res->metadata=NULL;
1206  res->inputs=NULL;
1207  res->outputs=NULL;
1208}
1209
1210/**
1211 * Dump a service on stderr
1212 *
1213 * @param s the service to dump
1214 */
1215void dumpService(service* s){
1216  if(s==NULL)
1217    return;
1218  fprintf(stderr,"++++++++++++++++++\nSERVICE [%s]\n++++++++++++++++++\n",s->name);
1219  if(s->content!=NULL){
1220    fprintf(stderr,"CONTENT MAP\n");
1221    dumpMap(s->content);
1222    fprintf(stderr,"CONTENT METADATA\n");
1223    dumpMap(s->metadata);
1224  }
1225  if(s->inputs!=NULL){
1226    fprintf(stderr,"INPUT ELEMENTS [%s]\n------------------\n",s->name);
1227    dumpElements(s->inputs);
1228  }
1229  if(s->outputs!=NULL){
1230    fprintf(stderr,"OUTPUT ELEMENTS [%s]\n------------------\n",s->name);
1231    dumpElements(s->outputs);
1232  }
1233  fprintf(stderr,"++++++++++++++++++\n");
1234}
1235
1236/**
1237 * Dump a service on stderr using the YAML syntaxe
1238 *
1239 * @param s the service to dump
1240 */
1241void dumpServiceAsYAML(service* s){
1242  int i;
1243  fprintf(stderr,"# %s\n\n",s->name);
1244  if(s->content!=NULL){
1245    map* mcurs=s->content;
1246    dumpMap(mcurs);
1247    mcurs=s->metadata;
1248    if(mcurs!=NULL){
1249      fprintf(stderr,"MetaData:\n");
1250      while(mcurs!=NULL){
1251        for(i=0;i<2;i++)
1252          fprintf(stderr," ");
1253        _dumpMap(mcurs);
1254        mcurs=mcurs->next;
1255      }
1256    }
1257  }
1258  if(s->inputs!=NULL){
1259    fprintf(stderr,"\ninputs:\n");
1260    dumpElementsAsYAML(s->inputs,0);
1261  }
1262  if(s->outputs!=NULL){
1263    fprintf(stderr,"\noutputs:\n");
1264    dumpElementsAsYAML(s->outputs,0);
1265  }
1266}
1267
1268/**
1269 * Duplicate a service
1270 *
1271 * @param s the service to clone
1272 * @return the allocated service containing a copy of the serfvice s
1273 */
1274service* dupService(service* s){
1275  service *res=(service*)malloc(SERVICE_SIZE);
1276  res->name=zStrdup(s->name);
1277  res->content=NULL;
1278  addMapToMap(&res->content,s->content);
1279  res->metadata=NULL;
1280  addMapToMap(&res->metadata,s->metadata);
1281  res->inputs=dupElements(s->inputs);
1282  res->outputs=dupElements(s->outputs);
1283  return res;
1284}
1285
1286/**
1287 * Print the registry on stderr.
1288 *
1289 * @param r the registry
1290 */
1291void dumpRegistry(registry* r){
1292  registry* p=r;
1293  while(p!=NULL){
1294    fprintf(stderr,"%s \n",p->name);
1295    services* s=p->content;
1296    s=p->content;
1297    while(s!=NULL){
1298      dumpService(s->content);
1299      s=s->next;
1300    }
1301    p=p->next;
1302  }
1303}
1304
1305/**
1306 * Add a service to the registry
1307 *
1308 * @param reg the resgitry to add the service
1309 * @param name the registry name to update
1310 * @param content the service to add
1311 */
1312bool addServiceToRegistry(registry** reg,char* name,service* content){
1313  registry *l=*reg;
1314  int isInitial=-1;
1315  if(l==NULL){
1316    l=(registry*)malloc(REGISTRY_SIZE);
1317    isInitial=1;
1318  }
1319  if(l!=NULL){
1320    int hasLevel=-1;
1321    while(isInitial<0 && l!=NULL){
1322      if(l->name!=NULL && strcasecmp(name,l->name)==0){
1323        hasLevel=1;
1324        break;
1325      }
1326      l=l->next;
1327    }
1328    if(hasLevel<0){
1329      if(isInitial<0)
1330        l=(registry*)malloc(REGISTRY_SIZE);
1331      l->name=zStrdup(name);
1332      l->content=NULL;
1333      l->next=NULL;
1334    }
1335    if(l->content==NULL){
1336      l->content=(services*)malloc(SERVICES_SIZE);
1337      l->content->content=dupService(content);
1338      l->content->next=NULL;
1339    }
1340    else{
1341      services* s=l->content;
1342      while(s->next!=NULL)
1343        s=s->next;
1344      s->next=(services*)malloc(SERVICES_SIZE);
1345      s->next->content=dupService(content);
1346      s->next->next=NULL;
1347    }
1348    l->next=NULL;
1349    if(isInitial>0)
1350      *reg=l;
1351    else{
1352      registry *r=*reg;
1353      while(r->next!=NULL)
1354        r=r->next;
1355      r->next=l;
1356      r->next->next=NULL;
1357    }
1358    return true;
1359  }
1360  else
1361    return false;
1362}
1363
1364/**
1365 * Free memory allocated for the registry
1366 *
1367 * @param r the registry
1368 */
1369void freeRegistry(registry** r){
1370  registry* lr=*r;
1371  while(lr!=NULL){
1372    services* s=lr->content;
1373    free(lr->name);
1374    while(s!=NULL){
1375      service* s1=s->content;
1376      s=s->next;
1377      if(s1!=NULL){
1378        freeService(&s1);
1379        free(s1);
1380        s1=NULL;
1381      }
1382    }
1383    lr=lr->next;
1384  }   
1385}
1386
1387/**
1388 * Access a service in the registry
1389 *
1390 * @param r the registry
1391 * @param level the regitry to search ("concept", "generic" or "implementation")
1392 * @param sname the service name
1393 * @return the service pointer if a corresponding service was found or NULL
1394 */
1395service* getServiceFromRegistry(registry* r,char  *level,char* sname){
1396  registry *lr=r;
1397  while(lr!=NULL){
1398    if(strcasecmp(lr->name,level)==0){
1399      services* s=lr->content;
1400      while(s!=NULL){
1401        if(s->content!=NULL && strcasecmp(s->content->name,sname)==0)
1402          return s->content;
1403        s=s->next;
1404      }
1405      break;
1406    }
1407    lr=lr->next;
1408  }
1409  return NULL;
1410}
1411
1412/**
1413 * Apply inheritance to an out map from a reference in map
1414 *
1415 * @param out the map to update
1416 * @param in the reference map (containing inherited properties)
1417 */
1418void inheritMap(map** out,map* in){
1419  map* content=in;
1420  if((*out)==NULL){
1421    addMapToMap(out,in);
1422    return;
1423  }
1424  while(content!=NULL){
1425    map* cmap=getMap(*out,content->name);
1426    if(cmap==NULL)
1427      addToMap(*out,content->name,content->value);
1428    content=content->next;
1429  }
1430}
1431
1432/**
1433 * Apply inheritance to an out iotype from a reference in iotype
1434 *
1435 * @param out the iotype to update
1436 * @param in the reference iotype (containing inherited properties)
1437 */
1438void inheritIOType(iotype** out,iotype* in){
1439  iotype* io=in;
1440  iotype* oio=*out;
1441  if(io!=NULL){
1442    if(*out==NULL){
1443      *out=(iotype*)malloc(IOTYPE_SIZE);
1444      (*out)->content=NULL;
1445      addMapToMap(&(*out)->content,io->content);
1446      (*out)->next=NULL;
1447      oio=*out;
1448      inheritIOType(&oio->next,io->next);
1449    }else{
1450      inheritIOType(&oio->next,io->next);
1451    }
1452  }
1453}
1454
1455/**
1456 * Apply inheritance to an out elements from a reference in elements
1457 *
1458 * @param out the elements to update
1459 * @param in the reference elements (containing inherited properties)
1460 */
1461void inheritElements(elements** out,elements* in){
1462  elements* content=in;
1463  while(content!=NULL && *out!=NULL){
1464    elements* cmap=getElements(*out,content->name);
1465    if(cmap==NULL)
1466      addToElements(out,content);
1467    else{
1468      inheritMap(&cmap->content,content->content);
1469      inheritMap(&cmap->metadata,content->metadata);
1470      if(cmap->format==NULL && content->format!=NULL)
1471        cmap->format=zStrdup(content->format);
1472      inheritIOType(&cmap->defaults,content->defaults);
1473      if(cmap->supported==NULL)
1474        inheritIOType(&cmap->supported,content->supported);
1475      else{
1476        iotype* p=content->supported;
1477        while(p!=NULL){
1478          addMapToIoType(&cmap->supported,p->content);
1479          p=p->next;
1480        }
1481      }
1482    }
1483    content=content->next;
1484  }
1485}
1486
1487/**
1488 * Apply inheritance to a service based on a registry
1489 *
1490 * @param r the registry storing profiles hierarchy
1491 * @param s the service to update depending on its inheritance
1492 */
1493void inheritance(registry *r,service** s){
1494  if(r==NULL)
1495    return;
1496  service* ls=*s;
1497  if(ls->content==NULL)
1498    return;
1499  map* profile=getMap(ls->content,"extend");
1500  map* level=getMap(ls->content,"level");
1501  if(profile!=NULL&&level!=NULL){
1502    service* s1;
1503    if(strncasecmp(level->value,"profile",7)==0)
1504      s1=getServiceFromRegistry(r,(char*)"generic",profile->value);
1505    else
1506      s1=getServiceFromRegistry(r,level->value,profile->value);
1507     
1508    inheritMap(&ls->content,s1->content);
1509    inheritMap(&ls->metadata,s1->metadata);
1510    if(ls->inputs==NULL && s1->inputs!=NULL){
1511      ls->inputs=dupElements(s1->inputs);
1512    }else{
1513      inheritElements(&ls->inputs,s1->inputs);
1514    }
1515    if(ls->outputs==NULL && s1->outputs!=NULL){
1516      ls->outputs=dupElements(s1->outputs);
1517    }else
1518      inheritElements(&ls->outputs,s1->outputs);
1519  }
1520}
1521
1522/**
1523 * Convert a maps to a char*** (only used for Fortran support)
1524 *
1525 * @param m the maps to convert
1526 * @param c the resulting array
1527 */
1528void mapsToCharXXX(maps* m,char*** c){
1529  maps* tm=m;
1530  int i=0;
1531  int j=0;
1532  char tmp[10][30][1024];
1533  memset(tmp,0,1024*10*10);
1534  while(tm!=NULL){
1535    if(i>=10)
1536      break;
1537    strcpy(tmp[i][j],"name");
1538    j++;
1539    strcpy(tmp[i][j],tm->name);
1540    j++;
1541    map* tc=tm->content;
1542    while(tc!=NULL){
1543      if(j>=30)
1544        break;
1545      strcpy(tmp[i][j],tc->name);
1546      j++;
1547      strcpy(tmp[i][j],tc->value);
1548      j++;
1549      tc=tc->next;
1550    }
1551    tm=tm->next;
1552    j=0;
1553    i++;
1554  }
1555  memcpy(c,tmp,10*10*1024);
1556}
1557
1558/**
1559 * Convert a char*** to a maps (only used for Fortran support)
1560 *
1561 * @param c the array to convert
1562 * @param m the resulting maps
1563 */
1564void charxxxToMaps(char*** c,maps**m){
1565  maps* trorf=*m;
1566  int i,j;
1567  char tmp[10][30][1024];
1568  memcpy(tmp,c,10*30*1024);
1569  for(i=0;i<10;i++){
1570    if(strlen(tmp[i][1])==0)
1571      break;
1572    trorf->name=tmp[i][1];
1573    trorf->content=NULL;
1574    trorf->next=NULL;
1575    for(j=2;j<29;j+=2){
1576      if(strlen(tmp[i][j+1])==0)
1577        break;
1578      if(trorf->content==NULL)
1579        trorf->content=createMap(tmp[i][j],tmp[i][j+1]);
1580      else
1581        addToMap(trorf->content,tmp[i][j],tmp[i][j+1]);
1582    }
1583    trorf=trorf->next;
1584  }
1585  m=&trorf;
1586}
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