/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
#if defined(__MWERKS__) && !defined(__private_extern__)
#define __private_extern__ __declspec(private_extern)
#endif

#include "stuff/ofile.h"

/*
 * This is used to build the table of contents of an archive.  Each toc_entry
 * Contains a pointer to a symbol name that is defined by a member of the
 * archive.  The member that defines this symbol is referenced by its index in
 * the archive plus one.  This is done so the negative value if the index can
 * be used for marking then later to generate the ran_off field with the byte
 * offset.
 */
struct toc_entry {
    char *symbol_name;
    int32_t member_index;
};

/*
 * The input files are broken out in to their object files and then placed in
 * these structures.  These structures are then used to edit the object files'
 * symbol table.  And then finally used to reassemble the object file for
 * output.
 */
struct arch {
    char *file_name;		/* name of file this arch came from */
    enum ofile_type type;	/* The type of file for this architecture */
				/*  can be OFILE_ARCHIVE, OFILE_Mach_O, */
    				/*  OFILE_LLVM_BITCODE or OFILE_UNKNOWN. */
    struct fat_arch *fat_arch;	/* If this came from fat file this is valid */
			        /*  and not NULL (needed for the align value */
				/*  and to output a fat file if only one arch)*/
    char *fat_arch_name;	/* If this came from fat file this is valid */
				/*  and is tthe name of this architecture */
				/*  (used for error messages). */

    /* if this is an archive: the members of this archive */
    struct member *members;	/* the members of the library for this arch */
    uint32_t       nmembers;	/* the number of the above members */
    /*
     * The output table of contents (toc) for this arch in the library (this
     * must be recreated, or at least the time of the toc member set, when
     * the output is modified because modifiy time is shared by all libraries
     * in the file).
     */
    uint32_t       toc_size;	/* total size of the toc including ar_hdr */
    struct ar_hdr  toc_ar_hdr;	/* the archive header for this member */
    enum bool      toc_long_name;/* use the long name in the output */
    char	  *toc_name;	 /* name of toc member */
    uint32_t       toc_name_size;/* size of name of toc member */
    uint32_t       ntocs;	/* number of table of contents entries */
    struct toc_entry
		  *toc_entries; /* the table of contents entries */
    struct ranlib *toc_ranlibs;	/* the ranlib structs */
    char	  *toc_strings;	/* strings of symbol names for toc entries */
    uint32_t       toc_strsize;	/* number of bytes for the strings above */
    uint32_t	  library_size;	/* current working size and final output size */
				/*  for this arch when it's a library (used */
				/*  for creating the toc entries). */

    /* if this is an object file: the object file */
    struct object *object;	/* the object file */

#ifdef LTO_SUPPORT
    /* if this member is an llvm bit code file: the lto module */
    void *lto;                  /* lto module */
#endif /* LTO_SUPPORT */

    /* if this is an unknown file: the addr and size of the file */
    char *unknown_addr;
    uint32_t unknown_size;

    /* don't update LC_ID_DYLIB timestamp */
    enum bool dont_update_LC_ID_DYLIB_timestamp;
};

struct member {
    enum ofile_type type;	/* the type of this member can be OFILE_Mach_O*/
				/*  OFILE_LLVM_BITCODE or OFILE_UNKNOWN */
    struct ar_hdr *ar_hdr;	/* the archive header for this member */
    uint32_t offset;		/* current working offset and final offset */
				/*  use in creating the table of contents */

    /* the name of the member in the output */
    char         *member_name;	    /* the member name */
    uint32_t      member_name_size; /* the size of the member name */
    enum bool     member_long_name; /* use the extended format #1 for the
				       member name in the output */

    /* if this member is an object file: the object file */
    struct object *object;	/* the object file */

#ifdef LTO_SUPPORT
    /* if this member is an llvm bit code file: the lto module */
    void *lto;                  /* lto module */
#endif /* LTO_SUPPORT */

    /* if this member is an unknown file: the addr and size of the member */
    char *unknown_addr;
    uint32_t unknown_size;

    /*
     * If this member was created from a file then input_file_name is set else
     * it is NULL and input_ar_hdr is set (these are recorded to allow
     * warn_member() messages to be printed)
     */
    char *input_file_name;
    struct ar_hdr *input_ar_hdr;
};

struct object {
    char *object_addr;		    /* the address of the object file */
    uint32_t object_size;	    /* the size of the object file on input */
    enum byte_sex object_byte_sex;  /* the byte sex of the object file */
    struct mach_header *mh;	    /* the mach_header of 32-bit object file */
    struct mach_header_64 *mh64;    /* the mach_header of 64-bit object file */
    /* these copied from the mach header above */
    cpu_type_t mh_cputype;	    /* cpu specifier */
    cpu_subtype_t mh_cpusubtype;    /* machine specifier */
    uint32_t mh_filetype;	    /* type of file */
    struct load_command		    /* the start of the load commands */
	*load_commands;
    struct symtab_command *st;	    /* the symbol table command */
    struct dysymtab_command *dyst;  /* the dynamic symbol table command */
    struct twolevel_hints_command   /* the two-level namespace hints command */
	*hints_cmd;
    struct prebind_cksum_command *cs;/* the prebind check sum command */
    struct segment_command
	*seg_linkedit;	    	    /* the 32-bit link edit segment command */
    struct segment_command_64
	*seg_linkedit64;    	    /* the 64-bit link edit segment command */
    struct linkedit_data_command
	*code_sig_cmd;	    	    /* the code signature load command, if any*/
    struct linkedit_data_command
	*split_info_cmd;    	    /* the split info load command, if any*/
    struct linkedit_data_command
	*func_starts_info_cmd; 	    /* the func starts load command, if any*/
    struct linkedit_data_command
	*data_in_code_cmd;	    /* the data in code load command, if any */
    struct linkedit_data_command
	*code_sign_drs_cmd;	    /* the code signing DRs command, if any */
    struct linkedit_data_command
	*link_opt_hint_cmd;	    /* the linker optimization hint command,
				       if any */
    struct section **sections;	    /* array of 32-bit section structs */
    struct section_64 **sections64; /* array of 64-bit section structs */
    struct dyld_info_command
	*dyld_info;		    /* the LC_DYLD_INFO command,if any */

    /*
     * This is only used for redo_prebinding and is calculated by breakout()
     * if the calculate_input_prebind_cksum parameter is TRUE and there is an
     * LC_PREBIND_CKSUM load command that has a zero value for the cksum field
     * (if so this will be value of the cksum field on output).
     */
    uint32_t calculated_input_prebind_cksum;

    /*
     * New content to be added to the output file just after where the input
     * sym info was.
     */
    char *output_new_content;
    uint32_t output_new_content_size;

    uint32_t input_sym_info_size;
    uint32_t output_sym_info_size;

    /*
     * For 64-bit Mach-O files they may have an odd number of indirect symbol
     * table entries so the next offset MAYBE or MAY NOT be rounded to a
     * multiple of 8. input_indirectsym_pad contains the amount of padding in
     * that was in the input.
     */
    uint32_t input_indirectsym_pad;

    char *output_dyld_info;
    uint32_t      output_dyld_info_size;
    struct nlist *output_symbols;
    struct nlist_64 *output_symbols64;
    uint32_t      output_nsymbols;
    char	 *output_strings;
    uint32_t      output_strings_size;
    char *output_code_sig_data;
    uint32_t      output_code_sig_data_size;
    char *output_split_info_data;
    uint32_t      output_split_info_data_size;
    char *output_func_start_info_data;
    uint32_t      output_func_start_info_data_size;
    char *output_data_in_code_info_data;
    uint32_t      output_data_in_code_info_data_size;
    char *output_code_sign_drs_info_data;
    uint32_t      output_code_sign_drs_info_data_size;
    char *output_link_opt_hint_info_data;
    uint32_t      output_link_opt_hint_info_data_size;

    uint32_t      output_ilocalsym;
    uint32_t      output_nlocalsym;
    uint32_t      output_iextdefsym;
    uint32_t      output_nextdefsym;
    uint32_t      output_iundefsym;
    uint32_t      output_nundefsym;

    struct twolevel_hint *output_hints;

    struct relocation_info *output_loc_relocs;
    struct relocation_info *output_ext_relocs;
    uint32_t *output_indirect_symtab;

    struct dylib_table_of_contents *output_tocs;
    uint32_t      output_ntoc;
    struct dylib_module *output_mods;
    struct dylib_module_64 *output_mods64;
    uint32_t      output_nmodtab;
    struct dylib_reference *output_refs;
    uint32_t      output_nextrefsyms;

    /*
     * For strip(1) to strip DWARF debug info it must run ld -r on the original
     * object contents and overwrite it with that output.  That output is mapped
     * by this ofile struct and is cleaned up when strip is done with the arch
     * that contains this object.
     */
    struct ofile *ld_r_ofile;
};

extern struct ofile * breakout(
    char *filename,
    struct arch **archs,
    uint32_t *narchs,
    enum bool calculate_input_prebind_cksum);

extern struct ofile * breakout_mem(
    void *membuf,
    uint32_t length,
    char *filename,
    struct arch **archs,
    uint32_t *narchs,
    enum bool calculate_input_prebind_cksum);

extern void free_archs(
    struct arch *archs,
    uint32_t narchs);

extern void writeout(
    struct arch *archs,
    uint32_t narchs,
    char *output,
    unsigned short mode,
    enum bool sort_toc,
    enum bool commons_in_toc,
    enum bool library_warnings,
    uint32_t *throttle);

extern void writeout_to_mem(
    struct arch *archs,
    uint32_t narchs,
    char *filename,
    void **outputbuf,
    uint32_t *length,
    enum bool sort_toc,
    enum bool commons_in_toc,
    enum bool library_warning,
    enum bool *seen_archive);

extern void checkout(
    struct arch *archs,
    uint32_t narchs);

void warning_arch(
    struct arch *arch,
    struct member *member,
    char *format, ...)
#ifdef __GNUC__
    __attribute__ ((format (printf, 3, 4)))
#endif
    ;

void error_arch(
    struct arch *arch,
    struct member *member,
    char *format, ...)
#ifdef __GNUC__
    __attribute__ ((format (printf, 3, 4)))
#endif
    ;

void fatal_arch(
    struct arch *arch,
    struct member *member,
    char *format, ...)
#ifdef __GNUC__
    __attribute__ ((format (printf, 3, 4)))
#endif
    ;
