summaryrefslogtreecommitdiffstats
path: root/Mac/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Mac/Modules')
-rwxr-xr-xMac/Modules/cg/CFMLateImport.c1360
-rwxr-xr-xMac/Modules/cg/CFMLateImport.h272
-rwxr-xr-xMac/Modules/cg/CGStubLib1
-rwxr-xr-xMac/Modules/cg/CGStubLib.exp58
-rwxr-xr-xMac/Modules/cg/CGStubLib.readme3
-rwxr-xr-xMac/Modules/cg/_CGmodule.c1332
-rwxr-xr-xMac/Modules/cg/cgscan.py83
-rwxr-xr-xMac/Modules/cg/cgsupport.py305
8 files changed, 3414 insertions, 0 deletions
diff --git a/Mac/Modules/cg/CFMLateImport.c b/Mac/Modules/cg/CFMLateImport.c
new file mode 100755
index 0000000..bc2976e
--- /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 <CodeFragments.h>
+ #include <PEFBinaryFormat.h>
+#endif
+
+// Standard C Interfaces
+
+#include <string.h>
+
+// 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 0000000..f3a89bc
--- /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 <MacTypes.h>
+ #include <CodeFragments.h>
+ #include <Devices.h>
+ #include <CFBundle.h>
+#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 0000000..74de909
--- /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&GTC(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 0000000..4b034b5
--- /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 0000000..d2c5fa8
--- /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 0000000..6523e71
--- /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 <Quickdraw.h>
+#include <CGContext.h>
+#else
+#include <CoreGraphics/CoreGraphics.h>
+#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 <Folders.h>
+ #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 0000000..f676470
--- /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 0000000..4ec56e4
--- /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 <Quickdraw.h>
+#include <CGContext.h>
+#else
+#include <CoreGraphics/CoreGraphics.h>
+#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 <Folders.h>
+ #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()
+