/*
**	Command & Conquer Generals(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* Copyright (C) Electronic Arts Canada Inc. 1998-1999.  All rights reserved. */

#include <string.h>
#include <assert.h>
#include "gimex.h"      /* for file and memory IO only */
#include "locale.h" 
#include "wnd_file.h"

/*************************************************************************/
/* File Format Structures                                                */
/*************************************************************************/

#define LOCALEFILE_HEADERCHUNKID    0x48434f4c /* 'LOCH' */
#define LOCALEFILE_INDEXCHUNKID     0x49434f4c /* 'LOCI' */
#define LOCALEFILE_LANGUAGECHUNKID  0x4c434f4c /* 'LOCL' */

typedef struct
{
    unsigned int   ChunkID;        /* 'LOCH' LOCALEFILE_HEADERCHUNKID */
    unsigned int   ChunkSize;      /* size of chunk in bytes */
    unsigned int   Flags;          /* 0=no index chunk present,1=index chunk present */
    unsigned int   LanguageCount;  /* number of language chunks in this file */
/*  unsigned int   LanguageOffset[LanguageCount]; \\ offsets in bytes from start of file to language chunk */
} LOCALEFILE_HEADERCHUNK;

/* offset LOCALEFILE_HEADERCHUNK_LANGUAGE_OFFSET bytes from the start of the chunk to the language offset table */
#define LOCALEFILE_HEADERCHUNK_LANGUAGE_OFFSET  sizeof(LOCALEFILE_HEADERCHUNK)


typedef struct
{
    unsigned int   ChunkID;        /* 'LOCI' LOCALEFILE_INDEXCHUNKID */
    unsigned int   ChunkSize;      /* size of chunk in bytes */
    unsigned int   StringCount;    /* number of string ids in this chunk (same value in all language chunks) */
    unsigned int   pad;            /* must be zero */
/*  STRINGID StringID[StringCount];  */
/*  { */
/*      unsigned short ID;          \\ id that user gives to look up value */
/*      unsigned short Index;       \\ index to look up value in language chunks */
/*  } */
} LOCALEFILE_INDEXCHUNK;

/* offset LOCALEFILE_INDEXCHUNK_STRINGID_OFFSET bytes from the start of the chunk to the string id table */
#define LOCALEFILE_INDEXCHUNK_STRINGID_OFFSET   sizeof(LOCALEFILE_INDEXCHUNK)


typedef struct
{
    unsigned int   ChunkID;        /* 'LOCL' LOCALEFILE_LANGUAGECHUNKID */
    unsigned int   ChunkSize;      /* size of chunk in bytes including this header and all string data */
    unsigned int   LanguageID;     /* language strings are in for this bank */
    unsigned int   StringCount;    /* number of strings in this chunk */
/*  unsigned int   StringOffset[StringCount];   \\ offsets in bytes from start of chunk to string */
/*  const char*    Data[StringCount];           \\ StringCount null terminated strings */
} LOCALEFILE_LANGUAGECHUNK;

/* offset LOCALEFILE_LANGUAGECHUNK_STRING_OFFSETbytes from the start of the chunk to the string offset table */
#define LOCALEFILE_LANGUAGECHUNK_STRING_OFFSET   sizeof(LOCALEFILE_LANGUAGECHUNK)


/*************************************************************************/
/* LOCALE_INSTANCE declaration                                           */
/*************************************************************************/

typedef LOCALEFILE_HEADERCHUNK   HEADER;
typedef LOCALEFILE_INDEXCHUNK    INDEX;
typedef LOCALEFILE_LANGUAGECHUNK BANK;

typedef struct
{
    int     BankIndex;     /* current language bank set (0..BANK_COUNT-1) */
    BANK*   pBank[LOCALE_BANK_COUNT];  /* array of string banks */
    INDEX*  pIndex[LOCALE_BANK_COUNT]; /* array of string indices */
} LOCALE_INSTANCE;

static LOCALE_INSTANCE	*lx			= NULL;

/*************************************************************************/
/* initialization/restore                                                */
/*************************************************************************/

/* helper function to make assertions for initialization clearer */
int LOCALE_isinitialized( void )
{
    if ( lx == NULL ) {
//        TRACE("LOCALE API is not initialized - call LOCALE_init before calling LOCALE functions\n");
	}
    return( lx != NULL );
}

/*
;
; ABSTRACT
;
; LOCALE_init - Init the localization module
;
;
; SUMMARY
;
; #include "realfont.h"
;
; int LOCALE_init(void)
;
; DESCRIPTION
;
; Initilizes everything needed to use the locale API.  Can only be called 
; once until LOCALE_restore is called.
;
; Returns non-zero if everything went ok.
;
; SEE ALSO
;
; LOCALE_restore
;
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
;
; END ABSTRACT
;
*/

int LOCALE_init(void)
{
    int ok = 0;

    /* ensure locale module is NOT already initialized */
    ASSERT(lx == NULL); /* can only call LOCALE_init after a restore or once, cannot double init locale API */

    /* allocate instance */
    lx = (LOCALE_INSTANCE*)galloc(sizeof(LOCALE_INSTANCE));
    if (lx != NULL) {
        memset(lx, 0, sizeof(LOCALE_INSTANCE));
        ok = 1;
    }
    return ok;
}

/*
;
; ABSTRACT
;
; LOCALE_restore - Free resources used by the locale module
;
;
; SUMMARY
;
; #include "realfont.h"
;
; void LOCALE_restore(void)
;
; DESCRIPTION
;
; Restores all resources used by the locale API.  Can only be called after
; LOCALE_init, and only once.
;
; SEE ALSO
;
; LOCALE_init
;
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
;
; END ABSTRACT
;
*/

void LOCALE_restore(void)
{
    int i;

	if( lx != NULL ) {

	    ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
		ASSERT(lx != NULL);

		/* free any language tables */
		for (i = 0; i < LOCALE_BANK_COUNT; i++) {
			if (lx->pBank[i]) {
				LOCALE_setbank(i);
				LOCALE_freetable();
			}
		}

		/* free instance */
		gfree(lx);
		lx = NULL;
	}
}

/*************************************************************************/
/* attributes                                                            */
/*************************************************************************/

/*
;
; ABSTRACT
;
; LOCALE_setbank - Set the current bank
;
;
; SUMMARY
;
; #include "realfont.h"
;
; void LOCALE_setbank(BankIndex)
;   int BankIndex;         Number between 0 and LOCALE_BANK_COUNT - 1
;
; DESCRIPTION
;
; Sets the current bank to be active.  All functions will now use this
; bank for strings.  A bank is slot where a string table is loaded.
; More than one bank can have a table loaded but the locale functions
; only work on one bank at a time, the active bank set by this function.
;
; SEE ALSO
;
; LOCALE_getbank
;
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
;
; END ABSTRACT
;
*/

void LOCALE_setbank(int BankIndex)
{
    ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
    lx->BankIndex = BankIndex;
}

/*
;
; ABSTRACT
;
; LOCALE_getbank - Get the current bank
;
;
; SUMMARY
;
; #include "realfont.h"
;
; int LOCALE_getbank(void)
;
; DESCRIPTION
;
; Returns the bank index of the current bank.
;
; SEE ALSO
;
; LOCALE_setbank
;
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
;
; END ABSTRACT
;
*/

int LOCALE_getbank(void)
{
    ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
    return lx->BankIndex;
}


/*
;
; ABSTRACT
;
; LOCALE_getbanklanguageid - Get the language id for the current bank
;
;
; SUMMARY
;
; #include "realfont.h"
;
; int LOCALE_getbanklanguageid(void)
;
; DESCRIPTION
;
; Returns the language id of the current bank.  This id will match
; the lanugage id in the header file generated by Locomoto
;
; SEE ALSO
;
; LOCALE_loadtable
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
;
; END ABSTRACT
;
*/

int LOCALE_getbanklanguageid(void)
{
    ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
    ASSERT(lx->pBank[lx->BankIndex]);       /* must load a table into bank before calling this function */
    return (int)(lx->pBank[lx->BankIndex]->LanguageID);
}

/*
;
; ABSTRACT
;
; LOCALE_getbankstringcount - Get the string count for the current bank
;
;
; SUMMARY
;
; #include "realfont.h"
;
; int LOCALE_getbankstringcount(void)
;
; DESCRIPTION
;
; Returns the number of strings in the current bank.  If zero is
; returned then this bank is empty.
;
; SEE ALSO
;
; LOCALE_loadtable
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
;
; END ABSTRACT
;
*/

int LOCALE_getbankstringcount(void)
{
    int StringCount = 0;

    ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
    if (lx->pBank[lx->BankIndex]) {
        StringCount = lx->pBank[lx->BankIndex]->StringCount;
    }
    return StringCount;
}

/*************************************************************************/
/* operations                                                            */
/*************************************************************************/

/*
;
; ABSTRACT
;
; LOCALE_loadtable - Load a string table into the current bank
;
;
; SUMMARY
;
; #include "realfont.h"
;
; int LOCALE_loadtable(pathname, languageid)
;
;   const char* pathname; // pathname of .loc file to load
;   int languageid;       // language id to load (from .h file)
;
; DESCRIPTION
;
; Loads the specified language from the string file into the
; current bank.  Returns non zero if the operation was succesful.
; The bank must be free before you can call LOCALE_loadtable.  To
; free a bank use the LOCALE_freetable function.  To determine
; if the bank is free use the LOCALE_getbankstringcount function.
;
; The languageid value is available in the .h file created by
; locomoto.
;
; Returns non-zero if everthing is ok.
;
; SEE ALSO
;
; LOCALE_freetable, LOCALE_getbankstringcount
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
;
; END ABSTRACT
;
*/

static int readheader( GSTREAM* g )
{
    int ok = 0;

    /* read file header */
    LOCALEFILE_HEADERCHUNK header;
    int HeaderChunkSize = sizeof(LOCALEFILE_HEADERCHUNK);

//	VERIFY(gread(g, &header, HeaderChunkSize) == HeaderChunkSize);
    if( gread(g, &header, HeaderChunkSize) != HeaderChunkSize ) {
		return ok;
	}

	Msg( __LINE__, __FILE__, "readheader - HeaderChunkSize = %d.", HeaderChunkSize );
	Msg( __LINE__, __FILE__, "readheader - header.LanguageCount = %d.", header.LanguageCount );
	Msg( __LINE__, __FILE__, "readheader - header.Flags = %d.", header.Flags );

    ASSERT( header.ChunkID == LOCALEFILE_HEADERCHUNKID ); /* ensure that this is a valid .loc file */

    /* read index chunk if present */
    if ( header.Flags == 1 ) {

        int IndexChunkSize;
        int IndexChunkPos = header.ChunkSize;

        /* read index chunk size */
//		VERIFY(gseek(g, IndexChunkPos + 4));
        if( !gseek( g, IndexChunkPos + 4)) {
			return ok;
		}

		Msg( __LINE__, __FILE__, "readheader - seek to = %d.", IndexChunkPos + 4 );

//		VERIFY(gread(g, &IndexChunkSize, 4) == 4);
        if( gread( g, &IndexChunkSize, 4) != 4 ) {
			return ok;
		}

		Msg( __LINE__, __FILE__, "readheader - IndexChunkSize = %d.", IndexChunkSize );

        /* alloc and read index chunk */
        lx->pIndex[lx->BankIndex] = (LOCALEFILE_INDEXCHUNK *)galloc((long)IndexChunkSize );
        if (lx->pIndex[lx->BankIndex]) {

//			VERIFY(gseek(g, IndexChunkPos));
            gseek( g, IndexChunkPos );

			Msg( __LINE__, __FILE__, "readheader - seek to = %d.", IndexChunkPos );

//			VERIFY(gread(g, lx->pIndex[lx->BankIndex], IndexChunkSize) == IndexChunkSize);
            if ( gread(g, lx->pIndex[lx->BankIndex], IndexChunkSize ) != IndexChunkSize ) {
				return ok;
			}
			Msg( __LINE__, __FILE__, "readheader - IndexChunkSize = %d.", IndexChunkSize );

            ASSERT( lx->pIndex[lx->BankIndex]->ChunkID == LOCALEFILE_INDEXCHUNKID );

			ok = 1;
        }
    }
	Msg( __LINE__, __FILE__, "readheader - exiting." );

	return ok;
}

static int readstrings( GSTREAM* g, int LanguageID )
{
	Msg( __LINE__, __FILE__, "readstrings:: g ok? %d.", ((g!= NULL)?1:0));

    int ok = 0;

    int LanguageChunkOffsetPos = 16 + LanguageID*4;
    int LanguageChunkPos = 0;
    int LanguageChunkSize = -1;

    /* read offset to language chunk */
//	VERIFY(gseek(g, (int)LanguageChunkOffsetPos));
//	VERIFY(gread(g, &LanguageChunkPos, 4) == 4);
    if( !gseek( g, (int)LanguageChunkOffsetPos )) {
		return ok;
	}
    if( gread( g, &LanguageChunkPos, 4 ) != 4 ) {
		return ok;
	}

    /* read language chunk size */
//	VERIFY(gseek(g, LanguageChunkPos + 4));
//	VERIFY(gread(g, &LanguageChunkSize, 4) == 4);
    if( !gseek( g, LanguageChunkPos + 4 )) {
		return ok;
	}   
	if( gread( g, &LanguageChunkSize, 4 ) != 4 ) {
		return ok;
	}   

	Msg( __LINE__, __FILE__, "readstrings::LanguageChunkOffsetPos = %d.", LanguageChunkOffsetPos );
	Msg( __LINE__, __FILE__, "readstrings::LanguageChunkPos = %d.", LanguageChunkPos );
	Msg( __LINE__, __FILE__, "readstrings::LanguageChunkSize = %d.", LanguageChunkSize );

    /* alloc and read language chunk */
    lx->pBank[lx->BankIndex] = (LOCALEFILE_LANGUAGECHUNK *)galloc((long)LanguageChunkSize);
    if (lx->pBank[lx->BankIndex]) {

		Msg( __LINE__, __FILE__, "readstrings:: A." );

//		VERIFY(gseek(g, LanguageChunkPos));
//		VERIFY(gread(g, lx->pBank[lx->BankIndex], LanguageChunkSize) == LanguageChunkSize);
		if( !gseek( g, LanguageChunkPos )) {
			return ok;
		}   
		if( gread( g, lx->pBank[lx->BankIndex], LanguageChunkSize ) != LanguageChunkSize ) {
			return ok;
		}   
        
		ASSERT(lx->pBank[lx->BankIndex]->ChunkID == LOCALEFILE_LANGUAGECHUNKID);
        ok = 1;
    }
    return ok;
}

int LOCALE_loadtable(const char* PathName, int LanguageID)
{
    int ok = 0;
    GSTREAM* g;

    ASSERT(LOCALE_isinitialized());             /* must call LOCALE_init before calling this function */
    ASSERT(lx->pBank[lx->BankIndex] == NULL);   /* bank must be empty before loading a new table */
    ASSERT(lx->pIndex[lx->BankIndex] == NULL);  /* bank must be empty before loading a new table */

    g = gopen( PathName );
    if( g != NULL ) {

		Msg( __LINE__, __FILE__, "LOCALE_loadtable-- file opened." );

        if( readheader(g)) {

			Msg( __LINE__, __FILE__, "LOCALE_loadtable-- readstrings." );

		    ok = readstrings( g, LanguageID );

			Msg( __LINE__, __FILE__, "LOCALE_loadtable-- ok = %d ).", ok );
		}
        gclose(g);
    }
    return ok;
}

/*
;
; ABSTRACT
;
; LOCALE_purgetable - OBSOLETE 
;
; Make all references to LOCALE_freetable
;
; END ABSTRACT
;
*/

/*
;
; ABSTRACT
;
; LOCALE_freetable - Free the string table in the current bank
;
;
; SUMMARY
;
; #include "realfont.h"
;
; void LOCALE_freetable(void)
;
; DESCRIPTION
;
; Frees the table loaded in the current bank.  There must be a
; table loaded in the current bank.  Use LOCALE_getbankstringcount
; to determine if the bank is free or not.
;
; SEE ALSO
;
; LOCALE_loadtable, LOCALE_getbankstringcount
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
;
; END ABSTRACT
;
*/

void LOCALE_freetable(void)
{
	if( lx != NULL ) {

		ASSERT(LOCALE_isinitialized());			/* must call LOCALE_init before calling this function */
		ASSERT(lx->pBank[lx->BankIndex]);       /* table must be loaded before calling this function  */

	    /* free string bank */
		gfree(lx->pBank[lx->BankIndex]);
	    lx->pBank[lx->BankIndex] = NULL;

		/* if the bank has an index loaded, free that as well */
	    if (lx->pIndex[lx->BankIndex]) {
		    gfree(lx->pIndex[lx->BankIndex]);
			lx->pIndex[lx->BankIndex] = NULL;
	    }
	}
}

/*
;
; ABSTRACT
;
; LOCALE_getstring - Return the specified string from the current bank
;
; SUMMARY
;
; #include "realfont.h"
;
; const char* LOCALE_getstring( StringID )
;   int StringID;   ID of string to return
;
; DESCRIPTION
;
; Returns the string specified from the current bank.  There must
; be a string table loaded into the current bank.  Use the String
; ID specified in the header file created by Locomoto.  Note that
; the string pointer is a const pointer.  Do not modify the string
; or the Locale library may return invalid results.
;
; If the .loc file was created with an index StringID can be any
; valid integer in the range 0..65535.  If no index was created
; with the .loc file StringID will be a zero based array index.
;
; String is returned by const for a reason.  Bad things will happen 
; if you modify it.  You have been warned.
;
; SEE ALSO
;
; LOCALE_loadtable, LOCALE_getbankstringcount
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
;
; END ABSTRACT
;
*/

#include <stdlib.h>     // for bsearch function

static int compare ( const void* arg1, const void* arg2 )
{
    const unsigned short* s1 = (const unsigned short*)(arg1);
    const unsigned short* s2 = (const unsigned short*)(arg2);
    return (*s1) - (*s2);
}

static int getstringbyindex( unsigned short key, const INDEX* pIndex )
{
    int index = 0;
    unsigned short* result;
    unsigned char*  base;   /* pointer to base of string id table */

    ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
    ASSERT(pIndex != NULL); /* index not loaded - .loc file must have index created (use -i option) */

    base	= ((unsigned char*)pIndex) + LOCALEFILE_INDEXCHUNK_STRINGID_OFFSET;
    result	= (unsigned short*)bsearch((unsigned char *)&key, base, pIndex->StringCount, 4, compare);

    if (result != NULL) {
        /* index is the second unsigned short */
        ++result;
        index = *result;
    } else {
        index = -1;
    }
    return index;
}

const char* LOCALE_getstring( int StringID )
{
    const char* p;							/* pointer to string, NULL if string cannot be found */

	Msg( __LINE__, __FILE__, "Locale_getstring::( %d ).", StringID );

    ASSERT( LOCALE_isinitialized());		/* must call LOCALE_init before calling this function */

    /* get string array index from the index if it exists */
    if ( lx->pIndex[ lx->BankIndex ] != NULL ) {
        StringID = getstringbyindex((unsigned short)StringID, lx->pIndex[lx->BankIndex]);
    }

	Msg( __LINE__, __FILE__, "Locale_getstring::( %d ).", StringID );
	Msg( __LINE__, __FILE__, "Locale_getstring::( lx->BankIndex = %d ).", lx->BankIndex );
	Msg( __LINE__, __FILE__, "Locale_getstring::( lx->pBank[lx->BankIndex]->StringCount = %d ).", lx->pBank[lx->BankIndex]->StringCount );

    if ((StringID >= 0) && (StringID < (int)(lx->pBank[lx->BankIndex]->StringCount ))) {

		Msg( __LINE__, __FILE__, "Locale_getstring:: A" );

        unsigned int offset;

        p = (const char*)(lx->pBank[lx->BankIndex]);

		Msg( __LINE__, __FILE__, "Locale_getstring:: B" );

        offset = *(unsigned int*)(p + LOCALEFILE_LANGUAGECHUNK_STRING_OFFSET + StringID*4);

		Msg( __LINE__, __FILE__, "Locale_getstring:: C" );

        p += offset;

		Msg( __LINE__, __FILE__, "Locale_getstring:: D" );


    } else {
        p = NULL;
    }

	Msg( __LINE__, __FILE__, L"%s", 1252, (wchar_t *)p );

    return p;
}


/*
;
; ABSTRACT
;
; LOCALE_getstr - return selected string from the specified .loc file
;
;
; SUMMARY
;
; #include "realfont.h"
;
; const char* LOCALE_getstr(stringid)
;
;   int stringid;   // string id to return
;
; DESCRIPTION
;
; Returns the string identified by stringid from the specified 
; .loc file.  Use the string ID specified in the header file created 
; by Locomoto.  Note that the string pointer is a const pointer.  Do 
; not modify the string or the Locale library may return invalid results.
;
; If your strings are Unicode strings, cast the result to a const USTR *.
;
; If the .loc file was created with an index stringid can be any
; valid integer in the range 0..65535.  If no index was created
; with the .loc file stringid will be a zero based array index.
;
; String is returned by const for a reason.  Bad things will happen 
; if you modify it.  You have been warned.
;
; SEE ALSO
;
; EXAMPLE
;
; locale_eg.c
;
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
;
; END ABSTRACT
;
*/

int LOCALElanguageid = 0;

const char* LOCALE_getstr( const void* pLocFile, int StringID )
{
	const char* p; /* pointer to string, NULL if string cannot be found */

    HEADER* pHeader;
    BANK*   pBank;

    ASSERT(pLocFile != NULL);

    pHeader = (LOCALEFILE_HEADERCHUNK*)(pLocFile);
    ASSERT(pHeader->ChunkID == LOCALEFILE_HEADERCHUNKID);
    ASSERT(pHeader->LanguageCount >= 1);

    if( pHeader->Flags == 1 ) {

        /* file has an index */
        INDEX* pIndex = (INDEX*)((unsigned char*)(pLocFile) + pHeader->ChunkSize);
        StringID = getstringbyindex((unsigned short)StringID, pIndex);
    }

    /* get pointer to string bank */
    {
        int offset = *((int*)(pLocFile) + 4 + LOCALElanguageid); 
        pBank = (BANK*)((unsigned char*)(pLocFile) + offset);
    }
    
    if ((StringID >= 0) && (StringID < (int)(pBank->StringCount))) {

        unsigned int offset;

        p = (const char*)(pBank);
        offset = *(unsigned int*)(p + LOCALEFILE_LANGUAGECHUNK_STRING_OFFSET + StringID*4);
        p += offset;

    } else {
        p = NULL;
    }

    return p;
}

