1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2018 Stanislav Yuzvinsky
4 Based on the work done by viruxx
5
6 This file is part of the SANE package.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>.
20
21 As a special exception, the authors of SANE give permission for
22 additional uses of the libraries contained in this release of SANE.
23
24 The exception is that, if you link a SANE library with other files
25 to produce an executable, this does not by itself cause the
26 resulting executable to be covered by the GNU General Public
27 License. Your use of that executable is in no way restricted on
28 account of linking the SANE library code into it.
29
30 This exception does not, however, invalidate any other reasons why
31 the executable file might be covered by the GNU General Public
32 License.
33
34 If you submit changes to SANE to the maintainers to be included in
35 a subsequent release, you agree by submitting the changes that
36 those changes may be distributed with this exception intact.
37
38 If you write modifications of your own for SANE, it is your choice
39 whether to permit this exception to apply to your modifications.
40 If you do not wish that, delete this exception notice.
41 */
42
43 #include "../include/sane/config.h"
44
45 #include <assert.h>
46 #include <stdlib.h>
47
48 #include "../include/sane/sanei_debug.h"
49
50 typedef struct ricoh2_buffer
51 {
52 /* lifetime constants */
53 SANE_Byte *data;
54 SANE_Int size;
55 SANE_Int pixels_per_line;
56 SANE_Int info_size;
57 SANE_Bool is_rgb;
58
59 /* state */
60 SANE_Int current_position;
61 SANE_Int remain_in_line;
62
63 }
64 ricoh2_buffer;
65
66 static ricoh2_buffer *
ricoh2_buffer_create(SANE_Int size,SANE_Int pixels_per_line,SANE_Int info_size,SANE_Bool is_rgb)67 ricoh2_buffer_create (SANE_Int size,
68 SANE_Int pixels_per_line,
69 SANE_Int info_size,
70 SANE_Bool is_rgb)
71 {
72 ricoh2_buffer *self;
73 assert (size > 0);
74 assert (pixels_per_line > 0);
75 assert (info_size >= 0);
76
77 self = malloc (sizeof (ricoh2_buffer));
78 if (!self)
79 return NULL;
80
81 self->data = malloc (size);
82 if (!self->data)
83 {
84 free (self);
85 return NULL;
86 }
87
88 self->size = size;
89 self->pixels_per_line = pixels_per_line;
90 self->info_size = info_size;
91 self->is_rgb = is_rgb;
92
93 self->current_position = 0;
94 self->remain_in_line = pixels_per_line;
95
96
97 DBG (192,
98 "size = %d pixels_per_line = %d info_size = %d rgb? = %d pos = %d\n",
99 self->size,
100 self->pixels_per_line,
101 self->info_size,
102 self->is_rgb,
103 self->current_position);
104
105 return self;
106 }
107
108 /* destructor */
109 static void
ricoh2_buffer_dispose(ricoh2_buffer * self)110 ricoh2_buffer_dispose (ricoh2_buffer *self)
111 {
112 assert (self);
113 free (self->data);
114 free (self);
115 }
116
117 static SANE_Byte *
ricoh2_buffer_get_internal_buffer(ricoh2_buffer * self)118 ricoh2_buffer_get_internal_buffer (ricoh2_buffer *self)
119 {
120 assert (self);
121 DBG (192, "engaging a buffer of size %d\n", self->size);
122
123 self->current_position = 0;
124 self->remain_in_line = self->pixels_per_line;
125
126 DBG (192, "remain in line = %d\n", self->remain_in_line);
127
128 return self->data;
129 }
130
131 static SANE_Int
ricoh2_buffer_get_bytes_remain(ricoh2_buffer * self)132 ricoh2_buffer_get_bytes_remain (ricoh2_buffer *self)
133 {
134 assert (self);
135
136 DBG (192,
137 "bytes remain in the buffer %d\n",
138 self->size - self->current_position);
139
140 return self->size - self->current_position;
141 }
142
143 inline static SANE_Int
min(SANE_Int v1,SANE_Int v2)144 min (SANE_Int v1, SANE_Int v2)
145 {
146 return v1 < v2 ? v1 : v2;
147 }
148
149 static SANE_Int
ricoh2_buffer_get_data(ricoh2_buffer * self,SANE_Byte * dest,SANE_Int dest_size)150 ricoh2_buffer_get_data (ricoh2_buffer *self,
151 SANE_Byte *dest,
152 SANE_Int dest_size)
153 {
154 SANE_Int actually_copied = 0;
155 SANE_Int pixels_to_copy;
156 SANE_Int bytes_per_pixel;
157 SANE_Int bytes_per_color;
158 SANE_Byte *src;
159 SANE_Byte *end;
160
161 assert (self);
162 assert (dest);
163 assert (self->size > self->current_position);
164
165 bytes_per_pixel = self->is_rgb ? 3 : 1;
166 bytes_per_color = self->pixels_per_line + self->info_size;
167
168 DBG (192,
169 "trying to get %d bytes from the buffer, "
170 "while %d bytes in the line\n",
171 dest_size,
172 self->remain_in_line);
173
174 for (pixels_to_copy =
175 min (dest_size / bytes_per_pixel, self->remain_in_line);
176 pixels_to_copy && self->size > self->current_position;
177 pixels_to_copy =
178 min (dest_size / bytes_per_pixel, self->remain_in_line))
179 {
180
181 DBG (192,
182 "providing %d bytes to the user (until the end of the line), "
183 "position in buffer is %d\n",
184 pixels_to_copy * bytes_per_pixel,
185 self->current_position);
186
187 for (src = self->data + self->current_position,
188 end = src + pixels_to_copy;
189 src < end;
190 ++src)
191 {
192 *(dest++) = *(src);
193 if (bytes_per_pixel == 3)
194 {
195 *(dest++) = *(src + bytes_per_color);
196 *(dest++) = *(src + 2 * bytes_per_color);
197 }
198 }
199
200 dest_size -= pixels_to_copy * bytes_per_pixel;
201 actually_copied += pixels_to_copy * bytes_per_pixel;
202 self->current_position += pixels_to_copy;
203 self->remain_in_line -= pixels_to_copy;
204
205 // move to the next line
206 if (!self->remain_in_line)
207 {
208 self->current_position += self->info_size;
209 if (self->is_rgb)
210 self->current_position += 2 * bytes_per_color;
211 self->remain_in_line = self->pixels_per_line;
212 DBG (192,
213 "Line feed, new position is %d\n",
214 self->current_position);
215 }
216
217 DBG (192,
218 "left in the buffer: %d\n",
219 self->size - self->current_position);
220 }
221
222 /* invariant */
223 assert (self->size >= self->current_position);
224
225 return actually_copied;
226 }
227