Source code of Windows XP (NT5)
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.

732 lines
20 KiB

  1. /*
  2. * RING16.C: Ring buffer code
  3. *
  4. * History:
  5. * 30-Oct-1996 jforbes Cloned from QUANTUM\DECOMP.C
  6. */
  7. #include <stdio.h> /* for NULL */
  8. #include <stdlib.h> /* for disk ring buffer code (SEEK_SET) */
  9. #include <fcntl.h> /* for disk ring buffer code (_O_*) */
  10. #include <sys\stat.h> /* for disk ring buffer code (_S_I*) */
  11. #include <io.h>
  12. #include "decoder.h"
  13. /* --- local function prototypes ------------------------------------------ */
  14. static void NEAR DComp_Internal_Literal(t_decoder_context *context, int Chr );
  15. static void NEAR DComp_Internal_Match(t_decoder_context *context, MATCH Match );
  16. static void NEAR DComp_Ring_Close(t_decoder_context *context);
  17. static int NEAR DComp_Ring_Init(t_decoder_context *context);
  18. static void NEAR DComp_Ring_Literal(t_decoder_context *context, int Chr );
  19. static BYTE * NEAR DComp_Ring_Load(t_decoder_context *context, int page,int fWrite);
  20. static void NEAR DComp_Ring_Match(t_decoder_context *context, MATCH Match );
  21. static void NEAR DComp_Ring_Reset(t_decoder_context *context);
  22. #define Disk context->Disk
  23. #define DComp context->DComp
  24. /* --- DComp_Close() ------------------------------------------------------ */
  25. void NEAR DComp_Close(t_decoder_context *context)
  26. {
  27. if (DComp.Buf == NULL)
  28. {
  29. DComp_Ring_Close(context); /* if using a disk-based ring buffer */
  30. }
  31. else
  32. {
  33. context->dec_free( DComp.Buf ); /* if using memory-based ring buffer */
  34. }
  35. }
  36. /* --- DComp_Init() ------------------------------------------------------- */
  37. int NEAR DComp_Init(t_decoder_context *context)
  38. {
  39. DComp.Cur = 0;
  40. DComp.fRingFault = 0;
  41. if( (DComp.Buf = context->dec_malloc( context->dec_window_size )) != NULL )
  42. {
  43. DComp.BufPos = DComp.Buf;
  44. DComp.BufEnd = DComp.Buf + context->dec_window_size;
  45. context->DComp_Token_Match = DComp_Internal_Match; /* use internal buffering */
  46. context->DComp_Token_Literal = DComp_Internal_Literal;
  47. }
  48. else if (DComp_Ring_Init(context)) /* try disk ring buffer */
  49. {
  50. context->DComp_Token_Match = DComp_Ring_Match; /* use disk buffering */
  51. context->DComp_Token_Literal = DComp_Ring_Literal;
  52. }
  53. else
  54. {
  55. return (1); /* if can't create ring buffer */
  56. }
  57. return(0);
  58. }
  59. /* --- DComp_Internal_Literal() ------------------------------------------- */
  60. static void NEAR DComp_Internal_Literal(t_decoder_context *context, int Chr)
  61. {
  62. if (DComp.NumBytes)
  63. {
  64. DComp.NumBytes--;
  65. DComp.Cur++;
  66. *context->dec_output_curpos++ = *DComp.BufPos++ = (BYTE) Chr;
  67. if (DComp.BufPos == DComp.BufEnd)
  68. DComp.BufPos = DComp.Buf;
  69. }
  70. }
  71. /* --- DComp_Internal_Match() --------------------------------------------- */
  72. static void NEAR DComp_Internal_Match(t_decoder_context *context, MATCH Match)
  73. {
  74. BYTE HUGE *SrcPtr;
  75. if (DComp.NumBytes >= (unsigned) Match.Len)
  76. {
  77. SrcPtr = DComp.Buf +
  78. ((DComp.Cur - Match.Dist) & context->dec_window_mask);
  79. DComp.NumBytes -= Match.Len;
  80. DComp.Cur += Match.Len;
  81. while (Match.Len--)
  82. {
  83. *context->dec_output_curpos++ = *DComp.BufPos++ = *SrcPtr++;
  84. if (SrcPtr == DComp.BufEnd)
  85. SrcPtr = DComp.Buf;
  86. if (DComp.BufPos == DComp.BufEnd)
  87. DComp.BufPos = DComp.Buf;
  88. }
  89. }
  90. else /* match too large to fit */
  91. {
  92. DComp.NumBytes = 0;
  93. DComp.fOutOverflow = 1;
  94. }
  95. }
  96. /* --- DComp_Reset() ------------------------------------------------------ */
  97. void NEAR DComp_Reset(t_decoder_context *context)
  98. {
  99. DComp.Cur = 0;
  100. DComp.fRingFault = 0;
  101. if (DComp.Buf != NULL)
  102. DComp.BufPos = DComp.Buf; /* big buffer */
  103. else
  104. DComp_Ring_Reset(context); /* ring buffer */
  105. }
  106. /* --- DComp_Ring_Close() ------------------------------------------------- */
  107. static void NEAR DComp_Ring_Close(t_decoder_context *context)
  108. {
  109. PBUFFER pBuffer, pNext; /* buffer walk pointer */
  110. context->dec_free(Disk.PageTable); /* discard page table */
  111. pBuffer = Disk.pNewest;
  112. while (pBuffer != NULL) /* discard buffer chain */
  113. {
  114. pNext = pBuffer->pLinkOlder;
  115. context->dec_free(pBuffer);
  116. pBuffer = pNext;
  117. }
  118. context->dec_close(Disk.Handle); /* close that file (and delete) */
  119. }
  120. /* --- DComp_Ring_Init() -------------------------------------------------- */
  121. static int NEAR DComp_Ring_Init(t_decoder_context *context)
  122. {
  123. RINGNAME ringName;
  124. PBUFFER pBuffer;
  125. int cBuffers;
  126. ringName.wildName[0] = '*';
  127. ringName.wildName[1] = '\0';
  128. ringName.fileSize = context->dec_window_size;
  129. Disk.Handle = context->dec_open(
  130. (char FAR *) &ringName,
  131. (_O_BINARY|_O_RDWR|_O_CREAT),
  132. (_S_IREAD|_S_IWRITE)
  133. );
  134. if (Disk.Handle == -1)
  135. {
  136. return(0); /* failed, can't make disk file */
  137. }
  138. Disk.RingPages = (int) (context->dec_window_size / BUFFER_SIZE);
  139. if (Disk.RingPages < MIN_BUFFERS)
  140. {
  141. Disk.RingPages = MIN_BUFFERS; /* if DComp.WindowSize < BUFFER_SIZE */
  142. }
  143. Disk.PageTable = context->dec_malloc(sizeof(PAGETABLEENTRY) * Disk.RingPages);
  144. if (Disk.PageTable == NULL)
  145. {
  146. context->dec_close(Disk.Handle); /* close the file */
  147. return(0); /* failed, can't get page table */
  148. }
  149. Disk.pNewest = NULL;
  150. /* DComp_Ring_Close() can be used to abort from this point on */
  151. for (cBuffers = 0; cBuffers < Disk.RingPages; cBuffers++)
  152. {
  153. pBuffer = context->dec_malloc(sizeof(BUFFER));
  154. if (pBuffer != NULL)
  155. {
  156. pBuffer->pLinkNewer = NULL; /* none are newer */
  157. pBuffer->pLinkOlder = Disk.pNewest; /* all the others older now */
  158. if (Disk.pNewest != NULL)
  159. {
  160. Disk.pNewest->pLinkNewer = pBuffer; /* old guy now knows about new */
  161. }
  162. else /* if nobody else */
  163. {
  164. Disk.pOldest = pBuffer; /* guess I'm the oldest too */
  165. }
  166. Disk.pNewest = pBuffer; /* I'm the newest */
  167. }
  168. else /* if pBuffer == NULL */
  169. {
  170. if (cBuffers < MIN_BUFFERS) /* less than minimum? */
  171. {
  172. DComp_Ring_Close(context); /* give it up */
  173. return(0); /* failed, can't get min buffers */
  174. }
  175. else /* if we got the minimum */
  176. {
  177. break; /* got enough, quit trying */
  178. }
  179. }
  180. }
  181. // printf("Got %d of %d ring pages\n",cBuffers,Disk.RingPages);
  182. return(1); /* ring buffer created */
  183. }
  184. /* --- DComp_Ring_Literal() ----------------------------------------------- */
  185. static void NEAR DComp_Ring_Literal(t_decoder_context *context, int Chr)
  186. {
  187. if (DComp.NumBytes)
  188. {
  189. DComp.NumBytes--;
  190. DComp.Cur++;
  191. *context->dec_output_curpos++ = (BYTE) Chr;
  192. }
  193. }
  194. /*
  195. * Insert output buffer contents into the page table
  196. */
  197. static void NEAR save_page(
  198. t_decoder_context * context,
  199. int page,
  200. byte * data
  201. )
  202. {
  203. PBUFFER pBuffer;
  204. long iPagefileOffset;
  205. pBuffer = Disk.PageTable[page].pBuffer; /* look up this page */
  206. if (pBuffer != NULL) /* if it's in the table */
  207. {
  208. if (pBuffer != Disk.pNewest) /* promote if not newest */
  209. {
  210. pBuffer->pLinkNewer->pLinkOlder = pBuffer->pLinkOlder;
  211. if (pBuffer->pLinkOlder != NULL) /* if there is someone older */
  212. {
  213. pBuffer->pLinkOlder->pLinkNewer = pBuffer->pLinkNewer;
  214. }
  215. else
  216. {
  217. Disk.pOldest = pBuffer->pLinkNewer;
  218. }
  219. /* link into head of chain */
  220. Disk.pNewest->pLinkNewer = pBuffer; /* newest now knows one newer */
  221. pBuffer->pLinkNewer = NULL; /* nobody's newer */
  222. pBuffer->pLinkOlder = Disk.pNewest; /* everybody's older */
  223. Disk.pNewest = pBuffer; /* I'm the newest */
  224. }
  225. memcpy(
  226. pBuffer->Buffer,
  227. data,
  228. BUFFER_SIZE
  229. );
  230. pBuffer->BufferDirty = 1; /* might already be dirty */
  231. return;
  232. }
  233. pBuffer = Disk.pOldest; /* choose the oldest buffer */
  234. if (pBuffer->BufferPage != -1) /* take it out of page table */
  235. {
  236. Disk.PageTable[pBuffer->BufferPage].pBuffer = NULL; /* not here now */
  237. if (pBuffer->BufferDirty) /* write on eject, if dirty */
  238. {
  239. iPagefileOffset = (long) pBuffer->BufferPage * BUFFER_SIZE;
  240. if (context->dec_seek(Disk.Handle,iPagefileOffset,SEEK_SET) !=
  241. iPagefileOffset)
  242. {
  243. return;
  244. }
  245. if (context->dec_write(Disk.Handle,pBuffer->Buffer,BUFFER_SIZE) !=
  246. BUFFER_SIZE)
  247. {
  248. return;
  249. }
  250. Disk.PageTable[pBuffer->BufferPage].fDiskValid = 1;
  251. }
  252. }
  253. Disk.pOldest = Disk.pOldest->pLinkNewer; /* newer is now oldest */
  254. Disk.pOldest->pLinkOlder = NULL; /* oldest knows none older */
  255. Disk.pNewest->pLinkNewer = pBuffer;
  256. pBuffer->pLinkNewer = NULL; /* link into head of chain */
  257. pBuffer->pLinkOlder = Disk.pNewest;
  258. Disk.pNewest = pBuffer;
  259. /* add new buffer to paging table */
  260. Disk.PageTable[page].pBuffer = pBuffer; /* add new to paging table */
  261. memcpy(
  262. pBuffer->Buffer,
  263. data,
  264. BUFFER_SIZE
  265. );
  266. pBuffer->BufferDirty = 1;
  267. pBuffer->BufferPage = page; /* our new page number */
  268. }
  269. static void NEAR init_last_chance_table(t_decoder_context *context)
  270. {
  271. int i;
  272. for (i = 0; i < NUM_OUTPUT_BUFFER_PAGES; i++)
  273. context->dec_pos_to_page[i] = -1;
  274. context->dec_last_chance_page_to_use = NUM_OUTPUT_BUFFER_PAGES;
  275. }
  276. static byte * NEAR last_chance_retrieve(t_decoder_context *context, int page)
  277. {
  278. int used_output_pages;
  279. int table_entry;
  280. /*
  281. * Where in the output buffer would our page be?
  282. */
  283. table_entry = Disk.PageTable[page].last_chance_ptr;
  284. /*
  285. * It's not there
  286. */
  287. if (table_entry == -1)
  288. return NULL;
  289. /*
  290. * It's now an invalid entry
  291. */
  292. if (context->dec_pos_to_page[table_entry] != page)
  293. return NULL;
  294. context->dec_pos_to_page[table_entry] = -1;
  295. Disk.PageTable[page].last_chance_ptr = -1;
  296. used_output_pages = (int) (((context->dec_output_curpos - context->dec_output_buffer) / BUFFER_SIZE) + 1);
  297. if (table_entry <= used_output_pages)
  298. return NULL;
  299. return (context->dec_output_buffer + (BUFFER_SIZE * table_entry));
  300. }
  301. static void NEAR last_chance_store(t_decoder_context *context, int page, byte *data)
  302. {
  303. int used_output_pages;
  304. int prev_owner;
  305. int dest;
  306. used_output_pages = (int) (((context->dec_output_curpos - context->dec_output_buffer) / BUFFER_SIZE) + 1);
  307. if (used_output_pages >= NUM_OUTPUT_BUFFER_PAGES)
  308. return;
  309. context->dec_last_chance_page_to_use--;
  310. if (context->dec_last_chance_page_to_use < used_output_pages)
  311. context->dec_last_chance_page_to_use = NUM_OUTPUT_BUFFER_PAGES-1;
  312. dest = context->dec_last_chance_page_to_use;
  313. /*
  314. * If any other page was pointing to this area of the buffer
  315. * as a last chance page, toast them.
  316. */
  317. prev_owner = context->dec_pos_to_page[dest];
  318. if (prev_owner != -1)
  319. {
  320. Disk.PageTable[prev_owner].last_chance_ptr = -1;
  321. }
  322. /*
  323. * Now we own this area
  324. */
  325. Disk.PageTable[page].last_chance_ptr = dest;
  326. context->dec_pos_to_page[dest] = page;
  327. memcpy(
  328. context->dec_output_buffer + (BUFFER_SIZE*dest),
  329. data,
  330. BUFFER_SIZE
  331. );
  332. }
  333. void NEAR DComp_Save_Output_Pages(
  334. t_decoder_context * context,
  335. uint bytes_decoded
  336. )
  337. {
  338. uint pages_to_save;
  339. int page_num;
  340. uint i;
  341. byte * data;
  342. /*
  343. * If we managed to allocate one big buffer in the first place, then
  344. * there are no ring pages to save.
  345. */
  346. if (DComp.Buf != NULL)
  347. return;
  348. pages_to_save = (bytes_decoded / BUFFER_SIZE);
  349. page_num = (int) ((context->dec_position_at_start & context->dec_window_mask) / (long) BUFFER_SIZE);
  350. data = context->dec_output_buffer;
  351. for (i = 0; i < pages_to_save; i++)
  352. {
  353. save_page(context, page_num, data);
  354. page_num++;
  355. if (page_num >= Disk.RingPages)
  356. page_num = 0;
  357. data += BUFFER_SIZE;
  358. }
  359. init_last_chance_table(context);
  360. }
  361. static int NEAR retrieve_page_from_disk(t_decoder_context *context, int page, byte *buffer)
  362. {
  363. long iPagefileOffset;
  364. byte *data;
  365. data = last_chance_retrieve(context, page);
  366. if (data)
  367. {
  368. memcpy(buffer, data, BUFFER_SIZE);
  369. return 1;
  370. }
  371. iPagefileOffset = (long) page * BUFFER_SIZE;
  372. if (context->dec_seek(Disk.Handle,iPagefileOffset,SEEK_SET) !=
  373. iPagefileOffset)
  374. {
  375. return 0;
  376. }
  377. if (context->dec_read(Disk.Handle,buffer,BUFFER_SIZE) !=
  378. BUFFER_SIZE)
  379. {
  380. return 0;
  381. }
  382. #ifdef DEBUG_VERIFY_LAST_CHANCE
  383. /*
  384. * verifies last chance data against disk page
  385. */
  386. if (data)
  387. {
  388. int i;
  389. for (i=0;i<BUFFER_SIZE;i++)
  390. {
  391. if (data[i] != buffer[i])
  392. {
  393. printf("page %3d, err@%5d: %3d vs %3d (real)\n",
  394. page, i, data[i], buffer[i]);
  395. }
  396. }
  397. }
  398. #endif
  399. return 1;
  400. }
  401. /* --- DComp_Ring_Load() -------------------------------------------------- */
  402. /* Bring page into a buffer, return a pointer to that buffer. fWrite */
  403. /* indicates the caller's intentions for this buffer, NZ->consider it */
  404. /* dirty now. Returns NULL if there is a paging fault (callback */
  405. /* failed) or if any internal assertions fail. */
  406. static BYTE * NEAR DComp_Ring_Load(
  407. t_decoder_context * context,
  408. int page,
  409. int fWrite
  410. )
  411. {
  412. PBUFFER pBuffer;
  413. long iPagefileOffset;
  414. pBuffer = Disk.PageTable[page].pBuffer; /* look up this page */
  415. if (pBuffer != NULL) /* if it's in the table */
  416. {
  417. if (pBuffer != Disk.pNewest) /* promote if not newest */
  418. {
  419. pBuffer->pLinkNewer->pLinkOlder = pBuffer->pLinkOlder;
  420. if (pBuffer->pLinkOlder != NULL) /* if there is someone older */
  421. {
  422. pBuffer->pLinkOlder->pLinkNewer = pBuffer->pLinkNewer;
  423. }
  424. else
  425. {
  426. Disk.pOldest = pBuffer->pLinkNewer;
  427. }
  428. /* link into head of chain */
  429. Disk.pNewest->pLinkNewer = pBuffer; /* newest now knows one newer */
  430. pBuffer->pLinkNewer = NULL; /* nobody's newer */
  431. pBuffer->pLinkOlder = Disk.pNewest; /* everybody's older */
  432. Disk.pNewest = pBuffer; /* I'm the newest */
  433. }
  434. pBuffer->BufferDirty |= fWrite; /* might already be dirty */
  435. return(pBuffer->Buffer);
  436. }
  437. /* desired page is not in the table; discard oldest & use it */
  438. pBuffer = Disk.pOldest; /* choose the oldest buffer */
  439. if (pBuffer->BufferPage != -1) /* take it out of page table */
  440. {
  441. Disk.PageTable[pBuffer->BufferPage].pBuffer = NULL; /* not here now */
  442. if (pBuffer->BufferDirty) /* write on eject, if dirty */
  443. {
  444. iPagefileOffset = (long) pBuffer->BufferPage * BUFFER_SIZE;
  445. if (context->dec_seek(Disk.Handle,iPagefileOffset,SEEK_SET) !=
  446. iPagefileOffset)
  447. {
  448. return(NULL);
  449. }
  450. if (context->dec_write(Disk.Handle,pBuffer->Buffer,BUFFER_SIZE) !=
  451. BUFFER_SIZE)
  452. {
  453. return(NULL);
  454. }
  455. Disk.PageTable[pBuffer->BufferPage].fDiskValid = 1;
  456. }
  457. last_chance_store(context, pBuffer->BufferPage, pBuffer->Buffer);
  458. }
  459. Disk.pOldest = Disk.pOldest->pLinkNewer; /* newer is now oldest */
  460. Disk.pOldest->pLinkOlder = NULL; /* oldest knows none older */
  461. Disk.pNewest->pLinkNewer = pBuffer;
  462. pBuffer->pLinkNewer = NULL; /* link into head of chain */
  463. pBuffer->pLinkOlder = Disk.pNewest;
  464. Disk.pNewest = pBuffer;
  465. /* add new buffer to paging table */
  466. Disk.PageTable[page].pBuffer = pBuffer; /* add new to paging table */
  467. /* if this disk page is valid, load it */
  468. if (Disk.PageTable[page].fDiskValid)
  469. {
  470. if (retrieve_page_from_disk(context, page, pBuffer->Buffer) == 0)
  471. return NULL;
  472. }
  473. else if (!fWrite)
  474. {
  475. /* assertion failure, trying to load a never-written page from disk */
  476. return(NULL);
  477. }
  478. pBuffer->BufferDirty = fWrite; /* might be dirty now */
  479. pBuffer->BufferPage = page; /* our new page number */
  480. return(pBuffer->Buffer); /* return new handle */
  481. }
  482. /* --- DComp_Ring_Match() ------------------------------------------------- */
  483. static void NEAR DComp_Ring_Match(t_decoder_context *context, MATCH Match)
  484. {
  485. long SrcOffset; /* offset into output ring */
  486. int SrcPage; /* page # where that offset lies */
  487. int Chunk; /* number of bytes this pass */
  488. BYTE FAR *SrcPtr; /* pointer to source bytes */
  489. BYTE *SrcBuffer; /* buffer where source data is */
  490. int SrcBufferOffset; /* offset within the buffer */
  491. if (DComp.NumBytes >= (unsigned) Match.Len)
  492. {
  493. SrcOffset = (DComp.Cur - Match.Dist) & context->dec_window_mask;
  494. DComp.NumBytes -= Match.Len;
  495. DComp.Cur += Match.Len;
  496. while (Match.Len)
  497. {
  498. /* Limit: number of bytes requested */
  499. Chunk = Match.Len; /* try for everything */
  500. /*
  501. * Match source inside current output buffer?
  502. */
  503. if (Match.Dist <= (long) (context->dec_output_curpos - context->dec_output_buffer))
  504. {
  505. SrcPtr = context->dec_output_curpos - Match.Dist;
  506. while (Chunk--) /* copy this chunk */
  507. {
  508. *context->dec_output_curpos++ = *SrcPtr++;
  509. }
  510. return;
  511. }
  512. else
  513. {
  514. SrcPage = (int) (SrcOffset / BUFFER_SIZE);
  515. SrcBufferOffset = (int) (SrcOffset % BUFFER_SIZE);
  516. SrcBuffer = DComp_Ring_Load(context,SrcPage,0); /* for reading */
  517. if (SrcBuffer == NULL)
  518. {
  519. DComp.NumBytes = 0;
  520. DComp.fRingFault = 1;
  521. return;
  522. }
  523. SrcPtr = SrcBuffer + SrcBufferOffset;
  524. /* Limit: number of source bytes on input page */
  525. if ((BUFFER_SIZE - SrcBufferOffset) < Chunk)
  526. Chunk = (BUFFER_SIZE - SrcBufferOffset);
  527. SrcOffset += Chunk;
  528. SrcOffset &= context->dec_window_mask;
  529. Match.Len -= Chunk;
  530. while (Chunk--) /* copy this chunk */
  531. {
  532. *context->dec_output_curpos++ = *SrcPtr++;
  533. }
  534. }
  535. } /* while Match.Len */
  536. } /* if Match.Len size OK */
  537. else /* match too large to fit */
  538. {
  539. DComp.NumBytes = 0;
  540. DComp.fOutOverflow = 1;
  541. }
  542. }
  543. /* --- DComp_Ring_Reset() ------------------------------------------------- */
  544. static void NEAR DComp_Ring_Reset(t_decoder_context *context)
  545. {
  546. PBUFFER walker;
  547. int iPage;
  548. for (walker = Disk.pNewest; walker != NULL; walker = walker->pLinkOlder)
  549. {
  550. walker->BufferPage = -1; /* buffer is not valid */
  551. walker->BufferDirty = 0; /* and doesn't need writing */
  552. }
  553. for (iPage = 0; iPage < Disk.RingPages; iPage++)
  554. {
  555. Disk.PageTable[iPage].pBuffer = NULL; /* not in memory */
  556. Disk.PageTable[iPage].fDiskValid = 0; /* not on disk */
  557. Disk.PageTable[iPage].last_chance_ptr = -1; /* not in last chance list */
  558. }
  559. init_last_chance_table(context);
  560. context->dec_last_chance_page_to_use = NUM_OUTPUT_BUFFER_PAGES;
  561. }