void TiledMap::saveTo(PACKFILE *file) { ASSERT(file); // Version info // Version 1: No version number stored, one layer in map // Version 2: First int is version number, second one the number of layers // Version 3: Object list stored at end of tile data. pack_iputw(3, file); // The map header pack_iputw(nrLayers, file); // The tile data for (int i = 0; i < nrLayers; i++) { mapLayers[i]->saveTo(file); } // Object data list<Object*>::iterator i; pack_iputw(objects.size(), file); for (i = objects.begin(); i != objects.end(); i++) { pack_iputw(int(TILES_W * (*i)->x), file); pack_iputw(int(TILES_H * (*i)->y), file); pack_fputs((*i)->className, file); pack_fputs("\n", file); } // Extra newline fixes last tile not loaded. pack_fputs("\n", file); }
void Tile::saveTo(PACKFILE *file) { // Write tile name to file if (tileType) { pack_fputs(tileType->getName(), file); } pack_fputs("\n", file); pack_iputw(obstacle, file); }
/* exports a sample into an external file */ static int export_sample(AL_CONST DATAFILE *dat, AL_CONST char *filename) { SAMPLE *spl = (SAMPLE *)dat->dat; int bps = spl->bits/8 * ((spl->stereo) ? 2 : 1); int len = spl->len * bps; int i; int16_t s; PACKFILE *f; errno = 0; f = pack_fopen(filename, F_WRITE); if (f) { pack_fputs("RIFF", f); /* RIFF header */ pack_iputl(36+len, f); /* size of RIFF chunk */ pack_fputs("WAVE", f); /* WAV definition */ pack_fputs("fmt ", f); /* format chunk */ pack_iputl(16, f); /* size of format chunk */ pack_iputw(1, f); /* PCM data */ pack_iputw((spl->stereo) ? 2 : 1, f); /* mono/stereo data */ pack_iputl(spl->freq, f); /* sample frequency */ pack_iputl(spl->freq*bps, f); /* avg. bytes per sec */ pack_iputw(bps, f); /* block alignment */ pack_iputw(spl->bits, f); /* bits per sample */ pack_fputs("data", f); /* data chunk */ pack_iputl(len, f); /* actual data length */ if (spl->bits == 8) { pack_fwrite(spl->data, len, f); /* write the data */ } else { for (i=0; i < (int)spl->len * ((spl->stereo) ? 2 : 1); i++) { s = ((int16_t *)spl->data)[i]; pack_iputw(s^0x8000, f); } } pack_fclose(f); } return (errno == 0); }
int eof_undo_add(int type) { char fn[1024] = {0}, temp[1024] = {0}; unsigned long ctr; eof_log("eof_undo_add() entered", 1); if(eof_undo_states_initialized == -1) { //The undo filename array couldn't be initialized previously return 0; } if(eof_validate_temp_folder()) { //Ensure the correct working directory and presence of the temporary folder eof_log("\tCould not validate working directory and temp folder", 1); return 0; } if(!eof_undo_states_initialized) { //Initialize the undo filename array for(ctr = 0; ctr < EOF_MAX_UNDO; ctr++) { //For each undo slot (void) snprintf(fn, sizeof(fn) - 1, "%seof%03u-%03lu.undo", eof_temp_path_s, eof_log_id, ctr); //Build the undo filename in the format of "eof#-#.undo", where the first number is the EOF ID eof_undo_filename[ctr] = malloc(sizeof(fn) + 1); if(eof_undo_filename[ctr] == NULL) { allegro_message("Error initializing undo system. Undo disabled"); eof_undo_states_initialized = -1; return 0; } strcpy(eof_undo_filename[ctr], fn); //Save the undo filename to the array } eof_undo_states_initialized = 1; } if((type == EOF_UNDO_TYPE_NOTE_LENGTH) && (eof_undo_last_type == EOF_UNDO_TYPE_NOTE_LENGTH)) { return 0; } if((type == EOF_UNDO_TYPE_LYRIC_NOTE) && (eof_undo_last_type == EOF_UNDO_TYPE_LYRIC_NOTE)) { return 0; } if((type == EOF_UNDO_TYPE_RECORD) && (eof_undo_last_type == EOF_UNDO_TYPE_RECORD)) { return 0; } if((type == EOF_UNDO_TYPE_TEMPO_ADJUST) && (eof_undo_last_type == EOF_UNDO_TYPE_TEMPO_ADJUST)) { return 0; } if(type == EOF_UNDO_TYPE_SILENCE) { (void) snprintf(fn, sizeof(fn) - 1, "%s%s.ogg", eof_temp_path_s, eof_undo_filename[eof_undo_current_index]); (void) eof_copy_file(eof_loaded_ogg_name, fn); } eof_undo_last_type = type; (void) eof_save_song(eof_song, eof_undo_filename[eof_undo_current_index]); eof_undo_type[eof_undo_current_index] = type; if(eof_recovery) { //If this EOF instance is maintaining auto-recovery files PACKFILE *fp; (void) snprintf(fn, sizeof(fn) - 1, "%seof.recover", eof_temp_path_s); fp = pack_fopen(fn, "w"); //Open the recovery definition file for writing if(fp) { //If the file opened (void) append_filename(temp, eof_song_path, eof_loaded_song_name, 1024); //Construct the full path to the project file (void) pack_fputs(eof_undo_filename[eof_undo_current_index], fp); //Write the undo file path (void) pack_fputs("\n", fp); //Write a newline character (void) pack_fputs(temp, fp); //Write the project path (void) pack_fclose(fp); } } eof_undo_current_index++; if(eof_undo_current_index >= EOF_MAX_UNDO) { eof_undo_current_index = 0; } eof_undo_count++; if(eof_undo_count >= EOF_MAX_UNDO) { eof_undo_count = EOF_MAX_UNDO; } eof_redo_count = 0; return 1; }
int eof_export_bandfuse(EOF_SONG * sp, char * fn, unsigned short *user_warned) { PACKFILE * fp; char buffer[600] = {0}, buffer2[600] = {0}; EOF_PRO_GUITAR_TRACK *tp; char restore_tech_view = 0; //If tech view is in effect, it is temporarily disabled so that the correct notes are exported unsigned long ctr, ctr2, ctr3, ctr4, ctr5, gemcount, bitmask, guitartracknum = 0, basstracknum = 0; eof_log("eof_export_bandfuse() entered", 1); if(!sp || !fn || !sp->beats || !user_warned) { eof_log("\tError saving: Invalid parameters", 1); return 0; //Return failure } fp = pack_fopen(fn, "w"); if(!fp) { eof_log("\tError saving: Cannot open file for writing", 1); return 0; //Return failure } //Write the song metadata (void) pack_fputs("<?xml version='1.0' encoding='UTF-8'?>\n", fp); (void) pack_fputs("<Bandfuse>\n", fp); (void) pack_fputs("<!-- " EOF_VERSION_STRING " -->\n", fp); //Write EOF's version in an XML comment expand_xml_text(buffer2, sizeof(buffer2) - 1, sp->tags->title, 64, 0); //Expand XML special characters into escaped sequences if necessary, and check against the maximum supported length of this field (void) snprintf(buffer, sizeof(buffer) - 1, " <title>%s</title>\n", buffer2); (void) pack_fputs(buffer, fp); expand_xml_text(buffer2, sizeof(buffer2) - 1, sp->tags->artist, 256, 0); //Replace any special characters in the artist song property with escape sequences if necessary (void) snprintf(buffer, sizeof(buffer) - 1, " <artistName>%s</artistName>\n", buffer2); (void) pack_fputs(buffer, fp); expand_xml_text(buffer2, sizeof(buffer2) - 1, sp->tags->album, 256, 0); //Replace any special characters in the album song property with escape sequences if necessary (void) snprintf(buffer, sizeof(buffer) - 1, " <albumName>%s</albumName>\n", buffer2); (void) pack_fputs(buffer, fp); expand_xml_text(buffer2, sizeof(buffer2) - 1, sp->tags->year, 32, 0); //Replace any special characters in the year song property with escape sequences if necessary (void) snprintf(buffer, sizeof(buffer) - 1, " <albumYear>%s</albumYear>\n", buffer2); (void) pack_fputs(buffer, fp); //Write tempo changes (void) pack_fputs(" <tempochanges>\n", fp); ctr = 0; //Begin with the first beat while(ctr < sp->beats) { //Until the last beat has been reached for(ctr2 = ctr + 1; ctr2 < sp->beats; ctr2++) { //For each beat that follows if(sp->beat[ctr]->ppqn != sp->beat[ctr2]->ppqn) { //If the following beat has a different tempo break; //Break from inner for loop } } if(ctr2 < sp->beats) { //If a beat with a different tempo was found, that beat is written as the end position of this tempo change (void) snprintf(buffer, sizeof(buffer) - 1, " <tempo start=\"%lu\" end=\"%lu\" tempo=\"%f\">\n", sp->beat[ctr]->pos, sp->beat[ctr2]->pos, 60000000.0 / (double)sp->beat[ctr]->ppqn); } else { //No remaining beats had a different tempo, the outer for loop's beat is written as the end position of this tempo change (void) snprintf(buffer, sizeof(buffer) - 1, " <tempo start=\"%lu\" end=\"%lu\" tempo=\"%f\">\n", sp->beat[ctr]->pos, sp->beat[ctr]->pos, 60000000.0 / (double)sp->beat[ctr]->ppqn); } (void) pack_fputs(buffer, fp); ctr = ctr2; //Advance the beat counter } (void) pack_fputs(" </tempochanges>\n", fp); for(ctr = 1; ctr < sp->tracks; ctr++) { //For each track if(ctr >= EOF_TRACKS_MAX) break; //Redundant bounds check to satisfy a false positive with Coverity if(sp->track[ctr]->track_format != EOF_PRO_GUITAR_TRACK_FORMAT) continue; //If this isn't a pro guitar/bass track, skip it if(ctr == EOF_TRACK_PRO_GUITAR_B) continue; //If this is the bonus Rocksmith arrangement, skip it tp = sp->pro_guitar_track[sp->track[ctr]->tracknum]; restore_tech_view = eof_menu_track_get_tech_view_state(sp, ctr); eof_menu_track_set_tech_view_state(sp, ctr, 0); //Disable tech view if applicable if(tp->notes) { //If this track is populated eof_determine_phrase_status(sp, ctr); //Update the trill and tremolo status of each note if(tp->arrangement != 4) { //If this isn't a bass track guitartracknum++; //Keep count of how many of this track type there have been (void) snprintf(buffer, sizeof(buffer) - 1, " <arrangement name=\"Guitar %lu (%s)\">\n", guitartracknum, sp->track[ctr]->name); (void) pack_fputs(buffer, fp); } else { //This is a bass track basstracknum++; //Keep count of how many of this track type there have been (void) snprintf(buffer, sizeof(buffer) - 1, " <arrangement name=\"Bass %lu (%s)\">\n", guitartracknum, sp->track[ctr]->name); (void) pack_fputs(buffer, fp); } (void) snprintf(buffer, sizeof(buffer) - 1, " <tuning string0=\"%d\" string1=\"%d\" string2=\"%d\" string3=\"%d\" string4=\"%d\" string5=\"%d\" />\n", tp->tuning[0], tp->tuning[1], tp->tuning[2], tp->tuning[3], tp->tuning[4], tp->tuning[5]); (void) pack_fputs(buffer, fp); (void) eof_detect_difficulties(sp, ctr); //Update eof_track_diff_populated_status[] to reflect all populated difficulties for this track for(ctr2 = 0; ctr2 < 6; ctr2++) { //For each of the first 6 difficulties unsigned long anchorcount; char anchorsgenerated = 0; //Is set to nonzero if fret hand positions are automatically generated for this difficulty and will have to be deleted if(!eof_track_diff_populated_status[ctr2]) continue; //If this difficulty is not populated, skip it (void) snprintf(buffer, sizeof(buffer) - 1, " <level difficulty=\"%lu\">\n", ctr2); (void) pack_fputs(buffer, fp); //Count the number of note gems in this track difficulty for(ctr3 = 0, gemcount = 0; ctr3 < tp->notes; ctr3++) { //For each note in the track if(eof_get_note_type(sp, ctr, ctr3) == ctr2) { //If the note is in this difficulty gemcount += eof_note_count_rs_lanes(sp, ctr, ctr3, 2); //Add this note's number of non-ghosted gems to a counter } } (void) snprintf(buffer, sizeof(buffer) - 1, " <notes count=\"%lu\">\n", gemcount); (void) pack_fputs(buffer, fp); //Generate fret hand positions if there are none for this difficulty for(ctr3 = 0, anchorcount = 0; ctr3 < tp->handpositions; ctr3++) { //For each hand position defined in the track if(tp->handposition[ctr3].difficulty == ctr2) { //If the hand position is in this difficulty anchorcount++; } } if(!anchorcount) { //If there are no anchors in this track difficulty, automatically generate them if((tp->arrangement != 4) || eof_warn_missing_bass_fhps) { //Don't warn about missing FHPs in bass arrangements if user disabled that preference if((*user_warned & 1) == 0) { //If the user wasn't alerted that one or more track difficulties have no fret hand positions defined allegro_message("Warning: At least one track difficulty has no fret hand positions defined. They will be created automatically."); *user_warned |= 1; } } eof_fret_hand_position_list_dialog_undo_made = 1; //Ensure no undo state is written during export eof_generate_efficient_hand_positions(sp, ctr, ctr2, 0, 0); //Generate the fret hand positions for the track difficulty being currently written anchorsgenerated = 1; } for(ctr3 = 0, anchorcount = 0; ctr3 < tp->handpositions; ctr3++) //Re-count the hand positions { //For each hand position defined in the track if(tp->handposition[ctr3].difficulty == ctr) { //If the hand position is in this difficulty anchorcount++; } } //Write the notes to XML for(ctr3 = 0; ctr3 < tp->notes; ctr3++) { //For each note in the track if(eof_get_note_type(sp, ctr, ctr3) != ctr2) continue; //If the note is not in this difficulty, skip it for(ctr4 = 0, bitmask = 1; ctr4 < tp->numstrings; ctr4++, bitmask <<= 1) { //For each string in this track EOF_RS_TECHNIQUES tech = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned long notepos; unsigned long fret, finger; //The fret and finger numbers used to play the gem on this string unsigned long trill_start, trill_stop; //The start and stop positions of the note's trill phrase int trillwith = -1; //If the note is in a trill phrase, this is set to the fret value of the next or previous gem on the string long next; unsigned long stringnum; //The converted string number (ie. low E string is string 6) char *sustainpadding; if(!(tp->note[ctr3]->note & bitmask) || (tp->note[ctr3]->ghost & bitmask)) continue; //If this string does not have a gem, or if it has one that is ghosted, skip it trill_start = trill_stop = tp->note[ctr3]->pos; //Initialize variables in order to track if the trill phrase can't be properly found if(tp->note[ctr3]->flags & EOF_NOTE_FLAG_IS_TRILL) { //If this note is in a trill phrase //Find which trill phrase it's in for(ctr5 = 0; ctr5 < tp->trills; ctr5++) { //For each trill phrase if((tp->trill[ctr5].difficulty == 0xFF) || (tp->trill[ctr5].difficulty == ctr2)) { //If this trill phrase applies to all difficulties or if it otherwise applies to this note's difficulty if((tp->trill[ctr5].start_pos <= tp->note[ctr3]->pos) && (tp->trill[ctr5].end_pos >= tp->note[ctr3]->pos)) { //If the note is inside this trill phrase trill_start = tp->trill[ctr5].start_pos; trill_stop = tp->trill[ctr5].end_pos; break; } } } //Determine if this is the first note in the trill phrase, and if so, what note it trills with if(trill_start != trill_stop) { //If a trill phrase was identified for(ctr5 = 0; ctr5 < tp->notes; ctr5++) { //For each note in the track if(eof_get_note_type(sp, ctr, ctr3) != ctr2) continue; //If the note is not in this difficulty, skip it if(tp->note[ctr5]->pos > trill_stop) break; //Stop looking at notes if the trill has already been passed if(tp->note[ctr5]->pos < trill_start) continue; //If the note is not within the trill phrase if(ctr5 != ctr3) { //If the note being written to XML is not this note break; //Don't export it with trill technique } next = eof_fixup_next_pro_guitar_note(tp, ctr5); if((next > 0) && (tp->note[next]->pos <= trill_stop)) { //If the next note in the track difficulty is also in this trill phrase if((tp->note[next]->note & bitmask) && ((tp->note[next]->frets[next] & 0x7F) > (tp->note[ctr3]->frets[ctr4] & 0x7F))) { //If the next note has a gem on the target string and its fret value is higher than that of the note being currently written to XML trillwith = tp->note[next]->frets[ctr4] & 0x7F; //This is the fret value being trilled with } } break; }//For each note in the track }//If a trill phrase was identified }//If this note is in a trill phrase (void) eof_get_rs_techniques(sp, ctr, ctr3, ctr4, &tech, 2, 1); //Determine techniques used by this note (honoring technotes where applicable) notepos = eof_get_note_pos(sp, ctr, ctr3); fret = tp->note[ctr3]->frets[ctr4] & 0x7F; //Get the fret value for this string (mask out the muting bit) finger = eof_pro_guitar_note_lookup_string_fingering(tp, ctr3, ctr4, 1); //Unless a more suitable fingering for this note can be determined, assume 1 (index) if(tech.length < 10) { //The sustain is one digit sustainpadding = " "; } else if(tech.length < 100) { //The sustain is two digits sustainpadding = " "; } else if(tech.length < 1000) { //The sustain is three digits sustainpadding = " "; } else { //It's four or more digits sustainpadding = ""; } fret += tp->capo; //Compensate for the the capo position if applicable stringnum = tp->numstrings - ctr4; //Convert to tab string numbering (low E is string 6 in a 6 string track, string 4 on a 4 string track, etc) (void) snprintf(buffer, sizeof(buffer) - 1, " <note time=\"%lu\" linkNext=\"%d\" bend=\"%lu\" fret=%s\"%lu\" hammerOn=\"%d\" harmonic=\"%d\" hopo=\"%d\" ignore=\"0\" mute=\"%d\" palmMute=\"%d\" pluck=\"%d\" pullOff=\"%d\" slap=\"%d\" slideTo=\"%ld\" string=\"%lu\" sustain=%s\"%lu\" tremolo=\"%d\" harmonicPinch=\"%d\" slideUnpitchTo=\"%ld\" trillwith=\"%d\" finger=\"%lu\" vibrato=\"%d\"/>\n", notepos, tech.linknext, tech.bendstrength_h, ((fret < 10) ? " " : ""), fret, tech.hammeron, tech.harmonic, tech.hopo, tech.stringmute, tech.palmmute, tech.pop, tech.pulloff, tech.slap, tech.slideto, stringnum, sustainpadding, tech.length, tech.tremolo, tech.pinchharmonic, tech.unpitchedslideto, trillwith, finger, tech.vibrato); (void) pack_fputs(buffer, fp); }//For each string in this track }//For each note in the track //Remove any automatically generated fret hand positions if(anchorsgenerated) { //If anchors were automatically generated for this track difficulty, remove them now for(ctr3 = tp->handpositions; ctr3 > 0; ctr3--) { //For each hand position defined in the track, in reverse order if(tp->handposition[ctr3 - 1].difficulty == ctr2) { //If the hand position is in this difficulty eof_pro_guitar_track_delete_hand_position(tp, ctr3 - 1); //Delete the hand position } } } (void) pack_fputs(" </notes>\n", fp); (void) pack_fputs(" </level>\n", fp); }//For each of the first 6 difficulties (void) pack_fputs(" </arrangement>\n", fp); }//If this track is populated eof_menu_track_set_tech_view_state(sp, ctr, restore_tech_view); //Re-enable tech view if applicable }//For each track (void) pack_fputs("</Bandfuse>\n", fp); //Cleanup (void) pack_fclose(fp); return 1; //Return success }
/* saves a wave file to file pointer */ static int save_wav_fp(SAMPLE * sp, PACKFILE * fp) { size_t channels, bits, freq; size_t data_size; size_t samples; size_t i, n; void * pval = NULL; unsigned short *data; eof_log("save_wav_fp() entered", 1); if(!sp || !fp) { return 0; } channels = sp->stereo ? (size_t)2 : (size_t)1; bits = (size_t)sp->bits; samples = (size_t)sp->len; data_size = samples * channels * (bits / 8); n = samples * channels; freq = (size_t)sp->freq; (void) pack_fputs("RIFF", fp); (void) pack_iputl(36 + (long)data_size, fp); (void) pack_fputs("WAVE", fp); (void) pack_fputs("fmt ", fp); (void) pack_iputl(16, fp); (void) pack_iputw(1, fp); (void) pack_iputw((int)channels, fp); (void) pack_iputl((long)freq, fp); (void) pack_iputl((long)(freq * channels * (bits / 8)), fp); //ByteRate = SampleRate * NumChannels * BitsPerSample/8 (void) pack_iputw((int)(channels * (bits / 8)), fp); (void) pack_iputw((int)bits, fp); (void) pack_fputs("data", fp); (void) pack_iputl((long)data_size, fp); if(bits == 8) { pval = sp->data; (void) pack_fwrite(pval, (long)(samples * channels), fp); } else if(bits == 16) { data = (unsigned short *)sp->data; for (i = 0; i < n; i++) { (void) pack_iputw((short)(data[i] - 0x8000), fp); } } else { (void) snprintf(eof_log_string, sizeof(eof_log_string) - 1, "Unknown audio depth (%lu) when saving wav ALLEGRO_FILE.", (unsigned long) bits); eof_log(eof_log_string, 1); return 0; } return 1; }
/* main: * Guess what this function does. */ int main(int argc, char *argv[]) { PACKFILE *f; CFURLRef cf_url_ref; FSRef fs_ref; FSSpec fs_spec; IconFamilyHandle icon_family; Handle raw_data; char datafile[MAX_STRING_SIZE]; char bundle[MAX_STRING_SIZE]; char bundle_dir[MAX_STRING_SIZE]; char bundle_contents_dir[MAX_STRING_SIZE]; char bundle_contents_resources_dir[MAX_STRING_SIZE]; char bundle_contents_macos_dir[MAX_STRING_SIZE]; char bundle_contents_frameworks_dir[MAX_STRING_SIZE]; char *bundle_exe = NULL; char bundle_plist[MAX_STRING_SIZE]; char bundle_pkginfo[MAX_STRING_SIZE]; char bundle_icns[MAX_STRING_SIZE]; char bundle_version[MAX_STRING_SIZE]; char bundle_long_version[MAX_STRING_SIZE]; char *buffer = NULL; int arg, type = 0, result = 0; int i, size, x, y, mask_bit, mask_byte; unsigned char *data; install_allegro(SYSTEM_NONE, &errno, &atexit); set_color_depth(32); set_color_conversion(COLORCONV_TOTAL | COLORCONV_KEEP_TRANS); if (argc < 2) usage(); datafile[0] = '\0'; bundle[0] = '\0'; select_palette(black_palette); /* Parse command line and load any given resource */ for (arg = 2; arg < argc; arg++) { if (!strcmp(argv[arg], "-m")) flags |= F_MOVE; else if (!strcmp(argv[arg], "-e")) flags |= F_EMBED_FRAMEWORK; else if (!strcmp(argv[arg], "-o")) { if ((argc < arg + 2) || (bundle[0] != '\0')) usage(); strcpy(bundle, argv[++arg]); } else if (!strcmp(argv[arg], "-v")) { if (argc < arg + 2) usage(); flags |= F_GOT_VERSION; strcpy(bundle_version, argv[++arg]); } else if (!strcmp(argv[arg], "-V")) { if (argc < arg + 2) usage(); flags |= F_GOT_LONG_VERSION; strcpy(bundle_long_version, argv[++arg]); } else if (!strcmp(argv[arg], "-d")) { if (argc < arg + 2) usage(); strcpy(datafile, argv[++arg]); } else if ((!strcmp(argv[arg], "-16")) || (!strcmp(argv[arg], "-32")) || (!strcmp(argv[arg], "-48")) || (!strcmp(argv[arg], "-128"))) { if (argc < arg + 2) usage(); switch (atoi(&argv[arg][1])) { case 16: type = 0; break; case 32: type = 1; break; case 48: type = 2; break; case 128: type = 3; break; } if (load_resource(datafile, argv[++arg], &icon_data[type])) { result = -1; goto exit_error; } } else { if (load_resource(datafile, argv[arg], NULL)) { result = -1; goto exit_error; } } } buffer = malloc(4096); if (!buffer) { result = -1; goto exit_error_bundle; } bundle_exe = argv[1]; if (!exists(bundle_exe)) { fprintf(stderr, "Cannot locate executable file '%s'\n", bundle_exe); result = -1; goto exit_error; } if (bundle[0] == '\0') strcpy(bundle, bundle_exe); replace_extension(bundle_dir, bundle, "app", MAX_STRING_SIZE); strcpy(bundle_contents_dir, bundle_dir); strcat(bundle_contents_dir, "/Contents"); strcpy(bundle_contents_resources_dir, bundle_contents_dir); strcat(bundle_contents_resources_dir, "/Resources"); strcpy(bundle_contents_macos_dir, bundle_contents_dir); strcat(bundle_contents_macos_dir, "/MacOS"); strcpy(bundle_contents_frameworks_dir, bundle_contents_dir); strcat(bundle_contents_frameworks_dir, "/Frameworks"); bundle_icns[0] = '\0'; bundle_plist[0] = '\0'; bundle_pkginfo[0] = '\0'; /* Create bundle structure */ if ((mkdir(bundle_dir, 0777) && (errno != EEXIST)) || (mkdir(bundle_contents_dir, 0777) && (errno != EEXIST)) || (mkdir(bundle_contents_resources_dir, 0777) && (errno != EEXIST)) || (mkdir(bundle_contents_macos_dir, 0777) && (errno != EEXIST))) { fprintf(stderr, "Cannot create %s\n", bundle_dir); result = -1; goto exit_error_bundle; } /* Copy/move executable into the bundle */ if (copy_file(bundle_exe, bundle_contents_macos_dir)) { fprintf(stderr, "Cannot create %s\n", bundle_contents_macos_dir); result = -1; goto exit_error_bundle; } strcat(bundle_contents_macos_dir, "/"); strcat(bundle_contents_macos_dir, get_filename(bundle_exe)); chmod(bundle_contents_macos_dir, 0755); if (flags & F_MOVE) unlink(bundle_exe); /* Embed Allegro framework if requested */ if (flags & F_EMBED_FRAMEWORK) { if (!file_exists("/Library/Frameworks/Allegro.framework", FA_RDONLY | FA_DIREC, NULL)) { fprintf(stderr, "Cannot find Allegro framework\n"); result = -1; goto exit_error_bundle; } if (!exists("/Library/Frameworks/Allegro.framework/Resources/Embeddable")) { fprintf(stderr, "Cannot embed system wide Allegro framework; install embeddable version first!\n"); result = -1; goto exit_error_bundle; } sprintf(buffer, "/Developer/Tools/pbxcp -exclude .DS_Store -exclude CVS -resolve-src-symlinks /Library/Frameworks/Allegro.framework %s", bundle_contents_frameworks_dir); if ((mkdir(bundle_contents_frameworks_dir, 0777) && (errno != EEXIST)) || (system(buffer))) { fprintf(stderr, "Cannot create %s\n", bundle_contents_frameworks_dir); result = -1; goto exit_error_bundle; } } /* Setup the .icns resource */ if (flags & F_ICONS_DEFINED) { strcat(bundle_contents_resources_dir, "/"); strcat(bundle_contents_resources_dir, get_filename(bundle)); replace_extension(bundle_icns, bundle_contents_resources_dir, "icns", MAX_STRING_SIZE); icon_family = (IconFamilyHandle)NewHandle(0); for (i = 0; i < 4; i++) { if (flags & icon_data[i].defined) { /* Set 32bit RGBA data */ raw_data = NewHandle(icon_data[i].size * icon_data[i].size * 4); data = *(unsigned char **)raw_data; for (y = 0; y < icon_data[i].size; y++) { for (x = 0; x < icon_data[i].size; x++) { *data++ = geta32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); *data++ = getr32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); *data++ = getg32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); *data++ = getb32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); } } if (SetIconFamilyData(icon_family, icon_data[i].data, raw_data) != noErr) { DisposeHandle(raw_data); fprintf(stderr, "Error setting %dx%d icon resource RGBA data\n", icon_data[i].size, icon_data[i].size); result = -1; goto exit_error_bundle; } DisposeHandle(raw_data); /* Set 8bit mask */ raw_data = NewHandle(icon_data[i].size * icon_data[i].size); data = *(unsigned char **)raw_data; for (y = 0; y < icon_data[i].size; y++) { for (x = 0; x < icon_data[i].size; x++) { *data++ = geta32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]); } } if (SetIconFamilyData(icon_family, icon_data[i].mask8, raw_data) != noErr) { DisposeHandle(raw_data); fprintf(stderr, "Error setting %dx%d icon resource 8bit mask\n", icon_data[i].size, icon_data[i].size); result = -1; goto exit_error_bundle; } DisposeHandle(raw_data); /* Set 1bit mask */ if (icon_data[i].mask1) { size = ((icon_data[i].size * icon_data[i].size) + 7) / 8; raw_data = NewHandle(size * 2); data = *(unsigned char **)raw_data; mask_byte = 0; mask_bit = 7; for (y = 0; y < icon_data[i].size; y++) { for (x = 0; x < icon_data[i].size; x++) { if (geta32(((unsigned int *)(icon_data[i].scaled->line[y]))[x]) >= 0xfd) mask_byte |= (1 << mask_bit); mask_bit--; if (mask_bit < 0) { *data++ = mask_byte; mask_byte = 0; mask_bit = 7; } } } memcpy(*raw_data + size, *raw_data, size); if (SetIconFamilyData(icon_family, icon_data[i].mask1, raw_data) != noErr) { DisposeHandle(raw_data); fprintf(stderr, "Error setting %dx%d icon resource 1bit mask\n", icon_data[i].size, icon_data[i].size); result = -1; goto exit_error_bundle; } DisposeHandle(raw_data); } } } f = pack_fopen(bundle_icns, F_WRITE); if (!f) { fprintf(stderr, "Cannot create %s\n", bundle_icns); result = -1; goto exit_error_bundle; } pack_fclose(f); cf_url_ref = CFURLCreateWithBytes(kCFAllocatorDefault, (unsigned char *)bundle_icns, strlen(bundle_icns), 0, NULL); if (!cf_url_ref) { fprintf(stderr, "Cannot create %s\n", bundle_icns); result = -1; goto exit_error_bundle; } CFURLGetFSRef(cf_url_ref, &fs_ref); CFRelease(cf_url_ref); if ((FSGetCatalogInfo(&fs_ref, kFSCatInfoNone, NULL, NULL, &fs_spec, NULL)) || (WriteIconFile(icon_family, &fs_spec) != noErr)) { fprintf(stderr, "Cannot create %s\n", bundle_icns); result = -1; goto exit_error_bundle; } DisposeHandle((Handle)icon_family); } /* Setup Info.plist */ sprintf(bundle_plist, "%s/Info.plist", bundle_contents_dir); f = pack_fopen(bundle_plist, F_WRITE); if (!f) { fprintf(stderr, "Cannot create %s\n", bundle_plist); result = -1; goto exit_error_bundle; } sprintf(buffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" "<plist version=\"1.0\">\n" "<dict>\n" "\t<key>CFBundleExecutable</key>\n" "\t<string>%s</string>\n" "\t<key>CFBundleInfoDictionaryVersion</key>\n" "\t<string>6.0</string>\n" "\t<key>CFBundlePackageType</key>\n" "\t<string>APPL</string>\n" "\t<key>CFBundleSignature</key>\n" "\t<string>%s</string>\n" "\t<key>CFBundleVersion</key>\n" "\t<string>%s</string>\n" "\t<key>CFBundleDocumentTypes</key>\n" "\t<array>\n" "\t\t<dict>\n" "\t\t\t<key>CFBundleTypeExtensions</key>\n" "\t\t\t<array>\n" "\t\t\t\t<string>*</string>\n" "\t\t\t</array>\n" "\t\t\t<key>CFBundleTypeName</key>\n" "\t\t\t<string>NSStringPboardType</string>\n" "\t\t\t<key>CFBundleTypeOSTypes</key>\n" "\t\t\t<array>\n" "\t\t\t\t<string>****</string>\n" "\t\t\t</array>\n" "\t\t\t<key>CFBundleTypeRole</key>\n" "\t\t\t<string>Viewer</string>\n" "\t\t</dict>\n" "\t</array>\n", get_filename(bundle_exe), "????", (flags & F_GOT_VERSION) ? bundle_version : "1.0"); pack_fputs(buffer, f); if (flags & F_GOT_LONG_VERSION) { sprintf(buffer, "\t<key>CFBundleGetInfoString</key>\n" "\t<string>%s</string>\n", bundle_long_version); pack_fputs(buffer, f); } if (flags & F_ICONS_DEFINED) { sprintf(buffer, "\t<key>CFBundleIconFile</key>\n" "\t<string>%s</string>\n", get_filename(bundle_icns)); pack_fputs(buffer, f); } pack_fputs("</dict>\n</plist>\n", f); pack_fclose(f); /* Setup PkgInfo */ sprintf(bundle_pkginfo, "%s/PkgInfo", bundle_contents_dir); f = pack_fopen(bundle_pkginfo, F_WRITE); if (!f) { fprintf(stderr, "Cannot create %s\n", bundle_pkginfo); result = -1; goto exit_error_bundle; } pack_fputs("APPL????", f); pack_fclose(f); exit_error: if (buffer) free(buffer); for (i = 0; i < 4; i++) { if (icon_data[i].original) destroy_bitmap(icon_data[i].original); if (icon_data[i].workspace) destroy_bitmap(icon_data[i].workspace); if (icon_data[i].scaled) destroy_bitmap(icon_data[i].scaled); } return result; exit_error_bundle: sprintf(buffer, "%s/%s", bundle_contents_macos_dir, get_filename(bundle_exe)); unlink(buffer); unlink(bundle_plist); unlink(bundle_pkginfo); unlink(bundle_icns); rmdir(bundle_dir); rmdir(bundle_contents_dir); rmdir(bundle_contents_resources_dir); rmdir(bundle_contents_macos_dir); goto exit_error; }