📄 exerespe.c
字号:
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "exerespe.h"
#define RESOURCE_OBJECT_NAME ".rsrc"
#ifndef MAKELANGID
#define MAKELANGID(p, s) ( ( ( (uint_16)(s) ) << 10 ) | (uint_16)(p) )
#endif
/* align should be a power of 2 */
/* without the casts the macro reads: (value + (align-1)) & ~(align-1) */
#define ALIGN_VALUE( value, align ) ( (uint_32)( \
( (uint_32)(value) + ( (uint_32)(align) - 1 ) ) \
& ~( (uint_32)(align) - 1 ) ) )
WResStatus WritePad(int handle, int size) {
static char blank[200]; // automatically initialized to 0 by compiler
for (; size > 200; size -= 200) {
if (WRESWRITE(handle, blank, 200) != 200) {
return WRS_WRITE_FAILED;
}
}
if (WRESWRITE(handle, blank, size) != size) {
return WRS_WRITE_FAILED;
} else {
return WRS_OK;
}
}
WResStatus CopyData( int from, int to, int len ) {
static char buff[200];
for (; len > 200; len -= 200) {
if (WRESREAD(from, buff, 200) != 200) return WRS_READ_FAILED;
if (WRESWRITE(to, buff, 200) != 200) return WRS_WRITE_FAILED;
}
if (WRESREAD(from, buff, len) != len) return WRS_READ_FAILED;
if (WRESWRITE(to, buff, len) != len) return WRS_WRITE_FAILED;
return WRS_OK;
}
/* structures and routines to manipulate a queue of PEResDirEntry * */
/* This uses a linked list representation despite the overhead of the pointer */
/* since the total number of entries in the queue should be small and this is */
/* easier to code while still being dynamic */
typedef struct QueueNode {
struct QueueNode * next;
PEResDirEntry * entry;
} QueueNode;
typedef struct DirEntryQueue {
QueueNode * front;
QueueNode * back;
} DirEntryQueue;
static void QueueInit( DirEntryQueue * queue )
/********************************************/
{
queue->front = NULL;
queue->back = NULL;
} /* QueueInit */
static void QueueEmpty( DirEntryQueue * queue )
/*********************************************/
{
QueueNode * curr;
QueueNode * old;
curr = queue->front;
while( curr != NULL ) {
old = curr;
curr = curr->next;
WRESFREE( old );
}
QueueInit( queue );
} /* QueueEmpty */
static int QueueIsEmpty( DirEntryQueue * queue )
/**********************************************/
{
return( queue->front == NULL );
}
static void QueueAdd( DirEntryQueue * queue, PEResDirEntry * entry )
/******************************************************************/
{
QueueNode * new;
new = WRESALLOC( sizeof(QueueNode) );
new->entry = entry;
new->next = NULL;
if( queue->front == NULL ) {
queue->front = new;
queue->back = new;
} else {
queue->back->next = new;
queue->back = new;
}
} /* QueueAdd */
static PEResDirEntry * QueueRemove( DirEntryQueue * queue )
/*********************************************************/
{
QueueNode * old;
PEResDirEntry * entry;
old = queue->front;
if( old == NULL ) {
return( NULL );
}
queue->front = old->next;
if( queue->front == NULL ) {
queue->back = NULL;
}
entry = old->entry;
WRESFREE( old );
return( entry );
} /* QueueRemove */
static void PEResDirEntryInit( PEResDirEntry * entry, int num_entries )
/*********************************************************************/
{
entry->Head.flags = 0;
entry->Head.time_stamp = time( NULL );
entry->Head.major = 0;
entry->Head.minor = 0;
entry->Head.num_name_entries = 0;
entry->Head.num_id_entries = 0;
entry->NumUnused = num_entries;
entry->Children = WRESALLOC( num_entries * sizeof(PEResEntry) );
}
static void PEResDirAdd( PEResDirEntry * entry, WResID * name,
StringBlock * strings )
/***********************************************************/
{
int entry_num;
int_32 name_off;
PEResEntry * curr;
entry_num = entry->Head.num_name_entries + entry->Head.num_id_entries;
curr = entry->Children + entry_num;
if( name->IsName ) {
name_off = StringBlockFind( strings, &name->ID.Name );
if( name_off == -1 ) {
/* this case should not happen */
curr->Entry.id_name = PE_RESOURCE_MASK_ON | 0;
curr->Name = NULL;
} else {
/* This value will be changed later when we know the size of the */
/* the resource directory */
curr->Entry.id_name = PE_RESOURCE_MASK_ON | name_off;
curr->Name = (char *)strings->StringBlock + name_off;
}
entry->Head.num_name_entries++;
} else {
curr->Entry.id_name = name->ID.Num;
curr->Name = NULL;
entry->Head.num_id_entries++;
}
entry->NumUnused--;
}
static int PEResDirAddDir( PEResDirEntry * entry, WResID * name,
int num_sub_entries, StringBlock * strings )
/***************************************************************/
{
int entry_num;
PEResEntry * curr;
if( entry->NumUnused <= 0 ) return( TRUE );
PEResDirAdd( entry, name, strings );
entry_num = entry->Head.num_name_entries + entry->Head.num_id_entries - 1;
curr = entry->Children + entry_num;
curr->IsDirEntry = TRUE;
PEResDirEntryInit( &curr->Dir, num_sub_entries );
return( FALSE );
}
static int PEResDirAddData( PEResDirEntry * entry, WResID * name,
WResDirWindow wind, StringBlock * strings )
/***************************************************************/
{
int entry_num;
PEResEntry * curr;
if( entry->NumUnused <= 0 ) return( TRUE );
PEResDirAdd( entry, name, strings );
entry_num = entry->Head.num_name_entries + entry->Head.num_id_entries - 1;
curr = entry->Children + entry_num;
curr->IsDirEntry = FALSE;
curr->Data.Wind = wind;
/* The Data.Entry field will be filled in as the resource is writen */
return( FALSE );
}
static int AddType( PEResDir * res, WResTypeInfo * type )
/*******************************************************/
{
return( PEResDirAddDir( &res->Root, &type->TypeName, type->NumResources,
&res->String ) );
}
static int AddLang( PEResDir *res, WResDirWindow wind ) {
/*******************************************************/
int entry_num;
PEResEntry *currres;
PEResEntry *currtype;
WResLangInfo *langinfo;
WResID lang_id;
langinfo = WResGetLangInfo( wind );
/* find the current type */
entry_num = res->Root.Head.num_name_entries
+ res->Root.Head.num_id_entries - 1;
currtype = res->Root.Children + entry_num;
/* find the current resource */
entry_num = currtype->Dir.Head.num_name_entries
+ currtype->Dir.Head.num_id_entries - 1;
currres = currtype->Dir.Children + entry_num;
lang_id.IsName = FALSE;
lang_id.ID.Num = MAKELANGID( langinfo->lang.lang, langinfo->lang.sublang );
if( PEResDirAddData( &currres->Dir, &lang_id, wind,
&res->String ) ) {
return( TRUE );
}
return( FALSE );
}
static int AddRes( PEResDir * res, WResDirWindow wind )
/*****************************************************/
{
int entry_num;
PEResEntry * currtype;
WResResInfo * resinfo;
resinfo = WResGetResInfo( wind );
/* find the current type */
entry_num = res->Root.Head.num_name_entries + res->Root.Head.num_id_entries;
currtype = res->Root.Children + entry_num - 1;
/* Add a directory level for the languages */
if( PEResDirAddDir( &currtype->Dir, &resinfo->ResName,
resinfo->NumResources, &res->String ) ) {
return( TRUE );
}
return( FALSE );
}
/*
* traverseTree
* NB when a visit function returns an error this function MUST return
* without altering errno
*/
static WResStatus traverseTree( PEResDir * dir, void * visit_data,
WResStatus (*visit)( PEResEntry *, void * visit_data ) )
/*******************************************************************/
/* Perfroms a level order traversal of a PEResDir tree calling visit at */
/* each entry */
{
PEResEntry * curr_entry;
PEResEntry * last_child;
PEResDirEntry * curr_dir;
DirEntryQueue queue;
WResStatus ret;
QueueInit( &queue );
QueueAdd( &queue, &dir->Root );
while( !QueueIsEmpty( &queue ) ) {
curr_dir = QueueRemove( &queue );
last_child = curr_dir->Children + curr_dir->Head.num_name_entries +
curr_dir->Head.num_id_entries;
curr_entry = curr_dir->Children;
while( curr_entry < last_child ) {
ret = visit( curr_entry, visit_data );
if( ret != WRS_OK ) return( ret );
if( curr_entry->IsDirEntry ) {
QueueAdd( &queue, &curr_entry->Dir );
}
curr_entry++;
}
}
QueueEmpty( &queue );
return( WRS_OK );
} /* traverseTree */
static WResStatus SetEntryOffset( PEResEntry * entry, uint_32 * curr_offset )
/********************************************************************/
{
int num_entries;
if( entry->IsDirEntry ) {
entry->Entry.entry_rva = *curr_offset | PE_RESOURCE_MASK_ON;
num_entries = entry->Dir.Head.num_name_entries +
entry->Dir.Head.num_id_entries;
*curr_offset += sizeof(resource_dir_header) +
num_entries * sizeof(resource_dir_entry);
} else {
entry->Entry.entry_rva = *curr_offset;
*curr_offset += sizeof(resource_entry);
}
return( WRS_OK );
} /* SetEntryOffset */
static WResStatus AdjustNameEntry( PEResEntry * entry, uint_32 * dir_size )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -