Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

912 lines
24 KiB

  1. // SymbolTable.cpp: implementation of the CSymbolTable class.
  2. //
  3. // (c) Copyright Schlumberger Technology Corp., unpublished work, created
  4. // 1999. This computer program includes Confidential, Proprietary
  5. // Information and is a Trade Secret of Schlumberger Technology Corp. All
  6. // use, disclosure, and/or reproduction is prohibited unless authorized
  7. // in writing. All Rights Reserved.
  8. //////////////////////////////////////////////////////////////////////
  9. #include "NoWarning.h"
  10. // Don't allow the min & max macros in WINDEF.H to be defined so the
  11. // min/max methods declared in limits are accessible.
  12. #define NOMINMAX
  13. #include <limits>
  14. #include <slbCrc32.h>
  15. #include <scuArrayP.h>
  16. // must include this file first (there is probably an error in some header file) (scm)
  17. #include "cciExc.h"
  18. #include "cciCard.h"
  19. #include "SymbolTable.h"
  20. #ifdef _DEBUG
  21. #include <iostream>
  22. #endif
  23. using namespace std;
  24. using namespace scu;
  25. using namespace cci;
  26. using namespace iop;
  27. #define CONCAT_BYTES(hi,lo) ((unsigned short)(hi*256 + lo))
  28. //////////////////////////////////////////////////////////////////////
  29. // Construction/Destruction
  30. //////////////////////////////////////////////////////////////////////
  31. CSymbolTable::CSymbolTable(CSmartCard &rSmartCard,
  32. const string &rPath,
  33. unsigned short Offset)
  34. : m_rSmartCard(rSmartCard),
  35. m_Offset(Offset),
  36. m_aastrCachedStrings(),
  37. m_aafCacheMask(),
  38. m_aasHashTable(),
  39. m_aasOffsetTable(),
  40. m_aasLengthTable(),
  41. m_fSymbolTableLoaded(false),
  42. m_Path(rPath),
  43. m_sMaxNumSymbols(),
  44. m_sFirstFreeBlock(),
  45. m_sTableSize()
  46. {
  47. m_aastrCachedStrings = AutoArrayPtr<string>(new string[NumSymbols()]);
  48. m_aafCacheMask = AutoArrayPtr<bool>(new bool[NumSymbols()]);
  49. for (int i = 0; i < NumSymbols(); i++)
  50. {
  51. m_aastrCachedStrings[i] = "";
  52. m_aafCacheMask[i] = false;
  53. }
  54. }
  55. CSymbolTable::~CSymbolTable()
  56. {}
  57. bool CSymbolTable::Remove(const SymbolID &rsid)
  58. {
  59. if (!m_fSymbolTableLoaded)
  60. GetSymbolTable();
  61. else
  62. SelectSymbolFile();
  63. if(rsid<1 || rsid>NumSymbols())
  64. throw Exception(ccSymbolNotFound);
  65. BYTE sidx = rsid-1;
  66. if (m_aasOffsetTable[sidx] == 0)
  67. {
  68. // We have a bad reference!
  69. throw Exception(ccSymbolNotFound);
  70. }
  71. // Let's read in the header info for the string we want to delete.
  72. BYTE bBuffer[5];
  73. ReadSymbolFile(m_aasOffsetTable[sidx], 3, bBuffer);
  74. unsigned short sStrLen, sBlockLen;
  75. BYTE bRefCount;
  76. sStrLen = m_aasLengthTable[sidx];
  77. sBlockLen = CONCAT_BYTES(bBuffer[1],bBuffer[0]);
  78. bRefCount = bBuffer[2];
  79. // The trivial case is when the refcount is greater than one. In that
  80. // case we just dec the count!
  81. if (bRefCount > 1)
  82. {
  83. bRefCount--;
  84. WriteSymbolFile(m_aasOffsetTable[sidx] + 2, 1, &bRefCount);
  85. return true;
  86. }
  87. // Need to take it out of the cache
  88. m_aastrCachedStrings[sidx] = "";
  89. m_aafCacheMask[sidx] = false;
  90. // Simply connect the deleted block to the head of the free list.
  91. bBuffer[0] = LOBYTE(FirstFreeBlock());
  92. bBuffer[1] = HIBYTE(FirstFreeBlock());
  93. WriteSymbolFile(m_aasOffsetTable[sidx]+2, 2, bBuffer);
  94. FirstFreeBlock(m_aasOffsetTable[sidx]);
  95. ClearTableEntry(sidx);
  96. return true;
  97. }
  98. void CSymbolTable::Replace(SymbolID const &rsid, string const &rstrUpd)
  99. {
  100. if (!m_fSymbolTableLoaded)
  101. GetSymbolTable();
  102. else
  103. SelectSymbolFile();
  104. if(rsid<1 || rsid>NumSymbols())
  105. throw Exception(ccSymbolNotFound);
  106. BYTE sidx = rsid-1;
  107. if (m_aasOffsetTable[sidx] == 0)
  108. throw Exception(ccSymbolNotFound);
  109. // This implementation require the new string to have the same size as the old.
  110. // It may be that this requirement should be lifted later, however it is essential
  111. // that the SymbolID is not changed by this function.
  112. if(rstrUpd.size() != m_aasLengthTable[sidx])
  113. throw Exception(ccBadLength);
  114. WriteSymbolFile(m_aasOffsetTable[sidx] + 3,
  115. static_cast<BYTE>(rstrUpd.size()),
  116. reinterpret_cast<BYTE const *>(rstrUpd.data()));
  117. unsigned short sHash = Hash(rstrUpd);
  118. UpdateTableEntry(sidx, sHash, m_aasOffsetTable[sidx], m_aasLengthTable[sidx]);
  119. m_aastrCachedStrings[sidx] = rstrUpd;
  120. m_aafCacheMask[sidx] = true;
  121. }
  122. SymbolID CSymbolTable::Add(const string &rstrNew, ShareMode mode)
  123. {
  124. if (!m_fSymbolTableLoaded)
  125. GetSymbolTable();
  126. else
  127. SelectSymbolFile();
  128. SymbolID rsid;
  129. BYTE sidx;
  130. if(mode==smShared) {
  131. bool fFind = Find(rstrNew, &rsid);
  132. if (fFind)
  133. {
  134. sidx = rsid-1;
  135. // The string is already in the table. Just bump the ref count.
  136. BYTE bRefCount;
  137. ReadSymbolFile(m_aasOffsetTable[sidx] + 2, 1, &bRefCount);
  138. bRefCount++;
  139. WriteSymbolFile(m_aasOffsetTable[sidx] + 2, 1, &bRefCount);
  140. return sidx+1;
  141. }
  142. // String is not in the table. We have to add it.
  143. }
  144. // Need to allocate a new string. First make sure
  145. // that there is a free slot in the hash table.
  146. sidx = 0;
  147. while (sidx < NumSymbols())
  148. {
  149. if (m_aasOffsetTable[sidx] == 0)
  150. break;
  151. sidx++;
  152. }
  153. if(sidx == NumSymbols())
  154. throw Exception(ccOutOfSymbolTableEntries);
  155. // Let's see if we have space for the new string. To do this, we just
  156. // cruise the empty block chain until we find an available block
  157. unsigned short sLength = static_cast<unsigned short>(rstrNew.length());
  158. unsigned short sExtra = (sLength) ? 0 : 1; // To make sure that the block is minimum 4 bytes since
  159. // this is the minimum size for a free block.
  160. // If there is no first free block, then the card is completely full. Need
  161. // to throw an error.
  162. if (FirstFreeBlock() == 0)
  163. throw Exception(ccOutOfSymbolTableSpace);
  164. // When we finally find a block of appropriate size, we need to keep track of the
  165. // previous block, so that we can chain together the empty spaces.
  166. // Set of free block pointers that we will use to track the free space.
  167. auto_ptr<CFreeBlock> apFreeBlock(new CFreeBlock(this, FirstFreeBlock()));
  168. auto_ptr<CFreeBlock> apNewLocation;
  169. auto_ptr<CFreeBlock> apPrevious;
  170. unsigned short sTotalFreeSize = 0;
  171. // We will loop until we find a free block that is large enough, or we
  172. // will throw an error.
  173. while (!apNewLocation.get())
  174. {
  175. // Remember that not only the string but the header info must fit into the
  176. // space.
  177. sTotalFreeSize += apFreeBlock->m_sBlockLength;
  178. if (apFreeBlock->m_sBlockLength >= sLength + 3 + sExtra)
  179. {
  180. // The string fits in this block
  181. apNewLocation = apFreeBlock;
  182. }
  183. else
  184. {
  185. // String doesn't fit. See if it fits in the next block.
  186. apPrevious = apFreeBlock;
  187. apFreeBlock = apPrevious->Next();
  188. // The Next() method returns 0 if we are out of free spots
  189. if (!apFreeBlock.get())
  190. {
  191. if (sTotalFreeSize < sLength + 3 + sExtra)
  192. throw Exception(ccOutOfSymbolTableSpace);
  193. else
  194. {
  195. Compress();
  196. return Add(rstrNew);
  197. }
  198. }
  199. }
  200. }
  201. // The block of space that is my size is sitting in pNewLocation.
  202. // I need to chain the empty spaces on either side together.
  203. // How much space will be left in this empty block after I put my string in it?
  204. unsigned short sRemaining =
  205. apNewLocation->m_sBlockLength - (sLength + 3 + sExtra);
  206. // If less than 6 bytes remain, it isn't really worth splitting this block
  207. if (sRemaining < 6)
  208. {
  209. sExtra += sRemaining;
  210. if (apPrevious.get())
  211. {
  212. apPrevious->m_sNextBlock = apNewLocation->m_sNextBlock;
  213. apPrevious->Update();
  214. }
  215. else
  216. FirstFreeBlock(apNewLocation->m_sNextBlock);
  217. }
  218. else
  219. {
  220. // There is enough space in the block to make splitting worthwhile
  221. unsigned short sNewOffset =
  222. apNewLocation->m_sStartLoc + sLength + 3 + sExtra;
  223. BYTE bBuffer[4];
  224. bBuffer[0] = LOBYTE(sRemaining);
  225. bBuffer[1] = HIBYTE(sRemaining);
  226. bBuffer[2] = LOBYTE(apNewLocation->m_sNextBlock);
  227. bBuffer[3] = HIBYTE(apNewLocation->m_sNextBlock);
  228. WriteSymbolFile(sNewOffset, 4, bBuffer);
  229. if (apPrevious.get())
  230. {
  231. apPrevious->m_sNextBlock = sNewOffset;
  232. apPrevious->Update();
  233. }
  234. else
  235. FirstFreeBlock(sNewOffset);
  236. }
  237. // Drop the string in the empty slot
  238. AutoArrayPtr<BYTE> aabTemp(new BYTE[3 + sLength]);
  239. aabTemp[0] = LOBYTE(sLength + 3 + sExtra);
  240. aabTemp[1] = HIBYTE(sLength + 3 + sExtra);
  241. // Shared symbols are indicated by a ref-count >=1
  242. if(mode==smShared) aabTemp[2] = 1;
  243. else aabTemp[2] = 0;
  244. memcpy(&aabTemp[3], rstrNew.data(), sLength);
  245. WriteSymbolFile(apNewLocation->m_sStartLoc, 3 + sLength, aabTemp.Get());
  246. // cout << "Adding " << strNew << " at " << pNewLocation->m_sStartLoc << endl;
  247. // cout << "Length = " << sLength << " Block Length = " << sLength + 5 + sExtra << endl;
  248. // Populate the hash table entry
  249. unsigned short sHash = Hash(rstrNew);
  250. UpdateTableEntry(sidx, sHash, apNewLocation->m_sStartLoc, sLength);
  251. m_aastrCachedStrings[sidx] = rstrNew;
  252. m_aafCacheMask[sidx] = true;
  253. return sidx+1;
  254. }
  255. void CSymbolTable::GetSymbolTable()
  256. {
  257. // There are 6 bytes in each entry of the symbol table, and we'll go ahead and
  258. // read in the whole table.
  259. unsigned short sTableSize = 6 * NumSymbols();
  260. AutoArrayPtr<BYTE> aabBuffer(new BYTE[sTableSize]);
  261. SelectSymbolFile();
  262. ReadSymbolFile(SymbHashTableLoc, sTableSize, aabBuffer.Get());
  263. m_aasHashTable =
  264. AutoArrayPtr<unsigned short>(new unsigned short[NumSymbols()]);
  265. m_aasOffsetTable =
  266. AutoArrayPtr<unsigned short>(new unsigned short[NumSymbols()]);
  267. m_aasLengthTable =
  268. AutoArrayPtr<unsigned short>(new unsigned short[NumSymbols()]);
  269. m_fSymbolTableLoaded = true;
  270. for (int i = 0; i < NumSymbols(); i++)
  271. {
  272. m_aasHashTable[i] = CONCAT_BYTES(aabBuffer[1 + i*6],
  273. aabBuffer[0 + i*6]);
  274. m_aasOffsetTable[i] = CONCAT_BYTES(aabBuffer[3 + i*6],
  275. aabBuffer[2 + i*6]);
  276. m_aasLengthTable[i] = CONCAT_BYTES(aabBuffer[5 + i*6],
  277. aabBuffer[4 + i*6]);
  278. }
  279. }
  280. WORD CSymbolTable::Hash(const string &rstr)
  281. {
  282. // A 32-bit CRC is used to produce a 16-bit hash value is used.
  283. // There are several reasons for using a 32-bit CRC instead of a
  284. // 16-bit version:
  285. //
  286. // 1. A 16-bit CRC has the characteristics that the hash value 1
  287. // would occur twice for every 65536 CRC runs where all other values
  288. // would occur only once on average. Using a 32-bit CRC the hash
  289. // values are spread evenly within a small percentage fraction
  290. // this problem doesn't occur.
  291. //
  292. // 2. The CCI uses a compression algorithm based on the same
  293. // 32-bit CRC. The CRC algorithm is implemented with a table.
  294. // Using a 16-bit CRC would result in an additional CRC lookup
  295. // table of 512-bytes or require one of the algorithms not to be
  296. // table-driven and therefore slower.
  297. //
  298. // 3. On 32-bit architectures, a 32-bit CRC algorithm is faster
  299. // than a 16-bit algorithm.
  300. //
  301. DWORD crc = Crc32(rstr.data(), rstr.length());
  302. DWORD remainder = crc % std::numeric_limits<WORD>::max();
  303. WORD Value = static_cast<WORD>(remainder);
  304. return Value;
  305. }
  306. vector <string> CSymbolTable::EnumStrings()
  307. {
  308. vector <string> vStrings;
  309. if (!m_fSymbolTableLoaded)
  310. GetSymbolTable();
  311. for (BYTE sidx = 0; sidx < NumSymbols(); sidx++)
  312. {
  313. if (m_aasOffsetTable[sidx])
  314. {
  315. vStrings.push_back(Find((SymbolID)(sidx+1)));
  316. }
  317. }
  318. return vStrings;
  319. }
  320. bool CSymbolTable::Find(const string &rsOrig, SymbolID *sid)
  321. {
  322. unsigned short sICV = 0;
  323. unsigned short sHash = Hash(rsOrig);
  324. if (!m_fSymbolTableLoaded)
  325. GetSymbolTable();
  326. else
  327. SelectSymbolFile();
  328. for (BYTE sidx = 0; sidx < NumSymbols(); sidx++)
  329. {
  330. if (m_aasOffsetTable[sidx] && sHash == m_aasHashTable[sidx])
  331. {
  332. // This is a potential match
  333. if (rsOrig == Find(sidx+1))
  334. {
  335. // Check that it is allowed to share it.
  336. if(RefCount(sidx)) {
  337. *sid = (SymbolID)(sidx+1);
  338. return true;
  339. }
  340. }
  341. }
  342. }
  343. return false;
  344. }
  345. string CSymbolTable::Find(const SymbolID &rsid)
  346. {
  347. if(rsid<1 || rsid>NumSymbols())
  348. throw Exception(ccSymbolNotFound);
  349. BYTE sidx = rsid-1;
  350. if (m_aafCacheMask[sidx])
  351. return m_aastrCachedStrings[sidx];
  352. if (!m_fSymbolTableLoaded)
  353. GetSymbolTable();
  354. else
  355. SelectSymbolFile();
  356. if (m_aasOffsetTable[sidx] == 0)
  357. return string();
  358. unsigned short sLength = m_aasLengthTable[sidx];
  359. if (0 == sLength)
  360. return string();
  361. AutoArrayPtr<BYTE> aabBuffer(new BYTE[sLength]);
  362. ReadSymbolFile(m_aasOffsetTable[sidx] + 3, sLength, aabBuffer.Get());
  363. string strRetVal((char*)aabBuffer.Get(), sLength);
  364. // Verify the data isn't corrupted by hashing the data retrieved
  365. // and comparing that resulting hash against the hashed used to
  366. // find the data originally. This provides checking for both the
  367. // string and the hash used to store the string.
  368. DWORD const dwHash = Hash(strRetVal);
  369. if (dwHash != m_aasHashTable[sidx])
  370. throw Exception(ccSymbolDataCorrupted);
  371. m_aastrCachedStrings[sidx] = strRetVal;
  372. m_aafCacheMask[sidx] = true;
  373. return strRetVal;
  374. }
  375. BYTE CSymbolTable::RefCount(const BYTE &sidx)
  376. {
  377. if (!m_fSymbolTableLoaded)
  378. GetSymbolTable();
  379. else
  380. SelectSymbolFile();
  381. if (m_aasOffsetTable[sidx] == 0)
  382. {
  383. return 0;
  384. }
  385. BYTE bBuffer;
  386. ReadSymbolFile(m_aasOffsetTable[sidx] + 2, 1, &bBuffer);
  387. return bBuffer;
  388. }
  389. unsigned short CSymbolTable::NumSymbols()
  390. {
  391. if (!m_sMaxNumSymbols.IsCached())
  392. {
  393. SelectSymbolFile();
  394. BYTE bSymbols[2];
  395. ReadSymbolFile(SymbNumSymbolLoc, 1, bSymbols);
  396. m_sMaxNumSymbols.Value(bSymbols[0]);
  397. }
  398. return m_sMaxNumSymbols.Value();
  399. }
  400. void CSymbolTable::FirstFreeBlock(unsigned short sOffset)
  401. {
  402. BYTE bFBlock[2];
  403. bFBlock[0] = LOBYTE(sOffset);
  404. bFBlock[1] = HIBYTE(sOffset);
  405. SelectSymbolFile();
  406. WriteSymbolFile(SymbFreeListLoc, 2, bFBlock);
  407. m_sFirstFreeBlock.Value(sOffset);
  408. }
  409. unsigned short CSymbolTable::FirstFreeBlock()
  410. {
  411. if (!m_sFirstFreeBlock.IsCached())
  412. {
  413. BYTE bSymbols[2];
  414. SelectSymbolFile();
  415. ReadSymbolFile(SymbFreeListLoc, 2, bSymbols);
  416. m_sFirstFreeBlock.Value(CONCAT_BYTES(bSymbols[1],bSymbols[0]));
  417. }
  418. return m_sFirstFreeBlock.Value();
  419. }
  420. unsigned short CSymbolTable::TableSize()
  421. {
  422. if (!m_sTableSize.IsCached())
  423. {
  424. SelectSymbolFile();
  425. BYTE bSymbols[2];
  426. ReadSymbolFile(SymbTableSizeLoc,2, bSymbols);
  427. m_sTableSize.Value(CONCAT_BYTES(bSymbols[1],bSymbols[0]));
  428. }
  429. return m_sTableSize.Value();
  430. }
  431. unsigned short CSymbolTable::FreeSpace()
  432. {
  433. unsigned short sTotalFreeSize = 0;
  434. if(FirstFreeBlock())
  435. {
  436. SelectSymbolFile();
  437. auto_ptr<CFreeBlock> apNextFreeBlock;
  438. auto_ptr<CFreeBlock> apFreeBlock(new CFreeBlock(this, FirstFreeBlock()));
  439. sTotalFreeSize += apFreeBlock->m_sBlockLength;
  440. while(apFreeBlock->m_sNextBlock)
  441. {
  442. apNextFreeBlock = apFreeBlock->Next();
  443. apFreeBlock = apNextFreeBlock;
  444. sTotalFreeSize += apFreeBlock->m_sBlockLength;
  445. }
  446. }
  447. return sTotalFreeSize;
  448. }
  449. void CSymbolTable::SelectSymbolFile()
  450. {
  451. m_rSmartCard.Select(m_Path.c_str());
  452. }
  453. void CSymbolTable::ReadSymbolFile(const WORD wOffset, const WORD wDataLength, BYTE* bDATA)
  454. {
  455. m_rSmartCard.ReadBinary(wOffset+m_Offset,wDataLength,bDATA);
  456. }
  457. void CSymbolTable::WriteSymbolFile(const WORD wOffset, const WORD wDataLength, const BYTE* bDATA)
  458. {
  459. m_rSmartCard.WriteBinary(wOffset+m_Offset,wDataLength,bDATA);
  460. }
  461. #ifdef _DEBUG
  462. void CSymbolTable::DumpState()
  463. {
  464. cout << "Dumping card state." << endl;
  465. cout << "Symbol Table Global Info:" << endl;
  466. cout << " Number of Symbols: " << NumSymbols();
  467. cout << " Total table size: " << TableSize();
  468. cout << " First free block: " << hex << FirstFreeBlock() << endl;
  469. cout << "Hash Table contents: " << endl;
  470. GetSymbolTable();
  471. cout << "Hash Offset Length" << endl;
  472. for (int i = 0; i < NumSymbols(); i++)
  473. cout << hex << m_aasHashTable[i] << "\t" << m_aasOffsetTable[i] << "\t" << m_aasLengthTable[i] << endl;
  474. unsigned short sFBOffset = FirstFreeBlock();
  475. cout << "Free Block List" << endl;
  476. if (!FirstFreeBlock())
  477. cout << endl << "NO FREE BLOCKS" << endl <<endl;
  478. else
  479. {
  480. CFreeBlock fb(this, sFBOffset);
  481. cout << dec << fb.m_sBlockLength << " bytes starting at " << hex << fb.m_sStartLoc
  482. << "\tNext = " << fb.m_sNextBlock << endl;
  483. while (fb.m_sNextBlock)
  484. {
  485. fb = CFreeBlock(this, fb.m_sNextBlock);
  486. cout << dec << fb.m_sBlockLength << " bytes starting at " << hex << fb.m_sStartLoc
  487. << "\tNext = " << fb.m_sNextBlock << endl;
  488. }
  489. }
  490. cout << "String List" << endl;
  491. cout << "Offset StrLen BlkLen Refcnt String" << endl;
  492. for (i = 0; i < NumSymbols(); i++)
  493. if (m_aasOffsetTable[i])
  494. {
  495. // Read in the header
  496. BYTE bHeader[5];
  497. ReadSymbolFile(m_aasOffsetTable[i], 3, bHeader);
  498. unsigned short sStrLen = m_aasLengthTable[i];
  499. unsigned short sBlockLen = CONCAT_BYTES(bHeader[1],bHeader[0]);
  500. BYTE bRefCnt = bHeader[2];
  501. AutoArrayPtr<BYTE> aabString(new BYTE[sStrLen]);
  502. ReadSymbolFile(m_aasOffsetTable[i] + 3, sStrLen, aabString.Get());
  503. string s1((char*)aabString.Get(), sStrLen);
  504. // cout << hex << m_aasOffsetTable[i] << "\t" << sStrLen << "\t" << sBlockLen
  505. // << "\t" << (int)bRefCnt << "\t" << s1 << endl;
  506. }
  507. }
  508. #endif
  509. void CSymbolTable::Reset()
  510. {
  511. unsigned short sSize = TableSize();
  512. unsigned short sNumSym = NumSymbols();
  513. unsigned short sTotalSize = SymbHashTableLoc + 6 * sNumSym + sSize;
  514. unsigned short sFirstFree = SymbHashTableLoc + 6 * sNumSym;
  515. AutoArrayPtr<BYTE> aabBuffer(new BYTE[sTotalSize]);
  516. memset(aabBuffer.Get(), 0, sTotalSize);
  517. aabBuffer[SymbNumSymbolLoc] = sNumSym & 0xFF;
  518. aabBuffer[SymbFreeListLoc] = LOBYTE(sFirstFree);
  519. aabBuffer[SymbFreeListLoc+1] = HIBYTE(sFirstFree);
  520. aabBuffer[SymbTableSizeLoc] = LOBYTE(sSize);
  521. aabBuffer[SymbTableSizeLoc+1] = HIBYTE(sSize);
  522. aabBuffer[sFirstFree] = LOBYTE(sSize);
  523. aabBuffer[sFirstFree + 1] = HIBYTE(sSize);
  524. m_fSymbolTableLoaded = false;
  525. SelectSymbolFile();
  526. WriteSymbolFile( 0, sTotalSize, aabBuffer.Get());
  527. for (int i = 0; i < NumSymbols(); i++)
  528. {
  529. m_aafCacheMask[i] = false;
  530. m_aastrCachedStrings[i] = "";
  531. }
  532. m_sFirstFreeBlock.Dirty();
  533. GetSymbolTable();
  534. }
  535. void CSymbolTable::Compress()
  536. {
  537. unsigned short sSize = TableSize();
  538. unsigned short sNumSym = NumSymbols();
  539. unsigned short sStringStart = SymbHashTableLoc + 6 * sNumSym;
  540. unsigned short sTotalSize = sStringStart + sSize;
  541. // cout << "Compressing..." << endl;
  542. GetSymbolTable();
  543. vector<string> vStringTable;
  544. AutoArrayPtr<unsigned short> aasStringSize(new unsigned short[sNumSym]);
  545. // cout << "Building table" << endl;
  546. BYTE sidx;
  547. for (sidx = 0; sidx < sNumSym; sidx++)
  548. {
  549. string strTemp;
  550. if (m_aasOffsetTable[sidx]) {
  551. strTemp = Find(sidx+1);
  552. aasStringSize[sidx] = static_cast<unsigned short>(strTemp.size());
  553. } else {
  554. strTemp = "";
  555. }
  556. // cout << " Adding to table: " << strTemp << endl;
  557. vStringTable.push_back(strTemp);
  558. }
  559. AutoArrayPtr<BYTE> aabNewTable(new BYTE[sTotalSize]);
  560. memset(aabNewTable.Get(), 0, sTotalSize);
  561. aabNewTable[SymbNumSymbolLoc] = sNumSym & 0xFF;
  562. aabNewTable[SymbTableSizeLoc] = LOBYTE(sSize);
  563. aabNewTable[SymbTableSizeLoc+1] = HIBYTE(sSize);
  564. unsigned short sCurrentWrite = sStringStart;
  565. for (sidx = 0; sidx < sNumSym; sidx++)
  566. {
  567. if (m_aasOffsetTable[sidx])
  568. {
  569. BYTE bTableEntry[6];
  570. bTableEntry[0] = LOBYTE(m_aasHashTable[sidx]);
  571. bTableEntry[1] = HIBYTE(m_aasHashTable[sidx]);
  572. bTableEntry[2] = LOBYTE(sCurrentWrite);
  573. bTableEntry[3] = HIBYTE(sCurrentWrite);
  574. bTableEntry[4] = LOBYTE(m_aasLengthTable[sidx]);
  575. bTableEntry[5] = HIBYTE(m_aasLengthTable[sidx]);
  576. // cout << "Placing '"<< vStringTable[i] << " at location " << hex << sCurrentWrite << endl;
  577. unsigned short sExtra = (aasStringSize[sidx]) ? 0 : 1; // To make sure that the block is minimum
  578. // 4 bytes since this is the minimum size
  579. // for a free block.
  580. AutoArrayPtr<BYTE> aabStringEntry(new BYTE[aasStringSize[sidx] + 3]);
  581. aabStringEntry[0] = LOBYTE(aasStringSize[sidx] + 3 + sExtra);
  582. aabStringEntry[1] = HIBYTE(aasStringSize[sidx] + 3 + sExtra);
  583. aabStringEntry[2] = RefCount(sidx);
  584. memcpy(&aabStringEntry[3], vStringTable[sidx].data(),
  585. aasStringSize[sidx]);
  586. // Write the new entries
  587. memcpy(&aabNewTable[SymbHashTableLoc + sidx * 6], bTableEntry, 6);
  588. memcpy(&aabNewTable[sCurrentWrite], aabStringEntry.Get(),
  589. aasStringSize[sidx] + 3);
  590. sCurrentWrite += aasStringSize[sidx] + 3 + sExtra;
  591. }
  592. }
  593. m_fSymbolTableLoaded = false;
  594. unsigned short sFreeSpace = sStringStart + sSize - sCurrentWrite;
  595. if (sFreeSpace < 8)
  596. {
  597. // Then there is essentially no more space on the card
  598. aabNewTable[SymbFreeListLoc] = 0;
  599. aabNewTable[SymbFreeListLoc+1] = 0;
  600. }
  601. else
  602. {
  603. aabNewTable[SymbFreeListLoc] = LOBYTE(sCurrentWrite);
  604. aabNewTable[SymbFreeListLoc+1] = HIBYTE(sCurrentWrite);
  605. // Need to set up the last empty block as well.
  606. aabNewTable[sCurrentWrite] = LOBYTE(sFreeSpace);
  607. aabNewTable[sCurrentWrite + 1] = HIBYTE(sFreeSpace);
  608. }
  609. // Phew! Write the table back to the card.
  610. WriteSymbolFile(0, sTotalSize, aabNewTable.Get());
  611. m_sFirstFreeBlock.Dirty();
  612. // Clean up
  613. for (sidx = 0; sidx < NumSymbols(); sidx++)
  614. {
  615. m_aafCacheMask[sidx] = false;
  616. m_aastrCachedStrings[sidx] = "";
  617. }
  618. }
  619. void CSymbolTable::ClearTableEntry(BYTE const &sidx)
  620. {
  621. UpdateTableEntry(sidx, 0, 0, 0);
  622. }
  623. void CSymbolTable::UpdateTableEntry(BYTE const &sidx,
  624. WORD wNewHash,
  625. WORD wNewOffset,
  626. WORD wNewLength)
  627. {
  628. BYTE bBuffer[6];
  629. bBuffer[0] = LOBYTE(wNewHash);
  630. bBuffer[1] = HIBYTE(wNewHash);
  631. bBuffer[2] = LOBYTE(wNewOffset);
  632. bBuffer[3] = HIBYTE(wNewOffset);
  633. bBuffer[4] = LOBYTE(wNewLength);
  634. bBuffer[5] = HIBYTE(wNewLength);
  635. WriteSymbolFile(SymbHashTableLoc + (sidx * sizeof bBuffer),
  636. sizeof bBuffer, bBuffer);
  637. m_aasHashTable[sidx] = wNewHash;
  638. m_aasOffsetTable[sidx] = wNewOffset;
  639. m_aasLengthTable[sidx] = wNewLength;
  640. }
  641. CFreeBlock::CFreeBlock(CSymbolTable *pSymTable, unsigned short sStartLocation)
  642. {
  643. m_pSymbolTable = pSymTable;
  644. m_sStartLoc = sStartLocation;
  645. BYTE bBuffer[4];
  646. m_pSymbolTable->ReadSymbolFile(m_sStartLoc, sizeof(bBuffer), bBuffer);
  647. m_sBlockLength = CONCAT_BYTES(bBuffer[1], bBuffer[0]);
  648. m_sNextBlock = CONCAT_BYTES(bBuffer[3], bBuffer[2]);
  649. }
  650. void CFreeBlock::Update()
  651. {
  652. BYTE bBuffer[4];
  653. bBuffer[0] = LOBYTE(m_sBlockLength);
  654. bBuffer[1] = HIBYTE(m_sBlockLength);
  655. bBuffer[2] = LOBYTE(m_sNextBlock);
  656. bBuffer[3] = HIBYTE(m_sNextBlock);
  657. m_pSymbolTable->WriteSymbolFile(m_sStartLoc, 4, bBuffer);
  658. }
  659. auto_ptr<CFreeBlock>
  660. CFreeBlock::Next()
  661. {
  662. auto_ptr<CFreeBlock> apNext((0 == m_sNextBlock)
  663. ? 0
  664. : new CFreeBlock(m_pSymbolTable,
  665. m_sNextBlock));
  666. return apNext;
  667. }