Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1424 lines
44 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
dllmsg.c
Abstract:
This module implements the Message OS/2 V2.0 API Calls
Author:
Steve Wood (stevewo) 20-Sep-1989
Revision History:
--*/
#define INCL_OS2V20_TASKING
#define INCL_OS2V20_ERRORMSG
#define INCL_OS2V20_ERRORS
#define INCL_OS2V20_FILESYS
#define INCL_OS2V20_NLS
#include "os2dll.h"
#include "os2dll16.h"
#include "conrqust.h"
#ifdef DBCS
// MSKK Oct.29.1993 V-AkihIS
#include "os2win.h"
#endif
#include <stdio.h>
#ifdef DBCS
// MSKK Jun.16.1993 V-AkihiS
//
// OS/2 internal multibyte string function.
//
#include "dlldbcs.h"
#define strpbrk Od2MultiByteStrpbrk
#define strchr Od2MultiByteStrchr
#define strrchr Od2MultiByteStrrchr
#endif
BOOLEAN
Od2FindMessageInRam(
IN PSZ MsgPathName,
IN ULONG MsgNumber,
IN PBYTE pMsgSeg,
OUT PSZ *MsgText,
OUT PULONG MsgLen,
IN OUT PSZ CompId
)
/*++
Routine Description:
This routine searches a program's message segment for the message. This is done before the file
is searched for. Currently, this routine only works with os/2 1.x 16 bit segments, since the
format of 2.x segments was not available at the time of writing.
This code was adapted from the assembler sources of DosTrueGetMessage() in OS/2.
A description of how OS/2 handles ram messages:
The user calls DosGetMessage() without the 8th parameter which is the pointer to the message segment.
The linker then modifies this call as follows: it adds a message segment to the executable. It
modifies the DosGetMessage() call to call inside a small piece of code in the message segment. This
code pushes the 8th parameter (pointer to the message segment) on the stack, and calls the real
OS/2 API which is called DosTrueGetMessage(). This API expects this 8th parameter pointing to the
msg segment to already exist. Since this "thunk" process is done internally in the OS/2 program code,
our OS2SS DosTrueGetMessage() function also receives this 8th parameter on the stack.
A general description of the format of an os/2 1.x message segment:
10 byte signature ("\xffMKMSGSEG")
2 byte version number (should be 1)
2 reserved bytes
2 byte offset of the start of the file table
<now comes the small piece of code mentioned earlier>
now comes the file table:
2 byte count of the number of files supported in the message segment.
table of 2-byte offsets pointing to the file names.
table of 2-byte offsets pointing to each file's message table.
text of null-terminated file names.
now, for each file supported, there is a message table in the following format:
3 byte component ID name
2-byte count of # of msgs from the file contained in the segment
table of 2-byte offsets pointing to each message entry in the table
now come the message entries, each one of the following format:
2-byte message ID
2-byte message length (including severity byte)
message text (not null-terminated, first byte is severity).
Arguments:
MsgPathName -- supplies pathname of messagefile containing the wanted message.
MsgNumber -- supplies the message number in the file to search for.
pMsgSeg -- a pointer to the 16 bit message segment
MsgText -- returns a pointer to the message text in the ram segement (including severity character).
MsgLen -- returns the length of the string in MsgText
CompId -- supplies a pointer to a buffer of length at least COMP_ID_LEN. if message is found in ram,
returns the component ID.
Return Value:
TRUE -- Message was successfully located in RAM. In this case, MsgText,
MsgLen and CompID are valid.
FALSE -- Unable to locate message in RAM.
--*/
{
PMSGSEGMENT_HEADER16 pHeader = (PMSGSEGMENT_HEADER16) pMsgSeg;
PSZ MsgFileName, FileNamePtr, CurrentMsgPtr;
PBYTE TablePtr;
USHORT FileCount, MsgCount, i;
PUSHORT WordPtr, CurrentMsgHdrPtr;
try {
//
// if it's the system msg file -- skip ram search
//
if (_stricmp(MsgPathName, OD2_MESSAGE_RESOURCE_FILENAME) == 0) {
return(FALSE);
}
//
// get last component of msg file path name
//
MsgFileName = strrchr(MsgPathName, '\\');
if (MsgFileName != NULL) {
MsgFileName++;
} else if ((MsgFileName = strrchr(MsgPathName, ':')) != NULL) {
MsgFileName++;
} else {
MsgFileName = MsgPathName;
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
try {
Od2ProbeForRead(pHeader, sizeof(pHeader), 1);
} except( EXCEPTION_EXECUTE_HANDLER ) {
return(FALSE);
}
if (pHeader->Signature[0] != 0xff ||
strncmp(pHeader->Signature + 1, "MKMSGSEG", 9) != 0 ||
pHeader->Version != 1) {
return(FALSE);
}
WordPtr = (PUSHORT) (pMsgSeg + pHeader->FileTableOffset);
try {
FileCount = *WordPtr++;
if (FileCount == 0) {
return(FALSE);
}
Od2ProbeForRead(WordPtr, 2 * FileCount * sizeof(USHORT), 1);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
for (i = 0; i < FileCount; i++) {
FileNamePtr = (PSZ) (pMsgSeg + WordPtr[i]);
try {
if (_stricmp(MsgFileName, FileNamePtr) == 0) {
break;
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
}
if (i == FileCount) {
return(FALSE);
}
TablePtr = pMsgSeg + WordPtr[i + FileCount];
try {
RtlMoveMemory(CompId, TablePtr, COMP_ID_LEN);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
WordPtr = (PUSHORT) (TablePtr + COMP_ID_LEN);
try {
MsgCount = *WordPtr++;
Od2ProbeForRead(WordPtr, MsgCount * sizeof(USHORT), 1);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
for (i = 0; i < MsgCount; i++) {
CurrentMsgHdrPtr = (PUSHORT) (pMsgSeg + WordPtr[i]);
try {
if ((ULONG) (CurrentMsgHdrPtr[0]) != MsgNumber) {
continue;
}
*MsgLen = (ULONG) (CurrentMsgHdrPtr[1]);
CurrentMsgPtr = (PSZ) (CurrentMsgHdrPtr + 2);
Od2ProbeForRead(CurrentMsgPtr, *MsgLen, 1);
*MsgText = CurrentMsgPtr;
return(TRUE);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
}
return(FALSE);
}
APIRET
Od2FindMessageFile(
IN PSZ MessageFileName,
OUT POD2_MSGFILE *ReturnedMsgFile
)
{
APIRET rc;
PLIST_ENTRY ListHead, ListNext;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE File;
IO_STATUS_BLOCK IoStatus;
HANDLE Section;
POD2_MSGFILE MsgFile;
ULONG CountBytes;
POD2_MSGFILE_HEADER MsgFileHeader;
POD2_MSGFILE_HEADER16 MsgFileHeader16;
STRING MessageFileString;
UNICODE_STRING MessageFileString_U;
ULONG MessageFileFlags;
ULONG MessageFileType;
FILE_STANDARD_INFORMATION StdInfo;
BOOL Od2MsgFileFlag = FALSE;
CHAR SystemMessageFileName[CCHMAXPATH];
CHAR FoundMessageFileName[CCHMAXPATH];
CHAR SearchPath[1024];
ULONG LangId;
PSZ PathPtr;
//
// See if requesting a message from the system message file (OSO001.MSG).
// If so, then just return that message file that was created during
// process initialization.
//
try {
if (!_stricmp( MessageFileName, OD2_MESSAGE_RESOURCE_FILENAME ))
{
if (Od2MsgFile != NULL)
{
*ReturnedMsgFile = Od2MsgFile;
return( NO_ERROR );
}
#ifdef DBCS
// MSKK Nov.12.1992 V-AkihiS
// Change message file acording to current code page.
if (SesGrp->DosCP == SesGrp->PrimaryCP || SesGrp->DosCP == 0)
{
LangId = SesGrp->LanguageID;
} else if (SesGrp->DosCP == SesGrp->SecondaryCP)
{
LangId = LANG_ENGLISH;
} else {
LangId = SesGrp->LanguageID;
}
#else
LangId = SesGrp->LanguageID;
#endif
if (LangId > 999)
{
#ifdef JAPAN
// MSKK Jun.16.1993 V-AkihiS
LangId = LANG_JAPANESE;
#else
LangId = LANG_ENGLISH;
#endif
}
sprintf(SystemMessageFileName, "%s\\os2\\oso001.%3.3u",
Od2SystemRoot, LangId);
MessageFileName = SystemMessageFileName;
Od2MsgFileFlag = TRUE;
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
//
// Order to search:
//
// - message resource (Call DosGetResource)
//
// If not found there then constuct a search path with the following
// components and search that for the file name.
// - root directory of boot drive
// - current directory
// - DPATH environment variable
//
//
// Check if the message file name is fully specified (i.e. it includes
// a drive or path name).
//
if (strpbrk(MessageFileName, ":/\\") != NULL) {
strcpy(FoundMessageFileName, MessageFileName);
}
else {
SearchPath[0] = '\\';
SearchPath[1] = ';';
SearchPath[2] = '.';
SearchPath[3] = '\0';
//
// Expand Path elements without root dir but with current dir
//
rc = DosScanEnv("DPATH", &PathPtr);
if (rc == NO_ERROR) {
SearchPath[3] = ';'; // after the "\;."
strncpy(&SearchPath[4], PathPtr, sizeof(SearchPath)-5); // after the "\;.;"
SearchPath[sizeof(SearchPath)-1] = '\0'; // just to be safe
}
rc = DosSearchPath(SEARCH_PATH, SearchPath, MessageFileName,
FoundMessageFileName, sizeof(FoundMessageFileName)
);
if (rc != NO_ERROR) {
return(ERROR_FILE_NOT_FOUND);
}
}
//
// Canonicalize message file name
//
rc = Od2Canonicalize( FoundMessageFileName,
CANONICALIZE_FILE_OR_DEV,
&MessageFileString,
NULL,
&MessageFileFlags,
&MessageFileType
);
if (rc != NO_ERROR) {
return( rc );
}
Section = NULL;
MsgFile = NULL;
if (MessageFileType != FILE_TYPE_FILE) {
rc = ERROR_ACCESS_DENIED;
}
if (MessageFileFlags != 0) {
rc = ERROR_PATH_NOT_FOUND;
}
if (rc != NO_ERROR) {
goto ErrorExit;
}
//
// Here with a fully qualified name. Search the list of message files
// that we have mapped already and see if it is there. If so, then
// just return the base address of the mapped file.
//
if (!Od2MsgFileFlag)
{
ListHead = &Od2Process->MsgFileList;
ListNext = ListHead->Flink;
while (ListNext != ListHead) {
MsgFile = CONTAINING_RECORD( ListNext, OD2_MSGFILE, Link );
if (RtlEqualString( &MessageFileString, &MsgFile->FileName, TRUE )) {
*ReturnedMsgFile = MsgFile;
goto ErrorExit;
return( NO_ERROR );
}
ListNext = ListNext->Flink;
}
}
//
// This is the first time the message file has been referenced by this
// process, so open the file, create a section for it and map a view of
// the section. We can close the file after the section has been
// created as it will not go away until the section is closed, which
// wont happen until process death.
//
//
// UNICODE conversion -
//
rc = Od2MBStringToUnicodeString(
&MessageFileString_U,
&MessageFileString,
TRUE);
if (rc)
{
#if DBG
// DbgPrint("Od2FindMessageFile: no memory for Unicode Conversion\n");
#endif
RtlFreeHeap( Od2Heap, 0, MessageFileString.Buffer );
return rc;
}
InitializeObjectAttributes( &ObjectAttributes,
&MessageFileString_U,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenFile( &File,
SYNCHRONIZE | FILE_READ_DATA,
&ObjectAttributes,
&IoStatus,
FILE_SHARE_READ,
0
);
if (!NT_SUCCESS( Status ))
{
rc = Or2MapStatus( Status );
//
// change to correct error msg in case of sharing violation
//
if (rc == ERROR_SHARING_VIOLATION) {
rc = ERROR_MR_UN_ACC_MSGF;
}
//
// Maybe be try system message file, which is not english
// but we have the english file on our machine.
//
if (( rc == ERROR_FILE_NOT_FOUND ) && Od2MsgFileFlag &&
#ifdef JAPAN
// MSKK Jun.16.1993 V-AkihiS
( LangId != LANG_JAPANESE ))
#else
( LangId != LANG_ENGLISH ))
#endif
{
#ifdef JAPAN
// MSKK Jul.29.1993 V-AKihIS
LangId = LANG_JAPANESE;
MessageFileString_U.Buffer[MessageFileString_U.Length - 3] = '0';
MessageFileString_U.Buffer[MessageFileString_U.Length - 2] =
'0' + ((LANG_JAPANESE & 0xF0) >> 4);
MessageFileString_U.Buffer[MessageFileString_U.Length - 1] =
'0' + (LANG_JAPANESE & 0x0F);
#else
LangId = LANG_ENGLISH;
MessageFileString_U.Buffer[MessageFileString_U.Length - 3] = '0';
MessageFileString_U.Buffer[MessageFileString_U.Length - 2] =
'0' + ((LANG_ENGLISH & 0xF0) >> 4);
MessageFileString_U.Buffer[MessageFileString_U.Length - 1] =
'0' + (LANG_ENGLISH & 0x0F);
#endif
Status = NtOpenFile( &File,
SYNCHRONIZE | FILE_READ_DATA,
&ObjectAttributes,
&IoStatus,
FILE_SHARE_READ,
0
);
if (!NT_SUCCESS( Status ))
{
rc = Or2MapStatus( Status );
RtlFreeUnicodeString (&MessageFileString_U);
goto ErrorExit;
}
} else
{
RtlFreeUnicodeString (&MessageFileString_U);
goto ErrorExit;
}
}
RtlFreeUnicodeString (&MessageFileString_U);
Status = NtQueryInformationFile(File,
&IoStatus,
&StdInfo,
sizeof (StdInfo),
FileStandardInformation);
if (!NT_SUCCESS( Status )) {
rc = Or2MapStatus( Status );
goto ErrorExit;
}
//
// Create a memory section backed by the opened message file
//
Status = NtCreateSection( &Section,
SECTION_MAP_READ,
NULL,
NULL,
PAGE_READONLY,
SEC_COMMIT,
File
);
NtClose( File );
if ( !NT_SUCCESS( Status ) ) {
rc = Or2MapStatus( Status );
goto ErrorExit;
}
CountBytes = sizeof( OD2_MSGFILE ) + MessageFileString.Length + 1;
MsgFile = RtlAllocateHeap( Od2Heap, 0, CountBytes );
if (MsgFile == NULL) {
rc = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorExit;
}
MsgFile->BaseAddress = 0;
MsgFile->Size = 0;
MsgFile->SectionHandle = Section;
MsgFile->FileName.Length = MessageFileString.Length;
MsgFile->FileName.MaximumLength = MessageFileString.Length;
MsgFile->FileName.Buffer = (PCH)(MsgFile+1);
MsgFile->Type = MSG_FILE_TYPE_OS2_20;
RtlMoveMemory( MsgFile->FileName.Buffer,
MessageFileString.Buffer,
MessageFileString.Length
);
Status = NtMapViewOfSection( Section,
NtCurrentProcess(),
&MsgFile->BaseAddress,
0,
0,
NULL,
&MsgFile->Size,
/*
Value in MsgFile->Size is a multiple of 0x1000
and is changed later to match the true size of the
msg file.
*/
ViewUnmap,
0,
PAGE_READONLY
);
if (!NT_SUCCESS( Status )) {
rc = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorExit;
}
/* Fix the size of the file with the true size */
MsgFile->Size = StdInfo.EndOfFile.LowPart;
MsgFileHeader = (POD2_MSGFILE_HEADER)MsgFile->BaseAddress;
MsgFileHeader16 = (POD2_MSGFILE_HEADER16)MsgFile->BaseAddress;
if ((MsgFileHeader->HeaderLength != FIELD_OFFSET( OD2_MSGFILE_HEADER,
MessageOffsets ) ||
strncmp( MsgFileHeader->Signature, "_NTMSGF", 7 ))
&&
((MsgFileHeader16->HeaderMsgFF != 0xff) ||
(strncmp( MsgFileHeader16->Signature, "MKMSGF", 6 )))
) {
NtUnmapViewOfSection( NtCurrentProcess(), MsgFile->BaseAddress );
RtlFreeHeap( Od2Heap, 0, MsgFile );
NtClose( Section );
return( ERROR_MR_INV_MSGF_FORMAT );
}
if (!strncmp( MsgFileHeader16->Signature, "MKMSGF", 6 )) {
MsgFile->Type = MSG_FILE_TYPE_OS2_1x;
}
if (Od2MsgFileFlag)
{
Od2MsgFile = RtlAllocateHeap( Od2Heap, 0, sizeof( OD2_MSGFILE ) );
if (Od2MsgFile == NULL)
{
rc = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorExit;
}
RtlMoveMemory( Od2MsgFile,
MsgFile,
sizeof( OD2_MSGFILE )
);
*ReturnedMsgFile = Od2MsgFile;
} else
{
InsertTailList( &Od2Process->MsgFileList, &MsgFile->Link );
*ReturnedMsgFile = MsgFile;
}
rc = NO_ERROR;
ErrorExit:
if (MessageFileString.Buffer != NULL) {
RtlFreeHeap( Od2Heap, 0, MessageFileString.Buffer );
}
if (Section != NULL) {
NtClose( Section );
}
if ((rc != NO_ERROR) && (MsgFile != NULL)) {
RtlFreeHeap( Od2Heap, 0, MsgFile );
}
return( rc );
}
APIRET
DosGetMessage(
IN PSZ Variables[],
IN ULONG CountVariables,
OUT PCHAR Buffer,
IN ULONG Length,
IN ULONG MessageNumber,
IN PSZ MessageFileName,
OUT PULONG MessageLength,
IN PBYTE pMsgSeg
)
{
APIRET rc;
POD2_MSGFILE MsgFile;
PSZ Message, MessageBuffer, s;
CHAR MessageSeverity;
ULONG i, Offset;
ULONG LengthInFile, BufferLength;
CHAR CompId[COMP_ID_LEN];
BOOLEAN IsRamMsg;
//
// We start off by doing a search in the executable ram image for
// the message. pMsgSeg (if valid) is a pointer to the program's message
// segement. We currently only handle 16 bit os/2 1.x message segments.
//
IsRamMsg = Od2FindMessageInRam(MessageFileName,
MessageNumber,
pMsgSeg,
&Message,
&LengthInFile,
CompId);
if (IsRamMsg) {
goto RamSegProcessJunction; // found it, go process
}
//
// Otherwise, go search for the file.
//
// Get a pointer to the message file, mapped into memory. Return an
// error if not found or invalid format.
//
rc = Od2FindMessageFile( MessageFileName,
&MsgFile
);
if (rc != NO_ERROR) {
return( rc );
}
//
// Get a pointer to the message file header and validate the message
// number as being within range of the first and last message Id
// described by the message file. Return an error if it is not.
//
if (MsgFile->Type == MSG_FILE_TYPE_OS2_20) {
POD2_MSGFILE_HEADER MsgFileHeader;
MsgFileHeader = (POD2_MSGFILE_HEADER)MsgFile->BaseAddress;
if (MessageNumber < MsgFileHeader->BaseMessageId) {
return( ERROR_MR_MID_NOT_FOUND );
}
MessageNumber -= MsgFileHeader->BaseMessageId;
if (MessageNumber >= MsgFileHeader->CountOfMessages) {
return( ERROR_MR_MID_NOT_FOUND );
}
//
// Calculate a pointer to the actual message and calculate the length
// of the message as the difference between the offset of this message
// and the offset of the next message or end of file if retreiving the
// last message.
//
Offset = MsgFileHeader->MessageOffsets[ MessageNumber ];
Message = (PSZ)MsgFileHeader + Offset;
if (MessageNumber+1 == MsgFileHeader->CountOfMessages) {
LengthInFile = MsgFile->Size - Offset;
}
else {
LengthInFile = MsgFileHeader->MessageOffsets[ MessageNumber+1 ] -
Offset;
}
//
// Extract the first character of the message, which is the severity
// of the message. Return message not found if the severity is '?'
// as it marks a place holder for unused message numbers.
//
MessageSeverity = *Message;
if (MessageSeverity == '?') {
return( ERROR_MR_MID_NOT_FOUND );
}
//
// Allocate a buffer to hold a null terminated copy of the message,
// plus an extra 9 bytes in case we have to prefix the message with
// the error code ('W'arning and 'E'rror severity only).
//
MessageBuffer = RtlAllocateHeap( Od2Heap, 0, LengthInFile + COMP_ID_LEN + 6);
if (!MessageBuffer) {
#if DBG
KdPrint(("Os2: DosGetMessage out of heap memory\n"));
#endif
ASSERT( FALSE );
return ERROR_NOT_ENOUGH_MEMORY;
}
s = MessageBuffer;
//
// If the severity of the message is 'W'arning or 'E'rror then copy the
// 3 character component id from the message file header, the 4 character
// ASCII representation of the message number and 2 trailing separator
// characters ": ". A total of 9 extra bytes.
//
if (MessageSeverity == 'W' || MessageSeverity == 'E') {
RtlMoveMemory( s, MsgFileHeader->Component, COMP_ID_LEN );
s += COMP_ID_LEN;
i = 4;
while (i--) {
s[ i ] = (CHAR)((MessageNumber % 10) + '0');
MessageNumber /= 10;
}
s += 4;
*s++ = ':';
*s++ = ' ';
BufferLength = COMP_ID_LEN + 6;
}
else {
BufferLength = 0;
}
//
// Now copy the message from the mapped message file into the allocated
// buffer and null terminate the message in the buffer. Remember not
// to include the message severity code.
//
RtlMoveMemory( s, ++Message, LengthInFile-1 );
s[ LengthInFile-1 ] = '\0';
BufferLength += LengthInFile - 1;
}
else /* (MsgFile->Type == MSG_FILE_TYPE_OS2_1x) */ {
POD2_MSGFILE_HEADER16 MsgFileHeader16;
POD2_MSGFILE_HEADER_SYS16 SysMsgFileHeader16;
MsgFileHeader16 = (POD2_MSGFILE_HEADER16)MsgFile->BaseAddress;
if (MessageNumber < (ULONG)(MsgFileHeader16->BaseMessageId)) {
return( ERROR_MR_MID_NOT_FOUND );
}
MessageNumber -= MsgFileHeader16->BaseMessageId;
if (MessageNumber >= (ULONG)(MsgFileHeader16->CountOfMessages)) {
return( ERROR_MR_MID_NOT_FOUND );
}
//
// Calculate a pointer to the actual message and calculate the length
// of the message as the difference between the offset of this message
// and the offset of the next message or end of file if retreiving the
// last message.
//
// For system message file always create ULONG offset of messages,
// so use OD2_MSGFILE_HEADER_SYS16 instaed of OD2_MSGFILE_HEADER16.
// change: mjarus - Aug 30, 1992.
//
// Correction: For "huge" message file the offset table is ULONG array
// so use OD2_MSGFILE_HEADER_SYS16 instaed of OD2_MSGFILE_HEADER16.
// This is determinated by the first byte of the Resered field (one
// for small files (USHORT array) and zero for huge files (ULONG array).
// change: mjarus - jan 12, 1993.
//
if(MsgFileHeader16->Reserved[0] == 0)
{
SysMsgFileHeader16 = (POD2_MSGFILE_HEADER_SYS16)MsgFileHeader16;
Offset = SysMsgFileHeader16->MessageOffsets[ MessageNumber ];
Message = (PSZ)SysMsgFileHeader16 + Offset;
if (MessageNumber+1 == (ULONG)(SysMsgFileHeader16->CountOfMessages)) {
LengthInFile = MsgFile->Size - Offset;
}
else { /* if(MsgFileHeader16->Reserved[0] == 1) */
LengthInFile = SysMsgFileHeader16->MessageOffsets[ MessageNumber+1 ] -
Offset;
}
} else
{
Offset = MsgFileHeader16->MessageOffsets[ MessageNumber ];
Message = (PSZ)MsgFileHeader16 + Offset;
if (MessageNumber+1 == (ULONG)(MsgFileHeader16->CountOfMessages)) {
LengthInFile = MsgFile->Size - Offset;
}
else {
LengthInFile = MsgFileHeader16->MessageOffsets[ MessageNumber+1 ] -
Offset;
}
}
//
// Extract the first character of the message, which is the severity
// of the message. Return message not found if the severity is '?'
// as it marks a place holder for unused message numbers.
//
RamSegProcessJunction:
MessageSeverity = *Message;
if (MessageSeverity == '?') {
return( ERROR_MR_MID_NOT_FOUND );
}
//
// Allocate a buffer to hold a null terminated copy of the message,
// plus an extra 9 bytes in case we have to prefix the message with
// the error code ('W'arning and 'E'rror severity only).
//
MessageBuffer = RtlAllocateHeap( Od2Heap, 0, LengthInFile + COMP_ID_LEN + 6 );
if (!MessageBuffer) {
#if DBG
KdPrint(("Os2: DosGetMessage out of heap memory\n"));
#endif
ASSERT( FALSE );
return ERROR_NOT_ENOUGH_MEMORY;
}
s = MessageBuffer;
//
// If the severity of the message is 'W'arning or 'E'rror then copy the
// 3 character component id from the message file header, the 4 character
// ASCII representation of the message number and 2 trailing separator
// characters ": ". A total of 9 extra bytes.
//
if (MessageSeverity == 'W' || MessageSeverity == 'E') {
RtlMoveMemory( s,
IsRamMsg ? CompId :
MsgFileHeader16->Component,
COMP_ID_LEN );
s += COMP_ID_LEN;
i = 4;
while (i--) {
s[ i ] = (CHAR)((MessageNumber % 10) + '0');
MessageNumber /= 10;
}
s += 4;
*s++ = ':';
*s++ = ' ';
BufferLength = COMP_ID_LEN + 6;
}
else {
BufferLength = 0;
}
//
// Now copy the message from the mapped message file into the allocated
// buffer and null terminate the message in the buffer. Remember not
// to include the message severity code.
//
RtlMoveMemory( s, ++Message, LengthInFile-1 );
s[ LengthInFile-1 ] = '\0';
BufferLength += LengthInFile - 1;
}
//
// Now call DosInsertMessage to process any insert strings and copy the
// resulting message into the caller's buffer.
//
rc = DosInsertMessage( Variables,
CountVariables,
MessageBuffer,
BufferLength,
Buffer,
Length,
MessageLength
);
//
// All done, free the message buffer and return any error code to the
// caller.
//
RtlFreeHeap( Od2Heap, 0, MessageBuffer );
return( rc );
}
APIRET
DosInsertMessage(
IN PSZ Variables[],
IN ULONG CountVariables,
IN PCHAR Message,
IN ULONG MessageLength,
OUT PCHAR Buffer,
IN ULONG Length,
OUT PULONG ActualMessageLength
)
{
UCHAR c, MaxInsert;
PUCHAR Src, Dst, InsSrc;
ULONG i, DstLength;
//
// May not specify more than 9 insert parameters. These correspond to
// %1 through %p in the input message string.
//
if (CountVariables > 9) {
return( ERROR_MR_INV_IVCOUNT );
}
//
// Calculate the character representation of the maximum %n value in the
// input message that will trigger an insertion.
//
MaxInsert = (UCHAR)('0' + CountVariables);
//
// Now copy the input message to the output buffer, looking for insert
// specifiers (%n) and making sure we do not overflow the output buffer.
//
Src = Message;
Dst = Buffer;
DstLength = 0;
try {
while (MessageLength != 0) {
//
// Get the next character from the input message
//
c = *Src++;
MessageLength--;
//
// If it is a percent sign ('%') and there is at least one more
// character in the input message and that character is a valid
// insert specifier based on the number of insertion strings passed
// to this functions (CountVariables), then do the insertion.
//
if (c == '%' && MessageLength && *Src > '0' && *Src <= MaxInsert) {
//
// Valid insertion specifier. Get the corresponding pointer
// to the string to insert and copy that string to the output
// buffer, making sure we do not overflow the output buffer.
// Skip over the insert specifier in the input message.
//
i = *Src++ - '1';
MessageLength--;
InsSrc = Variables[ i ];
while (c = *InsSrc++) {
#ifdef DBCS
// MSKK Mar.03.1993 V-AkihiS
if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
if (DstLength < Length-1) {
*Dst++ = c;
*Dst++ = *InsSrc++;
DstLength += 2;
} else {
*ActualMessageLength = DstLength;
return( ERROR_MR_MSG_TOO_LONG );
}
} else {
if (DstLength++ >= Length) {
*ActualMessageLength = Length;
return( ERROR_MR_MSG_TOO_LONG );
} else {
*Dst++ = c;
}
}
#else
if (DstLength++ >= Length) {
*ActualMessageLength = Length;
return( ERROR_MR_MSG_TOO_LONG );
}
*Dst++ = c;
#endif
}
}
else {
//
// Not an insert specifier, so copy this character into the output
// buffer, making sure we do not overflow the output buffer.
//
#ifdef DBCS
// MSKK Mar.03.1993 V-AkihiS
if (IsDBCSLeadByte(c)) {
if (DstLength < Length-1) {
*Dst++ = c;
*Dst++ = *Src++;
MessageLength--;
DstLength += 2;
} else {
*ActualMessageLength = DstLength;
return( ERROR_MR_MSG_TOO_LONG );
}
} else {
if (DstLength++ >= Length) {
*ActualMessageLength = Length;
return( ERROR_MR_MSG_TOO_LONG );
} else {
*Dst++ = c;
}
}
#else
if (DstLength++ >= Length) {
*ActualMessageLength = Length;
return( ERROR_MR_MSG_TOO_LONG );
}
*Dst++ = c;
#endif
}
}
//
// Success, return the actual length of the message written to the output
// buffer.
//
*ActualMessageLength = DstLength;
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
return( NO_ERROR );
}
APIRET
DosPutMessage(
IN HFILE FileHandle,
IN ULONG MessageLength,
IN PCHAR Message
)
{
#ifdef DBCS
// MSKK Apr.22.1993 V-AkihiS
//
// Bug fix. Handle DBCS.
//
PCHAR sPrev, sCurrent;
ULONG Discard;
BOOL IsFlushed;
USHORT PrevPosition;
APIRET rc;
sCurrent = sPrev = Message;
PrevPosition = 0;
try {
while (sCurrent < Message + MessageLength) {
if (sCurrent[0] == '\r' && sCurrent[1] == '\n') {
if ((PrevPosition + (sCurrent - sPrev)) >= 79) {
//
// If a wordwrap is needed, write CR+LF.
//
rc = DosWrite( FileHandle,
(PVOID)"\r\n",
2,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
}
//
// Write charaters from previous position to CR+LF.
//
sCurrent += 2;
rc = DosWrite( FileHandle,
(PVOID)sPrev,
sCurrent - sPrev,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
IsFlushed = TRUE;
sPrev = sCurrent;
PrevPosition = 0;
} else if (*sCurrent == ' ') {
if ((PrevPosition + (sCurrent - sPrev)) >= 79) {
//
// If a wordwrap is needed, write CR+LF.
//
rc = DosWrite( FileHandle,
(PVOID)"\r\n",
2,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
PrevPosition = 0;
}
//
// Write charaters from previous position to
// current position.
//
rc = DosWrite( FileHandle,
(PVOID)sPrev,
sCurrent - sPrev + 1,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
IsFlushed = TRUE;
PrevPosition += (sCurrent - sPrev + 1);
sPrev = ++sCurrent;
} else if (Ow2NlsIsDBCSLeadByte(*sCurrent, SesGrp->DosCP)) {
if ((PrevPosition + (sCurrent - sPrev)) >= 79) {
//
// If a wordwrap is needed, write CR+LF.
//
rc = DosWrite( FileHandle,
(PVOID)"\r\n",
2,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
PrevPosition = 0;
}
if (sCurrent != sPrev) {
//
// Write charaters from previous position to
// (current position - 1).
//
rc = DosWrite( FileHandle,
(PVOID)sPrev,
sCurrent - sPrev,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
}
if ((PrevPosition + (sCurrent - sPrev) + 2) >= 79) {
//
// In this case, there is no space to write DBCS
// character(Consider CR+LF space).
// So DBCS character should be written in next line.
//
rc = DosWrite( FileHandle,
(PVOID)"\r\n",
2,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
PrevPosition = 2;
} else {
PrevPosition += (sCurrent - sPrev + 2);
}
if (*(sCurrent+1)) {
//
// Write DBCS character.
//
rc = DosWrite( FileHandle,
(PVOID)sCurrent,
2,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
sCurrent += 2;
} else {
//
// Write character.
//
rc = DosWrite( FileHandle,
(PVOID)sCurrent,
1,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
sCurrent ++;
}
sPrev = sCurrent;
IsFlushed = TRUE;
} else {
//
// if charater is SBCS, only increment the pointer
// which indicates the current position in message
// string.
//
IsFlushed = FALSE;
sCurrent++;
}
}
//
// If all of message are not written, flush them.
//
if (!IsFlushed) {
if ((PrevPosition + (sCurrent - sPrev)) >= 79) {
rc = DosWrite( FileHandle,
(PVOID)"\r\n",
2,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
}
rc = DosWrite( FileHandle,
(PVOID)sPrev,
sCurrent - sPrev,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
return( NO_ERROR );
#else
PCHAR sStart, sBlank, sCurrent, sEnd;
ULONG Discard;
APIRET rc;
sBlank = sStart = sCurrent = Message;
sEnd = sCurrent + MessageLength;
rc = NO_ERROR;
try {
while (sCurrent < sEnd) {
if (sCurrent[ 0 ] == '\r' && sCurrent[ 1 ] == '\n') {
if ((sCurrent - sStart) >= 80) {
rc = DosWrite( FileHandle,
(PVOID)sStart,
sBlank - sStart + 1,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
rc = DosWrite( FileHandle,
(PVOID)"\r\n",
2,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
sStart = sCurrent = sBlank + 1;
}
else {
sCurrent += 2;
rc = DosWrite( FileHandle,
(PVOID)sStart,
sCurrent - sStart,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
sStart = sBlank = sCurrent;
}
}
else
if (*sCurrent == ' ')
{
if ((sCurrent - sStart) >= 80) {
rc = DosWrite( FileHandle,
(PVOID)sStart,
sBlank - sStart + 1,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
rc = DosWrite( FileHandle,
(PVOID)"\r\n",
2,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
sStart = sCurrent = sBlank + 1;
}
else {
sBlank = sCurrent++;
}
}
else {
sCurrent++;
}
}
if (sCurrent > sStart) {
if ((sCurrent - sStart) >= 80) {
rc = DosWrite( FileHandle,
(PVOID)sStart,
sBlank - sStart + 1,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
rc = DosWrite( FileHandle,
(PVOID)"\r\n",
2,
&Discard
);
if (rc != NO_ERROR) {
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
}
sStart = sCurrent = sBlank + 1;
}
rc = DosWrite( FileHandle,
(PVOID)sStart,
sCurrent - sStart,
&Discard
);
}
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
#endif
}
APIRET
DosQueryMessageCP(
PCHAR Buffer,
ULONG Length,
IN PSZ MessageFileName,
OUT PULONG ActualLength
)
{
UNREFERENCED_PARAMETER(Buffer);
UNREFERENCED_PARAMETER(Length);
UNREFERENCED_PARAMETER(MessageFileName);
UNREFERENCED_PARAMETER(ActualLength);
return( ERROR_INVALID_FUNCTION );
}
NTSTATUS
Od2InitializeMessageFile( VOID )
{
Od2MsgFile = NULL;
return( STATUS_SUCCESS );
}