write.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include "lib9.h"
  2. #include "draw.h"
  3. #include "memdraw.h"
  4. #define CHUNK 8000
  5. #define HSHIFT 3 /* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */
  6. #define NHASH (1<<(HSHIFT*NMATCH))
  7. #define HMASK (NHASH-1)
  8. #define hupdate(h, c) ((((h)<<HSHIFT)^(c))&HMASK)
  9. typedef struct Hlist Hlist;
  10. struct Hlist{
  11. uchar *s;
  12. Hlist *next, *prev;
  13. };
  14. int
  15. writememimage(int fd, Memimage *i)
  16. {
  17. uchar *outbuf, *outp, *eout; /* encoded data, pointer, end */
  18. uchar *loutp; /* start of encoded line */
  19. Hlist *hash; /* heads of hash chains of past strings */
  20. Hlist *chain, *hp; /* hash chain members, pointer */
  21. Hlist *cp; /* next Hlist to fall out of window */
  22. int h; /* hash value */
  23. uchar *line, *eline; /* input line, end pointer */
  24. uchar *data, *edata; /* input buffer, end pointer */
  25. ulong n; /* length of input buffer */
  26. ulong nb; /* # of bytes returned by unloadimage */
  27. int bpl; /* input line length */
  28. int offs, runlen; /* offset, length of consumed data */
  29. uchar dumpbuf[NDUMP]; /* dump accumulator */
  30. int ndump; /* length of dump accumulator */
  31. int miny, dy; /* y values while unloading input */
  32. int ncblock; /* size of compressed blocks */
  33. Rectangle r;
  34. uchar *p, *q, *s, *es, *t;
  35. char hdr[11+5*12+1];
  36. char cbuf[20];
  37. r = i->r;
  38. bpl = bytesperline(r, i->depth);
  39. n = Dy(r)*bpl;
  40. data = malloc(n);
  41. ncblock = _compblocksize(r, i->depth);
  42. outbuf = malloc(ncblock);
  43. hash = malloc(NHASH*sizeof(Hlist));
  44. chain = malloc(NMEM*sizeof(Hlist));
  45. if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){
  46. ErrOut:
  47. free(data);
  48. free(outbuf);
  49. free(hash);
  50. free(chain);
  51. return -1;
  52. }
  53. for(miny = r.min.y; miny != r.max.y; miny += dy){
  54. dy = r.max.y-miny;
  55. if(dy*bpl > CHUNK)
  56. dy = CHUNK/bpl;
  57. nb = unloadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy),
  58. data+(miny-r.min.y)*bpl, dy*bpl);
  59. if(nb != dy*bpl)
  60. goto ErrOut;
  61. }
  62. sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ",
  63. chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y);
  64. if(write(fd, hdr, 11+5*12) != 11+5*12)
  65. goto ErrOut;
  66. edata = data+n;
  67. eout = outbuf+ncblock;
  68. line = data;
  69. r.max.y = r.min.y;
  70. while(line != edata){
  71. memset(hash, 0, NHASH*sizeof(Hlist));
  72. memset(chain, 0, NMEM*sizeof(Hlist));
  73. cp = chain;
  74. h = 0;
  75. outp = outbuf;
  76. for(n = 0; n != NMATCH; n++)
  77. h = hupdate(h, line[n]);
  78. loutp = outbuf;
  79. while(line != edata){
  80. ndump = 0;
  81. eline = line+bpl;
  82. for(p = line; p != eline; ){
  83. if(eline-p < NRUN)
  84. es = eline;
  85. else
  86. es = p+NRUN;
  87. q = 0;
  88. runlen = 0;
  89. for(hp = hash[h].next; hp; hp = hp->next){
  90. s = p + runlen;
  91. if(s >= es)
  92. continue;
  93. t = hp->s + runlen;
  94. for(; s >= p; s--)
  95. if(*s != *t--)
  96. goto matchloop;
  97. t += runlen+2;
  98. s += runlen+2;
  99. for(; s < es; s++)
  100. if(*s != *t++)
  101. break;
  102. n = s-p;
  103. if(n > runlen){
  104. runlen = n;
  105. q = hp->s;
  106. if(n == NRUN)
  107. break;
  108. }
  109. matchloop: ;
  110. }
  111. if(runlen < NMATCH){
  112. if(ndump == NDUMP){
  113. if(eout-outp < ndump+1)
  114. goto Bfull;
  115. *outp++ = ndump-1+128;
  116. memmove(outp, dumpbuf, ndump);
  117. outp += ndump;
  118. ndump = 0;
  119. }
  120. dumpbuf[ndump++] = *p;
  121. runlen = 1;
  122. }
  123. else{
  124. if(ndump != 0){
  125. if(eout-outp < ndump+1)
  126. goto Bfull;
  127. *outp++ = ndump-1+128;
  128. memmove(outp, dumpbuf, ndump);
  129. outp += ndump;
  130. ndump = 0;
  131. }
  132. offs = p-q-1;
  133. if(eout-outp < 2)
  134. goto Bfull;
  135. *outp++ = ((runlen-NMATCH)<<2) + (offs>>8);
  136. *outp++ = offs&255;
  137. }
  138. for(q = p+runlen; p != q; p++){
  139. if(cp->prev)
  140. cp->prev->next = 0;
  141. cp->next = hash[h].next;
  142. cp->prev = &hash[h];
  143. if(cp->next)
  144. cp->next->prev = cp;
  145. cp->prev->next = cp;
  146. cp->s = p;
  147. if(++cp == &chain[NMEM])
  148. cp = chain;
  149. if(edata-p > NMATCH)
  150. h = hupdate(h, p[NMATCH]);
  151. }
  152. }
  153. if(ndump != 0){
  154. if(eout-outp < ndump+1)
  155. goto Bfull;
  156. *outp++ = ndump-1+128;
  157. memmove(outp, dumpbuf, ndump);
  158. outp += ndump;
  159. }
  160. line = eline;
  161. loutp = outp;
  162. r.max.y++;
  163. }
  164. Bfull:
  165. if(loutp == outbuf)
  166. goto ErrOut;
  167. n = loutp-outbuf;
  168. sprint(hdr, "%11d %11ld ", r.max.y, n);
  169. write(fd, hdr, 2*12);
  170. write(fd, outbuf, n);
  171. r.min.y = r.max.y;
  172. }
  173. free(data);
  174. free(outbuf);
  175. free(hash);
  176. free(chain);
  177. return 0;
  178. }