/*
**	termTranslate.c
**
**	Character translation support routines
**
**	Copyright © 1990-1994 by Olaf `Olsen' Barthel
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* Translation chunk header types. */

enum	{	TYPE_NONE, TYPE_SEND, TYPE_RECEIVE };

	/* Master translation table entry types. */

enum	{	TRANSLATION_VERBATIM, TRANSLATION_IGNORE, TRANSLATION_OTHER };

	/* Symbolic names for character codes. */

STATIC struct { STRPTR Name; UBYTE Value; } CodeTab[44] =
{
	{	"NUL",	0	},
	{	"SOH",	1	},
	{	"STX",	2	},
	{	"ETX",	3	},
	{	"EOT",	4	},
	{	"ENQ",	5	},
	{	"ACK",	6	},
	{	"BEL",	7	},
	{	"BS",	8	},
	{	"HT",	9	},
	{	"LF",	10	},
	{	"VT",	11	},
	{	"FF",	12	},
	{	"CR",	13	},
	{	"SO",	14	},
	{	"SI",	15	},
	{	"DLE",	16	},
	{	"DC1",	17	},
	{	"DC2",	18	},
	{	"DC3",	19	},
	{	"DC4",	20	},
	{	"NAK",	21	},
	{	"SYN",	22	},
	{	"ETB",	23	},
	{	"CAN",	24	},
	{	"EM",	25	},
	{	"SUB",	26	},
	{	"ESC",	27	},
	{	"FS",	28	},
	{	"GS",	29	},
	{	"RS",	30	},
	{	"US",	31	},
	{	"SP",	32	},
	{	"DEL",	127	},
	{	"SS2",	142	},
	{	"SS3",	143	},
	{	"DCS",	144	},
	{	"CSI",	155	},
	{	"ST",	156	},
	{	"OSC",	157	},
	{	"PM",	158	},
	{	"APC",	159	},
	{	"NBS",	160	},
	{	"SHY",	173	}
};

	/* TranslateSetup():
	 *
	 *	Set up for buffer translation.
	 */

VOID __regargs
TranslateSetup(struct TranslationHandle *Handle,STRPTR SourceBuffer,LONG SourceLen,STRPTR DestinationBuffer,LONG DestinationLen,struct TranslationEntry **Table)
{
	Handle -> LocalBuffer		= NULL;
	Handle -> LocalLen		= 0;

	Handle -> SourceBuffer		= SourceBuffer;
	Handle -> SourceLen		= SourceLen;

	Handle -> DestinationBuffer	= DestinationBuffer;
	Handle -> DestinationLen	= DestinationLen;

	Handle -> Table			= Table;
}

	/* TranslateBuffer(struct TranslationHandle *Handle):
	 *
	 *	Translate buffer contents according to
	 *	translation table contents.
	 */

LONG __regargs
TranslateBuffer(struct TranslationHandle *Handle)
{
	register STRPTR				 Data		= Handle -> DestinationBuffer;
	register LONG				 BytesWritten	= 0;
	register struct TranslationEntry	*Entry;

		/* Are we to return any translated data? */

	while(Handle -> LocalLen && BytesWritten < Handle -> DestinationLen)
	{
			/* Decrement number of bytes in buffer. */

		Handle -> LocalLen--;

			/* Return next character. */

		*Data++ = *Handle -> LocalBuffer++;

			/* Add another byte. */

		BytesWritten++;
	}

		/* Loop until done. */

	while(Handle -> SourceLen && BytesWritten < Handle -> DestinationLen)
	{
			/* Another byte eaten. */

		Handle -> SourceLen--;

			/* Get table entry. */

		if(Entry = Handle -> Table[*Handle -> SourceBuffer++])
		{
				/* Copy to local data area. */

			Handle -> LocalBuffer	= Entry -> String;
			Handle -> LocalLen	= Entry -> Len;

				/* Translate the data. */

			while(Handle -> LocalLen && BytesWritten < Handle -> DestinationLen)
			{
					/* Decrement number of bytes in buffer. */

				Handle -> LocalLen--;

					/* Return next character. */

				*Data++ = *Handle -> LocalBuffer++;

					/* Add another byte. */

				BytesWritten++;
			}
		}
	}

	return(BytesWritten);
}

	/* NameToCode(STRPTR Name):
	 *
	 *	Translate a symbolic character code name of numeral.
	 */

UBYTE __regargs
NameToCode(STRPTR Name)
{
	WORD i;

	for(i = 0 ; i < 44 ; i++)
	{
		if(!Stricmp(CodeTab[i] . Name,Name))
			return(CodeTab[i] . Value);
	}

	return((UBYTE)Atol(Name));
}

	/* CodeToName(UBYTE Code):
	 *
	 *	Translate a character code into a symbolic
	 *	name or numeral.
	 */

STRPTR __regargs
CodeToName(UBYTE Code)
{
	STATIC UBYTE Name[6];

	WORD i;

	for(i = 0 ; i < 44 ; i++)
	{
		if(CodeTab[i] . Value == Code)
			return(CodeTab[i] . Name);
	}

	SPrintf(Name,"%03ld",Code);

	return(Name);
}

	/* FreeTranslationTable(struct TranslationEntry **Table):
	 *
	 *	Free a character translation table.
	 */

VOID __regargs
FreeTranslationTable(struct TranslationEntry **Table)
{
	WORD i;

	for(i = 0 ; i < 256 ; i++)
	{
		if(Table[i])
			FreeTranslationEntry(Table[i]);
	}

	FreeVecPooled(Table);
}

	/* AllocTranslationTable():
	 *
	 *	Allocate a character translation table.
	 */

struct TranslationEntry **
AllocTranslationTable()
{
	return((struct TranslationEntry **)AllocVecPooled(sizeof(struct TranslationEntry *) * 256,MEMF_ANY|MEMF_CLEAR));
}

	/* FreeTranslationEntry(struct TranslationEntry *Entry):
	 *
	 *	Free a character translation table entry.
	 */

VOID __regargs
FreeTranslationEntry(struct TranslationEntry *Entry)
{
	FreeVecPooled(Entry);
}

	/* TranslateString(STRPTR From,STRPTR To):
	 *
	 *	Translate a string to contain control codes
	 *	into a string to contain the real codes.
	 */

LONG __regargs
TranslateString(STRPTR From,STRPTR To)
{
	BYTE	GotControl	= FALSE,
		GotEscape	= FALSE;

	LONG	Len	= strlen(From),
		Count	= 0,
		i;

	for(i = 0 ; i < Len ; i++)
	{
		if(!GotControl && !GotEscape)
		{
			if(From[i] == '\\')
			{
				GotControl = TRUE;

				continue;
			}

			if(From[i] == '^')
			{
				GotEscape = TRUE;

				continue;
			}

			To[Count++] = From[i];
		}
		else
		{
			if(GotEscape)
			{
				if(ToUpper(From[i]) >= 'A' && ToUpper(From[i]) <= '_')
					To[Count++] = ToUpper(From[i]) - '@';
				else
					To[Count++] = From[i];

				GotEscape = FALSE;
			}
			else
			{
				if(GotControl)
				{
					switch(ToUpper(From[i]))
					{
							/* These macro commands are plainly
							 * ignored.
							 */

						case '0':
						case '1':
						case '2':
						case '3':
						case '4':
						case '5':
						case '6':

							break;

							/* These are macro commands and
							 * not supported.
							 */

						case 'A':
						case 'C':
						case 'D':
						case 'G':
						case 'H':
						case 'I':
						case 'P':
						case 'U':
						case 'X':

							To[Count++] = '\\';
							To[Count++] = From[i];
							break;

							/* Translate code. */

						case '*':

							i++;

							while(i < Len && From[i] == ' ')
								i++;

							if(i < Len)
							{
								UBYTE DummyBuffer[5],j = 0,Char;

								if(From[i] >= '0' && From[i] <= '9')
								{
									while(j < 3 && i < Len)
									{
										Char = From[i++];

										if(Char >= '0' && Char <= '9')
											DummyBuffer[j++] = Char;
										else
										{
											i--;

											break;
										}
									}
								}
								else
								{
									while(j < 4 && i < Len)
									{
										Char = ToLower(From[i++]);

										if((Char >= '0' && Char <= '9') || (Char >= 'a' && Char <= 'z'))
											DummyBuffer[j++] = Char;
										else
										{
											i--;

											break;
										}
									}
								}

								DummyBuffer[j] = 0;

								To[Count++] = NameToCode(DummyBuffer);
							}

							i--;

							break;

							/* This is a backspace. */

						case 'B':

							To[Count++] = '\b';
							break;

							/* This is a form feed. */

						case 'F':

							To[Count++] = '\f';
							break;

							/* This is a line feed. */

						case 'N':

							To[Count++] = '\n';
							break;

							/* This is a carriage return. */

						case 'R':

							To[Count++] = '\r';
							break;

							/* This is a tab. */

						case 'T':

							To[Count++] = '\t';
							break;

							/* Produce the escape character. */

						case 'E':

							To[Count++] = ESC;
							break;

							/* Stuff the character into the buffer. */

						default:

							To[Count++] = From[i];
							break;
					}

					GotControl = FALSE;
				}
			}
		}
	}

	return(Count);
}

	/* AllocTranslationEntry(STRPTR String):
	 *
	 *	Allocate a character translation table entry.
	 */

struct TranslationEntry * __regargs
AllocTranslationEntry(STRPTR String)
{
	LONG Count = TranslateString(String,SharedBuffer);

	if(Count > 0)
	{
		struct TranslationEntry	*Entry;
		UBYTE			 Type;

		if(Count > 1)
		{
			Type = TRANSLATE_STRING;

			if(Entry = (struct TranslationEntry *)AllocVecPooled(sizeof(struct TranslationEntry) + Count + 1,MEMF_ANY|MEMF_CLEAR))
			{
				Entry -> String	= (STRPTR)(Entry + 1);

				memcpy(Entry -> String,SharedBuffer,Count);
			}
		}
		else
		{
			Type = TRANSLATE_SINGLE;

			if(Entry = (struct TranslationEntry *)AllocVecPooled(sizeof(struct TranslationEntry),MEMF_ANY|MEMF_CLEAR))
			{
				Entry -> String	= &Entry -> Extra;
				Entry -> Extra	= SharedBuffer[0];
			}
		}

		if(Entry)
		{
			Entry -> Type	= Type;
			Entry -> Len	= Count;

			return(Entry);
		}
	}

	return(NULL);
}

	/* FillTranslationTable(struct TranslationEntry **Table):
	 *
	 *	Fill the translation table with defaults.
	 */

BYTE __regargs
FillTranslationTable(struct TranslationEntry **Table)
{
	BYTE Success = TRUE;
	WORD i;

	for(i = 0 ; Success && i < 256 ; i++)
	{
		if(Table[i] = (struct TranslationEntry *)AllocVecPooled(sizeof(struct TranslationEntry),MEMF_ANY|MEMF_CLEAR))
		{
			Table[i] -> Type	= TRANSLATE_SINGLE;
			Table[i] -> String	= &Table[i] -> Extra;
			Table[i] -> Extra	= i;
			Table[i] -> Len		= 1;
		}
		else
			Success = FALSE;
	}

	if(!Success)
	{
		for(i = 0 ; i < 256 ; i++)
		{
			if(Table[i])
			{
				FreeVecPooled(Table[i]);

				Table[i] = NULL;
			}
		}
	}

	return(Success);
}

	/* IsStandardTable(struct TranslationEntry **Table):
	 *
	 *	Checks a translation table to see if it contains
	 *	standard data.
	 */

BYTE __regargs
IsStandardTable(struct TranslationEntry **Table)
{
	WORD i;

	for(i = 0 ; i < 256 ; i++)
	{
		if(Table[i])
		{
			if(Table[i] -> Type != TRANSLATE_SINGLE || Table[i] -> Len != 1 || Table[i] -> String[0] != i)
				return(FALSE);
		}
		else
			return(FALSE);
	}

	return(TRUE);
}

	/* TranslateBack(STRPTR From,LONG Len,STRPTR To):
	 *
	 *	Translate a precompiled translation string
	 *	back.
	 */

VOID __regargs
TranslateBack(STRPTR From,LONG Len,STRPTR To)
{
	STATIC char TypeTable[256] =
	{
		 1 , 1 , 1 , 1 , 1 , 1 , 1 ,1 ,'b','t','n', 1 ,'f','r', 1 , 1,
		 1 , 1 , 1 , 1 , 1 , 1 , 1 ,1 , 1 , 1 , 1 ,'e', 1 , 1 , 1 , 1,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 ,'\\',2 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 0,
		 0 , 0 , 0 , 0 , 0 , 0 , 0 ,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
		 0 , 0 , 0 , 0 , 0 , 0 , 0 ,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
		 0 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 0 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2,
		 2 , 2 , 2 , 2 , 2 , 2 , 2 ,2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2
	};

	STRPTR 	Buffer;
	LONG	i,j,BufLen;

	for(i = j = 0 ; i < Len ; i++)
	{
		switch(TypeTable[From[i]])
		{
			case 0:	To[j++] = '\\';
				To[j++] = '*';

				Buffer = CodeToName(From[i]);

				BufLen = strlen(Buffer);

				memcpy(&To[j],Buffer,BufLen);

				j += BufLen;

				break;

			case 1:	To[j++] = '^';
				To[j++] = From[i] + '@';
				break;

			case 2:	To[j++] = From[i];
				break;

			default:To[j++] = '\\';
				To[j++] = TypeTable[From[i]];
				break;
		}
	}

	To[j] = 0;
}

	/* SaveTranslationTables():
	 *
	 *	Save a character translation table to a file.
	 */

BYTE __regargs
SaveTranslationTables(STRPTR Name,struct TranslationEntry **SendTable,struct TranslationEntry **ReceiveTable)
{
	BYTE	Success = FALSE,
		DoIt = FALSE;
	WORD	i;
	LONG	Error = 0;

	for(i = 0 ; !DoIt && i < 256 ; i++)
	{
		if(SendTable[i] || ReceiveTable[i])
			DoIt = TRUE;
	}

	if(DoIt)
	{
		struct IFFHandle	*Handle;
		UBYTE			 MasterTable[256];

		for(i = 0 ; i < 256 ; i++)
		{
			if(SendTable[i])
			{
				if(SendTable[i] -> Type == TRANSLATE_SINGLE && SendTable[i] -> Len == 1 && SendTable[i] -> String[0] == i)
					MasterTable[i] = TRANSLATION_VERBATIM;
				else
					MasterTable[i] = TRANSLATION_OTHER;
			}
			else
				MasterTable[i] = TRANSLATION_IGNORE;

			if(ReceiveTable[i])
			{
				if(ReceiveTable[i] -> Type == TRANSLATE_SINGLE && ReceiveTable[i] -> Len == 1 && ReceiveTable[i] -> String[0] == i)
					MasterTable[i] |= TRANSLATION_VERBATIM << 4;
				else
					MasterTable[i] |= TRANSLATION_OTHER << 4;
			}
			else
				MasterTable[i] |= TRANSLATION_IGNORE << 4;
		}

		if(Handle = AllocIFF())
		{
			if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
			{
				InitIFFasDOS(Handle);

				if(!(Error = OpenIFF(Handle,IFFF_WRITE)))
				{
					if(!(Error = PushChunk(Handle,ID_TERM,ID_CAT,IFFSIZE_UNKNOWN)))
					{
						if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
						{
							if(!(Error = PushChunk(Handle,0,ID_VERS,IFFSIZE_UNKNOWN)))
							{
								struct TermInfo TermInfo;

								TermInfo . Version	= TermVersion;
								TermInfo . Revision	= TermRevision;

								if(WriteChunkRecords(Handle,&TermInfo,sizeof(struct TermInfo),1))
								{
									if(!(Error = PopChunk(Handle)))
									{
										if(!(Error = PushChunk(Handle,0,ID_TRNS,256)))
										{
											if(WriteChunkBytes(Handle,MasterTable,256) == 256)
											{
												if(!(Error = PopChunk(Handle)))
												{
													if(!(Error = PopChunk(Handle)))
													{
														struct TranslationHeader Header;

														Success = TRUE;

														for(i = 0 ; Success && i < 256 ; i++)
														{
															if(SendTable[i] && (MasterTable[i] & 0xF) == TRANSLATION_OTHER)
															{
																Header . Type	= SendTable[i] -> Type;
																Header . Len	= SendTable[i] -> Len;
																Header . Code	= i;
																Header . Pad	= 0;

																if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
																{
																	if(!(Error = PushChunk(Handle,0,ID_SEND,sizeof(struct TranslationHeader))))
																	{
																		if(WriteChunkRecords(Handle,&Header,sizeof(struct TranslationHeader),1))
																		{
																			if(!(Error = PopChunk(Handle)))
																			{
																				if(!(Error = PushChunk(Handle,0,ID_CHRS,SendTable[i] -> Len)))
																				{
																					if(WriteChunkRecords(Handle,SendTable[i] -> String,SendTable[i] -> Len,1))
																					{
																						if(Error = PopChunk(Handle))
																							Success = FALSE;
																					}
																					else
																					{
																						Error = IoErr();

																						Success = FALSE;
																					}
																				}
																			}
																			else
																				Success = FALSE;
																		}
																		else
																		{
																			Error = IoErr();

																			Success = FALSE;
																		}
																	}

																	if(Success)
																	{
																		if(PopChunk(Handle))
																			Success = FALSE;
																	}
																}
																else
																	Success = FALSE;
															}

															if(ReceiveTable[i] && (MasterTable[i] >> 4) == TRANSLATION_OTHER)
															{
																Header . Type	= ReceiveTable[i] -> Type;
																Header . Len	= ReceiveTable[i] -> Len;
																Header . Code	= i;
																Header . Pad	= 0;

																if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
																{
																	if(!(Error = PushChunk(Handle,0,ID_RECV,sizeof(struct TranslationHeader))))
																	{
																		if(WriteChunkRecords(Handle,&Header,sizeof(struct TranslationHeader),1))
																		{
																			if(!(Error = PopChunk(Handle)))
																			{
																				if(!(Error = PushChunk(Handle,0,ID_CHRS,ReceiveTable[i] -> Len)))
																				{
																					if(WriteChunkRecords(Handle,ReceiveTable[i] -> String,ReceiveTable[i] -> Len,1))
																					{
																						if(Error = PopChunk(Handle))
																							Success = FALSE;
																					}
																					else
																					{
																						Error = IoErr();

																						Success = FALSE;
																					}
																				}
																			}
																			else
																				Success = FALSE;
																		}
																		else
																		{
																			Error = IoErr();

																			Success = FALSE;
																		}
																	}

																	if(Success)
																	{
																		if(Error = PopChunk(Handle))
																			Success = FALSE;
																	}
																}
																else
																	Success = FALSE;
															}
														}
													}
												}
											}
											else
												Error = IoErr();
										}
									}
								}
								else
									Error = IoErr();
							}
						}

						if(Success)
						{
							if(PopChunk(Handle))
								Success = FALSE;
						}
					}

					CloseIFF(Handle);
				}

				Close(Handle -> iff_Stream);

				if(Success)
					AddProtection(Name,FIBF_EXECUTE);
				else
					DeleteFile(Name);
			}
			else
				Error = IoErr();

			FreeIFF(Handle);
		}
		else
			Error = ERR_NO_MEM;
	}

	if(Error)
		SetIoErr(Error);

	return(Success);
}

	/* LoadTranslationTable()s:
	 *
	 *	Load a translation table from a file.
	 */

BYTE __regargs
LoadTranslationTables(STRPTR Name,struct TranslationEntry **SendTable,struct TranslationEntry **ReceiveTable)
{
	STATIC ULONG Stops[5 * 2] =
	{
		ID_TERM,	ID_VERS,
		ID_TERM,	ID_TRNS,
		ID_TERM,	ID_SEND,
		ID_TERM,	ID_RECV,
		ID_TERM,	ID_CHRS
	};

	struct IFFHandle	*Handle;
	BYTE			 Success = FALSE;
	WORD			 i;

	UBYTE			 MasterTable[256];
	BYTE			 GotMasterTable = FALSE;
	LONG			 Error = 0;

	if(Handle = AllocIFF())
	{
		if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
		{
			InitIFFasDOS(Handle);

			if(!(Error = OpenIFF(Handle,IFFF_READ)))
			{
				if(!(Error = StopChunks(Handle,(LONG *)Stops,5)))
				{
					struct ContextNode		*Chunk;
					struct TermInfo			 TermInfo;
					struct TranslationHeader	 Header;
					BYTE				 LastType = TYPE_NONE;

					Success = TRUE;

					while(Success && !ParseIFF(Handle,IFFPARSE_SCAN))
					{
						Chunk = CurrentChunk(Handle);

						switch(Chunk -> cn_ID)
						{
							case ID_VERS:

								if(ReadChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
								{
									if(TermInfo . Version > TermVersion || (TermInfo . Version == TermVersion && TermInfo . Revision > TermRevision))
									{
										Error = ERR_OUTDATED;

										Success = FALSE;
									}
								}
								else
								{
									Error = IoErr();

									Success = FALSE;
								}

								break;

							case ID_TRNS:

								if(ReadChunkBytes(Handle,MasterTable,256) == 256)
									GotMasterTable = TRUE;
								else
								{
									Error = IoErr();

									Success = FALSE;
								}

								break;

							case ID_SEND:

								if(LastType != TYPE_NONE)
									Success = FALSE;
								else
								{
									if(!ReadChunkRecords(Handle,&Header,MIN(sizeof(struct TranslationHeader),Chunk -> cn_Size),1))
									{
										Error = IoErr();

										Success = FALSE;
									}
									else
										LastType = TYPE_SEND;
								}

								break;

							case ID_RECV:

								if(LastType != TYPE_NONE)
								{
									Error = IFFERR_MANGLED;

									Success = FALSE;
								}
								else
								{
									if(!ReadChunkRecords(Handle,&Header,MIN(sizeof(struct TranslationHeader),Chunk -> cn_Size),1))
									{
										Success = FALSE;

										Error = IoErr();
									}
									else
										LastType = TYPE_RECEIVE;
								}

								break;

							case ID_CHRS:

								if(LastType == TYPE_NONE)
								{
									Error = IFFERR_MANGLED;

									Success = FALSE;
								}
								else
								{
									if(ReadChunkRecords(Handle,SharedBuffer,Header . Len,1))
									{
										struct TranslationEntry *Entry;

										if(Header . Type == TRANSLATE_SINGLE)
										{
											if(Entry = (struct TranslationEntry *)AllocVecPooled(sizeof(struct TranslationEntry),MEMF_ANY|MEMF_CLEAR))
											{
												Entry -> String	= &Entry -> Extra;
												Entry -> Extra	= SharedBuffer[0];
											}
										}
										else
										{
											if(Entry = (struct TranslationEntry *)AllocVecPooled(sizeof(struct TranslationEntry) + Header . Len + 1,MEMF_ANY|MEMF_CLEAR))
											{
												Entry -> String	= (STRPTR)(Entry + 1);

												memcpy(Entry -> String,SharedBuffer,Header . Len);
											}
										}

										if(Entry)
										{
											Entry -> Type	= Header . Type;
											Entry -> Len	= Header . Len;

											if(LastType == TYPE_SEND)
												SendTable[Header . Code]	= Entry;
											else
												ReceiveTable[Header . Code]	= Entry;

											LastType = TYPE_NONE;
										}
										else
										{
											Error = ERR_NO_MEM;

											Success = FALSE;
										}
									}
									else
									{
										Error = IoErr();

										Success = FALSE;
									}
								}

								break;
						}
					}
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}
		else
			Error = IoErr();

		FreeIFF(Handle);
	}
	else
		Error = ERR_NO_MEM;

	if(Success && GotMasterTable)
	{
		struct TranslationEntry *Entry;

		for(i = 0 ; i < 256 ; i++)
		{
			if((MasterTable[i] & 0xF) == TRANSLATION_VERBATIM)
			{
				if(Entry = (struct TranslationEntry *)AllocVecPooled(sizeof(struct TranslationEntry),MEMF_ANY|MEMF_CLEAR))
				{
					Entry -> Type	= TRANSLATE_SINGLE;
					Entry -> String	= &Entry -> Extra;
					Entry -> Extra	= i;
					Entry -> Len	= 1;

					SendTable[i] = Entry;
				}
				else
				{
					Error = ERR_NO_MEM;

					Success = FALSE;

					break;
				}
			}

			if((MasterTable[i] >> 4) == TRANSLATION_VERBATIM)
			{
				if(Entry = (struct TranslationEntry *)AllocVecPooled(sizeof(struct TranslationEntry),MEMF_ANY|MEMF_CLEAR))
				{
					Entry -> Type	= TRANSLATE_SINGLE;
					Entry -> String	= &Entry -> Extra;
					Entry -> Extra	= i;
					Entry -> Len	= 1;

					ReceiveTable[i] = Entry;
				}
				else
				{
					Error = ERR_NO_MEM;

					Success = FALSE;

					break;
				}
			}
		}
	}

	if(!Success)
	{
		for(i = 0 ; i < 256 ; i++)
		{
			if(SendTable[i])
			{
				FreeTranslationEntry(SendTable[i]);

				SendTable[i] = NULL;
			}

			if(ReceiveTable[i])
			{
				FreeTranslationEntry(ReceiveTable[i]);

				ReceiveTable[i] = NULL;
			}
		}
	}

	if(Error)
		SetIoErr(Error);

	return(Success);
}
