/*------------------------------------------------------------------------
 * object from tokens
 */
ogc_time_origin * ogc_time_origin :: from_tokens(
   const ogc_token * t,
   int               start,
   int *             pend,
   ogc_error *       err)
{
   const ogc_token_entry * arr;
   const char * kwd;
   bool bad = false;
   int  level;
   int  same;
   int  end;
   int  num;

   ogc_time_origin * obj      = OGC_NULL;
   const char * origin;

   /*---------------------------------------------------------
    * sanity checks
    */
   if ( t == OGC_NULL )
   {
      ogc_error::set(err, OGC_ERR_WKT_EMPTY_STRING, obj_kwd());
      return OGC_NULL;
   }
   arr = t->_arr;

   if ( start < 0 || start >= t->_num )
   {
      ogc_error::set(err, OGC_ERR_WKT_INDEX_OUT_OF_RANGE, obj_kwd(), start);
      return OGC_NULL;
   }
   kwd = arr[start].str;

   if ( !is_kwd(kwd) )
   {
      ogc_error::set(err, OGC_ERR_WKT_INVALID_KEYWORD, obj_kwd(), kwd);
      return OGC_NULL;
   }

   /*---------------------------------------------------------
    * Get the level for this object,
    * the number of tokens at that level,
    * and the total number of tokens.
    */
   level = arr[start].lvl;
   for (end = start+1; end < t->_num; end++)
   {
      if ( arr[end].lvl <= level )
         break;
   }

   if ( pend != OGC_NULL )
      *pend = end;
   num = (end - start);

   for (same = 0; same < num; same++)
   {
      if ( arr[start+same+1].lvl != level+1 || arr[start+same+1].idx == 0 )
         break;
   }

   /*---------------------------------------------------------
    * There must be 2 tokens: TIMEEXTENT[ start, end ...
    */
   if ( same < 2 )
   {
      ogc_error::set(err, OGC_ERR_WKT_INSUFFICIENT_TOKENS, obj_kwd(), same);
      return OGC_NULL;
   }

   if ( same > 2 && get_strict_parsing() )
   {
      ogc_error::set(err, OGC_ERR_WKT_TOO_MANY_TOKENS,     obj_kwd(), same);
      return OGC_NULL;
   }

   start++;

   /*---------------------------------------------------------
    * Process all non-object tokens.
    * They come first and are syntactically fixed.
    */
   origin = arr[start++].str;

   /*---------------------------------------------------------
    * Now process all sub-objects
    */
#if 0 /* who cares? */
   int  next = 0;
   for (int i = start; i < end; i = next)
   {
      /* unknown object, skip over it */
      for (next = i+1; next < end; next++)
      {
         if ( (arr[next].lvl <= arr[i].lvl) )
            break;
      }
   }
#endif

   /*---------------------------------------------------------
    * Create the object
    */
   if ( !bad )
   {
      obj = create(origin, err);
   }

   if ( obj == OGC_NULL )
   {
   }

   return obj;
}
Example #2
0
/*------------------------------------------------------------------------
 * object from tokens
 */
ogc_meridian * ogc_meridian :: from_tokens(
   const ogc_token * t,
   int               start,
   int *             pend,
   ogc_error *       err)
{
   const ogc_token_entry * arr;
   const char * kwd;
   bool bad = false;
   int  level;
   int  end;
   int  same;
   int  num;

   ogc_meridian * obj     = OGC_NULL;
   ogc_angunit *  angunit = OGC_NULL;
   double value;

   /*---------------------------------------------------------
    * sanity checks
    */
   if ( t == OGC_NULL )
   {
      ogc_error::set(err, OGC_ERR_WKT_EMPTY_STRING, obj_kwd());
      return OGC_NULL;
   }
   arr = t->_arr;

   if ( start < 0 || start >= t->_num )
   {
      ogc_error::set(err, OGC_ERR_WKT_INDEX_OUT_OF_RANGE, obj_kwd(), start);
      return OGC_NULL;
   }
   kwd = arr[start].str;

   if ( !is_kwd(kwd) )
   {
      ogc_error::set(err, OGC_ERR_WKT_INVALID_KEYWORD, obj_kwd(), kwd);
      return OGC_NULL;
   }

   /*---------------------------------------------------------
    * Get the level for this object,
    * the number of tokens at that level,
    * and the total number of tokens.
    */
   level = arr[start].lvl;
   for (end = start+1; end < t->_num; end++)
   {
      if ( arr[end].lvl <= level )
         break;
   }

   if ( pend != OGC_NULL )
      *pend = end;
   num = (end - start);

   for (same = 0; same < num; same++)
   {
      if ( arr[start+same+1].lvl != level+1 || arr[start+same+1].idx == 0 )
         break;
   }

   /*---------------------------------------------------------
    * There must be 1 token: MERIDIAN[ value ...
    */
   if ( same < 1 )
   {
      ogc_error::set(err, OGC_ERR_WKT_INSUFFICIENT_TOKENS, obj_kwd(), same);
      return OGC_NULL;
   }

   if ( same > 1 && get_strict_parsing() )
   {
      ogc_error::set(err, OGC_ERR_WKT_TOO_MANY_TOKENS,     obj_kwd(), same);
      return OGC_NULL;
   }

   start++;

   /*---------------------------------------------------------
    * Process all non-object tokens.
    * They come first and are syntactically fixed.
    */
   value = ogc_string::atod( arr[start++].str );

   /*---------------------------------------------------------
    * Now process all sub-objects
    */
   int  next = 0;
   for (int i = start; i < end; i = next)
   {
      if ( ogc_angunit::is_kwd(arr[i].str) )
      {
         if ( angunit != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_UNIT, obj_kwd());
            bad = true;
         }
         else
         {
            angunit = ogc_angunit::from_tokens(t, i, &next, err);
            if ( angunit == OGC_NULL )
               bad = true;
         }
         continue;
      }

      /* unknown object, skip over it */
      for (next = i+1; next < end; next++)
      {
         if ( (arr[next].lvl <= arr[i].lvl) )
            break;
      }
   }

   /*---------------------------------------------------------
    * Create the object
    */
   if ( !bad )
   {
      obj = create(value, angunit, err);
   }

   if ( obj == OGC_NULL )
   {
      ogc_angunit :: destroy( angunit );
   }

   return obj;
}
/*------------------------------------------------------------------------
 * object from tokens
 */
ogc_parameter * ogc_parameter :: from_tokens(
   const ogc_token * t,
   int               start,
   int *             pend,
   ogc_error *       err)
{
   const ogc_token_entry * arr;
   const char * kwd;
   bool bad = false;
   int  level;
   int  end;
   int  same;
   int  num;

   ogc_parameter * obj  = OGC_NULL;
   ogc_unit *      unit = OGC_NULL;
   ogc_id *        id   = OGC_NULL;
   ogc_vector *    ids  = OGC_NULL;
   const char * name;
   double       value;

   /*---------------------------------------------------------
    * sanity checks
    */
   if ( t == OGC_NULL )
   {
      ogc_error::set(err, OGC_ERR_WKT_EMPTY_STRING, obj_kwd());
      return OGC_NULL;
   }
   arr = t->_arr;

   if ( start < 0 || start >= t->_num )
   {
      ogc_error::set(err, OGC_ERR_WKT_INDEX_OUT_OF_RANGE, obj_kwd(), start);
      return OGC_NULL;
   }
   kwd = arr[start].str;

   if ( !ogc_string::is_equal(kwd, obj_kwd()) )
   {
      ogc_error::set(err, OGC_ERR_WKT_INVALID_KEYWORD, obj_kwd(), kwd);
      return OGC_NULL;
   }

   /*---------------------------------------------------------
    * Get the level for this object,
    * the number of tokens at that level,
    * and the total number of tokens.
    */
   level = arr[start].lvl;
   for (end = start+1; end < t->_num; end++)
   {
      if ( arr[end].lvl <= level )
         break;
   }

   if ( pend != OGC_NULL )
      *pend = end;
   num = (end - start);

   for (same = 0; same < num; same++)
   {
      if ( arr[start+same+1].lvl != level+1 || arr[start+same+1].idx == 0 )
         break;
   }

   /*---------------------------------------------------------
    * There must be 2 tokens: PARAMETER[ "name", value ...
    */
   if ( same < 2 )
   {
      ogc_error::set(err, OGC_ERR_WKT_INSUFFICIENT_TOKENS, obj_kwd(), same);
      return OGC_NULL;
   }

   if ( same > 2 && get_strict_parsing() )
   {
      ogc_error::set(err, OGC_ERR_WKT_TOO_MANY_TOKENS,     obj_kwd(), same);
      return OGC_NULL;
   }

   start++;

   /*---------------------------------------------------------
    * Process all non-object tokens.
    * They come first and are syntactically fixed.
    */
   name  = arr[start++].str;
   value = ogc_string::atod( arr[start++].str );

   /*---------------------------------------------------------
    * Now process all sub-objects
    */
   int  next = 0;
   for (int i = start; i < end; i = next)
   {
      if ( ogc_string::is_equal(arr[0].str, ogc_unit     ::obj_kwd()) ||
           ogc_string::is_equal(arr[0].str, ogc_angunit  ::obj_kwd()) ||
           ogc_string::is_equal(arr[0].str, ogc_lenunit  ::obj_kwd()) ||
           ogc_string::is_equal(arr[0].str, ogc_paramunit::obj_kwd()) ||
           ogc_string::is_equal(arr[0].str, ogc_scaleunit::obj_kwd()) ||
           ogc_string::is_equal(arr[0].str, ogc_timeunit ::obj_kwd()) )
      {
         if ( unit != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_UNIT, obj_kwd());
            bad = true;
         }
         else
         {
            unit = ogc_unit::from_tokens(t, i, &next, err);
            if ( unit == OGC_NULL )
               bad = true;
         }
         continue;
      }

      if ( ogc_string::is_equal(arr[i].str, ogc_id::obj_kwd()) ||
           ogc_string::is_equal(arr[i].str, ogc_id::alt_kwd()) )
      {
         id = ogc_id::from_tokens(t, i, &next, err);
         if ( id == OGC_NULL )
         {
            bad = true;
         }
         else
         {
            if ( ids == OGC_NULL )
            {
               ids = ogc_vector::create(1, 1);
               if ( ids == OGC_NULL )
               {
                  ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                  delete id;
                  bad = true;
               }
            }

            if ( ids != OGC_NULL )
            {
               void * p = ids->find(
                             id,
                             false,
                             ogc_utils::compare_id);
               if ( p != OGC_NULL )
               {
                  ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_ID,
                     obj_kwd(), id->name());
                  delete id;
                  bad = true;
               }
               else
               {
                  if ( ids->add( id ) < 0 )
                  {
                     ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                     delete id;
                     bad = true;
                  }
               }
            }
         }
         continue;
      }

      /* unknown object, skip over it */
      for (next = i+1; next < end; next++)
      {
         if ( (arr[next].lvl <= arr[i].lvl) )
            break;
      }
   }

   /*---------------------------------------------------------
    * Create the object
    */
   if ( !bad )
   {
      obj = create(name, value, unit, ids, err);
   }

   if ( obj == OGC_NULL )
   {
      ogc_unit   :: destroy( unit );
      ogc_vector :: destroy( ids  );
   }

   return obj;
}
Example #4
0
/*------------------------------------------------------------------------
 * object from tokens
 */
ogc_id * ogc_id :: from_tokens(
   const ogc_token * t,
   int               start,
   int *             pend,
   ogc_error *       err)
{
   const ogc_token_entry * arr;
   const char * kwd;
   bool bad = false;
   int  level;
   int  end;
   int  same;
   int  num;

   ogc_id *       obj      = OGC_NULL;
   ogc_citation * citation = OGC_NULL;
   ogc_uri *      uri      = OGC_NULL;
   const char * name;
   const char * identifier;
   const char * version;

   /*---------------------------------------------------------
    * sanity checks
    */
   if ( t == OGC_NULL )
   {
      ogc_error::set(err, OGC_ERR_WKT_EMPTY_STRING, obj_kwd());
      return OGC_NULL;
   }
   arr = t->_arr;

   if ( start < 0 || start >= t->_num )
   {
      ogc_error::set(err, OGC_ERR_WKT_INDEX_OUT_OF_RANGE, obj_kwd(), start);
      return OGC_NULL;
   }
   kwd = arr[start].str;

   if ( !is_kwd(kwd) )
   {
      ogc_error::set(err, OGC_ERR_WKT_INVALID_KEYWORD, obj_kwd(), kwd);
      return OGC_NULL;
   }

   /*---------------------------------------------------------
    * Get the level for this object,
    * the number of tokens at that level,
    * and the total number of tokens.
    */
   level = arr[start].lvl;
   for (end = start+1; end < t->_num; end++)
   {
      if ( arr[end].lvl <= level )
         break;
   }

   if ( pend != OGC_NULL )
      *pend = end;
   num = (end - start);

   for (same = 0; same < num; same++)
   {
      if ( arr[start+same+1].lvl != level+1 || arr[start+same+1].idx == 0 )
         break;
   }

   /*---------------------------------------------------------
    * There must be 2 or 3 tokens: ID[ "name", "identity" ...
    * (version is optional)
    */
   if ( same < 2 )
   {
      ogc_error::set(err, OGC_ERR_WKT_INSUFFICIENT_TOKENS, obj_kwd(), same);
      return OGC_NULL;
   }

   if ( same > 3 && get_strict_parsing() )
   {
      ogc_error::set(err, OGC_ERR_WKT_TOO_MANY_TOKENS,     obj_kwd(), same);
      return OGC_NULL;
   }


   start++;

   /*---------------------------------------------------------
    * Process all non-object tokens.
    * They come first and are syntactically fixed.
    */
   name       = arr[start++].str;
   identifier = arr[start++].str;

   if ( same > 2 )
      version = arr[start++].str;
   else
      version = "";

   /*---------------------------------------------------------
    * Now process all sub-objects
    */
   int  next = 0;
   for (int i = start; i < end; i = next)
   {
      if ( ogc_citation::is_kwd(arr[i].str) )
      {
         if ( citation != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_CITATION, obj_kwd());
            bad = true;
         }
         else
         {
            citation = ogc_citation::from_tokens(t, i, &next, err);
            if ( citation == OGC_NULL )
               bad = true;
         }
         continue;
      }

      if ( ogc_uri::is_kwd(arr[i].str) )
      {
         if ( uri != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_URI, obj_kwd());
            bad = true;
         }
         else
         {
            uri = ogc_uri::from_tokens(t, i, &next, err);
            if ( uri == OGC_NULL )
               bad = true;
         }
         continue;
      }

      /* unknown object, skip over it */
      for (next = i+1; next < end; next++)
      {
         if ( (arr[next].lvl <= arr[i].lvl) )
            break;
      }
   }

   /*---------------------------------------------------------
    * Create the object
    */
   if ( !bad )
   {
      obj = create(name, identifier, version, citation, uri, err);
   }

   if ( obj == OGC_NULL )
   {
      ogc_citation :: destroy( citation );
      ogc_uri      :: destroy( uri      );
   }

   return obj;
}
/*------------------------------------------------------------------------
 * object from tokens
 */
ogc_geog3d_crs * ogc_geog3d_crs :: from_tokens(
   const ogc_token * t,
   int               start,
   int *             pend,
   ogc_error *       err)
{
   const ogc_token_entry * arr;
   const char * kwd;
   bool bad = false;
   int  level;
   int  end;
   int  same;
   int  num;

   ogc_geog3d_crs *      obj     = OGC_NULL;
   ogc_geodetic_datum *  datum   = OGC_NULL;
   ogc_primem *          primem  = OGC_NULL;
   ogc_cs *              cs      = OGC_NULL;
   ogc_axis *            axis    = OGC_NULL;
   ogc_axis *            axis_1  = OGC_NULL;
   ogc_axis *            axis_2  = OGC_NULL;
   ogc_axis *            axis_3  = OGC_NULL;
   ogc_unit *            unit    = OGC_NULL;
   ogc_scope *           scope   = OGC_NULL;
   ogc_extent *          extent  = OGC_NULL;
   ogc_vector *          extents = OGC_NULL;
   ogc_id *              id      = OGC_NULL;
   ogc_vector *          ids     = OGC_NULL;
   ogc_remark *          remark  = OGC_NULL;
   const char * name;

   /*---------------------------------------------------------
    * sanity checks
    */
   if ( t == OGC_NULL )
   {
      ogc_error::set(err, OGC_ERR_WKT_EMPTY_STRING, obj_kwd());
      return OGC_NULL;
   }
   arr = t->_arr;

   if ( start < 0 || start >= t->_num )
   {
      ogc_error::set(err, OGC_ERR_WKT_INDEX_OUT_OF_RANGE, obj_kwd(), start);
      return OGC_NULL;
   }
   kwd = arr[start].str;

   if ( !ogc_string::is_equal(kwd, obj_kwd()) )
   {
      ogc_error::set(err, OGC_ERR_WKT_INVALID_KEYWORD, obj_kwd(), kwd);
      return OGC_NULL;
   }

   /*---------------------------------------------------------
    * Get the level for this object,
    * the number of tokens at that level,
    * and the total number of tokens.
    */
   level = arr[start].lvl;
   for (end = start+1; end < t->_num; end++)
   {
      if ( arr[end].lvl <= level )
         break;
   }

   if ( pend != OGC_NULL )
      *pend = end;
   num = (end - start);

   for (same = 0; same < num; same++)
   {
      if ( arr[start+same+1].lvl != level+1 || arr[start+same+1].idx == 0 )
         break;
   }

   /*---------------------------------------------------------
    * There must be 1 token: GEOG3DCRS[ "name" ...
    */
   if ( same < 1 )
   {
      ogc_error::set(err, OGC_ERR_WKT_INSUFFICIENT_TOKENS, obj_kwd(), same);
      return OGC_NULL;
   }

   if ( same > 1 && get_strict_parsing() )
   {
      ogc_error::set(err, OGC_ERR_WKT_TOO_MANY_TOKENS,     obj_kwd(), same);
      return OGC_NULL;
   }

   start++;

   /*---------------------------------------------------------
    * Process all non-object tokens.
    * They come first and are syntactically fixed.
    */
   name = arr[start++].str;

   /*---------------------------------------------------------
    * Now process all sub-objects
    */
   int  next = 0;
   for (int i = start; i < end; i = next)
   {
      if ( ogc_string::is_equal(arr[i].str, ogc_geodetic_datum::obj_kwd()) )
      {
         if ( datum != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_DATUM, obj_kwd());
            bad = true;
         }
         else
         {
            datum = ogc_geodetic_datum::from_tokens(t, i, &next, err);
            if ( datum == OGC_NULL )
               bad = true;
         }
         continue;
      }

      if ( ogc_string::is_equal(arr[i].str, ogc_primem::obj_kwd()) )
      {
         if ( primem != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_PRIMEM, obj_kwd());
            bad = true;
         }
         else
         {
            primem = ogc_primem::from_tokens(t, i, &next, err);
            if ( primem == OGC_NULL )
               bad = true;
         }
         continue;
      }

      if ( ogc_string::is_equal(arr[i].str, ogc_cs::obj_kwd()) )
      {
         if ( cs != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_CS, obj_kwd());
            bad = true;
         }
         else
         {
            cs = ogc_cs::from_tokens(t, i, &next, err);
            if ( cs == OGC_NULL )
               bad = true;
         }
         continue;
      }

      if ( ogc_string::is_equal(arr[i].str, ogc_axis::obj_kwd()) )
      {
         axis = ogc_axis::from_tokens(t, i, &next, err);
         if ( axis == OGC_NULL )
         {
            bad = true;
         }
         else
         {
            if ( !ogc_utils::place_axis(axis, &axis_1, &axis_2, &axis_3,
                                        obj_kwd(), err) )
            {
               delete axis;
               bad = true;
            }
         }
         continue;
      }

      if ( ogc_string::is_equal(arr[i].str, ogc_lenunit::obj_kwd()) ||
           ogc_string::is_equal(arr[i].str, ogc_lenunit::alt_kwd()) )
      {
         if ( unit != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_UNIT, obj_kwd());
            bad = true;
         }
         else
         {
            unit = ogc_unit::from_tokens(t, i, &next, err);
            if ( unit == OGC_NULL )
               bad = true;
         }
         continue;
      }

      if ( ogc_string::is_equal(arr[i].str, ogc_scope::obj_kwd()) )
      {
         if ( scope != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_SCOPE, obj_kwd());
            bad = true;
         }
         else
         {
            scope = ogc_scope::from_tokens(t, i, &next, err);
            if ( scope == OGC_NULL )
               bad = true;
         }
         continue;
      }

      if ( ogc_string::is_equal(arr[i].str, ogc_area_extent::obj_kwd()) ||
           ogc_string::is_equal(arr[i].str, ogc_bbox_extent::obj_kwd()) ||
           ogc_string::is_equal(arr[i].str, ogc_time_extent::obj_kwd()) ||
           ogc_string::is_equal(arr[i].str, ogc_vert_extent::obj_kwd()) )
      {
         extent = ogc_extent::from_tokens(t, i, &next, err);
         if ( extent == OGC_NULL )
         {
            bad = true;
         }
         else
         {
            if ( extents == OGC_NULL )
            {
               extents = ogc_vector::create(1, 1);
               if ( extents == OGC_NULL )
               {
                  ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                  delete extent;
                  bad = true;
               }
            }

            if ( extents != OGC_NULL )
            {
               void * p = extents->find(
                             extent,
                             false,
                             ogc_utils::compare_extent);
               if ( p != OGC_NULL )
               {
                  ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_EXTENT,
                     obj_kwd(),
                     ogc_utils::obj_type_to_kwd(extent->obj_type()));
                  delete extent;
                  bad = true;
               }
               else
               {
                  if ( extents->add( extent ) < 0 )
                  {
                     ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                     delete extent;
                     bad = true;
                  }
               }
            }
         }
         continue;
      }

      if ( ogc_string::is_equal(arr[i].str, ogc_id::obj_kwd()) ||
           ogc_string::is_equal(arr[i].str, ogc_id::alt_kwd()) )
      {
         id = ogc_id::from_tokens(t, i, &next, err);
         if ( id == OGC_NULL )
         {
            bad = true;
         }
         else
         {
            if ( ids == OGC_NULL )
            {
               ids = ogc_vector::create(1, 1);
               if ( ids == OGC_NULL )
               {
                  ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                  delete id;
                  bad = true;
               }
            }

            if ( ids != OGC_NULL )
            {
               void * p = ids->find(
                             id,
                             false,
                             ogc_utils::compare_id);
               if ( p != OGC_NULL )
               {
                  ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_ID,
                     obj_kwd(), id->name());
                  delete id;
                  bad = true;
               }
               else
               {
                  if ( ids->add( id ) < 0 )
                  {
                     ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                     delete id;
                     bad = true;
                  }
               }
            }
         }
         continue;
      }

      if ( ogc_string::is_equal(arr[i].str, ogc_remark::obj_kwd()) )
      {
         if ( remark != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_REMARK, obj_kwd());
            bad = true;
         }
         else
         {
            remark = ogc_remark::from_tokens(t, i, &next, err);
            if ( remark == OGC_NULL )
               bad = true;
         }
         continue;
      }

      /* unknown object, skip over it */
      for (next = i+1; next < end; next++)
      {
         if ( (arr[next].lvl <= arr[i].lvl) )
            break;
      }
   }

   /*---------------------------------------------------------
    * Create the object
    */
   if ( !bad )
   {
      obj = create(name, datum, primem, cs, axis_1, axis_2, axis_3, unit,
                   scope, extents, ids, remark, err);
   }

   if ( obj == OGC_NULL )
   {
      ogc_geodetic_datum :: destroy( datum   );
      ogc_primem         :: destroy( primem  );
      ogc_cs             :: destroy( cs      );
      ogc_axis           :: destroy( axis_1  );
      ogc_axis           :: destroy( axis_2  );
      ogc_axis           :: destroy( axis_3  );
      ogc_unit           :: destroy( unit    );
      ogc_scope          :: destroy( scope   );
      ogc_vector         :: destroy( extents );
      ogc_vector         :: destroy( ids     );
      ogc_remark         :: destroy( remark  );
   }

   return obj;
}
/*------------------------------------------------------------------------
 * object from tokens
 */
ogc_image_datum * ogc_image_datum :: from_tokens(
   const ogc_token * t,
   int               start,
   int *             pend,
   ogc_error *       err)
{
   const ogc_token_entry * arr;
   const char * kwd;
   bool bad = false;
   int  level;
   int  end;
   int  same;
   int  num;

   ogc_image_datum *   obj       = OGC_NULL;
   ogc_anchor *       anchor    = OGC_NULL;
   ogc_id *           id        = OGC_NULL;
   ogc_vector *       ids       = OGC_NULL;
   ogc_pixel_type     pixel_type;
   const char * name;

   /*---------------------------------------------------------
    * sanity checks
    */
   if ( t == OGC_NULL )
   {
      ogc_error::set(err, OGC_ERR_WKT_EMPTY_STRING, obj_kwd());
      return OGC_NULL;
   }
   arr = t->_arr;

   if ( start < 0 || start >= t->_num )
   {
      ogc_error::set(err, OGC_ERR_WKT_INDEX_OUT_OF_RANGE, obj_kwd(), start);
      return OGC_NULL;
   }
   kwd = arr[start].str;

   if ( !is_kwd(kwd) )
   {
      ogc_error::set(err, OGC_ERR_WKT_INVALID_KEYWORD, obj_kwd(), kwd);
      return OGC_NULL;
   }

   /*---------------------------------------------------------
    * Get the level for this object,
    * the number of tokens at that level,
    * and the total number of tokens.
    */
   level = arr[start].lvl;
   for (end = start+1; end < t->_num; end++)
   {
      if ( arr[end].lvl <= level )
         break;
   }

   if ( pend != OGC_NULL )
      *pend = end;
   num = (end - start);

   for (same = 0; same < num; same++)
   {
      if ( arr[start+same+1].lvl != level+1 || arr[start+same+1].idx == 0 )
         break;
   }

   /*---------------------------------------------------------
    * There must be 1 token: <kwd>[ "name", pixel_type ...
    */
   if ( same < 2 )
   {
      ogc_error::set(err, OGC_ERR_WKT_INSUFFICIENT_TOKENS, obj_kwd(), same);
      return OGC_NULL;
   }

   if ( same > 2 && get_strict_parsing() )
   {
      ogc_error::set(err, OGC_ERR_WKT_TOO_MANY_TOKENS,     obj_kwd(), same);
      return OGC_NULL;
   }

   start++;

   /*---------------------------------------------------------
    * Process all non-object tokens.
    * They come first and are syntactically fixed.
    */
   name = arr[start++].str;

   pixel_type = ogc_utils::pixel_kwd_to_type( arr[start++].str );
   if ( !ogc_utils::pixel_type_valid(pixel_type) )
   {
      ogc_error::set(err, OGC_ERR_INVALID_PIXEL_TYPE,
         obj_kwd(), arr[start-1].str);
      bad = true;
   }

   /*---------------------------------------------------------
    * Now process all sub-objects
    */
   int  next = 0;
   for (int i = start; i < end; i = next)
   {
      if ( ogc_anchor::is_kwd(arr[i].str) )
      {
         if ( anchor != OGC_NULL )
         {
            ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_ANCHOR, obj_kwd());
            bad = true;
         }
         else
         {
            anchor = ogc_anchor::from_tokens(t, i, &next, err);
            if ( anchor == OGC_NULL )
               bad = true;
         }
         continue;
      }

      if ( ogc_id::is_kwd(arr[i].str) )
      {
         id = ogc_id::from_tokens(t, i, &next, err);
         if ( id == OGC_NULL )
         {
            bad = true;
         }
         else
         {
            if ( ids == OGC_NULL )
            {
               ids = ogc_vector::create(1, 1);
               if ( ids == OGC_NULL )
               {
                  ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                  delete id;
                  bad = true;
               }
            }

            if ( ids != OGC_NULL )
            {
               void * p = ids->find(
                             id,
                             false,
                             ogc_utils::compare_id);
               if ( p != OGC_NULL )
               {
                  ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_ID,
                     obj_kwd(), id->name());
                  delete id;
                  bad = true;
               }
               else
               {
                  if ( ids->add( id ) < 0 )
                  {
                     ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                     delete id;
                     bad = true;
                  }
               }
            }
         }
         continue;
      }

      /* unknown object, skip over it */
      for (next = i+1; next < end; next++)
      {
         if ( (arr[next].lvl <= arr[i].lvl) )
            break;
      }
   }

   /*---------------------------------------------------------
    * Create the object
    */
   if ( !bad )
   {
      obj = create(name, pixel_type, anchor, ids, err);
   }

   if ( obj == OGC_NULL )
   {
      ogc_anchor :: destroy( anchor );
      ogc_vector :: destroy( ids    );
   }

   return obj;
}
/*------------------------------------------------------------------------
 * object from tokens
 */
ogc_deriving_conv * ogc_deriving_conv :: from_tokens(
    const ogc_token * t,
    int               start,
    int *             pend,
    ogc_error *       err)
{
    const ogc_token_entry * arr;
    const char * kwd;
    bool bad = false;
    int  level;
    int  end;
    int  same;
    int  num;

    ogc_deriving_conv * obj         = OGC_NULL;
    ogc_id *            id          = OGC_NULL;
    ogc_method *        method      = OGC_NULL;
    ogc_vector *        parameters  = OGC_NULL;
    ogc_vector *        param_files = OGC_NULL;
    ogc_parameter *     param       = OGC_NULL;
    ogc_param_file *    param_file  = OGC_NULL;
    ogc_vector *        ids         = OGC_NULL;
    const char * name;

    /*---------------------------------------------------------
     * sanity checks
     */
    if ( t == OGC_NULL )
    {
        ogc_error::set(err, OGC_ERR_WKT_EMPTY_STRING, obj_kwd());
        return OGC_NULL;
    }
    arr = t->_arr;

    if ( start < 0 || start >= t->_num )
    {
        ogc_error::set(err, OGC_ERR_WKT_INDEX_OUT_OF_RANGE, obj_kwd(), start);
        return OGC_NULL;
    }
    kwd = arr[start].str;

    if ( !is_kwd(kwd) )
    {
        ogc_error::set(err, OGC_ERR_WKT_INVALID_KEYWORD, obj_kwd(), kwd);
        return OGC_NULL;
    }

    /*---------------------------------------------------------
     * Get the level for this object,
     * the number of tokens at that level,
     * and the total number of tokens.
     */
    level = arr[start].lvl;
    for (end = start+1; end < t->_num; end++)
    {
        if ( arr[end].lvl <= level )
            break;
    }

    if ( pend != OGC_NULL )
        *pend = end;
    num = (end - start);

    for (same = 0; same < num; same++)
    {
        if ( arr[start+same+1].lvl != level+1 || arr[start+same+1].idx == 0 )
            break;
    }

    /*---------------------------------------------------------
     * There must be 1 token: DERIVINGCONVERSION[ "name" ...
     */
    if ( same < 1 )
    {
        ogc_error::set(err, OGC_ERR_WKT_INSUFFICIENT_TOKENS, obj_kwd(), same);
        return OGC_NULL;
    }

    if ( same > 1 && get_strict_parsing() )
    {
        ogc_error::set(err, OGC_ERR_WKT_TOO_MANY_TOKENS,     obj_kwd(), same);
        return OGC_NULL;
    }

    start++;

    /*---------------------------------------------------------
     * Process all non-object tokens.
     * They come first and are syntactically fixed.
     */
    name = arr[start++].str;

    /*---------------------------------------------------------
     * Now process all sub-objects
     */
    int  next = 0;
    for (int i = start; i < end; i = next)
    {
        if ( ogc_method::is_kwd(arr[i].str) )
        {
            if ( method != OGC_NULL )
            {
                ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_METHOD, obj_kwd());
                bad = true;
            }
            else
            {
                method = ogc_method::from_tokens(t, i, &next, err);
                if ( method == OGC_NULL )
                    bad = true;
            }
            continue;
        }

        if ( ogc_parameter::is_kwd(arr[i].str) )
        {
            param = ogc_parameter::from_tokens(t, i, &next, err);
            if ( param == OGC_NULL )
            {
                bad = true;
            }
            else
            {
                if ( parameters == OGC_NULL )
                {
                    parameters = ogc_vector::create(1, 1);
                    if ( parameters == OGC_NULL )
                    {
                        ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                        delete param;
                        bad = true;
                    }
                }

                if ( parameters != OGC_NULL )
                {
                    void * p = parameters->find(
                                   param,
                                   false,
                                   ogc_utils::compare_parameter);
                    if ( p != OGC_NULL )
                    {
                        ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_PARAMETER,
                                       obj_kwd(), param->name());
                        delete param;
                        bad = true;
                    }
                    else
                    {
                        if ( parameters->add( param ) < 0 )
                        {
                            ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                            delete param;
                            bad = true;
                        }
                    }
                }
            }
            continue;
        }

        if ( ogc_param_file::is_kwd(arr[i].str) )
        {
            param_file = ogc_param_file::from_tokens(t, i, &next, err);
            if ( param_file == OGC_NULL )
            {
                bad = true;
            }
            else
            {
                if ( param_files == OGC_NULL )
                {
                    param_files = ogc_vector::create(1, 1);
                    if ( param_files == OGC_NULL )
                    {
                        ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                        delete param;
                        bad = true;
                    }
                }

                if ( param_files != OGC_NULL )
                {
                    void * p = param_files->find(
                                   param,
                                   false,
                                   ogc_utils::compare_param_file);
                    if ( p != OGC_NULL )
                    {
                        ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_PARAM_FILE,
                                       obj_kwd(), param->name());
                        delete param;
                        bad = true;
                    }
                    else
                    {
                        if ( param_files->add( param ) < 0 )
                        {
                            ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                            delete param;
                            bad = true;
                        }
                    }
                }
            }
            continue;
        }

        if ( ogc_id::is_kwd(arr[i].str) )
        {
            id = ogc_id::from_tokens(t, i, &next, err);
            if ( id == OGC_NULL )
            {
                bad = true;
            }
            else
            {
                if ( ids == OGC_NULL )
                {
                    ids = ogc_vector::create(1, 1);
                    if ( ids == OGC_NULL )
                    {
                        ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                        delete id;
                        bad = true;
                    }
                }

                if ( ids != OGC_NULL )
                {
                    void * p = ids->find(
                                   id,
                                   false,
                                   ogc_utils::compare_id);
                    if ( p != OGC_NULL )
                    {
                        ogc_error::set(err, OGC_ERR_WKT_DUPLICATE_ID,
                                       obj_kwd(), id->name());
                        delete id;
                        bad = true;
                    }
                    else
                    {
                        if ( ids->add( id ) < 0 )
                        {
                            ogc_error::set(err, OGC_ERR_NO_MEMORY, obj_kwd());
                            delete id;
                            bad = true;
                        }
                    }
                }
            }
            continue;
        }

        /* unknown object, skip over it */
        for (next = i+1; next < end; next++)
        {
            if ( (arr[next].lvl <= arr[i].lvl) )
                break;
        }
    }

    /*---------------------------------------------------------
     * Final checks
     */

    /*---------------------------------------------------------
     * Create the object
     */
    if ( !bad )
    {
        obj = create(name, method, parameters, param_files, ids, err);
    }

    if ( obj == OGC_NULL )
    {
        ogc_method :: destroy( method      );
        ogc_vector :: destroy( parameters  );
        ogc_vector :: destroy( param_files );
        ogc_vector :: destroy( ids         );
    }

    return obj;
}