imp_ar.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /* imp_ar.c: Routines to import an archive file
  2. Copyright (C) 2002-2003 Sebastian Reichelt
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  14. #include "imp_ar.h"
  15. #include "../formats/ar.h"
  16. #include "import.h"
  17. #include "../manip.h"
  18. #include "../special.h"
  19. #include <string.h>
  20. #include <stdlib.h>
  21. // Add an archive to the program's list of available archives.
  22. // Do not free the data related to the File parameter after this.
  23. BOOLEAN AddArchiveFile (PROGRAM *Program, const I1 *File, SIZE FileSize, const char *FileName)
  24. {
  25. // Check if memory allocation was successful.
  26. #define TestMem(Ptr) ({ if (!(Ptr)) { Error (FileName, "Out of memory."); return FALSE; } })
  27. // Check if a given object with a given type is completely inside the file.
  28. #define IsInFile(Ptr,Type) (((const I1 *) (Ptr)) >= File && ((const I1 *) (Ptr)) + sizeof (Type) <= File + FileSize)
  29. #define TestInFile(Ptr,Type) ({ if (!(IsInFile (Ptr, Type))) { Error (FileName, "Corrupt archive file."); return FALSE; } })
  30. if (IsArchiveFile (File, FileSize))
  31. {
  32. const AR_MEMBER_HEADER *SymbolTableHeader = (const AR_MEMBER_HEADER *) (File + AR_FILE_HEADER_SIZE);
  33. const AR_SYMBOL_TABLE_HEADER *SymbolTable = (const AR_SYMBOL_TABLE_HEADER *) (SymbolTableHeader + 1);
  34. TestInFile (SymbolTableHeader, AR_MEMBER_HEADER);
  35. // Check the magic string.
  36. if (!(strncmp (SymbolTableHeader->Magic, AR_MEMBER_MAGIC, sizeof (SymbolTableHeader->Magic))))
  37. {
  38. // Check whether the file contains a symbol table (Name is "/", padded with spaces).
  39. if (SymbolTableHeader->Name [0] == '/' && SymbolTableHeader->Name [1] == ' ')
  40. {
  41. COUNT SymCount;
  42. const char *SymbolTableStrings;
  43. TestInFile (&(SymbolTable->SymbolCount), TI4);
  44. TestInFile (&(SymbolTable->PSymbols), TI4 [SymCount = ReadTI4 (SymbolTable->SymbolCount)]);
  45. SymbolTableStrings = (const char *) (&(SymbolTable->PSymbols [SymCount]));
  46. // Add a new entry to the program's archive files.
  47. {
  48. ARCHIVE *Archive = calloc (1, sizeof (ARCHIVE));
  49. TestMem (Archive);
  50. Archive->Parent = Program;
  51. Archive->Data = File;
  52. Archive->Size = FileSize;
  53. Archive->FileName = FileName;
  54. Append (Program->Archives, Archive);
  55. {
  56. OFFSET CurSym;
  57. const char *CurStr = SymbolTableStrings;
  58. // Add all symbols to our own list of exported symbols.
  59. for (CurSym = 0; CurSym < SymCount; CurSym++)
  60. {
  61. TestInFile (CurStr, char);
  62. {
  63. ARCHIVE_SYMBOL *Symbol = calloc (1, sizeof (ARCHIVE_SYMBOL));
  64. TestMem (Symbol);
  65. Symbol->Parent = Archive;
  66. Symbol->Name = CurStr;
  67. Symbol->ObjectFile = GetArchiveObject (Archive, ReadTI4 (SymbolTable->PSymbols [CurSym]));
  68. if (strstr (CurStr, SYMOP_NOT))
  69. Symbol->ContainsInversion = TRUE;
  70. Append (Archive->Symbols, Symbol);
  71. CheckGlobalImports (Program, Symbol);
  72. }
  73. CurStr += strlen (CurStr) + 1;
  74. }
  75. }
  76. }
  77. return TRUE;
  78. }
  79. else
  80. {
  81. Error (FileName, "Archive has no symbol table.");
  82. return FALSE;
  83. }
  84. }
  85. else
  86. {
  87. Error (FileName, "Corrupt archive file (magic string mismatch).");
  88. return FALSE;
  89. }
  90. }
  91. else
  92. {
  93. Error (FileName, "Not an archive file.");
  94. return FALSE;
  95. }
  96. #undef TestInFile
  97. #undef IsInFile
  98. #undef TestMem
  99. }
  100. // Import an object file inside an archive file into the internal data
  101. // structures.
  102. BOOLEAN ImportArchiveObject (PROGRAM *Program, ARCHIVE_OBJECT *Object)
  103. {
  104. // Check if a given object with a given type is completely inside the file.
  105. #define IsInFile(Ptr,Type) (((const I1 *) (Ptr)) >= Archive->Data && ((const I1 *) (Ptr)) + sizeof (Type) <= Archive->Data + Archive->Size)
  106. #define TestInFile(Ptr,Type) ({ if (!(IsInFile (Ptr, Type))) { Error (Archive->FileName, "Corrupt archive file."); return FALSE; } })
  107. // Safety check for the ImportArchiveSymbol macro.
  108. if (!Object)
  109. return FALSE;
  110. // Do not import a file twice.
  111. if (!(Object->Imported))
  112. {
  113. ARCHIVE *Archive = Object->Parent;
  114. // Find the location of the appropriate object file.
  115. const AR_MEMBER_HEADER *ObjectFileHeader = (const AR_MEMBER_HEADER *) (Archive->Data + Object->FileOffset);
  116. const I1 *ObjectFile = (const I1 *) (ObjectFileHeader + 1);
  117. SIZE ObjectFileSize;
  118. TestInFile (ObjectFileHeader, AR_MEMBER_HEADER);
  119. // Check the magic string.
  120. if (!(strncmp (ObjectFileHeader->Magic, AR_MEMBER_MAGIC, sizeof (ObjectFileHeader->Magic))))
  121. {
  122. // Get the size of the file.
  123. ObjectFileSize = strtol (ObjectFileHeader->Size, NULL, 10);
  124. // Check whether the file is completely inside the archive.
  125. TestInFile (ObjectFile, I1 [ObjectFileSize]);
  126. if (ObjectFileSize > 0)
  127. {
  128. // Mark the file as imported.
  129. Object->Imported = TRUE;
  130. // Import the file.
  131. return (ImportObjectFile (Program, ObjectFile, ObjectFileSize, Archive->FileName));
  132. }
  133. else
  134. {
  135. Error (Archive->FileName, "Corrupt object in archive.");
  136. return FALSE;
  137. }
  138. }
  139. else
  140. {
  141. Error (Archive->FileName, "Corrupt archive file (magic string mismatch).");
  142. return FALSE;
  143. }
  144. }
  145. else
  146. return TRUE;
  147. #undef TestInFile
  148. #undef IsInFile
  149. }