1/*
2 * Copyright 2021, J��r��me Duval, jerome.duval@gmail.com.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "LibRAW.h"
8
9#include <Message.h>
10#include <TranslationErrors.h>
11
12#include <ctype.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include <libraw/libraw.h>
18
19#include "StreamBuffer.h"
20
21
22//#define TRACE(x...) printf(x)
23#define TRACE(x...)
24#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
25#define RETURN(x, y) { TRACE("RETURN %s %s\n", __PRETTY_FUNCTION__, x); \
26	return y; }
27
28static const uint32 kImageBufferCount = 10;
29static const uint32 kDecodeBufferCount = 2048;
30
31
32#define P1 fRaw->imgdata.idata
33#define S fRaw->imgdata.sizes
34#define C fRaw->imgdata.color
35#define T fRaw->imgdata.thumbnail
36#define P2 fRaw->imgdata.other
37#define OUT fRaw->imgdata.params
38
39
40//	#pragma mark -
41
42
43class LibRaw_haiku_datastream : public LibRaw_abstract_datastream
44{
45public:
46	BPositionIO* fStream;
47	virtual ~LibRaw_haiku_datastream();
48			LibRaw_haiku_datastream(BPositionIO* stream);
49	virtual int valid();
50	virtual int read(void *ptr, size_t size, size_t nmemb);
51	virtual int eof();
52	virtual int seek(INT64 o, int whence);
53	virtual INT64 tell();
54	virtual INT64 size();
55	virtual int get_char();
56	virtual char *gets(char *str, int sz);
57	virtual int scanf_one(const char *fmt, void *val);
58	virtual void *make_jas_stream();
59
60private:
61	StreamBuffer *buffer;
62	off_t	fSize;
63	status_t iseof;
64};
65
66
67LibRaw_haiku_datastream::LibRaw_haiku_datastream(BPositionIO* stream)
68{
69	CALLED();
70	iseof = 0;
71	buffer = new StreamBuffer(stream, 2048);
72	fStream = stream;
73	fStream->GetSize(&fSize);
74}
75
76LibRaw_haiku_datastream::~LibRaw_haiku_datastream()
77{
78	delete buffer;
79}
80
81
82int
83LibRaw_haiku_datastream::read(void *ptr, size_t sz, size_t nmemb)
84{
85	CALLED();
86	TRACE("read %ld %ld\n", sz, nmemb);
87	size_t to_read = sz * nmemb;
88
89	to_read = buffer->Read(ptr, to_read);
90	if (to_read < B_OK)
91		RETURN("ERROR2", to_read);
92	return int((to_read + sz - 1) / (sz > 0 ? sz : 1));
93}
94
95
96int
97LibRaw_haiku_datastream::seek(INT64 o, int whence)
98{
99	CALLED();
100	TRACE("seek %lld %d\n", o, whence);
101	return buffer->Seek(o, whence) < 0;
102}
103
104
105INT64
106LibRaw_haiku_datastream::tell()
107{
108	CALLED();
109	off_t position = buffer->Position();
110	TRACE("RETURN LibRaw_haiku_datastream::tell %ld\n", position);
111	return position;
112}
113
114
115INT64
116LibRaw_haiku_datastream::size()
117{
118	CALLED();
119	TRACE("RETURN size %ld\n", fSize);
120	return fSize;
121}
122
123
124int
125LibRaw_haiku_datastream::get_char()
126{
127	CALLED();
128	unsigned char value;
129	ssize_t error;
130	iseof = 0;
131	error = buffer->Read((void*)&value, sizeof(unsigned char));
132	if (error >= 0)
133		return value;
134	iseof = EOF;
135	return EOF;
136}
137
138
139char*
140LibRaw_haiku_datastream::gets(char* s, int sz)
141{
142	CALLED();
143	if (sz<1)
144		return NULL;
145	int pos = 0;
146	bool found = false ;
147	while (!found && pos < (sz - 1)) {
148		char buffer;
149		if (this->buffer->Read(&buffer, 1) < 1)
150			break;
151		s[pos++] = buffer ;
152		if (buffer == '\n') {
153			found = true;
154			break;
155		}
156	}
157	if (found) {
158		s[pos] = 0;
159	} else
160		s[sz - 1] = 0 ;
161	return s;
162}
163
164
165int
166LibRaw_haiku_datastream::scanf_one(const char *fmt, void *val)
167{
168	CALLED();
169  int scanf_res = 0;
170/*  if (streampos > streamsize)
171    return 0;
172  scanf_res = sscanf_s((char *)(buf + streampos), fmt, val);
173  if (scanf_res > 0)
174  {
175    int xcnt = 0;
176    while (streampos < streamsize)
177    {
178      streampos++;
179      xcnt++;
180      if (buf[streampos] == 0 || buf[streampos] == ' ' ||
181          buf[streampos] == '\t' || buf[streampos] == '\n' || xcnt > 24)
182        break;
183    }
184  }*/
185  return scanf_res;
186}
187
188
189int
190LibRaw_haiku_datastream::eof()
191{
192	CALLED();
193	return iseof;
194}
195
196
197int
198LibRaw_haiku_datastream::valid()
199{
200	CALLED();
201	return buffer != NULL ? 1 : 0;
202}
203
204
205void *
206LibRaw_haiku_datastream::make_jas_stream()
207{
208	return NULL;
209}
210
211
212//	#pragma mark -
213
214
215LibRAW::LibRAW(BPositionIO& stream)
216	:
217	fProgressMonitor(NULL),
218	fRaw(new LibRaw()),
219	fDatastream(new LibRaw_haiku_datastream(&stream))
220{
221	CALLED();
222}
223
224
225LibRAW::~LibRAW()
226{
227	delete fRaw;
228	delete fDatastream;
229}
230
231
232
233//	#pragma mark -
234
235
236status_t
237LibRAW::Identify()
238{
239	CALLED();
240	fDatastream->fStream->Seek(0, SEEK_SET);
241
242	status_t status = B_NO_TRANSLATOR;
243	int ret = fRaw->open_datastream(fDatastream);
244	if (ret != LIBRAW_SUCCESS) {
245		TRACE("LibRAW::Identify() open_datastream returned %s\n",
246			libraw_strerror(ret));
247		return status;
248	}
249
250	return B_OK;
251}
252
253
254status_t
255LibRAW::ReadImageAt(uint32 index, uint8*& outputBuffer, size_t& bufferSize)
256{
257	CALLED();
258	if (index >= P1.raw_count)
259		return B_BAD_VALUE;
260	OUT.shot_select = index;
261	OUT.output_bps = 8;
262	OUT.output_tiff = 1;
263	OUT.no_auto_bright = 1;
264	OUT.use_auto_wb = 1;
265	OUT.user_qual = 3;
266
267	if (fRaw->unpack() != LIBRAW_SUCCESS)
268		return B_BAD_DATA;
269	if (fRaw->dcraw_process() != LIBRAW_SUCCESS)
270		return B_BAD_DATA;
271
272	libraw_processed_image_t* img = fRaw->dcraw_make_mem_image();
273	if (img == NULL)
274		return B_BAD_DATA;
275	bufferSize = img->data_size;
276	outputBuffer = (uint8*)malloc(bufferSize);
277	if (outputBuffer == NULL) {
278		fRaw->dcraw_clear_mem(img);
279		throw (status_t)B_NO_MEMORY;
280	}
281
282	memcpy(outputBuffer, img->data, bufferSize);
283
284	fRaw->dcraw_clear_mem(img);
285	return B_OK;
286}
287
288
289void
290LibRAW::GetMetaInfo(image_meta_info& metaInfo) const
291{
292	strlcpy(metaInfo.manufacturer, fRaw->imgdata.idata.make,
293		sizeof(metaInfo.manufacturer));
294	strlcpy(metaInfo.model, fRaw->imgdata.idata.model, sizeof(metaInfo.model));
295}
296
297
298uint32
299LibRAW::CountImages() const
300{
301	return fRaw->imgdata.idata.raw_count;
302}
303
304
305status_t
306LibRAW::ImageAt(uint32 index, image_data_info& info) const
307{
308	if (index >= fRaw->imgdata.idata.raw_count)
309		return B_BAD_VALUE;
310
311	info.width = S.width;
312	info.height = S.height;
313	info.output_width = S.flip > 4 ? S.iheight : S.iwidth;
314	info.output_height = S.flip > 4 ? S.iwidth : S.iheight;
315	info.flip = S.flip;
316	info.bytes = S.raw_pitch;
317	info.is_raw = 1;
318	return B_OK;
319}
320
321
322status_t
323LibRAW::GetEXIFTag(off_t& offset, size_t& length, bool& bigEndian) const
324{
325	return B_ENTRY_NOT_FOUND;
326}
327
328
329void
330LibRAW::SetProgressMonitor(monitor_hook hook, void* data)
331{
332	fProgressMonitor = hook;
333	fProgressData = data;
334	fRaw->set_progress_handler(hook != NULL ? ProgressCallback : NULL, this);
335}
336
337
338void
339LibRAW::SetHalfSize(bool half)
340{
341	OUT.half_size = half;
342}
343
344
345int
346LibRAW::ProgressCallback(void *data, enum LibRaw_progress p, int iteration,
347	int expected)
348{
349	return ((LibRAW*)data)->_ProgressCallback(p, iteration, expected);
350}
351
352
353int
354LibRAW::_ProgressCallback(enum LibRaw_progress p,int iteration, int expected)
355{
356	fProgressMonitor(libraw_strprogress(p), iteration * 100 / expected,
357		fProgressData);
358	return 0;
359}
360