4
votes

I inherited a Delphi application and I know nothing about object pascal.

It's a BPL that I need to compile into the new version of C++ Builder XE.
When I run a make I get the error:

E2064 left side cannot be assigned to.

I've learned enough obj pascal to know I have a constant that is trying to be assigned a value.

But, apparently, you can over ride this behanvior; essentially turning constants into vars by going into Build options under the Delphi compiler and turning on "Assignable Typed constants".

I did that and I continue to get the same error.

I tried surrounding my code with {$J+} and {$J-} and still it will not compile.

procedure TChunkIDAT.CopyInterlacedRGB8(const Pass: Byte;
  Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar );
var
  Col: Integer;
 begin
 {Get first column and enter in loop}
 Col := ColumnStart[Pass];
 Dest := pChar(Longint(Dest) + Col * 3);
 repeat
 {Copy this row}

  Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);

Get the error on last line. If I change the const to a var, I then get the error that the declaration differs from the previous declaration but I have no idea where the previous declaration is....

3
@jachguate target is XE, so it looks like a Unicode issue.Jeroen Wiert Pluimers
I hadn't realized my 38% rate. Thanks for pointing that out, I'll see if I can fix that. It's a package I did not write (3rd party from IOCOMP.com). And it's a 3rd party set of VCL controls used in C++ Builder 6 I'm trying to just compile for CBuilder XE as they don't yet have an XE version of their tools out yet.Eric

3 Answers

9
votes

You're type-casting a two-byte thing (Char) into a one-byte thing (Byte). Reading that value is easy to define, but making that value writable is tricky, probably for the same reason the types of formal and actual "var" parameters need to be identical.

Maybe you wanted to type-cast it to a two-byte thing, such as Word. Or maybe you want GammaTable to be an array of Char so you don't have to type-cast at all. Or maybe, if this code was originally written for a Delphi version earlier than 2009, you want those PChar declarations to be PAnsiChar — character types have gotten wider. Another option is to type-cast Dest to PByte, and then dereference the result. That's probably a bad idea, though, because you'll only be overwriting every other byte of the buffer.

Based on the name of the function, it sounds like PChar was never the right data type to use. That type is for character data, but I think this code is dealing with bytes. The correct thing to do is probably to change PChar to PByte, and then you don't need to type-cast Dest at all.

The $J directive is irrelevant; it controls whether the compiler will allow you to assign values to typed constants. You don't have any of those in this code.

2
votes

The reason is that as of Delphi 2009, Char, PChar, and String are Unicode, and store more than one byte per character.
You should not cast those pointers to bytes, and the compiler prevents you from assigning them if you cast the left side of an assignment to a byte.

This compiles:

procedure CopyInterlacedRGB8(const Pass: Byte; Dest: pAnsiChar); overload;
begin
  Byte(Dest^) := Pass;
end;

This doesn't:

procedure CopyInterlacedRGB8(const Pass: Byte; Dest: pChar); overload;
begin
  Byte(Dest^) := Pass;
end;

Instead of pChar, you should use pByte, which makes the code simpler:

procedure CopyInterlacedRGB8(const Pass: Byte; Dest: PByte); overload;
begin
  Dest^ := Pass;
end;

--jeroen

1
votes

That looks like you're working with Gustavo Daud's TPngImage library. You don't need that code in an external BPL because it's been included in the RTL since D2009. Remove that unit from the BPL and you should be able to get at the updated version via the PngImage unit.