### Write and read AFP with AfpOutputStream and AfpInputStream
Source: https://github.com/yan74/afplib/wiki/Hello-World-Example
This Java example shows how to create an AFP file by writing a BDT and EDT structured field, then read it back to verify the document name and comment. It uses try-with-resources for proper stream handling and prints the read values to the console.
```java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.afplib.afplib.AfplibFactory;
import org.afplib.afplib.BDT;
import org.afplib.afplib.Comment;
import org.afplib.afplib.EDT;
import org.afplib.io.AfpInputStream;
import org.afplib.io.AfpOutputStream;
public class HelloWorld {
public static void main(String[] args) {
try (AfpOutputStream aout = new AfpOutputStream(new FileOutputStream("hello.afp"))) {
BDT bdt = AfplibFactory.eINSTANCE.createBDT();
bdt.setDocName("HELLOWLD");
Comment comment = AfplibFactory.eINSTANCE.createComment();
comment.setComment("My first AFPLib Program");
bdt.getTriplets().add(comment);
aout.writeStructuredField(bdt);
EDT edt = AfplibFactory.eINSTANCE.createEDT();
edt.setDocName("HELLOWLD");
aout.writeStructuredField(edt);
} catch (IOException e) {
e.printStackTrace();
}
try(AfpInputStream ain = new AfpInputStream(new FileInputStream("hello.afp"))) {
BDT bdt = (BDT) ain.readStructuredField();
EDT edt = (EDT) ain.readStructuredField();
System.out.println(bdt.getDocName());
System.out.println(bdt.getReserved());
System.out.println(bdt.getTriplets().size());
System.out.println(((Comment)bdt.getTriplets().get(0)).getComment());
System.out.println(edt.getDocName());
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
--------------------------------
### Find medium maps by name, bin, or media name
Source: https://github.com/yan74/afplib/blob/master/org.afplib/src/main/java/org/afplib/helper/formdef/package.html
Shows how to retrieve MediumMap objects from a Formdef using findByName, findFirstByBin, and findFirstByMediaName, and how to get all medium maps with mediumMaps(). The example uses Plex.DUPLEX for the media name lookup.
```java
MediumMap map = formdef.findByName("MM000000");
map = formdef.findFirstByBin(1);
map = formdef.findFirstByMediaName("A108", Plex.DUPLEX);
MediumMap[] maps = formdef.mediumMaps();
```
--------------------------------
### Read AFP binary data
Source: https://github.com/yan74/afplib/blob/master/README.md
Example of reading an AFP file using AfpInputStream and accessing the parsed structured fields.
```java
try(AfpInputStream ain = new AfpInputStream(new FileInputStream("hello.afp"))) {
BDT bdt = (BDT) ain.readStructuredField();
EDT edt = (EDT) ain.readStructuredField();
System.out.println(bdt.getDocName());
System.out.println(bdt.getReserved());
System.out.println(bdt.getTriplets().size());
System.out.println(((Comment)bdt.getTriplets().get(0)).getComment());
System.out.println(edt.getDocName());
} catch (IOException e) {
e.printStackTrace();
}
```
--------------------------------
### Anonymizer example using AfpFilter
Source: https://github.com/yan74/afplib/wiki/Create-an-AFP-Filter
Shows how to use AfpFilter.filter with a custom Filter implementation to anonymize TRN triplets in PTX structured fields. It reads from an input file and writes to an output file, returning MODIFIED when changes are made and UNTOUCHED otherwise.
```java
public static void main(String[] args) {
try (AfpInputStream in = new AfpInputStream(
new BufferedInputStream(new FileInputStream(args[0])));
AfpOutputStream out = new AfpOutputStream(
new BufferedOutputStream(new FileOutputStream(args[1])))) {
AfpFilter.filter(in, out, new Filter() {
@Override
public STATE onStructuredField(SF sf) {
switch(sf.getId()) {
case SFName.PTX_VALUE:
PTX ptx = (PTX) sf;
for(Triplet t : ptx.getCS()) {
if(t instanceof TRN) {
anonymize((TRN) t);
}
}
return STATE.MODIFIED;
}
return STATE.UNTOUCHED;
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
```
--------------------------------
### Scan formdef from AFP input stream
Source: https://github.com/yan74/afplib/blob/master/org.afplib/src/main/java/org/afplib/helper/formdef/package.html
Use FormdefScanner.scan() to read a Formdef object from an AfpInputStream. The example wraps a FileInputStream in an AfpInputStream and uses try-with-resources to ensure the stream is closed.
```java
try(AfpInputStream ain = new AfpInputStream(new FileInputStream(file))) {
Formdef formdef = FormdefScanner.scan(ain);
}
```
--------------------------------
### Run PDF2Overlay sample
Source: https://github.com/yan74/afplib/wiki/Samples
Command-line invocation for the PDF2Overlay sample. It converts a PDF file into an AFP object container resource. The command assumes the sample jar is built and the input PDF exists.
```bash
java -cp target/samples-0.0.8-SNAPSHOT-jar-with-dependencies.jar org.afplib.samples.PDF2Overlay testdata/mushrooms.pdf tmp/O1MUSHRO
```
--------------------------------
### Maven POM for afplib HelloWorld sample
Source: https://github.com/yan74/afplib/wiki/Installation
Use this POM file to set up a Maven project with afplib version 0.0.14 and the required Eclipse Modeling Framework dependencies (ecore, common, ecore.xmi). It configures the compiler to Java 1.7 and sets the source directory to 'src'.
```xml
4.0.0org.afplib.samplesHelloWorld0.0.1-SNAPSHOTorg.afplibafplib0.0.14org.eclipse.emforg.eclipse.emf.ecore2.10.1org.eclipse.emforg.eclipse.emf.common2.10.1org.eclipse.emforg.eclipse.emf.ecore.xmi2.10.1srcmaven-compiler-plugin3.11.71.7
```
--------------------------------
### Maven pom.xml for AFPLib HelloWorld
Source: https://github.com/yan74/afplib/blob/master/org.afplib/docs/getStarted.txt
Maven project configuration with dependencies on afplib and Eclipse EMF libraries. Sets source and target to Java 1.7.
```xml
4.0.0org.afplib.samplesHelloWorld0.0.1-SNAPSHOTorg.afplibafplib0.0.9org.eclipse.emforg.eclipse.emf.ecore2.10.1org.eclipse.emforg.eclipse.emf.common2.10.1org.eclipse.emforg.eclipse.emf.ecore.xmi2.10.1srcmaven-compiler-plugin3.11.71.7
```
--------------------------------
### Run AfpCombine with debug logging and sample AFP files
Source: https://github.com/yan74/afplib/wiki/Samples
Command to run the AfpCombine sample with debug logging enabled, using all .afp files in testdata as input and writing the combined output to tmp/out.afp. The output shows the detection of resource name conflicts (e.g., O1VORNAL and MM000000) and the renaming of resources to resolve them.
```bash
java -Dlog4j.configuration=debug.properties -cp target/samples-0.0.8-SNAPSHOT-jar-with-dependencies.jar org.afplib.samples.AfpCombine testdata/*.afp -o tmp/out.afp
20.07.2015 16:20:36.167 INFO - starting...
20.07.2015 16:20:36.172 DEBUG - in: testdata/ende.afp:testdata/start.afp
20.07.2015 16:20:36.173 DEBUG - out: tmp/out.afp
20.07.2015 16:20:36.332 DEBUG - processing formdef
20.07.2015 16:20:36.335 DEBUG - testdata/ende.afp: found medium map MM000000
20.07.2015 16:20:36.338 DEBUG - testdata/ende.afp@118-227: found MM000000, hash 7a2ab1111745f6dc63b6ddee8fd451
20.07.2015 16:20:36.349 DEBUG - testdata/ende.afp@253-824: found ResourceKey [type=252, name=O1VORNAL, objId=null], hash 687cb2c2ff6aadf6f28fbe9efc390d9
20.07.2015 16:20:36.360 DEBUG - testdata/ende.afp@824-368200: found ResourceKey [type=146, name=Arial Regular, objId=06072b12000401013300000000000000], hash ef198ff8655f9b7987b728e288b17bfe
20.07.2015 16:20:36.361 DEBUG - processing formdef
20.07.2015 16:20:36.362 DEBUG - testdata/start.afp: found medium map MM000000
20.07.2015 16:20:36.362 DEBUG - testdata/start.afp@118-235: found MM000000, hash dfb570f28067e1b47bc28221ea682521
20.07.2015 16:20:36.363 DEBUG - testdata/start.afp@261-848: found ResourceKey [type=252, name=O1VORNAL, objId=null], hash 9d43ea8bcd9ca862d0a4f65b4fd43
20.07.2015 16:20:36.366 DEBUG - testdata/start.afp@848-368224: found ResourceKey [type=146, name=Arial Regular, objId=06072b12000401013300000000000000], hash ef198ff8655f9b7987b728e288b17bfe
20.07.2015 16:20:36.366 DEBUG - comparing resources in ende.afp and start.afp
20.07.2015 16:20:36.367 DEBUG - start.afp: renaming resource O1VORNAL to O19D43EA
20.07.2015 16:20:36.370 DEBUG - resource Arial Regular is same in ende.afp and start.afp
20.07.2015 16:20:36.370 DEBUG - start.afp: renaming medium map MM000000 to MM7A2AB1
20.07.2015 16:20:36.370 DEBUG - writing medium map MM000000 from ende.afp
20.07.2015 16:20:36.371 DEBUG - writing medium map MM000000 as MM7A2AB1 from start.afp
20.07.2015 16:20:36.839 INFO - writing resource group
20.07.2015 16:20:36.845 DEBUG - writing resource O1VORNAL from ende.afp
20.07.2015 16:20:36.846 DEBUG - writing resource Arial Regular from ende.afp
20.07.2015 16:20:36.857 DEBUG - writing resource O1VORNAL as O19D43EA from start.afp
20.07.2015 16:20:36.858 DEBUG - not writing resource Arial Regular again
20.07.2015 16:20:36.869 INFO - writing documents from ende.afp
20.07.2015 16:20:36.894 INFO - writing documents from start.afp
20.07.2015 16:20:36.906 INFO - done.
```
--------------------------------
### HelloWorld.java using AfpOutputStream
Source: https://github.com/yan74/afplib/blob/master/org.afplib/docs/getStarted.txt
Java application that creates an AFP file with BDT and EDT structured fields. Uses try-with-resources and writes a comment triplet.
```java
import java.io.FileOutputStream;
import java.io.IOException;
import org.afplib.afplib.AfplibFactory;
import org.afplib.afplib.BDT;
import org.afplib.afplib.Comment;
import org.afplib.afplib.EDT;
import org.afplib.io.AfpOutputStream;
public class HelloWorld {
public static void main(String[] args) {
try (AfpOutputStream aout = new AfpOutputStream(new FileOutputStream("hello.afp"))) {
BDT bdt = AfplibFactory.eINSTANCE.createBDT();
bdt.setDocName("HELLOWLD");
Comment comment = AfplibFactory.eINSTANCE.createComment();
comment.setComment("My first AFPLib Program");
bdt.getTriplets().add(comment);
aout.writeStructuredField(bdt);
EDT edt = AfplibFactory.eINSTANCE.createEDT();
edt.setDocName("HELLOWLD");
aout.writeStructuredField(edt);
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
--------------------------------
### Maven pom.xml configuration
Source: https://github.com/yan74/afplib/blob/master/README.md
The required dependencies and build configuration for a new Maven project using AFPLib.
```xml
4.0.0org.afplib.samplesHelloWorld0.0.1-SNAPSHOTorg.afplibafplib0.0.14org.eclipse.emforg.eclipse.emf.ecore2.10.1org.eclipse.emforg.eclipse.emf.common2.10.1org.eclipse.emforg.eclipse.emf.ecore.xmi2.10.1srcmaven-compiler-plugin3.11.71.7
```
--------------------------------
### Run CountPagesAndResources from command line
Source: https://github.com/yan74/afplib/wiki/Samples
Command-line invocation of CountPagesAndResources with a list of files. The output shows the count of pages and resources per file.
```bash
java -cp target/samples-0.0.8-SNAPSHOT-jar-with-dependencies.jar org.afplib.samples.CountPagesAndResources testdata/*.afp
20.07.2015 12:44:08.090 INFO - starting...
pages res file
000001 0003 testdata/ende.afp
000001 0003 testdata/start.afp
20.07.2015 12:44:08.317 INFO - done...
```
--------------------------------
### Run Anonymizer sample
Source: https://github.com/yan74/afplib/wiki/Samples
Command-line invocation for the Anonymizer sample. It processes an AFP file and writes an anonymized version. The command assumes the sample jar is built and the test data file exists.
```bash
java -cp target/samples-0.0.8-SNAPSHOT-jar-with-dependencies.jar org.afplib.samples.Anonymizer testdata/start.afp tmp/start-anon.afp
```
--------------------------------
### Run DumpAFP from command line
Source: https://github.com/yan74/afplib/wiki/Samples
Command-line invocation of DumpAFP with an AFP file. The output shows a human-readable dump of structured fields and triplets.
```bash
java -cp target/samples-0.0.8-SNAPSHOT-jar-with-dependencies.jar org.afplib.samples.DumpAFP testdata/start.afp
...
BDT number:44,offset:368241,id:13871272,length:19,rawData:null,charset:null,DocName:,Reserved:0,
IMM number:45,offset:368260,id:13872076,length:17,rawData:null,charset:null,MMPName:MM000000,
BPG number:46,offset:368277,id:13871279,length:17,rawData:null,charset:null,PageName:,
BAG number:47,offset:368294,id:13871305,length:9,rawData:null,charset:null,AEGName:null,
MPO number:48,offset:368303,id:13872088,length:27,rawData:null,charset:null,
MPORG label:null,charset:null,fileOffset:0,tripletLength:0,tripletId:0,tripletNumber:0,RGLength:18,
ResourceLocalIdentifier label:null,charset:null,fileOffset:0,tripletLength:0,tripletId:0,tripletNumber:0,ResType:2,ResLID:1,
FullyQualifiedName label:null,charset:null,fileOffset:0,tripletLength:0,tripletId:0,tripletNumber:0,FQNType:132,FQNFormat:0,FQName:O1VORNAL,
...
```
--------------------------------
### Creating Structured Fields with AfplibFactory
Source: https://github.com/yan74/afplib/wiki/Creating-AFP
Using the AfplibFactory to instantiate structured fields and add triplets.
```java
BRG brg = AfplibFactory.eINSTANCE.createBRG();
brg.setRGrpName("BRGTEST0");
Comment comment = AfplibFactory.eINSTANCE.createComment();
comment.setComment("My Comment");
brg.getTriplets().add(comment);
```
--------------------------------
### PDF2Overlay BRS creation with AfpBuilder
Source: https://github.com/yan74/afplib/wiki/Samples
Constructs a BRS (Begin Resource) structured field using AfpBuilder. Sets the RsName attribute to ovlName and adds a ResourceObjectType triplet with ObjType = Overlay and ConData = binary 0.
```java
String ovlName = ...
AfpOutputStream out = ...
out.writeStructuredField(new AfpBuilder()
.with(AfplibPackage.BRS__RS_NAME, ovlName)
.withMember(new AfpBuilder()
.with(AfplibPackage.RESOURCE_OBJECT_TYPE__OBJ_TYPE, ResourceObjectTypeObjType.CONST_OVERLAY_VALUE)
.with(AfplibPackage.RESOURCE_OBJECT_TYPE__CON_DATA, new byte[] {0,0,0,0,0,0,0})
.create(ResourceObjectType.class))
.create(BRS.class));
```
--------------------------------
### Defining Structured Fields and Repeating Groups
Source: https://github.com/yan74/afplib/wiki/Creating-AFP
Interfaces for structured fields like PTX and MDR, showing how triplets and repeating groups are stored.
```java
public interface PTX extends SF {
EList getCS();
} // PTX
public interface MDR extends SF {
EList getRG();
} // MDR
```
--------------------------------
### Count pages and resources using AfpInputStream
Source: https://github.com/yan74/afplib/wiki/Samples
Java code that reads structured fields from an AFP input stream and increments counters for BPG (Begin Page) and BRS (Begin Resource) fields.
```java
AfpInputStream in = ...
SF sf;
while((sf = in.readStructuredField()) != null) {
switch(sf.getId()) {
case SFName.BPG_VALUE:
pages++;
break;
case SFName.BRS_VALUE:
resources++;
break;
}
}
```
--------------------------------
### Inspect medium map properties
Source: https://github.com/yan74/afplib/blob/master/org.afplib/src/main/java/org/afplib/helper/formdef/package.html
Retrieves the bin number and plex (duplex mode) from a MediumMap object using getBin() and getPlex().
```java
Integer bin = map.getBin();
Plex plex = map.getPlex();
```
--------------------------------
### Creating Structured Fields with AfpBuilder
Source: https://github.com/yan74/afplib/wiki/Creating-AFP
Using the AfpBuilder fluent API to create structured fields and nested members.
```java
BRG brg = new AfpBuilder()
.with(AfplibPackage.BRG__RGRP_NAME, "BRGTEST0")
.withMember(new AfpBuilder()
.with(AfplibPackage.COMMENT__COMMENT, "My Comment")
.create(Comment.class))
.create(BRG.class);
```
--------------------------------
### Read AFP with AfpInputStream
Source: https://github.com/yan74/afplib/wiki/Reading-AFP
Basic pattern to read structured fields from an AFP file using AfpInputStream wrapped around a FileInputStream. The loop reads each structured field until null, and the try-with-resources ensures the stream is closed.
```java
try (AfpInputStream afpin = new AfpInputStream(new FileInputStream(file))) {
SF sf;
while((sf = afpin.readStructuredField()) != null) {
...
}
}
```
--------------------------------
### Read Large AFP Files with BufferedInputStream
Source: https://github.com/yan74/afplib/wiki/Reading-AFP
Recommended for reading rather large files, this snippet wraps the FileInputStream in a BufferedInputStream before passing it to AfpInputStream. The try-with-resources block automatically closes the stream.
```java
try(AfpInputStream ain = new AfpInputStream(new BufferedInputStream(new FileInputStream(file)))) {
}
```
--------------------------------
### AfpFilter.filter
Source: https://github.com/yan74/afplib/wiki/Create-an-AFP-Filter
Static method to run a filter on an AFP input stream and write the result to an output stream. It processes structured fields on the fly.
```APIDOC
## Method: AfpFilter.filter
### Description
Runs the given filter on the input AFP stream and writes the filtered output to the output stream. The filter's onStructuredField method is called for each structured field.
### Method
filter
### Signature
static void filter(AfpInputStream in, AfpOutputStream out, Filter filter) throws IOException
### Parameters
- **in** (AfpInputStream) - Required - The input stream to read AFP data from.
- **out** (AfpOutputStream) - Required - The output stream to write the filtered AFP data to.
- **filter** (Filter) - Required - The filter implementation to apply.
### Example
```java
AfpFilter.filter(in, out, new Filter() {
@Override
public STATE onStructuredField(SF sf) {
switch(sf.getId()) {
case SFName.PTX_VALUE:
PTX ptx = (PTX) sf;
for(Triplet t : ptx.getCS()) {
if(t instanceof TRN) {
anonymize((TRN) t);
}
}
return STATE.MODIFIED;
}
return STATE.UNTOUCHED;
}
});
```
```
--------------------------------
### Mark and Rewind to a Structured Field with getCurrentOffset()
Source: https://github.com/yan74/afplib/wiki/Reading-AFP
Shows how to save the current data stream position using getCurrentOffset() when a BDT structured field is encountered, then later rewind the underlying FileInputStream to that position using its channel. Note that this technique does not work with BufferedInputStream.
```java
FileInputStream fis = new FileInputStream(file);
AfpInputStream ain = new AfpInputStream(fis);
while((sf = ain.readStructuredField()) != null) {
if(sf instanceof BDT) {
beginDocument = ain.getCurrentOffset();
}
}
...
// rewind to the BDT
fis.getChannel().position(beginDocument);
```
--------------------------------
### Saving Structured Fields to a Stream
Source: https://github.com/yan74/afplib/wiki/Creating-AFP
Writing a created structured field to a file using AfpOutputStream.
```java
File ftmp = File.createTempFile("tmp", ".afp");
try (AfpOutputStream afpout = new AfpOutputStream(new FileOutputStream(ftmp))) {
BRG brg = AfplibFactory.eINSTANCE.createBRG();
brg.setRGrpName("MYRESGRP");
afpout.writeStructuredField(brg);
}
```
--------------------------------
### Output of reading AFP data
Source: https://github.com/yan74/afplib/blob/master/README.md
The console output produced by reading the AFP file.
```bash
HELLOWLD # System.out.println(bdt.getDocName());
0 # System.out.println(bdt.getReserved());
1 # System.out.println(bdt.getTriplets().size());
My first AFPLib Program # System.out.println(((Comment)bdt.getTriplets().get(0)).getComment());
HELLOWLD # System.out.println(edt.getDocName());
```
--------------------------------
### SDFHelper.ipds2sdf
Source: https://github.com/yan74/afplib/wiki/Work-with-IOCA-and-SDF-(Self-Defined-Fields)
Converts a list of IPD structured fields into an array of Triplet objects representing SDFs.
```APIDOC
## SDFHelper.ipds2sdf
### Description
Converts a list of IPD structured fields into an array of Triplet objects representing SDFs.
### Method
static method
### Signature
`public static Triplet[] ipds2sdf(List ipds)`
### Parameters
- **ipds** (List) - Required - The list of IPD structured fields to convert.
### Returns
- **Triplet[]** - An array of Triplet objects representing the SDFs.
### Example
```java
List ipds = ...;
Triplet[] sdfs = SDFHelper.ipds2sdf(ipds);
```
```
--------------------------------
### SDFHelper.sdf2ipds
Source: https://github.com/yan74/afplib/wiki/Work-with-IOCA-and-SDF-(Self-Defined-Fields)
Converts a list of Triplet objects (SDFs) into an array of IPD structured fields.
```APIDOC
## SDFHelper.sdf2ipds
### Description
Converts a list of Triplet objects (SDFs) into an array of IPD structured fields.
### Method
static method
### Signature
`public static IPD[] sdf2ipds(List triplets)`
### Parameters
- **triplets** (List) - Required - The list of Triplet objects to convert.
### Returns
- **IPD[]** - An array of IPD structured fields.
### Example
```java
List triplets = ...;
IPD[] ipds = SDFHelper.sdf2ipds(triplets);
```
```
--------------------------------
### Print attributes of an EObject
Source: https://github.com/yan74/afplib/wiki/Samples
Java method that iterates over all EAttributes of an EObject and prints their names and values. Used to dump structured fields and triplets.
```java
// print all attributes of an e.g. structured field
private static void printAttributes(EObject eobj) {
for(EAttribute atr : eobj.eClass().getEAllAttributes()) {
System.out.print(atr.getName()+":"+eobj.eGet(atr)+",");
}
}
```
--------------------------------
### BDT interface definition
Source: https://github.com/yan74/afplib/blob/master/README.md
The Java interface representation of the Begin Document (BDT) structured field.
```java
...
public interface BDT extends SF {
String getDocName();
void setDocName(String value);
Integer getReserved();
void setReserved(Integer value);
EList getTriplets();
} // BDT
```
--------------------------------
### org.afplib.io.Filter
Source: https://github.com/yan74/afplib/wiki/Create-an-AFP-Filter
The Filter interface that users must implement to process structured fields. It defines the onStructuredField method that is called for each structured field during filtering.
```APIDOC
## Interface: org.afplib.io.Filter
### Description
Interface to be implemented by users to create a filter for AFP files. The filter's onStructuredField method is called for each structured field during processing.
### Method
onStructuredField
### Signature
STATE onStructuredField(SF sf) throws IOException
### Parameters
- **sf** (SF) - Required - The structured field to be processed.
### Returns
- **STATE** - The state indicating how the structured field should be handled. Possible values: DROP, MODIFIED, UNTOUCHED, STOP.
### Enum: STATE
- **DROP** - The structured field is to be dropped and not saved to the output.
- **MODIFIED** - The filter modified the structured field.
- **UNTOUCHED** - The filter did nothing to the structured field.
- **STOP** - Stop processing; no more output is produced.
### Example
```java
public interface Filter {
enum STATE { DROP, MODIFIED, UNTOUCHED, STOP }
STATE onStructuredField(SF sf) throws IOException;
}
```
```
--------------------------------
### Anonymizer onStructuredField method
Source: https://github.com/yan74/afplib/wiki/Samples
This method is called by AfpFilter for every structured field. It checks if the field is a PTX, then iterates its triplets and anonymizes any TRN triplets. Returns STATE.MODIFIED if changed, otherwise STATE.UNTOUCHED.
```java
public STATE onStructuredField(SF sf) {
switch(sf.getId()) {
case SFName.PTX_VALUE:
PTX ptx = (PTX) sf;
for(Triplet t : ptx.getCS()) {
if(t instanceof TRN) anonymize((TRN) t);
}
return STATE.MODIFIED;
}
return STATE.UNTOUCHED;
}
```
--------------------------------
### Filter interface definition
Source: https://github.com/yan74/afplib/wiki/Create-an-AFP-Filter
Defines the org.afplib.io.Filter interface with the onStructuredField method that returns a STATE enum (DROP, MODIFIED, UNTOUCHED, STOP).
```java
public interface Filter {
enum STATE { DROP, MODIFIED, UNTOUCHED, STOP }
STATE onStructuredField(SF sf) throws IOException;
}
```