src/share/native/sun/java2d/cmm/lcms/LCMS.c
Print this page
@@ -28,10 +28,45 @@
#include "jni_util.h"
#include "Trace.h"
#include "Disposer.h"
#include "lcms.h"
+
+#define ALIGNLONG(x) (((x)+3) & ~(3)) // Aligns to DWORD boundary
+
+#ifdef USE_BIG_ENDIAN
+#define AdjustEndianess32(a)
+#else
+
+static
+void AdjustEndianess32(LPBYTE pByte)
+{
+ BYTE temp1;
+ BYTE temp2;
+
+ temp1 = *pByte++;
+ temp2 = *pByte++;
+ *(pByte-1) = *pByte;
+ *pByte++ = temp2;
+ *(pByte-3) = *pByte;
+ *pByte = temp1;
+}
+
+#endif
+
+// Transports to properly encoded values - note that icc profiles does use
+// big endian notation.
+
+static
+icInt32Number TransportValue32(icInt32Number Value)
+{
+ icInt32Number Temp = Value;
+
+ AdjustEndianess32((LPBYTE) &Temp);
+ return Temp;
+}
+
#define SigMake(a,b,c,d) \
( ( ((int) ((unsigned char) (a))) << 24) | \
( ((int) ((unsigned char) (b))) << 16) | \
( ((int) ((unsigned char) (c))) << 8) | \
(int) ((unsigned char) (d)))
@@ -180,10 +215,12 @@
dataArray = (*env)->GetByteArrayElements (env, data, 0);
dataSize = (*env)->GetArrayLength (env, data);
sProf.pf = cmsOpenProfileFromMem((LPVOID)dataArray, (DWORD) dataSize);
+ (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
+
if (sProf.pf == NULL) {
JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
}
return sProf.j;
@@ -343,11 +380,27 @@
* Signature: (JI[B)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagData
(JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
{
- fprintf(stderr, "setTagData operation is not implemented");
+ cmsHPROFILE profile;
+ storeID_t sProf;
+ jbyte* dataArray;
+ int tagSize;
+
+ if (tagSig == SigHead) {
+ J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_setTagData on icSigHead not "
+ "permitted");
+ return;
+ }
+
+ sProf.j = id;
+ profile = (cmsHPROFILE) sProf.pf;
+ dataArray = (*env)->GetByteArrayElements(env, data, 0);
+ tagSize =(*env)->GetArrayLength(env, data);
+ _cmsModifyTagData(profile, (icTagSignature) tagSig, dataArray, tagSize);
+ (*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
}
void* getILData (JNIEnv *env, jobject img, jint* pDataType,
jobject* pDataObject) {
void* result = NULL;
@@ -505,5 +558,176 @@
IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I");
IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I");
PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J");
}
+
+BOOL _cmsModifyTagData(cmsHPROFILE hProfile, icTagSignature sig,
+ void *data, size_t size)
+{
+ BOOL isNew;
+ int i, idx, delta, count;
+ LPBYTE padChars[3] = {0, 0, 0};
+ LPBYTE beforeBuf, afterBuf, ptr;
+ size_t beforeSize, afterSize;
+ icUInt32Number profileSize, temp;
+ LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
+
+ isNew = FALSE;
+ idx = _cmsSearchTag(Icc, sig, FALSE);
+ if (idx < 0) {
+ isNew = TRUE;
+ idx = Icc->TagCount++;
+ if (Icc->TagCount >= MAX_TABLE_TAG) {
+ J2dRlsTraceLn1(J2D_TRACE_ERROR, "_cmsModifyTagData: Too many tags "
+ "(%d)\n", Icc->TagCount);
+ Icc->TagCount = MAX_TABLE_TAG-1;
+ return FALSE;
+ }
+ }
+
+ /* Read in size from header */
+ Icc->Seek(Icc, 0);
+ Icc->Read(&profileSize, sizeof(icUInt32Number), 1, Icc);
+ AdjustEndianess32((LPBYTE) &profileSize);
+
+ /* Compute the change in profile size */
+ if (isNew) {
+ delta = sizeof(icTag) + ALIGNLONG(size);
+ } else {
+ delta = ALIGNLONG(size) - ALIGNLONG(Icc->TagSizes[idx]);
+ }
+ /* Add tag to internal structures */
+ ptr = malloc(size);
+ if (ptr == NULL) {
+ if(isNew) {
+ Icc->TagCount--;
+ }
+ J2dRlsTraceLn(J2D_TRACE_ERROR, "_cmsModifyTagData: ptr == NULL");
+ return FALSE;
+ }
+
+ if (!Icc->Grow(Icc, delta)) {
+ free(ptr);
+ if(isNew) {
+ Icc->TagCount--;
+ }
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "_cmsModifyTagData: Icc->Grow() == FALSE");
+ return FALSE;
+ }
+
+ /* Compute size of tag data before/after the modified tag */
+ beforeSize = ((isNew)?profileSize:Icc->TagOffsets[idx]) -
+ Icc->TagOffsets[0];
+ if (Icc->TagCount == (idx + 1)) {
+ afterSize = 0;
+ } else {
+ afterSize = profileSize - Icc->TagOffsets[idx+1];
+ }
+ /* Make copies of the data before/after the modified tag */
+ if (beforeSize > 0) {
+ beforeBuf = malloc(beforeSize);
+ if (!beforeBuf) {
+ if(isNew) {
+ Icc->TagCount--;
+ }
+ free(ptr);
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "_cmsModifyTagData: beforeBuf == NULL");
+ return FALSE;
+ }
+ Icc->Seek(Icc, Icc->TagOffsets[0]);
+ Icc->Read(beforeBuf, beforeSize, 1, Icc);
+ }
+
+ if (afterSize > 0) {
+ afterBuf = malloc(afterSize);
+ if (!afterBuf) {
+ free(ptr);
+ if(isNew) {
+ Icc->TagCount--;
+ }
+ if (beforeSize > 0) {
+ free(beforeBuf);
+ }
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "_cmsModifyTagData: afterBuf == NULL");
+ return FALSE;
+ }
+ Icc->Seek(Icc, Icc->TagOffsets[idx+1]);
+ Icc->Read(afterBuf, afterSize, 1, Icc);
+ }
+
+ CopyMemory(ptr, data, size);
+ Icc->TagSizes[idx] = size;
+ Icc->TagNames[idx] = sig;
+ if (Icc->TagPtrs[idx]) {
+ free(Icc->TagPtrs[idx]);
+ }
+ Icc->TagPtrs[idx] = ptr;
+ if (isNew) {
+ Icc->TagOffsets[idx] = profileSize;
+ }
+
+
+ /* Update the profile size in the header */
+ profileSize += delta;
+ Icc->Seek(Icc, 0);
+ temp = TransportValue32(profileSize);
+ Icc->Write(Icc, sizeof(icUInt32Number), &temp);
+
+
+ /* Adjust tag offsets: if the tag is new, we must account
+ for the new tag table entry; otherwise, only those tags after
+ the modified tag are changed (by delta) */
+ if (isNew) {
+ for (i = 0; i < Icc->TagCount; ++i) {
+ Icc->TagOffsets[i] += sizeof(icTag);
+ }
+ } else {
+ for (i = idx+1; i < Icc->TagCount; ++i) {
+ Icc->TagOffsets[i] += delta;
+ }
+ }
+
+ /* Write out a new tag table */
+ count = 0;
+ for (i = 0; i < Icc->TagCount; ++i) {
+ if (Icc->TagNames[i] != 0) {
+ ++count;
+ }
+ }
+ Icc->Seek(Icc, sizeof(icHeader));
+ temp = TransportValue32(count);
+ Icc->Write(Icc, sizeof(icUInt32Number), &temp);
+
+ for (i = 0; i < Icc->TagCount; ++i) {
+ if (Icc->TagNames[i] != 0) {
+ icTag tag;
+ tag.sig = TransportValue32(Icc->TagNames[i]);
+ tag.offset = TransportValue32((icInt32Number) Icc->TagOffsets[i]);
+ tag.size = TransportValue32((icInt32Number) Icc->TagSizes[i]);
+ Icc->Write(Icc, sizeof(icTag), &tag);
+ }
+ }
+
+ /* Write unchanged data before the modified tag */
+ if (beforeSize > 0) {
+ Icc->Write(Icc, beforeSize, beforeBuf);
+ free(beforeBuf);
+ }
+
+ /* Write modified tag data */
+ Icc->Write(Icc, size, data);
+ if (size % 4) {
+ Icc->Write(Icc, 4 - (size % 4), padChars);
+ }
+
+ /* Write unchanged data after the modified tag */
+ if (afterSize > 0) {
+ Icc->Write(Icc, afterSize, afterBuf);
+ free(afterBuf);
+ }
+
+ return TRUE;
+}