/*-*-C-*-
 * Relocation etc - for Misc CSE
 */


#include "resed.h"
#include "main.h"

#include "resformat.h"

#include "relocate.h"


/*
 * Relocate a block received from the shell.  After calling this
 * all the pointers will be to the real strings and messages.
 * Sprite relocations are not done because we use the Wimp sprite
 * pool.
 *
 * If all is well, returns the address of the start of the object body.
 *
 * If the structure is found to be corrupt in some way, a NULL pointer
 * is returned.
 *
 * *** Note that object offsets are *not* relocated in this version ***
 *
 *     This is because the !Misc editor does not need to interpret
 *     these values as pointers; it merely provides a general interface
 *     for editing them.
 */

char * relocate_object (ResourceFileObjectTemplateHeaderPtr object)
{
    unsigned int strings = (unsigned int)
                             object + object->stringtableoffset;
    unsigned int messages = (unsigned int)
                             object + object->messagetableoffset;
    RelocationTablePtr relocs = (RelocationTablePtr)
                  ((unsigned int) object + object->relocationtableoffset);
    char * body = ((char *) &object->hdr) + object->hdr.bodyoffset;

    if (object->relocationtableoffset > 0)
    {
        int i;
        for (i = 0; i < relocs->numrelocations; i++)
        {
            unsigned int *word;
            word = (unsigned int *)
                      (body + relocs->relocations[i].wordtorelocate);

            switch (relocs->relocations[i].directive)
            {
            case RELOCATE_STRINGREFERENCE:
                if (*word == 0xffffffff)
                    *word = 0;
                else
                    *word += strings;
                break;

            case RELOCATE_MSGREFERENCE:
                if (*word == 0xffffffff)
                    *word = 0;
                else
                    *word += messages;
                break;

            case RELOCATE_OBJECTOFFSET:
                /* no action - these remain untouched */
                break;

            case RELOCATE_SPRITEAREAREFERENCE:
                switch (*word)
                {
                case CLIENT_SPRITEAREA:
                case WIMP_SPRITEAREA:
                    break;

                /* unknown SpriteAreaReference */
                default:
                    error_box (error_lookup ("BadSpriteReloc", *word));
                    *word = WIMP_SPRITEAREA;
                    break;
                }
                break;

            /* unknown object relocation */
            default:
                return NULL;
            }
        }
    }

    return body;
}


/*
 * Creates a StringReference, MsgReference, Offset or SpriteAreaReference
 * value (according to the value of 'type').
 *
 * 'tip' contains the information needed to calculate offsets and store
 * indirected strings; its fields are updated appropriately before exit.
 */

void relocate_make_ref (
    TemplateInfoPtr tip,
    int type,
    int *location,
    char *value
)
{
    /* fill in word to be relocated */
    switch (type)
    {
    case RELOCATE_STRINGREFERENCE:
        if (value == NULL)
            *location = -1;
        else
        {
            *location = tip->string - tip->stringbase;
            strcpy (tip->string, value);
            tip->string += strlen (value) + 1;
        }
        break;

    case RELOCATE_MSGREFERENCE:
        if (value == NULL)
            *location = -1;
        else
        {
            *location = tip->msg - tip->msgbase;
            strcpy (tip->msg, value);
            tip->msg += strlen (value) + 1;
        }
        break;

    case RELOCATE_OBJECTOFFSET:
        *location = (int) value;  /* just copy offset across */
        break;

    case RELOCATE_SPRITEAREAREFERENCE:
        *location = (int) value;
        break;
    }

    /* create relocation table entry */
    tip->reloc->wordtorelocate = (char *) location - tip->body;
    tip->reloc->directive = type;
    tip->reloc++;
    tip->numrelocs++;

    return;
}

