2 * Copyright 2010 Damjan Jovanovic
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
24 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
25 #define GetCurrentProcess GetCurrentProcess_Mac
26 #define GetCurrentThread GetCurrentThread_Mac
27 #define LoadResource LoadResource_Mac
28 #define AnimatePalette AnimatePalette_Mac
29 #define EqualRgn EqualRgn_Mac
30 #define FillRgn FillRgn_Mac
31 #define FrameRgn FrameRgn_Mac
32 #define GetPixel GetPixel_Mac
33 #define InvertRgn InvertRgn_Mac
34 #define LineTo LineTo_Mac
35 #define OffsetRgn OffsetRgn_Mac
36 #define PaintRgn PaintRgn_Mac
37 #define Polygon Polygon_Mac
38 #define ResizePalette ResizePalette_Mac
39 #define SetRectRgn SetRectRgn_Mac
40 #define EqualRect EqualRect_Mac
41 #define FillRect FillRect_Mac
42 #define FrameRect FrameRect_Mac
43 #define GetCursor GetCursor_Mac
44 #define InvertRect InvertRect_Mac
45 #define OffsetRect OffsetRect_Mac
46 #define PtInRect PtInRect_Mac
47 #define SetCursor SetCursor_Mac
48 #define SetRect SetRect_Mac
49 #define ShowCursor ShowCursor_Mac
50 #define UnionRect UnionRect_Mac
51 #include <ApplicationServices/ApplicationServices.h>
52 #undef GetCurrentProcess
53 #undef GetCurrentThread
88 #include "wincodecs_private.h"
90 #include "wine/debug.h"
91 #include "wine/library.h"
93 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
95 #if defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) && \
96 MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
98 typedef struct IcnsEncoder
{
99 IWICBitmapEncoder IWICBitmapEncoder_iface
;
102 IconFamilyHandle icns_family
;
103 BOOL any_frame_committed
;
104 int outstanding_commits
;
106 CRITICAL_SECTION lock
;
109 static inline IcnsEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
111 return CONTAINING_RECORD(iface
, IcnsEncoder
, IWICBitmapEncoder_iface
);
114 typedef struct IcnsFrameEncode
{
115 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
116 IcnsEncoder
*encoder
;
126 static inline IcnsFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
128 return CONTAINING_RECORD(iface
, IcnsFrameEncode
, IWICBitmapFrameEncode_iface
);
131 static HRESULT WINAPI
IcnsFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
134 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
135 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
137 if (!ppv
) return E_INVALIDARG
;
139 if (IsEqualIID(&IID_IUnknown
, iid
) ||
140 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
142 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
147 return E_NOINTERFACE
;
150 IUnknown_AddRef((IUnknown
*)*ppv
);
154 static ULONG WINAPI
IcnsFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
156 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
157 ULONG ref
= InterlockedIncrement(&This
->ref
);
159 TRACE("(%p) refcount=%u\n", iface
, ref
);
164 static ULONG WINAPI
IcnsFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
166 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
167 ULONG ref
= InterlockedDecrement(&This
->ref
);
169 TRACE("(%p) refcount=%u\n", iface
, ref
);
173 if (!This
->committed
)
175 EnterCriticalSection(&This
->encoder
->lock
);
176 This
->encoder
->outstanding_commits
--;
177 LeaveCriticalSection(&This
->encoder
->lock
);
179 if (This
->icns_image
!= NULL
)
180 HeapFree(GetProcessHeap(), 0, This
->icns_image
);
182 IUnknown_Release((IUnknown
*)This
->encoder
);
183 HeapFree(GetProcessHeap(), 0, This
);
189 static HRESULT WINAPI
IcnsFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
190 IPropertyBag2
*pIEncoderOptions
)
192 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
195 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
197 EnterCriticalSection(&This
->encoder
->lock
);
199 if (This
->initialized
)
201 hr
= WINCODEC_ERR_WRONGSTATE
;
204 This
->initialized
= TRUE
;
207 LeaveCriticalSection(&This
->encoder
->lock
);
211 static HRESULT WINAPI
IcnsFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
212 UINT uiWidth
, UINT uiHeight
)
214 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
217 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
219 EnterCriticalSection(&This
->encoder
->lock
);
221 if (!This
->initialized
|| This
->icns_image
)
223 hr
= WINCODEC_ERR_WRONGSTATE
;
227 if (uiWidth
!= uiHeight
)
229 WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth
, uiHeight
);
244 WARN("cannot generate ICNS icon from %dx%d image\n", This
->size
, This
->size
);
249 This
->size
= uiWidth
;
252 LeaveCriticalSection(&This
->encoder
->lock
);
256 static HRESULT WINAPI
IcnsFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
257 double dpiX
, double dpiY
)
259 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
262 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
264 EnterCriticalSection(&This
->encoder
->lock
);
266 if (!This
->initialized
|| This
->icns_image
)
268 hr
= WINCODEC_ERR_WRONGSTATE
;
273 LeaveCriticalSection(&This
->encoder
->lock
);
277 static HRESULT WINAPI
IcnsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
278 WICPixelFormatGUID
*pPixelFormat
)
280 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
283 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
285 EnterCriticalSection(&This
->encoder
->lock
);
287 if (!This
->initialized
|| This
->icns_image
)
289 hr
= WINCODEC_ERR_WRONGSTATE
;
293 memcpy(pPixelFormat
, &GUID_WICPixelFormat32bppBGRA
, sizeof(GUID
));
296 LeaveCriticalSection(&This
->encoder
->lock
);
300 static HRESULT WINAPI
IcnsFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
301 UINT cCount
, IWICColorContext
**ppIColorContext
)
303 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
307 static HRESULT WINAPI
IcnsFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
308 IWICPalette
*pIPalette
)
310 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
311 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
314 static HRESULT WINAPI
IcnsFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
315 IWICBitmapSource
*pIThumbnail
)
317 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
318 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
321 static HRESULT WINAPI
IcnsFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
322 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
324 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
328 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
330 EnterCriticalSection(&This
->encoder
->lock
);
332 if (!This
->initialized
|| !This
->size
)
334 hr
= WINCODEC_ERR_WRONGSTATE
;
337 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->size
)
343 if (!This
->icns_image
)
347 case 16: This
->icns_type
= kIconServices16PixelDataARGB
; break;
348 case 32: This
->icns_type
= kIconServices32PixelDataARGB
; break;
349 case 48: This
->icns_type
= kIconServices48PixelDataARGB
; break;
350 case 128: This
->icns_type
= kIconServices128PixelDataARGB
; break;
351 case 256: This
->icns_type
= kIconServices256PixelDataARGB
; break;
352 case 512: This
->icns_type
= kIconServices512PixelDataARGB
; break;
354 WARN("cannot generate ICNS icon from %dx%d image\n", This
->size
, This
->size
);
358 This
->icns_image
= HeapAlloc(GetProcessHeap(), 0, This
->size
* This
->size
* 4);
359 if (!This
->icns_image
)
361 WARN("failed to allocate image buffer\n");
367 for (i
= 0; i
< lineCount
; i
++)
369 BYTE
*src_row
, *dst_row
;
371 src_row
= pbPixels
+ cbStride
* i
;
372 dst_row
= This
->icns_image
+ (This
->lines_written
+ i
)*(This
->size
*4);
373 /* swap bgr -> rgb */
374 for (j
= 0; j
< This
->size
*4; j
+= 4)
376 dst_row
[j
] = src_row
[j
+3];
377 dst_row
[j
+1] = src_row
[j
+2];
378 dst_row
[j
+2] = src_row
[j
+1];
379 dst_row
[j
+3] = src_row
[j
];
382 This
->lines_written
+= lineCount
;
385 LeaveCriticalSection(&This
->encoder
->lock
);
389 static HRESULT WINAPI
IcnsFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
390 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
392 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
395 WICPixelFormatGUID guid
;
397 BYTE
*pixeldata
= NULL
;
399 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
401 if (!This
->initialized
|| !This
->size
)
403 hr
= WINCODEC_ERR_WRONGSTATE
;
407 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
410 if (!IsEqualGUID(&guid
, &GUID_WICPixelFormat32bppBGRA
))
412 FIXME("format %s unsupported, could use WICConvertBitmapSource to convert\n", debugstr_guid(&guid
));
420 hr
= IWICBitmapSource_GetSize(pIBitmapSource
, &width
, &height
);
430 if (prc
->Width
!= This
->size
)
436 stride
= (32 * This
->size
+ 7)/8;
437 pixeldata
= HeapAlloc(GetProcessHeap(), 0, stride
* prc
->Height
);
444 hr
= IWICBitmapSource_CopyPixels(pIBitmapSource
, prc
, stride
,
445 stride
*prc
->Height
, pixeldata
);
448 hr
= IWICBitmapFrameEncode_WritePixels(iface
, prc
->Height
, stride
,
449 stride
*prc
->Height
, pixeldata
);
453 HeapFree(GetProcessHeap(), 0, pixeldata
);
457 static HRESULT WINAPI
IcnsFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
459 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
464 TRACE("(%p): stub\n", iface
);
466 EnterCriticalSection(&This
->encoder
->lock
);
468 if (!This
->icns_image
|| This
->lines_written
!= This
->size
|| This
->committed
)
470 hr
= WINCODEC_ERR_WRONGSTATE
;
474 ret
= PtrToHand(This
->icns_image
, &handle
, This
->size
* This
->size
* 4);
475 if (ret
!= noErr
|| !handle
)
477 WARN("PtrToHand failed with error %d\n", ret
);
482 ret
= SetIconFamilyData(This
->encoder
->icns_family
, This
->icns_type
, handle
);
483 DisposeHandle(handle
);
487 WARN("SetIconFamilyData failed for image with error %d\n", ret
);
492 This
->committed
= TRUE
;
493 This
->encoder
->any_frame_committed
= TRUE
;
494 This
->encoder
->outstanding_commits
--;
497 LeaveCriticalSection(&This
->encoder
->lock
);
501 static HRESULT WINAPI
IcnsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
502 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
504 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
508 static const IWICBitmapFrameEncodeVtbl IcnsEncoder_FrameVtbl
= {
509 IcnsFrameEncode_QueryInterface
,
510 IcnsFrameEncode_AddRef
,
511 IcnsFrameEncode_Release
,
512 IcnsFrameEncode_Initialize
,
513 IcnsFrameEncode_SetSize
,
514 IcnsFrameEncode_SetResolution
,
515 IcnsFrameEncode_SetPixelFormat
,
516 IcnsFrameEncode_SetColorContexts
,
517 IcnsFrameEncode_SetPalette
,
518 IcnsFrameEncode_SetThumbnail
,
519 IcnsFrameEncode_WritePixels
,
520 IcnsFrameEncode_WriteSource
,
521 IcnsFrameEncode_Commit
,
522 IcnsFrameEncode_GetMetadataQueryWriter
525 static HRESULT WINAPI
IcnsEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
528 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
529 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
531 if (!ppv
) return E_INVALIDARG
;
533 if (IsEqualIID(&IID_IUnknown
, iid
) ||
534 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
541 return E_NOINTERFACE
;
544 IUnknown_AddRef((IUnknown
*)*ppv
);
548 static ULONG WINAPI
IcnsEncoder_AddRef(IWICBitmapEncoder
*iface
)
550 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
551 ULONG ref
= InterlockedIncrement(&This
->ref
);
553 TRACE("(%p) refcount=%u\n", iface
, ref
);
558 static ULONG WINAPI
IcnsEncoder_Release(IWICBitmapEncoder
*iface
)
560 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
561 ULONG ref
= InterlockedDecrement(&This
->ref
);
563 TRACE("(%p) refcount=%u\n", iface
, ref
);
567 This
->lock
.DebugInfo
->Spare
[0] = 0;
568 DeleteCriticalSection(&This
->lock
);
569 if (This
->icns_family
)
570 DisposeHandle((Handle
)This
->icns_family
);
572 IStream_Release(This
->stream
);
573 HeapFree(GetProcessHeap(), 0, This
);
579 static HRESULT WINAPI
IcnsEncoder_Initialize(IWICBitmapEncoder
*iface
,
580 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
582 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
585 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
587 EnterCriticalSection(&This
->lock
);
589 if (This
->icns_family
)
591 hr
= WINCODEC_ERR_WRONGSTATE
;
594 This
->icns_family
= (IconFamilyHandle
)NewHandle(0);
595 if (!This
->icns_family
)
597 WARN("error creating icns family\n");
601 IStream_AddRef(pIStream
);
602 This
->stream
= pIStream
;
605 LeaveCriticalSection(&This
->lock
);
610 static HRESULT WINAPI
IcnsEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
611 GUID
*pguidContainerFormat
)
613 FIXME("(%p,%s): stub\n", iface
, debugstr_guid(pguidContainerFormat
));
617 static HRESULT WINAPI
IcnsEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
618 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
620 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
624 static HRESULT WINAPI
IcnsEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
625 UINT cCount
, IWICColorContext
**ppIColorContext
)
627 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
631 static HRESULT WINAPI
IcnsEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
633 TRACE("(%p,%p)\n", iface
, pIPalette
);
634 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
637 static HRESULT WINAPI
IcnsEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
639 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
640 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
643 static HRESULT WINAPI
IcnsEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
645 TRACE("(%p,%p)\n", iface
, pIPreview
);
646 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
649 static HRESULT WINAPI
IcnsEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
650 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
652 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
654 IcnsFrameEncode
*frameEncode
= NULL
;
656 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
658 EnterCriticalSection(&This
->lock
);
660 if (!This
->icns_family
)
662 hr
= WINCODEC_ERR_NOTINITIALIZED
;
666 hr
= CreatePropertyBag2(ppIEncoderOptions
);
670 frameEncode
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsFrameEncode
));
671 if (frameEncode
== NULL
)
676 frameEncode
->IWICBitmapFrameEncode_iface
.lpVtbl
= &IcnsEncoder_FrameVtbl
;
677 frameEncode
->encoder
= This
;
678 frameEncode
->ref
= 1;
679 frameEncode
->initialized
= FALSE
;
680 frameEncode
->size
= 0;
681 frameEncode
->icns_image
= NULL
;
682 frameEncode
->lines_written
= 0;
683 frameEncode
->committed
= FALSE
;
684 *ppIFrameEncode
= &frameEncode
->IWICBitmapFrameEncode_iface
;
685 This
->outstanding_commits
++;
686 IUnknown_AddRef((IUnknown
*)This
);
689 LeaveCriticalSection(&This
->lock
);
694 static HRESULT WINAPI
IcnsEncoder_Commit(IWICBitmapEncoder
*iface
)
696 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
701 TRACE("(%p)\n", iface
);
703 EnterCriticalSection(&This
->lock
);
705 if (!This
->any_frame_committed
|| This
->outstanding_commits
> 0 || This
->committed
)
707 hr
= WINCODEC_ERR_WRONGSTATE
;
711 buffer_size
= GetHandleSize((Handle
)This
->icns_family
);
712 hr
= IStream_Write(This
->stream
, *This
->icns_family
, buffer_size
, &byteswritten
);
713 if (FAILED(hr
) || byteswritten
!= buffer_size
)
715 WARN("writing file failed, hr = 0x%08X\n", hr
);
720 This
->committed
= TRUE
;
723 LeaveCriticalSection(&This
->lock
);
727 static HRESULT WINAPI
IcnsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
728 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
730 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
734 static const IWICBitmapEncoderVtbl IcnsEncoder_Vtbl
= {
735 IcnsEncoder_QueryInterface
,
738 IcnsEncoder_Initialize
,
739 IcnsEncoder_GetContainerFormat
,
740 IcnsEncoder_GetEncoderInfo
,
741 IcnsEncoder_SetColorContexts
,
742 IcnsEncoder_SetPalette
,
743 IcnsEncoder_SetThumbnail
,
744 IcnsEncoder_SetPreview
,
745 IcnsEncoder_CreateNewFrame
,
747 IcnsEncoder_GetMetadataQueryWriter
750 HRESULT
IcnsEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
755 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
759 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
761 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsEncoder
));
762 if (!This
) return E_OUTOFMEMORY
;
764 This
->IWICBitmapEncoder_iface
.lpVtbl
= &IcnsEncoder_Vtbl
;
767 This
->icns_family
= NULL
;
768 This
->any_frame_committed
= FALSE
;
769 This
->outstanding_commits
= 0;
770 This
->committed
= FALSE
;
771 InitializeCriticalSection(&This
->lock
);
772 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IcnsEncoder.lock");
774 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
775 IUnknown_Release((IUnknown
*)This
);
780 #else /* !defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) ||
781 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 */
783 HRESULT
IcnsEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
785 ERR("Trying to save ICNS picture, but ICNS support is not compiled in.\n");