bzip2-ruby-rb20 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ #ifndef _RB_BZIP2_READER_H_
2
+ #define _RB_BZIP2_READER_H_
3
+
4
+ #include <ruby.h>
5
+
6
+ /* Instance methods */
7
+ VALUE bz_reader_init(int argc, VALUE *argv, VALUE obj);
8
+ VALUE bz_reader_read(int argc, VALUE *argv, VALUE obj);
9
+ VALUE bz_reader_ungetc(VALUE obj, VALUE a);
10
+ VALUE bz_reader_ungets(VALUE obj, VALUE a);
11
+ VALUE bz_reader_getc(VALUE obj);
12
+ VALUE bz_reader_readchar(VALUE obj);
13
+ VALUE bz_reader_gets_m(int argc, VALUE *argv, VALUE obj);
14
+ VALUE bz_reader_readline(int argc, VALUE *argv, VALUE obj);
15
+ VALUE bz_reader_readlines(int argc, VALUE *argv, VALUE obj);
16
+ VALUE bz_reader_each_line(int argc, VALUE *argv, VALUE obj);
17
+ VALUE bz_reader_each_byte(VALUE obj);
18
+ VALUE bz_reader_unused(VALUE obj);
19
+ VALUE bz_reader_set_unused(VALUE obj, VALUE a);
20
+ VALUE bz_reader_eoz(VALUE obj);
21
+ VALUE bz_reader_eof(VALUE obj);
22
+ VALUE bz_reader_closed(VALUE obj);
23
+ VALUE bz_reader_close(VALUE obj);
24
+ VALUE bz_reader_close_bang(VALUE obj);
25
+ VALUE bz_reader_finish(VALUE obj);
26
+ VALUE bz_reader_lineno(VALUE obj);
27
+ VALUE bz_reader_set_lineno(VALUE obj, VALUE lineno);
28
+
29
+ /* Class methods */
30
+ VALUE bz_reader_s_alloc(VALUE obj);
31
+ VALUE bz_reader_s_open(int argc, VALUE *argv, VALUE obj);
32
+ VALUE bz_reader_s_foreach(int argc, VALUE *argv, VALUE obj);
33
+ VALUE bz_reader_s_readlines(int argc, VALUE *argv, VALUE obj);
34
+
35
+ #endif
@@ -0,0 +1,453 @@
1
+ #include <ruby.h>
2
+ #include <unistd.h>
3
+ #include "common.h"
4
+ #include "writer.h"
5
+
6
+ struct bz_iv * bz_find_struct(VALUE obj, void *ptr, int *posp) {
7
+ struct bz_iv *bziv;
8
+ int i;
9
+
10
+ for (i = 0; i < RARRAY_LEN(bz_internal_ary); i++) {
11
+ Data_Get_Struct(RARRAY_PTR(bz_internal_ary)[i], struct bz_iv, bziv);
12
+ if (ptr) {
13
+ #ifndef RUBY_19_COMPATIBILITY
14
+ if (TYPE(bziv->io) == T_FILE && RFILE(bziv->io)->fptr == (OpenFile *)ptr) {
15
+ #else
16
+ if (TYPE(bziv->io) == T_FILE && RFILE(bziv->io)->fptr == (rb_io_t *)ptr) {
17
+ #endif
18
+ if (posp) {
19
+ *posp = i;
20
+ }
21
+ return bziv;
22
+ } else if (TYPE(bziv->io) == T_DATA && DATA_PTR(bziv->io) == ptr) {
23
+ if (posp) *posp = i;
24
+ return bziv;
25
+ }
26
+ } else if (bziv->io == obj) {
27
+ if (posp) *posp = i;
28
+ return bziv;
29
+ }
30
+ }
31
+ if (posp) *posp = -1;
32
+ return 0;
33
+ }
34
+
35
+ VALUE bz_str_closed(VALUE obj) {
36
+ return Qfalse;
37
+ }
38
+
39
+ void bz_io_data_finalize(void *ptr) {
40
+ struct bz_file *bzf;
41
+ struct bz_iv *bziv;
42
+ int pos;
43
+
44
+ bziv = bz_find_struct(0, ptr, &pos);
45
+ if (bziv) {
46
+ rb_ary_delete_at(bz_internal_ary, pos);
47
+ Data_Get_Struct(bziv->bz2, struct bz_file, bzf);
48
+ rb_protect((VALUE (*)(VALUE))bz_writer_internal_flush, (VALUE)bzf, 0);
49
+ RDATA(bziv->bz2)->dfree = free;
50
+ if (bziv->finalize) {
51
+ (*bziv->finalize)(ptr);
52
+ } else if (TYPE(bzf->io) == T_FILE) {
53
+ #ifndef RUBY_19_COMPATIBILITY
54
+ OpenFile *file = (OpenFile *)ptr;
55
+ if (file->f) {
56
+ fclose(file->f);
57
+ file->f = 0;
58
+ }
59
+ if (file->f2) {
60
+ fclose(file->f2);
61
+ file->f2 = 0;
62
+ }
63
+ #else
64
+ rb_io_t *file = (rb_io_t *)ptr;
65
+ if (file->fd) {
66
+ close(file->fd);
67
+
68
+ file->fd = 0;
69
+ }
70
+ if (file->stdio_file) {
71
+ fclose(file->stdio_file);
72
+ file->stdio_file = 0;
73
+ }
74
+ #endif
75
+ }
76
+ }
77
+
78
+ }
79
+
80
+ int bz_writer_internal_flush(struct bz_file *bzf) {
81
+ int closed = 1;
82
+
83
+ if (rb_respond_to(bzf->io, id_closed)) {
84
+ closed = RTEST(rb_funcall2(bzf->io, id_closed, 0, 0));
85
+ }
86
+ if (bzf->buf) {
87
+ if (!closed && bzf->state == BZ_OK) {
88
+ bzf->bzs.next_in = NULL;
89
+ bzf->bzs.avail_in = 0;
90
+ do {
91
+ bzf->bzs.next_out = bzf->buf;
92
+ bzf->bzs.avail_out = bzf->buflen;
93
+ bzf->state = BZ2_bzCompress(&(bzf->bzs), BZ_FINISH);
94
+ if (bzf->state != BZ_FINISH_OK && bzf->state != BZ_STREAM_END) {
95
+ break;
96
+ }
97
+ if (bzf->bzs.avail_out < bzf->buflen) {
98
+ rb_funcall(bzf->io, id_write, 1, rb_str_new(bzf->buf, bzf->buflen - bzf->bzs.avail_out));
99
+ }
100
+ } while (bzf->state != BZ_STREAM_END);
101
+ }
102
+ free(bzf->buf);
103
+ bzf->buf = 0;
104
+ BZ2_bzCompressEnd(&(bzf->bzs));
105
+ bzf->state = BZ_OK;
106
+ if (!closed && rb_respond_to(bzf->io, id_flush)) {
107
+ rb_funcall2(bzf->io, id_flush, 0, 0);
108
+ }
109
+ }
110
+ return closed;
111
+ }
112
+
113
+ VALUE bz_writer_internal_close(struct bz_file *bzf) {
114
+ struct bz_iv *bziv;
115
+ int pos, closed;
116
+ VALUE res;
117
+
118
+ closed = bz_writer_internal_flush(bzf);
119
+ bziv = bz_find_struct(bzf->io, 0, &pos);
120
+ if (bziv) {
121
+ if (TYPE(bzf->io) == T_FILE) {
122
+ RFILE(bzf->io)->fptr->finalize = bziv->finalize;
123
+ } else if (TYPE(bziv->io) == T_DATA) {
124
+ RDATA(bziv->io)->dfree = bziv->finalize;
125
+ }
126
+ RDATA(bziv->bz2)->dfree = free;
127
+ bziv->bz2 = 0;
128
+ rb_ary_delete_at(bz_internal_ary, pos);
129
+ }
130
+ if (bzf->flags & BZ2_RB_CLOSE) {
131
+ bzf->flags &= ~BZ2_RB_CLOSE;
132
+ if (!closed && rb_respond_to(bzf->io, id_close)) {
133
+ rb_funcall2(bzf->io, id_close, 0, 0);
134
+ }
135
+ res = Qnil;
136
+ } else {
137
+ res = bzf->io;
138
+ }
139
+ bzf->io = Qnil;
140
+ return res;
141
+ }
142
+
143
+ /*
144
+ * Closes this writer for further use. The remaining data is compressed and
145
+ * flushed.
146
+ *
147
+ * If the writer was constructed with an io object, that object is returned.
148
+ * Otherwise, the actual compressed data is returned
149
+ *
150
+ * writer = Bzip2::Writer.new File.open('path', 'w')
151
+ * writer << 'a'
152
+ * writer.close # => #<File:path>
153
+ *
154
+ * writer = Bzip2::Writer.new
155
+ * writer << 'a'
156
+ * writer.close # => "BZh91AY&SY...
157
+ */
158
+ VALUE bz_writer_close(VALUE obj) {
159
+ struct bz_file *bzf;
160
+ VALUE res;
161
+
162
+ Get_BZ2(obj, bzf);
163
+ res = bz_writer_internal_close(bzf);
164
+ #ifndef RUBINIUS
165
+ if (!NIL_P(res) && (bzf->flags & BZ2_RB_INTERNAL)) {
166
+ RBASIC(res)->klass = rb_cString;
167
+ }
168
+ #endif
169
+ return res;
170
+ }
171
+
172
+ /*
173
+ * Calls Bzip2::Writer#close and then does some more stuff...
174
+ */
175
+ VALUE bz_writer_close_bang(VALUE obj) {
176
+ struct bz_file *bzf;
177
+ int closed;
178
+
179
+ Get_BZ2(obj, bzf);
180
+ closed = bzf->flags & (BZ2_RB_INTERNAL|BZ2_RB_CLOSE);
181
+ bz_writer_close(obj);
182
+ if (!closed && rb_respond_to(bzf->io, id_close)) {
183
+ if (rb_respond_to(bzf->io, id_closed)) {
184
+ closed = RTEST(rb_funcall2(bzf->io, id_closed, 0, 0));
185
+ }
186
+ if (!closed) {
187
+ rb_funcall2(bzf->io, id_close, 0, 0);
188
+ }
189
+ }
190
+ return Qnil;
191
+ }
192
+
193
+ /*
194
+ * Tests whether this writer is closed
195
+ *
196
+ * @return [Boolean] +true+ if the writer is closed or +false+ otherwise
197
+ */
198
+ VALUE bz_writer_closed(VALUE obj) {
199
+ struct bz_file *bzf;
200
+
201
+ Data_Get_Struct(obj, struct bz_file, bzf);
202
+ return RTEST(bzf->io)?Qfalse:Qtrue;
203
+ }
204
+
205
+ void bz_writer_free(struct bz_file *bzf) {
206
+ bz_writer_internal_close(bzf);
207
+ free(bzf);
208
+ }
209
+
210
+ /*
211
+ * Internally allocates information about a new writer
212
+ * @private
213
+ */
214
+ VALUE bz_writer_s_alloc(VALUE obj) {
215
+ struct bz_file *bzf;
216
+ VALUE res;
217
+ res = Data_Make_Struct(obj, struct bz_file, bz_file_mark, bz_writer_free, bzf);
218
+ bzf->bzs.bzalloc = bz_malloc;
219
+ bzf->bzs.bzfree = bz_free;
220
+ bzf->blocks = DEFAULT_BLOCKS;
221
+ bzf->state = BZ_OK;
222
+ return res;
223
+ }
224
+
225
+ /*
226
+ * Flushes all of the data in this stream to the underlying IO.
227
+ *
228
+ * If this writer was constructed with no underlying io object, the compressed
229
+ * data is returned as a string.
230
+ *
231
+ * @return [String, nil]
232
+ * @raise [IOError] if the stream has been closed
233
+ */
234
+ VALUE bz_writer_flush(VALUE obj) {
235
+ struct bz_file *bzf;
236
+
237
+ Get_BZ2(obj, bzf);
238
+ if (bzf->flags & BZ2_RB_INTERNAL) {
239
+ return bz_writer_close(obj);
240
+ }
241
+ bz_writer_internal_flush(bzf);
242
+ return Qnil;
243
+ }
244
+
245
+ /*
246
+ * call-seq:
247
+ * open(filename, mode='wb', &block=nil) -> Bzip2::Writer
248
+ *
249
+ * @param [String] filename the name of the file to write to
250
+ * @param [String] mode a mode string passed to Kernel#open
251
+ * @yieldparam [Bzip2::Writer] writer the Bzip2::Writer instance
252
+ *
253
+ * If a block is given, the created Bzip2::Writer instance is yielded to the
254
+ * block and will be closed when the block completes. It is guaranteed via
255
+ * +ensure+ that the writer is closed
256
+ *
257
+ * If a block is not given, a Bzip2::Writer instance will be returned
258
+ *
259
+ * Bzip2::Writer.open('file') { |f| f << data }
260
+ *
261
+ * writer = Bzip2::Writer.open('file')
262
+ * writer << data
263
+ * writer.close
264
+ *
265
+ * @return [Bzip2::Writer, nil]
266
+ */
267
+ VALUE bz_writer_s_open(int argc, VALUE *argv, VALUE obj) {
268
+ VALUE res;
269
+ struct bz_file *bzf;
270
+
271
+ if (argc < 1) {
272
+ rb_raise(rb_eArgError, "invalid number of arguments");
273
+ }
274
+ if (argc == 1) {
275
+ argv[0] = rb_funcall(rb_mKernel, id_open, 2, argv[0],
276
+ rb_str_new2("wb"));
277
+ } else {
278
+ argv[1] = rb_funcall2(rb_mKernel, id_open, 2, argv);
279
+ argv += 1;
280
+ argc -= 1;
281
+ }
282
+ res = rb_funcall2(obj, id_new, argc, argv);
283
+ Data_Get_Struct(res, struct bz_file, bzf);
284
+ bzf->flags |= BZ2_RB_CLOSE;
285
+ if (rb_block_given_p()) {
286
+ return rb_ensure(rb_yield, res, bz_writer_close, res);
287
+ }
288
+ return res;
289
+ }
290
+
291
+ VALUE bz_str_write(VALUE obj, VALUE str) {
292
+ if (TYPE(str) != T_STRING) {
293
+ rb_raise(rb_eArgError, "expected a String");
294
+ }
295
+ if (RSTRING_LEN(str)) {
296
+ rb_str_cat(obj, RSTRING_PTR(str), RSTRING_LEN(str));
297
+ }
298
+ return str;
299
+ }
300
+
301
+ /*
302
+ * call-seq:
303
+ * initialize(io = nil)
304
+ *
305
+ * @param [File] io the file which to write compressed data to
306
+ *
307
+ * Creates a new Bzip2::Writer for compressing a stream of data. An optional
308
+ * io object (something responding to +write+) can be supplied which data
309
+ * will be written to.
310
+ *
311
+ * If nothing is given, the Bzip2::Writer#flush method can be called to retrieve
312
+ * the compressed stream so far.
313
+ *
314
+ * writer = Bzip2::Writer.new File.open('files.bz2')
315
+ * writer << 'a'
316
+ * writer << 'b'
317
+ * writer.close
318
+ *
319
+ * writer = Bzip2::Writer.new
320
+ * writer << 'abcde'
321
+ * writer.flush # => 'abcde' compressed
322
+ */
323
+ VALUE bz_writer_init(int argc, VALUE *argv, VALUE obj) {
324
+ struct bz_file *bzf;
325
+ int blocks = DEFAULT_BLOCKS;
326
+ int work = 0;
327
+ VALUE a, b, c;
328
+
329
+ switch(rb_scan_args(argc, argv, "03", &a, &b, &c)) {
330
+ case 3:
331
+ work = NUM2INT(c);
332
+ /* ... */
333
+ case 2:
334
+ blocks = NUM2INT(b);
335
+ }
336
+ Data_Get_Struct(obj, struct bz_file, bzf);
337
+ if (NIL_P(a)) {
338
+ a = rb_str_new(0, 0);
339
+ rb_define_method(rb_singleton_class(a), "write", bz_str_write, 1);
340
+ rb_define_method(rb_singleton_class(a), "closed?", bz_str_closed, 0);
341
+ bzf->flags |= BZ2_RB_INTERNAL;
342
+ } else {
343
+ VALUE iv;
344
+ struct bz_iv *bziv;
345
+ #ifndef RUBY_19_COMPATIBILITY
346
+ OpenFile *fptr;
347
+ #else
348
+ rb_io_t *fptr;
349
+ #endif
350
+
351
+ rb_io_taint_check(a);
352
+ if (!rb_respond_to(a, id_write)) {
353
+ rb_raise(rb_eArgError, "first argument must respond to #write");
354
+ }
355
+ if (TYPE(a) == T_FILE) {
356
+ GetOpenFile(a, fptr);
357
+ rb_io_check_writable(fptr);
358
+ } else if (rb_respond_to(a, id_closed)) {
359
+ iv = rb_funcall2(a, id_closed, 0, 0);
360
+ if (RTEST(iv)) {
361
+ rb_raise(rb_eArgError, "closed object");
362
+ }
363
+ }
364
+ bziv = bz_find_struct(a, 0, 0);
365
+ if (bziv) {
366
+ if (RTEST(bziv->bz2)) {
367
+ rb_raise(rb_eArgError, "invalid data type");
368
+ }
369
+ bziv->bz2 = obj;
370
+ } else {
371
+ iv = Data_Make_Struct(rb_cData, struct bz_iv, 0, free, bziv);
372
+ bziv->io = a;
373
+ bziv->bz2 = obj;
374
+ rb_ary_push(bz_internal_ary, iv);
375
+ }
376
+ switch (TYPE(a)) {
377
+ case T_FILE:
378
+ bziv->finalize = RFILE(a)->fptr->finalize;
379
+ RFILE(a)->fptr->finalize = (void (*)(struct rb_io_t *, int))bz_io_data_finalize;
380
+ break;
381
+ case T_DATA:
382
+ bziv->finalize = RDATA(a)->dfree;
383
+ RDATA(a)->dfree = bz_io_data_finalize;
384
+ break;
385
+ }
386
+ }
387
+ bzf->io = a;
388
+ bzf->blocks = blocks;
389
+ bzf->work = work;
390
+ return obj;
391
+ }
392
+
393
+ /*
394
+ * call-seq:
395
+ * write(data)
396
+ * Actually writes some data into this stream.
397
+ *
398
+ * @param [String] data the data to write
399
+ * @return [Integer] the length of the data which was written (uncompressed)
400
+ * @raise [IOError] if the stream has been closed
401
+ */
402
+ VALUE bz_writer_write(VALUE obj, VALUE a) {
403
+ struct bz_file *bzf;
404
+ int n;
405
+
406
+ a = rb_obj_as_string(a);
407
+ Get_BZ2(obj, bzf);
408
+ if (!bzf->buf) {
409
+ if (bzf->state != BZ_OK) {
410
+ bz_raise(bzf->state);
411
+ }
412
+ bzf->state = BZ2_bzCompressInit(&(bzf->bzs), bzf->blocks,
413
+ 0, bzf->work);
414
+ if (bzf->state != BZ_OK) {
415
+ bz_writer_internal_flush(bzf);
416
+ bz_raise(bzf->state);
417
+ }
418
+ bzf->buf = ALLOC_N(char, BZ_RB_BLOCKSIZE + 1);
419
+ bzf->buflen = BZ_RB_BLOCKSIZE;
420
+ bzf->buf[0] = bzf->buf[bzf->buflen] = '\0';
421
+ }
422
+ bzf->bzs.next_in = RSTRING_PTR(a);
423
+ bzf->bzs.avail_in = (int) RSTRING_LEN(a);
424
+ while (bzf->bzs.avail_in) {
425
+ bzf->bzs.next_out = bzf->buf;
426
+ bzf->bzs.avail_out = bzf->buflen;
427
+ bzf->state = BZ2_bzCompress(&(bzf->bzs), BZ_RUN);
428
+ if (bzf->state == BZ_SEQUENCE_ERROR || bzf->state == BZ_PARAM_ERROR) {
429
+ bz_writer_internal_flush(bzf);
430
+ bz_raise(bzf->state);
431
+ }
432
+ bzf->state = BZ_OK;
433
+ if (bzf->bzs.avail_out < bzf->buflen) {
434
+ n = bzf->buflen - bzf->bzs.avail_out;
435
+ rb_funcall(bzf->io, id_write, 1, rb_str_new(bzf->buf, n));
436
+ }
437
+ }
438
+ return INT2NUM(RSTRING_LEN(a));
439
+ }
440
+
441
+ /*
442
+ * call-seq:
443
+ * putc(num)
444
+ *
445
+ * Write one byte into this stream.
446
+ * @param [Integer] num the number value of the character to write
447
+ * @return [Integer] always 1
448
+ * @raise [IOError] if the stream has been closed
449
+ */
450
+ VALUE bz_writer_putc(VALUE obj, VALUE a) {
451
+ char c = NUM2CHR(a);
452
+ return bz_writer_write(obj, rb_str_new(&c, 1));
453
+ }