/** * gimp_image_arrange_objects: * @image: The #GimpImage to which the objects belong. * @list: A #GList of objects to be aligned. * @alignment: The point on each target object to bring into alignment. * @reference: The #GObject to align the targets with, or #NULL. * @reference_alignment: The point on the reference object to align the target item with.. * @offset: How much to shift the target from perfect alignment.. * * This function shifts the positions of a set of target objects, which can be * "items" or guides, to bring them into a specified type of alignment with a * reference object, which can be an item, guide, or image. If the requested * alignment does not make sense (i.e., trying to align a vertical guide vertically), * nothing happens and no error message is generated. * * The objects in the list are sorted into increasing order before * being arranged, where the order is defined by the type of alignment * being requested. If the @reference argument is #NULL, then the first * object in the sorted list is used as reference. * * When there are multiple target objects, they are arranged so that the spacing * between consecutive ones is given by the argument @offset. */ void gimp_image_arrange_objects (GimpImage *image, GList *list, GimpAlignmentType alignment, GObject *reference, GimpAlignmentType reference_alignment, gint offset) { gboolean do_x = FALSE; gboolean do_y = FALSE; gint z0 = 0; GList *object_list; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (G_IS_OBJECT (reference) || reference == NULL); /* get offsets used for sorting */ switch (alignment) { /* order vertically for horizontal alignment */ case GIMP_ALIGN_LEFT: case GIMP_ALIGN_HCENTER: case GIMP_ALIGN_RIGHT: do_x = TRUE; compute_offsets (list, GIMP_ALIGN_TOP); break; /* order horizontally for horizontal arrangement */ case GIMP_ARRANGE_LEFT: case GIMP_ARRANGE_HCENTER: case GIMP_ARRANGE_RIGHT: do_x = TRUE; compute_offsets (list, alignment); break; /* order horizontally for vertical alignment */ case GIMP_ALIGN_TOP: case GIMP_ALIGN_VCENTER: case GIMP_ALIGN_BOTTOM: do_y = TRUE; compute_offsets (list, GIMP_ALIGN_LEFT); break; /* order vertically for vertical arrangement */ case GIMP_ARRANGE_TOP: case GIMP_ARRANGE_VCENTER: case GIMP_ARRANGE_BOTTOM: do_y = TRUE; compute_offsets (list, alignment); break; } object_list = sort_by_offset (list); /* now get offsets used for aligning */ compute_offsets (list, alignment); if (reference == NULL) { reference = G_OBJECT (object_list->data); object_list = g_list_next (object_list); } else compute_offset (reference, reference_alignment); z0 = GPOINTER_TO_INT (g_object_get_data (reference, "align-offset")); if (object_list) { GList *l; gint n; /* FIXME: undo group type is wrong */ gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_DISPLACE, C_("undo-type", "Arrange Objects")); for (l = object_list, n = 1; l; l = g_list_next (l), n++) { GObject *target = G_OBJECT (l->data); gint xtranslate = 0; gint ytranslate = 0; gint z1; z1 = GPOINTER_TO_INT (g_object_get_data (target, "align-offset")); if (do_x) xtranslate = z0 - z1 + n * offset; if (do_y) ytranslate = z0 - z1 + n * offset; /* now actually align the target object */ if (GIMP_IS_ITEM (target)) { gimp_item_translate (GIMP_ITEM (target), xtranslate, ytranslate, TRUE); } else if (GIMP_IS_GUIDE (target)) { GimpGuide *guide = GIMP_GUIDE (target); switch (gimp_guide_get_orientation (guide)) { case GIMP_ORIENTATION_VERTICAL: gimp_image_move_guide (image, guide, z1 + xtranslate, TRUE); break; case GIMP_ORIENTATION_HORIZONTAL: gimp_image_move_guide (image, guide, z1 + ytranslate, TRUE); break; default: break; } } } gimp_image_undo_group_end (image); } g_list_free (object_list); }
void analyze_CPK(FILE *infile, long file_length, struct cpk_file *file, int new_file_count) { const long CpkHeader_offset = 0x0; char *toc_string_table = NULL; /* check header */ { unsigned char buf[4]; static const char CPK_signature[4] = "CPK "; /* intentionally unterminated */ get_bytes_seek(CpkHeader_offset, infile, buf, 4); CHECK_ERROR (memcmp(buf, CPK_signature, sizeof(CPK_signature)), "CPK signature not found"); } /* check CpkHeader */ { struct utf_query_result result = query_utf_nofail(infile, CpkHeader_offset+0x10, NULL); CHECK_ERROR (result.rows != 1, "wrong number of rows in CpkHeader"); } /* get TOC offset */ long toc_offset = query_utf_8byte(infile, CpkHeader_offset+0x10, 0, "TocOffset"); /* get content offset */ long content_offset = query_utf_8byte(infile, CpkHeader_offset+0x10, 0, "ContentOffset"); /* get file count from CpkHeader */ long CpkHeader_count = query_utf_4byte(infile, CpkHeader_offset+0x10, 0, "Files"); #ifdef DEBUG printf("(Debug)TocOffset: %d\n(Debug)ContentOffset: %d\n(Debug)Files(Count): %d\n",toc_offset,content_offset,CpkHeader_count); #endif /* check TOC header */ { unsigned char buf[4]; static const char TOC_signature[4] = "TOC "; /* intentionally unterminated */ get_bytes_seek(toc_offset, infile, buf, 4); CHECK_ERROR (memcmp(buf, TOC_signature, sizeof(TOC_signature)), "TOC signature not found"); } /* get TOC entry count, string table offset */ long toc_entries; long toc_string_table_offset; long toc_string_table_size; { struct utf_query_result result = query_utf_nofail(infile, toc_offset+0x10, NULL); toc_entries = result.rows; toc_string_table_offset = toc_offset + 0x10 + 8 + result.string_table_offset; toc_string_table_size = result.data_offset - result.string_table_offset; } #ifdef DEBUG printf("(Debug)TocEntries: %d\n(Debug)TocStringTableOffset: %d\n(Debug)TocStringTableSize:%d\n",toc_entries,toc_string_table_offset,toc_string_table_size); #endif /* check that counts match */ CHECK_ERROR( toc_entries != CpkHeader_count, "CpkHeader file count and TOC entry count do not match" ); /* load string table */ toc_string_table = malloc(toc_string_table_size + 1); { CHECK_ERRNO(!toc_string_table, "malloc"); memset(toc_string_table, 0, toc_string_table_size+1); get_bytes_seek(toc_string_table_offset, infile, (unsigned char *)toc_string_table, toc_string_table_size); } /* find files in cpk */ for (int i = 0; i < toc_entries; i++) { /* get file name */ const char *file_name = query_utf_string(infile, toc_offset+0x10, i, "FileName", toc_string_table); const char *dir_name=query_utf_string(infile,toc_offset+0x10,i,"DirName",toc_string_table); /* to query a file with relative path, remember to free it */ char* query_file=malloc(strlen(dir_name)+strlen(file_name)+2); strcpy(query_file,dir_name); char sep[]="/"; strcat(query_file,sep); strcat(query_file,file_name); int entry_num = contains_file_name(query_file, file, new_file_count); if (entry_num >= 0) { #ifdef DEBUG printf("(Debug)FileName length:%d\n(Debug)DirName length:%d\n",strlen(file_name),strlen(dir_name)); printf("(Debug)query file location:%s\n",query_file); #endif printf("Found %s/%s in cpk\n",dir_name, file_name); /* get file offset */ file[entry_num].orig_offset = content_offset + query_utf_8byte(infile, toc_offset+0x10, i, "FileOffset"); /* get file size */ file[entry_num].orig_size = query_utf_4byte(infile, toc_offset+0x10, i, "FileSize"); /* save index */ file[entry_num].index = i; file[entry_num].found = 1; #ifdef DEBUG printf("(Debug)EntryNum:%d\n",entry_num); #endif } /* free the query_file to avoid leak */ if(query_file) free(query_file); } sort_by_offset(file, new_file_count); FILE *outfile = fopen("out.cpk", "w+b"); printf("Starting file copy\n"); long current = 0; for (int i = 0; i < new_file_count; i++) { if (file[i].found) { /* copy from infile to start of current new file */ dump(infile, outfile, current, file[i].orig_offset-current); current = file[i].orig_offset; /* open new file and copy data */ FILE *newfile = fopen(file[i].location, "rb"); CHECK_ERRNO(!newfile, "fopen"); CHECK_ERRNO(fseek(newfile, 0 , SEEK_END) != 0, "fseek"); file[i].new_size = ftell(newfile); CHECK_ERRNO(file_length == -1, "ftell"); rewind(infile); printf("Copying %s(file name:%s)\n", file[i].location,file[i].filename); dump(newfile, outfile, 0, file[i].new_size); printf("Finished copying %s(file name:%s)\n", file[i].location,file[i].filename); fclose(newfile); /* update information */ current += file[i].orig_size; file[i].copied = 1; file[i].offset_diff = file[i].new_size -file[i].orig_size; } } /* copy remaining data */ dump(infile, outfile, current, file_length-current); printf("Finished file copy\n"); /* fix toc_offset */ toc_offset = fix_offset(outfile, CpkHeader_offset+0x10, 0, 0, "TocOffset", file, new_file_count); printf("Fixed toc offset\n"); /* fix file offsets */ for (int i = 0; i < toc_entries; i++) fix_offset(outfile, toc_offset+0x10, content_offset, i, "FileOffset", file, new_file_count); printf("Fixed file offsets\n"); /* fix file sizes */ for (int i = 0; i < new_file_count; i++) fix_file_sizes(outfile, toc_offset+0x10, file, i); printf("Finished replacing files and fixing data\n"); CHECK_ERRNO(fclose(outfile) != 0, "fclose"); if (toc_string_table) { free(toc_string_table); toc_string_table = NULL; } }