diff --git a/Mac/Modules/cg/CFMLateImport.c b/Mac/Modules/cg/CFMLateImport.c new file mode 100755 index 00000000000..bc2976e72f9 --- /dev/null +++ b/Mac/Modules/cg/CFMLateImport.c @@ -0,0 +1,1360 @@ +/* + File: CFMLateImport.c + + Contains: Implementation of CFM late import library. + + Written by: Quinn + + Copyright: Copyright © 1999 by Apple Computer, Inc., all rights reserved. + + You may incorporate this Apple sample source code into your program(s) without + restriction. This Apple sample source code has been provided "AS IS" and the + responsibility for its operation is yours. You are not permitted to redistribute + this Apple sample source code as "Apple sample source code" after having made + changes. If you're going to re-distribute the source, we require that you make + it clear in the source that the code was descended from Apple sample source + code, but that you've made changes. + + Change History (most recent first): + + <13> 24/9/01 Quinn Fixes to compile with C++ activated. + <12> 21/9/01 Quinn [2710489] Fix typo in the comments for FragmentLookup. + <11> 21/9/01 Quinn Changes for CWPro7 Mach-O build. + <10> 19/9/01 Quinn Corrected implementation of kPEFRelocSmBySection. Added + implementations of kPEFRelocSetPosition and kPEFRelocLgByImport + (from code contributed by Eric Grant, Ned Holbrook, and Steve + Kalkwarf), although I can't test them yet. + <9> 19/9/01 Quinn We now handle unpacked data sections, courtesy of some code from + Ned Holbrook. + <8> 19/9/01 Quinn Minor fixes for the previous checkin. Updated some comments and + killed some dead code. + <7> 19/9/01 Quinn Simplified API and implementation after a suggestion by Eric + Grant. You no longer have to CFM export a dummy function; you + can just pass in the address of your fragment's init routine. + <6> 15/2/01 Quinn Modify compile-time warnings to complain if you try to build + this module into a Mach-O binary. + <5> 5/2/01 Quinn Removed redundant assignment in CFMLateImportCore. + <4> 30/11/00 Quinn Added comment about future of data symbols in CF. + <3> 16/11/00 Quinn Allow symbol finding via a callback and use that to implement + CFBundle support. + <2> 18/10/99 Quinn Renamed CFMLateImport to CFMLateImportLibrary to allow for + possible future API expansion. + <1> 15/6/99 Quinn First checked in. +*/ + +// To Do List: +// +// o get rid of dependence on ANSI "string.h", but how? +// +// Done: +// +// Ã investigate alternative APIs, like an external lookup routine +// renamed CFMLateImport to CFMLateImportLibrary to allow for +// future expansion of the APIs for things like CFMLateImportSymbol +// Ã test with non-zero fragment offset in the file +// Ã test more with MPW fragments +// Ã test data imports + +///////////////////////////////////////////////////////////////// + +// MoreIsBetter Setup + +//#include "MoreSetup.h" +#define MoreAssert(x) (true) +#define MoreAssertQ(x) + +// Mac OS Interfaces + +#if ! MORE_FRAMEWORK_INCLUDES + #include + #include +#endif + +// Standard C Interfaces + +#include + +// MIB Prototypes + +//#include "MoreInterfaceLib.h" +#define MoreBlockZero BlockZero + +// Our Prototypes + +#include "CFMLateImport.h" + +///////////////////////////////////////////////////////////////// + +#if TARGET_RT_MAC_MACHO + #error CFMLateImport is not suitable for use in a Mach-O project. +#elif !TARGET_RT_MAC_CFM || !TARGET_CPU_PPC + #error CFMLateImport has not been qualified for 68K or CFM-68K use. +#endif + +///////////////////////////////////////////////////////////////// +#pragma mark ----- Utility Routines ----- + +static OSStatus FSReadAtOffset(SInt16 refNum, SInt32 offset, SInt32 count, void *buffer) + // A convenient wrapper around PBRead which has two advantages + // over FSRead. First, it takes count as a value parameter. + // Second, it reads from an arbitrary offset into the file, + // which avoids a bunch of SetFPos calls. + // + // I guess this should go into "MoreFiles.h", but I'm not sure + // how we're going to integrate such a concept into MIB yet. +{ + ParamBlockRec pb; + + pb.ioParam.ioRefNum = refNum; + pb.ioParam.ioBuffer = (Ptr) buffer; + pb.ioParam.ioReqCount = count; + pb.ioParam.ioPosMode = fsFromStart; + pb.ioParam.ioPosOffset = offset; + + return PBReadSync(&pb); +} + +///////////////////////////////////////////////////////////////// +#pragma mark ----- Late Import Engine ----- + +// This structure represents the core data structure of the late import +// engine. It basically holds information about the fragment we're going +// to fix up. It starts off with the first three fields, which are +// provided by the client. Then, as we procede through the operation, +// we fill out more fields. + +struct FragToFixInfo { + CFragSystem7DiskFlatLocator locator; // How to find the fragment's container. + CFragConnectionID connID; // CFM connection to the fragment. + CFragInitFunction initRoutine; // The CFM init routine for the fragment. + PEFContainerHeader containerHeader; // The CFM header, read in from the container. + PEFSectionHeader *sectionHeaders; // The CFM section headers. A pointer block containing an array of containerHeader.sectionCount elements. + PEFLoaderInfoHeader *loaderSection; // The entire CFM loader section in a pointer block. + SInt16 fileRef; // A read-only path to the CFM container. We keep this here because one that one routine needs to read from the container. + void *section0Base; // The base address of section 0, which we go through hoops to calculate. + void *section1Base; // The base address of section 1, which we go through hoops to calculate. + Boolean disposeSectionPointers; // See below. +}; +typedef struct FragToFixInfo FragToFixInfo; + +// The disposeSectionPointers Boolean is designed for future cool VM +// support. If VM is on, the entire code fragment is file mapped into +// high memory, including the data we're forced to allocate the +// sectionHeaders and loaderSection memory blocks to maintain. If +// we could find the address of the entire file mapped container, +// we could access the information directly from there and thus +// we wouldn't need to allocate (or dispose of) the memory blocks +// for sectionHeaders and loaderSection. +// +// I haven't implemented this yet because a) I'm not sure how to do +// it with documented APIs, and b) I couldn't be bothered, but +// disposeSectionPointers remains as vestigial support for the concept. + +static OSStatus ReadContainerBasics(FragToFixInfo *fragToFix) + // Reads some basic information from the container of the + // fragment to fix and stores it in various fields of + // fragToFix. This includes: + // + // o containerHeader -- The contain header itself. + // o sectionHeaders -- The array of section headers (in a newly allocated pointer block). + // o loaderSection -- The entire loader section (in a newly allocated pointer block). + // + // Also sets disposeSectionPointers to indicate whether + // the last two pointers should be disposed of. + // + // Finally, it leaves the container file open for later + // folks who want to read data from it. +{ + OSStatus err; + UInt16 sectionIndex; + Boolean found; + + MoreAssertQ(fragToFix != nil); + MoreAssertQ(fragToFix->locator.fileSpec != nil); + MoreAssertQ(fragToFix->connID != nil); + MoreAssertQ(fragToFix->loaderSection == nil); + MoreAssertQ(fragToFix->sectionHeaders == nil); + MoreAssertQ(fragToFix->fileRef == 0); + + fragToFix->disposeSectionPointers = true; + + // Open up the file, read the container head, then read in + // all the section headers, then go looking through the + // section headers for the loader section (PEF defines + // that there can be only one). + + err = FSpOpenDF(fragToFix->locator.fileSpec, fsRdPerm, &fragToFix->fileRef); + if (err == noErr) { + err = FSReadAtOffset(fragToFix->fileRef, + fragToFix->locator.offset, + sizeof(fragToFix->containerHeader), + &fragToFix->containerHeader); + if (err == noErr) { + if ( fragToFix->containerHeader.tag1 != kPEFTag1 + || fragToFix->containerHeader.tag2 != kPEFTag2 + || fragToFix->containerHeader.architecture != kCompiledCFragArch + || fragToFix->containerHeader.formatVersion != kPEFVersion) { + err = cfragFragmentFormatErr; + } + } + if (err == noErr) { + fragToFix->sectionHeaders = (PEFSectionHeader *) NewPtr(fragToFix->containerHeader.sectionCount * sizeof(PEFSectionHeader)); + err = MemError(); + } + if (err == noErr) { + err = FSReadAtOffset(fragToFix->fileRef, + fragToFix->locator.offset + sizeof(fragToFix->containerHeader), + fragToFix->containerHeader.sectionCount * sizeof(PEFSectionHeader), + fragToFix->sectionHeaders); + } + if (err == noErr) { + sectionIndex = 0; + found = false; + while ( sectionIndex < fragToFix->containerHeader.sectionCount && ! found ) { + found = (fragToFix->sectionHeaders[sectionIndex].sectionKind == kPEFLoaderSection); + if ( ! found ) { + sectionIndex += 1; + } + } + } + if (err == noErr && ! found) { + err = cfragNoSectionErr; + } + + // Now read allocate a pointer block and read the loader section into it. + + if (err == noErr) { + fragToFix->loaderSection = (PEFLoaderInfoHeader *) NewPtr(fragToFix->sectionHeaders[sectionIndex].containerLength); + err = MemError(); + } + if (err == noErr) { + err = FSReadAtOffset(fragToFix->fileRef, + fragToFix->locator.offset + fragToFix->sectionHeaders[sectionIndex].containerOffset, + fragToFix->sectionHeaders[sectionIndex].containerLength, + fragToFix->loaderSection); + } + } + + // No clean up. The client must init fragToFix to zeros and then + // clean up regardless of whether we return an error. + + return err; +} + +static UInt32 DecodeVCountValue(const UInt8 *start, UInt32 *outCount) + // Given a pointer to the start of a variable length PEF value, + // work out the value (in *outCount). Returns the number of bytes + // consumed by the value. +{ + UInt8 * bytePtr; + UInt8 byte; + UInt32 count; + + bytePtr = (UInt8 *)start; + + // Code taken from "PEFBinaryFormat.h". + count = 0; + do { + byte = *bytePtr++; + count = (count << kPEFPkDataVCountShift) | (byte & kPEFPkDataVCountMask); + } while ((byte & kPEFPkDataVCountEndMask) != 0); + + *outCount = count; + return bytePtr - start; +} + +static UInt32 DecodeInstrCountValue(const UInt8 *inOpStart, UInt32 *outCount) + // Given a pointer to the start of an opcode (inOpStart), work out the + // count argument for that opcode (*outCount). Returns the number of + // bytes consumed by the opcode and count combination. +{ + MoreAssertQ(inOpStart != nil); + MoreAssertQ(outCount != nil); + + if (PEFPkDataCount5(*inOpStart) != 0) + { + // Simple case, count encoded in opcode. + *outCount = PEFPkDataCount5(*inOpStart); + return 1; + } + else + { + // Variable-length case. + return 1 + DecodeVCountValue(inOpStart + 1, outCount); + } +} + +static OSStatus UnpackPEFDataSection(const UInt8 * const packedData, UInt32 packedSize, + UInt8 * const unpackedData, UInt32 unpackedSize) +{ + OSErr err; + UInt32 offset; + UInt8 opCode; + UInt8 * unpackCursor; + + MoreAssertQ(packedData != nil); + MoreAssertQ(unpackedData != nil); + MoreAssertQ(unpackedSize >= packedSize); + + // The following asserts assume that the client allocated the memory with NewPtr, + // which may not always be true. However, the asserts' value in preventing accidental + // memory block overruns outweighs the possible maintenance effort. + + MoreAssertQ( packedSize == GetPtrSize( (Ptr) packedData ) ); + MoreAssertQ( unpackedSize == GetPtrSize( (Ptr) unpackedData) ); + + err = noErr; + offset = 0; + unpackCursor = unpackedData; + while (offset < packedSize) { + MoreAssertQ(unpackCursor < &unpackedData[unpackedSize]); + + opCode = packedData[offset]; + + switch (PEFPkDataOpcode(opCode)) { + case kPEFPkDataZero: + { + UInt32 count; + + offset += DecodeInstrCountValue(&packedData[offset], &count); + + MoreBlockZero(unpackCursor, count); + unpackCursor += count; + } + break; + + case kPEFPkDataBlock: + { + UInt32 blockSize; + + offset += DecodeInstrCountValue(&packedData[offset], &blockSize); + + BlockMoveData(&packedData[offset], unpackCursor, blockSize); + unpackCursor += blockSize; + offset += blockSize; + } + break; + + case kPEFPkDataRepeat: + { + UInt32 blockSize; + UInt32 repeatCount; + UInt32 loopCounter; + + offset += DecodeInstrCountValue(&packedData[offset], &blockSize); + offset += DecodeVCountValue(&packedData[offset], &repeatCount); + repeatCount += 1; // stored value is (repeatCount - 1) + + for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) { + BlockMoveData(&packedData[offset], unpackCursor, blockSize); + unpackCursor += blockSize; + } + offset += blockSize; + } + break; + + case kPEFPkDataRepeatBlock: + { + UInt32 commonSize; + UInt32 customSize; + UInt32 repeatCount; + const UInt8 *commonData; + const UInt8 *customData; + UInt32 loopCounter; + + offset += DecodeInstrCountValue(&packedData[offset], &commonSize); + offset += DecodeVCountValue(&packedData[offset], &customSize); + offset += DecodeVCountValue(&packedData[offset], &repeatCount); + + commonData = &packedData[offset]; + customData = &packedData[offset + commonSize]; + + for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) { + BlockMoveData(commonData, unpackCursor, commonSize); + unpackCursor += commonSize; + BlockMoveData(customData, unpackCursor, customSize); + unpackCursor += customSize; + customData += customSize; + } + BlockMoveData(commonData, unpackCursor, commonSize); + unpackCursor += commonSize; + offset += (repeatCount * (commonSize + customSize)) + commonSize; + } + break; + + case kPEFPkDataRepeatZero: + { + UInt32 commonSize; + UInt32 customSize; + UInt32 repeatCount; + const UInt8 *customData; + UInt32 loopCounter; + + offset += DecodeInstrCountValue(&packedData[offset], &commonSize); + offset += DecodeVCountValue(&packedData[offset], &customSize); + offset += DecodeVCountValue(&packedData[offset], &repeatCount); + + customData = &packedData[offset]; + + for (loopCounter = 0; loopCounter < repeatCount; loopCounter++) { + MoreBlockZero(unpackCursor, commonSize); + unpackCursor += commonSize; + BlockMoveData(customData, unpackCursor, customSize); + unpackCursor += customSize; + customData += customSize; + } + MoreBlockZero(unpackCursor, commonSize); + unpackCursor += commonSize; + offset += repeatCount * customSize; + } + break; + + default: + #if MORE_DEBUG + DebugStr("\pUnpackPEFDataSection: Unexpected data opcode"); + #endif + err = cfragFragmentCorruptErr; + goto leaveNow; + break; + } + } + +leaveNow: + return err; +} + +/* SetupSectionBaseAddresses Rationale + ----------------------------------- + + OK, here's where things get weird. In order to run the relocation + engine, I need to be able to find the base address of an instantiated + section of the fragment we're fixing up given only its section number. + This isn't hard for CFM to do because it's the one that instantiated the + sections in the first place. It's surprisingly difficult to do if + you're not CFM. [And you don't have access to the private CFM APis for + doing it.] + + [Alan Lillich is going to kill me when he reads this! I should point out + that TVector's don't have to contain two words, they can be longer, + and that the second word isn't necessarily a TOC pointer, it's + just that the calling conventions require that it be put in the + TOC register when the code is called. + + Furthermore, the code section isn't always section 0, and the data + section isn't always section 1, and there can be zero to many sections + of each type. + + But these niceties are besides the point: I'm doing something tricky + because I don't have a nice API for getting section base addresses. + If I had a nice API for doing that, none of this code would exist. + ] + + The technique is very sneaky (thanks to Eric Grant). The fragment to + fix necessarily has a CFM init routine (because it needs that routine + in order to capture the fragment location and connection ID). Thus the + fragment to fix must have a TVector in its data section. TVectors are + interesting because they're made up of two words. The first is a pointer + to the code that implements the routine; the second is a pointer to the TOC + for the fragment that's exporting the TVector. How TVectors are + created is interesting too. On disk, a TVector consists of two words, + the first being the offset from the start of the code section to the + routine, the second being the offset from the start of the data section + to the TOC base. When CFM prepares a TVector, it applies the following + transform: + + tvector.codePtr = tvector.codeOffset + base of code section + tvector.tocPtr = tvector.tocOffset + base of data section + + Now, you can reverse these questions to make them: + + base of code section = tvector.codePtr - tvector.codeOffset + base of data section = tvector.dataPtr - tvector.dataOffset + + So if you can find the relocated contents of the TVector and + find the original offsets that made up the TVector, you can then + calculate the base address of both the code and data sections. + + Finding the relocated contents of the TVector is easy; I simply + require the client to pass in a pointer to its init routine. + A routine pointer is a TVector pointer, so you can just cast it + and extract the pair of words. + + Finding the original offsets is a trickier. My technique is to + look up the init routine in the fragment's loader info header. This + yields the section number and offset where the init routine's unrelocated + TVector exists. Once I have that, I can just read the unrelocated TVector + out of the file and extract the offsets. +*/ + +struct TVector { + void *codePtr; + void *tocPtr; +}; +typedef struct TVector TVector; + +static OSStatus SetupSectionBaseAddresses(FragToFixInfo *fragToFix) + // This routine initialises the section0Base and section1Base + // base fields of fragToFix to the base addresses of the + // instantiated fragment represented by the other fields + // of fragToFix. The process works in three states: + // + // 1. Find the contents of the relocated TVector of the + // fragment's initialisation routine, provided to us by + // the caller. + // + // 2. Find the contents of the non-relocated TVector by + // looking it up in the PEF loader info header and then + // using that to read the TVector contents from disk. + // This yields the offsets from the section bases for + // the init routine. + // + // 3. Subtract 2 from 3. +{ + OSStatus err; + TVector * relocatedExport; + SInt32 initSection; + UInt32 initOffset; + PEFSectionHeader * initSectionHeader; + Ptr packedDataSection; + Ptr unpackedDataSection; + TVector originalOffsets; + + packedDataSection = nil; + unpackedDataSection = nil; + + // Step 1. + + // First find the init routine's TVector, which gives us the relocated + // offsets of the init routine into the data and code sections. + + relocatedExport = (TVector *) fragToFix->initRoutine; + + // Step 2. + + // Now find the init routine's TVector's offsets in the data section on + // disk. This gives us the raw offsets from the data and code section + // of the beginning of the init routine. + + err = noErr; + initSection = fragToFix->loaderSection->initSection; + initOffset = fragToFix->loaderSection->initOffset; + if (initSection == -1) { + err = cfragFragmentUsageErr; + } + if (err == noErr) { + MoreAssertQ( initSection >= 0 ); // Negative indexes are pseudo-sections which are just not allowed! + MoreAssertQ( initSection < fragToFix->containerHeader.sectionCount ); + + initSectionHeader = &fragToFix->sectionHeaders[initSection]; + + // If the data section is packed, unpack it to a temporary buffer and then get the + // original offsets from that buffer. If the data section is unpacked, just read + // the original offsets directly off the disk. + + if ( initSectionHeader->sectionKind == kPEFPackedDataSection ) { + + // Allocate space for packed and unpacked copies of the section. + + packedDataSection = NewPtr(initSectionHeader->containerLength); + err = MemError(); + + if (err == noErr) { + unpackedDataSection = NewPtr(initSectionHeader->unpackedLength); + err = MemError(); + } + + // Read the contents of the packed section. + + if (err == noErr) { + err = FSReadAtOffset( fragToFix->fileRef, + fragToFix->locator.offset + + initSectionHeader->containerOffset, + initSectionHeader->containerLength, + packedDataSection); + } + + // Unpack the data into the unpacked section. + + if (err == noErr) { + err = UnpackPEFDataSection( (UInt8 *) packedDataSection, initSectionHeader->containerLength, + (UInt8 *) unpackedDataSection, initSectionHeader->unpackedLength); + } + + // Extract the init routine's TVector from the unpacked section. + + if (err == noErr) { + BlockMoveData(unpackedDataSection + initOffset, &originalOffsets, sizeof(TVector)); + } + + } else { + MoreAssertQ(fragToFix->sectionHeaders[initSection].sectionKind == kPEFUnpackedDataSection); + err = FSReadAtOffset(fragToFix->fileRef, + fragToFix->locator.offset + + fragToFix->sectionHeaders[initSection].containerOffset + + initOffset, + sizeof(TVector), + &originalOffsets); + } + } + + // Step 3. + + // Do the maths to subtract the unrelocated offsets from the current address + // to get the base address. + + if (err == noErr) { + fragToFix->section0Base = ((char *) relocatedExport->codePtr) - (UInt32) originalOffsets.codePtr; + fragToFix->section1Base = ((char *) relocatedExport->tocPtr) - (UInt32) originalOffsets.tocPtr; + } + + // Clean up. + + if (packedDataSection != nil) { + DisposePtr(packedDataSection); + MoreAssertQ( MemError() == noErr ); + } + if (unpackedDataSection != nil) { + DisposePtr(unpackedDataSection); + MoreAssertQ( MemError() == noErr ); + } + return err; +} + +static void *GetSectionBaseAddress(const FragToFixInfo *fragToFix, UInt16 sectionIndex) + // This routine returns the base of the instantiated section + // whose index is sectionIndex. This routine is the evil twin + // of SetupSectionBaseAddresses. It simply returns the values + // for section 0 and 1 that we derived in SetupSectionBaseAddresses. + // In a real implementation, this routine would call CFM API + // to get this information, and SetupSectionBaseAddresses would + // not exist, but CFM does not export the necessary APIs to + // third parties. +{ + void *result; + + MoreAssertQ(fragToFix != nil); + MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1); + + switch (sectionIndex) { + case 0: + result = fragToFix->section0Base; + break; + case 1: + result = fragToFix->section1Base; + break; + default: + result = nil; + break; + } + return result; +} + + +static OSStatus FindImportLibrary(PEFLoaderInfoHeader *loaderSection, const char *libraryName, PEFImportedLibrary **importLibrary) + // This routine finds the import library description (PEFImportedLibrary) + // for the import library libraryName in the PEF loader section. + // It sets *importLibrary to the address of the description. +{ + OSStatus err; + UInt32 librariesRemaining; + PEFImportedLibrary *thisImportLibrary; + Boolean found; + + MoreAssertQ(loaderSection != nil); + MoreAssertQ(libraryName != nil); + MoreAssertQ(importLibrary != nil); + + // Loop through each import library looking for a matching name. + + // Initialise thisImportLibrary to point to the byte after the + // end of the loader section's header. + + thisImportLibrary = (PEFImportedLibrary *) (loaderSection + 1); + librariesRemaining = loaderSection->importedLibraryCount; + found = false; + while ( librariesRemaining > 0 && ! found ) { + // PEF defines that import library names will have + // a null terminator, so we can just use strcmp. + found = (strcmp( libraryName, + ((char *)loaderSection) + + loaderSection->loaderStringsOffset + + thisImportLibrary->nameOffset) == 0); + // *** Remove ANSI strcmp eventually. + if ( ! found ) { + thisImportLibrary += 1; + librariesRemaining -= 1; + } + } + + if (found) { + *importLibrary = thisImportLibrary; + err = noErr; + } else { + *importLibrary = nil; + err = cfragNoLibraryErr; + } + return err; +} + +static OSStatus LookupSymbol(CFMLateImportLookupProc lookup, void *refCon, + PEFLoaderInfoHeader *loaderSection, + UInt32 symbolIndex, + UInt32 *symbolValue) + // This routine is used to look up a symbol during relocation. + // "lookup" is a client callback and refCon is its argument. + // Typically refCon is the CFM connection to the library that is + // substituting for the weak linked library. loaderSection + // is a pointer to the loader section of the fragment to fix up. + // symbolIndex is the index of the imported symbol in the loader section. + // The routine sets the word pointed to by symbolValue to the + // value of the symbol. + // + // The routine works by using symbolIndex to index into the imported + // symbol table to find the offset of the symbol's name in the string + // table. It then looks up the symbol by calling the client's "lookup" + // function and passes the resulting symbol address back in symbolValue. +{ + OSStatus err; + UInt32 *importSymbolTable; + UInt32 symbolStringOffset; + Boolean symbolIsWeak; + CFragSymbolClass symbolClass; + char *symbolStringAddress; + Str255 symbolString; + + MoreAssertQ(lookup != nil); + MoreAssertQ(loaderSection != nil); + MoreAssertQ(symbolIndex < loaderSection->totalImportedSymbolCount); + MoreAssertQ(symbolValue != nil); + + // Find the base of the imported symbol table. + + importSymbolTable = (UInt32 *)(((char *)(loaderSection + 1)) + (loaderSection->importedLibraryCount * sizeof(PEFImportedLibrary))); + + // Grab the appropriate entry out of the table and + // extract the information from that entry. + + symbolStringOffset = importSymbolTable[symbolIndex]; + symbolClass = PEFImportedSymbolClass(symbolStringOffset); + symbolIsWeak = ((symbolClass & kPEFWeakImportSymMask) != 0); + symbolClass = symbolClass & ~kPEFWeakImportSymMask; + symbolStringOffset = PEFImportedSymbolNameOffset(symbolStringOffset); + + // Find the string for the symbol in the strings table and + // extract it from the table into a Pascal string on the stack. + + symbolStringAddress = ((char *)loaderSection) + loaderSection->loaderStringsOffset + symbolStringOffset; + symbolString[0] = strlen(symbolStringAddress); // *** remove ANSI strlen + BlockMoveData(symbolStringAddress, &symbolString[1], symbolString[0]); + + // Look up the symbol in substitute library. If it fails, return + // a 0 value and check whether the error is fatal (a strong linked + // symbol) or benign (a weak linked symbol). + + err = lookup(symbolString, symbolClass, (void **) symbolValue, refCon); + if (err != noErr) { + *symbolValue = 0; + if (symbolIsWeak) { + err = noErr; + } + } + return err; +} + +// The EngineState structure encapsulates all of the persistent state +// of the CFM relocation engine virtual machine. I originally defined +// this structure so I could pass the state around between routines +// that implement various virtual opcodes, however I later worked +// out that the relocation was sufficiently simple that I could put it +// in in one routine. Still, I left the state in this structure in +// case I ever need to reverse that decision. It's also a convenient +// instructional design. + +struct EngineState { + UInt32 currentReloc; // Index of current relocation opcodes + UInt32 terminatingReloc; // Index of relocation opcodes which terminates relocation + UInt32 *sectionBase; // Start of the section + UInt32 *relocAddress; // Address within the section where the relocations are to be performed + UInt32 importIndex; // Symbol index, which is used to access an imported symbol's address + void *sectionC; // Memory address of an instantiated section within the PEF container; this variable is used by relocation opcodes that relocate section addresses + void *sectionD; // Memory address of an instantiated section within the PEF container; this variable is used by relocation opcodes that relocate section addresses +}; +typedef struct EngineState EngineState; + +// Note: +// If I ever have to support the repeat opcodes, I'll probably +// have to add a repeat counter to EngineState. + +static OSStatus InitEngineState(const FragToFixInfo *fragToFix, + UInt16 relocHeaderIndex, + EngineState *state) + // This routine initialises the engine state suitably for + // running the relocation opcodes for the section whose + // index is relocHeaderIndex. relocHeaderIndex is not a + // a section number. See the comment where it's used below + // for details. The routine basically fills out all the fields + // in the EngineState structure as described by + // "Mac OS Runtime Architectures". +{ + OSStatus err; + PEFLoaderRelocationHeader *relocHeader; + + MoreAssertQ(fragToFix != nil); + MoreAssertQ(state != nil); + + // This bit is tricky. relocHeaderIndex is an index into the relocation + // header table, starting at relocSectionCount (which is in the loader + // section header) for the first relocated section and decrementing + // down to 1 for the last relocated section. I find the relocation + // header by using relocHeaderIndex as a index backwards from the + // start of the relocation opcodes (ie relocInstrOffset). If you + // look at the diagram of the layout of the container in + // "PEFBinaryFormat.h", you'll see that the relocation opcodes + // immediately follow the relocation headers. + // + // I did this because the alternative (starting at the loader + // header and stepping past the import library table and the + // import symbol table) was a pain. + + relocHeader = (PEFLoaderRelocationHeader *) (((char *) fragToFix->loaderSection) + fragToFix->loaderSection->relocInstrOffset - relocHeaderIndex * sizeof(PEFLoaderRelocationHeader)); + + MoreAssertQ(relocHeader->reservedA == 0); // PEF spec says it must be; we check to try to catch bugs in calculation of relocHeader + + state->currentReloc = relocHeader->firstRelocOffset; + state->terminatingReloc = relocHeader->firstRelocOffset + relocHeader->relocCount; + state->sectionBase = (UInt32 *) GetSectionBaseAddress(fragToFix, relocHeader->sectionIndex); + state->relocAddress = state->sectionBase; + state->importIndex = 0; + + // From "Mac OS Runtime Architectures": + // + // The sectionC and sectionD variables actually contain the + // memory address of an instantiated section minus the + // default address for that section. The default address for a + // section is contained in the defaultAddress field of the + // section header. However, in almost all cases the default + // address should be 0, so the simplified definition suffices. + // + // In the debug version, we drop into MacsBug if this weird case + // ever executes because it's more likely we made a mistake than + // we encountered a section with a default address. + + state->sectionC = GetSectionBaseAddress(fragToFix, 0); + if (state->sectionC != nil) { + #if MORE_DEBUG + if (fragToFix->sectionHeaders[0].defaultAddress != 0) { + DebugStr("\pInitEngineState: Executing weird case."); + } + #endif + (char *) state->sectionC -= fragToFix->sectionHeaders[0].defaultAddress; + } + state->sectionD = GetSectionBaseAddress(fragToFix, 1); + if (state->sectionD != nil) { + #if MORE_DEBUG + if (fragToFix->sectionHeaders[1].defaultAddress != 0) { + DebugStr("\pInitEngineState: Executing weird case."); + } + #endif + (char *) state->sectionD -= fragToFix->sectionHeaders[1].defaultAddress; + } + + err = noErr; + if (state->relocAddress == nil) { + err = cfragFragmentUsageErr; + } + return err; +} + +// kPEFRelocBasicOpcodes is a table that maps the top 7 bits of the opcode +// to a fundamental action. It's contents are defined for me in "PEFBinaryFormat.h", +// which is really convenient. + +static UInt8 kPEFRelocBasicOpcodes[kPEFRelocBasicOpcodeRange] = { PEFMaskedBasicOpcodes }; + +static OSStatus RunRelocationEngine(const FragToFixInfo *fragToFix, + PEFImportedLibrary *importLibrary, + CFMLateImportLookupProc lookup, void *refCon) + // This is where the rubber really hits the. Given a fully + // populated fragToFix structure, the import library description + // of the weak imported library we're resolving, and a connection + // to the library we're going to substitute it, re-execute the + // relocation instructions (CFM has already executed them once) + // but only *do* instructions (ie store the change to the data section) + // that CFM skipped because the weak symbols were missing. +{ + OSStatus err; + EngineState state; + UInt16 sectionsLeftToRelocate; + UInt32 totalRelocs; + UInt16 *relocInstrTable; + UInt16 opCode; + + MoreAssertQ(fragToFix != nil); + MoreAssertQ(fragToFix->containerHeader.tag1 == kPEFTag1); + MoreAssertQ(fragToFix->sectionHeaders != nil); + MoreAssertQ(fragToFix->loaderSection != nil); + MoreAssertQ(fragToFix->section0Base != nil); // Technically, having a nil for these two is not a problem, ... + MoreAssertQ(fragToFix->section1Base != nil); // but in practise it a wildly deviant case and we should know about it. + MoreAssertQ(importLibrary != nil); + MoreAssertQ(lookup != nil); + + // Before entering the loop, work out some information in advance. + + // totalRelocs is only used for debugging, to make sure our + // relocation PC (state.currentReloc) doesn't run wild. + + totalRelocs = (fragToFix->loaderSection->loaderStringsOffset - fragToFix->loaderSection->relocInstrOffset) / sizeof(UInt16); + + // relocInstrTable is the base address of the table of relocation + // instructions in the fragment to fix. + + relocInstrTable = (UInt16 *)((char *) fragToFix->loaderSection + fragToFix->loaderSection->relocInstrOffset); + + // sectionsLeftToRelocate is the loop counter for the outer loop. + + MoreAssertQ(fragToFix->loaderSection->relocSectionCount <= 0x0FFFF); + sectionsLeftToRelocate = fragToFix->loaderSection->relocSectionCount; + + // Now let's run the relocation engine. We run it once per + // section in the table. Each time around, we init the engine + // and then loop again, this time executing individual opcodes. + // The opcode loop terminates when the relocation PC + // (state.currentReloc) hits the final opcode (state.terminatingReloc). + + // Note: + // One design decision I made was to totally re-init the engine state + // for each section. The CFM spec is unclear as to whether you're supposed + // to totally re-init the engine state, or just re-init the section-specific + // state (ie currentReloc, terminatingReloc, and relocAddress). I hope this + // is correct, but it's hard to test without having a fragment with multiple + // relocated sections, which is difficult to create. + + // How do I decide which opcodes should be effective (ie make changes to + // the section being relocated) and which opcodes should just be executed + // for their side effects (ie updated state.relocAddress or state.importIndex)? + // The answer is both simple and subtle. Opcodes whose actions are dependent + // on a symbol that was in the weak linked library are effective, those that + // an independent of those symbols are not. The only opcodes that use + // symbolic values are kPEFRelocImportRun and kPEFRelocSmByImport, and + // these are only if the symbol is in the weak linked library. + // All other cases are executed for their side effects only. + // + // How do I determine if a symbol is in the weak linked library? + // Well I know the symbol's index and I know the lower bound and count + // of the symbols in the weak linked library, so I just do a simple + // bounds test, ie + // + // firstImportedSymbol <= importIndex < firstImportedSymbol + importedSymbolCount + + // From this code, it's relatively easy to see which relocation opcodes + // aren't implemented. If you ever encounter one, you'll find yourself + // in MacsBug with a message telling you which opcode was found. The + // two big groups of opcodes I skipped were the large format opcodes + // and the repeating opcodes. I skipped them because: + // + // a) I haven't got a way to generate them in a PEF container that I can + // test against. Without that, there's no way I could be assured that + // the code worked. + // + // b) I'm lazy. + + err = noErr; + while ( sectionsLeftToRelocate > 0 ) { + err = InitEngineState(fragToFix, sectionsLeftToRelocate, &state); + if (err != noErr) { + goto leaveNow; + } + + while ( state.currentReloc != state.terminatingReloc ) { + + MoreAssertQ( state.currentReloc < totalRelocs ); + + opCode = relocInstrTable[state.currentReloc]; + switch ( PEFRelocBasicOpcode(opCode) ) { + case kPEFRelocBySectDWithSkip: + { + UInt16 skipCount; + UInt16 relocCount; + + skipCount = ((opCode >> 6) & 0x00FF); + relocCount = (opCode & 0x003F); + state.relocAddress += skipCount; + state.relocAddress += relocCount; + } + break; + case kPEFRelocBySectC: + case kPEFRelocBySectD: + { + UInt16 runLength; + + runLength = (opCode & 0x01FF) + 1; + state.relocAddress += runLength; + } + break; + case kPEFRelocTVector12: + { + UInt16 runLength; + + runLength = (opCode & 0x01FF) + 1; + state.relocAddress += (runLength * 3); + } + break; + case kPEFRelocTVector8: + case kPEFRelocVTable8: + { + UInt16 runLength; + + runLength = (opCode & 0x01FF) + 1; + state.relocAddress += (runLength * 2); + } + break; + case kPEFRelocImportRun: + { + UInt32 symbolValue; + UInt16 runLength; + + runLength = (opCode & 0x01FF) + 1; + while (runLength > 0) { + if ( state.importIndex >= importLibrary->firstImportedSymbol && state.importIndex < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) { + err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, state.importIndex, &symbolValue); + if (err != noErr) { + goto leaveNow; + } + *(state.relocAddress) += symbolValue; + } + state.importIndex += 1; + state.relocAddress += 1; + runLength -= 1; + } + } + break; + case kPEFRelocSmByImport: + { + UInt32 symbolValue; + UInt32 index; + + index = (opCode & 0x01FF); + if ( index >= importLibrary->firstImportedSymbol && index < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) { + err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, index, &symbolValue); + if (err != noErr) { + goto leaveNow; + } + *(state.relocAddress) += symbolValue; + } + state.importIndex = index + 1; + state.relocAddress += 1; + } + break; + case kPEFRelocSmSetSectC: + { + UInt32 index; + + index = (opCode & 0x01FF); + state.sectionC = GetSectionBaseAddress(fragToFix, index); + MoreAssertQ(state.sectionC != nil); + } + break; + case kPEFRelocSmSetSectD: + { + UInt32 index; + + index = (opCode & 0x01FF); + state.sectionD = GetSectionBaseAddress(fragToFix, index); + MoreAssertQ(state.sectionD != nil); + } + break; + case kPEFRelocSmBySection: + state.relocAddress += 1; + break; + case kPEFRelocIncrPosition: + { + UInt16 offset; + + offset = (opCode & 0x0FFF) + 1; + ((char *) state.relocAddress) += offset; + } + break; + case kPEFRelocSmRepeat: + #if MORE_DEBUG + DebugStr("\pRunRelocationEngine: kPEFRelocSmRepeat not yet implemented"); + #endif + err = unimpErr; + goto leaveNow; + break; + case kPEFRelocSetPosition: + { + UInt32 offset; + + // Lot's of folks have tried various interpretations of the description of + // this opCode in "Mac OS Runtime Architectures" (which states "This instruction + // sets relocAddress to the address of the section offset offset." *smile*). + // I eventually dug into the CFM source code to find my interpretation, which + // I believe is correct. The key point is tht the offset is relative to + // the start of the section for which these relocations are being performed. + + // Skip to next reloc word, which is the second chunk of the offset. + + state.currentReloc += 1; + + // Extract offset based on the most significant 10 bits in opCode and + // the next significant 16 bits in the next reloc word. + + offset = PEFRelocSetPosFullOffset(opCode, relocInstrTable[state.currentReloc]); + + state.relocAddress = (UInt32 *) ( ((char *) state.sectionBase) + offset); + } + break; + case kPEFRelocLgByImport: + { + UInt32 symbolValue; + UInt32 index; + + // Get the 26 bit symbol index from the current and next reloc words. + + state.currentReloc += 1; + index = PEFRelocLgByImportFullIndex(opCode, relocInstrTable[state.currentReloc]); + + if ( index >= importLibrary->firstImportedSymbol && index < (importLibrary->firstImportedSymbol + importLibrary->importedSymbolCount) ) { + err = LookupSymbol(lookup, refCon, fragToFix->loaderSection, index, &symbolValue); + if (err != noErr) { + goto leaveNow; + } + *(state.relocAddress) += symbolValue; + } + state.importIndex = index + 1; + state.relocAddress += 1; + } + break; + case kPEFRelocLgRepeat: + #if MORE_DEBUG + DebugStr("\pRunRelocationEngine: kPEFRelocLgRepeat not yet implemented"); + #endif + err = unimpErr; + goto leaveNow; + break; + case kPEFRelocLgSetOrBySection: + #if MORE_DEBUG + DebugStr("\pRunRelocationEngine: kPEFRelocLgSetOrBySection not yet implemented"); + #endif + err = unimpErr; + goto leaveNow; + break; + case kPEFRelocUndefinedOpcode: + err = cfragFragmentCorruptErr; + goto leaveNow; + break; + default: + MoreAssertQ(false); + err = cfragFragmentCorruptErr; + goto leaveNow; + break; + } + state.currentReloc += 1; + } + + sectionsLeftToRelocate -= 1; + } + +leaveNow: + return err; +} + +extern pascal OSStatus CFMLateImportCore(const CFragSystem7DiskFlatLocator *fragToFixLocator, + CFragConnectionID fragToFixConnID, + CFragInitFunction fragToFixInitRoutine, + ConstStr255Param weakLinkedLibraryName, + CFMLateImportLookupProc lookup, + void *refCon) + // See comments in interface part. +{ + OSStatus err; + OSStatus junk; + FragToFixInfo fragToFix; + PEFImportedLibrary *importLibrary; + char weakLinkedLibraryNameCString[256]; + + MoreAssertQ(fragToFixLocator != nil); + MoreAssertQ(fragToFixConnID != nil); + MoreAssertQ(fragToFixInitRoutine != nil); + MoreAssertQ(weakLinkedLibraryName != nil); + MoreAssertQ(lookup != nil); + + // Fill out the bits of fragToFix which are passed in + // by the client. + + MoreBlockZero(&fragToFix, sizeof(fragToFix)); + fragToFix.locator = *fragToFixLocator; + fragToFix.connID = fragToFixConnID; + fragToFix.initRoutine = fragToFixInitRoutine; + + // Make a C string from weakLinkedLibraryName. + + BlockMoveData(weakLinkedLibraryName + 1, weakLinkedLibraryNameCString, weakLinkedLibraryName[0]); + weakLinkedLibraryNameCString[weakLinkedLibraryName[0]] = 0; + + // Get the basic information from the fragment. + // Fills out the containerHeader, sectionHeaders, loaderSection and fileRef fields + // of fragToFix. + + err = ReadContainerBasics(&fragToFix); + + // Set up the base address fields in fragToFix (ie section0Base and section1Base) + // by looking up our init routine (fragToFix.initRoutine) and subtracting + // away the section offsets (which we get from the disk copy of the section) + // to derive the bases of the sections themselves. + + if (err == noErr) { + err = SetupSectionBaseAddresses(&fragToFix); + } + + // Look inside the loader section for the import library description + // of weakLinkedLibraryName. We need this to know the range of symbol + // indexes we're going to fix up. + + if (err == noErr) { + err = FindImportLibrary(fragToFix.loaderSection, weakLinkedLibraryNameCString, &importLibrary); + } + + // Do a quick check to ensure that the library was actually imported weak. + // If it wasn't, it doesn't make much sense to resolve its weak imports + // later on. Resolving them again is likely to be bad. + + if (err == noErr) { + if ((importLibrary->options & kPEFWeakImportLibMask) == 0) { + err = cfragFragmentUsageErr; + } + } + + // Now run the main relocation engine. + + if (err == noErr) { + err = RunRelocationEngine(&fragToFix, importLibrary, lookup, refCon); + } + + // Clean up. + + if (fragToFix.disposeSectionPointers) { + if (fragToFix.fileRef != 0) { + junk = FSClose(fragToFix.fileRef); + MoreAssertQ(junk == noErr); + } + if (fragToFix.loaderSection != nil) { + DisposePtr( (Ptr) fragToFix.loaderSection); + MoreAssertQ(MemError() == noErr); + } + if (fragToFix.sectionHeaders != nil) { + DisposePtr( (Ptr) fragToFix.sectionHeaders); + MoreAssertQ(MemError() == noErr); + } + } + return err; +} + +static pascal OSStatus FragmentLookup(ConstStr255Param symName, CFragSymbolClass symClass, + void **symAddr, void *refCon) + // This is the CFMLateImportLookupProc callback used when + // late importing from a CFM shared library. +{ + OSStatus err; + CFragConnectionID connIDToImport; + CFragSymbolClass foundSymClass; + + MoreAssertQ(symName != nil); + MoreAssertQ(symAddr != nil); + MoreAssertQ(refCon != nil); + + connIDToImport = (CFragConnectionID) refCon; + + // Shame there's no way to validate that connIDToImport is valid. + + err = FindSymbol(connIDToImport, symName, (Ptr *) symAddr, &foundSymClass); + if (err == noErr) { + // If the symbol isn't of the right class, we act like we didn't + // find it, but also assert in the debug build because weird things + // are afoot. + if (foundSymClass != symClass) { + MoreAssertQ(false); + *symAddr = nil; + err = cfragNoSymbolErr; + } + } + return err; +} + +extern pascal OSStatus CFMLateImportLibrary(const CFragSystem7DiskFlatLocator *fragToFixLocator, + CFragConnectionID fragToFixConnID, + CFragInitFunction fragToFixInitRoutine, + ConstStr255Param weakLinkedLibraryName, + CFragConnectionID connIDToImport) + // See comments in interface part. +{ + MoreAssertQ(connIDToImport != nil); + return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine, + weakLinkedLibraryName, FragmentLookup, connIDToImport); +} + +static pascal OSStatus BundleLookup(ConstStr255Param symName, CFragSymbolClass symClass, + void **symAddr, void *refCon) + // This is the CFMLateImportLookupProc callback used when + // late importing from a CFBundle. +{ + OSStatus err; + CFBundleRef bundleToImport; + CFStringRef symNameStr; + + MoreAssertQ(symName != nil); + MoreAssertQ(symAddr != nil); + MoreAssertQ(refCon != nil); + + symNameStr = nil; + + bundleToImport = (CFBundleRef) refCon; + + // Shame there's no way to validate that bundleToImport is really a bundle. + + // We can only find function pointers because CFBundleGetFunctionPointerForName + // only works for function pointers. So if the client is asking for something + // other than a function pointer (ie TVector symbol) then we don't even true. + // Also assert in the debug build because this shows a certain lack of + // understanding on the part of the client. + // + // CF is being revise to support accessing data symbols using a new API + // (currently this is available to Apple internal developers as + // CFBundleGetDataPointerForName). When the new API is available in a + // public header file I should revise this code to lift this restriction. + + err = noErr; + if (symClass != kTVectorCFragSymbol) { + MoreAssertQ(false); + err = cfragNoSymbolErr; + } + if (err == noErr) { + symNameStr = CFStringCreateWithPascalString(kCFAllocatorSystemDefault, + symName, kCFStringEncodingMacRoman); + if (symNameStr == nil) { + err = coreFoundationUnknownErr; + } + } + if (err == noErr) { + *symAddr = CFBundleGetFunctionPointerForName(bundleToImport, symNameStr); + if (*symAddr == nil) { + err = cfragNoSymbolErr; + } + } + if (symNameStr != nil) { + CFRelease(symNameStr); + } + return err; +} + +extern pascal OSStatus CFMLateImportBundle(const CFragSystem7DiskFlatLocator *fragToFixLocator, + CFragConnectionID fragToFixConnID, + CFragInitFunction fragToFixInitRoutine, + ConstStr255Param weakLinkedLibraryName, + CFBundleRef bundleToImport) + // See comments in interface part. +{ + MoreAssertQ(bundleToImport != nil); + return CFMLateImportCore(fragToFixLocator, fragToFixConnID, fragToFixInitRoutine, + weakLinkedLibraryName, BundleLookup, bundleToImport); +} diff --git a/Mac/Modules/cg/CFMLateImport.h b/Mac/Modules/cg/CFMLateImport.h new file mode 100755 index 00000000000..f3a89bcf58a --- /dev/null +++ b/Mac/Modules/cg/CFMLateImport.h @@ -0,0 +1,272 @@ +/* + File: CFMLateImport.h + + Contains: Interface to CFM late import library. + + Written by: Quinn + + Copyright: Copyright © 1999 by Apple Computer, Inc., all rights reserved. + + You may incorporate this Apple sample source code into your program(s) without + restriction. This Apple sample source code has been provided "AS IS" and the + responsibility for its operation is yours. You are not permitted to redistribute + this Apple sample source code as "Apple sample source code" after having made + changes. If you're going to re-distribute the source, we require that you make + it clear in the source that the code was descended from Apple sample source + code, but that you've made changes. + + Change History (most recent first): + + <6> 21/9/01 Quinn Changes for CWPro7 Mach-O build. + <5> 19/9/01 Quinn Change comments to reflect the fact that an unpacked data + section is no longer required. + <4> 19/9/01 Quinn Simplified API and implementation after a suggestion by Eric + Grant. You no longer have to CFM export a dummy function; you + can just pass in the address of your fragment's init routine. + <3> 16/11/00 Quinn Allow symbol finding via a callback and use that to implement + CFBundle support. + <2> 18/10/99 Quinn Renamed CFMLateImport to CFMLateImportLibrary to allow for + possible future API expansion. + <1> 15/6/99 Quinn First checked in. +*/ + +#pragma once + +///////////////////////////////////////////////////////////////// + +// MoreIsBetter Setup + +//#include "MoreSetup.h" + +// Mac OS Interfaces + +#if ! MORE_FRAMEWORK_INCLUDES + #include + #include + #include + #include +#endif + +///////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif + +/* FAQ + --- + + Q: What does this library do? + A: It allows you to resolve a weak linked library at runtime, + by supply a CFM connection to the library that should substitute + for the weak linked one. + + Q: Does the substituted library have to have the same name as the + weak linked library. + A: No. + + Q: What's this useful for? + A: The most obvious example of where this is useful is when + you rely on shared libraries that the user might delete + or move. To can find the shared library (possibly even + using CatSearch), call GetDiskFragment to open a connection + to it, late import it using this library, and then the + rest of your code can continue to use the shared library + as if nothing had happened. No more defining thousands + of stub routines which call through routine pointers. + + There are, however, numerous less obvious uses. You can + use this code to make a 'self repairing' application. If + the user removes your shared library from the Extensions + folder, the startup code for your application can offer + tor re-install it. If the user agrees, you can then + re-install your shared library, late import it, and then + continue running your application if nothing happened. + + You can even use this code to free yourself from the + Extensions folder entirely. Say you have a suite of + applications that currently installs a dozen shared + libraries in the Extensions folder. You can move those + libraries to another folder entirely and each application's + startup code can track down the library (using an alias + in the Preferences file) and late import it. + + An even cooler use is to provide easy abstraction layers. + Say you have a network code for both the MacTCP + API and the Open Transport API. Typically, you would be + force to do this by having an abstraction layer where every + routine contains a switch between MacTCP and OT. Your + OpenSocket routine might look like: + + static int OpenSocket(void) + { + if (gOTAvailable) { + return OpenSocketOT(); + } else { + return OpenSocketMacTCP(); + } + } + + With this code, you can avoid that entirely. Simply + weak link to a shared library that you know is never + going to be implemented ("crea;MySocketsDummy") and then, + at runtime, decide whether the system has MacTCP or OT + and late import the relevant real implementation + ("crea;MySocketsMacTCP" or "crea;MySocketsOT"). + One benefit of this approach is that only the MacTCP or + the OT code is resident in memory on any given system. +*/ + +typedef pascal OSStatus (*CFMLateImportLookupProc)(ConstStr255Param symName, CFragSymbolClass symClass, + void **symAddr, void *refCon); + // CFMLateImportLookupProc defines a callback for CFMLateImportCore. + // The routine is expected to look up the address of the symbol named + // symName and return it in *symAddr. The symbol should be of class + // symClass, although the callback decides whether a class mismatch is + // an error. refCon is an application defined value that was originally + // passed in to CFMLateImportCore. + // + // If this routine returns an error, a symbol address of 0 is assumed. + // If the symbol is marked as a weak import, the CFMLateImportCore will + // continue, otherwise the CFMLateImportCore routine will fail with the + // error. + +extern pascal OSStatus CFMLateImportCore(const CFragSystem7DiskFlatLocator *fragToFixLocator, + CFragConnectionID fragToFixConnID, + CFragInitFunction fragToFixInitRoutine, + ConstStr255Param weakLinkedLibraryName, + CFMLateImportLookupProc lookup, + void *refCon); + // This routine will link you, at runtime, to some library + // that you were weak linked to and wasn't present when your + // fragment was prepared. As well as the obvious functionality + // of being able to resolve weak links after prepare time, + // this functionality can be put to a number of less obvious uses, + // some of which are discussed at the top of this header file. + // + // To call this routine, you need a number of pieces of information: + // + // 1. fragToFixLocator, fragToFixConnID: The location of your own + // code fragment on disk and the CFM connection ID to your own + // code fragment. Typically you get this information from your + // fragment's CFM init routine. You must ensure that + // fragToFixLocator->fileSpec points to an FSSpec of the + // file which holds your code fragment. + // + // IMPORTANT: + // The fact that you pass in a CFragSystem7DiskFlatLocator as the + // fragToFixLocator implies that the fragment to be fixed up must + // be in the data fork of a file. The code could be modified + // to remove this requirement, but on disk code fragments are the most + // common case. + // + // IMPORTANT: + // The fragment to fix may have a packed data section. Packing the + // data section will reduce the size of your fragment on disk, but it + // will significantly increase the memory needed by this routine + // (it increases memory usage by the sum of the sizes of the packed + // and unpacked data section). See below for instructions on how to + // create an unpacked data section. + // + // 2. fragToFixInitRoutine: A pointer to your own code fragment's + // fragment initialiser routine. You necessarily have one of these + // because you need it to get values for the fragToFixLocator and + // fragToFixConnID parameters. Just pass its address in as a parameter + // as well. + // + // 3. weakLinkedLibraryName: The name of the weak linked library which + // failed to link. You must have weak linked to this library. + // It is oxymoric for you to pass a strong linked library here, + // because your code would not have prepared if a strong linked + // library failed to prepare, and so you couldn't supply a valid + /// fragToFix. + // + // 4. lookup, refCon: A pointer to a callback function that the + // routine calls to look up the address of a symbol, and a refCon + // for that callback routine. + // + // Note: + // The fragToFixLocator and fragToFixInitRoutine parameters + // are artifacts of the way in which this functionality is implemented. + // In an ideal world, where CFM exported decent introspection APIs + // to third party developers, these parameters would not be necessary. + // If you're using this code inside Apple, you probably should investigate + // using the CFM private APIs for getting at the information these + // parameters are needed for. See the comments inside the implementation + // for more details. + // + // Note: + // The extra memory taken when you use a packed data section is also an + // artifact of my workaround for the lack of CFM introspection APIs. In + // my opinion it's better to use an unpacked data section and consume more + // space on disk while saving memory. In CodeWarrior you can switch to an + // unpacked data section by checking the "Expand Uninitialized Data" + // checkbox in the "PPC PEF" settings panel. In MPW, specified the + // "-packdata off" option to PPCLink. + // + // When the routine returns, any symbols that you imported from the + // library named weakLinkedLibraryName will be resolved to the address + // of the symbol provided by the "lookup" callback routine. + // + // It is possible for an unresolved import to remain unresolved after + // this routine returns. If the symbol import is marked as weak (as + // opposed to the library, which *must* be marked as weak) and the symbol + // is not found by the "lookup" callback, the routine will simple skip + // that symbol. If the symbol isn't marked as weak, the routine will fail + // in that case. + // + // Most of the possible error results are co-opted CFM errors. These + // include: + // + // cfragFragmentFormatErr -- The fragment to fix is is an unknown format. + // cfragNoSectionErr -- Could not find the loader section in the fragment to fix. + // cfragNoLibraryErr -- The fragment to fix is not weak linked to weakLinkedLibraryName. + // cfragFragmentUsageErr -- The fragment to fix doesn't have a data section. + // -- The fragment to fix is strong linked to weakLinkedLibraryName. + // -- The fragment doesn't have an init routine. + // cfragFragmentCorruptErr -- Encountered an undefined relocation opcode. + // unimpErr -- Encountered an unimplement relocation opcode. The + // relocation engine only implements a subset of the CFM + // relocation opcodes, the subset most commonly used by + // MPW and CodeWarrior PEF containers. If you encounter + // this error, you'll probably have to add the weird + // relocation opcode to the engine, which shouldn't be + // be too hard. + // memFullErr -- It's likely that this error is triggered by the memory + // needed to unpack your data section. Either make your + // data section smaller, or unpack it (see above). + // errors returned by FindSymbol + // errors returned by Memory Manager + // + // The routine needs enough memory to hold the loader section of the fragment + // to fix in memory. It allocates that memory using NewPtr and dispsoses of + // it before it returns. You may want to change the memory allocator, which + // is very simple. + +extern pascal OSStatus CFMLateImportLibrary(const CFragSystem7DiskFlatLocator *fragToFixLocator, + CFragConnectionID fragToFixConnID, + CFragInitFunction fragToFixInitRoutine, + ConstStr255Param weakLinkedLibraryName, + CFragConnectionID connIDToImport); + // A wrapper around CFMLateImportCore that looks up symbols by calling + // FindSymbol on a connection to a CFM library (connIDToImport). + // You can get this connection ID through any standard CFM API, for example + // GetSharedLibrary, GetDiskFragment, or GetMemFragment. + // + // IMPORTANT: + // The fragment name for connIDToImport *does not* have to match + // weakLinkedLibraryName. This is part of the power of this library. + +extern pascal OSStatus CFMLateImportBundle(const CFragSystem7DiskFlatLocator *fragToFixLocator, + CFragConnectionID fragToFixConnID, + CFragInitFunction fragToFixInitRoutine, + ConstStr255Param weakLinkedLibraryName, + CFBundleRef bundleToImport); + // A wrapper around CFMLateImportCore that looks up symbols by calling + // CFBundleGetFunctionPointerForName on a reference to a Core Foundation + // bundle (bundleToImport). You can get this reference through any + // Core Foundation bundle API, for example CFBundleCreate. + +#ifdef __cplusplus +} +#endif diff --git a/Mac/Modules/cg/CGStubLib b/Mac/Modules/cg/CGStubLib new file mode 100755 index 00000000000..74de90927ee --- /dev/null +++ b/Mac/Modules/cg/CGStubLib @@ -0,0 +1 @@ +(This file must be converted with BinHex 4.0) :!!"cG(9L69"6)!#3"!L3!!!!!BUjr%T[H5&`C@CQF(G`B`!!!!'i-rHh!*!0!3# 3"[q3"!#3$JJm!!!!8!3"!*!1rj!%!*!%rj!%!*!%rj!%!*!A1!!!"2!!!!!$!!! !1N0(3fpZG'9iG&0SEhG8CAKd3A43EfPZG%0(3fpZG'9iG&0SEhG8CAKd3dG$Efj dCAKd8f9XC@0d4QpZG%0(3fpZG'9iG&0PG&4PH(4%FQ&hD@jR6@pNC80(3fpZG'9 iG%4bBAG3BA4S3dG$EfjdCAKd8f9d6'PZC8T[D@j$4d0[ER4PH(46CA4-D@jP3f& `3dG$EfjdCAKd4f9d9'9iG&"[FfPdD@pZ3dG$EfjdCAKd4f9d8'&dD%0eFR*PER4 3EfPZG%0(3fpZG'9iG&0PG&0SEh9XC%&ZG'PKE'PKFd0(3fpZG'9iG&0jEQ0SFQp ZDATP3dG$EfjdCAKd4QaeFfK$4d0[ER4PH(4&EQ43B@GP3dG$EfjdCAKd8f9d4Qp ZG&0THQ9$4d0[ER4PH(4(CA48CAKd6@&dFQPi3dG$EfjdCAKd8f9d9'9iG%eKG(* TH%0(3fpZG'9iG&0PG&4PH(43Eh0TG'P[EN0(3fpZG'9iG&0PG%0SBA*KBh4PFP0 `B@0TEQG$4d0[ER4PH(46CA4$69P,8h4bEfYP3fpXEh*$4d0[ER4PH(46CA4$69P ,4QPXE%0[E'pb3dG$EfjdCAKd8f9d8NG#8h4bEfYP3fpXEh*$4d0[ER4PH(46CA4 54d*'D@aX3fpXEh*$4d0[ER4PH(46CA4(FQ&j8h4bEfYP3fpXEh*$4d0[ER4PH(4 6CA4(FQ&j4QPXE%0[E'pb3dG$EfjdCAKd3faTF&4[8Q9MG%0(3fpZG'9iG%923fa TF%0(3fpZG'9iG%0XDA"$4d0[ER4PH(4$E'9KFP*PBh4$4d0[ER4PH(46G(*[Df9 5C@0d9fPdD>C(4S3dG$EfjdCAKd8h4bEfYP8Q9MG%0(3fpZG'9iG%CTE'a5C@0 d3dG$EfjdCAKd8h4bEfYP8'&dD%0(3fpZG'9iG%924QPXE&"KG'K$4d0[ER4PH(4 'D@aX8'&dD%0(3fpZG'9iG%GPG&"KG'K#Eh9ZC'PZCd*[H%0(3fpZG'9iG%Pc8'& dD%9YF(4j3dG$EfjdCAKd3@4N3A*M9'p3EfPZG%0(3fpZG'9iG%&NC%&bBd0(3fp ZG'9iG%&NC&*PBh4$4d0[ER4PH(4$E'pcC9"KG'K$4d0[ER4PH(4"C'44G@&N3h9 bGQ98Ee"[D@jd3dG$EfjdCAKd3@4N3h9bGQ98Ee"[D@jd3dG$EfjdCAKd3@4N6'P ZC94[8'pTER4$4d0[ER4PH(40EhCP9'p3EfPZG%0(3fpZG'9iG%*PCfPZ8'&dD%0 (3fpZG'9iG&0PG%&XF'KK3dG$EfjdCAKd8f9d4QaKG'jPFh0$4d0[ER4PH(46CA4 0DA4PFNaTE@Pd3dG$EfjdCAKd8f9d6'PZC9GTC(4S3dG$EfjdCAKd4f9d3e403dG $EfjdCAKd3fpZBf&d3e403dG$EfjdCAKd8QpdBA4P3e403dG$EfjdCAKd9(*KER0 XBA4P3e403dG$EfjdCAKd8f0KE'9$9%e$4d0[ER4PH(45CA0dEh*P4e0dBA4P3dG $EfjdCAKd8f&fC8G6G'&dC80(3fpZG'9iG&*PE'9KFf9$FQ9KG'9$4d0[ER4PH(4 'Eh*3Eh*d!*!%)!!!!#J!#!!X!")!&!!G!"`!)J!F!#N!(!!`!!`!0`!BrD3!()G E!"$KGJ!2F0)!%S6f!"X(8J!@+$m!%Er*!"3)b!!B18%!%TFP!"4133!6*YS!&QJ q!"`5j3!6+b8!%FZX!!ijfJ!E40N!%FBC!!pc5`!83A3!%1#[!"BVd!!4bhd!%ab 3!!!83a!!&Nmd!"S9CJ!B@h8!'pSB!"4$r!!6,PJ!&IIe!"QcA`!6,A)!%S40!"@ 4"!!C[em!(!eJ!"+&B!!B'J8!$h&S!"XE+!!4[r-!%r"c!"BZe`!6,@J!'&Y`!"+ (m!!0R!B!('d8!"Gd9!!E00d!%142!"3ae3!4bj`!&UJa!J#3"rrq!J!"D!#3"2r q!J!$+J#3"2rq!J!$'`#3"2rq!J!#63#3"2rq!J!#eJ#3"2rq!J!"1J#3"2rq!J! #a3#3"2rq!J!#m3#3"2rq!J!"dJ#3"2rq!J!%,J#3"2rq!J!!D!#3"2rq!J!!I!# 3"2rq!J!"*!#3"2rq!J!!T`#3"2rq!J!%I!#3"2rq!J!%93#3"2rq!J!!mJ#3"2r q!J!"kJ#3"2rq!J!!9`#3"2rq!J!#-3#3"2rq!J!!hJ#3"2rq!J!"!*!&rri#!!- &!*!%rri#!!!B!*!%rri#!!!T!*!%rri#!!21!*!%rri#!!4Q!*!%rri#!!'i!*! %rri#!!#2!*!%rri#!!!m!*!%rri#!!%3!*!%rri#!!+b!*!%rri#!!4!!*!%rri #!!'I!*!%rri#!!*l!*!%rri#!!3F!*!%rri#!!2i!*!%rri#!!)&!*!%rri#!!* I!*!%rri#!!-k!*!%rri#!!0S!*!%rri#!!30!*!%rri#!!$$!*!%rri#!!+1!*! %rri#!!)H!*!%rri#!!2L!*!%rri#!!+I!*!%rri#!!&3!*!%rri#!!1V!*!%rri #!!*!!*!%rri#!!0-!*!%rri#!!1!!*!%rri#!!'%!*!%rri#!!52!*!%rri#!!1 A!*!%rri#!!1p!*!%rri#!!5I!*!%rri!N!3E2!!!!3!!!!&B!!!!@!!!!$)!N20 8!*!,!3#3%`&`Gh"M!*!5!`%!N"%d#80(8h4eBNaTBJ!!!3!!!!&B!!!!@!!!!$* 66e*8"*B!J!!F!$)!!'0QFQF!!!!+!!$rr`#3#2Ib: \ No newline at end of file diff --git a/Mac/Modules/cg/CGStubLib.exp b/Mac/Modules/cg/CGStubLib.exp new file mode 100755 index 00000000000..4b034b58119 --- /dev/null +++ b/Mac/Modules/cg/CGStubLib.exp @@ -0,0 +1,58 @@ +CGContextShowTextAtPoint +CGContextShowText +CGContextSelectFont +CGContextSetTextDrawingMode +CGContextDrawPath +CGContextSetLineJoin +CGContextSetLineCap +CGContextGetTextPosition +CGContextGetPathCurrentPoint +CGContextSetShouldAntialias +CGContextSynchronize +CGContextFlush +CGContextEndPage +CGContextSetFontSize +CGContextGetTextMatrix +CGContextSetTextMatrix +CGContextSetTextPosition +CGContextSetCharacterSpacing +CGContextSetCMYKStrokeColor +CGContextSetCMYKFillColor +CGContextSetRGBStrokeColor +CGContextSetRGBFillColor +CGContextSetGrayStrokeColor +CGContextSetGrayFillColor +CGContextClipToRect +CGContextEOClip +CGContextClip +CGContextClearRect +CGContextStrokeRectWithWidth +CGContextStrokeRect +CGContextFillRect +CGContextStrokePath +CGContextEOFillPath +CGContextFillPath +CGContextGetPathBoundingBox +CGContextIsPathEmpty +CGContextAddArcToPoint +CGContextAddArc +CGContextAddRect +CGContextClosePath +CGContextAddQuadCurveToPoint +CGContextAddCurveToPoint +CGContextAddLineToPoint +CGContextMoveToPoint +CGContextBeginPath +CGContextSetAlpha +CGContextSetFlatness +CGContextSetMiterLimit +CGContextSetLineWidth +CGContextGetCTM +CGContextConcatCTM +CGContextRotateCTM +CGContextTranslateCTM +CGContextScaleCTM +CGContextRestoreGState +CGContextSaveGState +CGContextRelease +CreateCGContextForPort diff --git a/Mac/Modules/cg/CGStubLib.readme b/Mac/Modules/cg/CGStubLib.readme new file mode 100755 index 00000000000..d2c5fa8dcc9 --- /dev/null +++ b/Mac/Modules/cg/CGStubLib.readme @@ -0,0 +1,3 @@ +# CGStubLib was created by issuing this command in MPW: + +MakeStub CGStubLib.exp -o CGStubLib diff --git a/Mac/Modules/cg/_CGmodule.c b/Mac/Modules/cg/_CGmodule.c new file mode 100755 index 00000000000..6523e715cd1 --- /dev/null +++ b/Mac/Modules/cg/_CGmodule.c @@ -0,0 +1,1332 @@ + +/* =========================== Module _CG =========================== */ + +#include "Python.h" + + + +#include "macglue.h" +#include "pymactoolbox.h" + +/* Macro to test whether a weak-loaded CFM function exists */ +#define PyMac_PRECHECK(rtn) do { if ( &rtn == NULL ) {\ + PyErr_SetString(PyExc_NotImplementedError, \ + "Not available in this shared library/OS version"); \ + return NULL; \ + }} while(0) + + +#ifdef WITHOUT_FRAMEWORKS +#include +#include +#else +#include +#endif + +#if !TARGET_API_MAC_OSX + /* This code is adapted from the CallMachOFramework demo at: + http://developer.apple.com/samplecode/Sample_Code/Runtime_Architecture/CallMachOFramework.htm + It allows us to call Mach-O functions from CFM apps. */ + + #include + #include "CFMLateImport.h" + + static OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr) + // This routine finds a the named framework and creates a CFBundle + // object for it. It looks for the framework in the frameworks folder, + // as defined by the Folder Manager. Currently this is + // "/System/Library/Frameworks", but we recommend that you avoid hard coded + // paths to ensure future compatibility. + // + // You might think that you could use CFBundleGetBundleWithIdentifier but + // that only finds bundles that are already loaded into your context. + // That would work in the case of the System framework but it wouldn't + // work if you're using some other, less-obvious, framework. + { + OSStatus err; + FSRef frameworksFolderRef; + CFURLRef baseURL; + CFURLRef bundleURL; + + *bundlePtr = nil; + + baseURL = nil; + bundleURL = nil; + + // Find the frameworks folder and create a URL for it. + + err = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, true, &frameworksFolderRef); + if (err == noErr) { + baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef); + if (baseURL == nil) { + err = coreFoundationUnknownErr; + } + } + + // Append the name of the framework to the URL. + + if (err == noErr) { + bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false); + if (bundleURL == nil) { + err = coreFoundationUnknownErr; + } + } + + // Create a bundle based on that URL and load the bundle into memory. + // We never unload the bundle, which is reasonable in this case because + // the sample assumes that you'll be calling functions from this + // framework throughout the life of your application. + + if (err == noErr) { + *bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL); + if (*bundlePtr == nil) { + err = coreFoundationUnknownErr; + } + } + if (err == noErr) { + if ( ! CFBundleLoadExecutable( *bundlePtr ) ) { + err = coreFoundationUnknownErr; + } + } + + // Clean up. + + if (err != noErr && *bundlePtr != nil) { + CFRelease(*bundlePtr); + *bundlePtr = nil; + } + if (bundleURL != nil) { + CFRelease(bundleURL); + } + if (baseURL != nil) { + CFRelease(baseURL); + } + + return err; + } + + + + // The CFMLateImport approach requires that you define a fragment + // initialisation routine that latches the fragment's connection + // ID and locator. If your code already has a fragment initialiser + // you will have to integrate the following into it. + + static CFragConnectionID gFragToFixConnID; + static FSSpec gFragToFixFile; + static CFragSystem7DiskFlatLocator gFragToFixLocator; + + extern OSErr FragmentInit(const CFragInitBlock *initBlock); + extern OSErr FragmentInit(const CFragInitBlock *initBlock) + { + __initialize(initBlock); /* call the "original" initializer */ + gFragToFixConnID = (CFragConnectionID) initBlock->closureID; + gFragToFixFile = *(initBlock->fragLocator.u.onDisk.fileSpec); + gFragToFixLocator = initBlock->fragLocator.u.onDisk; + gFragToFixLocator.fileSpec = &gFragToFixFile; + + return noErr; + } + +#endif + +extern int GrafObj_Convert(PyObject *, GrafPtr *); + +/* +** Manual converters +*/ + +PyObject *CGPoint_New(CGPoint *itself) +{ + + return Py_BuildValue("(ff)", + itself->x, + itself->y); +} + +int +CGPoint_Convert(PyObject *v, CGPoint *p_itself) +{ + if( !PyArg_Parse(v, "(ff)", + &p_itself->x, + &p_itself->y) ) + return 0; + return 1; +} + +PyObject *CGRect_New(CGRect *itself) +{ + + return Py_BuildValue("(ffff)", + itself->origin.x, + itself->origin.y, + itself->size.width, + itself->size.height); +} + +int +CGRect_Convert(PyObject *v, CGRect *p_itself) +{ + if( !PyArg_Parse(v, "(ffff)", + &p_itself->origin.x, + &p_itself->origin.y, + &p_itself->size.width, + &p_itself->size.height) ) + return 0; + return 1; +} + +PyObject *CGAffineTransform_New(CGAffineTransform *itself) +{ + + return Py_BuildValue("(ffffff)", + itself->a, + itself->b, + itself->c, + itself->d, + itself->tx, + itself->ty); +} + +int +CGAffineTransform_Convert(PyObject *v, CGAffineTransform *p_itself) +{ + if( !PyArg_Parse(v, "(ffffff)", + &p_itself->a, + &p_itself->b, + &p_itself->c, + &p_itself->d, + &p_itself->tx, + &p_itself->ty) ) + return 0; + return 1; +} + +static PyObject *CG_Error; + +/* -------------------- Object type CGContextRef -------------------- */ + +PyTypeObject CGContextRef_Type; + +#define CGContextRefObj_Check(x) ((x)->ob_type == &CGContextRef_Type) + +typedef struct CGContextRefObject { + PyObject_HEAD + CGContextRef ob_itself; +} CGContextRefObject; + +PyObject *CGContextRefObj_New(CGContextRef itself) +{ + CGContextRefObject *it; + it = PyObject_NEW(CGContextRefObject, &CGContextRef_Type); + if (it == NULL) return NULL; + it->ob_itself = itself; + return (PyObject *)it; +} +int CGContextRefObj_Convert(PyObject *v, CGContextRef *p_itself) +{ + if (!CGContextRefObj_Check(v)) + { + PyErr_SetString(PyExc_TypeError, "CGContextRef required"); + return 0; + } + *p_itself = ((CGContextRefObject *)v)->ob_itself; + return 1; +} + +static void CGContextRefObj_dealloc(CGContextRefObject *self) +{ + CGContextRelease(self->ob_itself); + PyMem_DEL(self); +} + +static PyObject *CGContextRefObj_CGContextSaveGState(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextSaveGState(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextRestoreGState(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextRestoreGState(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextScaleCTM(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float sx; + float sy; + if (!PyArg_ParseTuple(_args, "ff", + &sx, + &sy)) + return NULL; + CGContextScaleCTM(_self->ob_itself, + sx, + sy); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextTranslateCTM(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float tx; + float ty; + if (!PyArg_ParseTuple(_args, "ff", + &tx, + &ty)) + return NULL; + CGContextTranslateCTM(_self->ob_itself, + tx, + ty); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextRotateCTM(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float angle; + if (!PyArg_ParseTuple(_args, "f", + &angle)) + return NULL; + CGContextRotateCTM(_self->ob_itself, + angle); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextConcatCTM(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGAffineTransform transform; + if (!PyArg_ParseTuple(_args, "O&", + CGAffineTransform_Convert, &transform)) + return NULL; + CGContextConcatCTM(_self->ob_itself, + transform); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextGetCTM(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGAffineTransform _rv; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + _rv = CGContextGetCTM(_self->ob_itself); + _res = Py_BuildValue("O&", + CGAffineTransform_New, &_rv); + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetLineWidth(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float width; + if (!PyArg_ParseTuple(_args, "f", + &width)) + return NULL; + CGContextSetLineWidth(_self->ob_itself, + width); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetLineCap(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + int cap; + if (!PyArg_ParseTuple(_args, "i", + &cap)) + return NULL; + CGContextSetLineCap(_self->ob_itself, + cap); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetLineJoin(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + int join; + if (!PyArg_ParseTuple(_args, "i", + &join)) + return NULL; + CGContextSetLineJoin(_self->ob_itself, + join); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetMiterLimit(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float limit; + if (!PyArg_ParseTuple(_args, "f", + &limit)) + return NULL; + CGContextSetMiterLimit(_self->ob_itself, + limit); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetFlatness(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float flatness; + if (!PyArg_ParseTuple(_args, "f", + &flatness)) + return NULL; + CGContextSetFlatness(_self->ob_itself, + flatness); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetAlpha(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float alpha; + if (!PyArg_ParseTuple(_args, "f", + &alpha)) + return NULL; + CGContextSetAlpha(_self->ob_itself, + alpha); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextBeginPath(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextBeginPath(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextMoveToPoint(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float x; + float y; + if (!PyArg_ParseTuple(_args, "ff", + &x, + &y)) + return NULL; + CGContextMoveToPoint(_self->ob_itself, + x, + y); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextAddLineToPoint(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float x; + float y; + if (!PyArg_ParseTuple(_args, "ff", + &x, + &y)) + return NULL; + CGContextAddLineToPoint(_self->ob_itself, + x, + y); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextAddCurveToPoint(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float cp1x; + float cp1y; + float cp2x; + float cp2y; + float x; + float y; + if (!PyArg_ParseTuple(_args, "ffffff", + &cp1x, + &cp1y, + &cp2x, + &cp2y, + &x, + &y)) + return NULL; + CGContextAddCurveToPoint(_self->ob_itself, + cp1x, + cp1y, + cp2x, + cp2y, + x, + y); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextAddQuadCurveToPoint(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float cpx; + float cpy; + float x; + float y; + if (!PyArg_ParseTuple(_args, "ffff", + &cpx, + &cpy, + &x, + &y)) + return NULL; + CGContextAddQuadCurveToPoint(_self->ob_itself, + cpx, + cpy, + x, + y); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextClosePath(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextClosePath(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextAddRect(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGRect rect; + if (!PyArg_ParseTuple(_args, "O&", + CGRect_Convert, &rect)) + return NULL; + CGContextAddRect(_self->ob_itself, + rect); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextAddArc(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float x; + float y; + float radius; + float startAngle; + float endAngle; + int clockwise; + if (!PyArg_ParseTuple(_args, "fffffi", + &x, + &y, + &radius, + &startAngle, + &endAngle, + &clockwise)) + return NULL; + CGContextAddArc(_self->ob_itself, + x, + y, + radius, + startAngle, + endAngle, + clockwise); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextAddArcToPoint(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float x1; + float y1; + float x2; + float y2; + float radius; + if (!PyArg_ParseTuple(_args, "fffff", + &x1, + &y1, + &x2, + &y2, + &radius)) + return NULL; + CGContextAddArcToPoint(_self->ob_itself, + x1, + y1, + x2, + y2, + radius); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextIsPathEmpty(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + int _rv; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + _rv = CGContextIsPathEmpty(_self->ob_itself); + _res = Py_BuildValue("i", + _rv); + return _res; +} + +static PyObject *CGContextRefObj_CGContextGetPathCurrentPoint(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGPoint _rv; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + _rv = CGContextGetPathCurrentPoint(_self->ob_itself); + _res = Py_BuildValue("O&", + CGPoint_New, &_rv); + return _res; +} + +static PyObject *CGContextRefObj_CGContextGetPathBoundingBox(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGRect _rv; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + _rv = CGContextGetPathBoundingBox(_self->ob_itself); + _res = Py_BuildValue("O&", + CGRect_New, &_rv); + return _res; +} + +static PyObject *CGContextRefObj_CGContextDrawPath(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + int mode; + if (!PyArg_ParseTuple(_args, "i", + &mode)) + return NULL; + CGContextDrawPath(_self->ob_itself, + mode); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextFillPath(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextFillPath(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextEOFillPath(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextEOFillPath(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextStrokePath(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextStrokePath(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextFillRect(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGRect rect; + if (!PyArg_ParseTuple(_args, "O&", + CGRect_Convert, &rect)) + return NULL; + CGContextFillRect(_self->ob_itself, + rect); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextStrokeRect(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGRect rect; + if (!PyArg_ParseTuple(_args, "O&", + CGRect_Convert, &rect)) + return NULL; + CGContextStrokeRect(_self->ob_itself, + rect); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextStrokeRectWithWidth(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGRect rect; + float width; + if (!PyArg_ParseTuple(_args, "O&f", + CGRect_Convert, &rect, + &width)) + return NULL; + CGContextStrokeRectWithWidth(_self->ob_itself, + rect, + width); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextClearRect(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGRect rect; + if (!PyArg_ParseTuple(_args, "O&", + CGRect_Convert, &rect)) + return NULL; + CGContextClearRect(_self->ob_itself, + rect); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextClip(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextClip(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextEOClip(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextEOClip(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextClipToRect(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGRect rect; + if (!PyArg_ParseTuple(_args, "O&", + CGRect_Convert, &rect)) + return NULL; + CGContextClipToRect(_self->ob_itself, + rect); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetGrayFillColor(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float gray; + float alpha; + if (!PyArg_ParseTuple(_args, "ff", + &gray, + &alpha)) + return NULL; + CGContextSetGrayFillColor(_self->ob_itself, + gray, + alpha); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetGrayStrokeColor(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float gray; + float alpha; + if (!PyArg_ParseTuple(_args, "ff", + &gray, + &alpha)) + return NULL; + CGContextSetGrayStrokeColor(_self->ob_itself, + gray, + alpha); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetRGBFillColor(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float r; + float g; + float b; + float alpha; + if (!PyArg_ParseTuple(_args, "ffff", + &r, + &g, + &b, + &alpha)) + return NULL; + CGContextSetRGBFillColor(_self->ob_itself, + r, + g, + b, + alpha); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetRGBStrokeColor(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float r; + float g; + float b; + float alpha; + if (!PyArg_ParseTuple(_args, "ffff", + &r, + &g, + &b, + &alpha)) + return NULL; + CGContextSetRGBStrokeColor(_self->ob_itself, + r, + g, + b, + alpha); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetCMYKFillColor(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float c; + float m; + float y; + float k; + float alpha; + if (!PyArg_ParseTuple(_args, "fffff", + &c, + &m, + &y, + &k, + &alpha)) + return NULL; + CGContextSetCMYKFillColor(_self->ob_itself, + c, + m, + y, + k, + alpha); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetCMYKStrokeColor(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float c; + float m; + float y; + float k; + float alpha; + if (!PyArg_ParseTuple(_args, "fffff", + &c, + &m, + &y, + &k, + &alpha)) + return NULL; + CGContextSetCMYKStrokeColor(_self->ob_itself, + c, + m, + y, + k, + alpha); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetCharacterSpacing(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float spacing; + if (!PyArg_ParseTuple(_args, "f", + &spacing)) + return NULL; + CGContextSetCharacterSpacing(_self->ob_itself, + spacing); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetTextPosition(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float x; + float y; + if (!PyArg_ParseTuple(_args, "ff", + &x, + &y)) + return NULL; + CGContextSetTextPosition(_self->ob_itself, + x, + y); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextGetTextPosition(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGPoint _rv; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + _rv = CGContextGetTextPosition(_self->ob_itself); + _res = Py_BuildValue("O&", + CGPoint_New, &_rv); + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetTextMatrix(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGAffineTransform transform; + if (!PyArg_ParseTuple(_args, "O&", + CGAffineTransform_Convert, &transform)) + return NULL; + CGContextSetTextMatrix(_self->ob_itself, + transform); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextGetTextMatrix(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + CGAffineTransform _rv; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + _rv = CGContextGetTextMatrix(_self->ob_itself); + _res = Py_BuildValue("O&", + CGAffineTransform_New, &_rv); + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetTextDrawingMode(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + int mode; + if (!PyArg_ParseTuple(_args, "i", + &mode)) + return NULL; + CGContextSetTextDrawingMode(_self->ob_itself, + mode); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetFontSize(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float size; + if (!PyArg_ParseTuple(_args, "f", + &size)) + return NULL; + CGContextSetFontSize(_self->ob_itself, + size); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSelectFont(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + char * name; + float size; + int textEncoding; + if (!PyArg_ParseTuple(_args, "sfi", + &name, + &size, + &textEncoding)) + return NULL; + CGContextSelectFont(_self->ob_itself, + name, + size, + textEncoding); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextShowText(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + char *cstring__in__; + long cstring__len__; + int cstring__in_len__; + if (!PyArg_ParseTuple(_args, "s#", + &cstring__in__, &cstring__in_len__)) + return NULL; + cstring__len__ = cstring__in_len__; + CGContextShowText(_self->ob_itself, + cstring__in__, cstring__len__); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextShowTextAtPoint(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + float x; + float y; + char *cstring__in__; + long cstring__len__; + int cstring__in_len__; + if (!PyArg_ParseTuple(_args, "ffs#", + &x, + &y, + &cstring__in__, &cstring__in_len__)) + return NULL; + cstring__len__ = cstring__in_len__; + CGContextShowTextAtPoint(_self->ob_itself, + x, + y, + cstring__in__, cstring__len__); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextEndPage(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextEndPage(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextFlush(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextFlush(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSynchronize(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + if (!PyArg_ParseTuple(_args, "")) + return NULL; + CGContextSynchronize(_self->ob_itself); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyObject *CGContextRefObj_CGContextSetShouldAntialias(CGContextRefObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + int shouldAntialias; + if (!PyArg_ParseTuple(_args, "i", + &shouldAntialias)) + return NULL; + CGContextSetShouldAntialias(_self->ob_itself, + shouldAntialias); + Py_INCREF(Py_None); + _res = Py_None; + return _res; +} + +static PyMethodDef CGContextRefObj_methods[] = { + {"CGContextSaveGState", (PyCFunction)CGContextRefObj_CGContextSaveGState, 1, + "() -> None"}, + {"CGContextRestoreGState", (PyCFunction)CGContextRefObj_CGContextRestoreGState, 1, + "() -> None"}, + {"CGContextScaleCTM", (PyCFunction)CGContextRefObj_CGContextScaleCTM, 1, + "(float sx, float sy) -> None"}, + {"CGContextTranslateCTM", (PyCFunction)CGContextRefObj_CGContextTranslateCTM, 1, + "(float tx, float ty) -> None"}, + {"CGContextRotateCTM", (PyCFunction)CGContextRefObj_CGContextRotateCTM, 1, + "(float angle) -> None"}, + {"CGContextConcatCTM", (PyCFunction)CGContextRefObj_CGContextConcatCTM, 1, + "(CGAffineTransform transform) -> None"}, + {"CGContextGetCTM", (PyCFunction)CGContextRefObj_CGContextGetCTM, 1, + "() -> (CGAffineTransform _rv)"}, + {"CGContextSetLineWidth", (PyCFunction)CGContextRefObj_CGContextSetLineWidth, 1, + "(float width) -> None"}, + {"CGContextSetLineCap", (PyCFunction)CGContextRefObj_CGContextSetLineCap, 1, + "(int cap) -> None"}, + {"CGContextSetLineJoin", (PyCFunction)CGContextRefObj_CGContextSetLineJoin, 1, + "(int join) -> None"}, + {"CGContextSetMiterLimit", (PyCFunction)CGContextRefObj_CGContextSetMiterLimit, 1, + "(float limit) -> None"}, + {"CGContextSetFlatness", (PyCFunction)CGContextRefObj_CGContextSetFlatness, 1, + "(float flatness) -> None"}, + {"CGContextSetAlpha", (PyCFunction)CGContextRefObj_CGContextSetAlpha, 1, + "(float alpha) -> None"}, + {"CGContextBeginPath", (PyCFunction)CGContextRefObj_CGContextBeginPath, 1, + "() -> None"}, + {"CGContextMoveToPoint", (PyCFunction)CGContextRefObj_CGContextMoveToPoint, 1, + "(float x, float y) -> None"}, + {"CGContextAddLineToPoint", (PyCFunction)CGContextRefObj_CGContextAddLineToPoint, 1, + "(float x, float y) -> None"}, + {"CGContextAddCurveToPoint", (PyCFunction)CGContextRefObj_CGContextAddCurveToPoint, 1, + "(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y) -> None"}, + {"CGContextAddQuadCurveToPoint", (PyCFunction)CGContextRefObj_CGContextAddQuadCurveToPoint, 1, + "(float cpx, float cpy, float x, float y) -> None"}, + {"CGContextClosePath", (PyCFunction)CGContextRefObj_CGContextClosePath, 1, + "() -> None"}, + {"CGContextAddRect", (PyCFunction)CGContextRefObj_CGContextAddRect, 1, + "(CGRect rect) -> None"}, + {"CGContextAddArc", (PyCFunction)CGContextRefObj_CGContextAddArc, 1, + "(float x, float y, float radius, float startAngle, float endAngle, int clockwise) -> None"}, + {"CGContextAddArcToPoint", (PyCFunction)CGContextRefObj_CGContextAddArcToPoint, 1, + "(float x1, float y1, float x2, float y2, float radius) -> None"}, + {"CGContextIsPathEmpty", (PyCFunction)CGContextRefObj_CGContextIsPathEmpty, 1, + "() -> (int _rv)"}, + {"CGContextGetPathCurrentPoint", (PyCFunction)CGContextRefObj_CGContextGetPathCurrentPoint, 1, + "() -> (CGPoint _rv)"}, + {"CGContextGetPathBoundingBox", (PyCFunction)CGContextRefObj_CGContextGetPathBoundingBox, 1, + "() -> (CGRect _rv)"}, + {"CGContextDrawPath", (PyCFunction)CGContextRefObj_CGContextDrawPath, 1, + "(int mode) -> None"}, + {"CGContextFillPath", (PyCFunction)CGContextRefObj_CGContextFillPath, 1, + "() -> None"}, + {"CGContextEOFillPath", (PyCFunction)CGContextRefObj_CGContextEOFillPath, 1, + "() -> None"}, + {"CGContextStrokePath", (PyCFunction)CGContextRefObj_CGContextStrokePath, 1, + "() -> None"}, + {"CGContextFillRect", (PyCFunction)CGContextRefObj_CGContextFillRect, 1, + "(CGRect rect) -> None"}, + {"CGContextStrokeRect", (PyCFunction)CGContextRefObj_CGContextStrokeRect, 1, + "(CGRect rect) -> None"}, + {"CGContextStrokeRectWithWidth", (PyCFunction)CGContextRefObj_CGContextStrokeRectWithWidth, 1, + "(CGRect rect, float width) -> None"}, + {"CGContextClearRect", (PyCFunction)CGContextRefObj_CGContextClearRect, 1, + "(CGRect rect) -> None"}, + {"CGContextClip", (PyCFunction)CGContextRefObj_CGContextClip, 1, + "() -> None"}, + {"CGContextEOClip", (PyCFunction)CGContextRefObj_CGContextEOClip, 1, + "() -> None"}, + {"CGContextClipToRect", (PyCFunction)CGContextRefObj_CGContextClipToRect, 1, + "(CGRect rect) -> None"}, + {"CGContextSetGrayFillColor", (PyCFunction)CGContextRefObj_CGContextSetGrayFillColor, 1, + "(float gray, float alpha) -> None"}, + {"CGContextSetGrayStrokeColor", (PyCFunction)CGContextRefObj_CGContextSetGrayStrokeColor, 1, + "(float gray, float alpha) -> None"}, + {"CGContextSetRGBFillColor", (PyCFunction)CGContextRefObj_CGContextSetRGBFillColor, 1, + "(float r, float g, float b, float alpha) -> None"}, + {"CGContextSetRGBStrokeColor", (PyCFunction)CGContextRefObj_CGContextSetRGBStrokeColor, 1, + "(float r, float g, float b, float alpha) -> None"}, + {"CGContextSetCMYKFillColor", (PyCFunction)CGContextRefObj_CGContextSetCMYKFillColor, 1, + "(float c, float m, float y, float k, float alpha) -> None"}, + {"CGContextSetCMYKStrokeColor", (PyCFunction)CGContextRefObj_CGContextSetCMYKStrokeColor, 1, + "(float c, float m, float y, float k, float alpha) -> None"}, + {"CGContextSetCharacterSpacing", (PyCFunction)CGContextRefObj_CGContextSetCharacterSpacing, 1, + "(float spacing) -> None"}, + {"CGContextSetTextPosition", (PyCFunction)CGContextRefObj_CGContextSetTextPosition, 1, + "(float x, float y) -> None"}, + {"CGContextGetTextPosition", (PyCFunction)CGContextRefObj_CGContextGetTextPosition, 1, + "() -> (CGPoint _rv)"}, + {"CGContextSetTextMatrix", (PyCFunction)CGContextRefObj_CGContextSetTextMatrix, 1, + "(CGAffineTransform transform) -> None"}, + {"CGContextGetTextMatrix", (PyCFunction)CGContextRefObj_CGContextGetTextMatrix, 1, + "() -> (CGAffineTransform _rv)"}, + {"CGContextSetTextDrawingMode", (PyCFunction)CGContextRefObj_CGContextSetTextDrawingMode, 1, + "(int mode) -> None"}, + {"CGContextSetFontSize", (PyCFunction)CGContextRefObj_CGContextSetFontSize, 1, + "(float size) -> None"}, + {"CGContextSelectFont", (PyCFunction)CGContextRefObj_CGContextSelectFont, 1, + "(char * name, float size, int textEncoding) -> None"}, + {"CGContextShowText", (PyCFunction)CGContextRefObj_CGContextShowText, 1, + "(Buffer cstring) -> None"}, + {"CGContextShowTextAtPoint", (PyCFunction)CGContextRefObj_CGContextShowTextAtPoint, 1, + "(float x, float y, Buffer cstring) -> None"}, + {"CGContextEndPage", (PyCFunction)CGContextRefObj_CGContextEndPage, 1, + "() -> None"}, + {"CGContextFlush", (PyCFunction)CGContextRefObj_CGContextFlush, 1, + "() -> None"}, + {"CGContextSynchronize", (PyCFunction)CGContextRefObj_CGContextSynchronize, 1, + "() -> None"}, + {"CGContextSetShouldAntialias", (PyCFunction)CGContextRefObj_CGContextSetShouldAntialias, 1, + "(int shouldAntialias) -> None"}, + {NULL, NULL, 0} +}; + +PyMethodChain CGContextRefObj_chain = { CGContextRefObj_methods, NULL }; + +static PyObject *CGContextRefObj_getattr(CGContextRefObject *self, char *name) +{ + return Py_FindMethodInChain(&CGContextRefObj_chain, (PyObject *)self, name); +} + +#define CGContextRefObj_setattr NULL + +#define CGContextRefObj_compare NULL + +#define CGContextRefObj_repr NULL + +#define CGContextRefObj_hash NULL + +PyTypeObject CGContextRef_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_CG.CGContextRef", /*tp_name*/ + sizeof(CGContextRefObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor) CGContextRefObj_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc) CGContextRefObj_getattr, /*tp_getattr*/ + (setattrfunc) CGContextRefObj_setattr, /*tp_setattr*/ + (cmpfunc) CGContextRefObj_compare, /*tp_compare*/ + (reprfunc) CGContextRefObj_repr, /*tp_repr*/ + (PyNumberMethods *)0, /* tp_as_number */ + (PySequenceMethods *)0, /* tp_as_sequence */ + (PyMappingMethods *)0, /* tp_as_mapping */ + (hashfunc) CGContextRefObj_hash, /*tp_hash*/ +}; + +/* ------------------ End object type CGContextRef ------------------ */ + + +static PyObject *CG_CreateCGContextForPort(PyObject *_self, PyObject *_args) +{ + PyObject *_res = NULL; + GrafPtr port; + CGContextRef ctx; + OSStatus _err; + + if (!PyArg_ParseTuple(_args, "O&", GrafObj_Convert, &port)) + return NULL; + + _err = CreateCGContextForPort(port, &ctx); + if (_err != noErr) + if (_err != noErr) return PyMac_Error(_err); + _res = Py_BuildValue("O&", CGContextRefObj_New, ctx); + return _res; + +} + +static PyMethodDef CG_methods[] = { + {"CreateCGContextForPort", (PyCFunction)CG_CreateCGContextForPort, 1, + "(CGrafPtr) -> CGContextRef"}, + {NULL, NULL, 0} +}; + + + + +void init_CG(void) +{ + PyObject *m; + PyObject *d; + + + +#if !TARGET_API_MAC_OSX + CFBundleRef sysBundle; + OSStatus err; + + if (&LoadFrameworkBundle == NULL) { + PyErr_SetString(PyExc_ImportError, "CoreCraphics not supported"); + return; + } + err = LoadFrameworkBundle(CFSTR("ApplicationServices.framework"), &sysBundle); + if (err == noErr) + err = CFMLateImportBundle(&gFragToFixLocator, gFragToFixConnID, FragmentInit, "\pCGStubLib", sysBundle); + if (err != noErr) { + PyErr_SetString(PyExc_ImportError, "CoreCraphics not supported"); + return; + }; +#endif /* !TARGET_API_MAC_OSX */ + + + m = Py_InitModule("_CG", CG_methods); + d = PyModule_GetDict(m); + CG_Error = PyMac_GetOSErrException(); + if (CG_Error == NULL || + PyDict_SetItemString(d, "Error", CG_Error) != 0) + return; + CGContextRef_Type.ob_type = &PyType_Type; + Py_INCREF(&CGContextRef_Type); + if (PyDict_SetItemString(d, "CGContextRefType", (PyObject *)&CGContextRef_Type) != 0) + Py_FatalError("can't initialize CGContextRefType"); +} + +/* ========================= End module _CG ========================= */ + diff --git a/Mac/Modules/cg/cgscan.py b/Mac/Modules/cg/cgscan.py new file mode 100755 index 00000000000..f67647008d1 --- /dev/null +++ b/Mac/Modules/cg/cgscan.py @@ -0,0 +1,83 @@ +# Scan an Apple header file, generating a Python file of generator calls. + +import sys +import os +BGENDIR=os.path.join(sys.prefix, ':Tools:bgen:bgen') +sys.path.append(BGENDIR) +from scantools import Scanner_OSX +from bgenlocations import TOOLBOXDIR + +LONG = "CoreGraphics" +SHORT = "cg" +OBJECTS = ("CGContextRef", + ) +# ADD object typenames here + +def main(): + input = [ + "CGContext.h", + ] + output = SHORT + "gen.py" + defsoutput = TOOLBOXDIR + LONG + ".py" + scanner = MyScanner(input, output, defsoutput) + scanner.scan() + scanner.gentypetest(SHORT+"typetest.py") + scanner.close() + print "=== Done scanning and generating, now importing the generated code... ===" + exec "import " + SHORT + "support" + print "=== Done. It's up to you to compile it now! ===" + +class MyScanner(Scanner_OSX): + + def destination(self, type, name, arglist): + classname = "Function" + listname = "functions" + if arglist: + t, n, m = arglist[0] + if t in OBJECTS and m == "InMode": + classname = "Method" + listname = t + "_methods" + # Special case for the silly first AllocatorRef argument + if t == 'CFAllocatorRef' and m == 'InMode' and len(arglist) > 1: + t, n, m = arglist[1] + if t in OBJECTS and m == "InMode": + classname = "MethodSkipArg1" + listname = t + "_methods" + return classname, listname + + def writeinitialdefs(self): + self.defsfile.write("def FOUR_CHAR_CODE(x): return x\n") + + def makeblacklistnames(self): + return [ + "CGContextRetain", + "CGContextRelease", + ] + + def makegreylist(self): + return [] + + def makeblacklisttypes(self): + return [ + "float_ptr", + "CGRect_ptr", + "CGPoint_ptr", + "CGColorSpaceRef", + "CGColorRenderingIntent", + "CGFontRef", +# "char_ptr", + "CGGlyph_ptr", + "CGImageRef", + "CGPDFDocumentRef", + ] + + def makerepairinstructions(self): + return [ + ([("char_ptr", "cstring", "InMode"), ("size_t", "length", "InMode")], + [("InBuffer", "*", "*")]), +# ([("char_ptr", "name", "InMode"),], +# [("CCCCC", "*", "*")]), + ] + +if __name__ == "__main__": + main() diff --git a/Mac/Modules/cg/cgsupport.py b/Mac/Modules/cg/cgsupport.py new file mode 100755 index 00000000000..4ec56e45509 --- /dev/null +++ b/Mac/Modules/cg/cgsupport.py @@ -0,0 +1,305 @@ +# This script generates a Python interface for an Apple Macintosh Manager. +# It uses the "bgen" package to generate C code. +# The function specifications are generated by scanning the mamager's header file, +# using the "scantools" package (customized for this particular manager). + +#error missing SetActionFilter + +import string + +# Declarations that change for each manager +MODNAME = '_CG' # The name of the module + +# The following is *usually* unchanged but may still require tuning +MODPREFIX = 'CG' # The prefix for module-wide routines +INPUTFILE = string.lower(MODPREFIX) + 'gen.py' # The file generated by the scanner +OUTPUTFILE = MODNAME + "module.c" # The file generated by this program + +from macsupport import * + + +# Create the type objects + +includestuff = includestuff + """ +#ifdef WITHOUT_FRAMEWORKS +#include +#include +#else +#include +#endif + +#if !TARGET_API_MAC_OSX + /* This code is adapted from the CallMachOFramework demo at: + http://developer.apple.com/samplecode/Sample_Code/Runtime_Architecture/CallMachOFramework.htm + It allows us to call Mach-O functions from CFM apps. */ + + #include + #include "CFMLateImport.h" + + static OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr) + // This routine finds a the named framework and creates a CFBundle + // object for it. It looks for the framework in the frameworks folder, + // as defined by the Folder Manager. Currently this is + // "/System/Library/Frameworks", but we recommend that you avoid hard coded + // paths to ensure future compatibility. + // + // You might think that you could use CFBundleGetBundleWithIdentifier but + // that only finds bundles that are already loaded into your context. + // That would work in the case of the System framework but it wouldn't + // work if you're using some other, less-obvious, framework. + { + OSStatus err; + FSRef frameworksFolderRef; + CFURLRef baseURL; + CFURLRef bundleURL; + + *bundlePtr = nil; + + baseURL = nil; + bundleURL = nil; + + // Find the frameworks folder and create a URL for it. + + err = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, true, &frameworksFolderRef); + if (err == noErr) { + baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef); + if (baseURL == nil) { + err = coreFoundationUnknownErr; + } + } + + // Append the name of the framework to the URL. + + if (err == noErr) { + bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false); + if (bundleURL == nil) { + err = coreFoundationUnknownErr; + } + } + + // Create a bundle based on that URL and load the bundle into memory. + // We never unload the bundle, which is reasonable in this case because + // the sample assumes that you'll be calling functions from this + // framework throughout the life of your application. + + if (err == noErr) { + *bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL); + if (*bundlePtr == nil) { + err = coreFoundationUnknownErr; + } + } + if (err == noErr) { + if ( ! CFBundleLoadExecutable( *bundlePtr ) ) { + err = coreFoundationUnknownErr; + } + } + + // Clean up. + + if (err != noErr && *bundlePtr != nil) { + CFRelease(*bundlePtr); + *bundlePtr = nil; + } + if (bundleURL != nil) { + CFRelease(bundleURL); + } + if (baseURL != nil) { + CFRelease(baseURL); + } + + return err; + } + + + + // The CFMLateImport approach requires that you define a fragment + // initialisation routine that latches the fragment's connection + // ID and locator. If your code already has a fragment initialiser + // you will have to integrate the following into it. + + static CFragConnectionID gFragToFixConnID; + static FSSpec gFragToFixFile; + static CFragSystem7DiskFlatLocator gFragToFixLocator; + + extern OSErr FragmentInit(const CFragInitBlock *initBlock); + extern OSErr FragmentInit(const CFragInitBlock *initBlock) + { + __initialize(initBlock); /* call the "original" initializer */ + gFragToFixConnID = (CFragConnectionID) initBlock->closureID; + gFragToFixFile = *(initBlock->fragLocator.u.onDisk.fileSpec); + gFragToFixLocator = initBlock->fragLocator.u.onDisk; + gFragToFixLocator.fileSpec = &gFragToFixFile; + + return noErr; + } + +#endif + +extern int GrafObj_Convert(PyObject *, GrafPtr *); + +/* +** Manual converters +*/ + +PyObject *CGPoint_New(CGPoint *itself) +{ + + return Py_BuildValue("(ff)", + itself->x, + itself->y); +} + +int +CGPoint_Convert(PyObject *v, CGPoint *p_itself) +{ + if( !PyArg_Parse(v, "(ff)", + &p_itself->x, + &p_itself->y) ) + return 0; + return 1; +} + +PyObject *CGRect_New(CGRect *itself) +{ + + return Py_BuildValue("(ffff)", + itself->origin.x, + itself->origin.y, + itself->size.width, + itself->size.height); +} + +int +CGRect_Convert(PyObject *v, CGRect *p_itself) +{ + if( !PyArg_Parse(v, "(ffff)", + &p_itself->origin.x, + &p_itself->origin.y, + &p_itself->size.width, + &p_itself->size.height) ) + return 0; + return 1; +} + +PyObject *CGAffineTransform_New(CGAffineTransform *itself) +{ + + return Py_BuildValue("(ffffff)", + itself->a, + itself->b, + itself->c, + itself->d, + itself->tx, + itself->ty); +} + +int +CGAffineTransform_Convert(PyObject *v, CGAffineTransform *p_itself) +{ + if( !PyArg_Parse(v, "(ffffff)", + &p_itself->a, + &p_itself->b, + &p_itself->c, + &p_itself->d, + &p_itself->tx, + &p_itself->ty) ) + return 0; + return 1; +} +""" + +initstuff = initstuff + """ +#if !TARGET_API_MAC_OSX +CFBundleRef sysBundle; +OSStatus err; + +if (&LoadFrameworkBundle == NULL) { + PyErr_SetString(PyExc_ImportError, "CoreCraphics not supported"); + return; +} +err = LoadFrameworkBundle(CFSTR("ApplicationServices.framework"), &sysBundle); +if (err == noErr) + err = CFMLateImportBundle(&gFragToFixLocator, gFragToFixConnID, FragmentInit, "\pCGStubLib", sysBundle); +if (err != noErr) { + PyErr_SetString(PyExc_ImportError, "CoreCraphics not supported"); + return; +}; +#endif /* !TARGET_API_MAC_OSX */ +""" + +class MyOpaqueByValueType(OpaqueByValueType): + """Sort of a mix between OpaqueByValueType and OpaqueType.""" + def mkvalueArgs(self, name): + return "%s, &%s" % (self.new, name) + +CGPoint = MyOpaqueByValueType('CGPoint', 'CGPoint') +CGRect = MyOpaqueByValueType('CGRect', 'CGRect') +CGAffineTransform = MyOpaqueByValueType('CGAffineTransform', 'CGAffineTransform') + +char_ptr = Type("char *", "s") + +CGTextEncoding = int +CGLineCap = int +CGLineJoin = int +CGTextDrawingMode = int +CGPathDrawingMode = int + +# The real objects +CGContextRef = OpaqueByValueType("CGContextRef", "CGContextRefObj") + + +class MyObjectDefinition(GlobalObjectDefinition): + def outputStructMembers(self): + ObjectDefinition.outputStructMembers(self) + def outputCleanupStructMembers(self): + Output("CGContextRelease(self->ob_itself);") + + +# Create the generator groups and link them +module = MacModule(MODNAME, MODPREFIX, includestuff, finalstuff, initstuff) + +CGContextRef_object = MyObjectDefinition('CGContextRef', 'CGContextRefObj', 'CGContextRef') + + +# ADD object here + +module.addobject(CGContextRef_object) + + + +Function = FunctionGenerator +Method = MethodGenerator + +CGContextRef_methods = [] + +# ADD _methods initializer here +execfile(INPUTFILE) + +CreateCGContextForPort_body = """\ +GrafPtr port; +CGContextRef ctx; +OSStatus _err; + +if (!PyArg_ParseTuple(_args, "O&", GrafObj_Convert, &port)) + return NULL; + +_err = CreateCGContextForPort(port, &ctx); +if (_err != noErr) + if (_err != noErr) return PyMac_Error(_err); +_res = Py_BuildValue("O&", CGContextRefObj_New, ctx); +return _res; +""" + +f = ManualGenerator("CreateCGContextForPort", CreateCGContextForPort_body); +f.docstring = lambda: "(CGrafPtr) -> CGContextRef" +module.add(f) + + +# ADD add forloop here +for f in CGContextRef_methods: + CGContextRef_object.add(f) + +# generate output (open the output file as late as possible) +SetOutputFileName(OUTPUTFILE) +module.generate() +