llimagebmp.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /**
  2. * @file LLImageBMP.cpp
  3. *
  4. * $LicenseInfo:firstyear=2001&license=viewergpl$
  5. *
  6. * Copyright (c) 2001-2009, Linden Research, Inc.
  7. *
  8. * Second Life Viewer Source Code
  9. * The source code in this file ("Source Code") is provided by Linden Lab
  10. * to you under the terms of the GNU General Public License, version 2.0
  11. * ("GPL"), unless you have obtained a separate licensing agreement
  12. * ("Other License"), formally executed by you and Linden Lab. Terms of
  13. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15. *
  16. * There are special exceptions to the terms and conditions of the GPL as
  17. * it is applied to this Source Code. View the full text of the exception
  18. * in the file doc/FLOSS-exception.txt in this software distribution, or
  19. * online at
  20. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21. *
  22. * By copying, modifying or distributing this software, you acknowledge
  23. * that you have read and understood your obligations described above,
  24. * and agree to abide by those obligations.
  25. *
  26. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28. * COMPLETENESS OR PERFORMANCE.
  29. * $/LicenseInfo$
  30. */
  31. #include "linden_common.h"
  32. #include "llimagebmp.h"
  33. #include "llendianswizzle.h"
  34. /**
  35. * @struct LLBMPHeader
  36. *
  37. * This struct helps deal with bmp files.
  38. */
  39. struct LLBMPHeader
  40. {
  41. S32 mSize;
  42. S32 mWidth;
  43. S32 mHeight;
  44. S16 mPlanes;
  45. S16 mBitsPerPixel;
  46. S16 mCompression;
  47. S16 mAlignmentPadding; // pads out to next word boundary
  48. S32 mImageSize;
  49. S32 mHorzPelsPerMeter;
  50. S32 mVertPelsPerMeter;
  51. S32 mNumColors;
  52. S32 mNumColorsImportant;
  53. };
  54. /**
  55. * @struct Win95BmpHeaderExtension
  56. */
  57. struct Win95BmpHeaderExtension
  58. {
  59. U32 mReadMask;
  60. U32 mGreenMask;
  61. U32 mBlueMask;
  62. U32 mAlphaMask;
  63. U32 mColorSpaceType;
  64. U16 mRed[3]; // Red CIE endpoint
  65. U16 mGreen[3]; // Green CIE endpoint
  66. U16 mBlue[3]; // Blue CIE endpoint
  67. U32 mGamma[3]; // Gamma scale for r g and b
  68. };
  69. /**
  70. * LLImageBMP
  71. */
  72. LLImageBMP::LLImageBMP()
  73. : LLImageFormatted(IMG_CODEC_BMP),
  74. mColorPaletteColors(0),
  75. mColorPalette(NULL),
  76. mBitmapOffset(0),
  77. mBitsPerPixel(0),
  78. mOriginAtTop(false)
  79. {
  80. mBitfieldMask[0] = 0;
  81. mBitfieldMask[1] = 0;
  82. mBitfieldMask[2] = 0;
  83. mBitfieldMask[3] = 0;
  84. }
  85. LLImageBMP::~LLImageBMP()
  86. {
  87. if (mColorPalette)
  88. {
  89. delete[] mColorPalette;
  90. mColorPalette = NULL;
  91. }
  92. }
  93. bool LLImageBMP::updateData()
  94. {
  95. resetLastError();
  96. // Check to make sure that this instance has been initialized with data
  97. U8* mdata = getData();
  98. if (!mdata || getDataSize() == 0)
  99. {
  100. setLastError("Uninitialized instance of LLImageBMP");
  101. return false;
  102. }
  103. // Read the bitmap headers in order to get all the useful info
  104. // about this image
  105. ////////////////////////////////////////////////////////////////////
  106. // Part 1: "File Header"
  107. // 14 bytes consisting of
  108. // 2 bytes: either BM or BA
  109. // 4 bytes: file size in bytes
  110. // 4 bytes: reserved (always 0)
  111. // 4 bytes: bitmap offset (starting position of image data in bytes)
  112. constexpr S32 FILE_HEADER_SIZE = 14;
  113. if (mdata[0] != 'B' || mdata[1] != 'M')
  114. {
  115. if (mdata[0] != 'B' || mdata[1] != 'A')
  116. {
  117. setLastError("OS/2 bitmap array BMP files are not supported");
  118. return false;
  119. }
  120. else
  121. {
  122. setLastError("Does not appear to be a bitmap file");
  123. return false;
  124. }
  125. }
  126. mBitmapOffset = mdata[13];
  127. mBitmapOffset <<= 8; mBitmapOffset += mdata[12];
  128. mBitmapOffset <<= 8; mBitmapOffset += mdata[11];
  129. mBitmapOffset <<= 8; mBitmapOffset += mdata[10];
  130. ////////////////////////////////////////////////////////////////////
  131. // Part 2: "Bitmap Header"
  132. constexpr S32 BITMAP_HEADER_SIZE = 40;
  133. LLBMPHeader header;
  134. llassert(sizeof(header) == BITMAP_HEADER_SIZE);
  135. memcpy((void*)&header, mdata + FILE_HEADER_SIZE, BITMAP_HEADER_SIZE);
  136. // Convert BMP header from little endian (no-op on little endian builds)
  137. llendianswizzleone(header.mSize);
  138. llendianswizzleone(header.mWidth);
  139. llendianswizzleone(header.mHeight);
  140. llendianswizzleone(header.mPlanes);
  141. llendianswizzleone(header.mBitsPerPixel);
  142. llendianswizzleone(header.mCompression);
  143. llendianswizzleone(header.mAlignmentPadding);
  144. llendianswizzleone(header.mImageSize);
  145. llendianswizzleone(header.mHorzPelsPerMeter);
  146. llendianswizzleone(header.mVertPelsPerMeter);
  147. llendianswizzleone(header.mNumColors);
  148. llendianswizzleone(header.mNumColorsImportant);
  149. bool windows_nt_version = false;
  150. bool windows_95_version = false;
  151. if (12 == header.mSize)
  152. {
  153. setLastError("Windows 2.x and OS/2 1.x BMP files are not supported");
  154. return false;
  155. }
  156. else if (40 == header.mSize)
  157. {
  158. if (3 == header.mCompression)
  159. {
  160. // Windows NT
  161. windows_nt_version = true;
  162. }
  163. }
  164. else if (12 <= header.mSize && header.mSize <= 64)
  165. {
  166. setLastError("OS/2 2.x BMP files are not supported");
  167. return false;
  168. }
  169. else if (108 == header.mSize)
  170. {
  171. // BITMAPV4HEADER
  172. windows_95_version = true;
  173. }
  174. else if (108 < header.mSize)
  175. {
  176. // BITMAPV5HEADER or greater
  177. // Should work as long at Microsoft maintained backwards compatibility
  178. // (which they did in V4 and V5)
  179. windows_95_version = true;
  180. }
  181. S32 width = header.mWidth;
  182. S32 height = header.mHeight;
  183. if (height < 0)
  184. {
  185. mOriginAtTop = true;
  186. height = -height;
  187. }
  188. else
  189. {
  190. mOriginAtTop = false;
  191. }
  192. mBitsPerPixel = header.mBitsPerPixel;
  193. S32 components;
  194. switch (mBitsPerPixel)
  195. {
  196. case 8:
  197. components = 1;
  198. break;
  199. case 24:
  200. case 32:
  201. components = 3;
  202. break;
  203. case 1:
  204. case 4:
  205. case 16: // Started work on 16, but doesn't work yet
  206. // These are legal, but we don't support them yet.
  207. setLastError("Unsupported bit depth");
  208. return false;
  209. default:
  210. setLastError("Unrecognized bit depth");
  211. return false;
  212. }
  213. setSize(width, height, components);
  214. switch (header.mCompression)
  215. {
  216. case 0:
  217. // Uncompressed
  218. break;
  219. case 1:
  220. setLastError("8 bit RLE compression not supported.");
  221. return false;
  222. case 2:
  223. setLastError("4 bit RLE compression not supported.");
  224. return false;
  225. case 3:
  226. // Windows NT or Windows 95
  227. break;
  228. default:
  229. setLastError("Unsupported compression format.");
  230. return false;
  231. }
  232. ////////////////////////////////////////////////////////////////////
  233. // Part 3: Bitfield Masks and other color data
  234. S32 extension_size = 0;
  235. if (windows_nt_version)
  236. {
  237. if (header.mBitsPerPixel != 16 && header.mBitsPerPixel != 32)
  238. {
  239. setLastError("Bitfield encoding requires 16 or 32 bits per pixel.");
  240. return false;
  241. }
  242. if (header.mNumColors != 0)
  243. {
  244. setLastError("Bitfield encoding is not compatible with a color table.");
  245. return false;
  246. }
  247. extension_size = 4 * 3;
  248. memcpy(mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE,
  249. extension_size);
  250. }
  251. else if (windows_95_version)
  252. {
  253. Win95BmpHeaderExtension win_95_extension;
  254. extension_size = sizeof(win_95_extension);
  255. llassert(sizeof(win_95_extension) + BITMAP_HEADER_SIZE == 108);
  256. memcpy(&win_95_extension,
  257. mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE,
  258. sizeof(win_95_extension));
  259. if (3 == header.mCompression)
  260. {
  261. memcpy(mBitfieldMask,
  262. mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, 4 * 4);
  263. }
  264. // Color correction ignored for now
  265. }
  266. ////////////////////////////////////////////////////////////////////
  267. // Part 4: Color Palette (optional)
  268. // Note: There's no color palette if there are 16 or more bits per pixel
  269. S32 color_palette_size = 0;
  270. mColorPaletteColors = 0;
  271. if (header.mBitsPerPixel < 16)
  272. {
  273. if (header.mNumColors == 0)
  274. {
  275. mColorPaletteColors = 1 << header.mBitsPerPixel;
  276. }
  277. else
  278. {
  279. mColorPaletteColors = header.mNumColors;
  280. }
  281. }
  282. color_palette_size = mColorPaletteColors * 4;
  283. if (mColorPaletteColors > 0)
  284. {
  285. mColorPalette = new (std::nothrow) U8[color_palette_size];
  286. if (!mColorPalette)
  287. {
  288. LLMemory::allocationFailed(color_palette_size);
  289. return false;
  290. }
  291. memcpy(mColorPalette,
  292. mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE + extension_size,
  293. color_palette_size);
  294. }
  295. return true;
  296. }
  297. bool LLImageBMP::decode(LLImageRaw* raw_image)
  298. {
  299. if (!raw_image)
  300. {
  301. llwarns << "Attempted to decode a NULL raw image" << llendl;
  302. llassert(false);
  303. return false;
  304. }
  305. resetLastError();
  306. // Check to make sure that this instance has been initialized with data
  307. U8* mdata = getData();
  308. if (!mdata || getDataSize() == 0)
  309. {
  310. setLastError("LLImageBMP trying to decode an image with no data");
  311. return false;
  312. }
  313. if (!raw_image->resize(getWidth(), getHeight(), 3))
  314. {
  315. setLastError("LLImageBMP failed to resize image");
  316. return false;
  317. }
  318. U8* src = mdata + mBitmapOffset;
  319. U8* dst = raw_image->getData();
  320. bool success = false;
  321. switch (mBitsPerPixel)
  322. {
  323. case 8:
  324. if (mColorPaletteColors >= 256)
  325. {
  326. success = decodeColorTable8(dst, src);
  327. }
  328. break;
  329. case 16:
  330. success = decodeColorMask16(dst, src);
  331. break;
  332. case 24:
  333. success = decodeTruecolor24(dst, src);
  334. break;
  335. case 32:
  336. success = decodeColorMask32(dst, src);
  337. break;
  338. }
  339. if (success && mOriginAtTop)
  340. {
  341. raw_image->verticalFlip();
  342. }
  343. return success;
  344. }
  345. U32 LLImageBMP::countTrailingZeros(U32 m)
  346. {
  347. U32 shift_count = 0;
  348. while (!(m & 1))
  349. {
  350. ++shift_count;
  351. m >>= 1;
  352. }
  353. return shift_count;
  354. }
  355. bool LLImageBMP::decodeColorMask16(U8* dst, U8* src)
  356. {
  357. if (mBitsPerPixel != 16)
  358. {
  359. llassert(false);
  360. return false;
  361. }
  362. if (!mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2])
  363. {
  364. // Use default values
  365. mBitfieldMask[0] = 0x00007C00;
  366. mBitfieldMask[1] = 0x000003E0;
  367. mBitfieldMask[2] = 0x0000001F;
  368. }
  369. S32 src_row_span = getWidth() * 2;
  370. // Round up to nearest multiple of 4:
  371. S32 alignment_bytes = (3 * src_row_span) % 4;
  372. U32 r_shift = countTrailingZeros(mBitfieldMask[2]);
  373. U32 g_shift = countTrailingZeros(mBitfieldMask[1]);
  374. U32 b_shift = countTrailingZeros(mBitfieldMask[0]);
  375. for (S32 row = 0, height = getHeight(); row < height; ++row)
  376. {
  377. for (S32 col = 0, width = getWidth(); col < width; ++col)
  378. {
  379. U32 value = *((U16*)src);
  380. dst[0] = U8((value & mBitfieldMask[2]) >> r_shift); // Red
  381. dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green
  382. dst[2] = U8((value & mBitfieldMask[0]) >> b_shift); // Blue
  383. src += 2;
  384. dst += 3;
  385. }
  386. src += alignment_bytes;
  387. }
  388. return true;
  389. }
  390. bool LLImageBMP::decodeColorMask32(U8* dst, U8* src)
  391. {
  392. if (mBitsPerPixel != 32)
  393. {
  394. // Alpha is not supported
  395. llassert(false);
  396. return false;
  397. }
  398. if (!mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2])
  399. {
  400. // Use default values
  401. mBitfieldMask[0] = 0x00FF0000;
  402. mBitfieldMask[1] = 0x0000FF00;
  403. mBitfieldMask[2] = 0x000000FF;
  404. }
  405. if (4 * getWidth() * getHeight() > getDataSize() - mBitmapOffset)
  406. {
  407. // here we have situation when data size in src less than actually
  408. // needed
  409. return false;
  410. }
  411. S32 src_row_span = getWidth() * 4;
  412. // Round up to nearest multiple of 4:
  413. S32 alignment_bytes = (3 * src_row_span) % 4;
  414. U32 r_shift = countTrailingZeros(mBitfieldMask[0]);
  415. U32 g_shift = countTrailingZeros(mBitfieldMask[1]);
  416. U32 b_shift = countTrailingZeros(mBitfieldMask[2]);
  417. for (S32 row = 0, height = getHeight(); row < height; ++row)
  418. {
  419. for (S32 col = 0, width = getWidth(); col < width; ++col)
  420. {
  421. U32 value = *((U32*)src);
  422. dst[0] = U8((value & mBitfieldMask[0]) >> r_shift); // Red
  423. dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green
  424. dst[2] = U8((value & mBitfieldMask[2]) >> b_shift); // Blue
  425. src += 4;
  426. dst += 3;
  427. }
  428. src += alignment_bytes;
  429. }
  430. return true;
  431. }
  432. bool LLImageBMP::decodeColorTable8(U8* dst, U8* src)
  433. {
  434. if (mBitsPerPixel != 8 || mColorPaletteColors < 256)
  435. {
  436. llassert(false);
  437. return false;
  438. }
  439. S32 src_row_span = getWidth() * 1;
  440. // Round up to nearest multiple of 4:
  441. S32 alignment_bytes = (3 * src_row_span) % 4;
  442. if (getWidth() * getHeight() + getHeight() * alignment_bytes >
  443. getDataSize() - mBitmapOffset)
  444. {
  445. // here we have situation when data size in src less than actually
  446. // needed
  447. return false;
  448. }
  449. for (S32 row = 0, height = getHeight(); row < height; ++row)
  450. {
  451. for (S32 col = 0, width = getWidth(); col < width; ++col)
  452. {
  453. S32 index = 4 * src[0];
  454. dst[0] = mColorPalette[index + 2]; // Red
  455. dst[1] = mColorPalette[index + 1]; // Green
  456. dst[2] = mColorPalette[index + 0]; // Blue
  457. src++;
  458. dst += 3;
  459. }
  460. src += alignment_bytes;
  461. }
  462. return true;
  463. }
  464. bool LLImageBMP::decodeTruecolor24(U8* dst, U8* src)
  465. {
  466. if (mBitsPerPixel != 24 || getComponents() != 3)
  467. {
  468. llassert(false);
  469. return false;
  470. }
  471. S32 src_row_span = getWidth() * 3;
  472. // Round up to nearest multiple of 4:
  473. S32 alignment_bytes = (3 * src_row_span) % 4;
  474. if (3 * getWidth() * getHeight() + getHeight() * alignment_bytes >
  475. getDataSize() - mBitmapOffset)
  476. {
  477. // here we have situation when data size in src less than actually
  478. // needed
  479. return false;
  480. }
  481. for (S32 row = 0, height = getHeight(); row < height; ++row)
  482. {
  483. for (S32 col = 0, width = getWidth(); col < width; ++col)
  484. {
  485. dst[0] = src[2]; // Red
  486. dst[1] = src[1]; // Green
  487. dst[2] = src[0]; // Blue
  488. src += 3;
  489. dst += 3;
  490. }
  491. src += alignment_bytes;
  492. }
  493. return true;
  494. }
  495. bool LLImageBMP::encode(const LLImageRaw* raw_image)
  496. {
  497. if (!raw_image)
  498. {
  499. llwarns << "Attempted to decode a NULL raw image" << llendl;
  500. llassert(false);
  501. return false;
  502. }
  503. resetLastError();
  504. S32 src_components = raw_image->getComponents();
  505. S32 dst_components = (src_components < 3) ? 1 : 3;
  506. if (src_components == 2 || src_components == 4)
  507. {
  508. llinfos << "Dropping alpha information during BMP encoding" << llendl;
  509. }
  510. setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components);
  511. U8 magic[14];
  512. LLBMPHeader header;
  513. int header_bytes = 14 + sizeof(header);
  514. llassert(header_bytes == 54);
  515. if (getComponents() == 1)
  516. {
  517. header_bytes += 1024; // Need colour LUT.
  518. }
  519. int line_bytes = getComponents() * getWidth();
  520. int alignment_bytes = (3 * line_bytes) % 4;
  521. line_bytes += alignment_bytes;
  522. int file_bytes = line_bytes*getHeight() + header_bytes;
  523. // Allocate the new buffer for the data.
  524. if (!allocateData(file_bytes)) // memory allocation failed
  525. {
  526. return false;
  527. }
  528. magic[0] = 'B'; magic[1] = 'M';
  529. magic[2] = (U8) file_bytes;
  530. magic[3] = (U8)(file_bytes>>8);
  531. magic[4] = (U8)(file_bytes>>16);
  532. magic[5] = (U8)(file_bytes>>24);
  533. magic[6] = magic[7] = magic[8] = magic[9] = 0;
  534. magic[10] = (U8) header_bytes;
  535. magic[11] = (U8)(header_bytes>>8);
  536. magic[12] = (U8)(header_bytes>>16);
  537. magic[13] = (U8)(header_bytes>>24);
  538. header.mSize = 40;
  539. header.mWidth = getWidth();
  540. header.mHeight = getHeight();
  541. header.mPlanes = 1;
  542. header.mBitsPerPixel = (getComponents()==1)?8:24;
  543. header.mCompression = 0;
  544. header.mAlignmentPadding = 0;
  545. header.mImageSize = 0;
  546. #if LL_DARWIN
  547. header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 2834; // 72dpi
  548. #else
  549. header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 0;
  550. #endif
  551. header.mNumColors = header.mNumColorsImportant = 0;
  552. // convert BMP header to little endian (no-op on little endian builds)
  553. llendianswizzleone(header.mSize);
  554. llendianswizzleone(header.mWidth);
  555. llendianswizzleone(header.mHeight);
  556. llendianswizzleone(header.mPlanes);
  557. llendianswizzleone(header.mBitsPerPixel);
  558. llendianswizzleone(header.mCompression);
  559. llendianswizzleone(header.mAlignmentPadding);
  560. llendianswizzleone(header.mImageSize);
  561. llendianswizzleone(header.mHorzPelsPerMeter);
  562. llendianswizzleone(header.mVertPelsPerMeter);
  563. llendianswizzleone(header.mNumColors);
  564. llendianswizzleone(header.mNumColorsImportant);
  565. U8* mdata = getData();
  566. // Output magic, then header, then the palette table, then the data.
  567. U32 cur_pos = 0;
  568. memcpy(mdata, magic, 14);
  569. cur_pos += 14;
  570. memcpy(mdata + cur_pos, &header, 40);
  571. cur_pos += 40;
  572. if (getComponents() == 1)
  573. {
  574. for (S32 n = 0; n < 256; ++n)
  575. {
  576. mdata[cur_pos++] = (U8)n;
  577. mdata[cur_pos++] = (U8)n;
  578. mdata[cur_pos++] = (U8)n;
  579. mdata[cur_pos++] = 0;
  580. }
  581. }
  582. // Need to iterate through, because we need to flip the RGB.
  583. const U8* src = raw_image->getData();
  584. U8* dst = mdata + cur_pos;
  585. for (S32 row = 0, height = getHeight(); row < height; ++row)
  586. {
  587. for (S32 col = 0, width = getWidth(); col < width; ++col)
  588. {
  589. switch (src_components)
  590. {
  591. case 1:
  592. {
  593. *dst++ = *src++;
  594. break;
  595. }
  596. case 2:
  597. {
  598. U32 lum = src[0];
  599. U32 alpha = src[1];
  600. *dst++ = (U8)(lum * alpha / 255);
  601. src += 2;
  602. break;
  603. }
  604. case 3:
  605. case 4:
  606. {
  607. dst[0] = src[2];
  608. dst[1] = src[1];
  609. dst[2] = src[0];
  610. src += src_components;
  611. dst += 3;
  612. break;
  613. }
  614. }
  615. }
  616. for (S32 i = 0; i < alignment_bytes; ++i)
  617. {
  618. *dst++ = 0;
  619. }
  620. }
  621. return true;
  622. }