BeLibManger.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. #pragma warning(disable:4996)
  2. #include "BeLibManger.h"
  3. #include "BeefySysLib/util/BeefPerf.h"
  4. #include "BeefySysLib/util/AllocDebug.h"
  5. USING_NS_BF;
  6. BeLibManager gBfLibManager;
  7. void BeLibEntry::AddSymbol(const StringImpl& sym)
  8. {
  9. mSymbols.push_back(sym);
  10. }
  11. //////////////////////////////////////////////////////////////////////////
  12. BeLibFile::BeLibFile()
  13. {
  14. mFailed = false;
  15. }
  16. BeLibFile::~BeLibFile()
  17. {
  18. for (auto& entry : mEntries)
  19. delete entry.mValue;
  20. for (auto& entry : mOldEntries)
  21. delete entry.mValue;
  22. }
  23. bool BeLibFile::ReadLib()
  24. {
  25. BP_ZONE("BeLibFile::ReadLib");
  26. char fileId[8];
  27. mOldFileStream.Read(fileId, 8);
  28. if (strncmp(fileId, "!<arch>\n", 8) != 0)
  29. return false;
  30. const char* libStrTable = NULL;
  31. Dictionary<int, BeLibEntry*> pendingLibEntryMap;
  32. int memberIdx = 0;
  33. while (true)
  34. {
  35. int headerFilePos = mOldFileStream.GetPos();
  36. BeLibMemberHeader header;
  37. mOldFileStream.Read(&header, sizeof(header));
  38. if (mOldFileStream.mReadPastEnd)
  39. break;
  40. int len = atoi(header.mSize);
  41. if (strncmp(header.mName, "/ ", 2) == 0)
  42. {
  43. if (memberIdx == 0)
  44. {
  45. uint8* data = new uint8[len];
  46. mOldFileStream.Read(data, len);
  47. int numSymbols = FromBigEndian(*(int32*)data);
  48. uint8* strTab = data + 4 + numSymbols * 4;
  49. for (int symIdx = 0; symIdx < numSymbols; symIdx++)
  50. {
  51. const char* str = (char*)strTab;
  52. strTab += strlen((char*)strTab) + 1;
  53. int offset = FromBigEndian(((int32*)(data + 4))[symIdx]);
  54. BeLibEntry* pendingEntry;
  55. BeLibEntry** pendingEntryPtr = NULL;
  56. if (!pendingLibEntryMap.TryAdd(offset, NULL, &pendingEntryPtr))
  57. {
  58. pendingEntry = *pendingEntryPtr;
  59. }
  60. else
  61. {
  62. pendingEntry = new BeLibEntry();
  63. pendingEntry->mLibFile = this;
  64. *pendingEntryPtr = pendingEntry;
  65. }
  66. pendingEntry->mSymbols.push_back(str);
  67. }
  68. delete data;
  69. }
  70. else
  71. {
  72. }
  73. }
  74. else if (strncmp(header.mName, "// ", 3) == 0)
  75. {
  76. libStrTable = new char[len];
  77. mOldFileStream.Read((uint8*)libStrTable, len);
  78. }
  79. else
  80. {
  81. String fileName;
  82. if ((header.mName[0] == '/') && (header.mName[1] != '<') && (libStrTable != NULL))
  83. {
  84. int tabIdx = atoi(&header.mName[1]);
  85. for (int checkIdx = tabIdx; true; checkIdx++)
  86. {
  87. char c = libStrTable[checkIdx];
  88. if ((c == 0) || (c == '/'))
  89. {
  90. fileName.Append(&libStrTable[tabIdx], checkIdx - tabIdx);
  91. break;
  92. }
  93. }
  94. }
  95. else
  96. {
  97. for (int i = 0; i < 16; i++)
  98. {
  99. if (header.mName[i] == '/')
  100. fileName.Append(&header.mName[0], i);
  101. }
  102. }
  103. BeLibEntry* libEntry = NULL;
  104. if (!pendingLibEntryMap.TryGetValue(headerFilePos, &libEntry))
  105. {
  106. libEntry = new BeLibEntry();
  107. libEntry->mLibFile = this;
  108. }
  109. BeLibEntry** namedEntry;
  110. if (mOldEntries.TryAdd(fileName, NULL, &namedEntry))
  111. {
  112. *namedEntry = libEntry;
  113. }
  114. else
  115. {
  116. auto prevEntry = *namedEntry;
  117. libEntry->mNextWithSameName = prevEntry->mNextWithSameName;
  118. prevEntry->mNextWithSameName = libEntry;
  119. }
  120. libEntry->mName = fileName;
  121. libEntry->mOldDataPos = headerFilePos;
  122. libEntry->mLength = len;
  123. }
  124. len = BF_ALIGN(len, 2); // Even addr
  125. mOldFileStream.SetPos(headerFilePos + sizeof(BeLibMemberHeader) + len);
  126. memberIdx++;
  127. }
  128. for (auto& entry : pendingLibEntryMap)
  129. {
  130. auto libEntry = entry.mValue;
  131. // Not used?
  132. if (libEntry->mOldDataPos == -1)
  133. delete libEntry;
  134. }
  135. delete libStrTable;
  136. return true;
  137. }
  138. bool BeLibFile::Init(const StringImpl& filePath, bool moveFile)
  139. {
  140. bool isInitialized = false;
  141. if (FileExists(filePath))
  142. {
  143. String altName;
  144. if (moveFile)
  145. {
  146. altName = filePath + "_";
  147. if (!::MoveFileA(filePath.c_str(), altName.c_str()))
  148. {
  149. ::DeleteFileA(altName.c_str());
  150. if (!::MoveFileA(filePath.c_str(), altName.c_str()))
  151. {
  152. mFilePath = filePath;
  153. return false;
  154. }
  155. }
  156. }
  157. else
  158. altName = filePath;
  159. mOldFilePath = altName;
  160. if (!mOldFileStream.Open(altName, "rb"))
  161. return false;
  162. if (!ReadLib())
  163. return false;
  164. }
  165. String newLibName = filePath;
  166. mFilePath = newLibName;
  167. return true;
  168. }
  169. bool BeLibFile::Finish()
  170. {
  171. BP_ZONE("BeLibFile::Finish");
  172. //mOldEntries.clear();
  173. Dictionary<String, BeLibEntry*>* libEntryMaps[2] = { &mEntries, &mOldEntries };
  174. Array<BeLibEntry*> libEntries;
  175. bool isAllReferenced = true;
  176. for (auto entryMap : libEntryMaps)
  177. {
  178. for (auto& libEntryPair : *entryMap)
  179. {
  180. auto libEntry = libEntryPair.mValue;
  181. if (libEntry->mReferenced)
  182. libEntries.push_back(libEntry);
  183. else
  184. isAllReferenced = false;
  185. }
  186. }
  187. if ((isAllReferenced) && (mEntries.IsEmpty()) && (mOldFileStream.IsOpen()))
  188. {
  189. mOldFileStream.Close();
  190. String altName = mFilePath + "_";
  191. if (::MoveFileA(altName.c_str(), mFilePath.c_str()))
  192. {
  193. return true; // There are no changes
  194. }
  195. }
  196. if (!mFileStream.Open(mFilePath, "wb"))
  197. {
  198. mFailed = true;
  199. return false;
  200. }
  201. if ((!mOldEntries.IsEmpty()) && (!mOldFileStream.IsOpen()))
  202. {
  203. // We failed to open the old stream but we still had old entries to references..
  204. mFailed = true;
  205. return false;
  206. }
  207. mFileStream.Write("!<arch>\n", 8);
  208. std::sort(libEntries.begin(), libEntries.end(),
  209. [&](BeLibEntry* lhs, BeLibEntry* rhs)
  210. {
  211. return lhs->mName < rhs->mName;
  212. });
  213. int longNamesSize = 0;
  214. int tabSize = 4; // num symbols
  215. int numSymbols = 0;
  216. for (auto libEntry : libEntries)
  217. {
  218. if (libEntry->mName.length() > 15)
  219. {
  220. longNamesSize += (int)libEntry->mName.length() + 2;
  221. }
  222. for (auto& sym : libEntry->mSymbols)
  223. {
  224. numSymbols++;
  225. tabSize += 4; // Offset
  226. tabSize += (int)sym.length() + 1; // String table
  227. }
  228. }
  229. // Determine where all these entries will be placed
  230. int predictPos = mFileStream.GetPos() + sizeof(BeLibMemberHeader) + BF_ALIGN(tabSize, 2);
  231. if (longNamesSize > 0)
  232. predictPos += sizeof(BeLibMemberHeader) + BF_ALIGN(longNamesSize, 2);
  233. for (auto libEntry : libEntries)
  234. {
  235. libEntry->mNewDataPos = predictPos;
  236. predictPos += sizeof(BeLibMemberHeader);
  237. predictPos += BF_ALIGN(libEntry->mLength, 2);
  238. }
  239. int tabStartPos = mFileStream.GetPos();
  240. BeLibMemberHeader header;
  241. header.Init("/", "0", tabSize);
  242. mFileStream.WriteT(header);
  243. mFileStream.Write(ToBigEndian((int32)numSymbols));
  244. // Offset table
  245. for (auto libEntry : libEntries)
  246. {
  247. for (auto& sym : libEntry->mSymbols)
  248. {
  249. mFileStream.Write((int32)ToBigEndian(libEntry->mNewDataPos));
  250. }
  251. }
  252. // String map table
  253. for (auto libEntry : libEntries)
  254. {
  255. for (auto& sym : libEntry->mSymbols)
  256. {
  257. mFileStream.Write((uint8*)sym.c_str(), (int)sym.length() + 1);
  258. }
  259. }
  260. int actualTabSize = mFileStream.GetPos() - tabStartPos - sizeof(BeLibMemberHeader);
  261. //return true;
  262. if ((tabSize % 2) != 0)
  263. mFileStream.Write((uint8)0);
  264. BF_ASSERT(actualTabSize == tabSize);
  265. // Create long names table
  266. if (longNamesSize > 0)
  267. {
  268. header.Init("//", "0", longNamesSize);
  269. mFileStream.WriteT(header);
  270. for (auto libEntry : libEntries)
  271. {
  272. if (libEntry->mName.length() > 15)
  273. {
  274. mFileStream.Write((uint8*)libEntry->mName.c_str(), (int)libEntry->mName.length());
  275. mFileStream.Write("/\n", 2);
  276. }
  277. }
  278. if ((longNamesSize % 2) != 0)
  279. mFileStream.Write((uint8)'\n');
  280. }
  281. int longNamesPos = 0;
  282. for (auto libEntry : libEntries)
  283. {
  284. int actualPos = mFileStream.GetPos();
  285. BF_ASSERT(actualPos == libEntry->mNewDataPos);
  286. String entryName;
  287. if (libEntry->mName.length() > 15)
  288. {
  289. char idxStr[32];
  290. _itoa(longNamesPos, idxStr, 10);
  291. entryName = "/";
  292. entryName += idxStr;
  293. longNamesPos += (int)libEntry->mName.length() + 2;
  294. }
  295. else
  296. {
  297. entryName = libEntry->mName;
  298. entryName += "/";
  299. }
  300. header.Init(entryName.c_str(), "644", libEntry->mLength);
  301. mFileStream.WriteT(header);
  302. if (libEntry->mOldDataPos != -1)
  303. {
  304. uint8* data = new uint8[libEntry->mLength];
  305. mOldFileStream.SetPos(libEntry->mOldDataPos + sizeof(BeLibMemberHeader));
  306. mOldFileStream.Read(data, libEntry->mLength);
  307. mFileStream.Write(data, libEntry->mLength);
  308. delete data;
  309. }
  310. else if (libEntry->mData.size() != 0)
  311. {
  312. mFileStream.Write((uint8*)&libEntry->mData[0], (int)libEntry->mData.size());
  313. }
  314. if ((libEntry->mLength % 2) != 0)
  315. mFileStream.Write((uint8)0);
  316. }
  317. mFileStream.Close();
  318. mOldFileStream.Close();
  319. ::DeleteFileA(mOldFilePath.c_str());
  320. return true;
  321. }
  322. //////////////////////////////////////////////////////////////////////////
  323. BeLibManager::BeLibManager()
  324. {
  325. /*BeLibFile libFile;
  326. libFile.Init("Hey");*/
  327. /*BeLibFile libFile;
  328. libFile.Init("c:/beef/IDE/mintest/build/Debug_Win64/minlib/minlib__.lib");
  329. libFile.Finish();*/
  330. /*BeLibFile libFile2;
  331. libFile2.Init("c:\\temp\\Beefy2D.lib_new");*/
  332. }
  333. BeLibManager::~BeLibManager()
  334. {
  335. Clear();
  336. }
  337. void BeLibManager::Clear()
  338. {
  339. BP_ZONE("BeLibManager::Clear");
  340. for (auto& entry : mLibFiles)
  341. delete entry.mValue;
  342. mLibFiles.Clear();
  343. }
  344. BeLibEntry* BeLibManager::AddFile(const StringImpl& filePath, void* data, int size)
  345. {
  346. BP_ZONE("BeLibManager::AddFile");
  347. String fileDir = GetFileDir(filePath);
  348. String fileName = GetFileName(filePath);
  349. String fixedFileDir = FixPathAndCase(fileDir);
  350. AutoCrit autoCrit(mCritSect);
  351. BeLibFile* libFile = NULL;
  352. // if ((data == NULL) && (!mLibFiles.ContainsKey(fixedFileDir)))
  353. // return NULL;
  354. BeLibFile** libFilePtr = NULL;
  355. if (!mLibFiles.TryAdd(fixedFileDir, NULL, &libFilePtr))
  356. {
  357. libFile = *libFilePtr;
  358. }
  359. else
  360. {
  361. libFile = new BeLibFile();
  362. *libFilePtr = libFile;
  363. String libPath = GetLibFilePath(filePath);
  364. libFile->Init(libPath, true);
  365. }
  366. if (libFile->mFailed)
  367. return NULL;
  368. BeLibEntry* oldEntry = NULL;
  369. if (libFile->mOldEntries.TryGetValue(fileName, &oldEntry))
  370. {
  371. if (data == NULL)
  372. {
  373. oldEntry->mReferenced = true;
  374. return oldEntry;
  375. }
  376. delete oldEntry;
  377. libFile->mOldEntries.Remove(fileName);
  378. }
  379. else
  380. {
  381. if (data == NULL)
  382. return NULL;
  383. }
  384. BeLibEntry* libEntry = NULL;
  385. BeLibEntry** libEntryPtr = NULL;
  386. libFile->mEntries.TryAdd(fileName, NULL, &libEntryPtr);
  387. if (*libEntryPtr != NULL)
  388. {
  389. // It's possible that we rebuild a type (generic, probably), decide we don't have any refs so we delete the type,
  390. // but then we specialize methods and then have to recreate it. Thus two entries here.
  391. delete *libEntryPtr;
  392. }
  393. libEntry = new BeLibEntry();
  394. libEntry->mLibFile = libFile;
  395. *libEntryPtr = libEntry;
  396. libEntry->mReferenced = true;
  397. libEntry->mName = fileName;
  398. libEntry->mData.Insert(0, (uint8*)data, size);
  399. libEntry->mLength = size;
  400. return libEntry;
  401. }
  402. bool BeLibManager::AddUsedFileName(const StringImpl& fileName)
  403. {
  404. return AddFile(fileName, NULL, -1) != NULL;
  405. }
  406. void BeLibManager::Finish()
  407. {
  408. BP_ZONE("BeLibManager::Finish");
  409. AutoCrit autoCrit(mCritSect);
  410. for (auto& libPair : mLibFiles)
  411. {
  412. auto libFile = libPair.mValue;
  413. if (!libFile->mFilePath.IsEmpty())
  414. {
  415. if (!libFile->Finish())
  416. {
  417. mErrors.Add(StrFormat("Failed to write lib file '%s'", libFile->mFilePath.c_str()));
  418. }
  419. }
  420. delete libFile;
  421. }
  422. mLibFiles.Clear();
  423. }
  424. String BeLibManager::GetLibFilePath(const StringImpl& objFilePath)
  425. {
  426. String fileDir = RemoveTrailingSlash(GetFileDir(objFilePath));
  427. return fileDir + "/" + GetFileName(fileDir) + "__.lib";
  428. }
  429. BeLibManager* BeLibManager::Get()
  430. {
  431. return &gBfLibManager;
  432. }