/* * guiKit.c * GUIKit * * Created by Colin Cornaby on 3/29/07. * Copyright 2007 White Magic Labs. All rights reserved. * */ /* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "guiKitLib.h" #include "zlib.h" #include #include #include #pragma mark Internal Methods #pragma mark Decompress Data CFDataRef copyDataForCompressedBytes(void *data, int length) { CFDataRef dataToReturn = nil; const void *cBuffer = data; unsigned cLen = length; Bytef *uBuffer = NULL; uLongf uLen = cLen; int err; do { uLen *= 2; // Double the buffer size each iteration through the loop if (uBuffer = malloc(uLen)) { err = uncompress(uBuffer, &uLen, cBuffer, cLen); if (err == Z_OK) dataToReturn = CFDataCreate(NULL,uBuffer,uLen); if (err == Z_MEM_ERROR || err == Z_DATA_ERROR) dataToReturn = nil; free(uBuffer); } else { return nil; } } while (err == Z_BUF_ERROR); // If the buffer wasn't big enough this time, repeat the loop return (CFDataRef)dataToReturn; } CFStringRef copyStringFromCompressedData(void * ptr, int length) { CFDataRef decompressedThemeName = copyDataForCompressedBytes(ptr+8,length-8); CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, CFDataGetBytePtr (decompressedThemeName), CFDataGetLength(decompressedThemeName), kCFStringEncodingUnicode, TRUE); CFRelease(decompressedThemeName); return (CFStringRef)string; } CFAttributedStringRef copyAttributedStringFromCompressData(void * ptr, int length) { CFDataRef decompressedString = copyDataForCompressedBytes(ptr+8,length-8); NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; CFAttributedStringRef attributedString = (CFAttributedStringRef) [[NSAttributedString alloc] initWithData:(NSData *)decompressedString options:[NSDictionary dictionaryWithObject:NSRTFDTextDocumentType forKey:NSDocumentTypeDocumentOption] documentAttributes:nil error:nil]; [pool release]; CFRelease(decompressedString); return (CFAttributedStringRef)attributedString; } #pragma mark Attribute Metadata SInt32 nameForAttribute(gkAttribRef ptr) { SInt32 *name = ptr; return *name; } SInt32 lengthForAttribute(gkAttribRef ptr) { SInt32 *length = ptr+4; return CFSwapInt32BigToHost((SInt32)*length); } #pragma mark Attribute Discovery int countForAttribType(SInt32 type, gkAttribRef ptr, int length) { int currentOffset = 8; int count = 0; while(length>currentOffset) { SInt32 attributeName = nameForAttribute(ptr+currentOffset); SInt32 attributeLength = lengthForAttribute(ptr+currentOffset); if(type==attributeName) { count++; } currentOffset += attributeLength; } return count; } void * ptrForAttribute(SInt32 type, gkAttribRef ptr, int length, int index) { int currentOffset = 8; int currentIndex=0; while(length>currentOffset) { SInt32 attributeName = nameForAttribute(ptr+currentOffset); SInt32 attributeLength = lengthForAttribute(ptr+currentOffset); if(type==attributeName) { if(currentIndex==index) return (void *)(ptr+currentOffset); currentIndex++; } currentOffset += attributeLength; } return NULL; } #pragma mark Public Methods #pragma mark Fetching attribute information CFDataRef GKCopyImagePreviewOfAttribute(gkAttribRef gkRef) { void *pictureAttribRef = ptrForAttribute(*((SInt32 *)(void *)"PRVW"),gkRef,lengthForAttribute(gkRef), 0); if(pictureAttribRef==NULL) return NULL; void *pictureDataRef = ptrForAttribute(*((SInt32 *)(void *)"DATA"),pictureAttribRef,lengthForAttribute(pictureAttribRef), 0); if(pictureDataRef==NULL) return NULL; return copyDataForCompressedBytes(pictureDataRef+8,lengthForAttribute(pictureDataRef)-8); } CFStringRef GKCopyNameOfAttribute(gkAttribRef gkRef) { void *nameAttribRef = ptrForAttribute(*((SInt32 *)(void *)"NAME"),gkRef,lengthForAttribute(gkRef), 0); return copyStringFromCompressedData(nameAttribRef,lengthForAttribute(nameAttribRef)); } CFAttributedStringRef GKCopyDescriptionOfAttribute(gkAttribRef gkRef) { void *descAttribRef = ptrForAttribute(*((SInt32 *)(void *)"DESC"),gkRef,lengthForAttribute(gkRef), 0); if(descAttribRef!=NULL) { void *rtfdAttribRef = ptrForAttribute(*((SInt32 *)(void *)"RTFD"),descAttribRef,lengthForAttribute(descAttribRef), 0); if(rtfdAttribRef!=NULL) return copyAttributedStringFromCompressData(rtfdAttribRef,lengthForAttribute(rtfdAttribRef)); void *unicAttribRef = ptrForAttribute(*((SInt32 *)(void *)"UNIC"),descAttribRef,lengthForAttribute(descAttribRef), 0); if(unicAttribRef!=NULL) { CFStringRef descriptionAsString = copyStringFromCompressedData(unicAttribRef,lengthForAttribute(unicAttribRef)); CFAttributedStringRef descriptionAsRichString = CFAttributedStringCreate(NULL,descriptionAsString,NULL); CFRelease(descriptionAsString); return descriptionAsRichString; } } return nil; } #pragma mark Variation Methods int GKThemeVariationCount(guiKitRef gkRef) { gkAttribRef themeRef = ptrForAttribute(*((SInt32 *)(void *)"THME"),(gkRef->buffer)+20,(gkRef->length)-20,0); return countForAttribType(*((SInt32 *)(void *)"TVAR"),themeRef,lengthForAttribute(themeRef)); } gkVariationRef GKThemeVariationAtIndex(int index, guiKitRef gkRef) { gkAttribRef themeRef = ptrForAttribute(*((SInt32 *)(void *)"THME"),(gkRef->buffer)+20,(gkRef->length)-20,0); return ptrForAttribute(*((SInt32 *)(void *)"TVAR"),themeRef,lengthForAttribute(themeRef), index); } int GKPatchCountForVariation(gkAttribRef gkRef) { gkAttribRef patchesRef = ptrForAttribute(*((SInt32 *)(void *)"PTCS"),gkRef,lengthForAttribute(gkRef),0); return countForAttribType(*((SInt32 *)(void *)"PTCH"),patchesRef,lengthForAttribute(patchesRef)); } gkPatchRef GKPatchForVariationAtIndex(int index, gkAttribRef gkRef) { gkAttribRef patchesRef = ptrForAttribute(*((SInt32 *)(void *)"PTCS"),gkRef,lengthForAttribute(gkRef),0); return ptrForAttribute(*((SInt32 *)(void *)"PTCH"),patchesRef,lengthForAttribute(patchesRef), index); } #pragma mark "Patch" Methods CFStringRef GKCopyPathOfPatch(gkAttribRef gkRef) { void *patchAttribRef = ptrForAttribute(*((SInt32 *)(void *)"PATH"),gkRef,lengthForAttribute(gkRef), 0); return copyStringFromCompressedData(patchAttribRef,lengthForAttribute(patchAttribRef)); } CFDataRef GKCopyFileOfPatch(gkAttribRef gkRef) { void *fileAttribRef = ptrForAttribute(*((SInt32 *)(void *)"FILE"),gkRef,lengthForAttribute(gkRef), 0); //void *fileDataAttribRef = ptrForAttribute(*((SInt32 *)(void *)"DDAT"),fileAttribRef,lengthForAttribute(fileAttribRef), 0); return copyDataForCompressedBytes(fileAttribRef+16,lengthForAttribute(fileAttribRef)-16); } CFStringRef GKCopyApplicationIDOfPatch(gkAttribRef gkRef) { void *apidAttribRef = ptrForAttribute(*((SInt32 *)(void *)"APID"),gkRef,lengthForAttribute(gkRef), 0); if(apidAttribRef==NULL) return NULL; return copyStringFromCompressedData(apidAttribRef,lengthForAttribute(apidAttribRef)); } #pragma mark Checksum int GKDoCheckSum(guiKitRef gkRef) { uLong checksum = (uLong)*((uLong *)(gkRef->buffer+8)); checksum = NSSwapBigLongToHost(checksum); uLong adler = adler32(0L, Z_NULL, 0); adler = adler32(adler, gkRef->buffer+12, gkRef->length-12); if(adler!=checksum) return 0; return 1; }