Memptr.java
/*
** Module : Memptr.java
** Abstract : Implementation of the builtin class OpenEdge.Core.Memptr.
**
** Copyright (c) 2019-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD.
** 002 CA 20190710 First pass at runtime implementation; _Debug and GetHash are still stubs.
** Codepage support is not implemented.
** 003 CA 20191024 Added method support levels and updated the class support level.
** 004 ME 20200331 Fix constructors, add setters and validate input parameters for get methods.
** GES 20200526 Change to match legacy enum implementation.
** 005 CA 20210113 Renamed clear() to clear_(), to follow NameConverter's rules.
** ME 20210204 The class implements ImemptrHolder.
** 006 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy
** signature.
** CA 20220923 Variable definitions (including associated with parameters) must be done always outside of
** the BlockManager API
** 007 CA 20231019 All BlockManager calls must have a non-null referent.
** 008 CA 20231113 The 'execute' method must be annotated with LegacySignature Type.Execute, and also can be
** dropped if is a no-op.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.oo.core;
import com.goldencode.p2j.util.*;
import com.goldencode.p2j.util.BlockManager.Action;
import com.goldencode.p2j.util.BlockManager.Condition;
import com.goldencode.p2j.util.InternalEntry.Type;
import com.goldencode.p2j.oo.common.support.ImemptrHolder;
import com.goldencode.p2j.oo.lang.*;
import java.io.IOException;
import static com.goldencode.p2j.util.MathOps.*;
import static com.goldencode.p2j.util.BlockManager.*;
import static com.goldencode.p2j.report.ReportConstants.*;
/**
* Business logic (converted to Java from the 4GL source code
* in OpenEdge/Core/Memptr.cls).
*/
@LegacyResource(resource = "OpenEdge.Core.Memptr")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_PARTIAL)
public class Memptr extends BaseObject implements ImemptrHolder
{
private logical autoDestroy = TypeFactory.logical();
private logical externalAllocation = TypeFactory.logical();
private memptr value = TypeFactory.memptr();
@LegacySignature(type = Type.EXECUTE)
public void __core_Memptr_execute__()
{
onBlockLevel(Condition.ERROR, Action.THROW);
}
@LegacySignature(returns = "LOGICAL", type = Type.GETTER, name = "AutoDestroy")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public logical getAutoDestroy()
{
return function(this, "AutoDestroy", logical.class, new Block((Body) () ->
{
returnNormal(autoDestroy);
}));
}
/**
* Set auto destroy.
*
* @param _autodestroy
* destroy flag
*/
@LegacySignature(type = Type.SETTER, name = "AutoDestroy", parameters = {
@LegacyParameter(name = "autodestroy", type = "LOGICAL", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void setAutoDestroy(logical _autodestroy)
{
logical autodestroy = TypeFactory.initInput(_autodestroy);
internalProcedure(this, "AutoDestroy", new Block((Body) () ->
{
this.autoDestroy.assign(autodestroy);
}));
}
@LegacySignature(returns = "OBJECT", qualified = "OpenEdge.Core.Memptr", type = Type.GETTER, name = "Empty")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public static object<? extends Memptr> getEmpty()
{
ObjectOps.load(Memptr.class);
return function(Memptr.class, "Empty", object.class, new Block((Body) () ->
{
returnNormal(ObjectOps.newInstance(Memptr.class, "I", new int64(0)));
}));
}
@LegacySignature(returns = "LOGICAL", type = Type.GETTER, name = "ExternalAllocation")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public logical getExternalAllocation()
{
return function(this, "ExternalAllocation", logical.class, new Block((Body) () ->
{
returnNormal(externalAllocation);
}));
}
@LegacySignature(returns = "INT64", type = Type.GETTER, name = "Size")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public int64 getSize()
{
return function(this, "Size", int64.class, new Block((Body) () ->
{
returnNormal(BinaryData.length(value));
}));
}
/**
* Set size.
*
* @param _size
* The new size.
*/
@LegacySignature(type = Type.SETTER, name = "Size", parameters = {
@LegacyParameter(name = "size", type = "INT64", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void setSize(int64 _size)
{
int64 size = TypeFactory.initInput(_size);
internalProcedure(this, "Size", new Block((Body) () ->
{
if (this.getSize().longValue() == 0)
this.value.setLength(size);
}));
}
@LegacySignature(returns = "MEMPTR", type = Type.GETTER, name = "Value")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public memptr getValue()
{
// return the actual memptr reference, returnNormal is making a deep copy
return value;
}
@LegacySignature(type = Type.CONSTRUCTOR)
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public static void __core_Memptr_constructor__static__()
{
externalProcedure(Memptr.class, new Block((Body) () ->
{
onBlockLevel(Condition.ERROR, Action.THROW);
}));
}
@LegacySignature(type = Type.CONSTRUCTOR)
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void __core_Memptr_constructor__()
{
internalProcedure(this, "__core_Memptr_constructor__", new Block((Body) () ->
{
__lang_BaseObject_constructor__();
this.externalAllocation.assign(false);
this.autoDestroy.assign(true);
}));
}
@LegacySignature(type = Type.CONSTRUCTOR, parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void __core_Memptr_constructor__(final int64 _p1)
{
int64 p1 = TypeFactory.initInput(_p1);
internalProcedure(this, "__core_Memptr_constructor__", new Block((Body) () ->
{
Assert.isZeroOrPositive(p1, new character("Size"));
__core_Memptr_constructor__();
this.value.setLength(p1);
}));
}
@LegacySignature(type = Type.CONSTRUCTOR, parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT"),
@LegacyParameter(name = "p2", type = "INT64", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void __core_Memptr_constructor__(final int64 _p1, final int64 _p2)
{
int64 p1 = TypeFactory.initInput(_p1);
int64 p2 = TypeFactory.initInput(_p2);
internalProcedure(this, "__core_Memptr_constructor__", new Block((Body) () ->
{
Assert.isZeroOrPositive(p2, new character("Size"));
__core_Memptr_constructor__();
this.value.setPointerValue(p1);
this.value.setLength(p2);
this.externalAllocation.assign(true);
}));
}
@LegacySignature(type = Type.CONSTRUCTOR, parameters = {
@LegacyParameter(name = "p1", type = "MEMPTR", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void __core_Memptr_constructor__(final memptr _p1)
{
memptr p1 = TypeFactory.initInput(_p1);
internalProcedure(this, "__core_Memptr_constructor__", new Block((Body) () ->
{
__core_Memptr_constructor__(BinaryData.length(p1));
this.value.assign(p1);
}));
}
@LegacySignature(type = Type.CONSTRUCTOR, parameters = {
@LegacyParameter(name = "p1", type = "RAW", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void __core_Memptr_constructor__(final raw _p1)
{
raw p1 = TypeFactory.initInput(_p1);
internalProcedure(this, "__core_Memptr_constructor__", new Block((Body) () ->
{
__core_Memptr_constructor__(BinaryData.length(p1));
this.value.assign(p1);
}));
}
/**
* Destructor for this class. Cleanup/delete any created resources.
*/
@LegacySignature(type = Type.DESTRUCTOR)
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void __core_Memptr_destructor__()
{
internalProcedure(this, "__core_Memptr_destructor__", new Block((Body) () ->
{
if (!value.isUnknown() && autoDestroy.booleanValue())
{
if (externalAllocation.booleanValue())
value.setPointerValue(0);
if (BinaryData.length(value).longValue() > 0)
value.setLength(0);
}
}));
}
@LegacySignature(type = Type.METHOD, name = "_Debug")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB)
public void debug_1()
{
internalProcedure(this, "_Debug", new Block((Body) () ->
{
String debugFile = EnvironmentOps.getTempDirectory().getValue()
+ toLegacyString().getValue() + ".bin";
FileStream fs = null;
try
{
fs = new FileStream(debugFile, true, false);
for (long i = 1; i <= this.value.length().longValue(); i++)
{
long bit = this.value.getByte(i).longValue();
String line = String.valueOf(bit) + "\t";
if (bit != 10 && bit != 13)
line += "\t\t" + character.chr(bit).getValue();
fs.write(line + Stream.NEWLINE);
}
} catch (IOException e) {
// TODO: this should probably be handled in FileStream anyway
} finally {
fs.close();
}
}));
}
@LegacySignature(type = Type.METHOD, name = "Clear")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void clear_()
{
internalProcedure(this, "Clear", new Block((Body) () ->
{
if (!externalAllocation.booleanValue())
{
int64 size = this.value.length();
if (size.longValue() > 0)
{
this.value.setLength(0);
this.value.setLength(size);
}
}
}));
}
@LegacySignature(returns = "INTEGER", type = Type.METHOD, name = "GetByte", parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public integer getByte(final int64 _p1)
{
int64 p1 = TypeFactory.initInput(_p1);
return function(this, "GetByte", integer.class, new Block((Body) () ->
{
Assert.isPositive(p1, new character("Position"));
returnNormal(this.value.getByte(p1));
}));
}
@LegacySignature(returns = "OBJECT", type = Type.METHOD, name = "GetBytes", qualified = "openedge.core.memptr", parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public object<? extends com.goldencode.p2j.oo.core.Memptr> getBytes(final int64 _p1)
{
int64 p1 = TypeFactory.initInput(_p1);
return function(this, "GetBytes", object.class, new Block((Body) () ->
{
Assert.isPositive(p1, new character("Start position"));
returnNormal(getBytes(p1, minus(getSize(), p1)));
}));
}
@LegacySignature(returns = "OBJECT", type = Type.METHOD, name = "GetBytes", qualified = "openedge.core.memptr", parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT"),
@LegacyParameter(name = "p2", type = "INT64", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public object<? extends com.goldencode.p2j.oo.core.Memptr> getBytes(final int64 _p1,
final int64 _p2)
{
int64 p1 = TypeFactory.initInput(_p1);
int64 p2 = TypeFactory.initInput(_p2);
memptr mpData = TypeFactory.memptr();
return function(this, "GetBytes", object.class, new Block((Body) () ->
{
Assert.isPositive(p1, new character("Start position"));
Assert.isPositive(p2, new character("Slice size"));
if (getSize().intValue() == 0)
returnNormal(getEmpty());
else
{
mpData.assign(this.value.getBytes(p1, p2));
returnNormal(ObjectOps.newInstance(Memptr.class, "I", mpData));
}
}, (Fini) () ->
{
mpData.setLength(0);
}));
}
@LegacySignature(returns = "RAW", type = Type.METHOD, name = "GetHash")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB)
public raw getHash()
{
return function(this, "GetHash", raw.class, new Block((Body) () ->
{
returnNormal(getHash(HashAlgorithmEnum.md5));
}));
}
@LegacySignature(returns = "RAW", type = Type.METHOD, name = "GetHash", parameters = {
@LegacyParameter(name = "p1", type = "OBJECT", qualified = "openedge.core.hashalgorithmenum", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB)
public raw getHash(final object<? extends HashAlgorithmEnum> _p1)
{
Assert.notNull(_p1, new character("Algorithm"));
object<? extends HashAlgorithmEnum> p1 = TypeFactory
.initInput(_p1);
return function(this, "GetHash", raw.class, new Block((Body) () ->
{
returnNormal(SecurityOps.messageDigest(p1.ref().toLegacyString(), value));
}));
}
@LegacySignature(returns = "INT64", type = Type.METHOD, name = "GetPointerValue")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public int64 getPointerValue()
{
return function(this, "GetPointerValue", int64.class, new Block((Body) () ->
{
returnNormal(this.value.getPointerValue());
}));
}
@LegacySignature(returns = "LONGCHAR", type = Type.METHOD, name = "GetString", parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public longchar getString(final int64 _p1)
{
return getString(_p1, plus(minus(getSize(), _p1), 1));
}
@LegacySignature(returns = "LONGCHAR", type = Type.METHOD, name = "GetString", parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT"),
@LegacyParameter(name = "p2", type = "INT64", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public longchar getString(final int64 _p1, final int64 _p2)
{
return getString(_p1, _p2, I18nOps.getCPInternal(), new character("UTF-8"));
}
@LegacySignature(returns = "LONGCHAR", type = Type.METHOD, name = "GetString", parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT"),
@LegacyParameter(name = "p2", type = "INT64", mode = "INPUT"),
@LegacyParameter(name = "p3", type = "CHARACTER", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_BASIC)
public longchar getString(final int64 _p1, final int64 _p2, final character _p3)
{
return getString(_p1, _p2, I18nOps.getCPInternal(), _p3);
}
@LegacySignature(returns = "LONGCHAR", type = Type.METHOD, name = "GetString", parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT"),
@LegacyParameter(name = "p2", type = "INT64", mode = "INPUT"),
@LegacyParameter(name = "p3", type = "CHARACTER", mode = "INPUT"),
@LegacyParameter(name = "p4", type = "CHARACTER", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_BASIC)
public longchar getString(final int64 _p1, final int64 _p2, final character _p3,
final character _p4)
{
int64 startPos = TypeFactory.initInput(_p1);
int64 sliceSize = TypeFactory.initInput(_p2);
character sourceCodepage = TypeFactory.initInput(_p3);
character targetCodepage = TypeFactory.initInput(_p4);
longchar ch = TypeFactory.longchar();
return function(this, "GetString", longchar.class, new Block((Body) () ->
{
Assert.isPositive(startPos, new character("Start position"));
Assert.isZeroOrPositive(sliceSize, new character("Slice size"));
Assert.notNullOrEmpty(sourceCodepage, new character("Source codepage"));
Assert.notNullOrEmpty(targetCodepage, new character("Target codepage"));
// if length is zero the code page is not set - empty string but still copy-lob validation take place
if (sliceSize.longValue() > 0)
ch.fixCodePage(targetCodepage);
new LobCopy(new SourceLob(this.value).length(sliceSize).offset(startPos),
new TargetLob(ch)).targetCodePage(targetCodepage).sourceCodePage(sourceCodepage)
.run();
returnNormal(ch);
}));
}
@LegacySignature(type = Type.METHOD, name = "PutBytes", parameters = {
@LegacyParameter(name = "p1", type = "INT64", mode = "INPUT"),
@LegacyParameter(name = "p2", type = "INT64", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void putBytes(final int64 _p1, final int64 _p2)
{
int64 p1 = TypeFactory.initInput(_p1);
int64 p2 = TypeFactory.initInput(_p2);
memptr mtemp = TypeFactory.memptr();
internalProcedure(this, "PutBytes", new Block((Body) () ->
{
Assert.isZeroOrPositive(p1, new character("Pointer"));
Assert.isZeroOrPositive(p2, new character("Size"));
long size = getSize().longValue();
if (size != 0 && p2.longValue() > size)
{
undoThrowTopLevel(AppError.newInstance("Input memptr larger than available size", 0));
}
else
{
try
{
if (size == 0)
{
setSize(p2);
}
mtemp.setPointerValue(p1.longValue());
mtemp.setLength(p2);
this.value.setBytes(mtemp, 1);
}
finally
{
mtemp.setPointerValue(0);
if (mtemp.length().longValue() > 0)
mtemp.setLength(0);
}
}
}));
}
@LegacySignature(type = Type.METHOD, name = "PutBytes", parameters = {
@LegacyParameter(name = "p1", type = "MEMPTR", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void putBytes(final memptr _p1)
{
putBytes(_p1.getPointerValue(), _p1.length());
}
@LegacySignature(type = Type.METHOD, name = "PutBytes", parameters = {
@LegacyParameter(name = "p1", type = "RAW", mode = "INPUT") })
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
public void putBytes(final raw _p1)
{
raw p1 = TypeFactory.initInput(_p1);
memptr mptemp = TypeFactory.memptr();
internalProcedure(this, "PutBytes", new Block((Body) () ->
{
try
{
mptemp.setLength(p1.length());
mptemp.setBytes(p1, 1);
putBytes(mptemp.getPointerValue(), mptemp.length());
}
finally
{
if (mptemp.length().longValue() > 0)
mptemp.setLength(0);
}
}));
}
@LegacySignature(returns = "CHARACTER", type = Type.METHOD, name = "ToString")
@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
@Override
public character toLegacyString()
{
return TextOps.substitute("OpenEdge.Core.Memptr_&1", this.value.getPointerValue());
}
}