• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "picture_handle_client.h"
17 
18 #include <cstdlib>
19 #include <fcntl.h>
20 #include <libexif/exif-entry.h>
21 #include <securec.h>
22 #include <sys/mman.h>
23 #include <unistd.h>
24 
25 #include "exif_metadata.h"
26 #include "image_type.h"
27 #include "image_utils.h"
28 #include "medialibrary_db_const.h"
29 #include "medialibrary_errno.h"
30 #include "medialibrary_napi_utils.h"
31 #include "media_column.h"
32 #include "media_file_utils.h"
33 #include "media_log.h"
34 #include "pixel_yuv.h"
35 #include "pixel_yuv_ext.h"
36 #include "userfilemgr_uri.h"
37 #include "userfile_client.h"
38 #include <fstream>
39 
40 namespace OHOS {
41 namespace Media {
42 const int32_t MAX_VALUE = 100000000;
RequestPicture(const int32_t & fileId)43 std::shared_ptr<Media::Picture> PictureHandlerClient::RequestPicture(const int32_t &fileId)
44 {
45     MEDIA_DEBUG_LOG("PictureHandlerClient::RequestPicture fileId: %{public}d", fileId);
46     std::string uri = PhotoColumn::PHOTO_REQUEST_PICTURE;
47     MediaFileUtils::UriAppendKeyValue(uri, MediaColumn::MEDIA_ID, std::to_string(fileId));
48     Uri requestUri(uri);
49     int32_t fd = UserFileClient::OpenFile(requestUri, MEDIA_FILEMODE_READONLY);
50     if (fd < 0) {
51         MEDIA_DEBUG_LOG("PictureHandlerClient::RequestPicture picture not exist");
52         return nullptr;
53     }
54     std::shared_ptr<Media::Picture> picture = nullptr;
55     ReadPicture(fd, fileId, picture);
56     FinishRequestPicture(fileId);
57     close(fd);
58     return picture;
59 }
60 
FinishRequestPicture(const int32_t & fileId)61 void PictureHandlerClient::FinishRequestPicture(const int32_t &fileId)
62 {
63     MEDIA_DEBUG_LOG("PictureHandlerClient::FinishRequestPicture fileId: %{public}d", fileId);
64     std::string uri = PAH_FINISH_REQUEST_PICTURE;
65     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
66     Uri finishRequestPictureUri(uri);
67 
68     DataShare::DataShareValuesBucket valuesBucket;
69     valuesBucket.Put(PhotoColumn::MEDIA_ID, fileId);
70     UserFileClient::Insert(finishRequestPictureUri, valuesBucket);
71 }
72 
ReadPicture(const int32_t & fd,const int32_t & fileId,std::shared_ptr<Media::Picture> & picture)73 int32_t PictureHandlerClient::ReadPicture(const int32_t &fd, const int32_t &fileId,
74     std::shared_ptr<Media::Picture> &picture)
75 {
76     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPicture fd: %{public}d", fd);
77     // 获取消息总长度
78     void *msgLenAddr = mmap(nullptr, UINT32_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
79     if (msgLenAddr == MAP_FAILED || msgLenAddr == nullptr) {
80         MEDIA_ERR_LOG("PictureHandlerClient::ReadPicture mmap msgLenAddr failed!");
81         close(fd);
82         return E_ERR;
83     }
84     uint32_t msgLen = *((uint32_t*)msgLenAddr);
85     munmap(msgLenAddr, UINT32_LEN);
86     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPicture msgLen: %{public}d", msgLen);
87 
88     // 获取消息
89     uint8_t *addr = (uint8_t*)mmap(nullptr, msgLen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
90     if (addr == MAP_FAILED || addr == nullptr) {
91         MEDIA_ERR_LOG("PictureHandlerClient::ReadPicture mmap addr failed!");
92         close(fd);
93         return E_ERR;
94     }
95     uint32_t readoffset = UINT32_LEN;
96 
97     // 读取dataSize
98     uint32_t dataSize = *reinterpret_cast<const uint32_t*>(addr + readoffset);
99     readoffset += UINT32_LEN;
100     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPicture dataSize: %{public}d", dataSize);
101     if (dataSize == 0) {
102         MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPicture picture is not exists");
103         munmap(addr, msgLen);
104         return E_NO_SUCH_FILE;
105     }
106 
107     // 读取auxiliaryPictureSize
108     uint32_t auxiliaryPictureSize =  *reinterpret_cast<const uint32_t*>(addr + readoffset);
109     readoffset += UINT32_LEN;
110     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPicture auxiliaryPictureSize: %{public}d",
111         auxiliaryPictureSize);
112     uint8_t *pictureParcelData = static_cast<uint8_t *>(malloc(dataSize));
113     if (pictureParcelData == nullptr) {
114         munmap(addr, msgLen);
115         return E_ERR;
116     }
117     if (memcpy_s((void*)pictureParcelData, dataSize, addr+readoffset, dataSize)) {
118         MEDIA_ERR_LOG("PictureHandlerService::ReadPicture memcpy_s pictureParcel failed!");
119         free(pictureParcelData);
120         munmap(addr, msgLen);
121         return E_ERR;
122     }
123     MessageParcel pictureParcel;
124     if (!pictureParcel.ParseFrom(reinterpret_cast<uintptr_t>(pictureParcelData), dataSize)) {
125         MEDIA_ERR_LOG("pictureParcel parse failed!");
126         free(pictureParcelData);
127         return E_ERR;
128     }
129 
130     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPicture read mainPixelMap");
131     std::shared_ptr<PixelMap> mainPixelMap = ReadPixelMap(pictureParcel);
132     std::unique_ptr<Media::Picture> picturePtr = Picture::Create(mainPixelMap);
133     if (picturePtr == nullptr) {
134         MEDIA_ERR_LOG("PictureHandlerService::ReadPicture picturePtr is nullptr!");
135         munmap(addr, msgLen);
136         return E_ERR;
137     }
138 
139     ReadExifMetadata(pictureParcel, picturePtr);
140     ReadMaintenanceData(pictureParcel, picturePtr);
141 
142     for (size_t i = 1; i <= auxiliaryPictureSize; i++) {
143         MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPicture read auxiliaryPicture, index:%{public}zu", i);
144         ReadAuxiliaryPicture(pictureParcel, picturePtr);
145     }
146     picture.reset(picturePtr.get());
147     picturePtr.release();
148     munmap(addr, msgLen);
149     return E_OK;
150 }
151 
ReadPixelMap(MessageParcel & data)152 std::shared_ptr<PixelMap> PictureHandlerClient::ReadPixelMap(MessageParcel &data)
153 {
154     ImageInfo imageInfo;
155     ReadImageInfo(data, imageInfo);
156 
157     bool isYuv = data.ReadBool();
158     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPixelMap isYuv:%{public}d", isYuv);
159     YUVDataInfo yuvInfo;
160     if (isYuv) {
161         ReadYuvDataInfo(data, yuvInfo);
162     }
163 
164     bool editable = data.ReadBool();
165     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPixelMap editable:%{public}d", editable);
166 
167     std::unique_ptr<PixelMap> pixelMap;
168     if (isYuv) {
169 #ifdef EXT_PIXEL
170         pixelMap = std::make_unique<PixelYuvExt>();
171 #else
172         pixelMap = std::make_unique<PixelYuv>();
173 #endif
174     } else {
175         pixelMap = std::make_unique<PixelMap>();
176     }
177     pixelMap->SetImageInfo(imageInfo);
178     pixelMap->SetImageYUVInfo(yuvInfo);
179 
180     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadPixelMap read surface buffer");
181     ReadSurfaceBuffer(data, pixelMap);
182 
183     return pixelMap;
184 }
185 
ReadAuxiliaryPicture(MessageParcel & data,std::unique_ptr<Media::Picture> & picture)186 bool PictureHandlerClient::ReadAuxiliaryPicture(MessageParcel &data, std::unique_ptr<Media::Picture> &picture)
187 {
188     AuxiliaryPictureInfo auxiliaryPictureInfo;
189     ReadAuxiliaryPictureInfo(data, auxiliaryPictureInfo);
190 
191     std::shared_ptr<PixelMap> pixelMap = ReadPixelMap(data);
192     std::unique_ptr<AuxiliaryPicture> uptr = AuxiliaryPicture::Create(pixelMap,
193         auxiliaryPictureInfo.auxiliaryPictureType, auxiliaryPictureInfo.size);
194     std::shared_ptr<AuxiliaryPicture> auxiliaryPicture;
195     auxiliaryPicture.reset(uptr.get());
196     uptr.release();
197 
198     auxiliaryPicture->SetAuxiliaryPictureInfo(auxiliaryPictureInfo);
199 
200     int32_t metadataSize = 0;
201     if (data.ReadInt32(metadataSize) && metadataSize >= 0 && metadataSize < MAX_VALUE) {
202         MEDIA_DEBUG_LOG("PictureHandlerClient::ReadAuxiliaryPicture metadataSize: %{public}d", metadataSize);
203         for (int i = 0; i < metadataSize; i++) {
204             MetadataType type = static_cast<MetadataType>(data.ReadInt32());
205             MEDIA_DEBUG_LOG("PictureHandlerClient::ReadAuxiliaryPicture type: %{public}d", type);
206             std::shared_ptr<ImageMetadata> metadataPtr(nullptr);
207             metadataPtr.reset(ExifMetadata::Unmarshalling(data));
208             auxiliaryPicture->SetMetadata(type, metadataPtr);
209         }
210     } else {
211         MEDIA_ERR_LOG("PictureHandlerClient::ReadAuxiliaryPicture metadataSize failed");
212     }
213     picture->SetAuxiliaryPicture(auxiliaryPicture);
214     MEDIA_DEBUG_LOG("PictureHandler::ReadAuxiliaryPicture end");
215     return true;
216 }
217 
ReadAuxiliaryPictureInfo(MessageParcel & data,AuxiliaryPictureInfo & auxiliaryPictureInfo)218 bool PictureHandlerClient::ReadAuxiliaryPictureInfo(MessageParcel &data, AuxiliaryPictureInfo &auxiliaryPictureInfo)
219 {
220     auxiliaryPictureInfo.auxiliaryPictureType = static_cast<AuxiliaryPictureType>(data.ReadInt32());
221     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadAuxiliaryPictureInfo auxiliaryPictureType: %{public}d",
222         auxiliaryPictureInfo.auxiliaryPictureType);
223 
224     auxiliaryPictureInfo.colorSpace = static_cast<ColorSpace>(data.ReadInt32());
225     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadAuxiliaryPictureInfo colorSpace: %{public}d",
226         auxiliaryPictureInfo.colorSpace);
227 
228     auxiliaryPictureInfo.pixelFormat = static_cast<PixelFormat>(data.ReadInt32());
229     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadAuxiliaryPictureInfo pixelFormat: %{public}d",
230         auxiliaryPictureInfo.pixelFormat);
231 
232     auxiliaryPictureInfo.rowStride = static_cast<uint32_t>(data.ReadInt32());
233     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadAuxiliaryPictureInfo rowStride: %{public}d",
234         auxiliaryPictureInfo.rowStride);
235 
236     auxiliaryPictureInfo.size.height = data.ReadInt32();
237     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadAuxiliaryPictureInfo height: %{public}d",
238         auxiliaryPictureInfo.size.height);
239 
240     auxiliaryPictureInfo.size.width = data.ReadInt32();
241     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadAuxiliaryPictureInfo width: %{public}d",
242         auxiliaryPictureInfo.size.width);
243 
244     return true;
245 }
246 
ReadImageInfo(MessageParcel & data,ImageInfo & imageInfo)247 bool PictureHandlerClient::ReadImageInfo(MessageParcel &data, ImageInfo &imageInfo)
248 {
249     imageInfo.size.width = data.ReadInt32();
250     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadImageInfo width: %{public}d", imageInfo.size.width);
251     imageInfo.size.height = data.ReadInt32();
252     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadImageInfo height: %{public}d", imageInfo.size.height);
253     imageInfo.pixelFormat = static_cast<PixelFormat>(data.ReadInt32());
254     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadImageInfo pixelFormat: %{public}d", imageInfo.pixelFormat);
255     imageInfo.colorSpace = static_cast<ColorSpace>(data.ReadInt32());
256     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadImageInfo colorSpace: %{public}d", imageInfo.colorSpace);
257     imageInfo.alphaType = static_cast<AlphaType>(data.ReadInt32());
258     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadImageInfo alphaType: %{public}d", imageInfo.alphaType);
259     imageInfo.baseDensity = data.ReadInt32();
260     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadImageInfo baseDensity: %{public}d", imageInfo.baseDensity);
261     return true;
262 }
263 
ReadYuvDataInfo(MessageParcel & data,YUVDataInfo & info)264 bool PictureHandlerClient::ReadYuvDataInfo(MessageParcel &data, YUVDataInfo &info)
265 {
266     info.imageSize.width = data.ReadInt32();
267     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo width: %{public}d", info.imageSize.width);
268     info.imageSize.height = data.ReadInt32();
269     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo height: %{public}d", info.imageSize.height);
270     info.yWidth = data.ReadUint32();
271     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo yWidth: %{public}d", info.yWidth);
272     info.yHeight = data.ReadUint32();
273     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo yHeight: %{public}d", info.yHeight);
274     info.uvWidth = data.ReadUint32();
275     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo uvWidth: %{public}d", info.uvWidth);
276     info.uvHeight = data.ReadUint32();
277     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo uvHeight: %{public}d", info.uvHeight);
278     info.yStride = data.ReadUint32();
279     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo yStride: %{public}d", info.yStride);
280     info.uStride = data.ReadUint32();
281     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo uStride: %{public}d", info.uStride);
282     info.vStride = data.ReadUint32();
283     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo vStride: %{public}d", info.vStride);
284     info.uvStride = data.ReadUint32();
285     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo uvStride: %{public}d", info.uvStride);
286     info.yOffset = data.ReadUint32();
287     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo yOffset: %{public}d", info.yOffset);
288     info.uOffset = data.ReadUint32();
289     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo uOffset: %{public}d", info.uOffset);
290     info.vOffset = data.ReadUint32();
291     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo vOffset: %{public}d", info.vOffset);
292     info.uvOffset = data.ReadUint32();
293     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadYuvDataInfo uvOffset: %{public}d", info.uvOffset);
294     return true;
295 }
296 
ReadSurfaceBuffer(MessageParcel & data,std::unique_ptr<PixelMap> & pixelMap)297 bool PictureHandlerClient::ReadSurfaceBuffer(MessageParcel &data, std::unique_ptr<PixelMap> &pixelMap)
298 {
299     bool hasBufferHandle = data.ReadBool();
300     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadSurfaceBuffer hasBufferHandle: %{public}d", hasBufferHandle);
301     if (!hasBufferHandle) {
302         return false;
303     }
304     sptr<SurfaceBuffer> surfaceBuffer = SurfaceBuffer::Create();
305     ReadBufferHandle(data, surfaceBuffer);
306     void* nativeBuffer = surfaceBuffer.GetRefPtr();
307     OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(nativeBuffer);
308     ref->IncStrongRef(ref);
309     pixelMap->SetPixelsAddr(static_cast<uint8_t*>(surfaceBuffer->GetVirAddr()), nativeBuffer,
310         pixelMap->GetByteCount(), AllocatorType::DMA_ALLOC, nullptr);
311     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadSurfaceBuffer end");
312     return true;
313 }
314 
ReadBufferHandle(MessageParcel & data,sptr<SurfaceBuffer> & surfaceBuffer)315 bool PictureHandlerClient::ReadBufferHandle(MessageParcel &data, sptr<SurfaceBuffer> &surfaceBuffer)
316 {
317     uint32_t reserveFds = 0;
318     bool readReserveFdsRet = data.ReadUint32(reserveFds);
319     if (reserveFds < 0 || reserveFds > static_cast<uint32_t>(MAX_VALUE)) {
320         return false;
321     }
322     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle reserveFds: %{public}d", reserveFds);
323     uint32_t reserveInts = 0;
324     bool reserveIntsRet = data.ReadUint32(reserveInts);
325     if (reserveInts < 0 || reserveInts > static_cast<uint32_t>(MAX_VALUE)) {
326         return false;
327     }
328     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle reserveInts: %{public}d", reserveInts);
329 
330     size_t handleSize = sizeof(BufferHandle) + (sizeof(int32_t) * (reserveFds + reserveInts));
331     BufferHandle *handle = static_cast<BufferHandle *>(malloc(handleSize));
332     if (handle == nullptr) {
333         MEDIA_ERR_LOG("PictureHandlerClient::ReadBufferHandle malloc BufferHandle failed");
334         return false;
335     }
336     memset_s(handle, handleSize, 0, handleSize);
337 
338     handle->reserveFds = reserveFds;
339     handle->reserveInts = reserveInts;
340     handle->width = data.ReadInt32();
341     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle width: %{public}d", handle->width);
342     handle->stride = data.ReadInt32();
343     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle stride: %{public}d", handle->stride);
344     handle->height = data.ReadInt32();
345     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle height: %{public}d", handle->height);
346     handle->size = data.ReadInt32();
347     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle size: %{public}d", handle->size);
348     handle->format = data.ReadInt32();
349     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle format: %{public}d", handle->format);
350     handle->usage = data.ReadUint64();
351     handle->phyAddr = data.ReadUint64();
352 
353     int32_t fd = RequestBufferHandlerFd(data.ReadInt32());
354     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle fd: %{public}d", fd);
355     handle->fd = dup(fd);
356     close(fd);
357     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle handle->fd: %{public}d", handle->fd);
358     if (readReserveFdsRet) {
359         for (uint32_t i = 0; i < reserveFds; i++) {
360             int32_t reserveFd = RequestBufferHandlerFd(data.ReadInt32());
361             MEDIA_DEBUG_LOG("PictureHandlerClient::ReadBufferHandle reserve[%{public}d]: %{public}d", i, reserveFd);
362             handle->reserve[i] = dup(reserveFd);
363             close(reserveFd);
364         }
365     }
366 
367     if (reserveIntsRet) {
368         for (uint32_t j = 0; j < handle->reserveInts; j++) {
369             handle->reserve[reserveFds + j] = data.ReadInt32();
370         }
371     }
372     surfaceBuffer->SetBufferHandle(handle);
373     return true;
374 }
375 
ReadExifMetadata(MessageParcel & data,std::unique_ptr<Media::Picture> & picture)376 bool PictureHandlerClient::ReadExifMetadata(MessageParcel &data, std::unique_ptr<Media::Picture> &picture)
377 {
378     bool hasExifMetadata = data.ReadBool();
379     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadExifMetadata hasExifMetadata:%{public}d", hasExifMetadata);
380     if (!hasExifMetadata) {
381         return true;
382     }
383     ExifMetadata *exifMetadataPtr = ExifMetadata::Unmarshalling(data);
384     auto exifMetadata = std::shared_ptr<ExifMetadata>(exifMetadataPtr);
385     picture->SetExifMetadata(exifMetadata);
386     return true;
387 }
388 
ReadMaintenanceData(MessageParcel & data,std::unique_ptr<Media::Picture> & picture)389 bool PictureHandlerClient::ReadMaintenanceData(MessageParcel &data, std::unique_ptr<Media::Picture> &picture)
390 {
391     bool hasMaintenanceData = data.ReadBool();
392     MEDIA_DEBUG_LOG("PictureHandlerClient::ReadMaintenanceData hasMaintenanceData:%{public}d", hasMaintenanceData);
393     if (!hasMaintenanceData) {
394         return true;
395     }
396     sptr<SurfaceBuffer> surfaceBuffer = SurfaceBuffer::Create();
397     ReadBufferHandle(data, surfaceBuffer);
398     return picture->SetMaintenanceData(surfaceBuffer);
399 }
400 
RequestBufferHandlerFd(const int32_t & fd)401 int32_t PictureHandlerClient::RequestBufferHandlerFd(const int32_t &fd)
402 {
403     std::string uri = PhotoColumn::PHOTO_REQUEST_PICTURE_BUFFER;
404     MediaFileUtils::UriAppendKeyValue(uri, "fd", std::to_string(fd));
405     MEDIA_DEBUG_LOG("PictureHandlerClient::RequestBufferHandlerFd uri: %{public}s", uri.c_str());
406     Uri requestUri(uri);
407     return UserFileClient::OpenFile(requestUri, MEDIA_FILEMODE_READONLY);
408 }
409 }
410 }