View difference between Paste ID: ygHjTxM1 and qB1A3vsX
SHOW: | | - or go back to the newest paste.
1
/***
2
 * File: StrBuff.c
3
 * AUTHOR:	FX. J. Adi Lima ( adi7598@gmail.com )
4
 * DESCRIPTION:
5
 *		A simple implementation of MSVC DLL which link against GNU libobjc.
6
 *		This module implements a simple StringBuffer object, creatable from Objective-C.
7
 *		The resulting Objective-C interface should be:
8
 *
9
 *		// typedef for Range (unsigned __int64)
10
 *		typedef unsigned __int64 Range;
11
 *		#define MakeRange(vStart, vEnd)	(Range)(((Range)(vEnd) << 32) | (vEnd & 0xFFFFFFFF))
12
 *		@interface StringBuffer {
13
 *			Class isa;
14
 *		}
15
 *		+ stringWithString:(id)aString;
16
 *		+ stringWithFormat:(LPCWSTR)pszFormat, ...;
17
 *		- retain;
18
 *		- (void) release;
19
 *		- (LPCWSTR) string;
20
 *		- (UINT) length;
21
 *		- (StringBuffer*) description;
22
 *		- (LPCWSTR) concatW:(LPCWSTR)pszFormat, ...;
23
 *		- (StringBuffer*) substringFromRange:(Range)range;
24
 *		@end
25
 *
26
 *		// You should also define the following
27
 *		__inline LPCSTR __objc_class_name_StringBuffer() { return "StringBuffer"; }
28
 *
29
 *		// And use the StringBuffer object like normal.
30
 *		// Ah, yes... please load the DLL first!!! (and free it when done)
31
*/
32
33
#include <windows.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <stdarg.h>
37
#include <string.h>
38
39
HINSTANCE hDllInstance = NULL;
40
HINSTANCE hObjc = NULL;
41
42
typedef struct objc_class *Class;
43
typedef struct objc_object *id;
44
typedef struct objc_selector *SEL;
45
typedef struct objc_protocol *Protocol;
46
47
struct objc_class { Class isa; };
48
struct objc_object { Class isa; };
49
typedef id (*IMP)(id _self, SEL _cmd, ...);
50
51
id (*objc_getClass)(LPCSTR) = NULL;
52
id (*objc_allocateClassPair)(Class, LPCSTR, size_t) = NULL;
53
void (*objc_registerClassPair)(Class) = NULL;
54
Protocol (*objc_getProtocol)(LPCSTR) = NULL;
55
56
LPCSTR (*class_getName)(Class) = NULL;
57
int (*class_addMethod)(Class, SEL, IMP, LPCSTR) = NULL;
58
int (*class_addIvar)(Class, LPCSTR, size_t, BYTE, LPCSTR) = NULL;
59
IMP (*class_getMethodImplementation)(Class, SEL) = NULL;
60
61
SEL (*selector)(LPCSTR) = NULL;
62
LPCSTR (*selectorName)(SEL) = NULL;
63
BOOL (*selectorEqual)(SEL, SEL) = NULL;
64
65
static int LoadFunctions(FARPROC* buffer, LPCSTR pszFirst, ...)
66
{
67
	FARPROC* pp = buffer;
68
	LPCSTR psz = pszFirst;
69
	int nRes = 0;
70
	va_list args;
71
	va_start(args, pszFirst);
72
	while (psz)
73
	{
74
		*pp = GetProcAddress(hObjc, psz);
75
		if (*pp) ++nRes;
76
		pp++;
77
		psz = va_arg(args, LPCSTR);
78
	}
79
	return nRes;
80
}
81
82
BYTE log2Of(size_t ilen)
83
{
84
	size_t n = ilen;
85
	BYTE ret = 0;
86
	while ((n >>= 1) != 0) ++ret;
87
	return ret;
88
}
89
90
typedef struct CSTR {
91
	Class isa;
92
	LPCSTR pszText;
93
	UINT length;
94
} CSTR;
95
96
static Class __stringBufferClass = NULL;
97
typedef unsigned __int64 UInt64;
98
99
typedef struct __GFSTRING {
100
	Class isa;
101
	LPWSTR lpw;
102
	size_t length;
103
	DWORD dwRef;
104
} GFSTRING, *LPGFSTRING;
105
106
static Class GFStringInitialize(Class cls);
107
static LPGFSTRING GFStringCreateWithString(Class cls, SEL _cmd, CSTR* pStr);
108
static LPGFSTRING GFStringCreateWithFormat(Class cls, SEL _cmd, LPCWSTR pszFormat, ...);
109
static LPGFSTRING GFStringRetain(LPGFSTRING pThis);
110
static void GFStringRelease(LPGFSTRING pThis);
111
static LPCWSTR GFStringGetString(LPGFSTRING pThis);
112
static UINT GFStringGetLength(LPGFSTRING pThis);
113
static LPGFSTRING GFStringGetDescription(LPGFSTRING pThis);
114
static LPCWSTR GFStringConcatW(LPGFSTRING pThis, SEL _cmd, LPCWSTR pszFormat, ...);
115
static LPGFSTRING GFStringSubstringFromRange(LPGFSTRING pThis, SEL _cmd, UInt64 range);
116
static WCHAR GFStringGetCharAtIndex(LPGFSTRING pThis, SEL _Cmd, int index);
117
static UINT GFStringGetFirstIndexOfChar(LPGFSTRING pThis, SEL _cmd, wchar_t chVal);
118
static UINT GFStringGetLastIndexOfChar(LPGFSTRING pThis, SEL _cmd, wchar_t chVal);
119
120
static BOOL GFStringRegisterClass(void)
121
{
122
	Class c = (Class)objc_allocateClassPair(NULL, "StringBuffer", 0);
123
	if (!c) return FALSE;
124
	class_addIvar(c, "isa", sizeof(Class), log2Of(sizeof(Class)), "#");
125
	class_addMethod(c->isa, selector("initialize"), (IMP)GFStringInitialize, "##");
126
	class_addMethod(c->isa, selector("stringWithString:"), (IMP)GFStringCreateWithString, "@#:@");
127
	class_addMethod(c, selector("stringWithFormat:"), (IMP)GFStringCreateWithFormat, "@#:*");
128
	class_addMethod(c, selector("retain"), (IMP)GFStringRetain, "@@:");
129
	class_addMethod(c, selector("release"), (IMP)GFStringRelease, "v@:");
130
	class_addMethod(c, selector("string"), (IMP)GFStringGetString, "*@:");
131
	class_addMethod(c, selector("length"), (IMP)GFStringGetLength, "I@:");
132
	class_addMethod(c, selector("description"), (IMP)GFStringGetDescription, "@@:");
133
	class_addMethod(c, selector("concatW:"), (IMP)GFStringConcatW, "*@:*");
134
	class_addMethod(c, selector("substringFromRange:"), (IMP)GFStringSubstringFromRange, "@@:Q");
135
	class_addMethod(c, selector("characterAtIndex:"), (IMP)GFStringGetCharAtIndex, "S@:I");
136
	class_addMethod(c, selector("firstIndexOf:"), (IMP)GFStringGetFirstIndexOfChar, "I@:S");
137
	class_addMethod(c, selector("lastIndexOf:"), (IMP)GFStringGetLastIndexOfChar, "I@:S");
138
	objc_registerClassPair(c);
139
	__stringBufferClass = c;
140
	return TRUE;
141
}
142
143
BOOL DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
144
{
145
	if (dwReason == DLL_PROCESS_ATTACH)
146
	{
147
		hDllInstance = hInstance;
148
		/* the following hardcoded path should be replaced according to what you need */
149
		if (hObjc = LoadLibrary(L"E:\\mingw64\\bin\\libobjc-4.dll"))
150
		{
151
			FARPROC buffer[10];
152
			int nRes = LoadFunctions(buffer, "objc_getClass", "objc_allocateClassPair",
153
				"objc_registerClassPair", "objc_getProtocol", NULL);
154
			if (!nRes) return FALSE;
155
			objc_getClass = (id (*)(LPCSTR))buffer[0];
156
			objc_allocateClassPair = (id (*)(Class, LPCSTR, size_t))buffer[1];
157
			objc_registerClassPair = (void (*)(Class))buffer[2];
158
			objc_getProtocol = (Protocol (*)(LPCSTR))buffer[3];
159
			nRes = LoadFunctions(buffer, "class_getName", "class_addMethod", "class_addIvar", "class_getMethodImplementation", NULL);
160
			if (!nRes) return FALSE;
161
			class_getName = (LPCSTR(*)(Class))buffer[0];
162
			class_addMethod = (int(*)(Class, SEL, IMP, LPCSTR))buffer[1];
163
			class_addIvar = (int(*)(Class, LPCSTR, size_t, BYTE, LPCSTR))buffer[2];
164
			class_getMethodImplementation = (IMP(*)(Class, SEL))buffer[3];
165
			nRes = LoadFunctions(buffer, "sel_registerName", "sel_getName", "sel_isEqual", NULL);
166
			if (!nRes) return FALSE;
167
			selector = (SEL(*)(LPCSTR))buffer[0];
168
			selectorName = (LPCSTR(*)(SEL))buffer[1];
169
			selectorEqual = (BOOL(*)(SEL, SEL))buffer[2];			
170
			return GFStringRegisterClass();
171
		}
172
		return FALSE;
173
	}
174
	else if (dwReason == DLL_PROCESS_DETACH)
175
	{
176
		if (hObjc)
177
		{
178
			FreeLibrary(hObjc);
179
			hObjc = NULL;
180
		}
181
	}
182
	return TRUE;
183
}
184
185
static Class GFStringInitialize(Class cls) {
186
	return cls;
187
}
188
189
static LPGFSTRING GFStringCreateWithString(Class cls, SEL _cmd, CSTR* pStr) {
190
	LPGFSTRING pObj = (LPGFSTRING)malloc(sizeof(GFSTRING));
191
	size_t len = 0;
192
	memset(pObj, 0, sizeof(GFSTRING));
193
	pObj->isa = cls;
194
	len = MultiByteToWideChar(CP_UTF8, 0, pStr->pszText, lstrlenA(pStr->pszText),
195
		NULL, 0) ;
196
	pObj->lpw = (LPWSTR)malloc(sizeof(wchar_t) * len);
197
	pObj->lpw[len-1] = 0;
198
	MultiByteToWideChar(CP_UTF8, 0, pStr->pszText, lstrlenA(pStr->pszText),
199
		pObj->lpw, len);
200
	pObj->dwRef = 1;
201
	pObj->length = len;
202
	return pObj;
203
}
204
205
static LPGFSTRING GFStringCreateWithFormat(Class cls, SEL _cmd, LPCWSTR pszFormat, ...) {
206
	LPWSTR temp = NULL;
207
	size_t len = 0;
208
	va_list args;
209
	LPGFSTRING pObj = (LPGFSTRING)malloc(sizeof(GFSTRING));
210
	memset(pObj, 0, sizeof(GFSTRING));
211
	pObj->isa = cls;
212
	
213
	va_start(args, pszFormat);
214
	len = _vscwprintf(pszFormat, args) + 1;
215
	temp = (LPWSTR)malloc(sizeof(WCHAR) * len);
216
	vswprintf_s(temp, len, pszFormat, args);
217
	va_end(args);
218
	
219
	pObj->lpw = temp;
220
	pObj->length = len;
221
	pObj->dwRef = 1;
222
	return pObj;
223
}
224
225
static LPGFSTRING GFStringRetain(LPGFSTRING pThis) {
226
	++pThis->dwRef;
227
	return pThis;
228
}
229
230
static void GFStringRelease(LPGFSTRING pThis) {
231
	if (--pThis->dwRef) return;
232
	if (pThis->lpw) {
233
		free(pThis->lpw);
234
		pThis->lpw = NULL;
235
		pThis->length = 0;
236
	}
237
	free((void*)pThis);
238
}
239
240
static LPCWSTR GFStringGetString(LPGFSTRING pThis) {
241
	return (LPCWSTR)pThis->lpw;
242
}
243
244
static UINT GFStringGetLength(LPGFSTRING pThis) {
245
	return (UINT)lstrlenW(pThis->lpw);
246
}
247
248
static LPGFSTRING GFStringGetDescription(LPGFSTRING pThis) {
249
	LPGFSTRING retVal = NULL;
250
	LPWSTR lpw = NULL;
251
	size_t len = lstrlenW(pThis->lpw) + 150;
252
	lpw = (LPWSTR)malloc(sizeof(WCHAR) * len);
253
	wsprintfW(lpw, L"<GFString 0x%p { string = %s, length = %lu }>",
254
		pThis, pThis->lpw, pThis->length);
255
	retVal = (LPGFSTRING)malloc(sizeof(GFSTRING));
256
	retVal->isa = pThis->isa;
257
	retVal->lpw = lpw;
258
	retVal->length = len;
259
	retVal->dwRef = 1;
260
	return retVal;
261
}
262
263
static LPCWSTR GFStringConcatW(LPGFSTRING pThis, SEL _cmd, LPCWSTR pszFormat, ...) {
264
	LPWSTR lpw = NULL;
265
	LPWSTR temp = NULL;
266
	size_t len, total;
267
	va_list args;
268
	va_start(args, pszFormat);
269
	len = _vscwprintf(pszFormat, args) + 1;
270
	temp = (LPWSTR)malloc(sizeof(WCHAR) * len);
271
	vswprintf_s(temp, len, pszFormat, args);
272
	va_end(args);
273
	total = lstrlenW(pThis->lpw) + len;
274
	lpw = (LPWSTR)malloc(sizeof(WCHAR) * total);
275
	lstrcpyW(lpw, pThis->lpw);
276
	lstrcatW(lpw, temp);
277
	free(temp);
278
	free(pThis->lpw);
279
	pThis->lpw = lpw;
280
	pThis->length = total;
281
	return lpw;
282
}
283
284
static LPGFSTRING GFStringSubstringFromRange(LPGFSTRING pThis, SEL _cmd, UInt64 range) {
285
	LPGFSTRING pObj = NULL;
286
	size_t nStart = (size_t)(range & 0xFFFFFFFF);
287
	size_t nEnd = (size_t)((range >> 32) & 0xFFFFFFFF);
288
	size_t total = nEnd - nStart;
289
	size_t i;
290
	LPWSTR p1, p2;
291
	
292
	if ((nEnd >= lstrlenW(pThis->lpw)) || (total > lstrlenW(pThis->lpw))) {
293
		OutputDebugString(L"Invalid range specified!\n");
294
		return NULL;
295
	}
296
	pObj = (LPGFSTRING)malloc(sizeof(GFSTRING));
297
	memset(pObj, 0, sizeof(GFSTRING));
298
	pObj->isa = pThis->isa;
299
	pObj->lpw = (LPWSTR)malloc(sizeof(WCHAR) * (total+1));
300
	pObj->lpw[total] = 0;
301
302
	p1 = &pThis->lpw[nStart];
303
	p2 = pObj->lpw;
304
	for (i = 0; i < total; i++)
305
		*p2++ = *p1++;
306
	
307
	pObj->length = lstrlenW(pObj->lpw);
308
	pObj->dwRef = 1;
309
	return pObj;
310
}
311
312
static WCHAR GFStringGetCharAtIndex(LPGFSTRING pThis, SEL _Cmd, int index) {
313
	if (pThis->lpw && (index < pThis->length))
314
		return pThis->lpw[index];
315
	return 0;
316
} 
317
318
static UINT GFStringGetFirstIndexOfChar(LPGFSTRING pThis, SEL _cmd, wchar_t chVal) {
319
	if (pThis->lpw) {
320
		size_t i = 0;
321
		LPWSTR p = pThis->lpw;
322
		while (i < pThis->length) {
323
			if (*p == chVal) return (UINT)i;
324
			i++;
325
			p++;
326
		}
327
	}
328
	/* not found */
329
	return -1;
330
}
331
332
static UINT GFStringGetLastIndexOfChar(LPGFSTRING pThis, SEL _cmd, wchar_t chVal) {
333
	if (pThis->lpw) {
334
		UINT i = (UINT)pThis->length - 1;
335
		LPWSTR p = &pThis->lpw[i];
336
		while (i >= 0) {
337
			if (*p == chVal) return i;
338
			--i;
339
			--p;
340
		}
341
	}
342
	return -1;
343
}