Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/modules/KextPatcher/kext_patcher.c

Source at commit 611 created 13 years 5 months ago.
By meklort, HDA codec can now be specified with HDACodec=888 (or another codec)
1/*
2 * Copyright (c) 2010 Evan Lojewski. All rights reserved.
3 *
4 *KextPather
5 *This is an experimental module that I'm looking into implimenting.
6 *The main purpose is to replace the need for programs such as
7 * NetbookInstaller's kext patching routines. THis way, Apple's kexts can be
8 * patched whe loaded instead. (eg: GMA950 kext, Bluetooth + Wifi kexts)
9 */
10
11#include "libsaio.h"
12#include "zlib.h"
13#include "kext_patcher.h"
14#include "boot.h"
15#include "bootstruct.h"
16#include "pci.h"
17#include "drivers.h"
18#include "mkext.h"
19#include "modules.h"
20#include "hex_editor.h"
21
22
23#define kHDACodec"HDACodec"/* acpi_patcher.c */
24
25
26#ifndef DEBUG_KEXT_PATCHER
27#define DEBUG_KEXT_PATCHER 0
28#endif
29
30#if DEBUG_KEXT_PATCHER
31#define DBG(x...)printf(x)
32#else
33#define DBG(x...)
34#endif
35bool patch_kext(TagPtr plist, char* plistbuffer, void* start);
36bool patch_gma_kexts(TagPtr plist, char* plistbuffer, void* start);
37bool patch_bcm_kext(TagPtr plist, char* plistbuffer, void* start);
38bool patch_hda_kext(TagPtr plist, char* plistbuffer, void* start);
39bool patch_hda_controller(TagPtr plist, char* plistbuffer, void* start);
40
41int chartohex(char c);
42
43static void * z_alloc(void *, u_int items, u_int size);
44static void z_free(void *, void *ptr);
45
46uint16_t patch_gma_deviceid = 0;
47uint16_t patch_bcm_deviceid = 0;
48// TODO: add detection code / a method for users to enter the id
49uint16_t patch_hda_codec = 0;
50
51#define NEEDS_PATCHING(patch_bcm_deviceid || patch_gma_deviceid || patch_hda_codec)
52
53typedef struct z_mem {
54 uint32_t alloc_size;
55 uint8_t data[0];
56} z_mem;
57
58/*
59 * Space allocation and freeing routines for use by zlib routines.
60 */
61void *
62z_alloc(void * notused __unused, u_int num_items, u_int size)
63{
64 void * result = NULL;
65 z_mem * zmem = NULL;
66 uint32_t total = num_items * size;
67 uint32_t allocSize = total + sizeof(zmem);
68
69 zmem = (z_mem *)malloc(allocSize);
70 if (!zmem) {
71 goto finish;
72 }
73 zmem->alloc_size = allocSize;
74 result = (void *)&(zmem->data);
75finish:
76 return result;
77}
78
79void
80z_free(void * notused __unused, void * ptr)
81{
82 uint32_t * skipper = (uint32_t *)ptr - 1;
83 z_mem * zmem = (z_mem *)skipper;
84 free((void *)zmem);
85 return;
86}
87
88
89unsigned long Mkext_Alder32( unsigned char * buffer, long length );
90
91void KextPatcher_hook(void* current, void* arg2, void* arg3, void* arg4);
92
93/**
94 ** KextPatcher_start -> module start
95 **Notified the module system that this module will hook into the
96 **LoadMatchedModules and LoadDriverMKext functions
97 **/
98void KextPatcher_start()
99{
100// Hooks into the following:
101//execute_hook("LoadDriverMKext", (void*)package, (void*) length, NULL, NULL);
102// execute_hook("LoadMatchedModules", module, &length, executableAddr, NULL);
103
104register_hook_callback("PCIDevice", &KextPatcher_hook);
105//register_hook_callback("LoadMatchedModules", &kext_loaded);
106register_hook_callback("LoadDriverMKext", &mkext_loaded);
107
108}
109
110/**
111 ** kext_loaded -> Called whenever a kext is in read into memory
112 **This function will be used to patch kexts ( eg AppleInteIntegratedFramebuffer)
113 **and their plists when they are loaded into memmory
114 **/
115void kext_loaded(void* moduletmp, void* lengthprt, void* executableAddr, void* arg3)
116{
117
118//ModulePtr module = moduletmp;
119//long length = *(long*)lengthprt;
120//long length2 = strlen(module->plistAddr);
121// *(long*)lengthprt = length2 + 5 * 1024 * 1024;
122
123//printf("Loading %s, lenght is %d, executable is 0x%X\n", module->plistAddr, length, executableAddr);
124//getc();
125}
126
127/**
128 ** mkext_loaded -> Called whenever an mkext is in read into memory
129 **This function will be used to patch mkext. Matching kexts will be
130 **Extracted, modified, and then compressed again. Note: I need to determine
131 **what sort of slowdown this will cause and if it's worth implimenting.
132 **/
133
134void mkext_loaded(void* filespec, void* packagetmp, void* lengthtmp, void* arg3)
135{
136const char* hda_codec;
137int len = 0;
138
139if (getValueForKey(kHDACodec, &hda_codec, &len, &bootInfo->bootConfig))
140{
141int index = 0;
142while(len)
143{
144patch_hda_codec <<= 4;
145patch_hda_codec |= chartohex(hda_codec[index]);
146
147len--;
148index++;
149}
150}
151
152if(!NEEDS_PATCHING) return;// No need to apply a patch, hardware doesn't need it
153
154int version = 0;
155//int length = *((int*)lengthtmp);
156mkext_basic_header* package = packagetmp;
157
158// Verify the MKext.
159 if (( MKEXT_GET_MAGIC(package)!= MKEXT_MAGIC ) ||
160 ( MKEXT_GET_SIGNATURE(package)!= MKEXT_SIGN ) ||
161 ( MKEXT_GET_LENGTH(package)> kLoadSize ) ||
162 ( MKEXT_GET_CHECKSUM(package) !=
163 Mkext_Alder32((unsigned char *)&package->version, MKEXT_GET_LENGTH(package) - 0x10) ) )
164 {
165 return;
166// Don't try to patch a b
167 }
168
169/*
170if(strcmp(filespec, "/System/Library/Caches/com.apple.kext.caches/Startup/Extensions.mkext") == 0)
171{
172printf("Invalidating mkext %s\n", filespec);
173// 10.6 cache folder. Doesn't contain certain extensions we need, so invalidate it.
174//package->adler32++;
175// NOTE: double check that this is needed
176package->magic = 0x00;
177return;
178}*/
179
180
181version = MKEXT_GET_VERSION(package);
182
183if(version == 0x01008000) // mkext1
184{
185// mkext1 uses lzss
186mkext1_header* package = packagetmp;
187int i;
188for(i = 0; i < MKEXT_GET_COUNT(package); i++)
189{
190DBG("Parsing kext %d\n", i);
191//mkext_kext* kext = MKEXT1_GET_KEXT(package, i);
192// uses decompress_lzss
193// TODO: handle kext
194
195}
196}
197else if((version & 0xFFFF0000) == 0x02000000) // mkext2
198{
199DBG("Mkext2 package located at 0x%X\n", package);
200
201// mkext2 uses zlib
202mkext2_header* package = packagetmp;
203z_stream zstream;
204bool zstream_inited = false;
205int zlib_result;
206int plist_offset = MKEXT2_GET_PLIST(package);
207
208char* plist = malloc(MKEXT2_GET_PLIST_FULLSIZE(package));
209
210bzero(&zstream, sizeof(zstream));
211zstream.next_in = (UInt8*)((char*)package + plist_offset);
212zstream.avail_in = MKEXT2_GET_PLIST_COMPSIZE(package);
213
214zstream.next_out = (UInt8*)plist;
215zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package);
216
217zstream.zalloc = z_alloc;
218zstream.zfree = z_free;
219
220zlib_result = inflateInit(&zstream);
221if (Z_OK != zlib_result)
222{
223printf("ZLIB Error: %s\n", zstream.msg);
224getc();
225}
226else
227{
228zstream_inited = true;
229}
230
231
232zlib_result = inflate(&zstream, Z_FINISH);
233if (zstream_inited) inflateEnd(&zstream);
234
235DBG("Inflated result is %d, in: %d bytes, out: %d bytes\n", zlib_result, zstream.total_in, zstream.total_out);
236if (zlib_result == Z_STREAM_END || zlib_result == Z_OK)
237{
238config_file_t plistData;
239config_file_t allDicts;
240bzero(&plistData, sizeof(plistData));
241bzero(&allDicts, sizeof(allDicts));
242
243XMLParseFile( plist, &plistData.dictionary );
244
245int count = 0;
246
247allDicts.dictionary = XMLGetProperty(plistData.dictionary, kMKEXTInfoDictionariesKey);
248count = XMLTagCount(allDicts.dictionary);
249
250DBG("Plist contains %d kexts\n", count);
251
252
253bool patched = false;
254for(; count--; count > 0)
255{
256TagPtr kextEntry = XMLGetElement(allDicts.dictionary, count);
257patched |= patch_kext(kextEntry, plist, package);
258}
259
260
261if(patched)
262{
263zstream_inited = false;
264// Recompress the plist
265bzero(&zstream, sizeof(zstream));
266zstream.next_in = (UInt8*)plist;
267zstream.next_out = (UInt8*)package + plist_offset;
268zstream.avail_in = MKEXT2_GET_PLIST_FULLSIZE(package);
269zstream.avail_out = MKEXT2_GET_PLIST_FULLSIZE(package)<<2;// Give us some extra free space, just in case
270zstream.zalloc = Z_NULL;
271zstream.zfree = Z_NULL;
272zstream.opaque = Z_NULL;
273
274
275zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);
276if (Z_OK != zlib_result) {
277printf("ZLIB Deflate Error: %s\n", zstream.msg);
278getc();
279}
280else
281{
282zstream_inited = true;
283}
284
285zlib_result = deflate(&zstream, Z_FINISH);
286
287if (zlib_result == Z_STREAM_END)
288{
289DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, MKEXT2_GET_PLIST_FULLSIZE(package));
290}
291else if (zlib_result == Z_OK)
292{
293/* deflate filled output buffer, meaning the data doesn't compress.
294 */
295DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, MKEXT2_GET_PLIST_FULLSIZE(package));
296
297}
298else if (zlib_result != Z_STREAM_ERROR)
299{
300printf("ZLIB Deflate Error: %s\n", zstream.msg);
301getc();
302}
303
304if(zstream.total_out != MKEXT2_GET_PLIST_COMPSIZE(package))
305{
306// Update the mkext length
307MKEXT2_HDR_CAST(package)->length = MKEXT_SWAP(MKEXT_GET_LENGTH(package) - MKEXT2_GET_PLIST_COMPSIZE(package) + zstream.total_out);
308MKEXT2_HDR_CAST(package)->plist_compressed_size = MKEXT_SWAP(zstream.total_out);
309*((int*)lengthtmp) -= MKEXT2_GET_PLIST_COMPSIZE(package);
310*((int*)lengthtmp) += zstream.total_out;
311}
312
313if (zstream_inited) deflateEnd(&zstream);
314
315
316
317// re alder32 the new mkext2 package
318MKEXT_HDR_CAST(package)->adler32 =
319MKEXT_SWAP(Mkext_Alder32((unsigned char *)&package->version,
320 MKEXT_GET_LENGTH(package) - 0x10));
321}
322}
323else
324{
325printf("ZLIB Error: %s\n", zstream.msg);
326getc();
327}
328
329//config_file_t mkextPlist;
330//ParseXMLFile((char*) plist, &mkextPlist.dictionary);
331
332
333
334
335
336/*int i;
337for(i = 0; i < MKEXT_GET_COUNT(package); i++)
338{
339printf("Parsing kext %d\n", i);
340}
341*/
342
343
344}
345
346
347DBG("Loading %s, length %d, version 0x%x\n", filespec, length, version);
348//getc();
349}
350
351// FIXME: only handles mkext2 entries
352bool patch_kext(TagPtr plist, char* plistbuffer, void* start)
353{
354char* bundleID;
355
356if(XMLGetProperty(plist, kMKEXTExecutableKey) == NULL) return false;// Kext is a plist only kext, don't patch
357
358bundleID = XMLCastString(XMLGetProperty(plist, kPropCFBundleIdentifier));
359
360
361if(patch_gma_deviceid &&
362 (
363(strcmp(bundleID, "com.apple.driver.AppleIntelGMA950") == 0) ||
364(strcmp(bundleID, "com.apple.driver.AppleIntelIntegratedFramebuffer") == 0)
365 )
366 )
367{
368return patch_gma_kexts(plist, plistbuffer, start);
369}
370else if(patch_bcm_deviceid && (strcmp(bundleID, "com.apple.driver.AirPortBrcm43xx") == 0))
371{
372return patch_bcm_kext(plist, plistbuffer, start);
373
374}
375else if(patch_hda_codec && strcmp(bundleID, "com.apple.driver.AppleHDA") == 0)
376{
377return patch_hda_kext(plist, plistbuffer, start);
378
379}
380/*
381else if(patch_hda_codec && strcmp(bundleID, "com.apple.driver.AppleHDAController") == 0)
382{
383return patch_hda_controller(plist, plistbuffer, start);
384
385}
386*/
387return false;
388}
389
390void KextPatcher_hook(void* arg1, void* arg2, void* arg3, void* arg4)
391{
392pci_dt_t* current = arg1;
393if(current)
394{
395if(current->class_id == PCI_CLASS_DISPLAY_VGA)
396{
397if(current->vendor_id == 0x8086 && current->device_id == 0x27AE)
398{
399// TODO: patche based on dev id.
400patch_gma_deviceid = current->device_id;
401}
402}
403else if(current->class_id == PCI_CLASS_NETWORK_OTHER)
404{
405// Patch BCM43xx
406if(current->vendor_id == 0x14E4 && ((current->device_id & 0xFF00) == 0x4300))
407{
408patch_bcm_deviceid = current->device_id;
409}
410}
411}
412}
413
414
415bool patch_hda_controller(TagPtr plist, char* plistbuffer, void* start)
416{
417return false;
418// change the PCI class code to match to. Note: A LegacyHDA plist should do this on it's own
419// As such, it's disabled
420
421// TODO: read class code
422TagPtr personality;
423personality =XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));
424personality =XMLGetProperty(personality, (const char*)"BuiltInHDA");
425TagPtr match_class =XMLCastArray(XMLGetProperty(personality, (const char*)"IOPCIClassMatch"));
426
427
428char* new_str = malloc(strlen("0xXXXX000&0xFFFE0000")+1);
429sprintf(new_str, "0x04030000&amp;0xFFFE0000"); // todo, pass in actual class id
430
431
432char* orig_string = "0x04020000&amp;0xFFFE0000"; //XMLCastString(match_class);
433
434DBG("Attemting to replace '%s' with '%s'\n", orig_string, new_str);
435
436// TODO: verify string doesn't exist first.
437
438replace_string(orig_string, new_str, plistbuffer + XMLCastStringOffset(match_class), 1024);
439
440return true;
441
442}
443
444
445bool patch_hda_kext(TagPtr plist, char* plistbuffer, void* start)
446{
447uint16_t find_codec = 0;
448int full_size, compressed_size, executable_offset;
449void* compressed_data;
450mkext2_file_entry* kext;
451int zlib_result;
452z_stream zstream;
453bool zstream_inited = false;
454
455switch(0xFF00 & patch_hda_codec)
456{
457case 0x0200:
458find_codec = 0x0262;
459break;
460
461case 0x0800:
462find_codec = 0x0885;
463break;
464
465case 0x0600:// specificaly the 662
466find_codec = 0x0885;
467break;
468}
469
470if(!find_codec) return false;// notify caller that we aren't patching the kext
471
472
473executable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));
474kext = (void*)((char*)start + executable_offset);
475
476full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);
477compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);
478compressed_data = MKEXT2_GET_ENTRY_DATA(kext);
479executable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));
480
481
482char* executable = malloc(full_size);
483
484bzero(&zstream, sizeof(zstream));
485zstream.next_in = (UInt8*)compressed_data;
486zstream.avail_in = compressed_size;
487
488zstream.next_out = (UInt8*)executable;
489zstream.avail_out = full_size;
490
491zstream.zalloc = z_alloc;
492zstream.zfree = z_free;
493
494zlib_result = inflateInit(&zstream);
495if (Z_OK != zlib_result)
496{
497printf("ZLIB Inflate Error: %s\n", zstream.msg);
498getc();
499}
500else
501{
502zstream_inited = true;
503}
504
505
506zlib_result = inflate(&zstream, Z_FINISH);
507
508DBG("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
509
510replace_word(0x10EC | (find_codec << 8), 0xE10EC | (patch_hda_codec << 8), executable, zstream.total_out);
511
512if (zstream_inited) inflateEnd(&zstream);
513
514
515zstream.next_in = (UInt8*)executable;
516zstream.next_out = (UInt8*)compressed_data;
517
518zstream.avail_in = full_size;
519zstream.avail_out = compressed_size;
520zstream.zalloc = Z_NULL;
521zstream.zfree = Z_NULL;
522zstream.opaque = Z_NULL;
523
524
525
526// Recompress the eecutable
527zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);
528if (Z_OK != zlib_result) {
529printf("ZLIB Deflate Error: %s\n", zstream.msg);
530getc();
531}
532else
533{
534zstream_inited = true;
535}
536
537zlib_result = deflate(&zstream, Z_FINISH);
538
539if (zlib_result == Z_STREAM_END)
540{
541DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
542}
543else if (zlib_result == Z_OK)
544{
545/* deflate filled output buffer, meaning the data doesn't compress.
546 */
547DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
548
549}
550else if (zlib_result != Z_STREAM_ERROR)
551{
552printf("ZLIB Deflate Error: %s\n", zstream.msg);
553getc();
554}
555
556if (zstream_inited) deflateEnd(&zstream);
557
558free(executable);
559
560return true;
561
562}
563
564bool patch_bcm_kext(TagPtr plist, char* plistbuffer, void* start)
565{
566TagPtr personality;
567personality =XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));
568personality =XMLGetProperty(personality, (const char*)"Broadcom 802.11 PCI");
569TagPtr match_names =XMLCastArray(XMLGetProperty(personality, (const char*)"IONameMatch"));
570
571
572char* new_str = malloc(strlen("pci14e4,xxxx")+1);
573sprintf(new_str, "pci14e4,%02x", patch_bcm_deviceid);
574
575// Check to see if we *really* need to modify the plist, if not, return false
576// so that *if* this were going ot be the only modified kext, the repacking code
577// won't need to be executed.
578int count = XMLTagCount(match_names);
579while(count)
580{
581count--;
582TagPtr replace =XMLGetElement(match_names, count);// Modify the second entry
583char* orig_string = XMLCastString(replace);
584if(strcmp(orig_string, new_str) == 0) return false;
585}
586
587
588TagPtr replace =XMLGetElement(match_names, 1);// Modify the second entry
589char* orig_string = XMLCastString(replace);
590
591DBG("Attemting to replace '%s' with '%s'\n", orig_string, new_str);
592
593// TODO: verify string doesn't exist first.
594
595replace_string(orig_string, new_str, plistbuffer + XMLCastStringOffset(replace), 1024);
596
597return true;
598}
599
600bool patch_gma_kexts(TagPtr plist, char* plistbuffer, void* start)
601{
602int exeutable_offset, full_size, compressed_size;
603TagPtr personality;
604long offset;
605int zlib_result;
606z_stream zstream;
607bool zstream_inited = false;
608mkext2_file_entry* kext;
609void* compressed_data;
610
611exeutable_offset = XMLCastInteger(XMLGetProperty(plist, kMKEXTExecutableKey));
612kext = (void*)((char*)start + exeutable_offset);
613
614full_size = MKEXT2_GET_ENTRY_FULLSIZE(kext);
615compressed_size = MKEXT2_GET_ENTRY_COMPSIZE(kext);
616compressed_data = MKEXT2_GET_ENTRY_DATA(kext);
617
618personality =XMLCastDict(XMLGetProperty(plist, kPropIOKitPersonalities));
619if(XMLGetProperty(personality, (const char*)"Intel915"))
620{
621personality =XMLGetProperty(personality, (const char*)"Intel915");
622}
623else
624{
625personality =XMLGetProperty(personality, (const char*)"AppleIntelIntegratedFramebuffer");
626}
627#if DEBUG_KEXT_PATCHER
628char* pcimatch =XMLCastString(XMLGetProperty(personality, (const char*)"IOPCIPrimaryMatch"));
629#endif
630offset =XMLCastStringOffset(XMLGetProperty(personality, (const char*)"IOPCIPrimaryMatch"));
631
632replace_string("0x27A28086", "0x27AE8086", plistbuffer + offset, 1024);
633
634DBG("Located kext %s\n", bundleID);
635DBG("PCI Match offset = %d, string = %s\n", offset, pcimatch);
636char* executable = malloc(full_size);
637
638bzero(&zstream, sizeof(zstream));
639zstream.next_in = (UInt8*)compressed_data;
640zstream.avail_in = compressed_size;
641
642zstream.next_out = (UInt8*)executable;
643zstream.avail_out = full_size;
644
645zstream.zalloc = z_alloc;
646zstream.zfree = z_free;
647
648zlib_result = inflateInit(&zstream);
649if (Z_OK != zlib_result)
650{
651printf("ZLIB Inflate Error: %s\n", zstream.msg);
652getc();
653}
654else
655{
656zstream_inited = true;
657}
658
659
660zlib_result = inflate(&zstream, Z_FINISH);
661
662DBG("Inflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
663
664replace_word(0x27A28086, 0x27AE8086, executable, zstream.total_out);
665if (zstream_inited) inflateEnd(&zstream);
666
667
668zstream.next_in = (UInt8*)executable;
669//zstream.next_out = (UInt8*)((int)compressed_data<<1);
670zstream.next_out = (UInt8*)compressed_data;
671
672zstream.avail_in = full_size;
673zstream.avail_out = compressed_size;
674zstream.zalloc = Z_NULL;
675zstream.zfree = Z_NULL;
676zstream.opaque = Z_NULL;
677
678
679
680// Recompress the eecutable
681zlib_result = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,15, 8 /* memLevel */, Z_DEFAULT_STRATEGY);
682if (Z_OK != zlib_result) {
683printf("ZLIB Deflate Error: %s\n", zstream.msg);
684getc();
685}
686else
687{
688zstream_inited = true;
689}
690
691zlib_result = deflate(&zstream, Z_FINISH);
692
693if (zlib_result == Z_STREAM_END)
694{
695DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
696}
697else if (zlib_result == Z_OK)
698{
699/* deflate filled output buffer, meaning the data doesn't compress.
700 */
701DBG("Deflated result is %d, in: %d bytes, out: %d bytes, full: %d\n", zlib_result, zstream.total_in, zstream.total_out, full_size);
702
703}
704else if (zlib_result != Z_STREAM_ERROR)
705{
706printf("ZLIB Deflate Error: %s\n", zstream.msg);
707getc();
708}
709
710if (zstream_inited) deflateEnd(&zstream);
711
712free(executable);
713
714return true;
715}
716
717int chartohex(char c)
718{
719if(c <= '9' && c >= '0')
720{
721return c - '0';// c is between 0 and 9
722}
723else if(c <= 'F' && c >= 'A')
724{
725return c - 'A' + 10; // c = 10 - 15;
726}
727else if(c <= 'f' && c >= 'a')
728{
729return c - 'a' + 10; // c = 10 - 15;
730}
731return 0;
732}

Archive Download this file

Revision: 611