origami 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. data/README +1 -1
  2. data/bin/gui/hexview.rb +1 -1
  3. data/bin/gui/menu.rb +4 -4
  4. data/bin/gui/textview.rb +6 -4
  5. data/bin/gui/treeview.rb +4 -4
  6. data/bin/gui/walker.rb +1 -1
  7. data/bin/pdf2graph +1 -1
  8. data/bin/pdf2pdfa +1 -1
  9. data/bin/pdf2ruby +1 -1
  10. data/bin/pdfcocoon +1 -1
  11. data/bin/pdfcop +1 -1
  12. data/bin/pdfdecompress +1 -1
  13. data/bin/pdfdecrypt +1 -1
  14. data/bin/pdfencrypt +1 -1
  15. data/bin/pdfextract +75 -14
  16. data/bin/pdfmetadata +1 -1
  17. data/bin/shell/.irbrc +1 -1
  18. data/{origami.rb → lib/origami.rb} +3 -3
  19. data/{origami → lib/origami}/3d.rb +0 -0
  20. data/{origami → lib/origami}/acroform.rb +2 -2
  21. data/{origami → lib/origami}/actions.rb +0 -0
  22. data/{origami → lib/origami}/annotations.rb +0 -0
  23. data/{origami → lib/origami}/array.rb +0 -0
  24. data/{origami → lib/origami}/boolean.rb +0 -0
  25. data/{origami → lib/origami}/catalog.rb +0 -0
  26. data/{origami → lib/origami}/destinations.rb +0 -0
  27. data/{origami → lib/origami}/dictionary.rb +0 -0
  28. data/{origami → lib/origami}/docmdp.rb +0 -0
  29. data/{origami → lib/origami}/encryption.rb +9 -7
  30. data/{origami → lib/origami}/export.rb +0 -0
  31. data/lib/origami/extensions/fdf.rb +257 -0
  32. data/{origami/adobe → lib/origami/extensions}/ppklite.rb +3 -1
  33. data/{origami → lib/origami}/file.rb +0 -0
  34. data/{origami → lib/origami}/filters.rb +0 -0
  35. data/{origami → lib/origami}/filters/ascii.rb +0 -0
  36. data/{origami → lib/origami}/filters/ccitt.rb +0 -1
  37. data/{origami → lib/origami}/filters/crypt.rb +0 -0
  38. data/{origami → lib/origami}/filters/dct.rb +0 -0
  39. data/{origami → lib/origami}/filters/flate.rb +0 -0
  40. data/{origami → lib/origami}/filters/jbig2.rb +0 -0
  41. data/{origami → lib/origami}/filters/jpx.rb +0 -0
  42. data/{origami → lib/origami}/filters/lzw.rb +0 -0
  43. data/{origami → lib/origami}/filters/predictors.rb +0 -0
  44. data/{origami → lib/origami}/filters/runlength.rb +0 -0
  45. data/{origami → lib/origami}/font.rb +0 -0
  46. data/{origami → lib/origami}/functions.rb +0 -0
  47. data/{origami → lib/origami}/graphics.rb +0 -0
  48. data/{origami → lib/origami}/graphics/colors.rb +45 -23
  49. data/{origami → lib/origami}/graphics/instruction.rb +0 -0
  50. data/{origami → lib/origami}/graphics/path.rb +0 -0
  51. data/{origami → lib/origami}/graphics/patterns.rb +0 -0
  52. data/{origami → lib/origami}/graphics/render.rb +0 -0
  53. data/{origami → lib/origami}/graphics/state.rb +2 -2
  54. data/{origami → lib/origami}/graphics/text.rb +0 -0
  55. data/{origami → lib/origami}/graphics/xobject.rb +219 -0
  56. data/{origami → lib/origami}/header.rb +0 -0
  57. data/{origami → lib/origami}/javascript.rb +0 -0
  58. data/{origami → lib/origami}/linearization.rb +0 -0
  59. data/{origami → lib/origami}/metadata.rb +0 -0
  60. data/{origami → lib/origami}/name.rb +0 -0
  61. data/{origami → lib/origami}/null.rb +0 -0
  62. data/{origami → lib/origami}/numeric.rb +0 -0
  63. data/{origami → lib/origami}/obfuscation.rb +0 -0
  64. data/{origami → lib/origami}/object.rb +7 -2
  65. data/{origami → lib/origami}/outline.rb +0 -0
  66. data/{origami → lib/origami}/outputintents.rb +0 -0
  67. data/{origami → lib/origami}/page.rb +0 -0
  68. data/{origami → lib/origami}/parser.rb +76 -51
  69. data/{origami → lib/origami}/parsers/fdf.rb +9 -6
  70. data/{origami/parsers/pdf/linear.rb → lib/origami/parsers/pdf.rb} +31 -39
  71. data/lib/origami/parsers/pdf/linear.rb +84 -0
  72. data/lib/origami/parsers/ppklite.rb +93 -0
  73. data/{origami → lib/origami}/pdf.rb +6 -3
  74. data/{origami → lib/origami}/reference.rb +0 -0
  75. data/{origami → lib/origami}/signature.rb +170 -19
  76. data/{origami → lib/origami}/stream.rb +9 -0
  77. data/{origami → lib/origami}/string.rb +0 -0
  78. data/{origami → lib/origami}/trailer.rb +0 -0
  79. data/{origami → lib/origami}/webcapture.rb +0 -0
  80. data/{origami → lib/origami}/xfa.rb +0 -0
  81. data/{origami → lib/origami}/xreftable.rb +3 -7
  82. data/samples/README.txt +45 -0
  83. data/samples/actions/launch/calc.rb +87 -0
  84. data/samples/actions/launch/winparams.rb +22 -0
  85. data/samples/actions/loop/loopgoto.rb +24 -0
  86. data/samples/actions/loop/loopnamed.rb +21 -0
  87. data/samples/actions/named/named.rb +31 -0
  88. data/samples/actions/samba/smbrelay.rb +26 -0
  89. data/samples/actions/triggerevents/trigger.rb +75 -0
  90. data/samples/actions/webbug/submitform.js +26 -0
  91. data/samples/actions/webbug/webbug-browser.rb +68 -0
  92. data/samples/actions/webbug/webbug-js.rb +67 -0
  93. data/samples/actions/webbug/webbug-reader.rb +90 -0
  94. data/samples/attachments/attach.rb +40 -0
  95. data/samples/attachments/attached.txt +1 -0
  96. data/samples/crypto/crypto.rb +28 -0
  97. data/samples/digsig/signed.rb +46 -0
  98. data/samples/exploits/cve-2008-2992-utilprintf.rb +87 -0
  99. data/samples/exploits/cve-2009-0927-geticon.rb +65 -0
  100. data/samples/exploits/exploit_customdictopen.rb +55 -0
  101. data/samples/exploits/getannots.rb +69 -0
  102. data/samples/flash/flash.rb +31 -0
  103. data/samples/flash/helloworld.swf +0 -0
  104. data/samples/javascript/attached.txt +1 -0
  105. data/samples/javascript/js.rb +52 -0
  106. data/{tests → test}/ts_pdf.rb +1 -1
  107. metadata +109 -95
  108. data/origami/adobe/fdf.rb +0 -259
  109. data/origami/parsers/pdf.rb +0 -27
  110. data/origami/parsers/ppklite.rb +0 -86
  111. data/tests/dataset/test.dummycrt +0 -28
  112. data/tests/dataset/test.dummykey +0 -27
  113. data/tests/tc_actions.rb +0 -32
  114. data/tests/tc_annotations.rb +0 -85
  115. data/tests/tc_pages.rb +0 -37
  116. data/tests/tc_pdfattach.rb +0 -24
  117. data/tests/tc_pdfencrypt.rb +0 -110
  118. data/tests/tc_pdfnew.rb +0 -32
  119. data/tests/tc_pdfparse.rb +0 -98
  120. data/tests/tc_pdfsig.rb +0 -37
  121. data/tests/tc_streams.rb +0 -129
File without changes
File without changes
File without changes
File without changes
@@ -69,9 +69,9 @@ module Origami
69
69
  @line_join = LineJoinStyle::MITER_JOIN
70
70
  @miter_limit = 10.0
71
71
  @dash_pattern = DashPattern.new([], 0)
72
- @rendering_intent = RenderingIntent::RELATIVE_COLORIMETRIC
72
+ @rendering_intent = Color::Intent::RELATIVE
73
73
  @stroke_adjustment = false
74
- @blend_mode = BlendMode::NORMAL
74
+ @blend_mode = Color::BlendMode::NORMAL
75
75
  @soft_mask = :None
76
76
  @alpha_constant = 1.0
77
77
  @alpha_source = false
File without changes
@@ -492,6 +492,225 @@ module Origami
492
492
  field :Measure, :Type => Dictionary, :Version => "1.7", :ExtensionLevel => 3
493
493
  field :PtData, :Type => Dictionary, :Version => "1.7", :ExtensionLevel => 3
494
494
 
495
+ #
496
+ # Converts an ImageXObject stream into an image file data.
497
+ # Output format depends on the stream encoding:
498
+ # * JPEG for DCTDecode
499
+ # * JPEG2000 for JPXDecode
500
+ # * JBIG2 for JBIG2Decode
501
+ # * PNG for everything else
502
+ #
503
+ # Returns an array of the form [ _format_, _data_ ]
504
+ #
505
+ def to_image_file
506
+ encoding = self.Filter
507
+ encoding = encoding[0] if encoding.is_a? ::Array
508
+
509
+ case (encoding && encoding.value)
510
+ when :DCTDecode then [ 'jpg', self.data ]
511
+ when :JBIG2Decode then [ 'jbig2', self.data ]
512
+ when :JPXDecode then [ 'jp2', self.data ]
513
+
514
+ else
515
+ raise InvalidColorError, "No colorspace specified" unless self.ColorSpace
516
+
517
+ case cs = self.ColorSpace.value
518
+ when Color::Space::DEVICE_GRAY
519
+ colortype = 0
520
+ components = 1
521
+ when Color::Space::DEVICE_RGB
522
+ colortype = 2
523
+ components = 3
524
+ when ::Array
525
+ cstype = cs[0].is_a?(Reference) ? cs[0].solve : cs[0]
526
+ case cstype.value
527
+ when :Indexed
528
+ colortype = 3
529
+ components = 3
530
+ csbase = cs[1].is_a?(Reference) ? cs[1].solve : cs[1]
531
+ lookup = cs[3].is_a?(Reference) ? cs[3].solve : cs[3]
532
+
533
+ when :ICCBased
534
+ iccprofile = cs[1].is_a?(Reference) ? cs[1].solve : cs[1]
535
+ raise InvalidColorError,
536
+ "Invalid ICC Profile parameter" unless iccprofile.is_a?(Stream)
537
+
538
+ case iccprofile.N
539
+ when 1
540
+ colortype = 0
541
+ components = 1
542
+ when 3
543
+ colortype = 2
544
+ components = 3
545
+ else
546
+ raise InvalidColorError,
547
+ "Invalid number of components in ICC profile: #{iccprofile.N}"
548
+ end
549
+ else
550
+ raise InvalidColorError, "Unsupported color space: #{self.ColorSpace}"
551
+ end
552
+ else
553
+ raise InvalidColorError, "Unsupported color space: #{self.ColorSpace}"
554
+ end
555
+
556
+ bpc = self.BitsPerComponent || 8
557
+ w,h = self.Width, self.Height
558
+ pixels = self.data
559
+
560
+ hdr = [137, 80, 78, 71, 13, 10, 26, 10].pack('C*')
561
+ chunks = []
562
+
563
+ chunks <<
564
+ [
565
+ 'IHDR',
566
+ [
567
+ w, h,
568
+ bpc, colortype, 0, 0, 0
569
+ ].pack("N2C5")
570
+ ]
571
+
572
+
573
+ if self.Intents
574
+ intents =
575
+ case self.Intents.value
576
+ when Intents::PERCEPTUAL then 0
577
+ when Intents::RELATIVE then 1
578
+ when Intents::SATURATION then 2
579
+ when Intents::ABSOLUTE then 3
580
+ else
581
+ 3
582
+ end
583
+
584
+ chunks <<
585
+ [
586
+ 'sRGB',
587
+ [ intents ].pack('C')
588
+ ]
589
+
590
+ chunks << [ 'gAMA', [ 45455 ].pack("N") ]
591
+ chunks <<
592
+ [
593
+ 'cHRM',
594
+ [
595
+ 31270,
596
+ 32900,
597
+ 64000,
598
+ 33000,
599
+ 30000,
600
+ 60000,
601
+ 15000,
602
+ 6000
603
+ ].pack("N8")
604
+ ]
605
+ end
606
+
607
+ if colortype == 3
608
+ lookup =
609
+ case lookup
610
+ when Stream then lookup.data
611
+ when String then lookup.value
612
+ else
613
+ raise InvalidColorError, "Invalid indexed palette table"
614
+ end
615
+
616
+ raise InvalidColorError, "Invalid base color space" unless csbase
617
+ palette = ""
618
+
619
+ case csbase.value
620
+ when Color::Space::DEVICE_GRAY
621
+ lookup.each_byte do |g|
622
+ palette << Color.gray_to_rgb(g).pack("C3")
623
+ end
624
+ when Color::Space::DEVICE_RGB
625
+ palette << lookup[0, (lookup.size / 3) * 3]
626
+ when Color::Space::DEVICE_CMYK
627
+ (lookup.size / 4).times do |i|
628
+ cmyk = lookup[i * 4, 4].unpack("C4").map!{|c| c.to_f / 255}
629
+ palette << Color.cmyk_to_rgb(*cmyk).map!{|c| (c * 255).to_i}.pack("C3")
630
+ end
631
+ when ::Array
632
+ case csbase[0].solve.value
633
+ when :ICCBased
634
+ iccprofile = csbase[1].solve
635
+ raise InvalidColorError,
636
+ "Invalid ICC Profile parameter" unless iccprofile.is_a?(Stream)
637
+
638
+ case iccprofile.N
639
+ when 1
640
+ lookup.each_byte do |g|
641
+ palette << Color.gray_to_rgb(g).pack("C3")
642
+ end
643
+ when 3
644
+ palette << lookup[0, (lookup.size / 3) * 3]
645
+ else
646
+ raise InvalidColorError,
647
+ "Invalid number of components in ICC profile: #{iccprofile.N}"
648
+ end
649
+ else
650
+ raise InvalidColorError, "Unsupported color space: #{csbase}"
651
+ end
652
+ else
653
+ raise InvalidColorError, "Unsupported color space: #{csbase}"
654
+ end
655
+
656
+ if iccprofile
657
+ chunks <<
658
+ [
659
+ 'iCCP',
660
+ 'ICC Profile' + "\x00\x00" + Zlib::Deflate.deflate(iccprofile.data, Zlib::BEST_COMPRESSION)
661
+ ]
662
+ end
663
+
664
+ chunks <<
665
+ [
666
+ 'PLTE',
667
+ palette
668
+ ]
669
+
670
+ bpr = w
671
+ else
672
+
673
+ if iccprofile
674
+ chunks <<
675
+ [
676
+ 'iCCP',
677
+ 'ICC Profile' + "\x00\x00" + Zlib::Deflate.deflate(iccprofile.data, Zlib::BEST_COMPRESSION)
678
+ ]
679
+ end
680
+
681
+ bpr = (bpc >> 3) * components * w
682
+ end
683
+
684
+ require 'zlib'
685
+
686
+ nrows = pixels.size / bpr
687
+ nrows.times do |irow|
688
+ pixels.insert(irow * bpr + irow, "\x00")
689
+ end
690
+
691
+ chunks <<
692
+ [
693
+ 'IDAT',
694
+ Zlib::Deflate.deflate(pixels, Zlib::BEST_COMPRESSION)
695
+ ]
696
+
697
+ if self.Metadata.is_a?(Stream)
698
+ chunks <<
699
+ [
700
+ 'tEXt',
701
+ "XML:com.adobe.xmp" + "\x00" + self.Metadata.data
702
+ ]
703
+ end
704
+
705
+ chunks << [ 'IEND', '' ]
706
+
707
+ [ 'png',
708
+ hdr + chunks.map!{ |chk|
709
+ [ chk[1].size, chk[0], chk[1], Zlib.crc32(chk[0] + chk[1]) ].pack("NA4A*N")
710
+ }.join
711
+ ]
712
+ end
713
+ end
495
714
  end
496
715
 
497
716
  class ReferenceDictionary < Dictionary
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -234,6 +234,12 @@ module Origami
234
234
  end
235
235
  end
236
236
 
237
+ WHITESPACES = "([ \\f\\t\\r\\n\\0]|%[^\\n]*\\n)*" #:nodoc:
238
+ WHITECHARS_NORET = "[ \\f\\t\\0]*" #:nodoc:
239
+ EOL = "\r\n" #:nodoc:
240
+ WHITECHARS = "[ \\f\\t\\r\\n\\0]*" #:nodoc:
241
+ REGEXP_WHITESPACES = Regexp.new(WHITESPACES) #:nodoc:
242
+
237
243
  #
238
244
  # Parent module representing a PDF Object.
239
245
  # PDF specification declares a set of primitive object types :
@@ -248,9 +254,8 @@ module Origami
248
254
  # * Stream
249
255
  #
250
256
  module Object
251
-
257
+
252
258
  TOKENS = %w{ obj endobj } #:nodoc:
253
-
254
259
  @@regexp_obj = Regexp.new(WHITESPACES + "(\\d+)" + WHITESPACES + "(\\d+)" + WHITESPACES + TOKENS.first + WHITESPACES)
255
260
  @@regexp_endobj = Regexp.new(WHITESPACES + TOKENS.last + WHITESPACES)
256
261
 
File without changes
File without changes
File without changes
@@ -94,15 +94,7 @@ module Origami
94
94
  end
95
95
 
96
96
  end
97
-
98
- EOL = "\r\n" #:nodoc:
99
- DEFINED_TOKENS = "[<\\[(%\\/)\\]>]" #:nodoc:
100
- WHITESPACES = "([ \\f\\t\\r\\n\\0]|%[^\\n]*\\n)*" #:nodoc:
101
- WHITECHARS = "[ \\f\\t\\r\\n\\0]*" #:nodoc:
102
- WHITECHARS_NORET = "[ \\f\\t\\0]*" #:nodoc:
103
97
 
104
- REGEXP_WHITESPACES = Regexp.new(WHITESPACES) #:nodoc:
105
-
106
98
  class Parser #:nodoc:
107
99
 
108
100
  class ParsingError < Exception #:nodoc:
@@ -138,9 +130,8 @@ module Origami
138
130
  :verbosity => VERBOSE_INFO, # Verbose level.
139
131
  :ignore_errors => true, # Try to keep on parsing when errors occur.
140
132
  :callback => Proc.new {}, # Callback procedure whenever a structure is read.
141
- :password => '', # Default password being tried when opening a protected document.
142
- :prompt_password => Proc.new { print "Password: "; gets.chomp }, # Callback procedure to prompt password when document is encrypted.
143
- :force => false # Force PDF header detection
133
+ :logger => STDERR, # Where to output parser messages.
134
+ :colorize_log => true # Colorize parser output?
144
135
  }
145
136
 
146
137
  @options.update(options)
@@ -167,75 +158,78 @@ module Origami
167
158
  raise TypeError
168
159
  end
169
160
 
161
+ @logger = @options[:logger]
170
162
  @data = data
171
163
  @data.pos = 0
172
164
  end
173
-
174
- def parse_objects(file) #:nodoc:
165
+
166
+ def parse_object(pos = @data.pos) #:nodoc:
167
+ @data.pos = pos
168
+
175
169
  begin
176
- loop do
177
- obj = Object.parse(@data)
178
- return if obj.nil?
179
-
180
- trace "Read #{obj.type} object#{if obj.type != obj.real_type then " (" + obj.real_type.to_s.split('::').last + ")" end}, #{obj.reference}"
181
-
182
- file << obj
183
-
184
- @options[:callback].call(obj)
185
- end
170
+ obj = Object.parse(@data)
171
+ return if obj.nil?
186
172
 
173
+ trace "Read #{obj.type} object#{
174
+ if obj.type != obj.real_type
175
+ " (" + obj.real_type.to_s.split('::').last + ")"
176
+ end
177
+ }, #{obj.reference}"
178
+
179
+ @options[:callback].call(obj)
180
+ obj
181
+
187
182
  rescue UnterminatedObjectError => e
188
183
  error e.message
189
- file << e.obj
190
-
191
- @options[:callback].call(e.obj)
184
+ obj = e.obj
192
185
 
193
186
  Object.skip_until_next_obj(@data)
194
- retry
187
+ @options[:callback].call(obj)
188
+ obj
195
189
 
196
190
  rescue Exception => e
197
191
  error "Breaking on: #{(@data.peek(10) + "...").inspect} at offset 0x#{@data.pos.to_s(16)}"
198
192
  error "Last exception: [#{e.class}] #{e.message}"
199
- debug "-> Stopped reading body : #{file.revisions.last.body.size} indirect objects have been parsed" if file.is_a?(PDF)
200
- abort("Manually fix the file or set :ignore_errors parameter.") if not @options[:ignore_errors]
193
+ if not @options[:ignore_errors]
194
+ error "Manually fix the file or set :ignore_errors parameter."
195
+ raise
196
+ end
201
197
 
202
198
  debug 'Skipping this indirect object.'
203
- raise(e) if not Object.skip_until_next_obj(@data)
199
+ raise if not Object.skip_until_next_obj(@data)
204
200
 
205
201
  retry
206
202
  end
207
203
  end
208
204
 
209
- def parse_xreftable(file) #:nodoc:
205
+ def parse_xreftable(pos = @data.pos) #:nodoc:
206
+ @data.pos = pos
207
+
210
208
  begin
211
209
  info "...Parsing xref table..."
212
- file.revisions.last.xreftable = XRef::Section.parse(@data)
213
- @options[:callback].call(file.revisions.last.xreftable)
210
+ xreftable = XRef::Section.parse(@data)
211
+ @options[:callback].call(xreftable)
212
+
213
+ xreftable
214
214
  rescue Exception => e
215
215
  debug "Exception caught while parsing xref table : " + e.message
216
216
  warn "Unable to parse xref table! Xrefs might be stored into an XRef stream."
217
217
 
218
218
  @data.pos -= 'trailer'.length unless @data.skip_until(/trailer/).nil?
219
+
220
+ nil
219
221
  end
220
222
  end
221
223
 
222
- def parse_trailer(file) #:nodoc:
224
+ def parse_trailer(pos = @data.pos) #:nodoc:
225
+ @data.pos = pos
226
+
223
227
  begin
224
228
  info "...Parsing trailer..."
225
229
  trailer = Trailer.parse(@data)
226
230
 
227
- if file.is_a?(PDF)
228
- xrefstm = file.get_object_by_offset(trailer.startxref) ||
229
- (file.get_object_by_offset(trailer.XRefStm) if trailer.has_field? :XRefStm)
230
- end
231
-
232
- if not xrefstm.nil?
233
- debug "Found a XRefStream for this revision at #{xrefstm.reference}"
234
- file.revisions.last.xrefstm = xrefstm
235
- end
236
-
237
- file.revisions.last.trailer = trailer
238
- @options[:callback].call(file.revisions.last.trailer)
231
+ @options[:callback].call(trailer)
232
+ trailer
239
233
 
240
234
  rescue Exception => e
241
235
  debug "Exception caught while parsing trailer : " + e.message
@@ -262,23 +256,54 @@ module Origami
262
256
  private
263
257
 
264
258
  def error(str = "") #:nodoc:
265
- Console.colorprint("[error] #{str}\n", Console::Colors::RED, false, STDERR)
259
+ if @options[:colorize_log]
260
+ Console.colorprint("[error] #{str}\n", Console::Colors::RED, false, @logger)
261
+ else
262
+ @logger.puts "[error] #{str}"
263
+ end
266
264
  end
267
265
 
268
266
  def warn(str = "") #:nodoc:
269
- Console.colorprint("[info ] Warning: #{str}\n", Console::Colors::YELLOW, false, STDERR) if @options[:verbosity] >= VERBOSE_INFO
267
+ if @options[:verbosity] >= VERBOSE_INFO
268
+ if @options[:colorize_log]
269
+ Console.colorprint("[info ] Warning: #{str}\n", Console::Colors::YELLOW, false, @logger)
270
+ else
271
+ @logger.puts "[info ] #{str}"
272
+ end
273
+ end
270
274
  end
271
275
 
272
276
  def info(str = "") #:nodoc:
273
- (Console.colorprint("[info ] ", Console::Colors::GREEN, false, STDERR); STDERR << "#{str}\n") if @options[:verbosity] >= VERBOSE_INFO
277
+ if @options[:verbosity] >= VERBOSE_INFO
278
+ if @options[:colorize_log]
279
+ Console.colorprint("[info ] ", Console::Colors::GREEN, false, @logger)
280
+ @logger.puts str
281
+ else
282
+ @logger.puts "[info ] #{str}"
283
+ end
284
+ end
274
285
  end
275
286
 
276
287
  def debug(str = "") #:nodoc:
277
- (Console.colorprint("[debug] ", Console::Colors::MAGENTA, false, STDERR); STDERR << "#{str}\n") if @options[:verbosity] >= VERBOSE_DEBUG
288
+ if @options[:verbosity] >= VERBOSE_DEBUG
289
+ if @options[:colorize_log]
290
+ Console.colorprint("[debug] ", Console::Colors::MAGENTA, false, @logger)
291
+ @logger.puts str
292
+ else
293
+ @logger.puts "[debug] #{str}"
294
+ end
295
+ end
278
296
  end
279
297
 
280
298
  def trace(str = "") #:nodoc:
281
- (Console.colorprint("[trace] ", Console::Colors::CYAN, false, STDERR); STDERR << "#{str}\n") if @options[:verbosity] >= VERBOSE_INSANE
299
+ if @options[:verbosity] >= VERBOSE_INSANE
300
+ if @options[:colorize_log]
301
+ Console.colorprint("[trace] ", Console::Colors::CYAN, false, @logger)
302
+ @logger.puts str
303
+ else
304
+ @logger.puts "[trace] #{str}"
305
+ end
306
+ end
282
307
  end
283
308
  end
284
309
  end