/*===========================================================================
 *
 * File:	Dfrmb.CPP
 * Author:	Dave Humphrey (uesp@m0use.net)
 * Created On:	Friday, June 29, 2001
 *
 * Implements the CDFRmbRecord and CDFRmbFile classes for handling 
 * Daggerfall RMB files from the BLOCKS.BSA file.
 *
 *=========================================================================*/

	/* Include Files */
#include "uesp/dagger/bsa/dfrmb.h"
#include "uesp/dagger/bsa/dfarchdt.h"


/*===========================================================================
 *
 * Begin Local Variable Definitions
 *
 *=========================================================================*/
  DEFINE_FILE();

	/* Local array of RMB filenames */
  char l_DFRMBFilenames[45][5] = {
	  "TVRN",  "GENR",  "RESI",  "WEAP",  "ARMR",  "ALCH",  "BANK",  "BOOK",
	  "CLOT",  "FURN",  "GEMS",  "LIBR",  "PAWN",  "TEMP",  "TEMP",  "PALA",
	  "FARM",  "DUNG",  "CAST",  "MANR",  "SHRI",  "RUIN",  "SHCK",  "GRVE",
	  "FILL",  "KRAV",  "KDRA",  "KOWL",  "KMOO",  "KCAN",  "KFLA",  "KHOR",
	  "KROS",  "KWHE",  "KSCA",  "KHAW",  "MAGE",  "THIE",  "DARK",  "FIGH",
 	  "CUST",  "WALL",  "MARK",  "SHIP",  "WITC" 
    };

/*===========================================================================
 *		End of Local Variable Definitions
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Constructor
 *
 *=========================================================================*/
CDFRmbRecord::CDFRmbRecord() {

	/* Initialize array pointers */
  m_p3DObjectRecords = NULL;
  m_pFlatObjectRecords = NULL;
  m_pSection3Records = NULL;
  m_pPeopleRecords = NULL;
  m_pDoorRecords = NULL;

  m_ExtraByte = 0;
  m_HasExtraByte = FALSE;

  	/* Initialize header data */
  memset(&m_Header, 0, sizeof(dfrmb_header_t));
 }
/*===========================================================================
 *		End of Class CDFRmbRecord Constructor	
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Destructor
 *
 *=========================================================================*/
void CDFRmbRecord::Destroy (void) {
  DEFINE_FUNCTION("CDFRmbRecord::Destroy()");

	/* Unallocate memory from object arrays */
  DestroyArrayPointer(m_p3DObjectRecords);
  DestroyArrayPointer(m_pFlatObjectRecords);
  DestroyArrayPointer(m_pSection3Records);
  DestroyArrayPointer(m_pPeopleRecords);
  DestroyArrayPointer(m_pDoorRecords);

	/* Clear header data */
  memset(&m_Header, 0, sizeof(dfrmb_header_t));
  m_HasExtraByte = FALSE;
 }
/*===========================================================================
 *		End of Class CDFRmbRecord Destructor
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Method - boolean Export3DS (File3DS, Flags, pTransPoint);
 *
 * Export the RMB file to the given 3DS file.  The optional flags indicate
 * which objects to include in the export.  Assumes that the 3DS file is
 * already open for output.  The point object, if not NULL, gives the 
 * optional position translation for the RMB record.
 *
 *=========================================================================*/
boolean CDFRmbRecord::Export3DS (C3dsFile& File3DS, const int Flags, const df3dpoint_t* pTransPoint) {
  DEFINE_FUNCTION("CDFRmbRecord::Export3DS()");
  boolean  Result = TRUE;
      
	/* Export the relevant sections */
  if (Flags & DFRMB_FLAG_3DOBJECTS) {
    if (Flags & DFRMB_FLAG_OUTSIDE) 
      Result &= Export3DS_3DObjects(File3DS, "RmbO3d", pTransPoint);
    else
      Result &= Export3DS_3DObjects(File3DS, "RmbI3d", pTransPoint);
   }

  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbRecord::Export3DS()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Method - 
 *	boolean Export3DS_3DObjects (File3DS, pNameHeader, pTransPoint);
 *
 * Protected class method to export the 3D objects of the RMB to the given
 * 3DS file.  Returns FALSE on any error.  The optional point object gives
 * the position translation to apply to all objects in the record.  The name
 * header string is used to name the 3DS objects.
 *
 *=========================================================================*/
boolean CDFRmbRecord::Export3DS_3DObjects (C3dsFile& File3DS, const char* pNameHeader, const df3dpoint_t* pTransPoint) {
  DEFINE_FUNCTION("CDFRmbRecord::Export3DS_3DObjects()");
  boolean      Result;
  float	       MeshMatrix[12];
  CDF3dObject* pObject;
  long         ObjectValue;
  float        ObjectAngle;
  float        XPos;
  float        YPos;
  float        ZPos;
  int          Index;

	/* Ensure valid input */
  ASSERT(pNameHeader != NULL);

	/* Ignore if no 3D objects to export */
  if (m_p3DObjectRecords == NULL || m_Header.Num3DObjectRecords == 0) return (TRUE);

	/* Export each 3D object in array */
  for (Index = 0; Index < m_Header.Num3DObjectRecords; Index++) {
    ObjectValue = m_p3DObjectRecords[Index].Get3DObjectValue();

		/* Get the specified 3D object */
    Result = GetDF3dObject(&pObject, ObjectValue);
    if (!Result) return (FALSE);
  
		/* Get object rotation/position translation */
    ObjectAngle = m_p3DObjectRecords[Index].Get3DObjectAngle();
    XPos =  (float) m_p3DObjectRecords[Index].Get3DObjectX();
    ZPos =  (float) m_p3DObjectRecords[Index].Get3DObjectZ();
   
   	 	/* Compute the proper Y-Position for the object */
    switch (m_p3DObjectRecords[Index].Unknown1) {
      case 3:
	YPos =  -m_p3DObjectRecords[Index].Get3DObjectY();
	YPos -= (float) (pObject->GetMaxY() - pObject->GetMinY())/DF_COOR_BLOCKTO3D/2;
	break;
      case 4:
        YPos = m_p3DObjectRecords[Index].Get3DObjectY();
        break;
      case 13:
        YPos = m_p3DObjectRecords[Index].Get3DObjectY();
	break;
      default:
        YPos = (float) m_p3DObjectRecords[Index].Get3DObjectY();
	SystemLog.Printf ("\t\t%3d) Unknown1 = %d (%ld, %ld, %6.0f)", Index+1, m_p3DObjectRecords[Index].Unknown1, m_p3DObjectRecords[Index].YPos2,  m_p3DObjectRecords[Index].YPos1, YPos);
	break;
     } 

    //SystemLog.Printf ("\t\t%3d) Unknown1 = %d (%ld, %ld, %6.0f)", Index+1, m_p3DObjectRecords[Index].Unknown1, m_p3DObjectRecords[Index].YPos2,  m_p3DObjectRecords[Index].YPos1, YPos);

		/* Apply the optional group translation */
    if (pTransPoint != NULL) {
      XPos += (float) pTransPoint->X;
      YPos += (float) pTransPoint->Y;
      ZPos += (float) pTransPoint->Z;
     }

		/* Apply the 3DS coordinate scaling factor */
    XPos *= (float)DF_COOR_BLOCKTO3D/(float)DF3D_3DS_FACTOR;
    YPos *= (float)DF_COOR_BLOCKTO3D/(float)DF3D_3DS_FACTOR;
    ZPos *= (float)DF_COOR_BLOCKTO3D/(float)DF3D_3DS_FACTOR;

    C3dsFile::CreateMeshMatrix(&MeshMatrix[0], 
				XPos, ZPos, -YPos,		/* Position */
				1.0,  1.0,   1.0,		/* Scale */
				0.0,  0.0,   ObjectAngle);	/* Rotation, radians */

		/* Export object */
    //Result = pObject->Export3DSObject(File3DS, &MeshMatrix[0]);
    Result = ExportDF3dObjectTo3DS(File3DS, *pObject, &MeshMatrix[0], NULL);
    if (!Result) return (FALSE);

LOOPEND:;
   }

  return (TRUE);
 }
/*===========================================================================
 *		End of Class Method CDFRmbRecord::Export3DS_3DObjects()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Method - boolean ReadRecord (void);
 *
 * Attempts to read the record from the current position in the file stream.
 * Returns FALSE on any error.  
 *
 *=========================================================================*/
boolean CDFRmbRecord::ReadRecord (void) {  
  DEFINE_FUNCTION("CDFRmbRecord::ReadRecord()");
  boolean Result;

	/* Delete the current contents, if any */
  Destroy();

	/* Attempt to read in all the record data sections */
  Result = ReadHeader();
  if (Result) Result = Read3DObjects();
  if (Result) Result = ReadFlatObjects();
  if (Result) Result = ReadSection3();
  if (Result) Result = ReadPeople();
  if (Result) Result = ReadDoors();

  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbRecord::ReadRecord()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Method - boolean ReadHeader (void);
 *
 * Attempts to read the record header from the current position in the 
 * file stream. Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbRecord::ReadHeader (void) {
  DEFINE_FUNCTION("CDFRmbRecord::ReadHeader()");
  boolean Result;

	/* Attempt to read the header all at once */
  Result = Read((char *)&m_Header, sizeof(dfrmb_header_t));
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbRecord::ReadHeader()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Method - boolean Read3DObjects (void);
 *
 * Attempts to read the record 3D Object data from the current position in the 
 * file stream. Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbRecord::Read3DObjects (void) {
  DEFINE_FUNCTION("CDFRmbRecord::Read3DObjects()");
  boolean Result;

	/* Ensure valid object state */
  ASSERT(m_p3DObjectRecords == NULL);
  if (m_Header.Num3DObjectRecords == 0) return (TRUE);
  
	/* Allocate pointer array and read data */
  CreateArrayPointer(m_p3DObjectRecords, dfrmb_3dobject_t, m_Header.Num3DObjectRecords);
  Result = ReadEx((char *)m_p3DObjectRecords, sizeof(dfrmb_3dobject_t), m_Header.Num3DObjectRecords);
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbRecord::Read3DObjects()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Method - boolean ReadFlatObjects (void);
 *
 * Attempts to read the record section2 data from the current position in the 
 * file stream. Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbRecord::ReadFlatObjects (void) {
  DEFINE_FUNCTION("CDFRmbRecord::ReadFlatObjects()")
  boolean Result;

  	/* Ensure valid object state */
  ASSERT(m_pFlatObjectRecords == NULL);
  if (m_Header.NumFlatObjectRecords == 0) return (TRUE);

	/* Allocate pointer array and read data */
  CreateArrayPointer(m_pFlatObjectRecords, dfrmb_flatobject_t, m_Header.NumFlatObjectRecords);
  Result = ReadEx((char *)m_pFlatObjectRecords, sizeof(dfrmb_flatobject_t), m_Header.NumFlatObjectRecords);
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbRecord::ReadFlatObjects()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Method - boolean ReadSection3 (void);
 *
 * Attempts to read the record section3 data from the current position in the 
 * file stream. Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbRecord::ReadSection3 (void) {
  DEFINE_FUNCTION("CDFRmbRecord::ReadSection3()");
  boolean Result;

	/* Ensure valid object state */
  ASSERT(m_pSection3Records == NULL);
  if (m_Header.NumSection3Records == 0) return (TRUE);

	/* Allocate pointer array and read data */
  CreateArrayPointer(m_pSection3Records, dfrmb_section3_t, m_Header.NumSection3Records);
  Result = ReadEx ((char *)m_pSection3Records, sizeof(dfrmb_section3_t), m_Header.NumSection3Records);
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbRecord::ReadSection3()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Method - boolean ReadPeople (void);
 *
 * Attempts to read the record section4 data from the current position in the 
 * file stream. Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbRecord::ReadPeople (void) {
  DEFINE_FUNCTION("CDFRmbRecord::ReadPeople()");
  boolean Result;

	/* Ensure valid object state */
  ASSERT(m_pPeopleRecords == NULL);
  if (m_Header.NumPeopleRecords == 0) return (TRUE);

	/* Allocate pointer array and read data */
  CreateArrayPointer(m_pPeopleRecords, dfrmb_people_t, m_Header.NumPeopleRecords);
  Result = ReadEx ((char *)m_pPeopleRecords, sizeof(dfrmb_people_t), m_Header.NumPeopleRecords);
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbRecord::ReadPeople()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbRecord Method - boolean ReadDoors (void);
 *
 * Attempts to read the record Door data from the current position in the 
 * file stream. Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbRecord::ReadDoors (void) {
  DEFINE_FUNCTION("CDFRmbRecord::ReadDoors()");
  boolean Result;

	/* Ensure valid object state */
  ASSERT(m_pDoorRecords == NULL);
  if (m_Header.NumDoorRecords == 0) return (TRUE);

	/* Allocate pointer array and read data */
  CreateArrayPointer(m_pDoorRecords, dfrmb_door_t, m_Header.NumDoorRecords);
  Result = ReadEx ((char *)m_pDoorRecords, sizeof(dfrmb_door_t), m_Header.NumDoorRecords);
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbRecord::ReadDoors()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbFile Constructor
 *
 *=========================================================================*/
CDFRmbFile::CDFRmbFile() {

	/* Initialize array pointers */
  m_pInsideRecords  = NULL;
  m_pOutsideRecords = NULL;
  m_p3DObjects      = NULL;
  m_pFlatObjects    = NULL;
  
  m_RecordOffset = 0;
  m_RecordSize = 0;

	/* Initialize fixed length data */
  memset(&m_FLDData, 0, sizeof(dfrmbfld_t));
 }
/*===========================================================================
 *		End of Class CDFRmbFile Constructor	
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbFile Destructor
 *
 *=========================================================================*/
void CDFRmbFile::Destroy (void) {
  DEFINE_FUNCTION("CDFRmbFile::Destroy()");

	/* Unallocate memory from arrays */
  DestroyArrayPointer(m_pOutsideRecords);
  DestroyArrayPointer(m_pInsideRecords);
  DestroyArrayPointer(m_p3DObjects);
  DestroyArrayPointer(m_pFlatObjects);

  m_RecordOffset = 0;
  m_RecordSize = 0;

	/* Initialize fixed length data */
  memset(&m_FLDData, 0, sizeof(dfrmbfld_t));
 }
/*===========================================================================
 *		End of Class CDFRmbFile Destructor
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbFile Method - boolean Export3DS (File3DS, Flags);
 *
 * Attempts to export the RMB file to the given 3DS file.  Returns FALSE
 * on any error.
 *
 *=========================================================================*/
boolean CDFRmbFile::Export3DS (C3dsFile& File3DS, const int Flags) {
  //DEFINE_FUNCTION("CDFRmbFile::Export3DS()");
  boolean     Result;
  int         Index;
  df3dpoint_t TransPoint;

	/* Attempt to output 3DS chunk headers */
  Result  = File3DS.StartMainChunk();
  Result &= File3DS.StartEditChunk();

	/* Output each sub-block to the 3DS file */
  for (Index = 0; Index < m_FLDData.NumBlocks; Index++) {

		/* Get the position translation for the sub-block */
    TransPoint.X = m_FLDData.PositionRecords[Index].XPos;
    TransPoint.Y = 0; 
    TransPoint.Z = m_FLDData.PositionRecords[Index].ZPos;

		/* Export the outside objects */
    if ((Flags & DFRMB_FLAG_OUTSIDE)) {
      Result &= m_pOutsideRecords[Index].Export3DS(File3DS, Flags, &TransPoint);
     }

		/* Export the inside objects */
    if ((Flags & DFRMB_FLAG_INSIDE)) {
      Result &= m_pInsideRecords[Index].Export3DS(File3DS, Flags, &TransPoint);
     }
   }

	/* End the main chunk sections */
  Result &= File3DS.EndEditChunk();
  Result &= File3DS.EndMainChunk();
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbFile::Export3DS()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbFile Method - boolean ReadRMB (RecordSize);
 *
 * Attempts to read the RMB file from the current position in the file stream.
 * Returns FALSE on any error.
 *
 *=========================================================================*/
boolean CDFRmbFile::ReadRMB (const long RecordSize) {
  DEFINE_FUNCTION("CDFRmbFile::ReadRMB()");
  boolean Result;

	/* Delete any current information */
  Destroy();

	/* Save record information */
  m_RecordOffset = Tell();
  m_RecordSize   = RecordSize;

	/* Attempt to read in all the record data */
  Result = ReadFLD();
  if (Result) Result = ReadBlocks();
  if (Result) Result = Read3DObjects();
  if (Result) Result = ReadFlatObjects();
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbFile::ReadRMB()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbFile Method - boolean ReadFLD (void);
 *
 * Attempts to read the RMB file FLD data from the current position in the
 * file stream.  Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbFile::ReadFLD (void) {
  DEFINE_FUNCTION("CDFRmbFile::ReadFLD()");
  boolean Result;

	/* Read in FLD all at once */
  Result = Read((char *)&m_FLDData, sizeof(dfrmbfld_t));
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbFile::ReadFLD()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbFile Method - boolean ReadBlocks (void);
 *
 * Attempts to read the RMB blocks data from the current position in the
 * file stream.  Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbFile::ReadBlocks (void) {
  DEFINE_FUNCTION("CDFRmbFile::ReadBlocks()");
  boolean Result;
  int     Index;
  char    InputByte;
  long    RecOffset;
  long    NumExtraBytes;
  
	/* Ensure valid object state */
  ASSERT(m_pOutsideRecords == NULL && m_pInsideRecords == NULL);
  if (m_FLDData.NumBlocks == 0) return (TRUE);

	/* Allocate the block arrays */
  CreateArrayPointer(m_pOutsideRecords, CDFRmbRecord, m_FLDData.NumBlocks);
  CreateArrayPointer(m_pInsideRecords,  CDFRmbRecord, m_FLDData.NumBlocks);

	/* Read all block sub-records */
  for (Index = 0; Index < m_FLDData.NumBlocks; Index++) {
    RecOffset = Tell();

		/* Attempt to read in the first record set */
    m_pOutsideRecords[Index].Attach(GetHandle());
    Result = m_pOutsideRecords[Index].ReadRecord();
    m_pOutsideRecords[Index].Detach();
    if (!Result) return (FALSE);

	    /* Attempt to read in the second record set */
    m_pInsideRecords[Index].Attach(GetHandle());
    Result = m_pInsideRecords[Index].ReadRecord();
    m_pInsideRecords[Index].Detach();
    if (!Result) return (FALSE);

		/* Compute amount of extra bytes remaining */
    NumExtraBytes = Tell() - RecOffset - m_FLDData.BlockSizes[Index].RecordSize;

		/* Special case of 1 extra byte at end of record */
    if (NumExtraBytes == -1) {
      Result = ReadChar(InputByte);
      if (!Result) return (FALSE);
      m_pInsideRecords[Index].SetExtraByte(InputByte);
     }
		/* Ensure there are no extra bytes left over */
    else if (NumExtraBytes != 0) {
      ErrorHandler.AddError(DFERR_RMB_RECORDSIZE, "ExtraBytes=%ld", NumExtraBytes);
      return (FALSE);
     }
     
    		/* Jump to the proper record offset for the next data */
    Result = Seek(RecOffset + m_FLDData.BlockSizes[Index].RecordSize, SEEK_SET);
    if (!Result) return (FALSE);
   }

  return (TRUE);
 }
/*===========================================================================
 *		End of Class Method CDFRmbFile::ReadBlocks()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbFile Method - boolean Read3DObjects (void);
 *
 * Attempts to read the RMB 3D Object data from the current position in the
 * file stream.  Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbFile::Read3DObjects (void) {
  DEFINE_FUNCTION("CDFRmbFile::Read3DObjects()");
  boolean Result;

	/* Ensure valid object state */
  ASSERT(m_p3DObjects == NULL);
  if (m_FLDData.Num3DObjects == 0) return (TRUE);

	/* Allocate and read data */
  CreateArrayPointer(m_p3DObjects, dfrmb_3dobject_t, m_FLDData.Num3DObjects);
  Result = ReadEx ((char *)m_p3DObjects, sizeof(dfrmb_3dobject_t), m_FLDData.Num3DObjects);
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbFile::Read3DObjects()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CDFRmbFile Method - boolean ReadFlatObjects (void);
 *
 * Attempts to read the RMB Flat Object data from the current position in the
 * file stream.  Returns FALSE on any error. Protected class method.
 *
 *=========================================================================*/
boolean CDFRmbFile::ReadFlatObjects (void) {
  DEFINE_FUNCTION("CDFRmbFile::ReadFlatObjects()");
  boolean Result;

	/* Ensure valid object state */
  ASSERT(m_pFlatObjects == NULL);
  if (m_FLDData.NumFlatObjects == 0) return (TRUE);

	/* Allocate object array and read data */
  CreateArrayPointer(m_pFlatObjects, dfrmb_flatobject_t, m_FLDData.NumFlatObjects);
  Result = ReadEx ((char *)m_pFlatObjects, sizeof(dfrmb_flatobject_t), m_FLDData.NumFlatObjects);
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CDFRmbFile::ReadRecords3()
 *=========================================================================*/



/*===========================================================================
 *
 * Function - boolean GetDFRmbFileChar (pString, CharIndex);
 *
 * Converts an RMB character index to a 2 byte string.  The input string
 * pointer must be valid and be at least 3 bytes in size.  Returns FALSE
 * if the given index is not valid.
 *
 *=========================================================================*/
boolean GetDFRmbFileChar (char* pString, const int CharIndex) {
  DEFINE_FUNCTION("GetDFRmbFileChar()");

	/* Ensure valid input */
  ASSERT(pString != NULL && CharIndex >= 0);

	/* Fill in the file character string */
  if (CharIndex < 0x0F)
    strcpy(pString, "AA");
  else if (CharIndex <= 0x1F)
    strcpy(pString, "DA");
  else if (CharIndex <= 0x2F)
    strcpy(pString, "AL");
  else if (CharIndex <= 0x3F)
    strcpy(pString, "DL");
  else if (CharIndex <= 0x4F)
    strcpy(pString, "AM");
  else if (CharIndex <= 0x5F)
    strcpy(pString, "DM");
  else if (CharIndex <= 0x6F)
    strcpy(pString, "AS");
  else if (CharIndex <= 0x7F)
    strcpy(pString, "DS");
  else if (CharIndex <= 0x8F)
    strcpy(pString, "AA");
  else if (CharIndex <= 0x9F) 
    strcpy(pString, "DA");
  else {	/* Invalid character index */
    *pString = NULL_CHAR;
    ErrorHandler.AddError(DFERR_RMB_CHARINDEX, "CharIndex=%d", CharIndex);
    return (FALSE);
   }

  return (TRUE);
 }
/*===========================================================================
 *		End of Function GetDFRmbFileChar()
 *=========================================================================*/


/*===========================================================================
 *
 * Function - boolean GetDFRmbFilename (pString, Index);
 *
 * Copies the specified RMB filename indicated by the index value into the
 * given string. The index should range from 0 to 44 or NULL will be returned.
 * The input string must be at least 5 bytes in size.
 *
 *=========================================================================*/
boolean GetDFRmbFilename (char* pString, const int Index) {
  DEFINE_FUNCTION("GetDFRmbFilename()");

	/* Ensure a valid input */
  ASSERT(pString != NULL);

	/* Ensure a valid index */
  if (Index < 0 || Index >= DFRMB_MAX_FILEINDEX) {
    ASSERT(FALSE);
    return (FALSE);
   }

	/* Copy the string */
  strnncpy(pString, l_DFRMBFilenames[Index], 4);
  return (TRUE);
 }
/*===========================================================================
 *		End of Function GetDFRmbFilename()
 *=========================================================================*/