1 /* exp_ar.c: Routines to export an archive file
2 
3    Copyright (C) 2003 Sebastian Reichelt
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 
19 #include "exp_ar.h"
20 
21 #include "../../formats/ar.h"
22 
23 #include <string.h>
24 
25 // Export the internal data structures into an archive file.
ExportArchiveFile(const ARCHIVE * Archive,EXP_FILE * File,BOOLEAN NoNames)26 BOOLEAN ExportArchiveFile (const ARCHIVE *Archive, EXP_FILE *File, BOOLEAN NoNames)
27 {
28 	// Call this instead of sprintf to overwrite the terminating null character with a space.
29 #define iprintf(str,fmt...) (str [sprintf (str, fmt)] = ' ')
30 
31 	SYMBOL_TABLE *SymbolTable = Archive->SymbolTable;
32 
33 	// Write the file header.
34 	ExportWrite (File, AR_FILE_HEADER_STRING, AR_FILE_HEADER_SIZE, 1);
35 
36 	// Write the symbol table.
37 	if (SymbolTable)
38 	{
39 		AR_MEMBER_HEADER MemberHeader;
40 
41 		// Fill the entire header with spaces.
42 		memset (&MemberHeader, ' ', sizeof (MemberHeader));
43 
44 		MemberHeader.Name [0] = '/';
45 
46 		// Insert the attributes
47 		iprintf (MemberHeader.Date, "%lu", (long) (StatGetModificationTime (Archive->FileStats)));
48 		iprintf (MemberHeader.UID, "%lu", (long) (StatGetUID (Archive->FileStats)));
49 		iprintf (MemberHeader.GID, "%lu", (long) (StatGetGID (Archive->FileStats)));
50 		iprintf (MemberHeader.Mode, "%lo", (long) (StatGetMode (Archive->FileStats)));
51 		iprintf (MemberHeader.Size, "%lu", (long) (SymbolTable->Size));
52 		memcpy (MemberHeader.Magic, AR_MEMBER_MAGIC, AR_MEMBER_MAGIC_SIZE);
53 
54 		// Write the header.
55 		ExportWrite (File, &MemberHeader, AR_MEMBER_HEADER_SIZE, 1);
56 
57 		// Write the data.
58 		{
59 			OFFSET CurSymbol;
60 
61 			ExportWriteI4 (File, SymbolTable->SymbolCount);
62 
63 			for (CurSymbol = 0; CurSymbol < SymbolTable->SymbolCount; CurSymbol++)
64 			{
65 				SYMBOL *Symbol = SymbolTable->Symbols [CurSymbol];
66 				if (Symbol)
67 					ExportWriteI4 (File, Symbol->Parent->ArMemberOffset);
68 			}
69 
70 			for (CurSymbol = 0; CurSymbol < SymbolTable->SymbolCount; CurSymbol++)
71 			{
72 				SYMBOL *Symbol = SymbolTable->Symbols [CurSymbol];
73 				if (Symbol)
74 					ExportWrite (File, Symbol->Name, strlen (Symbol->Name) + 1, 1);
75 			}
76 		}
77 
78 		// Write the padding.
79 		ExportFill (File, SymbolTable->ArMemberOffset + SymbolTable->ArMemberSize, AR_MEMBER_PADDING_CHAR);
80 	}
81 
82 	// Write the members.
83 	{
84 		OBJECT_FILE *ObjectFile;
85 		OFFSET CurObjectFile = 1;
86 
87 		for_each (ObjectFile, Archive->ObjectFiles)
88 		{
89 			AR_MEMBER_HEADER MemberHeader;
90 
91 			// Fill the entire header with spaces.
92 			memset (&MemberHeader, ' ', sizeof (MemberHeader));
93 
94 			if (NoNames)
95 				// Use an arbitrary name.
96 				iprintf (MemberHeader.Name, "fl%lu.o/", (long) CurObjectFile);
97 			else
98 			{
99 				SIZE NameLen;
100 
101 				// Seach for the last slash.
102 				const char *Name = strrchr (ObjectFile->FileName, '/');
103 				// If none is found, use the last backslash instead.
104 				if (!Name)
105 					Name = strrchr (ObjectFile->FileName, '\\');
106 
107 				// Use only the file name without a path.
108 				if (Name)
109 					Name++;
110 				else
111 					Name = ObjectFile->FileName;
112 
113 				// Insert the name into the header.
114 				NameLen = strlen (Name);
115 				if (NameLen > AR_MEMBER_MAX_NAME_LENGTH)
116 					NameLen = AR_MEMBER_MAX_NAME_LENGTH;
117 				memcpy (MemberHeader.Name, Name, NameLen);
118 				MemberHeader.Name [NameLen] = '/';
119 			}
120 
121 			// Insert the attributes
122 			iprintf (MemberHeader.Date, "%lu", (long) (StatGetModificationTime (ObjectFile->FileStats)));
123 			iprintf (MemberHeader.UID, "%lu", (long) (StatGetUID (ObjectFile->FileStats)));
124 			iprintf (MemberHeader.GID, "%lu", (long) (StatGetGID (ObjectFile->FileStats)));
125 			iprintf (MemberHeader.Mode, "%lo", (long) (StatGetMode (ObjectFile->FileStats)));
126 			iprintf (MemberHeader.Size, "%lu", (long) (ObjectFile->Size));
127 			memcpy (MemberHeader.Magic, AR_MEMBER_MAGIC, AR_MEMBER_MAGIC_SIZE);
128 
129 			// Write the header.
130 			ExportWrite (File, &MemberHeader, AR_MEMBER_HEADER_SIZE, 1);
131 
132 			// Write the data.
133 			ExportWrite (File, ObjectFile->Data, 1, ObjectFile->Size);
134 
135 			// Write the padding.
136 			ExportFill (File, ObjectFile->ArMemberOffset + ObjectFile->ArMemberSize, AR_MEMBER_PADDING_CHAR);
137 
138 			CurObjectFile++;
139 		}
140 	}
141 
142 	return TRUE;
143 }
144