2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 % SSSSS IIIII GGGG N N AAA TTTTT U U RRRR EEEEE %
6 % SS I G NN N A A T U U R R E %
7 % SSS I G GG N N N AAAAA T U U RRRR EEE %
8 % SS I G G N NN A A T U U R R E %
9 % SSSSS IIIII GGG N N A A T UUU R R EEEEE %
12 % MagickCore Methods to Compute a Message Digest for an Image %
19 % Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
20 % dedicated to making software imaging solutions freely available. %
22 % You may not use this file except in compliance with the License. You may %
23 % obtain a copy of the License at %
25 % http://www.imagemagick.org/script/license.php %
27 % Unless required by applicable law or agreed to in writing, software %
28 % distributed under the License is distributed on an "AS IS" BASIS, %
29 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
30 % See the License for the specific language governing permissions and %
31 % limitations under the License. %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "magick/studio.h"
43 #include "magick/cache.h"
44 #include "magick/exception.h"
45 #include "magick/exception-private.h"
46 #include "magick/property.h"
47 #include "magick/image.h"
48 #include "magick/memory_.h"
49 #include "magick/quantum.h"
50 #include "magick/quantum-private.h"
51 #include "magick/signature.h"
52 #include "magick/signature-private.h"
53 #include "magick/string_.h"
57 #define SignatureBlocksize 64
58 #define SignatureDigestsize 32
95 TransformSignature(SignatureInfo *);
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102 + A c q u i r e S i g n a t u r e I n f o %
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108 % AcquireSignatureInfo() allocate the SignatureInfo structure.
110 % The format of the AcquireSignatureInfo method is:
112 % SignatureInfo *AcquireSignatureInfo(void)
115 MagickExport SignatureInfo *AcquireSignatureInfo(void)
123 signature_info=(SignatureInfo *) AcquireMagickMemory(sizeof(*signature_info));
124 if (signature_info == (SignatureInfo *) NULL)
125 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
126 (void) ResetMagickMemory(signature_info,0,sizeof(*signature_info));
127 signature_info->digestsize=SignatureDigestsize;
128 signature_info->blocksize=SignatureBlocksize;
129 signature_info->digest=AcquireStringInfo(SignatureDigestsize);
130 signature_info->message=AcquireStringInfo(SignatureBlocksize);
131 signature_info->accumulator=(unsigned int *) AcquireQuantumMemory(
132 SignatureBlocksize,sizeof(*signature_info->accumulator));
133 if (signature_info->accumulator == (unsigned int *) NULL)
134 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
136 signature_info->lsb_first=(int) (*(char *) &lsb_first) == 1 ? MagickTrue :
138 signature_info->timestamp=(ssize_t) time(0);
139 signature_info->signature=MagickSignature;
140 InitializeSignature(signature_info);
141 return(signature_info);
145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149 + D e s t r o y S i g n a t u r e I n f o %
153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155 % DestroySignatureInfo() zeros memory associated with the SignatureInfo
158 % The format of the DestroySignatureInfo method is:
160 % SignatureInfo *DestroySignatureInfo(SignatureInfo *signature_info)
162 % A description of each parameter follows:
164 % o signature_info: the cipher signature_info.
167 MagickExport SignatureInfo *DestroySignatureInfo(SignatureInfo *signature_info)
169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
170 assert(signature_info != (SignatureInfo *) NULL);
171 assert(signature_info->signature == MagickSignature);
172 if (signature_info->accumulator != (unsigned int *) NULL)
173 signature_info->accumulator=(unsigned int *) RelinquishMagickMemory(
174 signature_info->accumulator);
175 if (signature_info->message != (StringInfo *) NULL)
176 signature_info->message=DestroyStringInfo(signature_info->message);
177 if (signature_info->digest != (StringInfo *) NULL)
178 signature_info->digest=DestroyStringInfo(signature_info->digest);
179 signature_info->signature=(~MagickSignature);
180 signature_info=(SignatureInfo *) RelinquishMagickMemory(signature_info);
181 return(signature_info);
185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189 + F i n a l i z e S i g n a t u r e %
193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195 % FinalizeSignature() finalizes the Signature message accumulator computation.
197 % The format of the FinalizeSignature method is:
199 % FinalizeSignature(SignatureInfo *signature_info)
201 % A description of each parameter follows:
203 % o signature_info: the address of a structure of type SignatureInfo.
206 MagickExport void FinalizeSignature(SignatureInfo *signature_info)
211 register unsigned char
214 register unsigned int
226 Add padding and return the message accumulator.
228 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
229 assert(signature_info != (SignatureInfo *) NULL);
230 assert(signature_info->signature == MagickSignature);
231 low_order=signature_info->low_order;
232 high_order=signature_info->high_order;
233 count=((low_order >> 3) & 0x3f);
234 datum=GetStringInfoDatum(signature_info->message);
235 datum[count++]=(unsigned char) 0x80;
236 if (count <= (unsigned int) (GetStringInfoLength(signature_info->message)-8))
237 (void) ResetMagickMemory(datum+count,0,GetStringInfoLength(
238 signature_info->message)-8-count);
241 (void) ResetMagickMemory(datum+count,0,GetStringInfoLength(
242 signature_info->message)-count);
243 TransformSignature(signature_info);
244 (void) ResetMagickMemory(datum,0,GetStringInfoLength(
245 signature_info->message)-8);
247 datum[56]=(unsigned char) (high_order >> 24);
248 datum[57]=(unsigned char) (high_order >> 16);
249 datum[58]=(unsigned char) (high_order >> 8);
250 datum[59]=(unsigned char) high_order;
251 datum[60]=(unsigned char) (low_order >> 24);
252 datum[61]=(unsigned char) (low_order >> 16);
253 datum[62]=(unsigned char) (low_order >> 8);
254 datum[63]=(unsigned char) low_order;
255 TransformSignature(signature_info);
256 p=signature_info->accumulator;
257 q=GetStringInfoDatum(signature_info->digest);
258 for (i=0; i < (SignatureDigestsize/4); i++)
260 *q++=(unsigned char) ((*p >> 24) & 0xff);
261 *q++=(unsigned char) ((*p >> 16) & 0xff);
262 *q++=(unsigned char) ((*p >> 8) & 0xff);
263 *q++=(unsigned char) (*p & 0xff);
267 Reset working registers.
275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 + G e t S i g n a t u r e B l o c k s i z e %
283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
285 % GetSignatureBlocksize() returns the Signature blocksize.
287 % The format of the GetSignatureBlocksize method is:
289 % unsigned int *GetSignatureBlocksize(const SignatureInfo *signature_info)
291 % A description of each parameter follows:
293 % o signature_info: the signature info.
296 MagickExport unsigned int GetSignatureBlocksize(
297 const SignatureInfo *signature_info)
299 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
300 assert(signature_info != (SignatureInfo *) NULL);
301 assert(signature_info->signature == MagickSignature);
302 return(signature_info->blocksize);
306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310 + G e t S i g n a t u r e D i g e s t %
314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316 % GetSignatureDigest() returns the signature digest.
318 % The format of the GetSignatureDigest method is:
320 % const StringInfo *GetSignatureDigest(const SignatureInfo *signature_info)
322 % A description of each parameter follows:
324 % o signature_info: the signature info.
327 MagickExport const StringInfo *GetSignatureDigest(
328 const SignatureInfo *signature_info)
330 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
331 assert(signature_info != (SignatureInfo *) NULL);
332 assert(signature_info->signature == MagickSignature);
333 return(signature_info->digest);
337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341 + G e t S i g n a t u r e D i g e s t s i z e %
345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 % GetSignatureDigestsize() returns the Signature digest size.
349 % The format of the GetSignatureDigestsize method is:
351 % unsigned int *GetSignatureDigestsize(const SignatureInfo *signature_info)
353 % A description of each parameter follows:
355 % o signature_info: the signature info.
358 MagickExport unsigned int GetSignatureDigestsize(
359 const SignatureInfo *signature_info)
361 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
362 assert(signature_info != (SignatureInfo *) NULL);
363 assert(signature_info->signature == MagickSignature);
364 return(signature_info->digestsize);
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372 + I n i t i a l i z e S i g n a t u r e %
376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378 % IntializeSignature() intializes the Signature accumulator.
380 % The format of the DestroySignatureInfo method is:
382 % void InitializeSignatureInfo(SignatureInfo *signature_info)
384 % A description of each parameter follows:
386 % o signature_info: the cipher signature_info.
389 MagickExport void InitializeSignature(SignatureInfo *signature_info)
391 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
392 assert(signature_info != (SignatureInfo *) NULL);
393 assert(signature_info->signature == MagickSignature);
394 signature_info->accumulator[0]=0x6a09e667U;
395 signature_info->accumulator[1]=0xbb67ae85U;
396 signature_info->accumulator[2]=0x3c6ef372U;
397 signature_info->accumulator[3]=0xa54ff53aU;
398 signature_info->accumulator[4]=0x510e527fU;
399 signature_info->accumulator[5]=0x9b05688cU;
400 signature_info->accumulator[6]=0x1f83d9abU;
401 signature_info->accumulator[7]=0x5be0cd19U;
402 signature_info->low_order=0;
403 signature_info->high_order=0;
404 signature_info->offset=0;
408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412 + S e t S i g n a t u r e D i g e s t %
416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418 % SetSignatureDigest() set the signature digest.
420 % The format of the SetSignatureDigest method is:
422 % SetSignatureDigest(SignatureInfo *signature_info,
423 % const StringInfo *digest)
425 % A description of each parameter follows:
427 % o signature_info: the signature info.
429 % o digest: the digest.
432 MagickExport void SetSignatureDigest(SignatureInfo *signature_info,
433 const StringInfo *digest)
436 Set the signature accumulator.
438 assert(signature_info != (SignatureInfo *) NULL);
439 assert(signature_info->signature == MagickSignature);
440 SetStringInfo(signature_info->digest,digest);
444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448 % S i g n a t u r e I m a g e %
452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454 % SignatureImage() computes a message digest from an image pixel stream with
455 % an implementation of the NIST SHA-256 Message Digest algorithm. This
456 % signature uniquely identifies the image and is convenient for determining
457 % if an image has been modified or whether two images are identical.
459 % The format of the SignatureImage method is:
461 % MagickBooleanType SignatureImage(Image *image)
463 % A description of each parameter follows:
465 % o image: the image.
468 MagickExport MagickBooleanType SignatureImage(Image *image)
488 register const PixelPacket
504 Compute image digital signature.
506 assert(image != (Image *) NULL);
507 assert(image->signature == MagickSignature);
508 if (image->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
510 quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
511 if (quantum_info == (QuantumInfo *) NULL)
512 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
514 quantum_type=RGBQuantum;
515 if (image->matte != MagickFalse)
516 quantum_type=RGBAQuantum;
517 if (image->colorspace == CMYKColorspace)
519 quantum_type=CMYKQuantum;
520 if (image->matte != MagickFalse)
521 quantum_type=CMYKAQuantum;
523 signature_info=AcquireSignatureInfo();
524 signature=AcquireStringInfo(quantum_info->extent);
525 pixels=GetQuantumPixels(quantum_info);
526 exception=(&image->exception);
527 image_view=AcquireCacheView(image);
528 for (y=0; y < (ssize_t) image->rows; y++)
530 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
531 if (p == (const PixelPacket *) NULL)
533 length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
534 pixels,&image->exception);
535 SetStringInfoLength(signature,length);
536 SetStringInfoDatum(signature,pixels);
537 UpdateSignature(signature_info,signature);
539 image_view=DestroyCacheView(image_view);
540 quantum_info=DestroyQuantumInfo(quantum_info);
541 FinalizeSignature(signature_info);
542 hex_signature=StringInfoToHexString(GetSignatureDigest(signature_info));
543 (void) DeleteImageProperty(image,"signature");
544 (void) SetImageProperty(image,"signature",hex_signature);
548 hex_signature=DestroyString(hex_signature);
549 signature=DestroyStringInfo(signature);
550 signature_info=DestroySignatureInfo(signature_info);
555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
559 + T r a n s f o r m S i g n a t u r e %
563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565 % TransformSignature() transforms the Signature message accumulator.
567 % The format of the TransformSignature method is:
569 % TransformSignature(SignatureInfo *signature_info)
571 % A description of each parameter follows:
573 % o signature_info: the address of a structure of type SignatureInfo.
577 static inline unsigned int Ch(unsigned int x,unsigned int y,unsigned int z)
579 return((x & y) ^ (~x & z));
582 static inline unsigned int Maj(unsigned int x,unsigned int y,unsigned int z)
584 return((x & y) ^ (x & z) ^ (y & z));
587 static inline unsigned int Trunc32(unsigned int x)
589 return((unsigned int) (x & 0xffffffffU));
592 static unsigned int RotateRight(unsigned int x,unsigned int n)
594 return(Trunc32((x >> n) | (x << (32-n))));
597 static void TransformSignature(SignatureInfo *signature_info)
599 #define Sigma0(x) (RotateRight(x,7) ^ RotateRight(x,18) ^ Trunc32((x) >> 3))
600 #define Sigma1(x) (RotateRight(x,17) ^ RotateRight(x,19) ^ Trunc32((x) >> 10))
601 #define Suma0(x) (RotateRight(x,2) ^ RotateRight(x,13) ^ RotateRight(x,22))
602 #define Suma1(x) (RotateRight(x,6) ^ RotateRight(x,11) ^ RotateRight(x,25))
610 register unsigned char
616 0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU,
617 0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, 0xd807aa98U, 0x12835b01U,
618 0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U,
619 0xc19bf174U, 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU,
620 0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, 0x983e5152U,
621 0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U,
622 0x06ca6351U, 0x14292967U, 0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU,
623 0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U,
624 0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U,
625 0xd6990624U, 0xf40e3585U, 0x106aa070U, 0x19a4c116U, 0x1e376c08U,
626 0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU,
627 0x682e6ff3U, 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U,
628 0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U
629 }; /* 32-bit fractional part of the cube root of the first 64 primes */
647 p=GetStringInfoDatum(signature_info->message);
648 if (signature_info->lsb_first == MagickFalse)
650 if (sizeof(unsigned int) <= 4)
651 for (i=0; i < 16; i++)
653 T=(*((unsigned int *) p));
658 for (i=0; i < 16; i+=2)
660 T=(*((unsigned int *) p));
662 W[i]=Trunc32(T >> shift);
667 if (sizeof(unsigned int) <= 4)
668 for (i=0; i < 16; i++)
670 T=(*((unsigned int *) p));
672 W[i]=((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
673 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
676 for (i=0; i < 16; i+=2)
678 T=(*((unsigned int *) p));
680 W[i]=((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
681 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
683 W[i+1]=((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
684 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
687 Copy accumulator to registers.
689 A=signature_info->accumulator[0];
690 B=signature_info->accumulator[1];
691 C=signature_info->accumulator[2];
692 D=signature_info->accumulator[3];
693 E=signature_info->accumulator[4];
694 F=signature_info->accumulator[5];
695 G=signature_info->accumulator[6];
696 H=signature_info->accumulator[7];
697 for (i=16; i < 64; i++)
698 W[i]=Trunc32(Sigma1(W[i-2])+W[i-7]+Sigma0(W[i-15])+W[i-16]);
699 for (j=0; j < 64; j++)
701 T1=Trunc32(H+Suma1(E)+Ch(E,F,G)+K[j]+W[j]);
702 T2=Trunc32(Suma0(A)+Maj(A,B,C));
713 Add registers back to accumulator.
715 signature_info->accumulator[0]=Trunc32(signature_info->accumulator[0]+A);
716 signature_info->accumulator[1]=Trunc32(signature_info->accumulator[1]+B);
717 signature_info->accumulator[2]=Trunc32(signature_info->accumulator[2]+C);
718 signature_info->accumulator[3]=Trunc32(signature_info->accumulator[3]+D);
719 signature_info->accumulator[4]=Trunc32(signature_info->accumulator[4]+E);
720 signature_info->accumulator[5]=Trunc32(signature_info->accumulator[5]+F);
721 signature_info->accumulator[6]=Trunc32(signature_info->accumulator[6]+G);
722 signature_info->accumulator[7]=Trunc32(signature_info->accumulator[7]+H);
724 Reset working registers.
737 (void) ResetMagickMemory(W,0,sizeof(W));
741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
745 + U p d a t e S i g n a t u r e %
749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
751 % UpdateSignature() updates the Signature message accumulator.
753 % The format of the UpdateSignature method is:
755 % UpdateSignature(SignatureInfo *signature_info,const StringInfo *message)
757 % A description of each parameter follows:
759 % o signature_info: the address of a structure of type SignatureInfo.
761 % o message: the message.
764 MagickExport void UpdateSignature(SignatureInfo *signature_info,
765 const StringInfo *message)
770 register unsigned char
780 Update the Signature accumulator.
782 assert(signature_info != (SignatureInfo *) NULL);
783 assert(signature_info->signature == MagickSignature);
784 n=GetStringInfoLength(message);
785 length=Trunc32((unsigned int) (signature_info->low_order+(n << 3)));
786 if (length < signature_info->low_order)
787 signature_info->high_order++;
788 signature_info->low_order=length;
789 signature_info->high_order+=(unsigned int) (n >> 29);
790 p=GetStringInfoDatum(message);
791 if (signature_info->offset != 0)
793 i=GetStringInfoLength(signature_info->message)-signature_info->offset;
796 (void) CopyMagickMemory(GetStringInfoDatum(signature_info->message)+
797 signature_info->offset,p,i);
800 signature_info->offset+=i;
801 if (signature_info->offset !=
802 GetStringInfoLength(signature_info->message))
804 TransformSignature(signature_info);
806 while (n >= GetStringInfoLength(signature_info->message))
808 SetStringInfoDatum(signature_info->message,p);
809 p+=GetStringInfoLength(signature_info->message);
810 n-=GetStringInfoLength(signature_info->message);
811 TransformSignature(signature_info);
813 (void) CopyMagickMemory(GetStringInfoDatum(signature_info->message),p,n);
814 signature_info->offset=n;
816 Reset working registers.