write.c 4.7 KB

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