< prev index next >

src/java.desktop/share/native/liblcms/cmsio0.c

Print this page




  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 // This file is available under and governed by the GNU General Public
  26 // License version 2 only, as published by the Free Software Foundation.
  27 // However, the following notice accompanied the original version of this
  28 // file:
  29 //
  30 //---------------------------------------------------------------------------------
  31 //
  32 //  Little Color Management System
  33 //  Copyright (c) 1998-2012 Marti Maria Saguer
  34 //
  35 // Permission is hereby granted, free of charge, to any person obtaining
  36 // a copy of this software and associated documentation files (the "Software"),
  37 // to deal in the Software without restriction, including without limitation
  38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  39 // and/or sell copies of the Software, and to permit persons to whom the Software
  40 // is furnished to do so, subject to the following conditions:
  41 //
  42 // The above copyright notice and this permission notice shall be included in
  43 // all copies or substantial portions of the Software.
  44 //
  45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  52 //
  53 //---------------------------------------------------------------------------------


 336     if (iohandler) _cmsFree(ContextID, iohandler);
 337     return NULL;
 338 }
 339 
 340 // File-based stream -------------------------------------------------------
 341 
 342 // Read count elements of size bytes each. Return number of elements read
 343 static
 344 cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
 345 {
 346     cmsUInt32Number nReaded = (cmsUInt32Number) fread(Buffer, size, count, (FILE*) iohandler->stream);
 347 
 348     if (nReaded != count) {
 349             cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size);
 350             return 0;
 351     }
 352 
 353     return nReaded;
 354 }
 355 
 356 // Postion file pointer in the file
 357 static
 358 cmsBool  FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
 359 {
 360     if (fseek((FILE*) iohandler ->stream, (long) offset, SEEK_SET) != 0) {
 361 
 362        cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Seek error; probably corrupted file");
 363        return FALSE;
 364     }
 365 
 366     return TRUE;
 367 }
 368 
 369 // Returns file pointer position
 370 static
 371 cmsUInt32Number FileTell(cmsIOHANDLER* iohandler)
 372 {
 373     return (cmsUInt32Number) ftell((FILE*)iohandler ->stream);
 374 }
 375 
 376 // Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error


 380        if (size == 0) return TRUE;  // We allow to write 0 bytes, but nothing is written
 381 
 382        iohandler->UsedSpace += size;
 383        return (fwrite(Buffer, size, 1, (FILE*) iohandler->stream) == 1);
 384 }
 385 
 386 // Closes the file
 387 static
 388 cmsBool  FileClose(cmsIOHANDLER* iohandler)
 389 {
 390     if (fclose((FILE*) iohandler ->stream) != 0) return FALSE;
 391     _cmsFree(iohandler ->ContextID, iohandler);
 392     return TRUE;
 393 }
 394 
 395 // Create a iohandler for disk based files.
 396 cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode)
 397 {
 398     cmsIOHANDLER* iohandler = NULL;
 399     FILE* fm = NULL;

 400 
 401     _cmsAssert(FileName != NULL);
 402     _cmsAssert(AccessMode != NULL);
 403 
 404     iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
 405     if (iohandler == NULL) return NULL;
 406 
 407     switch (*AccessMode) {
 408 
 409     case 'r':
 410         fm = fopen(FileName, "rb");
 411         if (fm == NULL) {
 412             _cmsFree(ContextID, iohandler);
 413              cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName);
 414             return NULL;
 415         }
 416         iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm);









 417         break;
 418 
 419     case 'w':
 420         fm = fopen(FileName, "wb");
 421         if (fm == NULL) {
 422             _cmsFree(ContextID, iohandler);
 423              cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName);
 424             return NULL;
 425         }
 426         iohandler -> ReportedSize = 0;
 427         break;
 428 
 429     default:
 430         _cmsFree(ContextID, iohandler);
 431          cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode);
 432         return NULL;
 433     }
 434 
 435     iohandler ->ContextID = ContextID;
 436     iohandler ->stream = (void*) fm;
 437     iohandler ->UsedSpace = 0;
 438 
 439     // Keep track of the original file
 440     strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1);
 441     iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0;
 442 
 443     iohandler ->Read    = FileRead;
 444     iohandler ->Seek    = FileSeek;
 445     iohandler ->Close   = FileClose;
 446     iohandler ->Tell    = FileTell;
 447     iohandler ->Write   = FileWrite;
 448 
 449     return iohandler;
 450 }
 451 
 452 // Create a iohandler for stream based files
 453 cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream)
 454 {
 455     cmsIOHANDLER* iohandler = NULL;








 456 
 457     iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
 458     if (iohandler == NULL) return NULL;
 459 
 460     iohandler -> ContextID = ContextID;
 461     iohandler -> stream = (void*) Stream;
 462     iohandler -> UsedSpace = 0;
 463     iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream);
 464     iohandler -> PhysicalFile[0] = 0;
 465 
 466     iohandler ->Read    = FileRead;
 467     iohandler ->Seek    = FileSeek;
 468     iohandler ->Close   = FileClose;
 469     iohandler ->Tell    = FileTell;
 470     iohandler ->Write   = FileWrite;
 471 
 472     return iohandler;
 473 }
 474 
 475 
 476 
 477 // Close an open IO handler
 478 cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io)
 479 {
 480     return io -> Close(io);
 481 }
 482 
 483 // -------------------------------------------------------------------------------------------------------


 635         _cmsDeleteTagByPos(Icc, i);
 636         *NewPos = i;
 637     }
 638     else  {
 639 
 640         // No, make a new one
 641 
 642         if (Icc -> TagCount >= MAX_TABLE_TAG) {
 643             cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
 644             return FALSE;
 645         }
 646 
 647         *NewPos = Icc ->TagCount;
 648         Icc -> TagCount++;
 649     }
 650 
 651     return TRUE;
 652 }
 653 
 654 
 655 // Check existance
 656 cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig)
 657 {
 658        _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) (void*) hProfile;
 659        return _cmsSearchTag(Icc, sig, FALSE) >= 0;
 660 }
 661 
 662 
 663 
 664 // Enforces that the profile version is per. spec.
 665 // Operates on the big endian bytes from the profile.
 666 // Called before converting to platform endianness.
 667 // Byte 0 is BCD major version, so max 9.
 668 // Byte 1 is 2 BCD digits, one per nibble.
 669 // Reserved bytes 2 & 3 must be 0.
 670 static
 671 cmsUInt32Number _validatedVersion(cmsUInt32Number DWord)
 672 {
 673     cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
 674     cmsUInt8Number temp1;
 675     cmsUInt8Number temp2;


 691 {
 692     cmsTagEntry Tag;
 693     cmsICCHeader Header;
 694     cmsUInt32Number i, j;
 695     cmsUInt32Number HeaderSize;
 696     cmsIOHANDLER* io = Icc ->IOhandler;
 697     cmsUInt32Number TagCount;
 698 
 699 
 700     // Read the header
 701     if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) {
 702         return FALSE;
 703     }
 704 
 705     // Validate file as an ICC profile
 706     if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) {
 707         cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature");
 708         return FALSE;
 709     }
 710 
 711     // Adjust endianess of the used parameters
 712     Icc -> DeviceClass     = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass);
 713     Icc -> ColorSpace      = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.colorSpace);
 714     Icc -> PCS             = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.pcs);
 715 
 716     Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent);
 717     Icc -> flags           = _cmsAdjustEndianess32(Header.flags);
 718     Icc -> manufacturer    = _cmsAdjustEndianess32(Header.manufacturer);
 719     Icc -> model           = _cmsAdjustEndianess32(Header.model);
 720     Icc -> creator         = _cmsAdjustEndianess32(Header.creator);
 721 
 722     _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes);
 723     Icc -> Version         = _cmsAdjustEndianess32(_validatedVersion(Header.version));
 724 
 725     // Get size as reported in header
 726     HeaderSize = _cmsAdjustEndianess32(Header.size);
 727 
 728     // Make sure HeaderSize is lower than profile size
 729     if (HeaderSize >= Icc ->IOhandler ->ReportedSize)
 730             HeaderSize = Icc ->IOhandler ->ReportedSize;
 731 


 809 
 810     Header.flags        = _cmsAdjustEndianess32(Icc -> flags);
 811     Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer);
 812     Header.model        = _cmsAdjustEndianess32(Icc -> model);
 813 
 814     _cmsAdjustEndianess64(&Header.attributes, &Icc -> attributes);
 815 
 816     // Rendering intent in the header (for embedded profiles)
 817     Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent);
 818 
 819     // Illuminant is always D50
 820     Header.illuminant.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->X));
 821     Header.illuminant.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
 822     Header.illuminant.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
 823 
 824     // Created by LittleCMS (that's me!)
 825     Header.creator      = _cmsAdjustEndianess32(lcmsSignature);
 826 
 827     memset(&Header.reserved, 0, sizeof(Header.reserved));
 828 
 829     // Set profile ID. Endianess is always big endian
 830     memmove(&Header.profileID, &Icc ->ProfileID, 16);
 831 
 832     // Dump the header
 833     if (!Icc -> IOhandler->Write(Icc->IOhandler, sizeof(cmsICCHeader), &Header)) return FALSE;
 834 
 835     // Saves Tag directory
 836 
 837     // Get true count
 838     for (i=0;  i < Icc -> TagCount; i++) {
 839         if (Icc ->TagNames[i] != 0)
 840             Count++;
 841     }
 842 
 843     // Store number of tags
 844     if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE;
 845 
 846     for (i=0; i < Icc -> TagCount; i++) {
 847 
 848         if (Icc ->TagNames[i] == 0) continue;   // It is just a placeholder
 849 
 850         Tag.sig    = (cmsTagSignature) _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagNames[i]);
 851         Tag.offset = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagOffsets[i]);
 852         Tag.size   = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagSizes[i]);
 853 
 854         if (!Icc ->IOhandler -> Write(Icc-> IOhandler, sizeof(cmsTagEntry), &Tag)) return FALSE;
 855     }
 856 
 857     return TRUE;
 858 }
 859 
 860 // ----------------------------------------------------------------------- Set/Get several struct members
 861 
 862 
 863 cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile)
 864 {
 865     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
 866     return Icc -> RenderingIntent;
 867 }
 868 


1178 
1179 
1180 
1181 // Dump tag contents. If the profile is being modified, untouched tags are copied from FileOrig
1182 static
1183 cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
1184 {
1185     cmsUInt8Number* Data;
1186     cmsUInt32Number i;
1187     cmsUInt32Number Begin;
1188     cmsIOHANDLER* io = Icc ->IOhandler;
1189     cmsTagDescriptor* TagDescriptor;
1190     cmsTagTypeSignature TypeBase;
1191     cmsTagTypeSignature Type;
1192     cmsTagTypeHandler* TypeHandler;
1193     cmsFloat64Number   Version = cmsGetProfileVersion((cmsHPROFILE) Icc);
1194     cmsTagTypeHandler LocalTypeHandler;
1195 
1196     for (i=0; i < Icc -> TagCount; i++) {
1197 
1198         if (Icc ->TagNames[i] == 0) continue;
1199 
1200         // Linked tags are not written
1201         if (Icc ->TagLinked[i] != (cmsTagSignature) 0) continue;
1202 
1203         Icc -> TagOffsets[i] = Begin = io ->UsedSpace;
1204 
1205         Data = (cmsUInt8Number*)  Icc -> TagPtrs[i];
1206 
1207         if (!Data) {
1208 
1209             // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user.
1210             // In this case a blind copy of the block data is performed
1211             if (FileOrig != NULL && Icc -> TagOffsets[i]) {
1212 
1213                 cmsUInt32Number TagSize   = FileOrig -> TagSizes[i];
1214                 cmsUInt32Number TagOffset = FileOrig -> TagOffsets[i];
1215                 void* Mem;
1216 
1217                 if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE;
1218 


1312 
1313         }
1314     }
1315 
1316     return TRUE;
1317 }
1318 
1319 // Low-level save to IOHANDLER. It returns the number of bytes used to
1320 // store the profile, or zero on error. io may be NULL and in this case
1321 // no data is written--only sizes are calculated
1322 cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io)
1323 {
1324     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
1325     _cmsICCPROFILE Keep;
1326     cmsIOHANDLER* PrevIO = NULL;
1327     cmsUInt32Number UsedSpace;
1328     cmsContext ContextID;
1329 
1330     _cmsAssert(hProfile != NULL);
1331 

1332     memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
1333 
1334     ContextID = cmsGetProfileContextID(hProfile);
1335     PrevIO = Icc ->IOhandler = cmsOpenIOhandlerFromNULL(ContextID);
1336     if (PrevIO == NULL) return 0;



1337 
1338     // Pass #1 does compute offsets
1339 
1340     if (!_cmsWriteHeader(Icc, 0)) goto Error;
1341     if (!SaveTags(Icc, &Keep)) goto Error;
1342 
1343     UsedSpace = PrevIO ->UsedSpace;
1344 
1345     // Pass #2 does save to iohandler
1346 
1347     if (io != NULL) {
1348 
1349         Icc ->IOhandler = io;
1350         if (!SetLinks(Icc)) goto Error;
1351         if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error;
1352         if (!SaveTags(Icc, &Keep)) goto Error;
1353     }
1354 
1355     memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
1356     if (!cmsCloseIOhandler(PrevIO)) return 0;



1357 
1358     return UsedSpace;
1359 
1360 
1361 Error:
1362     cmsCloseIOhandler(PrevIO);
1363     memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));


1364     return 0;
1365 }
1366 
1367 
1368 // Low-level save to disk.
1369 cmsBool  CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName)
1370 {
1371     cmsContext ContextID = cmsGetProfileContextID(hProfile);
1372     cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w");
1373     cmsBool rc;
1374 
1375     if (io == NULL) return FALSE;
1376 
1377     rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
1378     rc &= cmsCloseIOhandler(io);
1379 
1380     if (rc == FALSE) {          // remove() is C99 per 7.19.4.1
1381             remove(FileName);   // We have to IGNORE return value in this case
1382     }
1383     return rc;


1547     BaseType = _cmsReadTypeBase(io);
1548     if (BaseType == 0) goto Error;
1549 
1550     if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error;
1551 
1552     TagSize  -= 8;                      // Alredy read by the type base logic
1553 
1554     // Get type handler
1555     TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType);
1556     if (TypeHandler == NULL) goto Error;
1557     LocalTypeHandler = *TypeHandler;
1558 
1559 
1560     // Read the tag
1561     Icc -> TagTypeHandlers[n] = TypeHandler;
1562 
1563     LocalTypeHandler.ContextID = Icc ->ContextID;
1564     LocalTypeHandler.ICCVersion = Icc ->Version;
1565     Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize);
1566 
1567     // The tag type is supported, but something wrong happend and we cannot read the tag.
1568     // let know the user about this (although it is just a warning)
1569     if (Icc -> TagPtrs[n] == NULL) {
1570 
1571         char String[5];
1572 
1573         _cmsTagSignature2String(String, sig);
1574         cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String);
1575         goto Error;
1576     }
1577 
1578     // This is a weird error that may be a symptom of something more serious, the number of
1579     // stored item is actually less than the number of required elements.
1580     if (ElemCount < TagDescriptor ->ElemCount) {
1581 
1582         char String[5];
1583 
1584         _cmsTagSignature2String(String, sig);
1585         cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d",
1586             String, TagDescriptor ->ElemCount, ElemCount);
1587     }


1866 
1867     if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
1868 
1869     if (!_cmsNewTag(Icc, sig, &i)) {
1870         _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1871          return FALSE;
1872     }
1873 
1874     // Mark the tag as being written as RAW
1875     Icc ->TagSaveAsRaw[i] = TRUE;
1876     Icc ->TagNames[i]     = sig;
1877     Icc ->TagLinked[i]    = (cmsTagSignature) 0;
1878 
1879     // Keep a copy of the block
1880     Icc ->TagPtrs[i]  = _cmsDupMem(Icc ->ContextID, data, Size);
1881     Icc ->TagSizes[i] = Size;
1882 
1883     _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1884 
1885     if (Icc->TagPtrs[i] == NULL) {
1886            Icc->TagNames[i] = 0;
1887            return FALSE;
1888     }
1889     return TRUE;
1890 }
1891 
1892 // Using this function you can collapse several tag entries to the same block in the profile
1893 cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest)
1894 {
1895     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
1896     int i;
1897 
1898      if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE;
1899 
1900     if (!_cmsNewTag(Icc, sig, &i)) {
1901         _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1902         return FALSE;
1903     }
1904 
1905     // Keep necessary information
1906     Icc ->TagSaveAsRaw[i] = FALSE;




  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 // This file is available under and governed by the GNU General Public
  26 // License version 2 only, as published by the Free Software Foundation.
  27 // However, the following notice accompanied the original version of this
  28 // file:
  29 //
  30 //---------------------------------------------------------------------------------
  31 //
  32 //  Little Color Management System
  33 //  Copyright (c) 1998-2016 Marti Maria Saguer
  34 //
  35 // Permission is hereby granted, free of charge, to any person obtaining
  36 // a copy of this software and associated documentation files (the "Software"),
  37 // to deal in the Software without restriction, including without limitation
  38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  39 // and/or sell copies of the Software, and to permit persons to whom the Software
  40 // is furnished to do so, subject to the following conditions:
  41 //
  42 // The above copyright notice and this permission notice shall be included in
  43 // all copies or substantial portions of the Software.
  44 //
  45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  52 //
  53 //---------------------------------------------------------------------------------


 336     if (iohandler) _cmsFree(ContextID, iohandler);
 337     return NULL;
 338 }
 339 
 340 // File-based stream -------------------------------------------------------
 341 
 342 // Read count elements of size bytes each. Return number of elements read
 343 static
 344 cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
 345 {
 346     cmsUInt32Number nReaded = (cmsUInt32Number) fread(Buffer, size, count, (FILE*) iohandler->stream);
 347 
 348     if (nReaded != count) {
 349             cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size);
 350             return 0;
 351     }
 352 
 353     return nReaded;
 354 }
 355 
 356 // Position file pointer in the file
 357 static
 358 cmsBool  FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
 359 {
 360     if (fseek((FILE*) iohandler ->stream, (long) offset, SEEK_SET) != 0) {
 361 
 362        cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Seek error; probably corrupted file");
 363        return FALSE;
 364     }
 365 
 366     return TRUE;
 367 }
 368 
 369 // Returns file pointer position
 370 static
 371 cmsUInt32Number FileTell(cmsIOHANDLER* iohandler)
 372 {
 373     return (cmsUInt32Number) ftell((FILE*)iohandler ->stream);
 374 }
 375 
 376 // Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error


 380        if (size == 0) return TRUE;  // We allow to write 0 bytes, but nothing is written
 381 
 382        iohandler->UsedSpace += size;
 383        return (fwrite(Buffer, size, 1, (FILE*) iohandler->stream) == 1);
 384 }
 385 
 386 // Closes the file
 387 static
 388 cmsBool  FileClose(cmsIOHANDLER* iohandler)
 389 {
 390     if (fclose((FILE*) iohandler ->stream) != 0) return FALSE;
 391     _cmsFree(iohandler ->ContextID, iohandler);
 392     return TRUE;
 393 }
 394 
 395 // Create a iohandler for disk based files.
 396 cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode)
 397 {
 398     cmsIOHANDLER* iohandler = NULL;
 399     FILE* fm = NULL;
 400     cmsInt32Number fileLen;
 401 
 402     _cmsAssert(FileName != NULL);
 403     _cmsAssert(AccessMode != NULL);
 404 
 405     iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
 406     if (iohandler == NULL) return NULL;
 407 
 408     switch (*AccessMode) {
 409 
 410     case 'r':
 411         fm = fopen(FileName, "rb");
 412         if (fm == NULL) {
 413             _cmsFree(ContextID, iohandler);
 414              cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName);
 415             return NULL;
 416         }
 417         fileLen = cmsfilelength(fm);
 418         if (fileLen < 0)
 419         {
 420             fclose(fm);
 421             _cmsFree(ContextID, iohandler);
 422             cmsSignalError(ContextID, cmsERROR_FILE, "Cannot get size of file '%s'", FileName);
 423             return NULL;
 424         }
 425 
 426         iohandler -> ReportedSize = (cmsUInt32Number) fileLen;
 427         break;
 428 
 429     case 'w':
 430         fm = fopen(FileName, "wb");
 431         if (fm == NULL) {
 432             _cmsFree(ContextID, iohandler);
 433              cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName);
 434             return NULL;
 435         }
 436         iohandler -> ReportedSize = 0;
 437         break;
 438 
 439     default:
 440         _cmsFree(ContextID, iohandler);
 441          cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode);
 442         return NULL;
 443     }
 444 
 445     iohandler ->ContextID = ContextID;
 446     iohandler ->stream = (void*) fm;
 447     iohandler ->UsedSpace = 0;
 448 
 449     // Keep track of the original file
 450     strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1);
 451     iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0;
 452 
 453     iohandler ->Read    = FileRead;
 454     iohandler ->Seek    = FileSeek;
 455     iohandler ->Close   = FileClose;
 456     iohandler ->Tell    = FileTell;
 457     iohandler ->Write   = FileWrite;
 458 
 459     return iohandler;
 460 }
 461 
 462 // Create a iohandler for stream based files
 463 cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream)
 464 {
 465     cmsIOHANDLER* iohandler = NULL;
 466     cmsInt32Number fileSize;
 467 
 468     fileSize = cmsfilelength(Stream);
 469     if (fileSize < 0)
 470     {
 471         cmsSignalError(ContextID, cmsERROR_FILE, "Cannot get size of stream");
 472         return NULL;
 473     }
 474 
 475     iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
 476     if (iohandler == NULL) return NULL;
 477 
 478     iohandler -> ContextID = ContextID;
 479     iohandler -> stream = (void*) Stream;
 480     iohandler -> UsedSpace = 0;
 481     iohandler -> ReportedSize = (cmsUInt32Number) fileSize;
 482     iohandler -> PhysicalFile[0] = 0;
 483 
 484     iohandler ->Read    = FileRead;
 485     iohandler ->Seek    = FileSeek;
 486     iohandler ->Close   = FileClose;
 487     iohandler ->Tell    = FileTell;
 488     iohandler ->Write   = FileWrite;
 489 
 490     return iohandler;
 491 }
 492 
 493 
 494 
 495 // Close an open IO handler
 496 cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io)
 497 {
 498     return io -> Close(io);
 499 }
 500 
 501 // -------------------------------------------------------------------------------------------------------


 653         _cmsDeleteTagByPos(Icc, i);
 654         *NewPos = i;
 655     }
 656     else  {
 657 
 658         // No, make a new one
 659 
 660         if (Icc -> TagCount >= MAX_TABLE_TAG) {
 661             cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
 662             return FALSE;
 663         }
 664 
 665         *NewPos = Icc ->TagCount;
 666         Icc -> TagCount++;
 667     }
 668 
 669     return TRUE;
 670 }
 671 
 672 
 673 // Check existence
 674 cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig)
 675 {
 676        _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) (void*) hProfile;
 677        return _cmsSearchTag(Icc, sig, FALSE) >= 0;
 678 }
 679 
 680 
 681 
 682 // Enforces that the profile version is per. spec.
 683 // Operates on the big endian bytes from the profile.
 684 // Called before converting to platform endianness.
 685 // Byte 0 is BCD major version, so max 9.
 686 // Byte 1 is 2 BCD digits, one per nibble.
 687 // Reserved bytes 2 & 3 must be 0.
 688 static
 689 cmsUInt32Number _validatedVersion(cmsUInt32Number DWord)
 690 {
 691     cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
 692     cmsUInt8Number temp1;
 693     cmsUInt8Number temp2;


 709 {
 710     cmsTagEntry Tag;
 711     cmsICCHeader Header;
 712     cmsUInt32Number i, j;
 713     cmsUInt32Number HeaderSize;
 714     cmsIOHANDLER* io = Icc ->IOhandler;
 715     cmsUInt32Number TagCount;
 716 
 717 
 718     // Read the header
 719     if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) {
 720         return FALSE;
 721     }
 722 
 723     // Validate file as an ICC profile
 724     if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) {
 725         cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature");
 726         return FALSE;
 727     }
 728 
 729     // Adjust endianness of the used parameters
 730     Icc -> DeviceClass     = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass);
 731     Icc -> ColorSpace      = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.colorSpace);
 732     Icc -> PCS             = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.pcs);
 733 
 734     Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent);
 735     Icc -> flags           = _cmsAdjustEndianess32(Header.flags);
 736     Icc -> manufacturer    = _cmsAdjustEndianess32(Header.manufacturer);
 737     Icc -> model           = _cmsAdjustEndianess32(Header.model);
 738     Icc -> creator         = _cmsAdjustEndianess32(Header.creator);
 739 
 740     _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes);
 741     Icc -> Version         = _cmsAdjustEndianess32(_validatedVersion(Header.version));
 742 
 743     // Get size as reported in header
 744     HeaderSize = _cmsAdjustEndianess32(Header.size);
 745 
 746     // Make sure HeaderSize is lower than profile size
 747     if (HeaderSize >= Icc ->IOhandler ->ReportedSize)
 748             HeaderSize = Icc ->IOhandler ->ReportedSize;
 749 


 827 
 828     Header.flags        = _cmsAdjustEndianess32(Icc -> flags);
 829     Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer);
 830     Header.model        = _cmsAdjustEndianess32(Icc -> model);
 831 
 832     _cmsAdjustEndianess64(&Header.attributes, &Icc -> attributes);
 833 
 834     // Rendering intent in the header (for embedded profiles)
 835     Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent);
 836 
 837     // Illuminant is always D50
 838     Header.illuminant.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->X));
 839     Header.illuminant.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
 840     Header.illuminant.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
 841 
 842     // Created by LittleCMS (that's me!)
 843     Header.creator      = _cmsAdjustEndianess32(lcmsSignature);
 844 
 845     memset(&Header.reserved, 0, sizeof(Header.reserved));
 846 
 847     // Set profile ID. Endianness is always big endian
 848     memmove(&Header.profileID, &Icc ->ProfileID, 16);
 849 
 850     // Dump the header
 851     if (!Icc -> IOhandler->Write(Icc->IOhandler, sizeof(cmsICCHeader), &Header)) return FALSE;
 852 
 853     // Saves Tag directory
 854 
 855     // Get true count
 856     for (i=0;  i < Icc -> TagCount; i++) {
 857         if (Icc ->TagNames[i] != (cmsTagSignature) 0)
 858             Count++;
 859     }
 860 
 861     // Store number of tags
 862     if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE;
 863 
 864     for (i=0; i < Icc -> TagCount; i++) {
 865 
 866         if (Icc ->TagNames[i] == (cmsTagSignature) 0) continue;   // It is just a placeholder
 867 
 868         Tag.sig    = (cmsTagSignature) _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagNames[i]);
 869         Tag.offset = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagOffsets[i]);
 870         Tag.size   = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagSizes[i]);
 871 
 872         if (!Icc ->IOhandler -> Write(Icc-> IOhandler, sizeof(cmsTagEntry), &Tag)) return FALSE;
 873     }
 874 
 875     return TRUE;
 876 }
 877 
 878 // ----------------------------------------------------------------------- Set/Get several struct members
 879 
 880 
 881 cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile)
 882 {
 883     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
 884     return Icc -> RenderingIntent;
 885 }
 886 


1196 
1197 
1198 
1199 // Dump tag contents. If the profile is being modified, untouched tags are copied from FileOrig
1200 static
1201 cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
1202 {
1203     cmsUInt8Number* Data;
1204     cmsUInt32Number i;
1205     cmsUInt32Number Begin;
1206     cmsIOHANDLER* io = Icc ->IOhandler;
1207     cmsTagDescriptor* TagDescriptor;
1208     cmsTagTypeSignature TypeBase;
1209     cmsTagTypeSignature Type;
1210     cmsTagTypeHandler* TypeHandler;
1211     cmsFloat64Number   Version = cmsGetProfileVersion((cmsHPROFILE) Icc);
1212     cmsTagTypeHandler LocalTypeHandler;
1213 
1214     for (i=0; i < Icc -> TagCount; i++) {
1215 
1216         if (Icc ->TagNames[i] == (cmsTagSignature) 0) continue;
1217 
1218         // Linked tags are not written
1219         if (Icc ->TagLinked[i] != (cmsTagSignature) 0) continue;
1220 
1221         Icc -> TagOffsets[i] = Begin = io ->UsedSpace;
1222 
1223         Data = (cmsUInt8Number*)  Icc -> TagPtrs[i];
1224 
1225         if (!Data) {
1226 
1227             // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user.
1228             // In this case a blind copy of the block data is performed
1229             if (FileOrig != NULL && Icc -> TagOffsets[i]) {
1230 
1231                 cmsUInt32Number TagSize   = FileOrig -> TagSizes[i];
1232                 cmsUInt32Number TagOffset = FileOrig -> TagOffsets[i];
1233                 void* Mem;
1234 
1235                 if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE;
1236 


1330 
1331         }
1332     }
1333 
1334     return TRUE;
1335 }
1336 
1337 // Low-level save to IOHANDLER. It returns the number of bytes used to
1338 // store the profile, or zero on error. io may be NULL and in this case
1339 // no data is written--only sizes are calculated
1340 cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io)
1341 {
1342     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
1343     _cmsICCPROFILE Keep;
1344     cmsIOHANDLER* PrevIO = NULL;
1345     cmsUInt32Number UsedSpace;
1346     cmsContext ContextID;
1347 
1348     _cmsAssert(hProfile != NULL);
1349 
1350     if (!_cmsLockMutex(Icc->ContextID, Icc->UsrMutex)) return 0;
1351     memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
1352 
1353     ContextID = cmsGetProfileContextID(hProfile);
1354     PrevIO = Icc ->IOhandler = cmsOpenIOhandlerFromNULL(ContextID);
1355     if (PrevIO == NULL) {
1356         _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex);
1357         return 0;
1358     }
1359 
1360     // Pass #1 does compute offsets
1361 
1362     if (!_cmsWriteHeader(Icc, 0)) goto Error;
1363     if (!SaveTags(Icc, &Keep)) goto Error;
1364 
1365     UsedSpace = PrevIO ->UsedSpace;
1366 
1367     // Pass #2 does save to iohandler
1368 
1369     if (io != NULL) {
1370 
1371         Icc ->IOhandler = io;
1372         if (!SetLinks(Icc)) goto Error;
1373         if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error;
1374         if (!SaveTags(Icc, &Keep)) goto Error;
1375     }
1376 
1377     memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
1378     if (!cmsCloseIOhandler(PrevIO))
1379         UsedSpace = 0; // As a error marker
1380 
1381     _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex);
1382 
1383     return UsedSpace;
1384 
1385 
1386 Error:
1387     cmsCloseIOhandler(PrevIO);
1388     memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
1389     _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex);
1390 
1391     return 0;
1392 }
1393 
1394 
1395 // Low-level save to disk.
1396 cmsBool  CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName)
1397 {
1398     cmsContext ContextID = cmsGetProfileContextID(hProfile);
1399     cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w");
1400     cmsBool rc;
1401 
1402     if (io == NULL) return FALSE;
1403 
1404     rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
1405     rc &= cmsCloseIOhandler(io);
1406 
1407     if (rc == FALSE) {          // remove() is C99 per 7.19.4.1
1408             remove(FileName);   // We have to IGNORE return value in this case
1409     }
1410     return rc;


1574     BaseType = _cmsReadTypeBase(io);
1575     if (BaseType == 0) goto Error;
1576 
1577     if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error;
1578 
1579     TagSize  -= 8;                      // Alredy read by the type base logic
1580 
1581     // Get type handler
1582     TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType);
1583     if (TypeHandler == NULL) goto Error;
1584     LocalTypeHandler = *TypeHandler;
1585 
1586 
1587     // Read the tag
1588     Icc -> TagTypeHandlers[n] = TypeHandler;
1589 
1590     LocalTypeHandler.ContextID = Icc ->ContextID;
1591     LocalTypeHandler.ICCVersion = Icc ->Version;
1592     Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize);
1593 
1594     // The tag type is supported, but something wrong happened and we cannot read the tag.
1595     // let know the user about this (although it is just a warning)
1596     if (Icc -> TagPtrs[n] == NULL) {
1597 
1598         char String[5];
1599 
1600         _cmsTagSignature2String(String, sig);
1601         cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String);
1602         goto Error;
1603     }
1604 
1605     // This is a weird error that may be a symptom of something more serious, the number of
1606     // stored item is actually less than the number of required elements.
1607     if (ElemCount < TagDescriptor ->ElemCount) {
1608 
1609         char String[5];
1610 
1611         _cmsTagSignature2String(String, sig);
1612         cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d",
1613             String, TagDescriptor ->ElemCount, ElemCount);
1614     }


1893 
1894     if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
1895 
1896     if (!_cmsNewTag(Icc, sig, &i)) {
1897         _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1898          return FALSE;
1899     }
1900 
1901     // Mark the tag as being written as RAW
1902     Icc ->TagSaveAsRaw[i] = TRUE;
1903     Icc ->TagNames[i]     = sig;
1904     Icc ->TagLinked[i]    = (cmsTagSignature) 0;
1905 
1906     // Keep a copy of the block
1907     Icc ->TagPtrs[i]  = _cmsDupMem(Icc ->ContextID, data, Size);
1908     Icc ->TagSizes[i] = Size;
1909 
1910     _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1911 
1912     if (Icc->TagPtrs[i] == NULL) {
1913            Icc->TagNames[i] = (cmsTagSignature) 0;
1914            return FALSE;
1915     }
1916     return TRUE;
1917 }
1918 
1919 // Using this function you can collapse several tag entries to the same block in the profile
1920 cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest)
1921 {
1922     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
1923     int i;
1924 
1925      if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE;
1926 
1927     if (!_cmsNewTag(Icc, sig, &i)) {
1928         _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1929         return FALSE;
1930     }
1931 
1932     // Keep necessary information
1933     Icc ->TagSaveAsRaw[i] = FALSE;


< prev index next >