/*
	Software License Agreement (BSD License)
	
	Copyright (c) 1997-2008, David Lindauer, (LADSoft).
	All rights reserved.
	
	Redistribution and use of this software in source and binary forms, with or without modification, are
	permitted provided that the following conditions are met:
	
	* Redistributions of source code must retain the above
	  copyright notice, this list of conditions and the
	  following disclaimer.
	
	* Redistributions in binary form must reproduce the above
	  copyright notice, this list of conditions and the
	  following disclaimer in the documentation and/or other
	  materials provided with the distribution.
	
	* Neither the name of LADSoft nor the names of its
	  contributors may be used to endorse or promote products
	  derived from this software without specific prior
	  written permission of LADSoft.
	
	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
	WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
	PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
	ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
	LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
	TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
	ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstddef>
#include "_rtti.h"

// don't write to these, there is no space allocated
//extern const void * __code_seg_start, *__code_seg_end ;

static int findoffs(CLASSXCEPT *__newxt, CLASSXCEPT *__oldxt, int oldoffs)
{
   CLASSXCEPTREF *xr = (CLASSXCEPTREF *)((unsigned char *)(__newxt + 1) + __newxt->name[0]) ;
   while (xr->flags) {
      if (xr->flags & XD_CL_BASE) {
         int offset ;
         if (xr->xt == __oldxt) {
            offset =  xr->offset ;
            return offset + oldoffs ;
         } else {
            offset = findoffs(xr->xt,__oldxt,xr->offset) ;
            if (offset != -1)
               return offset + oldoffs ;
         }
      }
      xr = (CLASSXCEPTREF *)((unsigned char *)(xr + 1) + (xr->flags & XD_X_MASK)) ;
   }
   return -1 ;
}
void * _RTL_FUNC __dynamic_cast(void *__instance, void *__oldxt, void *__newxt)
{
   int offset = 0 ;

   // try to find an offsset for the func
   offset = findoffs((CLASSXCEPT*)__newxt, (CLASSXCEPT *)__oldxt,0) ;
   // if we found it
   if (offset != -1) {
      CLASSXCEPT *xoldxt ;

      // find the XT for this class
      int *temp = *(int **)__instance ; // vtab
      while (temp[-1]) // find beginning of this vtab
         temp = (int *)((unsigned char *)temp - temp[-1]) ;
      temp = temp - VTAB_XT_OFFS/sizeof(int *) ; // point to xt
      xoldxt = *(CLASSXCEPT **)temp ; // get xt
      if (xoldxt == (CLASSXCEPT *)__newxt) { // exact match, return the new instance ptr
         return (void *)((unsigned char *)__instance - offset) ;
      } else {
         // else check to make sure the new type is a base of the final type
         int offset1 = findoffs(xoldxt,(CLASSXCEPT*)__newxt,0) ;
         if (offset1 != -1)
            return (void *)((unsigned char *)__instance - offset + offset1) ;
      }
   }
   // no match, signal failure
   return 0 ;
}