View Javadoc
1   /*
2    * Copyright (C) 2012 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.geometry.io;
17  
18  import com.irurueta.geometry.InhomogeneousPoint3D;
19  import com.irurueta.geometry.Point3D;
20  import com.irurueta.geometry.Triangulator3D;
21  import com.irurueta.geometry.TriangulatorException;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.nio.ByteBuffer;
26  import java.util.ArrayList;
27  import java.util.List;
28  import java.util.TreeMap;
29  
30  /**
31   * Loads PLY files.
32   * This class is meant to read PLY files using an iterative process to read
33   * the file in small pieces of data.
34   * Because the file is loaded in small pieces, this class has a low memory
35   * impact. Besides parameters such as maxVerticesInChunk or maxStreamPositions
36   * can be adjusted in order to increase or reduce memory usage at the expense of
37   * performance (the greater the memory usage the better the performance).
38   * This class needs random access to file positions, and for that reason it
39   * cannot be used with streams.
40   * This class is based in the work of:
41   * <a href="http://w3.impa.br/~diego/software/rply/">http://w3.impa.br/~diego/software/rply/</a>
42   */
43  public class LoaderPLY extends Loader {
44      /**
45       * Size of internal buffer where bytes from stream of data read into.
46       * This size (8 bytes) is meant to be able to fit any data type.
47       *
48       * @see DataTypePLY
49       */
50      public static final int BUFFER_SIZE = 8;
51  
52      /**
53       * Constant defining maximum number of vertices to be stored in a single
54       * data chunk.
55       * By default, this is the maximum values stored in a short 65535. This is
56       * so that data chunks can be compatible with technologies such as openGL
57       * where vertex indices are short values, and hence only 65535 vertices can
58       * be indexed at a time.
59       */
60      public static final int DEFAULT_MAX_VERTICES_IN_CHUNK = 0xffff;
61  
62      /**
63       * Minimum allowed value for maximum vertices in a chunk. At least one
64       * vertex must be contained on a data chunk, for that reason this constant
65       * is 1.
66       */
67      public static final int MIN_MAX_VERTICES_IN_CHUNK = 1;
68  
69      /**
70       * Constant defining if by default duplicate vertices are allowed in a data
71       * chunk. By allowing duplicate vertices, PLY loading can be speed up a
72       * little bit at the expense of getting larger sets of data which will
73       * contain redundant vertices. If your environment is memory constrained,
74       * this should be disabled. By default, it is disabled.
75       */
76      public static final boolean DEFAULT_ALLOW_DUPLICATE_VERTICES_IN_CHUNK = false;
77  
78      /**
79       * Constant defining default maximum number of stream positions to be
80       * cached.
81       * This loader keeps track of a set of stream positions that have been
82       * parsed on ASCII mode. By keeping a cache of positions loading times can
83       * be largely reduced at the expense of using more memory during loading.
84       * By default, this is set to 1000000 positions.
85       * This only has effect on ASCII PLY files. For binary PLY files this
86       * constant is ignored.
87       */
88      public static final int DEFAULT_MAX_STREAM_POSITIONS = 1000000;
89  
90      /**
91       * Constant defining minimum allowed value for maximum stream positions.
92       */
93      public static final int MIN_STREAM_POSITIONS = 1;
94  
95      /**
96       * Constant defining when progress change should be notified. When progress
97       * is increased by this value from previous notification, then progress will
98       * be notified again.
99       */
100     public static final float PROGRESS_DELTA = 0.01f;
101 
102     /**
103      * Keeps PLY header data.
104      */
105     private HeaderPLY header;
106 
107     /**
108      * Boolean indicating if file is a valid PLY stream of data.
109      */
110     private boolean validStream;
111 
112     /**
113      * Boolean indicating whether validity of file has already been checked.
114      */
115     private boolean validityChecked;
116 
117     /**
118      * Iterator currently loading provided file.
119      */
120     private LoaderIteratorPLY loaderIterator;
121 
122     /**
123      * Indicates maximum number of vertices to keep in a chunk of data.
124      * By default, this is the maximum values stored in a short 65535. This is
125      * so that data chunks can be compatible with technologies such as openGL
126      * where vertex indices are short values, and hence only 65535 vertices can
127      * be indexed at a time.
128      */
129     private int maxVerticesInChunk;
130 
131     /**
132      * Indicates whether duplicate vertices in a chunk are allowed. By allowing
133      * duplicate vertices, PLY loading can be speed up a little bit at the
134      * expense of getting larger sets of data which will contain redundant
135      * vertices. If your environment is memory constrained, this should be
136      * disabled. By default, it is disabled.
137      */
138     private boolean allowDuplicateVerticesInChunk;
139 
140     /**
141      * Maximum number of stream positions to be cached.
142      * This loader keeps track of a set of stream positions that have been
143      * parsed on ASCII mode. By keeping a cache of positions loading times can
144      * be largely reduced at the expense of using more memory during loading.
145      * By default, this is set to 1000000 positions.
146      * This only has effect on ASCII PLY files. For binary PLY files this
147      * setting is ignored.
148      */
149     private long maxStreamPositions;
150 
151     /**
152      * Constructor.
153      */
154     public LoaderPLY() {
155         reader = null;
156         header = null;
157         validStream = false;
158         validityChecked = false;
159         loaderIterator = null;
160         maxVerticesInChunk = DEFAULT_MAX_VERTICES_IN_CHUNK;
161         allowDuplicateVerticesInChunk = DEFAULT_ALLOW_DUPLICATE_VERTICES_IN_CHUNK;
162         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
163     }
164 
165     /**
166      * Constructor.
167      *
168      * @param maxVerticesInChunk Indicates maximum number of vertices to keep in
169      *                           a chunk of data.
170      * @throws IllegalArgumentException Raised if maximum number of vertices is
171      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
172      */
173     public LoaderPLY(final int maxVerticesInChunk) {
174         reader = null;
175         header = null;
176         validStream = false;
177         validityChecked = false;
178         loaderIterator = null;
179         internalSetMaxVerticesInChunk(maxVerticesInChunk);
180         allowDuplicateVerticesInChunk = DEFAULT_ALLOW_DUPLICATE_VERTICES_IN_CHUNK;
181         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
182     }
183 
184     /**
185      * Constructor.
186      *
187      * @param maxVerticesInChunk            Indicates maximum number of vertices to keep in
188      *                                      a chunk of data.
189      * @param allowDuplicateVerticesInChunk Indicates whether duplicate vertices
190      *                                      in a chunk are allowed.
191      * @throws IllegalArgumentException Raised if maximum number of vertices is
192      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
193      */
194     public LoaderPLY(final int maxVerticesInChunk, final boolean allowDuplicateVerticesInChunk) {
195         reader = null;
196         header = null;
197         validStream = false;
198         validityChecked = false;
199         loaderIterator = null;
200         internalSetMaxVerticesInChunk(maxVerticesInChunk);
201         internalSetAllowDuplicateVerticesInChunk(allowDuplicateVerticesInChunk);
202         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
203     }
204 
205     /**
206      * Constructor.
207      *
208      * @param maxVerticesInChunk            Indicates maximum number of vertices to keep in
209      *                                      a chunk of data.
210      * @param allowDuplicateVerticesInChunk Indicates whether duplicate vertices
211      *                                      in a chunk are allowed.
212      * @param maxStreamPositions            Maximum number of stream positions to be
213      *                                      cached.
214      * @throws IllegalArgumentException Raised if maximum number of vertices is
215      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK or if maximum stream positions is
216      *                                  smaller than MIN_STREAM_POSITIONS.
217      */
218     public LoaderPLY(final int maxVerticesInChunk, final boolean allowDuplicateVerticesInChunk,
219                      final long maxStreamPositions) {
220         reader = null;
221         header = null;
222         validStream = false;
223         validityChecked = false;
224         loaderIterator = null;
225         internalSetMaxVerticesInChunk(maxVerticesInChunk);
226         internalSetAllowDuplicateVerticesInChunk(allowDuplicateVerticesInChunk);
227         internalSetMaxStreamPositions(maxStreamPositions);
228     }
229 
230     /**
231      * Constructor.
232      *
233      * @param f file to be loaded.
234      * @throws IOException if file does not exist or cannot be loaded.
235      */
236     public LoaderPLY(final File f) throws IOException {
237         super(f);
238         header = null;
239         validStream = false;
240         validityChecked = false;
241         loaderIterator = null;
242         maxVerticesInChunk = DEFAULT_MAX_VERTICES_IN_CHUNK;
243         allowDuplicateVerticesInChunk = DEFAULT_ALLOW_DUPLICATE_VERTICES_IN_CHUNK;
244         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
245     }
246 
247     /**
248      * Constructor.
249      *
250      * @param f                  file to be loaded.
251      * @param maxVerticesInChunk Indicates maximum number of vertices to keep in
252      *                           a chunk of data.
253      * @throws IllegalArgumentException Raised if maximum number of vertices is
254      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
255      * @throws IOException              if file does not exist or cannot be loaded.
256      */
257     public LoaderPLY(final File f, final int maxVerticesInChunk) throws IOException {
258         super(f);
259         header = null;
260         validStream = false;
261         validityChecked = false;
262         loaderIterator = null;
263         internalSetMaxVerticesInChunk(maxVerticesInChunk);
264         allowDuplicateVerticesInChunk = DEFAULT_ALLOW_DUPLICATE_VERTICES_IN_CHUNK;
265         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
266     }
267 
268     /**
269      * Constructor.
270      *
271      * @param f                             file to be loaded.
272      * @param maxVerticesInChunk            Indicates maximum number of vertices to keep in
273      *                                      a chunk of data.
274      * @param allowDuplicateVerticesInChunk Indicates whether duplicate vertices
275      *                                      in a chunk are allowed.
276      * @throws IllegalArgumentException Raised if maximum number of vertices is
277      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
278      * @throws IOException              if file does not exist or cannot be loaded.
279      */
280     public LoaderPLY(final File f, final int maxVerticesInChunk, final boolean allowDuplicateVerticesInChunk)
281             throws IOException {
282         super(f);
283         header = null;
284         validStream = false;
285         validityChecked = false;
286         loaderIterator = null;
287         internalSetMaxVerticesInChunk(maxVerticesInChunk);
288         internalSetAllowDuplicateVerticesInChunk(allowDuplicateVerticesInChunk);
289         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
290     }
291 
292     /**
293      * Constructor.
294      *
295      * @param f                             file to be loaded.
296      * @param maxVerticesInChunk            Indicates maximum number of vertices to keep in
297      *                                      a chunk of data.
298      * @param allowDuplicateVerticesInChunk Indicates whether duplicate vertices
299      *                                      in a chunk are allowed.
300      * @param maxStreamPositions            Maximum number of stream positions to be
301      *                                      cached.
302      * @throws IllegalArgumentException Raised if maximum number of vertices is
303      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK or if maximum stream positions is
304      *                                  smaller than MIN_STREAM_POSITIONS.
305      * @throws IOException              if file does not exist or cannot be loaded.
306      */
307     public LoaderPLY(final File f, final int maxVerticesInChunk, final boolean allowDuplicateVerticesInChunk,
308                      final long maxStreamPositions) throws IOException {
309         super(f);
310         header = null;
311         validStream = false;
312         validityChecked = false;
313         loaderIterator = null;
314         internalSetMaxVerticesInChunk(maxVerticesInChunk);
315         internalSetAllowDuplicateVerticesInChunk(allowDuplicateVerticesInChunk);
316         internalSetMaxStreamPositions(maxStreamPositions);
317     }
318 
319     /**
320      * Constructor.
321      *
322      * @param listener listener to notify start, end and progress events.
323      */
324     public LoaderPLY(final LoaderListener listener) {
325         super(listener);
326         reader = null;
327         header = null;
328         validStream = false;
329         validityChecked = false;
330         loaderIterator = null;
331         maxVerticesInChunk = DEFAULT_MAX_VERTICES_IN_CHUNK;
332         allowDuplicateVerticesInChunk = DEFAULT_ALLOW_DUPLICATE_VERTICES_IN_CHUNK;
333         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
334     }
335 
336     /**
337      * Constructor.
338      *
339      * @param listener           listener to notify start, end and progress events.
340      * @param maxVerticesInChunk Indicates maximum number of vertices to keep in
341      *                           a chunk of data.
342      * @throws IllegalArgumentException Raised if maximum number of vertices is
343      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
344      */
345     public LoaderPLY(final LoaderListener listener, final int maxVerticesInChunk) {
346         super(listener);
347         reader = null;
348         header = null;
349         validStream = false;
350         validityChecked = false;
351         loaderIterator = null;
352         internalSetMaxVerticesInChunk(maxVerticesInChunk);
353         allowDuplicateVerticesInChunk = DEFAULT_ALLOW_DUPLICATE_VERTICES_IN_CHUNK;
354         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
355     }
356 
357     /**
358      * Constructor.
359      *
360      * @param listener                      listener to notify start, end and progress events.
361      * @param maxVerticesInChunk            Indicates maximum number of vertices to keep in
362      *                                      a chunk of data.
363      * @param allowDuplicateVerticesInChunk Indicates whether duplicate vertices
364      *                                      in a chunk are allowed.
365      * @throws IllegalArgumentException Raised if maximum number of vertices is
366      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
367      */
368     public LoaderPLY(final LoaderListener listener, final int maxVerticesInChunk,
369                      final boolean allowDuplicateVerticesInChunk) {
370         super(listener);
371         reader = null;
372         header = null;
373         validStream = false;
374         validityChecked = false;
375         loaderIterator = null;
376         internalSetMaxVerticesInChunk(maxVerticesInChunk);
377         internalSetAllowDuplicateVerticesInChunk(allowDuplicateVerticesInChunk);
378         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
379     }
380 
381     /**
382      * Constructor.
383      *
384      * @param listener                      listener to notify start, end and progress events.
385      * @param maxVerticesInChunk            Indicates maximum number of vertices to keep in
386      *                                      a chunk of data.
387      * @param allowDuplicateVerticesInChunk Indicates whether duplicate vertices
388      *                                      in a chunk are allowed.
389      * @param maxStreamPositions            Maximum number of stream positions to be
390      *                                      cached.
391      * @throws IllegalArgumentException Raised if maximum number of vertices is
392      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK or if maximum stream positions is
393      *                                  smaller than MIN_STREAM_POSITIONS.
394      */
395     public LoaderPLY(final LoaderListener listener, final int maxVerticesInChunk,
396                      final boolean allowDuplicateVerticesInChunk, final long maxStreamPositions) {
397         super(listener);
398         reader = null;
399         header = null;
400         validStream = false;
401         validityChecked = false;
402         loaderIterator = null;
403         internalSetMaxVerticesInChunk(maxVerticesInChunk);
404         internalSetAllowDuplicateVerticesInChunk(allowDuplicateVerticesInChunk);
405         internalSetMaxStreamPositions(maxStreamPositions);
406     }
407 
408     /**
409      * Constructor.
410      *
411      * @param f        file to be loaded.
412      * @param listener listener to notify start, end and progress events.
413      * @throws IOException if file does not exist or cannot be loaded.
414      */
415     public LoaderPLY(final File f, final LoaderListener listener) throws IOException {
416         super(f, listener);
417         header = null;
418         validStream = false;
419         validityChecked = false;
420         loaderIterator = null;
421         maxVerticesInChunk = DEFAULT_MAX_VERTICES_IN_CHUNK;
422         allowDuplicateVerticesInChunk = DEFAULT_ALLOW_DUPLICATE_VERTICES_IN_CHUNK;
423         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
424     }
425 
426     /**
427      * Constructor.
428      *
429      * @param f                  file to be loaded.
430      * @param listener           listener to notify start, end and progress events.
431      * @param maxVerticesInChunk Indicates maximum number of vertices to keep in
432      *                           a chunk of data.
433      * @throws IllegalArgumentException Raised if maximum number of vertices is
434      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
435      * @throws IOException              if file does not exist or cannot be loaded.
436      */
437     public LoaderPLY(final File f, final LoaderListener listener, final int maxVerticesInChunk) throws IOException {
438         super(f, listener);
439         header = null;
440         validStream = false;
441         validityChecked = false;
442         loaderIterator = null;
443         internalSetMaxVerticesInChunk(maxVerticesInChunk);
444         allowDuplicateVerticesInChunk = DEFAULT_ALLOW_DUPLICATE_VERTICES_IN_CHUNK;
445         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
446     }
447 
448     /**
449      * Constructor.
450      *
451      * @param f                             file to be loaded.
452      * @param listener                      listener to notify start, end and progress events.
453      * @param maxVerticesInChunk            Indicates maximum number of vertices to keep in
454      *                                      a chunk of data.
455      * @param allowDuplicateVerticesInChunk Indicates whether duplicate vertices
456      *                                      in a chunk are allowed.
457      * @throws IllegalArgumentException Raised if maximum number of vertices is
458      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
459      * @throws IOException              if file does not exist or cannot be loaded.
460      */
461     public LoaderPLY(final File f, final LoaderListener listener, final int maxVerticesInChunk,
462                      final boolean allowDuplicateVerticesInChunk) throws IOException {
463         super(f, listener);
464         header = null;
465         validStream = false;
466         validityChecked = false;
467         loaderIterator = null;
468         internalSetMaxVerticesInChunk(maxVerticesInChunk);
469         internalSetAllowDuplicateVerticesInChunk(allowDuplicateVerticesInChunk);
470         maxStreamPositions = DEFAULT_MAX_STREAM_POSITIONS;
471     }
472 
473     /**
474      * Constructor.
475      *
476      * @param f                             file to be loaded.
477      * @param listener                      listener to notify start, end and progress events.
478      * @param maxVerticesInChunk            Indicates maximum number of vertices to keep in
479      *                                      a chunk of data.
480      * @param allowDuplicateVerticesInChunk Indicates whether duplicate vertices
481      *                                      in a chunk are allowed.
482      * @param maxStreamPositions            Maximum number of stream positions to be
483      *                                      cached.
484      * @throws IllegalArgumentException Raised if maximum number of vertices is
485      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK or if maximum stream positions is
486      *                                  smaller than MIN_STREAM_POSITIONS.
487      * @throws IOException              if file does not exist or cannot be loaded.
488      */
489     public LoaderPLY(final File f, final LoaderListener listener, final int maxVerticesInChunk,
490                      final boolean allowDuplicateVerticesInChunk, final long maxStreamPositions) throws IOException {
491         super(f, listener);
492         header = null;
493         validStream = false;
494         validityChecked = false;
495         loaderIterator = null;
496         internalSetMaxVerticesInChunk(maxVerticesInChunk);
497         internalSetAllowDuplicateVerticesInChunk(allowDuplicateVerticesInChunk);
498         internalSetMaxStreamPositions(maxStreamPositions);
499     }
500 
501     /**
502      * Returns maximum number of vertices to keep in a chunk of data.
503      * By default, this is the maximum values stored in a short is 65535. This is
504      * so that data chunks can be compatible with technologies such as openGL
505      * where vertex indices are short values, and hence only 65535 vertices can
506      * be indexed at a time.
507      *
508      * @return Maximum number of vertices to keep in a chunk of data.
509      */
510     public int getMaxVerticesInChunk() {
511         return maxVerticesInChunk;
512     }
513 
514     /**
515      * Sets maximum number of vertices to keep in a chunk of data.
516      *
517      * @param maxVerticesInChunk Indicates maximum number of vertices to keep in
518      *                           a chunk of data.
519      * @throws IllegalArgumentException Raised if maximum number of vertices is
520      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
521      * @throws LockedException          Raised if this instance is locked because loading
522      *                                  is in progress.
523      */
524     public void setMaxVerticesInChunk(final int maxVerticesInChunk) throws LockedException {
525         if (isLocked()) {
526             throw new LockedException();
527         }
528         internalSetMaxVerticesInChunk(maxVerticesInChunk);
529     }
530 
531     /**
532      * Determines whether duplicate vertices in a chunk are allowed. By allowing
533      * duplicate vertices, PLY loading can be speed up a little bit at the
534      * expense of getting larger sets of data which will contain redundant
535      * vertices. If your environment is memory constrained, this should be
536      * disabled. By default, it is disabled.
537      *
538      * @return Determines whether duplicate vertices in a chunk are allowed.
539      */
540     public boolean areDuplicateVerticesInChunkAllowed() {
541         return allowDuplicateVerticesInChunk;
542     }
543 
544     /**
545      * Sets whether duplicate vertices in a chunk are allowed. By allowing
546      * duplicate vertices, PLY loading can be speed up a little bit at the
547      * expense of getting larger sets of data which will contain redundant
548      * vertices. If your environment is memory constrained, this should be
549      * disabled. By default, it is disabled.
550      *
551      * @param allow Indicates whether duplicates will be allowed or not.
552      * @throws LockedException Raised if this instance is locked because loading
553      *                         is in progress.
554      */
555     public void setAllowDuplicateVerticesInChunk(final boolean allow) throws LockedException {
556         if (isLocked()) {
557             throw new LockedException();
558         }
559         internalSetAllowDuplicateVerticesInChunk(allow);
560     }
561 
562     /**
563      * Returns maximum number of stream positions to be cached.
564      * This loader keeps track of a set of stream positions that have been
565      * parsed on ASCII mode. By keeping a cache of positions loading times can
566      * be largely reduced at the expense of using more memory during loading.
567      * By default, this is set to 1000000 positions.
568      * This only has effect on ASCII PLY files. For binary PLY files this
569      * setting is ignored.
570      *
571      * @return maximum number of stream positions to be cached.
572      */
573     public long getMaxStreamPositions() {
574         return maxStreamPositions;
575     }
576 
577     /**
578      * Sets maximum number of stream positions to be cached.
579      * This loader keeps track of a set of stream positions that have been
580      * parsed on ASCII mode. By keeping a cache of positions loading times can
581      * be largely reduced at the expense of using more memory during loading.
582      * By default, this is set to 1000000 positions.
583      * This only has effect on ASCII PLY files. For binary PLY files this
584      * setting is ignored.
585      *
586      * @param maxStreamPositions Maximum number of stream positions to be cached.
587      * @throws IllegalArgumentException Raised if provided value is lower than
588      *                                  DEFAULT_MAX_STREAM_POSITIONS.
589      * @throws LockedException          Raised if this instance is locked because loading
590      *                                  is in progress.
591      */
592     public void setMaxStreamPositions(final long maxStreamPositions) throws LockedException {
593         if (isLocked()) {
594             throw new LockedException();
595         }
596         internalSetMaxStreamPositions(maxStreamPositions);
597     }
598 
599     /**
600      * Indicates it this loader has enough parameters to start the loading
601      * process.
602      *
603      * @return True if ready, false otherwise.
604      */
605     @Override
606     public boolean isReady() {
607         return hasFile();
608     }
609 
610     /**
611      * Returns mesh format supported by this loader, which is PLY_MESH_FORMAT.
612      *
613      * @return Format supported by this loader, which is PLY_MESH_FORMAT.
614      */
615     @Override
616     public MeshFormat getMeshFormat() {
617         return MeshFormat.MESH_FORMAT_PLY;
618     }
619 
620     /**
621      * Reads the header of provided file and determines whether file is valid or
622      * not.
623      *
624      * @return True if file is a valid PLY file, false otherwise.
625      * @throws LockedException Raised if this instance is locked because loading
626      *                         is in progress.
627      * @throws IOException     if an i/O error occurs.
628      */
629     @Override
630     public boolean isValidFile() throws LockedException, IOException {
631         if (isLocked()) {
632             throw new LockedException();
633         }
634 
635         setLocked(true);
636         if (reader == null) {
637             throw new IOException();
638         }
639         try {
640             readHeader();
641         } catch (final LoaderException ex) {
642             validStream = false;
643         }
644         setLocked(false);
645         return validStream;
646     }
647 
648     /**
649      * Starts the loading process.
650      * This method reads the file header, checks its validity and prepares an
651      * iterator so the loading process can be carried in an iterative process.
652      *
653      * @return Iterator to load the file in small chunks of data.
654      * @throws LockedException   Raised if this instance is locked because loading
655      *                           is in progress.
656      * @throws NotReadyException raised if this instance is not yet ready
657      *                           because not enough parameters have been set.
658      * @throws IOException       if an I/O error occurs.
659      * @throws LoaderException   Raised if file is not a valid PLY or is corrupted.
660      */
661     @Override
662     public LoaderIterator load() throws LockedException, NotReadyException, IOException, LoaderException {
663         if (!isReady()) {
664             throw new NotReadyException();
665         }
666 
667         readFromStream();
668         return loaderIterator;
669     }
670 
671     /**
672      * Internal method to set maximum number of vertices to keep in a chunk of
673      * data.
674      *
675      * @param maxVerticesInChunk Indicates maximum number of vertices to keep in
676      *                           a chunk of data.
677      * @throws IllegalArgumentException Raised if maximum number of vertices is
678      *                                  smaller than MIN_MAX_VERTICES_IN_CHUNK.
679      */
680     private void internalSetMaxVerticesInChunk(final int maxVerticesInChunk) {
681         if (maxVerticesInChunk < MIN_MAX_VERTICES_IN_CHUNK) {
682             throw new IllegalArgumentException();
683         }
684 
685         this.maxVerticesInChunk = maxVerticesInChunk;
686     }
687 
688     /**
689      * Internal method to set whether duplicate vertices in a chunk are allowed.
690      * By allowing duplicate vertices, PLY loading can be speed up a little bit
691      * at the expense of getting larger sets of data which will contain
692      * redundant vertices. If your environment is memory constrained, this
693      * should be disabled. By default, it is disabled.
694      *
695      * @param allow Indicates whether duplicates will be allowed or not.
696      */
697     private void internalSetAllowDuplicateVerticesInChunk(final boolean allow) {
698         allowDuplicateVerticesInChunk = allow;
699     }
700 
701     /**
702      * Internal method to set maximum number of stream positions to be cached.
703      * This loader keeps track of a set of stream positions that have been
704      * parsed on ASCII mode. By keeping a cache of positions loading times can
705      * be largely reduced at the expense of using more memory during loading.
706      * By default, this is set to 1000000 positions.
707      * This only has effect on ASCII PLY files. For binary PLY files this
708      * setting is ignored.
709      *
710      * @param maxStreamPositions Maximum number of stream positions to be cached.
711      * @throws IllegalArgumentException Raised if provided value is lower than
712      *                                  DEFAULT_MAX_STREAM_POSITIONS.
713      */
714     private void internalSetMaxStreamPositions(final long maxStreamPositions) {
715         if (maxStreamPositions < MIN_STREAM_POSITIONS) {
716             throw new IllegalArgumentException();
717         }
718 
719         this.maxStreamPositions = maxStreamPositions;
720     }
721 
722     /**
723      * Reads header of provided file and initializes iterator to read data
724      * chunks of this file.
725      *
726      * @throws LockedException Raised if this instance is locked because loading
727      *                         is in progress.
728      * @throws IOException     if an i/O error occurs.
729      * @throws LoaderException Raised if file is not a valid PLY or is corrupted
730      */
731     private void readFromStream() throws LockedException, IOException, LoaderException {
732 
733         if (isLocked()) {
734             throw new LockedException();
735         }
736 
737         setLocked(true);
738         if (listener != null) {
739             listener.onLoadStart(this);
740         }
741 
742         if (reader == null) {
743             throw new IOException();
744         }
745 
746         if (!validityChecked) {
747             readHeader();
748         }
749         if (!validStream) {
750             setLocked(false);
751             throw new LoaderException();
752         }
753 
754         loaderIterator = new LoaderIteratorPLY(this);
755         loaderIterator.setListener(new LoaderIteratorListenerImpl(this));
756     }
757 
758     /**
759      * Reads the header of provided file.
760      *
761      * @throws IOException     if an I/O error occurs.
762      * @throws LoaderException Raised if file is not a valid PLY or is
763      *                         corrupted.
764      */
765     private void readHeader() throws IOException, LoaderException {
766         if (reader == null) {
767             throw new IOException();
768         }
769 
770         validityChecked = true;
771 
772         // first line must be equal to string "ply"
773         var str = reader.readLine();
774 
775         if (!"ply".equals(str) || reader.isEndOfStream()) {
776             validStream = false;
777             throw new LoaderException();
778         }
779 
780         // second line contains format (i.e: format ascii 1.0)
781         // must start with "format" word
782         do {
783             // loop is to avoid empty strings
784             // (because of duplicate spaces or carriage returns)
785             str = reader.readWord();
786         } while ((str.isEmpty()) && !reader.isEndOfStream());
787 
788         if (!"format".equals(str) || reader.isEndOfStream()) {
789             validStream = false;
790             throw new LoaderException();
791         }
792 
793         // next to format word comes storage mode
794         do {
795             // loop to avoid empty strings
796             str = reader.readWord();
797         } while ((str.isEmpty()) && !reader.isEndOfStream());
798 
799         if (reader.isEndOfStream()) {
800             validStream = false;
801             throw new LoaderException();
802         }
803 
804         final PLYStorageMode storageMode = switch (str) {
805             case "ascii" ->
806                 // ASCII storage mode
807                     PLYStorageMode.PLY_ASCII;
808             case "binary_big_endian" ->
809                 // Binary big endian storage mode
810                     PLYStorageMode.PLY_BIG_ENDIAN;
811             case "binary_little_endian" ->
812                 // Binary little endian storage mode
813                     PLYStorageMode.PLY_LITTLE_ENDIAN;
814             default -> {
815                 // non supported storage mode
816                 validStream = false;
817                 throw new LoaderException();
818             }
819         };
820 
821         // next comes version (always must be 1.0)
822         do {
823             // loop to avoid empty strings
824             str = reader.readWord();
825         } while ((str.isEmpty()) && !reader.isEndOfStream());
826 
827         if (!"1.0".equals(str) || reader.isEndOfStream()) {
828             validStream = false;
829             throw new LoaderException();
830         }
831 
832         // instantiate header member
833         header = new HeaderPLY();
834         // set storage mode
835         header.setStorageMode(storageMode);
836 
837         // read until we find the line end_header
838         var endOfHeader = false;
839         ElementPLY lastElement = null;
840         PropertyPLY property;
841         do {
842             do {
843                 // loop to avoid empty strings
844                 str = reader.readWord();
845             } while ((str.isEmpty()) && !reader.isEndOfStream());
846 
847             if ("comment".equals(str)) {
848                 // if word is "comment", read until end of line
849                 str = reader.readLine();
850                 // add comment to list of comments in header
851                 header.getComments().add(str);
852             } else if ("obj_info".equals(str)) {
853                 // if word is "obj_info", read until end of line
854                 str = reader.readLine();
855                 // add obj_info to list of obj_infos in header
856                 header.getObjInfos().add(str);
857             } else if (str.endsWith("element")) {
858                 // and element has been found. We read its information and
859                 // add it to the list of elements
860 
861                 // next word contains element name
862                 do {
863                     // loop to avoid empty strings
864                     str = reader.readWord();
865                 } while ((str.isEmpty()) && !reader.isEndOfStream());
866 
867                 if (reader.isEndOfStream()) {
868                     validStream = false;
869                     throw new LoaderException();
870                 }
871 
872                 final var elementName = str;
873 
874                 // next word contains number of instances of this element
875                 do {
876                     str = reader.readWord();
877                 } while ((str.isEmpty()) && !reader.isEndOfStream());
878 
879                 if (reader.isEndOfStream()) {
880                     validStream = false;
881                     throw new LoaderException();
882                 }
883 
884                 final long elementInstances;
885                 try {
886                     elementInstances = Long.parseLong(str);
887                 } catch (NumberFormatException e) {
888                     throw new IOException(e);
889                 }
890 
891                 // instantiate element
892                 lastElement = new ElementPLY(elementName, elementInstances);
893 
894                 // add element to header
895                 header.getElements().add(lastElement);
896             } else if ("property".equals(str)) {
897                 // a property for last element that has been found. We read its
898                 // information and add it to the element
899 
900                 if (lastElement == null) {
901                     // no previous element was defined
902                     validStream = false;
903                     throw new LoaderException();
904                 }
905 
906                 // read next word
907                 do {
908                     // loop to avoid empty strings
909                     str = reader.readWord();
910                 } while ((str.isEmpty()) && !reader.isEndOfStream());
911 
912                 if (reader.isEndOfStream()) {
913                     validStream = false;
914                     throw new LoaderException();
915                 }
916 
917                 if ("list".equals(str)) {
918                     // property is a list
919                     final DataTypePLY lengthDataType;
920                     final DataTypePLY valueDataType;
921                     try {
922                         // read length data type
923                         do {
924                             // loop to avoid empty strings
925                             str = reader.readWord();
926                         } while ((str.isEmpty()) && !reader.isEndOfStream());
927 
928                         if (reader.isEndOfStream()) {
929                             validStream = false;
930                             throw new LoaderException();
931                         }
932 
933                         lengthDataType = wordToDataType(str);
934 
935                         // read value data type
936                         do {
937                             str = reader.readWord();
938                         } while ((str.isEmpty()) && !reader.isEndOfStream());
939 
940                         if (reader.isEndOfStream()) {
941                             validStream = false;
942                             throw new LoaderException();
943                         }
944 
945                         valueDataType = wordToDataType(str);
946                     } catch (final LoaderException ex) {
947                         // some error was found
948                         validStream = false;
949                         throw ex;
950                     }
951 
952                     // read property name
953                     do {
954                         str = reader.readWord();
955                     } while ((str.isEmpty()) && !reader.isEndOfStream());
956 
957                     if (reader.isEndOfStream()) {
958                         validStream = false;
959                         throw new LoaderException();
960                     }
961 
962                     final var propertyName = str;
963 
964                     property = new PropertyPLY(propertyName, lengthDataType, valueDataType);
965                 } else {
966                     // property is scalar
967                     // word that we have already read should contain value data
968                     // type
969 
970                     final DataTypePLY valueDataType;
971                     try {
972                         valueDataType = wordToDataType(str);
973                     } catch (final LoaderException ex) {
974                         // invalid data type was found
975                         validStream = false;
976                         throw ex;
977                     }
978                     // read property name
979                     do {
980                         str = reader.readWord();
981                     } while ((str.isEmpty()) && !reader.isEndOfStream());
982 
983                     if (reader.isEndOfStream()) {
984                         validStream = false;
985                         throw new LoaderException();
986                     }
987 
988                     final var propertyName = str;
989 
990                     property = new PropertyPLY(propertyName, valueDataType);
991                 }
992                 try {
993                     // add property to last element
994                     lastElement.getProperties().add(property);
995                 } catch (final NotAvailableException ex) {
996                     validStream = false;
997                     throw new LoaderException(ex);
998                 }
999             } else if ("end_header".equals(str)) {
1000                 // end of header has been found
1001                 endOfHeader = true;
1002             } else {
1003                 // something else that cannot be understood
1004                 validStream = false;
1005                 throw new LoaderException();
1006             }
1007         } while (!endOfHeader);
1008 
1009         validStream = true;
1010     }
1011 
1012     /**
1013      * Converts a word into a data type. If an unsupported word is found then a
1014      * LoaderException is raised.
1015      *
1016      * @param word word to be converted.
1017      * @return DataType obtained from word.
1018      * @throws LoaderException Raised if file is not a valid PLY or is
1019      *                         corrupted (i.e. an unsupported word is found).
1020      */
1021     private DataTypePLY wordToDataType(final String word) throws LoaderException {
1022         final var dataType = DataTypePLY.forValue(word);
1023         if (dataType == null) {
1024             throw new LoaderException();
1025         }
1026         return dataType;
1027     }
1028 
1029     /**
1030      * Internal listener to be notified when loading process finishes.
1031      * This listener is used to free resources when loading process finishes.
1032      */
1033     private class LoaderIteratorListenerImpl implements LoaderIteratorListener {
1034 
1035         /**
1036          * Reference to Loader loading PLY file.
1037          */
1038         private final LoaderPLY loader;
1039 
1040         /**
1041          * Constructor.
1042          *
1043          * @param loader reference to Loader.
1044          */
1045         public LoaderIteratorListenerImpl(final LoaderPLY loader) {
1046             this.loader = loader;
1047         }
1048 
1049         /**
1050          * Called when a loader iterator has no more data to be read.
1051          *
1052          * @param iterator Iterator loading a file.
1053          */
1054         @Override
1055         public void onIteratorFinished(final LoaderIterator iterator) {
1056             // because iterator is finished, we should allow subsequent calls to
1057             // load method
1058             try {
1059                 reader.seek(0); // attempt restart stream to current position
1060             } catch (final Exception ignore) {
1061                 // operation is attempted, if it fails it is ignored
1062             }
1063 
1064             // on subsequent calls
1065             validityChecked = false; // reset in case we want to read more data
1066             if (listener != null) {
1067                 listener.onLoadEnd(loader);
1068             }
1069             setLocked(false);
1070         }
1071     }
1072 
1073     /**
1074      * Internal implementation of a loader iterator for PLY files.
1075      */
1076     private class LoaderIteratorPLY implements LoaderIterator {
1077 
1078         /**
1079          * Reference to a LoaderPLY.
1080          */
1081         private final LoaderPLY loader;
1082 
1083         /**
1084          * Number of elements in a list property.
1085          */
1086         private int listElems;
1087 
1088         /**
1089          * Last x vertex coordinate that was read.
1090          */
1091         private float coordX;
1092 
1093         /**
1094          * Last y vertex coordinate that was read.
1095          */
1096         private float coordY;
1097 
1098         /**
1099          * Last z vertex coordinate that was read.
1100          */
1101         private float coordZ;
1102 
1103         /**
1104          * Last red color component that was read.
1105          */
1106         private short red;
1107 
1108         /**
1109          * Last green color component that was read.
1110          */
1111         private short green;
1112 
1113         /**
1114          * Last blue color component that was read.
1115          */
1116         private short blue;
1117 
1118         /**
1119          * Last alpha color component that was read.
1120          */
1121         private short alpha;
1122 
1123         /**
1124          * Last normal x component that was red.
1125          */
1126         private float nX;
1127 
1128         /**
1129          * Last normal y component that was read.
1130          */
1131         private float nY;
1132 
1133         /**
1134          * Last normal z component that was read.
1135          */
1136         private float nZ;
1137 
1138         /**
1139          * Last vertex index that was read.
1140          */
1141         private long index;
1142 
1143         // coordinates for bounding box in a chunk
1144 
1145         /**
1146          * Minimum x coordinate of all vertices that have been read so far in
1147          * current chunk of data.
1148          */
1149         private float minX;
1150 
1151         /**
1152          * Minimum y coordinate of all vertices that have been read so far in
1153          * current chunk of data.
1154          */
1155         private float minY;
1156 
1157         /**
1158          * Minimum z coordinate of all vertices that have been read so far in
1159          * current chunk of data.
1160          */
1161         private float minZ;
1162 
1163         /**
1164          * Maximum x coordinate of all vertices that have been read so far in
1165          * current chunk of data.
1166          */
1167         private float maxX;
1168 
1169         /**
1170          * Maximum y coordinate of all vertices that have been read so far in
1171          * current chunk of data.
1172          */
1173         private float maxY;
1174 
1175         /**
1176          * Maximum z coordinate of all vertices that have been read so far in
1177          * current chunk of data.
1178          */
1179         private float maxZ;
1180 
1181         /**
1182          * Indicates whether file contains vertices.
1183          */
1184         private boolean verticesAvailable;
1185 
1186         /**
1187          * Indicates whether file contains colors.
1188          */
1189         private boolean colorsAvailable;
1190 
1191         /**
1192          * Indicates whether file contains vertex indices.
1193          */
1194         private boolean indicesAvailable;
1195 
1196         /**
1197          * Indicates whether file contains normals.
1198          */
1199         private boolean normalsAvailable;
1200 
1201         /**
1202          * Indicates number of color components of vertices.
1203          */
1204         private int colorComponents;
1205 
1206         /**
1207          * Stores position where header of file finishes.
1208          */
1209         private long endHeaderStreamPosition;
1210 
1211         /**
1212          * Number of vertices contained in the file.
1213          */
1214         private long numberOfVertices;
1215 
1216         /**
1217          * Number of faces (triangles or polygons) contained in the file.
1218          */
1219         private long numberOfFaces;
1220 
1221         /**
1222          * Stores position where first vertex is located.
1223          */
1224         private long firstVertexStreamPosition;
1225 
1226         /**
1227          * Indicates whether first vertex position has already been read and is
1228          * available.
1229          */
1230         private boolean firstVertexStreamPositionAvailable;
1231 
1232         /**
1233          * Indicates size of vertex data.
1234          */
1235         private long vertexDataSize;
1236 
1237         /**
1238          * Stores position where first vertex index containing a triangle or
1239          * polygon is located.
1240          */
1241         private long firstFaceStreamPosition;
1242 
1243         /**
1244          * Indicates whether first vertex index position has already been read
1245          * and is available.
1246          */
1247         private boolean firstFaceStreamPositionAvailable;
1248 
1249         /**
1250          * Stores current position in file stream.
1251          */
1252         private long currentStreamPosition;
1253 
1254         /**
1255          * Number of instances of a given element in the header of the file
1256          * (i.e. number of vertices or faces).
1257          */
1258         private long totalInstances;
1259 
1260         /**
1261          * A header element that contains vertex properties.
1262          */
1263         private ElementPLY vertexElement;
1264 
1265         /**
1266          * A header element that contains face (triangles/polygons) properties.
1267          */
1268         private ElementPLY faceElement;
1269 
1270         /**
1271          * Current triangle/polygon being read from all faces available in the
1272          * file.
1273          */
1274         private long currentFace;
1275 
1276         /**
1277          * Listener to fetch a vertex position in the stream of data based on
1278          * its vertex index.
1279          * There are implementations for binary and text (ascii) fetchers.
1280          */
1281         private VertexFetcherListener fetchVertexListener;
1282 
1283         /**
1284          * Listener of this iterator that notifies the loader when the iterator
1285          * has finished loading the file, so that the loader becomes unlocked
1286          * again.
1287          */
1288         private LoaderIteratorListener listener;
1289 
1290         /**
1291          * Array containing vertex coordinates in current chunk of data.
1292          * Data is stored sequentially as x1, y1, z1, x2, y2, z2, etc.
1293          */
1294         private float[] coordsInChunkArray;
1295 
1296         /**
1297          * Array containing vertex colors in current chunk of data.
1298          * Data is stored sequentially depending on the number of color
1299          * components. For instance, for RGB this would be: r1, g1, b1, r2, g2,
1300          * b2, etc.
1301          */
1302         private short[] colorsInChunkArray;
1303 
1304         /**
1305          * Indices of vertices in current chunk.
1306          * Indices are stored sequentially in sets of 3 forming triangles like
1307          * this: t1a, t1b, t1c, t2a, t2b, t2c, etc.
1308          */
1309         private int[] indicesInChunkArray;
1310 
1311         /**
1312          * Indices of vertices in file. Original indices might differ of indices
1313          * numeration in current chunk because for each chunk indices start
1314          * again at zero. Indices are stored sequentially in sets of 3
1315          * forming triangles like: t1a, t1b, t1c, t2a, t2b, t2c, etc.
1316          */
1317         private long[] originalIndicesInChunkArray;
1318 
1319         /**
1320          * Normals of vertices in current chunk.
1321          * Normals are stored sequentially for each vertex like this: n1x, n1y,
1322          * n1z, n2x, n2y, n2z, etc.
1323          */
1324         private float[] normalsInChunkArray;
1325 
1326         /**
1327          * Number of vertices currently stored in chunk.
1328          * This is used to determine when no more vertices can be stored in
1329          * a chunk and an additional chunk needs to be loaded.
1330          */
1331         private int verticesInChunk;
1332 
1333         /**
1334          * Number of indices currently stored in chunk.
1335          */
1336         private int indicesInChunk;
1337 
1338         /**
1339          * Number of indices used as a default to initialize arrays.
1340          * When the number of indices exceeds this value arrays will be resized.
1341          */
1342         private int indicesInChunkSize;
1343 
1344         /**
1345          * Stores current stream position so that vertices positions can be
1346          * cached.
1347          */
1348         private long vertexStreamPosition;
1349 
1350         /**
1351          * Map containing relations between original indices of the stream (key)
1352          * and their corresponding index in the chunk (value).
1353          */
1354         private final TreeMap<Long, Integer> indicesMap;
1355 
1356         /**
1357          * Map relating original indices in stream (key) and stream positions
1358          * (value).
1359          */
1360         private final TreeMap<Long, Long> verticesStreamPositionsMap;
1361 
1362         /**
1363          * Constructor.
1364          *
1365          * @param loader Reference to the loader controlling this iterator.
1366          * @throws LoaderException Raised if file is corrupted and cannot be
1367          *                         loaded.
1368          * @throws IOException     if an I/O error occurs.
1369          */
1370         public LoaderIteratorPLY(final LoaderPLY loader) throws LoaderException, IOException {
1371             this.loader = loader;
1372             listElems = 1;
1373             nX = nY = nZ = 1.0f;
1374             alpha = 255;
1375             index = 0;
1376             colorComponents = 0;
1377             verticesAvailable = colorsAvailable = indicesAvailable = normalsAvailable = false;
1378             endHeaderStreamPosition = numberOfVertices = numberOfFaces = 0;
1379             firstVertexStreamPosition = 0;
1380             firstVertexStreamPositionAvailable = false;
1381             vertexDataSize = 0;
1382             firstFaceStreamPositionAvailable = false;
1383             currentStreamPosition = 0;
1384             totalInstances = 0;
1385             vertexElement = faceElement = null;
1386             currentFace = 0;
1387             fetchVertexListener = null;
1388             listener = null;
1389             coordsInChunkArray = null;
1390             colorsInChunkArray = null;
1391             indicesInChunkArray = null;
1392             originalIndicesInChunkArray = null;
1393             normalsInChunkArray = null;
1394             verticesInChunk = indicesInChunk = 0;
1395             indicesInChunkSize = 0;
1396             vertexStreamPosition = 0;
1397             indicesMap = new TreeMap<>();
1398             verticesStreamPositionsMap = new TreeMap<>();
1399 
1400             minX = minY = minZ = Float.MAX_VALUE;
1401             maxX = maxY = maxZ = -Float.MAX_VALUE;
1402 
1403             setUp();
1404         }
1405 
1406         /**
1407          * Sets listener to notify when this iterator has finished loading the
1408          * PLY file.
1409          *
1410          * @param listener listener to notify when this iterator has finished
1411          *                 loading the PLY file.
1412          */
1413         public void setListener(final LoaderIteratorListener listener) {
1414             this.listener = listener;
1415         }
1416 
1417         /**
1418          * Indicates if there are still more chunks of data to be read on this
1419          * PLY file.
1420          *
1421          * @return True if there are more chunks of data, false otherwise.
1422          */
1423         @Override
1424         public boolean hasNext() {
1425             return (currentFace < numberOfFaces);
1426         }
1427 
1428         /**
1429          * Reads next chunk of data from PLY file.
1430          *
1431          * @return A chunk of data containing vertex coordinates, colors, vertex
1432          * normals, textures, etc.
1433          * @throws NotAvailableException Raised if no more chunks are available.
1434          * @throws LoaderException       Raised if file is corrupted and cannot be
1435          *                               loaded.
1436          * @throws IOException           Raised if an I/O error occurs.
1437          */
1438         @Override
1439         @SuppressWarnings("all")
1440         public DataChunk next() throws NotAvailableException, LoaderException, IOException {
1441 
1442             if (reader == null) {
1443                 throw new IOException();
1444             }
1445 
1446             if (!hasNext()) {
1447                 throw new NotAvailableException();
1448             }
1449 
1450             initChunkArrays();
1451 
1452             // reset chunk bounding box values
1453             minX = minY = minZ = Float.MAX_VALUE;
1454             maxX = maxY = maxZ = -Float.MAX_VALUE;
1455 
1456             final var buffer = ByteBuffer.allocate(BUFFER_SIZE);
1457 
1458             final var nElems = faceElement.getNumberOfInstances();
1459             final var progressStep = Math.max((long) (LoaderPLY.PROGRESS_DELTA * nElems), 1);
1460 
1461             var end = false;
1462 
1463             // initialize list indices to a list of one element to be reused
1464             var previousListElems = 1;
1465             var listIndices = new long[previousListElems];
1466 
1467             while ((currentFace < nElems) && !end) {
1468 
1469                 final var faceStreamPos = reader.getPosition();
1470                 // Iterate on properties
1471                 for (final var property : faceElement.getProperties()) {
1472                     if (!property.isValidProperty()) {
1473                         throw new LoaderException();
1474                     }
1475 
1476                     // number of elements in list (initially assume that is
1477                     // scalar, hence 1)
1478                     listElems = 1;
1479 
1480                     // set listeners to read property length value
1481                     PLYReadValueFromStreamListener readValueFromStreamListener =
1482                             property.getReadLengthValueFromStreamListener();
1483                     PLYReadValueFromBufferListener readValueFromBufferListener =
1484                             property.getReadLengthValueFromBufferListener();
1485 
1486                     if (property.getPropertyType() == PropertyTypePLY.PROPERTY_PLY_LIST) {
1487                         // read number of list elements
1488                         readValueFromStreamListener.readFromStream(buffer);
1489 
1490                         if (reader.isEndOfStream() && (currentFace < (nElems - 1))) {
1491                             throw new LoaderException();
1492                         }
1493 
1494                         // set listElems
1495                         readValueFromBufferListener.readValueFromBuffer(buffer);
1496                     }
1497 
1498                     var needsTriangulation = false;
1499                     if (listElems > 3) {
1500                         needsTriangulation = true;
1501                     } else if (listElems < 3) {
1502                         // list does not form a triangle or polygon
1503                         throw new LoaderException();
1504                     }
1505 
1506                     if (listElems > loader.maxVerticesInChunk) {
1507                         // this list will never fit in a chunk with current
1508                         // maxVerticesInChunk setting
1509                         throw new LoaderException();
1510                     }
1511 
1512                     if ((verticesInChunk + listElems) > loader.maxVerticesInChunk) {
1513                         // no more vertices can be added to chunk so we reset stream
1514                         // to start on current face
1515                         reader.seek(faceStreamPos);
1516                         end = true;
1517                         break;
1518                     }
1519 
1520                     // set listeners to read property value
1521                     readValueFromStreamListener = property.getReadValueFromStreamListener();
1522                     readValueFromBufferListener = property.getReadValueFromBufferListener();
1523 
1524                     if (previousListElems != listElems) {
1525                         // listIndices can no longer be reused
1526                         listIndices = new long[listElems];
1527                     }
1528 
1529                     // read property list data
1530                     for (var u = 0; u < listElems; u++) {
1531                         // reads face index from stream and saves it into buffer
1532                         readValueFromStreamListener.readFromStream(buffer);
1533 
1534                         if (reader.isEndOfStream() && (currentFace < (nElems - 1))) {
1535                             throw new LoaderException();
1536                         }
1537 
1538                         // copies buffer content into index member doing proper
1539                         // type conversion
1540                         readValueFromBufferListener.readValueFromBuffer(buffer);
1541 
1542                         listIndices[u] = index;
1543                     }
1544 
1545                     // keep current face stream position
1546                     currentStreamPosition = reader.getPosition();
1547 
1548                     if (needsTriangulation) {
1549                         // search vertices data corresponding to read indices
1550                         final var polygonVertices = new ArrayList<Point3D>(listElems);
1551                         for (var u = 0; u < listElems; u++) {
1552                             index = listIndices[u];
1553                             // vertex needs to be added into chunk, so we need to
1554                             // read vertex data
1555 
1556                             // fetch vertex data position
1557                             fetchVertexListener.fetch(index);
1558 
1559                             // read all vertex data
1560                             for (final var vertexProperty : vertexElement.getProperties()) {
1561 
1562                                 // set delegates to read property value from stream
1563                                 readValueFromStreamListener = vertexProperty.getReadValueFromStreamListener();
1564 
1565                                 // read property from stream to buffer
1566                                 readValueFromStreamListener.readFromStream(buffer);
1567 
1568                                 if (vertexProperty.isReadValueFromBufferListenerAvailable()) {
1569                                     // only read from buffer if property is recognized by this class
1570                                     readValueFromBufferListener = vertexProperty.getReadValueFromBufferListener();
1571 
1572                                     // move value from buffer to apropriate member
1573                                     readValueFromBufferListener.readValueFromBuffer(buffer);
1574                                 }
1575                             }
1576 
1577                             final var point = new InhomogeneousPoint3D(coordX, coordY, coordZ);
1578                             polygonVertices.add(point);
1579                         }
1580 
1581                         try {
1582                             listIndices = buildTriangulatedIndices(polygonVertices, listIndices);
1583                             listElems = listIndices.length;
1584                         } catch (final TriangulatorException e) {
1585                             // reset face stream position
1586                             reader.seek(currentStreamPosition);
1587                             continue;
1588                         }
1589                     }
1590 
1591                     // search for vertices indices contained in list
1592                     for (var u = 0; u < listElems; u++) {
1593                         index = listIndices[u];
1594                         // index contains original face index in PLY file
1595                         int chunkIndex;
1596                         if (!loader.allowDuplicateVerticesInChunk && (chunkIndex = searchIndexInChunk(index)) >= 0) {
1597                             // vertex is already stored in chunk with chunkIndex
1598                             addExistingVertexToChunk(chunkIndex);
1599                         } else {
1600                             // vertex needs to be added into chunk, so we need to
1601                             // read vertex data
1602 
1603                             // fetch vertex data position
1604                             fetchVertexListener.fetch(index);
1605 
1606                             // read all vertex data
1607                             for (final var vertexProperty : vertexElement.getProperties()) {
1608 
1609                                 // set delegates to read property value from stream
1610                                 readValueFromStreamListener = vertexProperty.getReadValueFromStreamListener();
1611 
1612                                 // read property from stream to buffer
1613                                 readValueFromStreamListener.readFromStream(buffer);
1614 
1615                                 if (vertexProperty.isReadValueFromBufferListenerAvailable()) {
1616                                     // only read from buffer if property is recognized by this class
1617                                     readValueFromBufferListener = vertexProperty.getReadValueFromBufferListener();
1618 
1619                                     // move value from buffer to apropriate member
1620                                     readValueFromBufferListener.readValueFromBuffer(buffer);
1621                                 }
1622                             }
1623 
1624                             // store all vertex data into chunk arrays
1625                             addNewVertexDataToChunk();
1626                         }
1627                     }
1628 
1629                     // reset face stream position
1630                     reader.seek(currentStreamPosition);
1631 
1632                     // to reduce memory consumption and delete listIndices
1633                     if (previousListElems != listElems) {
1634                         // list indices haven't been reused
1635 
1636                         // update previousListElems
1637                         previousListElems = listElems;
1638                     }
1639                 }
1640 
1641                 if (!end) {
1642                     currentFace++;
1643                 }
1644 
1645                 // compute progress
1646                 if (loader.listener != null) {
1647                     if ((currentFace % progressStep) == 0) {
1648                         loader.listener.onLoadProgressChange(loader, (float) (currentFace) / (float) (nElems));
1649                     }
1650                 }
1651             }
1652 
1653             // trim arrays to store only needed data
1654             trimArrays();
1655 
1656             // Instantiate DataChunk with chunk arrays
1657             final var dataChunk = new DataChunk();
1658             if (verticesAvailable) {
1659                 dataChunk.setVerticesCoordinatesData(coordsInChunkArray);
1660                 dataChunk.setMinX(minX);
1661                 dataChunk.setMinY(minY);
1662                 dataChunk.setMinZ(minZ);
1663                 dataChunk.setMaxX(maxX);
1664                 dataChunk.setMaxY(maxY);
1665                 dataChunk.setMaxZ(maxZ);
1666             } else {
1667                 // so it can be garbage collected
1668                 coordsInChunkArray = null;
1669             }
1670 
1671             if (colorsAvailable) {
1672                 dataChunk.setColorData(colorsInChunkArray);
1673                 dataChunk.setColorComponents(colorComponents);
1674             } else {
1675                 // so it can be garbage collected
1676                 colorsInChunkArray = null;
1677             }
1678 
1679             if (indicesAvailable) {
1680                 dataChunk.setIndicesData(indicesInChunkArray);
1681             } else {
1682                 // so it can be garbage collected
1683                 indicesInChunkArray = null;
1684             }
1685 
1686             if (normalsAvailable) {
1687                 dataChunk.setNormalsData(normalsInChunkArray);
1688             } else {
1689                 // so it can be garbage collected
1690                 normalsInChunkArray = null;
1691             }
1692 
1693             if (!hasNext()) {
1694                 // notify iterator finished
1695                 if (listener != null) {
1696                     listener.onIteratorFinished(this);
1697                 }
1698             }
1699 
1700             // if no more chunks are available, then close input reader
1701             if (!hasNext()) {
1702                 reader.close();
1703             }
1704 
1705             return dataChunk;
1706         }
1707 
1708         /**
1709          * Triangulates provided polygon having vertices corresponding to
1710          * provided indices and returns an array of indices corresponding to the
1711          * triangles forming the polygon.
1712          *
1713          * @param polygonVertices vertices forming a polygon to be triangulated.
1714          * @param plyIndices      indices corresponding to provided polygon.
1715          * @return array of indices corresponding to the triangles forming the
1716          * polygon.
1717          * @throws TriangulatorException if triangulation fails because polygon
1718          *                               is degenerate or vertices contains invalid values such as NaN or
1719          *                               infinity.
1720          */
1721         private long[] buildTriangulatedIndices(final List<Point3D> polygonVertices, final long[] plyIndices)
1722                 throws TriangulatorException {
1723 
1724             final var indices = new ArrayList<int[]>();
1725             final var triangulator = Triangulator3D.create();
1726             final var triangles = triangulator.triangulate(polygonVertices, indices);
1727 
1728             final var result = new long[triangles.size() * 3];
1729             var pos = 0;
1730             long plyIndex;
1731             for (final var triangleIndices : indices) {
1732                 for (final var triangleIndex : triangleIndices) {
1733                     plyIndex = plyIndices[triangleIndex];
1734                     result[pos] = plyIndex;
1735                     pos++;
1736                 }
1737             }
1738 
1739             return result;
1740         }
1741 
1742 
1743         /**
1744          * Initializes arrays where chunk data will be stored.
1745          */
1746         private void initChunkArrays() {
1747             coordsInChunkArray = new float[loader.maxVerticesInChunk * 3];
1748             colorsInChunkArray = new short[loader.maxVerticesInChunk * colorComponents];
1749             indicesInChunkArray = new int[loader.maxVerticesInChunk];
1750             originalIndicesInChunkArray = new long[loader.maxVerticesInChunk];
1751             normalsInChunkArray = new float[loader.maxVerticesInChunk * 3];
1752             verticesInChunk = 0;
1753             indicesInChunk = 0;
1754             indicesInChunkSize = loader.maxVerticesInChunk;
1755             indicesMap.clear();
1756         }
1757 
1758         /**
1759          * Searches corresponding index in chunk for provided stream vertex
1760          * index.
1761          *
1762          * @param originalIndex Index in original stream of data.
1763          * @return Vertex index in current chunk of data.
1764          */
1765         private int searchIndexInChunk(final long originalIndex) {
1766             final var chunkIndex = indicesMap.get(originalIndex);
1767 
1768             if (chunkIndex == null) {
1769                 return -1;
1770             }
1771 
1772             return indicesInChunkArray[chunkIndex];
1773         }
1774 
1775         /**
1776          * Caches provided vertex index to relate it to given stream position
1777          * where vertex data can be found.
1778          * This method only has effect for ASCII PLY files.
1779          *
1780          * @param originalIndex  Vertex index in original stream of data.
1781          * @param streamPosition Stream position where vertex is found.
1782          */
1783         private void addVertexPositionToMap(final long originalIndex, final long streamPosition) {
1784             if (loader.header.getStorageMode() == PLYStorageMode.PLY_ASCII) {
1785                 if (verticesStreamPositionsMap.size() > loader.maxStreamPositions) {
1786                     // Map is full. Remove 1st item before adding a new one
1787                     final var origIndex = verticesStreamPositionsMap.firstKey();
1788                     verticesStreamPositionsMap.remove(origIndex);
1789                 }
1790                 // add new item
1791                 verticesStreamPositionsMap.put(originalIndex, streamPosition);
1792             }
1793         }
1794 
1795         /**
1796          * Adds data of last vertex that has been read to the arrays of current
1797          * chunk of data.
1798          */
1799         private void addNewVertexDataToChunk() {
1800             var pos = 3 * verticesInChunk;
1801             var colorPos = colorComponents * verticesInChunk;
1802             coordsInChunkArray[pos] = coordX;
1803             normalsInChunkArray[pos] = nX;
1804             if (colorComponents >= 1) {
1805                 colorsInChunkArray[colorPos] = red;
1806             }
1807 
1808             pos++;
1809             colorPos++;
1810 
1811             coordsInChunkArray[pos] = coordY;
1812             normalsInChunkArray[pos] = nY;
1813             if (colorComponents >= 2) {
1814                 colorsInChunkArray[colorPos] = green;
1815             }
1816 
1817             pos++;
1818             colorPos++;
1819 
1820             coordsInChunkArray[pos] = coordZ;
1821             normalsInChunkArray[pos] = nZ;
1822             if (colorComponents >= 3) {
1823                 colorsInChunkArray[colorPos] = blue;
1824             }
1825 
1826             if (colorComponents >= 4) {
1827                 colorPos++;
1828                 colorsInChunkArray[colorPos] = alpha;
1829             }
1830 
1831             // update bounding box values
1832             if (coordX < minX) {
1833                 minX = coordX;
1834             }
1835             if (coordY < minY) {
1836                 minY = coordY;
1837             }
1838             if (coordZ < minZ) {
1839                 minZ = coordZ;
1840             }
1841 
1842             if (coordX > maxX) {
1843                 maxX = coordX;
1844             }
1845             if (coordY > maxY) {
1846                 maxY = coordY;
1847             }
1848             if (coordZ > maxZ) {
1849                 maxZ = coordZ;
1850             }
1851 
1852             // if arrays of indices become full, we need to resize them
1853             if (indicesInChunk >= indicesInChunkSize) {
1854                 increaseIndicesArraySize();
1855             }
1856             indicesInChunkArray[indicesInChunk] = verticesInChunk;
1857             originalIndicesInChunkArray[indicesInChunk] = index;
1858             // store original index in map, so we can search chunk index by
1859             // original index
1860             indicesMap.put(index, indicesInChunk);
1861 
1862             // store vertex stream position in ascii mode
1863             addVertexPositionToMap(index, vertexStreamPosition);
1864 
1865             verticesInChunk++;
1866             indicesInChunk++;
1867         }
1868 
1869         /**
1870          * Adds provided vertex index into chunk of data.
1871          * This method is only called when duplicate vertices are allowed in
1872          * chunks of data.
1873          *
1874          * @param existingIndex Index to be added into chunk.
1875          */
1876         private void addExistingVertexToChunk(final int existingIndex) {
1877             // if arrays of indices become full, we need to resize them
1878             if (indicesInChunk >= indicesInChunkSize) {
1879                 increaseIndicesArraySize();
1880             }
1881             indicesInChunkArray[indicesInChunk] = existingIndex;
1882             originalIndicesInChunkArray[indicesInChunk] = index;
1883 
1884             indicesInChunk++;
1885         }
1886 
1887         /**
1888          * This method increases the size of arrays containing data of current
1889          * chunk. This method is called when arrays get full and need to be
1890          * enlarged.
1891          */
1892         private void increaseIndicesArraySize() {
1893             final var newIndicesInChunkSize = indicesInChunkSize + loader.maxVerticesInChunk;
1894             final var newIndicesInChunkArray = new int[newIndicesInChunkSize];
1895             final var newOriginalIndicesInChunkArray = new long[newIndicesInChunkSize];
1896 
1897             // copy contents of old arrays
1898             System.arraycopy(indicesInChunkArray, 0, newIndicesInChunkArray, 0, indicesInChunkSize);
1899             System.arraycopy(originalIndicesInChunkArray, 0, newOriginalIndicesInChunkArray, 0,
1900                     indicesInChunkSize);
1901 
1902             // set new arrays and new size
1903             indicesInChunkArray = newIndicesInChunkArray;
1904             originalIndicesInChunkArray = newOriginalIndicesInChunkArray;
1905             indicesInChunkSize = newIndicesInChunkSize;
1906         }
1907 
1908         /**
1909          * This method removes unnecessary data of arrays.
1910          * This method is called when finishing the processing of current chunk
1911          * of data.
1912          */
1913         private void trimArrays() {
1914             if (verticesInChunk > 0) {
1915                 final var elems = verticesInChunk * 3;
1916                 final var colorElems = verticesInChunk * colorComponents;
1917 
1918                 final var newCoordsInChunkArray = new float[elems];
1919                 final var newColorsInChunkArray = new short[colorElems];
1920                 final var newNormalsInChunkArray = new float[elems];
1921 
1922                 // copy contents of old arrays
1923                 System.arraycopy(coordsInChunkArray, 0, newCoordsInChunkArray, 0, elems);
1924                 System.arraycopy(colorsInChunkArray, 0, newColorsInChunkArray, 0, colorElems);
1925                 System.arraycopy(normalsInChunkArray, 0, newNormalsInChunkArray, 0, elems);
1926 
1927                 // set new arrays
1928                 coordsInChunkArray = newCoordsInChunkArray;
1929                 colorsInChunkArray = newColorsInChunkArray;
1930                 normalsInChunkArray = newNormalsInChunkArray;
1931             } else {
1932                 // allow garbage collection
1933                 coordsInChunkArray = null;
1934                 colorsInChunkArray = null;
1935                 normalsInChunkArray = null;
1936             }
1937 
1938             if (indicesInChunk > 0) {
1939                 final var newIndicesInChunkArray = new int[indicesInChunk];
1940                 System.arraycopy(indicesInChunkArray, 0, newIndicesInChunkArray, 0, indicesInChunk);
1941 
1942                 // set new array
1943                 indicesInChunkArray = newIndicesInChunkArray;
1944             } else {
1945                 // allow garbage collection
1946                 indicesInChunkArray = null;
1947                 originalIndicesInChunkArray = null;
1948             }
1949         }
1950 
1951         /**
1952          * Reads header data to set up listeners capable of reading stream data
1953          * according to data types contained in header.
1954          *
1955          * @throws LoaderException Raised if file is corrupted (header is
1956          *                         invalid).
1957          * @throws IOException     if an I/O error occurs.
1958          */
1959         private void setUp() throws LoaderException, IOException {
1960             endHeaderStreamPosition = reader.getPosition();
1961             var streamPositionOffset = endHeaderStreamPosition;
1962 
1963             // read header to set up listeners
1964             try {
1965                 totalInstances = 0;
1966                 colorComponents = 0;
1967                 for (final var element : loader.header.getElements()) {
1968                     if (!element.isValidElement()) {
1969                         throw new LoaderException();
1970                     }
1971                     totalInstances += element.getNumberOfInstances();
1972 
1973                     if ("vertex".equals(element.getName())) {
1974                         vertexElement = element;
1975 
1976                         // obtain position of first vertex
1977 
1978                         // obtain number of vertices
1979                         numberOfVertices = element.getNumberOfInstances();
1980 
1981                         vertexDataSize = 0;
1982                         for (final var property : element.getProperties()) {
1983 
1984                             // set listener to read data from stream
1985                             setReadValueFromStreamListener(property, loader.header.getStorageMode());
1986 
1987                             // set listener to read data stored in buffer
1988                             switch (property.getName()) {
1989                                 case "x":
1990                                     verticesAvailable = true;
1991                                     switch (property.getValueType()) {
1992                                         case PLY_INT8:
1993                                             property.setReadValueFromBufferListener(
1994                                                     new Xint8ReadValueFromBufferListener());
1995                                             break;
1996                                         case PLY_UINT8:
1997                                             property.setReadValueFromBufferListener(
1998                                                     new Xuint8ReadValueFromBufferListener());
1999                                             break;
2000                                         case PLY_INT16:
2001                                             property.setReadValueFromBufferListener(
2002                                                     new Xint16ReadValueFromBufferListener());
2003                                             break;
2004                                         case PLY_UINT16:
2005                                             property.setReadValueFromBufferListener(
2006                                                     new Xuint16ReadValueFromBufferListener());
2007                                             break;
2008                                         case PLY_INT32:
2009                                             property.setReadValueFromBufferListener(
2010                                                     new Xint32ReadValueFromBufferListener());
2011                                             break;
2012                                         case PLY_UINT32:
2013                                             property.setReadValueFromBufferListener(
2014                                                     new Xuint32ReadValueFromBufferListener());
2015                                             break;
2016                                         case PLY_FLOAT32:
2017                                             property.setReadValueFromBufferListener(
2018                                                     new Xfloat32ReadValueFromBufferListener());
2019                                             break;
2020                                         case PLY_FLOAT64:
2021                                             property.setReadValueFromBufferListener(
2022                                                     new Xfloat64ReadValueFromBufferListener());
2023                                             break;
2024                                         case PLY_CHAR:
2025                                             property.setReadValueFromBufferListener(
2026                                                     new XcharReadValueFromBufferListener());
2027                                             break;
2028                                         case PLY_UCHAR:
2029                                             property.setReadValueFromBufferListener(
2030                                                     new XucharReadValueFromBufferListener());
2031                                             break;
2032                                         case PLY_SHORT:
2033                                             property.setReadValueFromBufferListener(
2034                                                     new XshortReadValueFromBufferListener());
2035                                             break;
2036                                         case PLY_USHORT:
2037                                             property.setReadValueFromBufferListener(
2038                                                     new XushortReadValueFromBufferListener());
2039                                             break;
2040                                         case PLY_INT:
2041                                             property.setReadValueFromBufferListener(
2042                                                     new XintReadValueFromBufferListener());
2043                                             break;
2044                                         case PLY_UINT:
2045                                             property.setReadValueFromBufferListener(
2046                                                     new XuintReadValueFromBufferListener());
2047                                             break;
2048                                         case PLY_FLOAT:
2049                                             property.setReadValueFromBufferListener(
2050                                                     new XfloatReadValueFromBufferListener());
2051                                             break;
2052                                         case PLY_DOUBLE:
2053                                             property.setReadValueFromBufferListener(
2054                                                     new XdoubleReadValueFromBufferListener());
2055                                             break;
2056                                         default:
2057                                             throw new LoaderException();
2058                                     }
2059                                     break;
2060                                 case "y":
2061                                     verticesAvailable = true;
2062                                     switch (property.getValueType()) {
2063                                         case PLY_INT8:
2064                                             property.setReadValueFromBufferListener(
2065                                                     new Yint8ReadValueFromBufferListener());
2066                                             break;
2067                                         case PLY_UINT8:
2068                                             property.setReadValueFromBufferListener(
2069                                                     new Yuint8ReadValueFromBufferListener());
2070                                             break;
2071                                         case PLY_INT16:
2072                                             property.setReadValueFromBufferListener(
2073                                                     new Yint16ReadValueFromBufferListener());
2074                                             break;
2075                                         case PLY_UINT16:
2076                                             property.setReadValueFromBufferListener(
2077                                                     new Yuint16ReadValueFromBufferListener());
2078                                             break;
2079                                         case PLY_INT32:
2080                                             property.setReadValueFromBufferListener(
2081                                                     new Yint32ReadValueFromBufferListener());
2082                                             break;
2083                                         case PLY_UINT32:
2084                                             property.setReadValueFromBufferListener(
2085                                                     new Yuint32ReadValueFromBufferListener());
2086                                             break;
2087                                         case PLY_FLOAT32:
2088                                             property.setReadValueFromBufferListener(
2089                                                     new Yfloat32ReadValueFromBufferListener());
2090                                             break;
2091                                         case PLY_FLOAT64:
2092                                             property.setReadValueFromBufferListener(
2093                                                     new Yfloat64ReadValueFromBufferListener());
2094                                             break;
2095                                         case PLY_CHAR:
2096                                             property.setReadValueFromBufferListener(
2097                                                     new YcharReadValueFromBufferListener());
2098                                             break;
2099                                         case PLY_UCHAR:
2100                                             property.setReadValueFromBufferListener(
2101                                                     new YucharReadValueFromBufferListener());
2102                                             break;
2103                                         case PLY_SHORT:
2104                                             property.setReadValueFromBufferListener(
2105                                                     new YshortReadValueFromBufferListener());
2106                                             break;
2107                                         case PLY_USHORT:
2108                                             property.setReadValueFromBufferListener(
2109                                                     new YushortReadValueFromBufferListener());
2110                                             break;
2111                                         case PLY_INT:
2112                                             property.setReadValueFromBufferListener(
2113                                                     new YintReadValueFromBufferListener());
2114                                             break;
2115                                         case PLY_UINT:
2116                                             property.setReadValueFromBufferListener(
2117                                                     new YuintReadValueFromBufferListener());
2118                                             break;
2119                                         case PLY_FLOAT:
2120                                             property.setReadValueFromBufferListener(
2121                                                     new YfloatReadValueFromBufferListener());
2122                                             break;
2123                                         case PLY_DOUBLE:
2124                                             property.setReadValueFromBufferListener(
2125                                                     new YdoubleReadValueFromBufferListener());
2126                                             break;
2127                                         default:
2128                                             throw new LoaderException();
2129                                     }
2130                                     break;
2131                                 case "z":
2132                                     verticesAvailable = true;
2133                                     switch (property.getValueType()) {
2134                                         case PLY_INT8:
2135                                             property.setReadValueFromBufferListener(
2136                                                     new Zint8ReadValueFromBufferListener());
2137                                             break;
2138                                         case PLY_UINT8:
2139                                             property.setReadValueFromBufferListener(
2140                                                     new Zuint8ReadValueFromBufferListener());
2141                                             break;
2142                                         case PLY_INT16:
2143                                             property.setReadValueFromBufferListener(
2144                                                     new Zint16ReadValueFromBufferListener());
2145                                             break;
2146                                         case PLY_UINT16:
2147                                             property.setReadValueFromBufferListener(
2148                                                     new Zuint16ReadValueFromBufferListener());
2149                                             break;
2150                                         case PLY_INT32:
2151                                             property.setReadValueFromBufferListener(
2152                                                     new Zint32ReadValueFromBufferListener());
2153                                             break;
2154                                         case PLY_UINT32:
2155                                             property.setReadValueFromBufferListener(
2156                                                     new Zuint32ReadValueFromBufferListener());
2157                                             break;
2158                                         case PLY_FLOAT32:
2159                                             property.setReadValueFromBufferListener(
2160                                                     new Zfloat32ReadValueFromBufferListener());
2161                                             break;
2162                                         case PLY_FLOAT64:
2163                                             property.setReadValueFromBufferListener(
2164                                                     new Zfloat64ReadValueFromBufferListener());
2165                                             break;
2166                                         case PLY_CHAR:
2167                                             property.setReadValueFromBufferListener(
2168                                                     new ZcharReadValueFromBufferListener());
2169                                             break;
2170                                         case PLY_UCHAR:
2171                                             property.setReadValueFromBufferListener(
2172                                                     new ZucharReadValueFromBufferListener());
2173                                             break;
2174                                         case PLY_SHORT:
2175                                             property.setReadValueFromBufferListener(
2176                                                     new ZshortReadValueFromBufferListener());
2177                                             break;
2178                                         case PLY_USHORT:
2179                                             property.setReadValueFromBufferListener(
2180                                                     new ZushortReadValueFromBufferListener());
2181                                             break;
2182                                         case PLY_INT:
2183                                             property.setReadValueFromBufferListener(
2184                                                     new ZintReadValueFromBufferListener());
2185                                             break;
2186                                         case PLY_UINT:
2187                                             property.setReadValueFromBufferListener(
2188                                                     new ZuintReadValueFromBufferListener());
2189                                             break;
2190                                         case PLY_FLOAT:
2191                                             property.setReadValueFromBufferListener(
2192                                                     new ZfloatReadValueFromBufferListener());
2193                                             break;
2194                                         case PLY_DOUBLE:
2195                                             property.setReadValueFromBufferListener(
2196                                                     new ZdoubleReadValueFromBufferListener());
2197                                             break;
2198                                         default:
2199                                             throw new LoaderException();
2200                                     }
2201                                     break;
2202                                 case "nx":
2203                                     normalsAvailable = true;
2204                                     switch (property.getValueType()) {
2205                                         case PLY_INT8:
2206                                             property.setReadValueFromBufferListener(
2207                                                     new NXint8ReadValueFromBufferListener());
2208                                             break;
2209                                         case PLY_UINT8:
2210                                             property.setReadValueFromBufferListener(
2211                                                     new NXuint8ReadValueFromBufferListener());
2212                                             break;
2213                                         case PLY_INT16:
2214                                             property.setReadValueFromBufferListener(
2215                                                     new NXint16ReadValueFromBufferListener());
2216                                             break;
2217                                         case PLY_UINT16:
2218                                             property.setReadValueFromBufferListener(
2219                                                     new NXuint16ReadValueFromBufferListener());
2220                                             break;
2221                                         case PLY_INT32:
2222                                             property.setReadValueFromBufferListener(
2223                                                     new NXint32ReadValueFromBufferListener());
2224                                             break;
2225                                         case PLY_UINT32:
2226                                             property.setReadValueFromBufferListener(
2227                                                     new NXuint32ReadValueFromBufferListener());
2228                                             break;
2229                                         case PLY_FLOAT32:
2230                                             property.setReadValueFromBufferListener(
2231                                                     new NXfloat32ReadValueFromBufferListener());
2232                                             break;
2233                                         case PLY_FLOAT64:
2234                                             property.setReadValueFromBufferListener(
2235                                                     new NXfloat64ReadValueFromBufferListener());
2236                                             break;
2237                                         case PLY_CHAR:
2238                                             property.setReadValueFromBufferListener(
2239                                                     new NXcharReadValueFromBufferListener());
2240                                             break;
2241                                         case PLY_UCHAR:
2242                                             property.setReadValueFromBufferListener(
2243                                                     new NXucharReadValueFromBufferListener());
2244                                             break;
2245                                         case PLY_SHORT:
2246                                             property.setReadValueFromBufferListener(
2247                                                     new NXshortReadValueFromBufferListener());
2248                                             break;
2249                                         case PLY_USHORT:
2250                                             property.setReadValueFromBufferListener(
2251                                                     new NXushortReadValueFromBufferListener());
2252                                             break;
2253                                         case PLY_INT:
2254                                             property.setReadValueFromBufferListener(
2255                                                     new NXintReadValueFromBufferListener());
2256                                             break;
2257                                         case PLY_UINT:
2258                                             property.setReadValueFromBufferListener(
2259                                                     new NXuintReadValueFromBufferListener());
2260                                             break;
2261                                         case PLY_FLOAT:
2262                                             property.setReadValueFromBufferListener(
2263                                                     new NXfloatReadValueFromBufferListener());
2264                                             break;
2265                                         case PLY_DOUBLE:
2266                                             property.setReadValueFromBufferListener(
2267                                                     new NXdoubleReadValueFromBufferListener());
2268                                             break;
2269                                         default:
2270                                             throw new LoaderException();
2271                                     }
2272                                     break;
2273                                 case "ny":
2274                                     normalsAvailable = true;
2275                                     switch (property.getValueType()) {
2276                                         case PLY_INT8:
2277                                             property.setReadValueFromBufferListener(
2278                                                     new NYint8ReadValueFromBufferListener());
2279                                             break;
2280                                         case PLY_UINT8:
2281                                             property.setReadValueFromBufferListener(
2282                                                     new NYuint8ReadValueFromBufferListener());
2283                                             break;
2284                                         case PLY_INT16:
2285                                             property.setReadValueFromBufferListener(
2286                                                     new NYint16ReadValueFromBufferListener());
2287                                             break;
2288                                         case PLY_UINT16:
2289                                             property.setReadValueFromBufferListener(
2290                                                     new NYuint16ReadValueFromBufferListener());
2291                                             break;
2292                                         case PLY_INT32:
2293                                             property.setReadValueFromBufferListener(
2294                                                     new NYint32ReadValueFromBufferListener());
2295                                             break;
2296                                         case PLY_UINT32:
2297                                             property.setReadValueFromBufferListener(
2298                                                     new NYuint32ReadValueFromBufferListener());
2299                                             break;
2300                                         case PLY_FLOAT32:
2301                                             property.setReadValueFromBufferListener(
2302                                                     new NYfloat32ReadValueFromBufferListener());
2303                                             break;
2304                                         case PLY_FLOAT64:
2305                                             property.setReadValueFromBufferListener(
2306                                                     new NYfloat64ReadValueFromBufferListener());
2307                                             break;
2308                                         case PLY_CHAR:
2309                                             property.setReadValueFromBufferListener(
2310                                                     new NYcharReadValueFromBufferListener());
2311                                             break;
2312                                         case PLY_UCHAR:
2313                                             property.setReadValueFromBufferListener(
2314                                                     new NYucharReadValueFromBufferListener());
2315                                             break;
2316                                         case PLY_SHORT:
2317                                             property.setReadValueFromBufferListener(
2318                                                     new NYshortReadValueFromBufferListener());
2319                                             break;
2320                                         case PLY_USHORT:
2321                                             property.setReadValueFromBufferListener(
2322                                                     new NYushortReadValueFromBufferListener());
2323                                             break;
2324                                         case PLY_INT:
2325                                             property.setReadValueFromBufferListener(
2326                                                     new NYintReadValueFromBufferListener());
2327                                             break;
2328                                         case PLY_UINT:
2329                                             property.setReadValueFromBufferListener(
2330                                                     new NYuintReadValueFromBufferListener());
2331                                             break;
2332                                         case PLY_FLOAT:
2333                                             property.setReadValueFromBufferListener(
2334                                                     new NYfloatReadValueFromBufferListener());
2335                                             break;
2336                                         case PLY_DOUBLE:
2337                                             property.setReadValueFromBufferListener(
2338                                                     new NYdoubleReadValueFromBufferListener());
2339                                             break;
2340                                         default:
2341                                             throw new LoaderException();
2342                                     }
2343                                     break;
2344                                 case "nz":
2345                                     normalsAvailable = true;
2346                                     switch (property.getValueType()) {
2347                                         case PLY_INT8:
2348                                             property.setReadValueFromBufferListener(
2349                                                     new NZint8ReadValueFromBufferListener());
2350                                             break;
2351                                         case PLY_UINT8:
2352                                             property.setReadValueFromBufferListener(
2353                                                     new NZuint8ReadValueFromBufferListener());
2354                                             break;
2355                                         case PLY_INT16:
2356                                             property.setReadValueFromBufferListener(
2357                                                     new NZint16ReadValueFromBufferListener());
2358                                             break;
2359                                         case PLY_UINT16:
2360                                             property.setReadValueFromBufferListener(
2361                                                     new NZuint16ReadValueFromBufferListener());
2362                                             break;
2363                                         case PLY_INT32:
2364                                             property.setReadValueFromBufferListener(
2365                                                     new NZint32ReadValueFromBufferListener());
2366                                             break;
2367                                         case PLY_UINT32:
2368                                             property.setReadValueFromBufferListener(
2369                                                     new NZuint32ReadValueFromBufferListener());
2370                                             break;
2371                                         case PLY_FLOAT32:
2372                                             property.setReadValueFromBufferListener(
2373                                                     new NZfloat32ReadValueFromBufferListener());
2374                                             break;
2375                                         case PLY_FLOAT64:
2376                                             property.setReadValueFromBufferListener(
2377                                                     new NZfloat64ReadValueFromBufferListener());
2378                                             break;
2379                                         case PLY_CHAR:
2380                                             property.setReadValueFromBufferListener(
2381                                                     new NZcharReadValueFromBufferListener());
2382                                             break;
2383                                         case PLY_UCHAR:
2384                                             property.setReadValueFromBufferListener(
2385                                                     new NZucharReadValueFromBufferListener());
2386                                             break;
2387                                         case PLY_SHORT:
2388                                             property.setReadValueFromBufferListener(
2389                                                     new NZshortReadValueFromBufferListener());
2390                                             break;
2391                                         case PLY_USHORT:
2392                                             property.setReadValueFromBufferListener(
2393                                                     new NZushortReadValueFromBufferListener());
2394                                             break;
2395                                         case PLY_INT:
2396                                             property.setReadValueFromBufferListener(
2397                                                     new NZintReadValueFromBufferListener());
2398                                             break;
2399                                         case PLY_UINT:
2400                                             property.setReadValueFromBufferListener(
2401                                                     new NZuintReadValueFromBufferListener());
2402                                             break;
2403                                         case PLY_FLOAT:
2404                                             property.setReadValueFromBufferListener(
2405                                                     new NZfloatReadValueFromBufferListener());
2406                                             break;
2407                                         case PLY_DOUBLE:
2408                                             property.setReadValueFromBufferListener(
2409                                                     new NZdoubleReadValueFromBufferListener());
2410                                             break;
2411                                         default:
2412                                             throw new LoaderException();
2413                                     }
2414                                     break;
2415                                 case "red":
2416                                     colorsAvailable = true;
2417                                     colorComponents++;
2418                                     switch (property.getValueType()) {
2419                                         case PLY_INT8:
2420                                             property.setReadValueFromBufferListener(
2421                                                     new RedInt8ReadValueFromBufferListener());
2422                                             break;
2423                                         case PLY_UINT8:
2424                                             property.setReadValueFromBufferListener(
2425                                                     new RedUint8ReadValueFromBufferListener());
2426                                             break;
2427                                         case PLY_INT16:
2428                                             property.setReadValueFromBufferListener(
2429                                                     new RedInt16ReadValueFromBufferListener());
2430                                             break;
2431                                         case PLY_UINT16:
2432                                             property.setReadValueFromBufferListener(
2433                                                     new RedUint16ReadValueFromBufferListener());
2434                                             break;
2435                                         case PLY_INT32:
2436                                             property.setReadValueFromBufferListener(
2437                                                     new RedInt32ReadValueFromBufferListener());
2438                                             break;
2439                                         case PLY_UINT32:
2440                                             property.setReadValueFromBufferListener(
2441                                                     new RedUint32ReadValueFromBufferListener());
2442                                             break;
2443                                         case PLY_FLOAT32:
2444                                             property.setReadValueFromBufferListener(
2445                                                     new RedFloat32ReadValueFromBufferListener());
2446                                             break;
2447                                         case PLY_FLOAT64:
2448                                             property.setReadValueFromBufferListener(
2449                                                     new RedFloat64ReadValueFromBufferListener());
2450                                             break;
2451                                         case PLY_CHAR:
2452                                             property.setReadValueFromBufferListener(
2453                                                     new RedCharReadValueFromBufferListener());
2454                                             break;
2455                                         case PLY_UCHAR:
2456                                             property.setReadValueFromBufferListener(
2457                                                     new RedUcharReadValueFromBufferListener());
2458                                             break;
2459                                         case PLY_SHORT:
2460                                             property.setReadValueFromBufferListener(
2461                                                     new RedShortReadValueFromBufferListener());
2462                                             break;
2463                                         case PLY_USHORT:
2464                                             property.setReadValueFromBufferListener(
2465                                                     new RedUshortReadValueFromBufferListener());
2466                                             break;
2467                                         case PLY_INT:
2468                                             property.setReadValueFromBufferListener(
2469                                                     new RedIntReadValueFromBufferListener());
2470                                             break;
2471                                         case PLY_UINT:
2472                                             property.setReadValueFromBufferListener(
2473                                                     new RedUintReadValueFromBufferListener());
2474                                             break;
2475                                         case PLY_FLOAT:
2476                                             property.setReadValueFromBufferListener(
2477                                                     new RedFloatReadValueFromBufferListener());
2478                                             break;
2479                                         case PLY_DOUBLE:
2480                                             property.setReadValueFromBufferListener(
2481                                                     new RedDoubleReadValueFromBufferListener());
2482                                             break;
2483                                         default:
2484                                             throw new LoaderException();
2485                                     }
2486                                     break;
2487                                 case "green":
2488                                     colorsAvailable = true;
2489                                     colorComponents++;
2490                                     switch (property.getValueType()) {
2491                                         case PLY_INT8:
2492                                             property.setReadValueFromBufferListener(
2493                                                     new GreenInt8ReadValueFromBufferListener());
2494                                             break;
2495                                         case PLY_UINT8:
2496                                             property.setReadValueFromBufferListener(
2497                                                     new GreenUint8ReadValueFromBufferListener());
2498                                             break;
2499                                         case PLY_INT16:
2500                                             property.setReadValueFromBufferListener(
2501                                                     new GreenInt16ReadValueFromBufferListener());
2502                                             break;
2503                                         case PLY_UINT16:
2504                                             property.setReadValueFromBufferListener(
2505                                                     new GreenUint16ReadValueFromBufferListener());
2506                                             break;
2507                                         case PLY_INT32:
2508                                             property.setReadValueFromBufferListener(
2509                                                     new GreenInt32ReadValueFromBufferListener());
2510                                             break;
2511                                         case PLY_UINT32:
2512                                             property.setReadValueFromBufferListener(
2513                                                     new GreenUint32ReadValueFromBufferListener());
2514                                             break;
2515                                         case PLY_FLOAT32:
2516                                             property.setReadValueFromBufferListener(
2517                                                     new GreenFloat32ReadValueFromBufferListener());
2518                                             break;
2519                                         case PLY_FLOAT64:
2520                                             property.setReadValueFromBufferListener(
2521                                                     new GreenFloat64ReadValueFromBufferListener());
2522                                             break;
2523                                         case PLY_CHAR:
2524                                             property.setReadValueFromBufferListener(
2525                                                     new GreenCharReadValueFromBufferListener());
2526                                             break;
2527                                         case PLY_UCHAR:
2528                                             property.setReadValueFromBufferListener(
2529                                                     new GreenUcharReadValueFromBufferListener());
2530                                             break;
2531                                         case PLY_SHORT:
2532                                             property.setReadValueFromBufferListener(
2533                                                     new GreenShortReadValueFromBufferListener());
2534                                             break;
2535                                         case PLY_USHORT:
2536                                             property.setReadValueFromBufferListener(
2537                                                     new GreenUshortReadValueFromBufferListener());
2538                                             break;
2539                                         case PLY_INT:
2540                                             property.setReadValueFromBufferListener(
2541                                                     new GreenIntReadValueFromBufferListener());
2542                                             break;
2543                                         case PLY_UINT:
2544                                             property.setReadValueFromBufferListener(
2545                                                     new GreenUintReadValueFromBufferListener());
2546                                             break;
2547                                         case PLY_FLOAT:
2548                                             property.setReadValueFromBufferListener(
2549                                                     new GreenFloatReadValueFromBufferListener());
2550                                             break;
2551                                         case PLY_DOUBLE:
2552                                             property.setReadValueFromBufferListener(
2553                                                     new GreenDoubleReadValueFromBufferListener());
2554                                             break;
2555                                         default:
2556                                             throw new LoaderException();
2557                                     }
2558                                     break;
2559                                 case "blue":
2560                                     colorsAvailable = true;
2561                                     colorComponents++;
2562                                     switch (property.getValueType()) {
2563                                         case PLY_INT8:
2564                                             property.setReadValueFromBufferListener(
2565                                                     new BlueInt8ReadValueFromBufferListener());
2566                                             break;
2567                                         case PLY_UINT8:
2568                                             property.setReadValueFromBufferListener(
2569                                                     new BlueUint8ReadValueFromBufferListener());
2570                                             break;
2571                                         case PLY_INT16:
2572                                             property.setReadValueFromBufferListener(
2573                                                     new BlueInt16ReadValueFromBufferListener());
2574                                             break;
2575                                         case PLY_UINT16:
2576                                             property.setReadValueFromBufferListener(
2577                                                     new BlueUint16ReadValueFromBufferListener());
2578                                             break;
2579                                         case PLY_INT32:
2580                                             property.setReadValueFromBufferListener(
2581                                                     new BlueInt32ReadValueFromBufferListener());
2582                                             break;
2583                                         case PLY_UINT32:
2584                                             property.setReadValueFromBufferListener(
2585                                                     new BlueUint32ReadValueFromBufferListener());
2586                                             break;
2587                                         case PLY_FLOAT32:
2588                                             property.setReadValueFromBufferListener(
2589                                                     new BlueFloat32ReadValueFromBufferListener());
2590                                             break;
2591                                         case PLY_FLOAT64:
2592                                             property.setReadValueFromBufferListener(
2593                                                     new BlueFloat64ReadValueFromBufferListener());
2594                                             break;
2595                                         case PLY_CHAR:
2596                                             property.setReadValueFromBufferListener(
2597                                                     new BlueCharReadValueFromBufferListener());
2598                                             break;
2599                                         case PLY_UCHAR:
2600                                             property.setReadValueFromBufferListener(
2601                                                     new BlueUcharReadValueFromBufferListener());
2602                                             break;
2603                                         case PLY_SHORT:
2604                                             property.setReadValueFromBufferListener(
2605                                                     new BlueShortReadValueFromBufferListener());
2606                                             break;
2607                                         case PLY_USHORT:
2608                                             property.setReadValueFromBufferListener(
2609                                                     new BlueUshortReadValueFromBufferListener());
2610                                             break;
2611                                         case PLY_INT:
2612                                             property.setReadLengthValueFromBufferListener(
2613                                                     new BlueIntReadValueFromBufferListener());
2614                                             break;
2615                                         case PLY_UINT:
2616                                             property.setReadValueFromBufferListener(
2617                                                     new BlueUintReadValueFromBufferListener());
2618                                             break;
2619                                         case PLY_FLOAT:
2620                                             property.setReadValueFromBufferListener(
2621                                                     new BlueFloatReadValueFromBufferListener());
2622                                             break;
2623                                         case PLY_DOUBLE:
2624                                             property.setReadValueFromBufferListener(
2625                                                     new BlueDoubleReadValueFromBufferListener());
2626                                             break;
2627                                         default:
2628                                             throw new LoaderException();
2629                                     }
2630                                     break;
2631                                 case "alpha":
2632                                     colorsAvailable = true;
2633                                     colorComponents++;
2634                                     switch (property.getValueType()) {
2635                                         case PLY_INT8:
2636                                             property.setReadValueFromBufferListener(
2637                                                     new AlphaInt8ReadValueFromBufferListener());
2638                                             break;
2639                                         case PLY_UINT8:
2640                                             property.setReadValueFromBufferListener(
2641                                                     new AlphaUint8ReadValueFromBufferListener());
2642                                             break;
2643                                         case PLY_INT16:
2644                                             property.setReadValueFromBufferListener(
2645                                                     new AlphaInt16ReadValueFromBufferListener());
2646                                             break;
2647                                         case PLY_UINT16:
2648                                             property.setReadValueFromBufferListener(
2649                                                     new AlphaUint16ReadValueFromBufferListener());
2650                                             break;
2651                                         case PLY_INT32:
2652                                             property.setReadValueFromBufferListener(
2653                                                     new AlphaInt32ReadValueFromBufferListener());
2654                                             break;
2655                                         case PLY_UINT32:
2656                                             property.setReadValueFromBufferListener(
2657                                                     new AlphaUint32ReadValueFromBufferListener());
2658                                             break;
2659                                         case PLY_FLOAT32:
2660                                             property.setReadValueFromBufferListener(
2661                                                     new AlphaFloat32ReadValueFromBufferListener());
2662                                             break;
2663                                         case PLY_FLOAT64:
2664                                             property.setReadValueFromBufferListener(
2665                                                     new AlphaFloat64ReadValueFromBufferListener());
2666                                             break;
2667                                         case PLY_CHAR:
2668                                             property.setReadValueFromBufferListener(
2669                                                     new AlphaCharReadValueFromBufferListener());
2670                                             break;
2671                                         case PLY_UCHAR:
2672                                             property.setReadValueFromBufferListener(
2673                                                     new AlphaUcharReadValueFromBufferListener());
2674                                             break;
2675                                         case PLY_SHORT:
2676                                             property.setReadValueFromBufferListener(
2677                                                     new AlphaShortReadValueFromBufferListener());
2678                                             break;
2679                                         case PLY_USHORT:
2680                                             property.setReadValueFromBufferListener(
2681                                                     new AlphaUshortReadValueFromBufferListener());
2682                                             break;
2683                                         case PLY_INT:
2684                                             property.setReadValueFromBufferListener(
2685                                                     new AlphaIntReadValueFromBufferListener());
2686                                             break;
2687                                         case PLY_UINT:
2688                                             property.setReadValueFromBufferListener(
2689                                                     new AlphaUintReadValueFromBufferListener());
2690                                             break;
2691                                         case PLY_FLOAT:
2692                                             property.setReadValueFromBufferListener(
2693                                                     new AlphaFloatReadValueFromBufferListener());
2694                                             break;
2695                                         case PLY_DOUBLE:
2696                                             property.setReadValueFromBufferListener(
2697                                                     new AlphaDoubleReadValueFromBufferListener());
2698                                             break;
2699                                         default:
2700                                             throw new LoaderException();
2701                                     }
2702                                     break;
2703                                 default:
2704                                     // not recognized properties are ignored
2705                                     break;
2706                             }
2707 
2708                             // update vertex data size
2709                             if (loader.header.getStorageMode() != PLYStorageMode.PLY_ASCII) {
2710                                 vertexDataSize += sizeForDataType(property.getValueType());
2711                             }
2712                         }
2713 
2714                         if (loader.header.getStorageMode() != PLYStorageMode.PLY_ASCII
2715                                 && !firstFaceStreamPositionAvailable) {
2716 
2717                             firstVertexStreamPosition = streamPositionOffset;
2718                             firstVertexStreamPositionAvailable = true;
2719                             // update offset taking into account all vertex data
2720                             streamPositionOffset += numberOfVertices * vertexDataSize;
2721                         }
2722 
2723                     } else if ("face".equals(element.getName())) {
2724                         faceElement = element;
2725                         indicesAvailable = true;
2726 
2727                         // obtain number of faces
2728                         numberOfFaces = element.getNumberOfInstances();
2729 
2730                         for (final var property : element.getProperties()) {
2731 
2732                             // set listener to read data from stream
2733                             setReadValueFromStreamListener(property, loader.header.getStorageMode());
2734 
2735                             if (property.getPropertyType() == PropertyTypePLY.PROPERTY_PLY_LIST) {
2736                                 // set listeners to get number of elements in a
2737                                 // list
2738                                 setReadLengthValueFromBufferListener(property);
2739                                 setReadLengthValueFromStreamListener(property, loader.header.getStorageMode());
2740                             }
2741 
2742                             switch (property.getValueType()) {
2743                                 case PLY_INT8:
2744                                     property.setReadValueFromBufferListener(
2745                                             new FaceInt8ReadValueFromBufferListener());
2746                                     break;
2747                                 case PLY_UINT8:
2748                                     property.setReadValueFromBufferListener(
2749                                             new FaceUint8ReadValueFromBufferListener());
2750                                     break;
2751                                 case PLY_INT16:
2752                                     property.setReadValueFromBufferListener(
2753                                             new FaceInt16ReadValueFromBufferListener());
2754                                     break;
2755                                 case PLY_UINT16:
2756                                     property.setReadValueFromBufferListener(
2757                                             new FaceUint16ReadValueFromBufferListener());
2758                                     break;
2759                                 case PLY_INT32:
2760                                     property.setReadValueFromBufferListener(
2761                                             new FaceInt32ReadValueFromBufferListener());
2762                                     break;
2763                                 case PLY_UINT32:
2764                                     property.setReadValueFromBufferListener(
2765                                             new FaceUint32ReadValueFromBufferListener());
2766                                     break;
2767                                 case PLY_FLOAT32:
2768                                     property.setReadValueFromBufferListener(
2769                                             new FaceFloat32ReadValueFromBufferListener());
2770                                     break;
2771                                 case PLY_FLOAT64:
2772                                     property.setReadValueFromBufferListener(
2773                                             new FaceFloat64ReadValueFromBufferListener());
2774                                     break;
2775                                 case PLY_CHAR:
2776                                     property.setReadValueFromBufferListener(
2777                                             new FaceCharReadValueFromBufferListener());
2778                                     break;
2779                                 case PLY_UCHAR:
2780                                     property.setReadValueFromBufferListener(
2781                                             new FaceUcharReadValueFromBufferListener());
2782                                     break;
2783                                 case PLY_SHORT:
2784                                     property.setReadValueFromBufferListener(
2785                                             new FaceShortReadValueFromBufferListener());
2786                                     break;
2787                                 case PLY_USHORT:
2788                                     property.setReadValueFromBufferListener(
2789                                             new FaceUshortReadValueFromBufferListener());
2790                                     break;
2791                                 case PLY_INT:
2792                                     property.setReadValueFromBufferListener(
2793                                             new FaceIntReadValueFromBufferListener());
2794                                     break;
2795                                 case PLY_UINT:
2796                                     property.setReadValueFromBufferListener(
2797                                             new FaceUintReadValueFromBufferListener());
2798                                     break;
2799                                 case PLY_FLOAT:
2800                                     property.setReadValueFromBufferListener(
2801                                             new FaceFloatReadValueFromBufferListener());
2802                                     break;
2803                                 case PLY_DOUBLE:
2804                                     property.setReadValueFromBufferListener(
2805                                             new FaceDoubleReadValueFromBufferListener());
2806                                     break;
2807                                 default:
2808                                     throw new LoaderException();
2809                             }
2810                         }
2811 
2812                         if (loader.header.getStorageMode() != PLYStorageMode.PLY_ASCII) {
2813                             // Binary storage mode (either Little endian or Big
2814                             // endian)
2815                             firstFaceStreamPosition = streamPositionOffset;
2816                             firstFaceStreamPositionAvailable = true;
2817 
2818                             fetchVertexListener = new BinaryVertexFetcherListener();
2819                         } else {
2820                             // ASCII storage mode
2821                             fetchVertexListener = new AsciiVertexFetcherListener();
2822                         }
2823                     }
2824                 }
2825 
2826                 // find first vertex and face positions in stream in case it
2827                 // couldn't be computed
2828                 findFirstVertexAndFaceStreamPosition();
2829 
2830                 // set stream into 1st face position
2831                 if (!firstFaceStreamPositionAvailable) {
2832                     throw new LoaderException();
2833                 }
2834                 reader.seek(firstFaceStreamPosition);
2835                 currentFace = 0;
2836 
2837             } catch (final NotAvailableException e) {
2838                 throw new LoaderException(e);
2839             }
2840         }
2841 
2842         /**
2843          * Returns size in bytes for a given data type.
2844          *
2845          * @param type A data type.
2846          * @return Size in bytes for a given data type.
2847          */
2848         private long sizeForDataType(final DataTypePLY type) {
2849             return switch (type) {
2850                 case PLY_INT8, PLY_UINT8, PLY_CHAR, PLY_UCHAR -> 1; // 1 byte
2851                 case PLY_INT16, PLY_UINT16, PLY_SHORT, PLY_USHORT -> 2; // 2 bytes
2852                 case PLY_INT32, PLY_UINT32, PLY_FLOAT32, PLY_INT, PLY_UINT, PLY_FLOAT -> 4; // 4 bytes
2853                 case PLY_FLOAT64, PLY_DOUBLE -> 8; // 8 bytes
2854             };
2855         }
2856 
2857         /**
2858          * Finds in file stream the location of the first vertex and face.
2859          *
2860          * @throws LoaderException       Raised if file is corrupted and location of
2861          *                               first vertex or face cannot be found.
2862          * @throws NotAvailableException Raised if header does not contain a
2863          *                               given element.
2864          * @throws IOException           if an I/O error occurs.
2865          */
2866         private void findFirstVertexAndFaceStreamPosition() throws LoaderException, NotAvailableException, IOException {
2867 
2868             if (firstVertexStreamPositionAvailable && firstFaceStreamPositionAvailable) {
2869                 // already computed
2870                 return;
2871             }
2872 
2873             final var buffer = ByteBuffer.allocate(BUFFER_SIZE);
2874 
2875             long nElems;
2876             var counter = 0L;
2877 
2878             // iterate over elements in header
2879             for (final var element : loader.header.getElements()) {
2880                 if (!element.isValidElement()) {
2881                     throw new LoaderException();
2882                 }
2883 
2884                 var stop = false;
2885                 if ("vertex".equals(element.getName())) {
2886                     // FIRST VERTEX FOUND!
2887                     firstVertexStreamPosition = reader.getPosition();
2888                     firstVertexStreamPositionAvailable = true;
2889 
2890                     vertexElement = element;
2891 
2892                     // stop if both 1st vertex and face are known
2893                     stop = firstFaceStreamPositionAvailable;
2894                 } else if ("face".equals(element.getName())) {
2895                     // FIRST FACE FOUND!
2896                     firstFaceStreamPosition = reader.getPosition();
2897                     firstFaceStreamPositionAvailable = true;
2898 
2899                     faceElement = element;
2900 
2901                     // stop if both 1st vertex and face are known
2902                     stop = firstVertexStreamPositionAvailable;
2903                 }
2904 
2905                 if (stop) {
2906                     break;
2907                 }
2908 
2909                 nElems = element.getNumberOfInstances();
2910                 // repeat properties iteration for each element
2911                 for (var i = 0L; i < nElems; i++) {
2912 
2913                     PLYReadValueFromStreamListener readLengthValueFromStreamListener;
2914                     PLYReadValueFromBufferListener readLengthValueFromBufferListener;
2915                     PLYReadValueFromStreamListener readValueFromStreamListener;
2916 
2917                     // iterate on properties of element
2918                     for (final var property : element.getProperties()) {
2919                         if (!property.isValidProperty()) {
2920                             throw new LoaderException();
2921                         }
2922 
2923                         // number of elements in list (initially assume that is
2924                         // scalar, hence 1
2925                         listElems = 1;
2926 
2927                         if (property.getPropertyType() == PropertyTypePLY.PROPERTY_PLY_LIST) {
2928                             // read number of list elements
2929                             readLengthValueFromStreamListener = property.getReadLengthValueFromStreamListener();
2930                             readLengthValueFromStreamListener.readFromStream(buffer);
2931 
2932                             if (reader.isEndOfStream() && (counter < (totalInstances - 1))) {
2933                                 throw new LoaderException();
2934                             }
2935 
2936                             readLengthValueFromBufferListener = property.getReadLengthValueFromBufferListener();
2937                             readLengthValueFromBufferListener.readValueFromBuffer(buffer);
2938                         }
2939 
2940                         // set delegate to read from stream
2941                         readValueFromStreamListener = property.getReadValueFromStreamListener();
2942 
2943                         // read property data
2944                         for (var u = 0L; u < listElems; u++) {
2945                             readValueFromStreamListener.readFromStream(buffer);
2946 
2947                             if (reader.isEndOfStream() && (counter < (totalInstances - 1))) {
2948                                 throw new LoaderException();
2949                             }
2950                         }
2951                     }
2952 
2953                     counter++;
2954                 }
2955             }
2956         }
2957 
2958         /**
2959          * Class to fetch vertex position within the file stream for a binary.
2960          * file.
2961          */
2962         private class BinaryVertexFetcherListener implements VertexFetcherListener {
2963 
2964             /**
2965              * Fetches vertex position and sets current stream position to
2966              * desired vertex.
2967              *
2968              * @param index index of vertex to be searched.
2969              * @throws LoaderException if file is corrupted.
2970              * @throws IOException     if an I/O error occurs.
2971              */
2972             @Override
2973             public void fetch(final long index) throws LoaderException, IOException {
2974 
2975                 final var nElems = vertexElement.getNumberOfInstances();
2976                 if (index >= nElems) {
2977                     throw new LoaderException();
2978                 }
2979 
2980                 final var pos = firstVertexStreamPosition + (index * vertexDataSize);
2981                 if (reader.getPosition() != pos) {
2982                     reader.seek(pos);
2983                 }
2984             }
2985         }
2986 
2987         /**
2988          * Class to fetch vertex position within the file stream for an ascii
2989          * file.
2990          */
2991         private class AsciiVertexFetcherListener implements VertexFetcherListener {
2992 
2993             /**
2994              * Fetches vertex position and sets current stream position to
2995              * desired vertex.
2996              *
2997              * @param index index of vertex to be searched.
2998              * @throws LoaderException       if file is corrupted.
2999              * @throws IOException           if an I/O error occurs.
3000              * @throws NotAvailableException if a given element in the header
3001              *                               is not available.
3002              */
3003             @Override
3004             public void fetch(final long index) throws LoaderException, IOException, NotAvailableException {
3005 
3006                 final var nElems = vertexElement.getNumberOfInstances();
3007                 if (index >= nElems) {
3008                     throw new LoaderException();
3009                 }
3010 
3011                 final var fetchBuffer = ByteBuffer.allocate(BUFFER_SIZE);
3012 
3013                 var startStreamPos = firstVertexStreamPosition;
3014                 var startIndex = 0L;
3015 
3016                 if (!verticesStreamPositionsMap.isEmpty()) {
3017                     // with floorEntry, we will pick element immediately
3018                     // before or equal to index if any exists
3019                     final var entry = verticesStreamPositionsMap.floorEntry(index);
3020                     if (entry != null) {
3021                         final var origIndex = entry.getKey();
3022                         final var pos = entry.getValue();
3023                         if ((origIndex <= index) && (pos >= 0)) {
3024                             startIndex = origIndex;
3025                             startStreamPos = pos;
3026                         }
3027                     }
3028                 }
3029 
3030                 // if we need to read next vertex, don't do anything, otherwise
3031                 // move to next vertex location if reading some vertex located
3032                 // further on the stream. For previous vertex indices, start from
3033                 // beginning
3034                 if (reader.getPosition() != startStreamPos) {
3035                     reader.seek(startStreamPos);
3036                 }
3037 
3038                 // read from stream until start of data of desired vertex
3039                 for (var i = startIndex; i < index; i++) {
3040 
3041                     // when traversing stream of data until reaching desired
3042                     // index, we add all vertex positions into map
3043                     final var streamPosition = reader.getPosition();
3044                     addVertexPositionToMap(i, streamPosition);
3045 
3046                     PLYReadValueFromStreamListener readValueFromStreamListener;
3047 
3048                     // iterate on vertex element properties
3049                     for (final var property : vertexElement.getProperties()) {
3050                         if (!property.isValidProperty()) {
3051                             throw new LoaderException();
3052                         }
3053 
3054                         // set delegates to read property value
3055                         readValueFromStreamListener = property.getReadValueFromStreamListener();
3056                         // and read value
3057                         readValueFromStreamListener.readFromStream(fetchBuffer);
3058 
3059                         if (reader.isEndOfStream() && (i < (index - 1))) {
3060                             throw new LoaderException();
3061                         }
3062                     }
3063                 }
3064 
3065                 vertexStreamPosition = reader.getPosition();
3066             }
3067         }
3068 
3069         /**
3070          * Reads x vertex coordinate from temporal buffer using int8 data type.
3071          */
3072         private class Xint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3073 
3074             /**
3075              * Reads x vertex coordinate from temporal buffer and sets its value
3076              * on current loader iterator.
3077              *
3078              * @param buffer Temporal buffer.
3079              */
3080             @Override
3081             public void readValueFromBuffer(final ByteBuffer buffer) {
3082                 loaderIterator.coordX = buffer.get(0);
3083             }
3084         }
3085 
3086         /**
3087          * Reads y vertex coordinate from temporal buffer using int8 data type.
3088          */
3089         private class Yint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3090 
3091             /**
3092              * Reads y vertex coordinate from temporal buffer and sets its value
3093              * on current loader iterator.
3094              *
3095              * @param buffer Temporal buffer.
3096              */
3097             @Override
3098             public void readValueFromBuffer(final ByteBuffer buffer) {
3099                 loaderIterator.coordY = buffer.get(0);
3100             }
3101         }
3102 
3103         /**
3104          * Reads z vertex coordinate from temporal buffer using int8 data type.
3105          */
3106         private class Zint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3107 
3108             /**
3109              * Reads z vertex coordinate from temporal buffer and sets its value
3110              * on current loader iterator.
3111              *
3112              * @param buffer Temporal buffer.
3113              */
3114             @Override
3115             public void readValueFromBuffer(final ByteBuffer buffer) {
3116                 loaderIterator.coordZ = buffer.get(0);
3117             }
3118         }
3119 
3120         /**
3121          * Reads x vertex coordinate from temporal buffer using uint8 data type.
3122          */
3123         private class Xuint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3124 
3125             /**
3126              * Reads x vertex coordinate from temporal buffer and sets its value
3127              * on current loader iterator.
3128              *
3129              * @param buffer Temporal buffer.
3130              */
3131             @Override
3132             public void readValueFromBuffer(final ByteBuffer buffer) {
3133                 // because java doesn't support unsigned types we use the next
3134                 // type that can hold all desired values
3135                 loaderIterator.coordX = buffer.getShort(0);
3136             }
3137         }
3138 
3139         /**
3140          * Reads y vertex coordinate from temporal buffer using uint8 data type.
3141          */
3142         private class Yuint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3143 
3144             /**
3145              * Reads y vertex coordinate from temporal buffer and sets its value
3146              * on current loader iterator.
3147              *
3148              * @param buffer Temporal buffer.
3149              */
3150             @Override
3151             public void readValueFromBuffer(final ByteBuffer buffer) {
3152                 // because java doesn't support unsigned types we use the next
3153                 // type that can hold all desired values
3154                 loaderIterator.coordY = buffer.getShort(0);
3155             }
3156         }
3157 
3158         /**
3159          * Reads z vertex coordinate from temporal buffer using uint8 data type.
3160          */
3161         private class Zuint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3162 
3163             /**
3164              * Reads z vertex coordinate from temporal buffer and sets its value
3165              * on current loader iterator.
3166              *
3167              * @param buffer Temporal buffer.
3168              */
3169             @Override
3170             public void readValueFromBuffer(final ByteBuffer buffer) {
3171                 // because java doesn't support unsigned types we use the next
3172                 // type that can hold all desired values
3173                 loaderIterator.coordZ = buffer.getShort(0);
3174             }
3175         }
3176 
3177         /**
3178          * Reads x vertex coordinate from temporal buffer using int16 data type.
3179          */
3180         private class Xint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3181 
3182             /**
3183              * Reads x vertex coordinate from temporal buffer and sets its value
3184              * on current loader iterator.
3185              *
3186              * @param buffer Temporal buffer.
3187              */
3188             @Override
3189             public void readValueFromBuffer(final ByteBuffer buffer) {
3190                 loaderIterator.coordX = buffer.getShort(0);
3191             }
3192         }
3193 
3194         /**
3195          * Reads y vertex coordinate from temporal buffer using int16 data type.
3196          */
3197         private class Yint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3198 
3199             /**
3200              * Reads y vertex coordinate from temporal buffer and sets its value
3201              * on current loader iterator.
3202              *
3203              * @param buffer Temporal buffer.
3204              */
3205             @Override
3206             public void readValueFromBuffer(final ByteBuffer buffer) {
3207                 loaderIterator.coordY = buffer.getShort(0);
3208             }
3209         }
3210 
3211         /**
3212          * Reads z vertex coordinate from temporal buffer using int16 data type.
3213          */
3214         private class Zint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3215 
3216             /**
3217              * Reads z vertex coordinate from temporal buffer and sets its value
3218              * on current loader iterator.
3219              *
3220              * @param buffer Temporal buffer.
3221              */
3222             @Override
3223             public void readValueFromBuffer(final ByteBuffer buffer) {
3224                 loaderIterator.coordZ = buffer.getShort(0);
3225             }
3226         }
3227 
3228         /**
3229          * Reads x vertex coordinate from temporal buffer using uint16 data
3230          * type.
3231          */
3232         private class Xuint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3233 
3234             /**
3235              * Reads x vertex coordinate from temporal buffer and sets its value
3236              * on current loader iterator.
3237              *
3238              * @param buffer Temporal buffer.
3239              */
3240             @Override
3241             public void readValueFromBuffer(final ByteBuffer buffer) {
3242                 // because java doesn't support unsigned types we use the next
3243                 // type that can hold all desired values
3244                 loaderIterator.coordX = buffer.getInt(0);
3245             }
3246         }
3247 
3248         /**
3249          * Reads y vertex coordinate from temporal buffer using uint16 data
3250          * type.
3251          */
3252         private class Yuint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3253 
3254             /**
3255              * Reads y vertex coordinate from temporal buffer and sets its value
3256              * on current loader iterator.
3257              *
3258              * @param buffer Temporal buffer.
3259              */
3260             @Override
3261             public void readValueFromBuffer(final ByteBuffer buffer) {
3262                 // because java doesn't support unsigned types we use the next
3263                 // type that can hold all desired values
3264                 loaderIterator.coordY = buffer.getInt(0);
3265             }
3266         }
3267 
3268         /**
3269          * Reads z vertex coordinate from temporal buffer using uint16 data
3270          * type.
3271          */
3272         private class Zuint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3273 
3274             /**
3275              * Reads z vertex coordinate from temporal buffer and sets its value
3276              * on current loader iterator.
3277              *
3278              * @param buffer Temporal buffer.
3279              */
3280             @Override
3281             public void readValueFromBuffer(final ByteBuffer buffer) {
3282                 // because java doesn't support unsigned types we use the next
3283                 // type that can hold all desired values
3284                 loaderIterator.coordZ = buffer.getInt(0);
3285             }
3286         }
3287 
3288         /**
3289          * Reads x vertex coordinate from temporal buffer using int32 data type.
3290          */
3291         private class Xint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3292 
3293             /**
3294              * Reads x vertex coordinate from temporal buffer and sets its value
3295              * on current loader iterator.
3296              *
3297              * @param buffer Temporal buffer.
3298              */
3299             @Override
3300             public void readValueFromBuffer(final ByteBuffer buffer) {
3301                 loaderIterator.coordX = buffer.getInt(0);
3302             }
3303         }
3304 
3305         /**
3306          * Reads y vertex coordinate from temporal buffer using int32 data type.
3307          */
3308         private class Yint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3309 
3310             /**
3311              * Reads y vertex coordinate from temporal buffer and sets its value
3312              * on current loader iterator.
3313              *
3314              * @param buffer Temporal buffer.
3315              */
3316             @Override
3317             public void readValueFromBuffer(final ByteBuffer buffer) {
3318                 loaderIterator.coordY = buffer.getInt(0);
3319             }
3320         }
3321 
3322         /**
3323          * Reads z vertex coordinate from temporal buffer using int32 data type.
3324          */
3325         private class Zint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3326 
3327             /**
3328              * Reads z vertex coordinate from temporal buffer and sets its value
3329              * on current loader iterator.
3330              *
3331              * @param buffer Temporal buffer.
3332              */
3333             @Override
3334             public void readValueFromBuffer(final ByteBuffer buffer) {
3335                 loaderIterator.coordZ = buffer.getInt(0);
3336             }
3337         }
3338 
3339         /**
3340          * Reads x vertex coordinate from temporal buffer using uint32 data
3341          * type.
3342          */
3343         private class Xuint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3344 
3345             /**
3346              * Reads x vertex coordinate from temporal buffer and sets its value
3347              * on current loader iterator.
3348              *
3349              * @param buffer Temporal buffer.
3350              */
3351             @Override
3352             public void readValueFromBuffer(final ByteBuffer buffer) {
3353                 // because java doesn't support unsigned types we use the next
3354                 // type that can hold all desired values
3355                 loaderIterator.coordX = buffer.getLong(0);
3356             }
3357         }
3358 
3359         /**
3360          * Reads y vertex coordinate from temporal buffer using uint32 data
3361          * type.
3362          */
3363         private class Yuint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3364 
3365             /**
3366              * Reads y vertex coordinate from temporal buffer and sets its value
3367              * on current loader iterator.
3368              *
3369              * @param buffer Temporal buffer.
3370              */
3371             @Override
3372             public void readValueFromBuffer(final ByteBuffer buffer) {
3373                 // because java doesn't support unsigned types we use the next
3374                 // type that can hold all desired values
3375                 loaderIterator.coordY = buffer.getLong(0);
3376             }
3377         }
3378 
3379         /**
3380          * Reads z vertex coordinate from temporal buffer using uint32 data
3381          * type.
3382          */
3383         private class Zuint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3384 
3385             /**
3386              * Reads z vertex coordinate from temporal buffer and sets its value
3387              * on current loader iterator.
3388              *
3389              * @param buffer Temporal buffer.
3390              */
3391             @Override
3392             public void readValueFromBuffer(final ByteBuffer buffer) {
3393                 // because java doesn't support unsigned types we use the next
3394                 // type that can hold all desired values
3395                 loaderIterator.coordZ = buffer.getLong(0);
3396             }
3397         }
3398 
3399         /**
3400          * Reads x vertex coordinate from temporal buffer using float32 data
3401          * type.
3402          */
3403         private class Xfloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3404 
3405             /**
3406              * Reads x vertex coordinate from temporal buffer and sets its value
3407              * on current loader iterator.
3408              *
3409              * @param buffer Temporal buffer.
3410              */
3411             @Override
3412             public void readValueFromBuffer(final ByteBuffer buffer) {
3413                 loaderIterator.coordX = buffer.getFloat(0);
3414             }
3415         }
3416 
3417         /**
3418          * Reads y vertex coordinate from temporal buffer using float32 data
3419          * type.
3420          */
3421         private class Yfloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3422 
3423             /**
3424              * Reads y vertex coordinate from temporal buffer and sets its value
3425              * on current loader iterator.
3426              *
3427              * @param buffer Temporal buffer.
3428              */
3429             @Override
3430             public void readValueFromBuffer(final ByteBuffer buffer) {
3431                 loaderIterator.coordY = buffer.getFloat(0);
3432             }
3433         }
3434 
3435         /**
3436          * Reads z vertex coordinate from temporal buffer using float32 data
3437          * type.
3438          */
3439         private class Zfloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3440 
3441             /**
3442              * Reads z vertex coordinate from temporal buffer and sets its value
3443              * on current loader iterator.
3444              *
3445              * @param buffer Temporal buffer.
3446              */
3447             @Override
3448             public void readValueFromBuffer(final ByteBuffer buffer) {
3449                 loaderIterator.coordZ = buffer.getFloat(0);
3450             }
3451         }
3452 
3453         /**
3454          * Reads x vertex coordinate from temporal buffer using float64 data
3455          * type.
3456          */
3457         private class Xfloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3458 
3459             /**
3460              * Reads x vertex coordinate from temporal buffer and sets its value
3461              * on current loader iterator.
3462              *
3463              * @param buffer Temporal buffer.
3464              */
3465             @Override
3466             public void readValueFromBuffer(final ByteBuffer buffer) {
3467                 final var value = buffer.getDouble(0);
3468 
3469                 loaderIterator.coordX = (float) value;
3470             }
3471         }
3472 
3473         /**
3474          * Reads y vertex coordinate from temporal buffer using float64 data
3475          * type.
3476          */
3477         private class Yfloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3478 
3479             /**
3480              * Reads y vertex coordinate from temporal buffer and sets its value
3481              * on current loader iterator.
3482              *
3483              * @param buffer Temporal buffer.
3484              */
3485             @Override
3486             public void readValueFromBuffer(final ByteBuffer buffer) {
3487                 final var value = buffer.getDouble(0);
3488 
3489                 loaderIterator.coordY = (float) value;
3490             }
3491         }
3492 
3493         /**
3494          * Reads z vertex coordinate from temporal buffer using float64 data
3495          * type.
3496          */
3497         private class Zfloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3498 
3499             /**
3500              * Reads z vertex coordinate from temporal buffer and sets its value
3501              * on current loader iterator.
3502              *
3503              * @param buffer Temporal buffer.
3504              */
3505             @Override
3506             public void readValueFromBuffer(final ByteBuffer buffer) {
3507                 final var value = buffer.getDouble(0);
3508 
3509                 loaderIterator.coordZ = (float) value;
3510             }
3511         }
3512 
3513         /**
3514          * Reads x vertex coordinate from temporal buffer using char data type.
3515          */
3516         private class XcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3517 
3518             /**
3519              * Reads x vertex coordinate from temporal buffer and sets its value
3520              * on current loader iterator.
3521              *
3522              * @param buffer Temporal buffer.
3523              */
3524             @Override
3525             public void readValueFromBuffer(final ByteBuffer buffer) {
3526                 loaderIterator.coordX = buffer.get(0);
3527             }
3528         }
3529 
3530         /**
3531          * Reads y vertex coordinate from temporal buffer using char data type.
3532          */
3533         private class YcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3534 
3535             /**
3536              * Reads y vertex coordinate from temporal buffer and sets its value
3537              * on current loader iterator.
3538              *
3539              * @param buffer Temporal buffer.
3540              */
3541             @Override
3542             public void readValueFromBuffer(final ByteBuffer buffer) {
3543                 loaderIterator.coordY = buffer.get(0);
3544             }
3545         }
3546 
3547         /**
3548          * Reads z vertex coordinate from temporal buffer using char data type.
3549          */
3550         private class ZcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3551 
3552             /**
3553              * Reads z vertex coordinate from temporal buffer and sets its value
3554              * on current loader iterator.
3555              *
3556              * @param buffer Temporal buffer.
3557              */
3558             @Override
3559             public void readValueFromBuffer(final ByteBuffer buffer) {
3560                 loaderIterator.coordZ = buffer.get(0);
3561             }
3562         }
3563 
3564         /**
3565          * Reads x vertex coordinate from temporal buffer using uchar data type.
3566          */
3567         private class XucharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3568 
3569             /**
3570              * Reads x vertex coordinate from temporal buffer and sets its value
3571              * on current loader iterator.
3572              *
3573              * @param buffer Temporal buffer.
3574              */
3575             @Override
3576             public void readValueFromBuffer(final ByteBuffer buffer) {
3577                 // because java doesn't support unsigned types we use the next
3578                 // type that can hold all desired values
3579                 loaderIterator.coordX = buffer.getShort(0);
3580             }
3581         }
3582 
3583         /**
3584          * Reads y vertex coordinate from temporal buffer using uchar data type.
3585          */
3586         private class YucharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3587 
3588             /**
3589              * Reads y vertex coordinate from temporal buffer and sets its value
3590              * on current loader iterator.
3591              *
3592              * @param buffer Temporal buffer.
3593              */
3594             @Override
3595             public void readValueFromBuffer(final ByteBuffer buffer) {
3596                 // because java doesn't support unsigned types we use the next
3597                 // type that can hold all desired values
3598                 loaderIterator.coordY = buffer.getShort(0);
3599             }
3600         }
3601 
3602         /**
3603          * Reads z vertex coordinate from temporal buffer using uchar data type.
3604          */
3605         private class ZucharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3606 
3607             /**
3608              * Reads z vertex coordinate from temporal buffer and sets its value
3609              * on current loader iterator.
3610              *
3611              * @param buffer Temporal buffer.
3612              */
3613             @Override
3614             public void readValueFromBuffer(final ByteBuffer buffer) {
3615                 // because java doesn't support unsigned types we use the next
3616                 // type that can hold all desired values
3617                 loaderIterator.coordZ = buffer.getShort(0);
3618             }
3619         }
3620 
3621         /**
3622          * Reads x vertex coordinate from temporal buffer using short data type.
3623          */
3624         private class XshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3625 
3626             /**
3627              * Reads x vertex coordinate from temporal buffer and sets its value
3628              * on current loader iterator.
3629              *
3630              * @param buffer Temporal buffer.
3631              */
3632             @Override
3633             public void readValueFromBuffer(final ByteBuffer buffer) {
3634                 loaderIterator.coordX = buffer.getShort(0);
3635             }
3636         }
3637 
3638         /**
3639          * Reads y vertex coordinate from temporal buffer using short data type.
3640          */
3641         private class YshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3642 
3643             /**
3644              * Reads y vertex coordinate from temporal buffer and sets its value
3645              * on current loader iterator.
3646              *
3647              * @param buffer Temporal buffer.
3648              */
3649             @Override
3650             public void readValueFromBuffer(final ByteBuffer buffer) {
3651                 loaderIterator.coordY = buffer.getShort(0);
3652             }
3653         }
3654 
3655         /**
3656          * Reads z vertex coordinate from temporal buffer using short data type.
3657          */
3658         private class ZshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3659 
3660             /**
3661              * Reads z vertex coordinate from temporal buffer and sets its value
3662              * on current loader iterator.
3663              *
3664              * @param buffer Temporal buffer.
3665              */
3666             @Override
3667             public void readValueFromBuffer(final ByteBuffer buffer) {
3668                 loaderIterator.coordZ = buffer.getShort(0);
3669             }
3670         }
3671 
3672         /**
3673          * Reads x vertex coordinate from temporal buffer using ushort data
3674          * type.
3675          */
3676         private class XushortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3677 
3678             /**
3679              * Reads x vertex coordinate from temporal buffer and sets its value
3680              * on current loader iterator.
3681              *
3682              * @param buffer Temporal buffer.
3683              */
3684             @Override
3685             public void readValueFromBuffer(final ByteBuffer buffer) {
3686                 // because java doesn't support unsigned types we use the next
3687                 // type that can hold all desired values
3688                 loaderIterator.coordX = buffer.getInt(0);
3689             }
3690         }
3691 
3692         /**
3693          * Reads y vertex coordinate from temporal buffer using ushort data
3694          * type.
3695          */
3696         private class YushortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3697 
3698             /**
3699              * Reads y vertex coordinate from temporal buffer and sets its value
3700              * on current loader iterator.
3701              *
3702              * @param buffer Temporal buffer.
3703              */
3704             @Override
3705             public void readValueFromBuffer(final ByteBuffer buffer) {
3706                 // because java doesn't support unsigned types we use the next
3707                 // type that can hold all desired values
3708                 loaderIterator.coordY = buffer.getInt(0);
3709             }
3710         }
3711 
3712         /**
3713          * Reads z vertex coordinate from temporal buffer using ushort data
3714          * type.
3715          */
3716         private class ZushortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3717 
3718             /**
3719              * Reads z vertex coordinate from temporal buffer and sets its value
3720              * on current loader iterator.
3721              *
3722              * @param buffer Temporal buffer.
3723              */
3724             @Override
3725             public void readValueFromBuffer(final ByteBuffer buffer) {
3726                 // because java doesn't support unsigned types we use the next
3727                 // type that can hold all desired values
3728                 loaderIterator.coordZ = buffer.getInt(0);
3729             }
3730         }
3731 
3732         /**
3733          * Reads x vertex coordinate from temporal buffer using int data type.
3734          */
3735         private class XintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3736 
3737             /**
3738              * Reads x vertex coordinate from temporal buffer and sets its value
3739              * on current loader iterator.
3740              *
3741              * @param buffer Temporal buffer.
3742              */
3743             @Override
3744             public void readValueFromBuffer(final ByteBuffer buffer) {
3745                 loaderIterator.coordX = buffer.getInt(0);
3746             }
3747         }
3748 
3749         /**
3750          * Reads y vertex coordinate from temporal buffer using int data type.
3751          */
3752         private class YintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3753 
3754             /**
3755              * Reads y vertex coordinate from temporal buffer and sets its value
3756              * on current loader iterator.
3757              *
3758              * @param buffer Temporal buffer.
3759              */
3760             @Override
3761             public void readValueFromBuffer(final ByteBuffer buffer) {
3762                 loaderIterator.coordY = buffer.getInt(0);
3763             }
3764         }
3765 
3766         /**
3767          * Reads z vertex coordinate from temporal buffer using int data type.
3768          */
3769         private class ZintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3770 
3771             /**
3772              * Reads z vertex coordinate from temporal buffer and sets its value
3773              * on current loader iterator.
3774              *
3775              * @param buffer Temporal buffer.
3776              */
3777             @Override
3778             public void readValueFromBuffer(final ByteBuffer buffer) {
3779                 loaderIterator.coordZ = buffer.getInt(0);
3780             }
3781         }
3782 
3783         /**
3784          * Reads x vertex coordinate from temporal buffer using uint data type.
3785          */
3786         private class XuintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3787 
3788             /**
3789              * Reads x vertex coordinate from temporal buffer and sets its value
3790              * on current loader iterator.
3791              *
3792              * @param buffer Temporal buffer.
3793              */
3794             @Override
3795             public void readValueFromBuffer(final ByteBuffer buffer) {
3796                 // because java doesn't support unsigned types we use the next
3797                 // type that can hold all desired values
3798                 loaderIterator.coordX = buffer.getLong(0);
3799             }
3800         }
3801 
3802         /**
3803          * Reads y vertex coordinate from temporal buffer using uint data type.
3804          */
3805         private class YuintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3806 
3807             /**
3808              * Reads y vertex coordinate from temporal buffer and sets its value
3809              * on current loader iterator.
3810              *
3811              * @param buffer Temporal buffer.
3812              */
3813             @Override
3814             public void readValueFromBuffer(final ByteBuffer buffer) {
3815                 // because java doesn't support unsigned types we use the next
3816                 // type that can hold all desired values
3817                 loaderIterator.coordY = buffer.getLong(0);
3818             }
3819         }
3820 
3821         /**
3822          * Reads z vertex coordinate from temporal buffer using uint data type.
3823          */
3824         private class ZuintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3825 
3826             /**
3827              * Reads z vertex coordinate from temporal buffer and sets its value
3828              * on current loader iterator.
3829              *
3830              * @param buffer Temporal buffer.
3831              */
3832             @Override
3833             public void readValueFromBuffer(final ByteBuffer buffer) {
3834                 // because java doesn't support unsigned types we use the next
3835                 // type that can hold all desired values
3836                 loaderIterator.coordZ = buffer.getLong(0);
3837             }
3838         }
3839 
3840         /**
3841          * Reads x vertex coordinate from temporal buffer using float data type.
3842          */
3843         private class XfloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3844 
3845             /**
3846              * Reads x vertex coordinate from temporal buffer and sets its value
3847              * on current loader iterator.
3848              *
3849              * @param buffer Temporal buffer.
3850              */
3851             @Override
3852             public void readValueFromBuffer(final ByteBuffer buffer) {
3853                 loaderIterator.coordX = buffer.getFloat(0);
3854             }
3855         }
3856 
3857         /**
3858          * Reads y vertex coordinate from temporal buffer using float data type.
3859          */
3860         private class YfloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3861 
3862             /**
3863              * Reads y vertex coordinate from temporal buffer and sets its value
3864              * on current loader iterator.
3865              *
3866              * @param buffer Temporal buffer.
3867              */
3868             @Override
3869             public void readValueFromBuffer(final ByteBuffer buffer) {
3870                 loaderIterator.coordY = buffer.getFloat(0);
3871             }
3872         }
3873 
3874         /**
3875          * Reads z vertex coordinate from temporal buffer using float data type.
3876          */
3877         private class ZfloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3878 
3879             /**
3880              * Reads z vertex coordinate from temporal buffer and sets its value
3881              * on current loader iterator.
3882              *
3883              * @param buffer Temporal buffer.
3884              */
3885             @Override
3886             public void readValueFromBuffer(final ByteBuffer buffer) {
3887                 loaderIterator.coordZ = buffer.getFloat(0);
3888             }
3889         }
3890 
3891         /**
3892          * Reads x vertex coordinate from temporal buffer using double data
3893          * type.
3894          */
3895         private class XdoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3896 
3897             /**
3898              * Reads x vertex coordinate from temporal buffer and sets its value
3899              * on current loader iterator.
3900              *
3901              * @param buffer Temporal buffer.
3902              */
3903             @Override
3904             public void readValueFromBuffer(final ByteBuffer buffer) {
3905                 final var value = buffer.getDouble(0);
3906 
3907                 loaderIterator.coordX = (float) value;
3908             }
3909         }
3910 
3911         /**
3912          * Reads y vertex coordinate from temporal buffer using double data
3913          * type.
3914          */
3915         private class YdoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3916 
3917             /**
3918              * Reads y vertex coordinate from temporal buffer and sets its value
3919              * on current loader iterator.
3920              *
3921              * @param buffer Temporal buffer.
3922              */
3923             @Override
3924             public void readValueFromBuffer(final ByteBuffer buffer) {
3925                 final var value = buffer.getDouble(0);
3926 
3927                 loaderIterator.coordY = (float) value;
3928             }
3929         }
3930 
3931         /**
3932          * Reads z vertex coordinate from temporal buffer using double data
3933          * type.
3934          */
3935         private class ZdoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3936 
3937             /**
3938              * Reads z vertex coordinate from temporal buffer and sets its value
3939              * on current loader iterator.
3940              *
3941              * @param buffer Temporal buffer.
3942              */
3943             @Override
3944             public void readValueFromBuffer(final ByteBuffer buffer) {
3945                 final var value = buffer.getDouble(0);
3946 
3947                 loaderIterator.coordZ = (float) value;
3948             }
3949         }
3950 
3951         /**
3952          * Reads red color component from temporal buffer using int8 data type.
3953          */
3954         private class RedInt8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3955 
3956             /**
3957              * Reads red color component from temporal buffer and sets its value
3958              * on current loader iterator.
3959              *
3960              * @param buffer Temporal buffer.
3961              */
3962             @Override
3963             public void readValueFromBuffer(final ByteBuffer buffer) {
3964                 loaderIterator.red = buffer.get(0);
3965             }
3966         }
3967 
3968         /**
3969          * Reads green color component from temporal buffer using int8 data
3970          * type.
3971          */
3972         private class GreenInt8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3973 
3974             /**
3975              * Reads green color component from temporal buffer and sets its
3976              * value on current loader iterator.
3977              *
3978              * @param buffer Temporal buffer.
3979              */
3980             @Override
3981             public void readValueFromBuffer(final ByteBuffer buffer) {
3982                 loaderIterator.green = buffer.get(0);
3983             }
3984         }
3985 
3986         /**
3987          * Reads blue color component from temporal buffer using int8 data type.
3988          */
3989         private class BlueInt8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
3990 
3991             /**
3992              * Reads blue color component from temporal buffer and sets its
3993              * value on current loader iterator.
3994              *
3995              * @param buffer Temporal buffer.
3996              */
3997             @Override
3998             public void readValueFromBuffer(final ByteBuffer buffer) {
3999                 loaderIterator.blue = buffer.get(0);
4000             }
4001         }
4002 
4003         /**
4004          * Reads alpha color component from temporal buffer using int8 data
4005          * type.
4006          */
4007         private class AlphaInt8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4008 
4009             /**
4010              * Reads alpha color component from temporal buffer and sets its
4011              * value on current loader iterator.
4012              *
4013              * @param buffer Temporal buffer.
4014              */
4015             @Override
4016             public void readValueFromBuffer(final ByteBuffer buffer) {
4017                 loaderIterator.alpha = buffer.get(0);
4018             }
4019         }
4020 
4021         /**
4022          * Reads red color component from temporal buffer using uint8 data type.
4023          */
4024         private class RedUint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4025 
4026             /**
4027              * Reads red color component from temporal buffer and sets its value
4028              * on current loader iterator.
4029              *
4030              * @param buffer Temporal buffer.
4031              */
4032             @Override
4033             public void readValueFromBuffer(final ByteBuffer buffer) {
4034                 // because java doesn't support unsigned types we use the next
4035                 // type that can hold all desired values
4036                 loaderIterator.red = buffer.getShort(0);
4037             }
4038         }
4039 
4040         /**
4041          * Read green color component from temporal buffer using uint8 data
4042          * type.
4043          */
4044         private class GreenUint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4045 
4046             /**
4047              * Reads green color component from temporal buffer and sets its
4048              * value on current loader iterator.
4049              *
4050              * @param buffer Temporal buffer.
4051              */
4052             @Override
4053             public void readValueFromBuffer(final ByteBuffer buffer) {
4054                 // because java doesn't support unsigned types we use the next
4055                 // type that can hold all desired values
4056                 loaderIterator.green = buffer.getShort(0);
4057             }
4058         }
4059 
4060         /**
4061          * Reads blue color component from temporal buffer using uint8 data
4062          * type.
4063          */
4064         private class BlueUint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4065 
4066             /**
4067              * Reads blue color component from temporal buffer and sets its
4068              * value on current loader iterator.
4069              *
4070              * @param buffer Temporal buffer.
4071              */
4072             @Override
4073             public void readValueFromBuffer(final ByteBuffer buffer) {
4074                 // because java doesn't support unsigned types we use the next
4075                 // type that can hold all desired values
4076                 loaderIterator.blue = buffer.getShort(0);
4077             }
4078         }
4079 
4080         /**
4081          * Reads alpha color component from temporal buffer using uint8 data
4082          * type.
4083          */
4084         private class AlphaUint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4085 
4086             /**
4087              * Reads alpha color component from temporal buffer and sets its
4088              * value on current loader iterator.
4089              *
4090              * @param buffer Temporal buffer.
4091              */
4092             @Override
4093             public void readValueFromBuffer(final ByteBuffer buffer) {
4094                 // because java doesn't support unsigned types we use the next
4095                 // type that can hold all desired values
4096                 loaderIterator.alpha = buffer.getShort(0);
4097             }
4098         }
4099 
4100         /**
4101          * Reads red color component from temporal buffer using int16 data type.
4102          */
4103         private class RedInt16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4104 
4105             /**
4106              * Reads red color component from temporal buffer and sets its value
4107              * on current loader iterator.
4108              *
4109              * @param buffer Temporal buffer.
4110              */
4111             @Override
4112             public void readValueFromBuffer(final ByteBuffer buffer) {
4113                 loaderIterator.red = buffer.getShort(0);
4114             }
4115         }
4116 
4117         /**
4118          * Reads green color component from temporal buffer using int16 data
4119          * type.
4120          */
4121         private class GreenInt16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4122 
4123             /**
4124              * Reads green color component from temporal buffer and sets its
4125              * value on current loader iterator.
4126              *
4127              * @param buffer Temporal buffer.
4128              */
4129             @Override
4130             public void readValueFromBuffer(final ByteBuffer buffer) {
4131                 loaderIterator.green = buffer.getShort(0);
4132             }
4133         }
4134 
4135         /**
4136          * Reads blue color component from temporal buffer using int16 data
4137          * type.
4138          */
4139         private class BlueInt16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4140 
4141             /**
4142              * Reads blue color component from temporal buffer and sets its
4143              * value on current loader iterator.
4144              *
4145              * @param buffer Temporal buffer.
4146              */
4147             @Override
4148             public void readValueFromBuffer(final ByteBuffer buffer) {
4149                 loaderIterator.blue = buffer.getShort(0);
4150             }
4151         }
4152 
4153         /**
4154          * Reads alpha color component from temporal buffer using int16 data
4155          * type.
4156          */
4157         private class AlphaInt16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4158 
4159             /**
4160              * Reads alpha color component from temporal buffer and sets its
4161              * value on current loader iterator.
4162              *
4163              * @param buffer Temporal buffer.
4164              */
4165             @Override
4166             public void readValueFromBuffer(final ByteBuffer buffer) {
4167                 loaderIterator.alpha = buffer.getShort(0);
4168             }
4169         }
4170 
4171         /**
4172          * Reads red color component from temporal buffer using uint16 data
4173          * type.
4174          */
4175         private class RedUint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4176 
4177             /**
4178              * Reads red color component from temporal buffer and sets its value
4179              * on current loader iterator.
4180              *
4181              * @param buffer Temporal buffer.
4182              */
4183             @Override
4184             public void readValueFromBuffer(final ByteBuffer buffer) {
4185                 // because java doesn't support unsigned types we use the next
4186                 // type that can hold all desired values
4187                 final var value = buffer.getInt(0);
4188 
4189                 loaderIterator.red = (short) value;
4190             }
4191         }
4192 
4193         /**
4194          * Reads green color component from temporal buffer using uint16 data
4195          * type.
4196          */
4197         private class GreenUint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4198 
4199             /**
4200              * Reads green color component from temporal buffer and sets its
4201              * value on current loader iterator.
4202              *
4203              * @param buffer Temporal buffer.
4204              */
4205             @Override
4206             public void readValueFromBuffer(final ByteBuffer buffer) {
4207                 // because java doesn't support unsigned types we use the next
4208                 // type that can hold all desired values
4209                 final var value = buffer.getInt(0);
4210 
4211                 loaderIterator.green = (short) value;
4212             }
4213         }
4214 
4215         /**
4216          * Reads blue color component from temporal buffer using uint16 data
4217          * type.
4218          */
4219         private class BlueUint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4220 
4221             /**
4222              * Reads blue color component from temporal buffer and sets its
4223              * value on current loader iterator.
4224              *
4225              * @param buffer Temporal buffer.
4226              */
4227             @Override
4228             public void readValueFromBuffer(final ByteBuffer buffer) {
4229                 // because java doesn't support unsigned types we use the next
4230                 // type that can hold all desired values
4231                 final var value = buffer.getInt(0);
4232 
4233                 loaderIterator.blue = (short) value;
4234             }
4235         }
4236 
4237         /**
4238          * Reads alpha color component from temporal buffer using uint16 data
4239          * type.
4240          */
4241         private class AlphaUint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4242 
4243             /**
4244              * Reads alpha color component from temporal buffer and sets its
4245              * value on current loader iterator.
4246              *
4247              * @param buffer Temporal buffer.
4248              */
4249             @Override
4250             public void readValueFromBuffer(final ByteBuffer buffer) {
4251                 // because java doesn't support unsigned types we use the next
4252                 // type that can hold all desired values
4253                 final var value = buffer.getInt(0);
4254 
4255                 loaderIterator.alpha = (short) value;
4256             }
4257         }
4258 
4259         /**
4260          * Reads red color component from temporal buffer using int32 data type.
4261          */
4262         private class RedInt32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4263 
4264             /**
4265              * Reads red color component from temporal buffer and sets its
4266              * value on current loader iterator.
4267              *
4268              * @param buffer Temporal buffer.
4269              */
4270             @Override
4271             public void readValueFromBuffer(final ByteBuffer buffer) {
4272                 final var value = buffer.getInt(0);
4273 
4274                 loaderIterator.red = (short) value;
4275             }
4276         }
4277 
4278         /**
4279          * Reads green color component from temporal buffer using int32 data
4280          * type.
4281          */
4282         private class GreenInt32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4283 
4284             /**
4285              * Reads green color component from temporal buffer and sets its
4286              * value on current loader iterator.
4287              *
4288              * @param buffer Temporal buffer.
4289              */
4290             @Override
4291             public void readValueFromBuffer(final ByteBuffer buffer) {
4292                 final var value = buffer.getInt(0);
4293 
4294                 loaderIterator.green = (short) value;
4295             }
4296         }
4297 
4298         /**
4299          * Reads blue color component from temporal buffer using int32 data
4300          * type.
4301          */
4302         private class BlueInt32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4303 
4304             /**
4305              * Reads blue color component from temporal buffer and sets its
4306              * value on current loader iterator.
4307              *
4308              * @param buffer Temporal buffer.
4309              */
4310             @Override
4311             public void readValueFromBuffer(final ByteBuffer buffer) {
4312                 final var value = buffer.getInt(0);
4313 
4314                 loaderIterator.blue = (short) value;
4315             }
4316         }
4317 
4318         /**
4319          * Reads alpha color component from temporal buffer using int32 data
4320          * type.
4321          */
4322         private class AlphaInt32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4323 
4324             /**
4325              * Reads alpha color component from temporal buffer and sets its
4326              * value on current loader iterator.
4327              *
4328              * @param buffer Temporal buffer.
4329              */
4330             @Override
4331             public void readValueFromBuffer(final ByteBuffer buffer) {
4332                 final var value = buffer.getInt(0);
4333 
4334                 loaderIterator.alpha = (short) value;
4335             }
4336         }
4337 
4338         /**
4339          * Reads red color component from temporal buffer using uint32 data
4340          * type.
4341          */
4342         private class RedUint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4343 
4344             /**
4345              * Reads red color component from temporal buffer and sets its value
4346              * on current loader iterator.
4347              *
4348              * @param buffer Temporal buffer.
4349              */
4350             @Override
4351             public void readValueFromBuffer(final ByteBuffer buffer) {
4352                 // because java doesn't support unsigned types we use the next
4353                 // type that can hold all desired values
4354                 final var value = buffer.getLong(0);
4355 
4356                 loaderIterator.red = (short) value;
4357             }
4358         }
4359 
4360         /**
4361          * Reads green color component from temporal buffer using uint32 data
4362          * type.
4363          */
4364         private class GreenUint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4365 
4366             /**
4367              * Reads green color component from temporal buffer and sets its
4368              * value on current loader iterator.
4369              *
4370              * @param buffer Temporal buffer.
4371              */
4372             @Override
4373             public void readValueFromBuffer(final ByteBuffer buffer) {
4374                 // because java doesn't support unsigned types we use the next
4375                 // type that can hold all desired values
4376                 final var value = buffer.getLong(0);
4377 
4378                 loaderIterator.green = (short) value;
4379             }
4380         }
4381 
4382         /**
4383          * Reads blue color component from temporal buffer using uint32 data
4384          * type.
4385          */
4386         private class BlueUint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4387 
4388             /**
4389              * Reads blue color component from temporal buffer and sets its
4390              * value on current loader iterator.
4391              *
4392              * @param buffer Temporal buffer.
4393              */
4394             @Override
4395             public void readValueFromBuffer(final ByteBuffer buffer) {
4396                 // because java doesn't support unsigned types we use the next
4397                 // type that can hold all desired values
4398                 final var value = buffer.getLong(0);
4399 
4400                 loaderIterator.blue = (short) value;
4401             }
4402         }
4403 
4404         /**
4405          * Reads alpha color component from temporal buffer using uint32 data
4406          * type.
4407          */
4408         private class AlphaUint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4409 
4410             /**
4411              * Reads alpha color component from temporal buffer and sets its
4412              * value on current loader iterator.
4413              *
4414              * @param buffer Temporal buffer.
4415              */
4416             @Override
4417             public void readValueFromBuffer(final ByteBuffer buffer) {
4418                 // because java doesn't support unsigned types we use the next
4419                 // type that can hold all desired values
4420                 final var value = buffer.getLong(0);
4421 
4422                 loaderIterator.alpha = (short) value;
4423             }
4424         }
4425 
4426         /**
4427          * Reads red color component from temporal buffer using float32 data
4428          * type.
4429          */
4430         private class RedFloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4431 
4432             /**
4433              * Reads red color component from temporal buffer and sets its value
4434              * on current loader iterator.
4435              *
4436              * @param buffer Temporal buffer.
4437              */
4438             @Override
4439             public void readValueFromBuffer(final ByteBuffer buffer) {
4440                 final var value = buffer.getFloat(0);
4441 
4442                 loaderIterator.red = (short) value;
4443             }
4444         }
4445 
4446         /**
4447          * Reads green color component from temporal buffer using float32 data
4448          * type.
4449          */
4450         private class GreenFloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4451 
4452             /**
4453              * Reads green color component from temporal buffer and sets its
4454              * value on current loader iterator.
4455              *
4456              * @param buffer Temporal buffer.
4457              */
4458             @Override
4459             public void readValueFromBuffer(final ByteBuffer buffer) {
4460                 final var value = buffer.getFloat(0);
4461 
4462                 loaderIterator.green = (short) value;
4463             }
4464         }
4465 
4466         /**
4467          * Reads blue color component from temporal buffer using float32 data
4468          * type.
4469          */
4470         private class BlueFloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4471 
4472             /**
4473              * Reads blue color component from temporal buffer and sets its
4474              * value on current loader iterator.
4475              *
4476              * @param buffer Temporal buffer.
4477              */
4478             @Override
4479             public void readValueFromBuffer(final ByteBuffer buffer) {
4480                 final var value = buffer.getFloat(0);
4481 
4482                 loaderIterator.blue = (short) value;
4483             }
4484         }
4485 
4486         /**
4487          * Reads alpha color component from temporal buffer using float32 data
4488          * type.
4489          */
4490         private class AlphaFloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4491 
4492             /**
4493              * Reads alpha color component from temporal buffer and sets its
4494              * value on current loader iterator.
4495              *
4496              * @param buffer Temporal buffer.
4497              */
4498             @Override
4499             public void readValueFromBuffer(final ByteBuffer buffer) {
4500                 final var value = buffer.getFloat(0);
4501 
4502                 loaderIterator.alpha = (short) value;
4503             }
4504         }
4505 
4506         /**
4507          * Reads red color component from temporal buffer using float64 data
4508          * type.
4509          */
4510         private class RedFloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4511 
4512             /**
4513              * Reads red color component from temporal buffer and sets its
4514              * value on current loader iterator.
4515              *
4516              * @param buffer Temporal buffer.
4517              */
4518             @Override
4519             public void readValueFromBuffer(final ByteBuffer buffer) {
4520                 final var value = buffer.getDouble(0);
4521 
4522                 loaderIterator.red = (short) value;
4523             }
4524         }
4525 
4526         /**
4527          * Reads green color component from temporal buffer using float64 data
4528          * type.
4529          */
4530         private class GreenFloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4531 
4532             /**
4533              * Reads green color component from temporal buffer and sets its
4534              * value on current loader iterator.
4535              *
4536              * @param buffer Temporal buffer.
4537              */
4538             @Override
4539             public void readValueFromBuffer(final ByteBuffer buffer) {
4540                 final var value = buffer.getDouble(0);
4541 
4542                 loaderIterator.green = (short) value;
4543             }
4544         }
4545 
4546         /**
4547          * Reads blue color component from temporal buffer using float64 data
4548          * type.
4549          */
4550         private class BlueFloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4551 
4552             /**
4553              * Reads blue color component from temporal buffer and sets its
4554              * value on current loader iterator.
4555              *
4556              * @param buffer Temporal buffer.
4557              */
4558             @Override
4559             public void readValueFromBuffer(final ByteBuffer buffer) {
4560                 final var value = buffer.getDouble(0);
4561 
4562                 loaderIterator.blue = (short) value;
4563             }
4564         }
4565 
4566         /**
4567          * Reads alpha color component from temporal buffer using float64 data
4568          * type.
4569          */
4570         private class AlphaFloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4571 
4572             /**
4573              * Reads alpha color component from temporal buffer and sets its
4574              * value on current loader iterator.
4575              *
4576              * @param buffer Temporal buffer.
4577              */
4578             @Override
4579             public void readValueFromBuffer(final ByteBuffer buffer) {
4580                 final var value = buffer.getDouble(0);
4581 
4582                 loaderIterator.alpha = (short) value;
4583             }
4584         }
4585 
4586         /**
4587          * Reads red color component from temporal buffer using char data type.
4588          */
4589         private class RedCharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4590 
4591             /**
4592              * Reads red color component from temporal buffer and sets its value
4593              * on current loader iterator.
4594              *
4595              * @param buffer Temporal buffer.
4596              */
4597             @Override
4598             public void readValueFromBuffer(final ByteBuffer buffer) {
4599                 loaderIterator.red = buffer.get(0);
4600             }
4601         }
4602 
4603         /**
4604          * Reads green color component from temporal buffer using char data
4605          * type.
4606          */
4607         private class GreenCharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4608 
4609             /**
4610              * Reads green color component from temporal buffer and sets its
4611              * value on current loader iterator.
4612              *
4613              * @param buffer Temporal buffer.
4614              */
4615             @Override
4616             public void readValueFromBuffer(final ByteBuffer buffer) {
4617                 loaderIterator.green = buffer.get(0);
4618             }
4619         }
4620 
4621         /**
4622          * Reads blue color component from temporal buffer using char data type.
4623          */
4624         private class BlueCharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4625 
4626             /**
4627              * Reads blue color component from temporal buffer and sets its
4628              * value on current loader iterator.
4629              *
4630              * @param buffer Temporal buffer.
4631              */
4632             @Override
4633             public void readValueFromBuffer(final ByteBuffer buffer) {
4634                 loaderIterator.blue = buffer.get(0);
4635             }
4636         }
4637 
4638         /**
4639          * Reads alpha color component from temporal buffer using char data
4640          * type.
4641          */
4642         private class AlphaCharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4643 
4644             /**
4645              * Reads alpha color component from temporal buffer and sets its
4646              * value on current loader iterator.
4647              *
4648              * @param buffer Temporal buffer.
4649              */
4650             @Override
4651             public void readValueFromBuffer(final ByteBuffer buffer) {
4652                 loaderIterator.alpha = buffer.get(0);
4653             }
4654         }
4655 
4656         /**
4657          * Reads red color component from temporal buffer using uchar data type.
4658          */
4659         private class RedUcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4660 
4661             /**
4662              * Reads red color component from temporal buffer and sets its value
4663              * on current loader iterator.
4664              *
4665              * @param buffer Temporal buffer.
4666              */
4667             @Override
4668             public void readValueFromBuffer(final ByteBuffer buffer) {
4669                 // because java doesn't support unsigned types we use the next
4670                 // type that can hold all desired values
4671                 loaderIterator.red = buffer.getShort(0);
4672             }
4673         }
4674 
4675         /**
4676          * Reads green color component from temporal buffer using uchar data
4677          * type.
4678          */
4679         private class GreenUcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4680 
4681             /**
4682              * Reads green color component from temporal buffer and sets its
4683              * value on current loader iterator.
4684              *
4685              * @param buffer Temporal buffer.
4686              */
4687             @Override
4688             public void readValueFromBuffer(final ByteBuffer buffer) {
4689                 // because java doesn't support unsigned types we use the next
4690                 // type that can hold all desired values
4691                 loaderIterator.green = buffer.getShort(0);
4692             }
4693         }
4694 
4695         /**
4696          * Reads blue color component from temporal buffer using uchar data
4697          * type.
4698          */
4699         private class BlueUcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4700 
4701             /**
4702              * Reads blue color component from temporal buffer and sets its
4703              * value on current loader iterator.
4704              *
4705              * @param buffer Temporal buffer.
4706              */
4707             @Override
4708             public void readValueFromBuffer(final ByteBuffer buffer) {
4709                 // because java doesn't support unsigned types we use the next
4710                 // type that can hold all desired values
4711                 loaderIterator.blue = buffer.getShort(0);
4712             }
4713         }
4714 
4715         /**
4716          * Reads alpha color component from temporal buffer using uchar data
4717          * type.
4718          */
4719         private class AlphaUcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4720 
4721             /**
4722              * Reads alpha color component from temporal buffer and sets its
4723              * value on current loader iterator.
4724              *
4725              * @param buffer Temporal buffer.
4726              */
4727             @Override
4728             public void readValueFromBuffer(final ByteBuffer buffer) {
4729                 // because java doesn't support unsigned types we use the next
4730                 // type that can hold all desired values
4731                 loaderIterator.alpha = buffer.getShort(0);
4732             }
4733         }
4734 
4735         /**
4736          * Reads red color component from temporal buffer using short data type.
4737          */
4738         private class RedShortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4739 
4740             /**
4741              * Reads red color component from temporal buffer and sets its value
4742              * on current loader iterator.
4743              *
4744              * @param buffer Temporal buffer.
4745              */
4746             @Override
4747             public void readValueFromBuffer(final ByteBuffer buffer) {
4748                 loaderIterator.red = buffer.getShort(0);
4749             }
4750         }
4751 
4752         /**
4753          * Reads green color component from temporal buffer using short data
4754          * type.
4755          */
4756         private class GreenShortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4757 
4758             /**
4759              * Reads green color component from temporal buffer and sets its
4760              * value on current loader iterator.
4761              *
4762              * @param buffer Temporal buffer.
4763              */
4764             @Override
4765             public void readValueFromBuffer(final ByteBuffer buffer) {
4766                 loaderIterator.green = buffer.getShort(0);
4767             }
4768         }
4769 
4770         /**
4771          * Reads blue color component from temporal buffer using short data
4772          * type.
4773          */
4774         private class BlueShortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4775 
4776             /**
4777              * Reads blue color component from temporal buffer and sets its
4778              * value on current loader iterator.
4779              *
4780              * @param buffer Temporal buffer.
4781              */
4782             @Override
4783             public void readValueFromBuffer(final ByteBuffer buffer) {
4784                 loaderIterator.blue = buffer.getShort(0);
4785             }
4786         }
4787 
4788         /**
4789          * Reads alpha color component from temporal buffer using short data
4790          * type.
4791          */
4792         private class AlphaShortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4793 
4794             /**
4795              * Reads alpha color component from temporal buffer and sets its
4796              * value on current loader iterator.
4797              *
4798              * @param buffer Temporal buffer.
4799              */
4800             @Override
4801             public void readValueFromBuffer(final ByteBuffer buffer) {
4802                 loaderIterator.alpha = buffer.getShort(0);
4803             }
4804         }
4805 
4806         /**
4807          * Reads red color component from temporal buffer using ushort data
4808          * type.
4809          */
4810         private class RedUshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4811 
4812             /**
4813              * Reads red color component from temporal buffer and sets its value
4814              * on current loader iterator.
4815              *
4816              * @param buffer Temporal buffer.
4817              */
4818             @Override
4819             public void readValueFromBuffer(final ByteBuffer buffer) {
4820                 // because java doesn't support unsigned types we use the next
4821                 // type that can hold all desired values
4822                 final var value = buffer.getInt(0);
4823 
4824                 loaderIterator.red = (short) value;
4825             }
4826         }
4827 
4828         /**
4829          * Reads green color component from temporal buffer using ushort data
4830          * type.
4831          */
4832         private class GreenUshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4833 
4834             /**
4835              * Reads green color component from temporal buffer and sets its
4836              * value on current loader iterator.
4837              *
4838              * @param buffer Temporal buffer.
4839              */
4840             @Override
4841             public void readValueFromBuffer(final ByteBuffer buffer) {
4842                 // because java doesn't support unsigned types we use the next
4843                 // type that can hold all desired values
4844                 final var value = buffer.getInt(0);
4845 
4846                 loaderIterator.green = (short) value;
4847             }
4848         }
4849 
4850         /**
4851          * Reads blue color component from temporal buffer using ushort data
4852          * type.
4853          */
4854         private class BlueUshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4855 
4856             /**
4857              * Reads blue color component from temporal buffer and sets its
4858              * value on current loader iterator.
4859              *
4860              * @param buffer Temporal buffer.
4861              */
4862             @Override
4863             public void readValueFromBuffer(final ByteBuffer buffer) {
4864                 // because java doesn't support unsigned types we use the next
4865                 // type that can hold all desired values
4866                 final var value = buffer.getInt(0);
4867 
4868                 loaderIterator.blue = (short) value;
4869             }
4870         }
4871 
4872         /**
4873          * Reads alpha color component from temporal buffer using ushort data
4874          * type.
4875          */
4876         private class AlphaUshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4877 
4878             /**
4879              * Reads alpha color component from temporal buffer and sets its
4880              * value on current loader iterator.
4881              *
4882              * @param buffer Temporal buffer.
4883              */
4884             @Override
4885             public void readValueFromBuffer(final ByteBuffer buffer) {
4886                 // because java doesn't support unsigned types we use the next
4887                 // type that can hold all desired values
4888                 final var value = buffer.getInt(0);
4889 
4890                 loaderIterator.alpha = (short) value;
4891             }
4892         }
4893 
4894         /**
4895          * Reads red color component from temporal buffer using int data type.
4896          */
4897         private class RedIntReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4898 
4899             /**
4900              * Reads red color component from temporal buffer and sets its value
4901              * on current loader iterator.
4902              *
4903              * @param buffer Temporal buffer.
4904              */
4905             @Override
4906             public void readValueFromBuffer(final ByteBuffer buffer) {
4907                 final var value = buffer.getInt(0);
4908 
4909                 loaderIterator.red = (short) value;
4910             }
4911         }
4912 
4913         /**
4914          * Reads green color component from temporal buffer using int data type.
4915          */
4916         private class GreenIntReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4917 
4918             /**
4919              * Reads green color component from temporal buffer and sets its
4920              * value on current loader iterator.
4921              *
4922              * @param buffer Temporal buffer.
4923              */
4924             @Override
4925             public void readValueFromBuffer(final ByteBuffer buffer) {
4926                 final var value = buffer.getInt(0);
4927 
4928                 loaderIterator.green = (short) value;
4929             }
4930         }
4931 
4932         /**
4933          * Reads blue color component from temporal buffer using int data type.
4934          */
4935         private class BlueIntReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4936 
4937             /**
4938              * Reads blue color component from temporal buffer and sets its
4939              * value on current loader iterator.
4940              *
4941              * @param buffer Temporal buffer.
4942              */
4943             @Override
4944             public void readValueFromBuffer(final ByteBuffer buffer) {
4945                 final var value = buffer.getInt(0);
4946 
4947                 loaderIterator.blue = (short) value;
4948             }
4949         }
4950 
4951         /**
4952          * Reads alpha color component from temporal buffer using int data type.
4953          */
4954         private class AlphaIntReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4955 
4956             /**
4957              * Reads alpha color component from temporal buffer and sets its
4958              * value on current loader iterator.
4959              *
4960              * @param buffer Temporal buffer.
4961              */
4962             @Override
4963             public void readValueFromBuffer(final ByteBuffer buffer) {
4964                 final var value = buffer.getInt(0);
4965 
4966                 loaderIterator.alpha = (short) value;
4967             }
4968         }
4969 
4970         /**
4971          * Reads red color component from temporal buffer using uint data type.
4972          */
4973         private class RedUintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4974 
4975             /**
4976              * Reads red color component from temporal buffer and sets its value
4977              * on current loader iterator.
4978              *
4979              * @param buffer Temporal buffer.
4980              */
4981             @Override
4982             public void readValueFromBuffer(final ByteBuffer buffer) {
4983                 // because java doesn't support unsigned types we use the next
4984                 // type that can hold all desired values
4985                 final var value = buffer.getLong(0);
4986 
4987                 loaderIterator.red = (short) value;
4988             }
4989         }
4990 
4991         /**
4992          * Reads green color component from temporal buffer using uint data
4993          * type.
4994          */
4995         private class GreenUintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
4996 
4997             /**
4998              * Reads green color component from temporal buffer and sets its
4999              * value on current loader iterator.
5000              *
5001              * @param buffer Temporal buffer.
5002              */
5003             @Override
5004             public void readValueFromBuffer(final ByteBuffer buffer) {
5005                 // because java doesn't support unsigned types we use the next
5006                 // type that can hold all desired values
5007                 final var value = buffer.getLong(0);
5008 
5009                 loaderIterator.green = (short) value;
5010             }
5011         }
5012 
5013         /**
5014          * Reads blue color component from temporal buffer using uint data type.
5015          */
5016         private class BlueUintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5017 
5018             /**
5019              * Reads blue color component from temporal buffer and sets its
5020              * value on current loader iterator.
5021              *
5022              * @param buffer Temporal buffer.
5023              */
5024             @Override
5025             public void readValueFromBuffer(final ByteBuffer buffer) {
5026                 // because java doesn't support unsigned types we use the next
5027                 // type that can hold all desired values
5028                 final var value = buffer.getLong(0);
5029 
5030                 loaderIterator.blue = (short) value;
5031             }
5032         }
5033 
5034         /**
5035          * Reads alpha color component from temporal buffer using uint data
5036          * type.
5037          */
5038         private class AlphaUintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5039 
5040             /**
5041              * Reads alpha color component from temporal buffer and sets its
5042              * value on current loader iterator.
5043              *
5044              * @param buffer Temporal buffer.
5045              */
5046             @Override
5047             public void readValueFromBuffer(final ByteBuffer buffer) {
5048                 // because java doesn't support unsigned types we use the next
5049                 // type that can hold all desired values
5050                 final var value = buffer.getLong(0);
5051 
5052                 loaderIterator.alpha = (short) value;
5053             }
5054         }
5055 
5056         /**
5057          * Reads red color component from temporal buffer using float data type.
5058          */
5059         private class RedFloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5060 
5061             /**
5062              * Reads red color component from temporal buffer and sets its value
5063              * on current loader iterator.
5064              *
5065              * @param buffer Temporal buffer.
5066              */
5067             @Override
5068             public void readValueFromBuffer(final ByteBuffer buffer) {
5069                 final var value = buffer.getFloat(0);
5070 
5071                 loaderIterator.red = (short) value;
5072             }
5073         }
5074 
5075         /**
5076          * Reads green color component from temporal buffer using float data
5077          * type.
5078          */
5079         private class GreenFloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5080 
5081             /**
5082              * Reads green color component from temporal buffer and sets its
5083              * value on current loader iterator.
5084              *
5085              * @param buffer Temporal buffer.
5086              */
5087             @Override
5088             public void readValueFromBuffer(final ByteBuffer buffer) {
5089                 final var value = buffer.getFloat(0);
5090 
5091                 loaderIterator.green = (short) value;
5092             }
5093         }
5094 
5095         /**
5096          * Reads blue color component from temporal buffer using float data
5097          * type.
5098          */
5099         private class BlueFloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5100 
5101             /**
5102              * Reads blue color component from temporal buffer and sets its
5103              * value on current loader iterator.
5104              *
5105              * @param buffer Temporal buffer.
5106              */
5107             @Override
5108             public void readValueFromBuffer(final ByteBuffer buffer) {
5109                 final var value = buffer.getFloat(0);
5110 
5111                 loaderIterator.blue = (short) value;
5112             }
5113         }
5114 
5115         /**
5116          * Reads alpha color component from temporal buffer using float data
5117          * type.
5118          */
5119         private class AlphaFloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5120 
5121             /**
5122              * Reads alpha color component from temporal buffer and sets its
5123              * value on current loader iterator.
5124              *
5125              * @param buffer Temporal buffer.
5126              */
5127             @Override
5128             public void readValueFromBuffer(final ByteBuffer buffer) {
5129                 final var value = buffer.getFloat(0);
5130 
5131                 loaderIterator.alpha = (short) value;
5132             }
5133         }
5134 
5135         /**
5136          * Reads red color component from temporal buffer using double data
5137          * type.
5138          */
5139         private class RedDoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5140 
5141             /**
5142              * Reads red color component from temporal buffer and sets its value
5143              * on current loader iterator.
5144              *
5145              * @param buffer Temporal buffer.
5146              */
5147             @Override
5148             public void readValueFromBuffer(final ByteBuffer buffer) {
5149                 final var value = buffer.getDouble(0);
5150 
5151                 loaderIterator.red = (short) value;
5152             }
5153         }
5154 
5155         /**
5156          * Reads green color component from temporal buffer using double data
5157          * type.
5158          */
5159         private class GreenDoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5160 
5161             /**
5162              * Reads green color component from temporal buffer and sets its
5163              * value on current loader iterator.
5164              *
5165              * @param buffer Temporal buffer.
5166              */
5167             @Override
5168             public void readValueFromBuffer(final ByteBuffer buffer) {
5169                 final var value = buffer.getDouble(0);
5170 
5171                 loaderIterator.green = (short) value;
5172             }
5173         }
5174 
5175         /**
5176          * Reads blue color component from temporal buffer using double data
5177          * type.
5178          */
5179         private class BlueDoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5180 
5181             /**
5182              * Reads blue color component from temporal buffer and sets its
5183              * value on current loader iterator.
5184              *
5185              * @param buffer Temporal buffer.
5186              */
5187             @Override
5188             public void readValueFromBuffer(final ByteBuffer buffer) {
5189                 final var value = buffer.getDouble(0);
5190 
5191                 loaderIterator.blue = (short) value;
5192             }
5193         }
5194 
5195         /**
5196          * Reads alpha color component from temporal buffer using double data
5197          * type.
5198          */
5199         private class AlphaDoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5200 
5201             /**
5202              * Reads alpha color component from temporal buffer and sets its
5203              * value on current loader iterator.
5204              *
5205              * @param buffer Temporal buffer.
5206              */
5207             @Override
5208             public void readValueFromBuffer(final ByteBuffer buffer) {
5209                 final var value = buffer.getDouble(0);
5210 
5211                 loaderIterator.alpha = (short) value;
5212             }
5213         }
5214 
5215         /**
5216          * Reads a vertex normal x coordinate component from temporal buffer
5217          * using int8 type.
5218          */
5219         private class NXint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5220 
5221             /**
5222              * Reads a vertex normal x coordinate from temporal buffer and sets
5223              * its value on current loader iterator.
5224              *
5225              * @param buffer Temporal buffer.
5226              */
5227             @Override
5228             public void readValueFromBuffer(final ByteBuffer buffer) {
5229                 loaderIterator.nX = buffer.get(0);
5230             }
5231         }
5232 
5233         /**
5234          * Reads a vertex normal y coordinate component from temporal buffer
5235          * using int8 type.
5236          */
5237         private class NYint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5238 
5239             /**
5240              * Reads a vertex normal y coordinate from temporal buffer and sets
5241              * its value on current loader iterator.
5242              *
5243              * @param buffer Temporal buffer.
5244              */
5245             @Override
5246             public void readValueFromBuffer(final ByteBuffer buffer) {
5247                 loaderIterator.nY = buffer.get(0);
5248             }
5249         }
5250 
5251         /**
5252          * Reads a vertex normal z coordinate component from temporal buffer
5253          * using int8 type.
5254          */
5255         private class NZint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5256 
5257             /**
5258              * Reads a vertex normal z coordinate from temporal buffer and sets
5259              * its value on current loader iterator.
5260              *
5261              * @param buffer Temporal buffer.
5262              */
5263             @Override
5264             public void readValueFromBuffer(final ByteBuffer buffer) {
5265                 loaderIterator.nZ = buffer.get(0);
5266             }
5267         }
5268 
5269         /**
5270          * Reads a vertex normal x coordinate component from temporal buffer
5271          * using uint8 type.
5272          */
5273         private class NXuint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5274 
5275             /**
5276              * Reads a vertex normal x coordinate from temporal buffer and sets
5277              * its value on current loader iterator.
5278              *
5279              * @param buffer Temporal buffer.
5280              */
5281             @Override
5282             public void readValueFromBuffer(final ByteBuffer buffer) {
5283                 // because java doesn't support unsigned types we use the next
5284                 // type that can hold all desired values
5285                 loaderIterator.nX = buffer.getShort(0);
5286             }
5287         }
5288 
5289         /**
5290          * Reads a vertex normal y coordinate component from temporal buffer
5291          * using uint8 type.
5292          */
5293         private class NYuint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5294 
5295             /**
5296              * Reads a vertex normal y coordinate from temporal buffer and sets
5297              * its value on current loader iterator.
5298              *
5299              * @param buffer Temporal buffer.
5300              */
5301             @Override
5302             public void readValueFromBuffer(final ByteBuffer buffer) {
5303                 // because java doesn't support unsigned types we use the next
5304                 // type that can hold all desired values
5305                 loaderIterator.nY = buffer.getShort(0);
5306             }
5307         }
5308 
5309         /**
5310          * Reads a vertex normal z coordinate component from temporal buffer
5311          * using uint8 type.
5312          */
5313         private class NZuint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5314 
5315             /**
5316              * Reads a vertex normal z coordinate from temporal buffer and sets
5317              * its value on current loader iterator.
5318              *
5319              * @param buffer Temporal buffer.
5320              */
5321             @Override
5322             public void readValueFromBuffer(final ByteBuffer buffer) {
5323                 // because java doesn't support unsigned types we use the next
5324                 // type that can hold all desired values
5325                 loaderIterator.nZ = buffer.getShort(0);
5326             }
5327         }
5328 
5329         /**
5330          * Reads a vertex normal x coordinate component from temporal buffer
5331          * using int16 type.
5332          */
5333         private class NXint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5334 
5335             /**
5336              * Reads a vertex normal x coordinate from temporal buffer and sets
5337              * its value on current loader iterator.
5338              *
5339              * @param buffer Temporal buffer.
5340              */
5341             @Override
5342             public void readValueFromBuffer(final ByteBuffer buffer) {
5343                 loaderIterator.nX = buffer.getShort(0);
5344             }
5345         }
5346 
5347         /**
5348          * Reads a vertex normal y coordinate component from temporal buffer
5349          * using int16 type.
5350          */
5351         private class NYint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5352 
5353             /**
5354              * Reads a vertex normal y coordinate from temporal buffer and sets
5355              * its value on current loader iterator.
5356              *
5357              * @param buffer Temporal buffer.
5358              */
5359             @Override
5360             public void readValueFromBuffer(final ByteBuffer buffer) {
5361                 loaderIterator.nY = buffer.getShort(0);
5362             }
5363         }
5364 
5365         /**
5366          * Reads a vertex normal z coordinate component from temporal buffer
5367          * using int16 type.
5368          */
5369         private class NZint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5370 
5371             /**
5372              * Reads a vertex normal z coordinate from temporal buffer and sets
5373              * its value on current loader iterator.
5374              *
5375              * @param buffer Temporal buffer.
5376              */
5377             @Override
5378             public void readValueFromBuffer(final ByteBuffer buffer) {
5379                 loaderIterator.nZ = buffer.getShort(0);
5380             }
5381         }
5382 
5383         /**
5384          * Reads a vertex normal x coordinate component from temporal buffer
5385          * using uint16 type.
5386          */
5387         private class NXuint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5388 
5389             /**
5390              * Reads a vertex normal x coordinate from temporal buffer and sets
5391              * its value on current loader iterator.
5392              *
5393              * @param buffer Temporal buffer.
5394              */
5395             @Override
5396             public void readValueFromBuffer(final ByteBuffer buffer) {
5397                 // because java doesn't support unsigned types we use the next
5398                 // type that can hold all desired values
5399                 loaderIterator.nX = buffer.getInt(0);
5400             }
5401         }
5402 
5403         /**
5404          * Reads a vertex normal y coordinate component from temporal buffer
5405          * using uint16 type.
5406          */
5407         private class NYuint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5408 
5409             /**
5410              * Reads a vertex normal y coordinate from temporal buffer and sets
5411              * its value on current loader iterator.
5412              *
5413              * @param buffer Temporal buffer.
5414              */
5415             @Override
5416             public void readValueFromBuffer(final ByteBuffer buffer) {
5417                 // because java doesn't support unsigned types we use the next
5418                 // type that can hold all desired values
5419                 loaderIterator.nY = buffer.getInt(0);
5420             }
5421         }
5422 
5423         /**
5424          * Reads a vertex normal z coordinate component from temporal buffer
5425          * using uint16 type.
5426          */
5427         private class NZuint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5428 
5429             /**
5430              * Reads a vertex normal z coordinate from temporal buffer and sets
5431              * its value on current loader iterator.
5432              *
5433              * @param buffer Temporal buffer.
5434              */
5435             @Override
5436             public void readValueFromBuffer(final ByteBuffer buffer) {
5437                 // because java doesn't support unsigned types we use the next
5438                 // type that can hold all desired values
5439                 loaderIterator.nZ = buffer.getInt(0);
5440             }
5441         }
5442 
5443         /**
5444          * Reads a vertex normal x coordinate component from temporal buffer
5445          * using int32 type.
5446          */
5447         private class NXint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5448 
5449             /**
5450              * Reads a vertex normal x coordinate from temporal buffer and sets
5451              * its value on current loader iterator.
5452              *
5453              * @param buffer Temporal buffer.
5454              */
5455             @Override
5456             public void readValueFromBuffer(final ByteBuffer buffer) {
5457                 loaderIterator.nX = buffer.getInt(0);
5458             }
5459         }
5460 
5461         /**
5462          * Reads a vertex normal y coordinate component from temporal buffer
5463          * using int32 type.
5464          */
5465         private class NYint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5466 
5467             /**
5468              * Reads a vertex normal y coordinate from temporal buffer and sets
5469              * its value on current loader iterator.
5470              *
5471              * @param buffer Temporal buffer.
5472              */
5473             @Override
5474             public void readValueFromBuffer(final ByteBuffer buffer) {
5475                 loaderIterator.nY = buffer.getInt(0);
5476             }
5477         }
5478 
5479         /**
5480          * Reads a vertex normal z coordinate component from temporal buffer
5481          * using int32 type.
5482          */
5483         private class NZint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5484 
5485             /**
5486              * Reads a vertex normal z coordinate from temporal buffer and sets
5487              * its value on current loader iterator.
5488              *
5489              * @param buffer Temporal buffer.
5490              */
5491             @Override
5492             public void readValueFromBuffer(final ByteBuffer buffer) {
5493                 loaderIterator.nZ = buffer.getInt(0);
5494             }
5495         }
5496 
5497         /**
5498          * Reads a vertex normal x coordinate component from temporal buffer
5499          * using int32 type.
5500          */
5501         private class NXuint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5502 
5503             /**
5504              * Reads a vertex normal x coordinate from temporal buffer and sets
5505              * its value on current loader iterator.
5506              *
5507              * @param buffer Temporal buffer.
5508              */
5509             @Override
5510             public void readValueFromBuffer(final ByteBuffer buffer) {
5511                 // because java doesn't support unsigned types we use the next
5512                 // type that can hold all desired values
5513                 loaderIterator.nX = buffer.getLong(0);
5514             }
5515         }
5516 
5517         /**
5518          * Reads a vertex normal y coordinate component from temporal buffer
5519          * using uint32 type.
5520          */
5521         private class NYuint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5522 
5523             /**
5524              * Reads a vertex normal y coordinate from temporal buffer and sets
5525              * its value on current loader iterator.
5526              *
5527              * @param buffer Temporal buffer.
5528              */
5529             @Override
5530             public void readValueFromBuffer(final ByteBuffer buffer) {
5531                 // because java doesn't support unsigned types we use the next
5532                 // type that can hold all desired values
5533                 loaderIterator.nY = buffer.getLong(0);
5534             }
5535         }
5536 
5537         /**
5538          * Reads a vertex normal z coordinate component from temporal buffer
5539          * using uint32 type.
5540          */
5541         private class NZuint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5542 
5543             /**
5544              * Reads a vertex normal z coordinate from temporal buffer and sets
5545              * its value on current loader iterator.
5546              *
5547              * @param buffer Temporal buffer.
5548              */
5549             @Override
5550             public void readValueFromBuffer(final ByteBuffer buffer) {
5551                 // because java doesn't support unsigned types we use the next
5552                 // type that can hold all desired values
5553                 loaderIterator.nZ = buffer.getLong(0);
5554             }
5555         }
5556 
5557         /**
5558          * Reads a vertex normal x coordinate component from temporal buffer
5559          * using float32 type.
5560          */
5561         private class NXfloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5562 
5563             /**
5564              * Reads a vertex normal x coordinate from temporal buffer and sets
5565              * its value on current loader iterator.
5566              *
5567              * @param buffer Temporal buffer.
5568              */
5569             @Override
5570             public void readValueFromBuffer(final ByteBuffer buffer) {
5571                 loaderIterator.nX = buffer.getFloat(0);
5572             }
5573         }
5574 
5575         /**
5576          * Reads a vertex normal y coordinate component from temporal buffer
5577          * using float32 type.
5578          */
5579         private class NYfloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5580 
5581             /**
5582              * Reads a vertex normal y coordinate from temporal buffer and sets
5583              * its value on current loader iterator.
5584              *
5585              * @param buffer Temporal buffer.
5586              */
5587             @Override
5588             public void readValueFromBuffer(final ByteBuffer buffer) {
5589                 loaderIterator.nY = buffer.getFloat(0);
5590             }
5591         }
5592 
5593         /**
5594          * Reads a vertex normal z coordinate component from temporal buffer
5595          * using float32 type.
5596          */
5597         private class NZfloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5598 
5599             /**
5600              * Reads a vertex normal z coordinate from temporal buffer and sets
5601              * its value on current loader iterator.
5602              *
5603              * @param buffer Temporal buffer.
5604              */
5605             @Override
5606             public void readValueFromBuffer(final ByteBuffer buffer) {
5607                 loaderIterator.nZ = buffer.getFloat(0);
5608             }
5609         }
5610 
5611         /**
5612          * Reads a vertex normal x coordinate component from temporal buffer
5613          * using float64 type.
5614          */
5615         private class NXfloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5616 
5617             /**
5618              * Reads a vertex normal x coordinate from temporal buffer and sets
5619              * its value on current loader iterator.
5620              *
5621              * @param buffer Temporal buffer.
5622              */
5623             @Override
5624             public void readValueFromBuffer(final ByteBuffer buffer) {
5625                 final var value = buffer.getDouble(0);
5626 
5627                 loaderIterator.nX = (float) value;
5628             }
5629         }
5630 
5631         /**
5632          * Reads a vertex normal y coordinate component from temporal buffer
5633          * using float64 type.
5634          */
5635         private class NYfloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5636 
5637             /**
5638              * Reads a vertex normal y coordinate from temporal buffer and sets
5639              * its value on current loader iterator.
5640              *
5641              * @param buffer Temporal buffer.
5642              */
5643             @Override
5644             public void readValueFromBuffer(final ByteBuffer buffer) {
5645                 final var value = buffer.getDouble(0);
5646 
5647                 loaderIterator.nY = (float) value;
5648             }
5649         }
5650 
5651         /**
5652          * Reads a vertex normal z coordinate component from temporal buffer
5653          * using float64 type.
5654          */
5655         private class NZfloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5656 
5657             /**
5658              * Reads a vertex normal z coordinate from temporal buffer and sets
5659              * its value on current loader iterator.
5660              *
5661              * @param buffer Temporal buffer.
5662              */
5663             @Override
5664             public void readValueFromBuffer(final ByteBuffer buffer) {
5665                 final var value = buffer.getDouble(0);
5666 
5667                 loaderIterator.nZ = (float) value;
5668             }
5669         }
5670 
5671         /**
5672          * Reads a vertex normal x coordinate component from temporal buffer
5673          * using char type.
5674          */
5675         private class NXcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5676 
5677             /**
5678              * Reads a vertex normal x coordinate from temporal buffer and sets
5679              * its value on current loader iterator.
5680              *
5681              * @param buffer Temporal buffer.
5682              */
5683             @Override
5684             public void readValueFromBuffer(final ByteBuffer buffer) {
5685                 loaderIterator.nX = buffer.get(0);
5686             }
5687         }
5688 
5689         /**
5690          * Reads a vertex normal y coordinate component from temporal buffer
5691          * using char type.
5692          */
5693         private class NYcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5694 
5695             /**
5696              * Reads a vertex normal y coordinate from temporal buffer and sets
5697              * its value on current loader iterator.
5698              *
5699              * @param buffer Temporal buffer.
5700              */
5701             @Override
5702             public void readValueFromBuffer(final ByteBuffer buffer) {
5703                 loaderIterator.nY = buffer.get(0);
5704             }
5705         }
5706 
5707         /**
5708          * Reads a vertex normal z coordinate component from temporal buffer
5709          * using char type.
5710          */
5711         private class NZcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5712 
5713             /**
5714              * Reads a vertex normal z coordinate from temporal buffer and sets
5715              * its value on current loader iterator.
5716              *
5717              * @param buffer Temporal buffer.
5718              */
5719             @Override
5720             public void readValueFromBuffer(final ByteBuffer buffer) {
5721                 loaderIterator.nZ = buffer.get(0);
5722             }
5723         }
5724 
5725         /**
5726          * Reads a vertex normal x coordinate component from temporal buffer
5727          * using uchar type.
5728          */
5729         private class NXucharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5730 
5731             /**
5732              * Reads a vertex normal x coordinate from temporal buffer and sets
5733              * its value on current loader iterator.
5734              *
5735              * @param buffer Temporal buffer.
5736              */
5737             @Override
5738             public void readValueFromBuffer(final ByteBuffer buffer) {
5739                 // because java doesn't support unsigned types we use the next
5740                 // type that can hold all desired values
5741                 loaderIterator.nX = buffer.getShort(0);
5742             }
5743         }
5744 
5745         /**
5746          * Reads a vertex normal y coordinate component from temporal buffer
5747          * using uchar type.
5748          */
5749         private class NYucharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5750 
5751             /**
5752              * Reads a vertex normal y coordinate from temporal buffer and sets
5753              * its value on current loader iterator.
5754              *
5755              * @param buffer Temporal buffer.
5756              */
5757             @Override
5758             public void readValueFromBuffer(final ByteBuffer buffer) {
5759                 // because java doesn't support unsigned types we use the next
5760                 // type that can hold all desired values
5761                 loaderIterator.nY = buffer.getShort(0);
5762             }
5763         }
5764 
5765         /**
5766          * Reads a vertex normal z coordinate component from temporal buffer
5767          * using uchar type.
5768          */
5769         private class NZucharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5770 
5771             /**
5772              * Reads a vertex normal z coordinate from temporal buffer and sets
5773              * its value on current loader iterator.
5774              *
5775              * @param buffer Temporal buffer.
5776              */
5777             @Override
5778             public void readValueFromBuffer(final ByteBuffer buffer) {
5779                 // because java doesn't support unsigned types we use the next
5780                 // type that can hold all desired values
5781                 loaderIterator.nZ = buffer.getShort(0);
5782             }
5783         }
5784 
5785         /**
5786          * Reads a vertex normal x coordinate component from temporal buffer
5787          * using short type.
5788          */
5789         private class NXshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5790 
5791             /**
5792              * Reads a vertex normal x coordinate from temporal buffer and sets
5793              * its value on current loader iterator.
5794              *
5795              * @param buffer Temporal buffer.
5796              */
5797             @Override
5798             public void readValueFromBuffer(final ByteBuffer buffer) {
5799                 loaderIterator.nX = buffer.getShort(0);
5800             }
5801         }
5802 
5803         /**
5804          * Reads a vertex normal y coordinate component from temporal buffer
5805          * using short type.
5806          */
5807         private class NYshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5808 
5809             /**
5810              * Reads a vertex normal y coordinate from temporal buffer and sets
5811              * its value on current loader iterator.
5812              *
5813              * @param buffer Temporal buffer.
5814              */
5815             @Override
5816             public void readValueFromBuffer(final ByteBuffer buffer) {
5817                 loaderIterator.nY = buffer.getShort(0);
5818             }
5819         }
5820 
5821         /**
5822          * Reads a vertex normal z coordinate component from temporal buffer
5823          * using short type.
5824          */
5825         private class NZshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5826 
5827             /**
5828              * Reads a vertex normal z coordinate from temporal buffer and sets
5829              * its value on current loader iterator.
5830              *
5831              * @param buffer Temporal buffer.
5832              */
5833             @Override
5834             public void readValueFromBuffer(final ByteBuffer buffer) {
5835                 loaderIterator.nZ = buffer.getShort(0);
5836             }
5837         }
5838 
5839         /**
5840          * Reads a vertex normal x coordinate component from temporal buffer
5841          * using ushort type.
5842          */
5843         private class NXushortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5844 
5845             /**
5846              * Reads a vertex normal x coordinate from temporal buffer and sets
5847              * its value on current loader iterator.
5848              *
5849              * @param buffer Temporal buffer.
5850              */
5851             @Override
5852             public void readValueFromBuffer(final ByteBuffer buffer) {
5853                 // because java doesn't support unsigned types we use the next
5854                 // type that can hold all desired values
5855                 loaderIterator.nX = buffer.getInt(0);
5856             }
5857         }
5858 
5859         /**
5860          * Reads a vertex normal y coordinate component from temporal buffer
5861          * using ushort type.
5862          */
5863         private class NYushortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5864 
5865             /**
5866              * Reads a vertex normal y coordinate from temporal buffer and sets
5867              * its value on current loader iterator.
5868              *
5869              * @param buffer Temporal buffer.
5870              */
5871             @Override
5872             public void readValueFromBuffer(final ByteBuffer buffer) {
5873                 // because java doesn't support unsigned types we use the next
5874                 // type that can hold all desired values
5875                 loaderIterator.nY = buffer.getInt(0);
5876             }
5877         }
5878 
5879         /**
5880          * Reads a vertex normal z coordinate component from temporal buffer
5881          * using ushort type.
5882          */
5883         private class NZushortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5884 
5885             /**
5886              * Reads a vertex normal z coordinate from temporal buffer and sets
5887              * its value on current loader iterator.
5888              *
5889              * @param buffer Temporal buffer.
5890              */
5891             @Override
5892             public void readValueFromBuffer(final ByteBuffer buffer) {
5893                 // because java doesn't support unsigned types we use the next
5894                 // type that can hold all desired values
5895                 loaderIterator.nZ = buffer.getInt(0);
5896             }
5897         }
5898 
5899         /**
5900          * Reads a vertex normal x coordinate component from temporal buffer
5901          * using int type.
5902          */
5903         private class NXintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5904 
5905             /**
5906              * Reads a vertex normal x coordinate from temporal buffer and sets
5907              * its value on current loader iterator.
5908              *
5909              * @param buffer Temporal buffer.
5910              */
5911             @Override
5912             public void readValueFromBuffer(final ByteBuffer buffer) {
5913                 loaderIterator.nX = buffer.getInt(0);
5914             }
5915         }
5916 
5917         /**
5918          * Reads a vertex normal y coordinate component from temporal buffer
5919          * using int type.
5920          */
5921         private class NYintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5922 
5923             /**
5924              * Reads a vertex normal y coordinate from temporal buffer and sets
5925              * its value on current loader iterator.
5926              *
5927              * @param buffer Temporal buffer.
5928              */
5929             @Override
5930             public void readValueFromBuffer(final ByteBuffer buffer) {
5931                 loaderIterator.nY = buffer.getInt(0);
5932             }
5933         }
5934 
5935         /**
5936          * Reads a vertex normal z coordinate component from temporal buffer
5937          * using int type.
5938          */
5939         private class NZintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5940 
5941             /**
5942              * Reads a vertex normal z coordinate from temporal buffer and sets
5943              * its value on current loader iterator.
5944              *
5945              * @param buffer Temporal buffer.
5946              */
5947             @Override
5948             public void readValueFromBuffer(final ByteBuffer buffer) {
5949                 loaderIterator.nZ = buffer.getInt(0);
5950             }
5951         }
5952 
5953         /**
5954          * Reads a vertex normal x coordinate component from temporal buffer
5955          * using uint type.
5956          */
5957         private class NXuintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5958 
5959             /**
5960              * Reads a vertex normal x coordinate from temporal buffer and sets
5961              * its value on current loader iterator.
5962              *
5963              * @param buffer Temporal buffer.
5964              */
5965             @Override
5966             public void readValueFromBuffer(final ByteBuffer buffer) {
5967                 // because java doesn't support unsigned types we use the next
5968                 // type that can hold all desired values
5969                 loaderIterator.nX = buffer.getLong(0);
5970             }
5971         }
5972 
5973         /**
5974          * Reads a vertex normal y coordinate component from temporal buffer
5975          * using uint type.
5976          */
5977         private class NYuintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5978 
5979             /**
5980              * Reads a vertex normal y coordinate from temporal buffer and sets
5981              * its value on current loader iterator.
5982              *
5983              * @param buffer Temporal buffer.
5984              */
5985             @Override
5986             public void readValueFromBuffer(final ByteBuffer buffer) {
5987                 // because java doesn't support unsigned types we use the next
5988                 // type that can hold all desired values
5989                 loaderIterator.nY = buffer.getLong(0);
5990             }
5991         }
5992 
5993         /**
5994          * Reads a vertex normal z coordinate component from temporal buffer
5995          * using uint type.
5996          */
5997         private class NZuintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
5998 
5999             /**
6000              * Reads a vertex normal z coordinate from temporal buffer and sets
6001              * its value on current loader iterator.
6002              *
6003              * @param buffer Temporal buffer.
6004              */
6005             @Override
6006             public void readValueFromBuffer(final ByteBuffer buffer) {
6007                 // because java doesn't support unsigned types we use the next
6008                 // type that can hold all desired values
6009                 loaderIterator.nZ = buffer.getLong(0);
6010             }
6011         }
6012 
6013         /**
6014          * Reads a vertex normal x coordinate component form temporal buffer
6015          * using float type.
6016          */
6017         private class NXfloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6018 
6019             /**
6020              * Reads a vertex normal x coordinate from temporal buffer and sets
6021              * its value on current loader iterator.
6022              *
6023              * @param buffer Temporal buffer.
6024              */
6025             @Override
6026             public void readValueFromBuffer(final ByteBuffer buffer) {
6027                 loaderIterator.nX = buffer.getFloat(0);
6028             }
6029         }
6030 
6031         /**
6032          * Reads a vertex normal y coordinate component from temporal buffer
6033          * using float type.
6034          */
6035         private class NYfloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6036 
6037             /**
6038              * Reads a vertex normal y coordinate from temporal buffer and sets
6039              * its value on current loader iterator.
6040              *
6041              * @param buffer Temporal buffer.
6042              */
6043             @Override
6044             public void readValueFromBuffer(final ByteBuffer buffer) {
6045                 loaderIterator.nY = buffer.getFloat(0);
6046             }
6047         }
6048 
6049         /**
6050          * Reads a vertex normal z coordinate component from temporal buffer
6051          * using float type.
6052          */
6053         private class NZfloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6054 
6055             /**
6056              * Reads a vertex normal z coordinate from temporal buffer and sets
6057              * its value on current loader iterator.
6058              *
6059              * @param buffer Temporal buffer.
6060              */
6061             @Override
6062             public void readValueFromBuffer(final ByteBuffer buffer) {
6063                 loaderIterator.nZ = buffer.getFloat(0);
6064             }
6065         }
6066 
6067         /**
6068          * Reads a vertex normal x coordinate component from temporal buffer
6069          * using double type.
6070          */
6071         private class NXdoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6072 
6073             /**
6074              * Reads a vertex normal x coordinate from temporal buffer and sets
6075              * its value on current loader iterator.
6076              *
6077              * @param buffer Temporal buffer.
6078              */
6079             @Override
6080             public void readValueFromBuffer(final ByteBuffer buffer) {
6081                 final var value = buffer.getDouble(0);
6082 
6083                 loaderIterator.nX = (float) value;
6084             }
6085         }
6086 
6087         /**
6088          * Reads a vertex normal y coordinate component from temporal buffer
6089          * using double type.
6090          */
6091         private class NYdoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6092 
6093             /**
6094              * Reads a vertex normal y coordinate from temporal buffer and sets
6095              * its value on current loader iterator.
6096              *
6097              * @param buffer Temporal buffer.
6098              */
6099             @Override
6100             public void readValueFromBuffer(final ByteBuffer buffer) {
6101                 final var value = buffer.getDouble(0);
6102 
6103                 loaderIterator.nY = (float) value;
6104             }
6105         }
6106 
6107         /**
6108          * Reads a vertex normal z coordinate component from temporal buffer
6109          * using double type.
6110          */
6111         private class NZdoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6112 
6113             /**
6114              * Reads a vertex normal z coordinate from temporal buffer and sets
6115              * its value on current loader iterator.
6116              *
6117              * @param buffer Temporal buffer.
6118              */
6119             @Override
6120             public void readValueFromBuffer(final ByteBuffer buffer) {
6121                 final var value = buffer.getDouble(0);
6122 
6123                 loaderIterator.nZ = (float) value;
6124             }
6125         }
6126 
6127         /**
6128          * Reads the index of a face/polygon vertex from temporal buffer using
6129          * int8 type.
6130          */
6131         private class FaceInt8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6132 
6133             /**
6134              * Reads the index of a face/polygon vertex from temporal buffer and
6135              * sets its value on current loader iterator.
6136              *
6137              * @param buffer Temporal buffer.
6138              */
6139             @Override
6140             public void readValueFromBuffer(final ByteBuffer buffer) {
6141                 loaderIterator.index = buffer.get(0);
6142             }
6143         }
6144 
6145         /**
6146          * Reads the index of a face/polygon vertex from temporal buffer using
6147          * uint8 type.
6148          */
6149         private class FaceUint8ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6150 
6151             /**
6152              * Reads the index of a face/polygon vertex from temporal buffer and
6153              * sets its value on current loader iterator.
6154              *
6155              * @param buffer Temporal buffer.
6156              */
6157             @Override
6158             public void readValueFromBuffer(final ByteBuffer buffer) {
6159                 // because java doesn't support unsigned types we use the next
6160                 // type that can hold all desired values
6161                 loaderIterator.index = buffer.getShort(0);
6162             }
6163         }
6164 
6165         /**
6166          * Reads the index of a face/polygon vertex from temporal buffer using
6167          * int16 type.
6168          */
6169         private class FaceInt16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6170 
6171             /**
6172              * Reads the index of a face/polygon vertex from temporal buffer and
6173              * sets its value on current loader iterator.
6174              *
6175              * @param buffer Temporal buffer.
6176              */
6177             @Override
6178             public void readValueFromBuffer(final ByteBuffer buffer) {
6179                 loaderIterator.index = buffer.getShort(0);
6180             }
6181         }
6182 
6183         /**
6184          * Reads the index of a face/polygon vertex from temporal buffer using
6185          * uint16 type.
6186          */
6187         private class FaceUint16ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6188 
6189             /**
6190              * Reads the index of a face/polygon vertex from temporal buffer and
6191              * sets its value on current loader iterator.
6192              *
6193              * @param buffer Temporal buffer.
6194              */
6195             @Override
6196             public void readValueFromBuffer(final ByteBuffer buffer) {
6197                 // because java doesn't support unsigned types we use the next
6198                 // type that can hold all desired values
6199                 loaderIterator.index = buffer.getInt(0);
6200             }
6201         }
6202 
6203         /**
6204          * Reads the index of a face/polygon vertex from temporal buffer using
6205          * int32 type.
6206          */
6207         private class FaceInt32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6208 
6209             /**
6210              * Reads the index of a face/polygon vertex from temporal buffer and
6211              * sets its value on current loader iterator.
6212              *
6213              * @param buffer Temporal buffer.
6214              */
6215             @Override
6216             public void readValueFromBuffer(final ByteBuffer buffer) {
6217                 loaderIterator.index = buffer.getInt(0);
6218             }
6219         }
6220 
6221         /**
6222          * Reads the index of a face/polygon vertex from temporal buffer using
6223          * uint32 type.
6224          */
6225         private class FaceUint32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6226 
6227             /**
6228              * Reads the index of a face/polygon vertex from temporal buffer and
6229              * sets its value on current loader iterator.
6230              *
6231              * @param buffer Temporal buffer.
6232              */
6233             @Override
6234             public void readValueFromBuffer(final ByteBuffer buffer) {
6235                 // because java doesn't support unsigned types we use the next
6236                 // type that can hold all desired values
6237                 loaderIterator.index = buffer.getLong(0);
6238             }
6239         }
6240 
6241         /**
6242          * Reads the index of a face/polygon vertex from temporal buffer using
6243          * float32 type.
6244          */
6245         private class FaceFloat32ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6246 
6247             /**
6248              * Reads the index of a face/polygon vertex from temporal buffer and
6249              * sets its value on current loader iterator.
6250              *
6251              * @param buffer Temporal buffer.
6252              */
6253             @Override
6254             public void readValueFromBuffer(final ByteBuffer buffer) {
6255                 final var value = buffer.getFloat(0);
6256 
6257                 loaderIterator.index = (long) value;
6258             }
6259         }
6260 
6261         /**
6262          * Reads the index of a face/polygon vertex from temporal buffer using
6263          * float64 type.
6264          */
6265         private class FaceFloat64ReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6266 
6267             /**
6268              * Reads the index of a face/polygon vertex from temporal buffer and
6269              * sets its value on current loader iterator.
6270              *
6271              * @param buffer Temporal buffer.
6272              */
6273             @Override
6274             public void readValueFromBuffer(final ByteBuffer buffer) {
6275                 final var value = buffer.getDouble(0);
6276 
6277                 loaderIterator.index = (long) value;
6278             }
6279         }
6280 
6281         /**
6282          * Reads the index of a face/polygon vertex from temporal buffer using
6283          * char type.
6284          */
6285         private class FaceCharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6286 
6287             /**
6288              * Reads the index of a face/polygon vertex from temporal buffer and
6289              * sets its value on current loader iterator.
6290              *
6291              * @param buffer Temporal buffer.
6292              */
6293             @Override
6294             public void readValueFromBuffer(final ByteBuffer buffer) {
6295                 loaderIterator.index = buffer.get(0);
6296             }
6297         }
6298 
6299         /**
6300          * Reads the index of a face/polygon vertex from temporal buffer using
6301          * uchar type.
6302          */
6303         private class FaceUcharReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6304 
6305             /**
6306              * Reads the index of a face/polygon vertex from temporal buffer and
6307              * sets its value on current loader iterator.
6308              *
6309              * @param buffer Temporal buffer.
6310              */
6311             @Override
6312             public void readValueFromBuffer(final ByteBuffer buffer) {
6313                 // because java doesn't support unsigned types we use the next
6314                 // type that can hold all desired values
6315                 loaderIterator.index = buffer.getShort(0);
6316             }
6317         }
6318 
6319         /**
6320          * Reads the index of a face/polygon vertex from temporal buffer using
6321          * short type.
6322          */
6323         private class FaceShortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6324 
6325             /**
6326              * Reads the index of a face/polygon vertex from temporal buffer and
6327              * sets its value on current loader iterator.
6328              *
6329              * @param buffer Temporal buffer.
6330              */
6331             @Override
6332             public void readValueFromBuffer(final ByteBuffer buffer) {
6333                 loaderIterator.index = buffer.getShort(0);
6334             }
6335         }
6336 
6337         /**
6338          * Reads the index of a face/polygon vertex from temporal buffer using
6339          * ushort type.
6340          */
6341         private class FaceUshortReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6342 
6343             /**
6344              * Reads the index of a face/polygon vertex from temporal buffer and
6345              * sets its value on current loader iterator.
6346              *
6347              * @param buffer Temporal buffer.
6348              */
6349             @Override
6350             public void readValueFromBuffer(final ByteBuffer buffer) {
6351                 // because java doesn't support unsigned types we use the next
6352                 // type that can hold all desired values
6353                 loaderIterator.index = buffer.getInt(0);
6354             }
6355         }
6356 
6357         /**
6358          * Reads the index of a face/polygon vertex from temporal buffer using
6359          * int type.
6360          */
6361         private class FaceIntReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6362 
6363             /**
6364              * Reads the index of a face/polygon vertex from temporal buffer and
6365              * sets its value on current loader iterator.
6366              *
6367              * @param buffer Temporal buffer.
6368              */
6369             @Override
6370             public void readValueFromBuffer(final ByteBuffer buffer) {
6371                 loaderIterator.index = buffer.getInt(0);
6372             }
6373         }
6374 
6375         /**
6376          * Reads the index of a face/polygon vertex from temporal buffer using
6377          * uint type.
6378          */
6379         private class FaceUintReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6380 
6381             /**
6382              * Reads the index of a face/polygon vertex from temporal buffer and
6383              * sets its value on current loader iterator.
6384              *
6385              * @param buffer Temporal buffer.
6386              */
6387             @Override
6388             public void readValueFromBuffer(final ByteBuffer buffer) {
6389                 // because java doesn't support unsigned types we use the next
6390                 // type that can hold all desired values
6391                 loaderIterator.index = buffer.getLong(0);
6392             }
6393         }
6394 
6395         /**
6396          * Reads the index of a face/polygon vertex from temporal buffer using
6397          * float type.
6398          */
6399         private class FaceFloatReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6400 
6401             /**
6402              * Reads the index of a face/polygon vertex from temporal buffer and
6403              * sets its value on current loader iterator.
6404              *
6405              * @param buffer Temporal buffer.
6406              */
6407             @Override
6408             public void readValueFromBuffer(final ByteBuffer buffer) {
6409                 final var value = buffer.getFloat(0);
6410 
6411                 loaderIterator.index = (long) value;
6412             }
6413         }
6414 
6415         /**
6416          * Reads the index of a face/polygon vertex from temporal buffer using
6417          * double type.
6418          */
6419         private class FaceDoubleReadValueFromBufferListener implements PLYReadValueFromBufferListener {
6420 
6421             /**
6422              * Reads the index of a face/polygon vertex from temporal buffer and
6423              * sets its value on current loader iterator.
6424              *
6425              * @param buffer Temporal buffer.
6426              */
6427             @Override
6428             public void readValueFromBuffer(final ByteBuffer buffer) {
6429                 final var value = buffer.getDouble(0);
6430 
6431                 loaderIterator.index = (long) value;
6432             }
6433         }
6434 
6435         /**
6436          * Reads an int8 from the file stream of data assuming that file is in
6437          * ascii text format.
6438          */
6439         private class AsciiInt8ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6440 
6441             /**
6442              * Reads next word of text within file at current position and
6443              * attempts to parse it into an int8 value.
6444              *
6445              * @param buffer Buffer where data will be stored.
6446              * @throws IOException if an I/O error occurs or data cannot be
6447              *                     parsed into an int8.
6448              */
6449             @Override
6450             public void readFromStream(final ByteBuffer buffer) throws IOException {
6451                 String str;
6452 
6453                 // read word
6454                 do {
6455                     str = reader.readWord();
6456                     // loop to avoid empty strings
6457                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6458 
6459                 // retrieve word value
6460                 try {
6461                     final var value = Byte.parseByte(str);
6462 
6463                     // save to buffer
6464                     buffer.put(0, value);
6465                 } catch (final NumberFormatException e) {
6466                     throw new IOException(e);
6467                 }
6468             }
6469         }
6470 
6471         /**
6472          * Reads a uint8 from the file stream of data assuming that file is in
6473          * ascii text format.
6474          */
6475         private class AsciiUint8ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6476 
6477             /**
6478              * Reads next word of text within file at current position and
6479              * attempts to parse it into an uint8 value.
6480              *
6481              * @param buffer Buffer where data will be stored.
6482              * @throws IOException if an I/O error occurs or data cannot be
6483              *                     parsed into an uint8.
6484              */
6485             @Override
6486             public void readFromStream(final ByteBuffer buffer) throws IOException {
6487                 String str;
6488 
6489                 // read word
6490                 do {
6491                     str = reader.readWord();
6492                     // loop to avoid empty strings
6493                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6494 
6495                 // Because Java doesn't support unsigned types we use the next type
6496                 // capable of holding all values
6497                 try {
6498                     final var value = Short.parseShort(str);
6499 
6500                     // save to buffer
6501                     buffer.putShort(0, value);
6502                 } catch (final NumberFormatException e) {
6503                     throw new IOException(e);
6504                 }
6505             }
6506         }
6507 
6508         /**
6509          * Reads an int16 from the file stream of data assuming that file is in
6510          * ascii text format.
6511          */
6512         private class AsciiInt16ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6513 
6514             /**
6515              * Reads next word of text within file at current position and
6516              * attempts to parse it into an int16 value.
6517              *
6518              * @param buffer Buffer where data will be stored.
6519              * @throws IOException if an I/O error occurs or data cannot be
6520              *                     parsed into an int16.
6521              */
6522             @Override
6523             public void readFromStream(final ByteBuffer buffer) throws IOException {
6524                 String str;
6525 
6526                 // read word
6527                 do {
6528                     str = reader.readWord();
6529                     // loop to avoid empty strings
6530                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6531 
6532                 // retrieve word value
6533                 try {
6534                     final var value = Short.parseShort(str);
6535 
6536                     // save to buffer
6537                     buffer.putShort(0, value);
6538                 } catch (final NumberFormatException e) {
6539                     throw new IOException(e);
6540                 }
6541             }
6542         }
6543 
6544         /**
6545          * Reads a uint16 from the file stream of data assuming that file is in
6546          * ascii text format.
6547          */
6548         private class AsciiUint16ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6549 
6550             /**
6551              * Reads next word of text within file at current position and
6552              * attempts to parse it into an uint16 value.
6553              *
6554              * @param buffer Buffer where data will be stored.
6555              * @throws IOException if an I/O error occurs or data cannot be
6556              *                     parsed into an uint16.
6557              */
6558             @Override
6559             public void readFromStream(final ByteBuffer buffer) throws IOException {
6560                 String str;
6561 
6562                 // read word
6563                 do {
6564                     str = reader.readWord();
6565                     // loop to avoid empty strings
6566                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6567 
6568                 // Because Java doesn't support unsigned types we use the next type
6569                 // capable of holding all values
6570                 try {
6571                     final var value = Integer.parseInt(str);
6572 
6573                     // save to buffer
6574                     buffer.putInt(0, value);
6575                 } catch (final NumberFormatException e) {
6576                     throw new IOException(e);
6577                 }
6578             }
6579         }
6580 
6581         /**
6582          * Reads an int32 from the file stream of data assuming that file is in
6583          * ascii text format.
6584          */
6585         private class AsciiInt32ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6586 
6587             /**
6588              * Reads next word of text within file at current position and
6589              * attempts to parse it into an int32 value.
6590              *
6591              * @param buffer Buffer where data will be stored.
6592              * @throws IOException if an I/O error occurs or data cannot be
6593              *                     parsed into an int32.
6594              */
6595             @Override
6596             public void readFromStream(final ByteBuffer buffer) throws IOException {
6597                 String str;
6598 
6599                 // read word
6600                 do {
6601                     str = reader.readWord();
6602                     // loop to avoid empty strings
6603                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6604 
6605                 // retrieve word value
6606                 try {
6607                     final var value = Integer.parseInt(str);
6608 
6609                     // save to buffer
6610                     buffer.putInt(0, value);
6611                 } catch (final NumberFormatException e) {
6612                     throw new IOException(e);
6613                 }
6614             }
6615         }
6616 
6617         /**
6618          * Reads a uint32 from the file stream of data assuming that file is in
6619          * ascii text format.
6620          */
6621         private class AsciiUint32ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6622 
6623             /**
6624              * Reads next word of text within file at current position and
6625              * attempts to parse it into an uint32 value.
6626              *
6627              * @param buffer Buffer where data will be stored.
6628              * @throws IOException if an I/O error occurs or data cannot be
6629              *                     parsed into an uint32.
6630              */
6631             @Override
6632             public void readFromStream(final ByteBuffer buffer) throws IOException {
6633                 String str;
6634 
6635                 // read word
6636                 do {
6637                     str = reader.readWord();
6638                     // loop to avoid empty strings
6639                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6640 
6641                 // Because Java doesn't support unsigned types we use the next type
6642                 // capable of holding all values
6643                 try {
6644                     final var value = Long.parseLong(str);
6645 
6646                     // save to buffer
6647                     buffer.putLong(0, value);
6648                 } catch (final NumberFormatException e) {
6649                     throw new IOException(e);
6650                 }
6651             }
6652         }
6653 
6654         /**
6655          * Reads a float32 from the file stream of data assuming that file is in
6656          * ascii text format.
6657          */
6658         private class AsciiFloat32ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6659 
6660             /**
6661              * Reads next word of text within file at current position and
6662              * attempts to parse it into a float32 value.
6663              *
6664              * @param buffer Buffer where data will be stored.
6665              * @throws IOException if an I/O error occurs or data cannot be
6666              *                     parsed into an float32.
6667              */
6668             @Override
6669             public void readFromStream(final ByteBuffer buffer) throws IOException {
6670                 String str;
6671 
6672                 // read word
6673                 do {
6674                     str = reader.readWord();
6675                     // loop to avoid empty strings
6676                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6677 
6678                 // retrieve word value
6679                 try {
6680                     final var value = Float.parseFloat(str);
6681 
6682                     // save to buffer
6683                     buffer.putFloat(0, value);
6684                 } catch (final NumberFormatException e) {
6685                     throw new IOException(e);
6686                 }
6687             }
6688         }
6689 
6690         /**
6691          * Reads a float64 from the file stream of data assuming that file is in
6692          * ascii text format.
6693          */
6694         private class AsciiFloat64ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6695 
6696             /**
6697              * Reads next word of text within file at current position and
6698              * attempts to parse it into a float64 value.
6699              *
6700              * @param buffer Buffer where data will be stored.
6701              * @throws IOException if an I/O error occurs or data cannot be
6702              *                     parsed into an float64.
6703              */
6704             @Override
6705             public void readFromStream(final ByteBuffer buffer) throws IOException {
6706                 String str;
6707 
6708                 // read word
6709                 do {
6710                     str = reader.readWord();
6711                     // loop to avoid empty strings
6712                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6713 
6714                 // retrieve word value
6715                 try {
6716                     final var value = Double.parseDouble(str);
6717 
6718                     // save to buffer
6719                     buffer.putDouble(0, value);
6720                 } catch (final NumberFormatException e) {
6721                     throw new IOException(e);
6722                 }
6723             }
6724         }
6725 
6726         /**
6727          * Reads a char from the file stream of data assuming that file is in
6728          * ascii text format.
6729          */
6730         private class AsciiCharReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6731 
6732             /**
6733              * Reads next word of text within file at current position and
6734              * attempts to parse it into a char value.
6735              *
6736              * @param buffer Buffer where data will be stored.
6737              * @throws IOException if an I/O error occurs or data cannot be
6738              *                     parsed into a char.
6739              */
6740             @Override
6741             public void readFromStream(final ByteBuffer buffer) throws IOException {
6742                 String str;
6743 
6744                 // read word
6745                 do {
6746                     str = reader.readWord();
6747                     // loop to avoid empty strings
6748                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6749 
6750                 // retrieve word value
6751                 try {
6752                     final var value = Byte.parseByte(str);
6753 
6754                     // save to buffer
6755                     buffer.put(0, value);
6756                 } catch (final NumberFormatException e) {
6757                     throw new IOException(e);
6758                 }
6759             }
6760         }
6761 
6762         /**
6763          * Reads a uchar from the file stream of data assuming that file is in
6764          * ascii text format.
6765          */
6766         private class AsciiUcharReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6767 
6768             /**
6769              * Reads next word of text within file at current position and
6770              * attempts to parse it into a uchar value.
6771              *
6772              * @param buffer Buffer where data will be stored.
6773              * @throws IOException if an I/O error occurs or data cannot be
6774              *                     parsed into a uchar.
6775              */
6776             @Override
6777             public void readFromStream(final ByteBuffer buffer) throws IOException {
6778                 String str;
6779 
6780                 // read word
6781                 do {
6782                     str = reader.readWord();
6783                     // loop to avoid empty strings
6784                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6785 
6786                 // Because Java doesn't support unsigned types we use the next type
6787                 // capable of holding all values
6788                 try {
6789                     final var value = Short.parseShort(str);
6790 
6791                     // save to buffer
6792                     buffer.putShort(0, value);
6793                 } catch (final NumberFormatException e) {
6794                     throw new IOException(e);
6795                 }
6796             }
6797         }
6798 
6799         /**
6800          * Reads a short from the file stream of data assuming that file is in
6801          * ascii text format.
6802          */
6803         private class AsciiShortReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6804 
6805             /**
6806              * Reads next word of text within file at current position and
6807              * attempts to parse it into a short value.
6808              *
6809              * @param buffer Buffer where data will be stored.
6810              * @throws IOException if an I/O error occurs or data cannot be
6811              *                     parsed into a short.
6812              */
6813             @Override
6814             public void readFromStream(final ByteBuffer buffer) throws IOException {
6815                 String str;
6816 
6817                 // read word
6818                 do {
6819                     str = reader.readWord();
6820                     // loop to avoid empty strings
6821                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6822 
6823                 // retrieve word value
6824                 try {
6825                     final var value = Short.parseShort(str);
6826 
6827                     // save to buffer
6828                     buffer.putShort(0, value);
6829                 } catch (final NumberFormatException e) {
6830                     throw new IOException(e);
6831                 }
6832             }
6833         }
6834 
6835         /**
6836          * Reads a ushort from the file stream of data assuming that file is in
6837          * ascii text format.
6838          */
6839         private class AsciiUshortReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6840 
6841             /**
6842              * Reads next word of text within file at current position and
6843              * attempts to parse it into a ushort value.
6844              *
6845              * @param buffer Buffer where data will be stored.
6846              * @throws IOException if an I/O error occurs or data cannot be
6847              *                     parsed into a ushort.
6848              */
6849             @Override
6850             public void readFromStream(final ByteBuffer buffer) throws IOException {
6851                 String str;
6852 
6853                 // read word
6854                 do {
6855                     str = reader.readWord();
6856                     // loop to avoid empty strings
6857                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6858 
6859                 // Because Java doesn't support unsigned types we use the next type
6860                 // capable of holding all values
6861                 try {
6862                     final var value = Integer.parseInt(str);
6863 
6864                     // save to buffer
6865                     buffer.putInt(0, value);
6866                 } catch (final NumberFormatException e) {
6867                     throw new IOException(e);
6868                 }
6869             }
6870         }
6871 
6872         /**
6873          * Reads an int from the file stream of data assuming that file is in
6874          * ascii text format.
6875          */
6876         private class AsciiIntReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6877 
6878             /**
6879              * Reads next word of text within file at current position and
6880              * attempts to parse it into an int value.
6881              *
6882              * @param buffer Buffer where data will be stored.
6883              * @throws IOException if an I/O error occurs or data cannot be
6884              *                     parsed into an int.
6885              */
6886             @Override
6887             public void readFromStream(final ByteBuffer buffer) throws IOException {
6888                 String str;
6889 
6890                 // read word
6891                 do {
6892                     str = reader.readWord();
6893                     // loop to avoid empty strings
6894                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6895 
6896                 // retrieve word value
6897                 try {
6898                     final var value = Integer.parseInt(str);
6899 
6900                     // save to buffer
6901                     buffer.putInt(0, value);
6902                 } catch (final NumberFormatException e) {
6903                     throw new IOException(e);
6904                 }
6905             }
6906         }
6907 
6908         /**
6909          * Reads a uint from the file stream of data assuming that file is in
6910          * ascii text format.
6911          */
6912         private class AsciiUintReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6913 
6914             /**
6915              * Reads next word of text within file at current position and
6916              * attempts to parse it into a uint value.
6917              *
6918              * @param buffer Buffer where data will be stored.
6919              * @throws IOException if an I/O error occurs or data cannot be
6920              *                     parsed into a uint.
6921              */
6922             @Override
6923             public void readFromStream(final ByteBuffer buffer) throws IOException {
6924                 String str;
6925 
6926                 // read word
6927                 do {
6928                     str = reader.readWord();
6929                     // loop to avoid empty strings
6930                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6931 
6932                 // Because Java doesn't support unsigned types we use the next type
6933                 // capable of holding all values
6934                 try {
6935                     final var value = Long.parseLong(str);
6936 
6937                     // save to buffer
6938                     buffer.putLong(0, value);
6939                 } catch (final NumberFormatException e) {
6940                     throw new IOException(e);
6941                 }
6942             }
6943         }
6944 
6945         /**
6946          * Reads a float from the file stream of data assuming that file is in
6947          * ascii text format.
6948          */
6949         private class AsciiFloatReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6950 
6951             /**
6952              * Reads next word of text within file at current position and
6953              * attempts to parse it into a float value.
6954              *
6955              * @param buffer Buffer where data will be stored.
6956              * @throws IOException if an I/O error occurs or data cannot be
6957              *                     parsed into a float.
6958              */
6959             @Override
6960             public void readFromStream(final ByteBuffer buffer) throws IOException {
6961                 String str;
6962 
6963                 // read word
6964                 do {
6965                     str = reader.readWord();
6966                     // loop to avoid empty strings
6967                 } while ((str.isEmpty()) && !reader.isEndOfStream());
6968 
6969                 // retrieve word value
6970                 try {
6971                     final var value = Float.parseFloat(str);
6972 
6973                     // save to buffer
6974                     buffer.putFloat(0, value);
6975                 } catch (final NumberFormatException e) {
6976                     throw new IOException(e);
6977                 }
6978             }
6979         }
6980 
6981         /**
6982          * Reads a double from the file stream of data assuming that file is in
6983          * ascii text format.
6984          */
6985         private class AsciiDoubleReadValueFromStreamListener implements PLYReadValueFromStreamListener {
6986 
6987             /**
6988              * Reads next word of text within file at current position and
6989              * attempts to parse it into a double value.
6990              *
6991              * @param buffer Buffer where data will be stored.
6992              * @throws IOException if an I/O error occurs or data cannot be
6993              *                     parsed into a double.
6994              */
6995             @Override
6996             public void readFromStream(final ByteBuffer buffer) throws IOException {
6997                 String str;
6998 
6999                 // read word
7000                 do {
7001                     str = reader.readWord();
7002                     // loop to avoid empty strings
7003                 } while ((str.isEmpty()) && !reader.isEndOfStream());
7004 
7005                 // retrieve word value
7006                 try {
7007                     final var value = Double.parseDouble(str);
7008 
7009                     // save to buffer
7010                     buffer.putDouble(0, value);
7011                 } catch (final NumberFormatException e) {
7012                     throw new IOException(e);
7013                 }
7014             }
7015         }
7016 
7017         /**
7018          * Reads an int8 from the file stream of data assuming that file is in
7019          * binary format.
7020          */
7021         private class BinaryInt8ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7022 
7023             /**
7024              * Reads an int8 from the stream of data at current file position
7025              * and stores the result into provided byte buffer.
7026              *
7027              * @param buffer Buffer where data will be stored.
7028              * @throws IOException if an I/O error occurs.
7029              */
7030             @Override
7031             public void readFromStream(final ByteBuffer buffer) throws IOException {
7032                 final var value = reader.readByte();
7033 
7034                 // save to buffer
7035                 buffer.put(0, value);
7036             }
7037         }
7038 
7039         /**
7040          * Reads a uint8 from the file stream of data assuming that file is in
7041          * binary format.
7042          */
7043         private class BinaryUint8ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7044 
7045             /**
7046              * Reads a uint8 from the stream of data at current file position
7047              * and stores the result into provided byte buffer.
7048              *
7049              * @param buffer Buffer where data will be stored.
7050              * @throws IOException if an I/O error occurs.
7051              */
7052             @Override
7053             public void readFromStream(final ByteBuffer buffer) throws IOException {
7054                 // Because Java doesn't support unsigned types, we use the next
7055                 // type that can hold all values
7056                 final var value = reader.readUnsignedByte();
7057 
7058                 // save to buffer
7059                 buffer.putShort(0, value);
7060             }
7061         }
7062 
7063         /**
7064          * Reads a char from the file stream of data assuming that file is in
7065          * binary format.
7066          */
7067         private class BinaryCharReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7068 
7069             /**
7070              * Reads a char from the stream of data at current file position
7071              * and stores the result into provided byte buffer.
7072              *
7073              * @param buffer Buffer where data will be stored.
7074              * @throws IOException if an I/O error occurs.
7075              */
7076             @Override
7077             public void readFromStream(final ByteBuffer buffer) throws IOException {
7078                 final var value = reader.readByte();
7079 
7080                 // save to buffer
7081                 buffer.put(0, value);
7082             }
7083         }
7084 
7085         /**
7086          * Reads a uchar from the file stream of data assuming that file is in
7087          * binary format.
7088          */
7089         private class BinaryUcharReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7090 
7091             /**
7092              * Reads a uchar from the stream of data at current file position
7093              * and stores the result into provided byte buffer.
7094              *
7095              * @param buffer Buffer where data will be stored.
7096              * @throws IOException if an I/O error occurs.
7097              */
7098             @Override
7099             public void readFromStream(final ByteBuffer buffer) throws IOException {
7100                 // Because Java doesn't support unsigned types, we use the next
7101                 // type that can hold all values
7102                 final var value = reader.readUnsignedByte();
7103 
7104                 // save to buffer
7105                 buffer.putShort(0, value);
7106             }
7107         }
7108 
7109         /**
7110          * Reads an int16 from the file stream of data assuming that file is in
7111          * little endian binary format.
7112          */
7113         private class BinaryLittleEndianInt16ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7114 
7115             /**
7116              * Reads an int16 from the stream of data at current file position
7117              * and stores the result into provided byte buffer. Stream data is
7118              * assumed to be in little endian format.
7119              *
7120              * @param buffer Buffer where data will be stored.
7121              * @throws IOException if an I/O error occurs.
7122              */
7123             @Override
7124             public void readFromStream(final ByteBuffer buffer) throws IOException {
7125                 final var value = reader.readShort(EndianType.LITTLE_ENDIAN_TYPE);
7126 
7127                 // save to buffer
7128                 buffer.putShort(0, value);
7129             }
7130         }
7131 
7132         /**
7133          * Reads a uint16 from the file stream of data assuming that file is in
7134          * little endian binary format.
7135          */
7136         private class BinaryLittleEndianUint16ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7137 
7138             /**
7139              * Reads a uint16 from the stream of data at current file position
7140              * and stores the result into provided byte buffer. Stream data is
7141              * assumed to be in little endian format.
7142              *
7143              * @param buffer Buffer where data will be stored.
7144              * @throws IOException if an I/O error occurs.
7145              */
7146             @Override
7147             public void readFromStream(final ByteBuffer buffer) throws IOException {
7148                 // Because Java doesn't support unsigned types, we use the next
7149                 // type that can hold all values
7150                 final var value = reader.readUnsignedShort(EndianType.LITTLE_ENDIAN_TYPE);
7151 
7152                 // save to buffer
7153                 buffer.putInt(0, value);
7154             }
7155         }
7156 
7157         /**
7158          * Reads an int32 from the file stream of data assuming that file is in
7159          * little endian binary format.
7160          */
7161         private class BinaryLittleEndianInt32ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7162 
7163             /**
7164              * Reads an int32 from the stream of data at current file position
7165              * and stores the result into provided byte buffer. Stream data is
7166              * assumed to be in little endian format.
7167              *
7168              * @param buffer Buffer where data will be stored.
7169              * @throws IOException if an I/O error occurs.
7170              */
7171             @Override
7172             public void readFromStream(final ByteBuffer buffer) throws IOException {
7173                 final var value = reader.readInt(EndianType.LITTLE_ENDIAN_TYPE);
7174 
7175                 // save to buffer
7176                 buffer.putInt(0, value);
7177             }
7178         }
7179 
7180         /**
7181          * Reads a uint32 from the file stream of data assuming that file is in
7182          * little endian binary format.
7183          */
7184         private class BinaryLittleEndianUint32ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7185 
7186             /**
7187              * Reads a uint32 from the stream of data at current file position
7188              * and stores the result into provided byte buffer. Stream data is
7189              * assumed to be in little endian format.
7190              *
7191              * @param buffer Buffer where data will be stored.
7192              * @throws IOException if an I/O error occurs.
7193              */
7194             @Override
7195             public void readFromStream(final ByteBuffer buffer) throws IOException {
7196                 // Because Java doesn't support unsigned types, we use the next
7197                 // type that can hold all values
7198                 final var value = reader.readUnsignedInt(EndianType.LITTLE_ENDIAN_TYPE);
7199 
7200                 // save to buffer
7201                 buffer.putLong(0, value);
7202             }
7203         }
7204 
7205         /**
7206          * Reads a float32 from the file stream of data assuming that file is in
7207          * little endian binary format.
7208          */
7209         private class BinaryLittleEndianFloat32ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7210 
7211             /**
7212              * Reads a float32 from the stream of data at current file position
7213              * and stores the result into provided byte buffer. Stream data is
7214              * assumed to be in little endian format.
7215              *
7216              * @param buffer Buffer where data will be stored.
7217              * @throws IOException if an I/O error occurs.
7218              */
7219             @Override
7220             public void readFromStream(final ByteBuffer buffer) throws IOException {
7221                 final var value = reader.readFloat(EndianType.LITTLE_ENDIAN_TYPE);
7222 
7223                 // save to buffer
7224                 buffer.putFloat(0, value);
7225             }
7226         }
7227 
7228         /**
7229          * Reads a float64 from the file stream of data assuming that file is in
7230          * little endian binary format.
7231          */
7232         private class BinaryLittleEndianFloat64ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7233 
7234             /**
7235              * Reads a float64 from the stream of data at current file position
7236              * and stores the result into provided byte buffer. Stream data is
7237              * assumed to be in little endian format.
7238              *
7239              * @param buffer Buffer where data will be stored.
7240              * @throws IOException if an I/O error occurs.
7241              */
7242             @Override
7243             public void readFromStream(final ByteBuffer buffer) throws IOException {
7244                 final var value = reader.readDouble(EndianType.LITTLE_ENDIAN_TYPE);
7245 
7246                 // save to buffer
7247                 buffer.putDouble(0, value);
7248             }
7249         }
7250 
7251         /**
7252          * Reads a short from the file stream of data assuming that file is in
7253          * little endian binary format.
7254          */
7255         private class BinaryLittleEndianShortReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7256 
7257             /**
7258              * Reads a short from the stream of data at current file position
7259              * and stores the result into provided byte buffer. Stream data is
7260              * assumed to be in little endian format.
7261              *
7262              * @param buffer Buffer where data will be stored.
7263              * @throws IOException if an I/O error occurs.
7264              */
7265             @Override
7266             public void readFromStream(final ByteBuffer buffer) throws IOException {
7267                 final var value = reader.readShort(EndianType.LITTLE_ENDIAN_TYPE);
7268 
7269                 // save to buffer
7270                 buffer.putShort(0, value);
7271             }
7272         }
7273 
7274         /**
7275          * Reads a ushort from the file stream of data assuming that file is in
7276          * little endian binary format.
7277          */
7278         private class BinaryLittleEndianUshortReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7279 
7280             /**
7281              * Reads a ushort from the stream of data at current file position
7282              * and stores the result into provided byte buffer. Stream data is
7283              * assumed to be in little endian format.
7284              *
7285              * @param buffer Buffer where data will be stored.
7286              * @throws IOException if an I/O error occurs.
7287              */
7288             @Override
7289             public void readFromStream(final ByteBuffer buffer) throws IOException {
7290                 // Because Java doesn't support unsigned types, we use the next
7291                 // type that can hold all values
7292                 final var value = reader.readUnsignedShort(EndianType.LITTLE_ENDIAN_TYPE);
7293 
7294                 // save to buffer
7295                 buffer.putInt(0, value);
7296             }
7297         }
7298 
7299         /**
7300          * Reads an int from the file stream of data assuming that file is in
7301          * little endian binary format.
7302          */
7303         private class BinaryLittleEndianIntReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7304 
7305             /**
7306              * Reads an int from the stream of data at current file position
7307              * and stores the result into provided byte buffer. Stream data is
7308              * assumed to be in little endian format.
7309              *
7310              * @param buffer Buffer where data will be stored.
7311              * @throws IOException if an I/O error occurs.
7312              */
7313             @Override
7314             public void readFromStream(final ByteBuffer buffer) throws IOException {
7315                 final var value = reader.readInt(EndianType.LITTLE_ENDIAN_TYPE);
7316 
7317                 // save to buffer
7318                 buffer.putInt(0, value);
7319             }
7320         }
7321 
7322         /**
7323          * Reads a uint from the file stream of data assuming that file is in
7324          * little endian binary format.
7325          */
7326         private class BinaryLittleEndianUintReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7327 
7328             /**
7329              * Reads a uint from the stream of data at current file position
7330              * and stores the result into provided byte buffer. Stream data is
7331              * assumed to be in little endian format.
7332              *
7333              * @param buffer Buffer where data will be stored.
7334              * @throws IOException if an I/O error occurs.
7335              */
7336             @Override
7337             public void readFromStream(final ByteBuffer buffer) throws IOException {
7338                 // Because Java doesn't support unsigned types, we use the next
7339                 // type that can hold all values
7340                 final var value = reader.readUnsignedInt(EndianType.LITTLE_ENDIAN_TYPE);
7341 
7342                 // save to buffer
7343                 buffer.putLong(0, value);
7344             }
7345         }
7346 
7347         /**
7348          * Reads a float from the file stream of data assuming that file is in
7349          * little endian binary format.
7350          */
7351         private class BinaryLittleEndianFloatReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7352 
7353             /**
7354              * Reads a float from the stream of data at current file position
7355              * and stores the result into provided byte buffer. Stream data is
7356              * assumed to be in little endian format.
7357              *
7358              * @param buffer Buffer where data will be stored.
7359              * @throws IOException if an I/O error occurs.
7360              */
7361             @Override
7362             public void readFromStream(final ByteBuffer buffer) throws IOException {
7363                 final var value = reader.readFloat(EndianType.LITTLE_ENDIAN_TYPE);
7364 
7365                 // save to buffer
7366                 buffer.putFloat(0, value);
7367             }
7368         }
7369 
7370         /**
7371          * Reads a double from the file stream of data assuming that file is in
7372          * little endian binary format.
7373          */
7374         private class BinaryLittleEndianDoubleReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7375 
7376             /**
7377              * Reads a double from the stream of data at current file position
7378              * and stores the result into provided byte buffer. Stream data is
7379              * assumed to be in little endian format.
7380              *
7381              * @param buffer Buffer where data will be stored.
7382              * @throws IOException if an I/O error occurs.
7383              */
7384             @Override
7385             public void readFromStream(final ByteBuffer buffer) throws IOException {
7386                 final var value = reader.readDouble(EndianType.LITTLE_ENDIAN_TYPE);
7387 
7388                 // save to buffer
7389                 buffer.putDouble(0, value);
7390             }
7391         }
7392 
7393         /**
7394          * Reads an int16 from the file stream of data assuming that file is in
7395          * big endian binary format.
7396          */
7397         private class BinaryBigEndianInt16ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7398 
7399             /**
7400              * Reads an int16 from the stream of data at current file position
7401              * and stores the result into provided byte buffer. Stream data is
7402              * assumed to be in big endian format.
7403              *
7404              * @param buffer Buffer where data will be stored.
7405              * @throws IOException if an I/O error occurs.
7406              */
7407             @Override
7408             public void readFromStream(final ByteBuffer buffer) throws IOException {
7409                 final var value = reader.readShort(EndianType.BIG_ENDIAN_TYPE);
7410 
7411                 // save to buffer
7412                 buffer.putShort(0, value);
7413             }
7414         }
7415 
7416         /**
7417          * Reads a uint16 from the file stream of data assuming that file is in
7418          * big endian binary format.
7419          */
7420         private class BinaryBigEndianUint16ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7421 
7422             /**
7423              * Reads a uint16 from the stream of data at current file position
7424              * and stores the result into provided byte buffer. Stream data is
7425              * assumed to be in big endian format.
7426              *
7427              * @param buffer Buffer where data will be stored.
7428              * @throws IOException if an I/O error occurs.
7429              */
7430             @Override
7431             public void readFromStream(final ByteBuffer buffer) throws IOException {
7432                 // Because Java doesn't support unsigned types, we use the next
7433                 // type that can hold all values
7434                 final var value = reader.readUnsignedShort(EndianType.BIG_ENDIAN_TYPE);
7435 
7436                 // save to buffer
7437                 buffer.putInt(0, value);
7438             }
7439         }
7440 
7441         /**
7442          * Reads an int32 from the file stream of data assuming that file is in
7443          * big endian binary format.
7444          */
7445         private class BinaryBigEndianInt32ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7446 
7447             /**
7448              * Reads an int32 from the stream of data at current file position
7449              * and stores the result into provided byte buffer. Stream data is
7450              * assumed to be in big endian format.
7451              *
7452              * @param buffer Buffer where data will be stored.
7453              * @throws IOException if an I/O error occurs.
7454              */
7455             @Override
7456             public void readFromStream(final ByteBuffer buffer) throws IOException {
7457                 final var value = reader.readInt(EndianType.BIG_ENDIAN_TYPE);
7458 
7459                 // save to buffer
7460                 buffer.putInt(0, value);
7461             }
7462         }
7463 
7464         /**
7465          * Reads a uint32 from the file stream of data assuming that file is in
7466          * big endian binary format.
7467          */
7468         private class BinaryBigEndianUint32ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7469 
7470             /**
7471              * Reads a uint32 from the stream of data at current file position
7472              * and stores the result into provided byte buffer. Stream data is
7473              * assumed to be in big endian format.
7474              *
7475              * @param buffer Buffer where data will be stored.
7476              * @throws IOException if an I/O error occurs.
7477              */
7478             @Override
7479             public void readFromStream(final ByteBuffer buffer) throws IOException {
7480                 // Because Java doesn't support unsigned types, we use the next
7481                 // type that can hold all values
7482                 final var value = reader.readUnsignedInt(EndianType.BIG_ENDIAN_TYPE);
7483 
7484                 // save to buffer
7485                 buffer.putLong(0, value);
7486             }
7487         }
7488 
7489         /**
7490          * Reads a float32 from the file stream of data assuming that file is in
7491          * big endian binary format.
7492          */
7493         private class BinaryBigEndianFloat32ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7494 
7495             /**
7496              * Reads a float32 from the stream of data at current file position
7497              * and stores the result into provided byte buffer. Stream data is
7498              * assumed to be in big endian format.
7499              *
7500              * @param buffer Buffer where data will be stored.
7501              * @throws IOException if an I/O error occurs.
7502              */
7503             @Override
7504             public void readFromStream(final ByteBuffer buffer) throws IOException {
7505                 final var value = reader.readFloat(EndianType.BIG_ENDIAN_TYPE);
7506 
7507                 // save to buffer
7508                 buffer.putFloat(0, value);
7509             }
7510         }
7511 
7512         /**
7513          * Reads a float64 from the file stream of data assuming that file is in
7514          * big endian binary format.
7515          */
7516         private class BinaryBigEndianFloat64ReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7517 
7518             /**
7519              * Reads a float64 from the stream of data at current file position
7520              * and stores the result into provided byte buffer. Stream data is
7521              * assumed to be in big endian format.
7522              *
7523              * @param buffer Buffer where data will be stored.
7524              * @throws IOException if an I/O error occurs.
7525              */
7526             @Override
7527             public void readFromStream(final ByteBuffer buffer) throws IOException {
7528                 final var value = reader.readDouble(EndianType.BIG_ENDIAN_TYPE);
7529 
7530                 // save to buffer
7531                 buffer.putDouble(0, value);
7532             }
7533         }
7534 
7535         /**
7536          * Reads a short from the file stream of data assuming that file is in
7537          * big endian binary format.
7538          */
7539         private class BinaryBigEndianShortReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7540 
7541             /**
7542              * Reads a short from the stream of data at current file position
7543              * and stores the result into provided byte buffer. Stream data is
7544              * assumed to be in big endian format.
7545              *
7546              * @param buffer Buffer where data will be stored.
7547              * @throws IOException if an I/O error occurs.
7548              */
7549             @Override
7550             public void readFromStream(final ByteBuffer buffer) throws IOException {
7551                 final var value = reader.readShort(EndianType.BIG_ENDIAN_TYPE);
7552 
7553                 // save to buffer
7554                 buffer.putShort(0, value);
7555             }
7556         }
7557 
7558         /**
7559          * Reads a ushort from the file stream of data assuming that file is in
7560          * big endian binary format.
7561          */
7562         private class BinaryBigEndianUshortReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7563 
7564             /**
7565              * Reads a ushort from the stream of data at current file position
7566              * and stores the result into provided byte buffer. Stream data is
7567              * assumed to be in big endian format.
7568              *
7569              * @param buffer Buffer where data will be stored.
7570              * @throws IOException if an I/O error occurs.
7571              */
7572             @Override
7573             public void readFromStream(final ByteBuffer buffer) throws IOException {
7574                 // Because Java doesn't support unsigned types, we use the next
7575                 // type that can hold all values
7576                 final var value = reader.readUnsignedShort(EndianType.BIG_ENDIAN_TYPE);
7577 
7578                 // save to buffer
7579                 buffer.putInt(0, value);
7580             }
7581         }
7582 
7583         /**
7584          * Reads an int from the file stream of data assuming that file is in
7585          * big endian binary format.
7586          */
7587         private class BinaryBigEndianIntReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7588 
7589             /**
7590              * Reads an int from the stream of data at current file position
7591              * and stores the result into provided byte buffer. Stream data is
7592              * assumed to be in big endian format.
7593              *
7594              * @param buffer Buffer where data will be stored.
7595              * @throws IOException if an I/O error occurs.
7596              */
7597             @Override
7598             public void readFromStream(final ByteBuffer buffer) throws IOException {
7599                 final var value = reader.readInt(EndianType.BIG_ENDIAN_TYPE);
7600 
7601                 // save to buffer
7602                 buffer.putInt(0, value);
7603             }
7604         }
7605 
7606         /**
7607          * Reads a uint from the file stream of data assuming that file is in
7608          * big endian binary format.
7609          */
7610         private class BinaryBigEndianUintReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7611 
7612             /**
7613              * Reads a uint from the stream of data at current file position
7614              * and stores the result into provided byte buffer. Stream data is
7615              * assumed to be in big endian format.
7616              *
7617              * @param buffer Buffer where data will be stored.
7618              * @throws IOException if an I/O error occurs.
7619              */
7620             @Override
7621             public void readFromStream(final ByteBuffer buffer) throws IOException {
7622                 // Because Java doesn't support unsigned types, we use the next
7623                 // type that can hold all values
7624                 final var value = reader.readUnsignedInt(EndianType.BIG_ENDIAN_TYPE);
7625 
7626                 // save to buffer
7627                 buffer.putLong(0, value);
7628             }
7629         }
7630 
7631         /**
7632          * Reads a float from the file stream of data assuming that file is in
7633          * big endian binary format.
7634          */
7635         private class BinaryBigEndianFloatReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7636 
7637             /**
7638              * Reads a float from the stream of data at current file position
7639              * and stores the result into provided byte buffer. Stream data is
7640              * assumed to be in big endian format.
7641              *
7642              * @param buffer Buffer where data will be stored.
7643              * @throws IOException if an I/O error occurs.
7644              */
7645             @Override
7646             public void readFromStream(final ByteBuffer buffer) throws IOException {
7647                 final var value = reader.readFloat(EndianType.BIG_ENDIAN_TYPE);
7648 
7649                 // save to buffer
7650                 buffer.putFloat(0, value);
7651             }
7652         }
7653 
7654         /**
7655          * Reads a double from the file stream of data assuming that file is in
7656          * big endian binary format.
7657          */
7658         private class BinaryBigEndianDoubleReadValueFromStreamListener implements PLYReadValueFromStreamListener {
7659 
7660             /**
7661              * Reads a double from the stream of data at current file position
7662              * and stores the result into provided byte buffer. Stream data is
7663              * assumed to be in big endian format.
7664              *
7665              * @param buffer Buffer where data will be stored.
7666              * @throws IOException if an I/O error occurs.
7667              */
7668             @Override
7669             public void readFromStream(final ByteBuffer buffer) throws IOException {
7670                 final var value = reader.readDouble(EndianType.BIG_ENDIAN_TYPE);
7671 
7672                 // save to buffer
7673                 buffer.putDouble(0, value);
7674             }
7675         }
7676 
7677         /**
7678          * Reads length value of a list header element from temporal buffer of
7679          * data assuming it has int8 data type.
7680          */
7681         private class FaceInt8ReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7682 
7683             /**
7684              * Reads length value of a list header element from temporal buffer
7685              * of data assuming it has int8 data type. Value read from buffer
7686              * will be stored into this PLY loader iterator.
7687              *
7688              * @param buffer Temporal buffer of data.
7689              */
7690             @Override
7691             public void readValueFromBuffer(final ByteBuffer buffer) {
7692                 loaderIterator.listElems = buffer.get(0);
7693             }
7694         }
7695 
7696         /**
7697          * Reads length value of a list header element from temporal buffer of
7698          * data assuming it has uint8 data type.
7699          */
7700         private class FaceUint8ReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7701 
7702             /**
7703              * Reads length value of a list header element from temporal buffer
7704              * of data assuming it has uint8 data type. Value read from buffer
7705              * will be stored into this PLY loader iterator.
7706              *
7707              * @param buffer Temporal buffer of data.
7708              */
7709             @Override
7710             public void readValueFromBuffer(final ByteBuffer buffer) {
7711                 // Because Jave doesn't support unsigned types, we use next
7712                 // type capable of holding all values
7713                 loaderIterator.listElems = buffer.getShort(0);
7714             }
7715         }
7716 
7717         /**
7718          * Reads length value of a list header element from temporal buffer of
7719          * data assuming it has int16 data type.
7720          */
7721         private class FaceInt16ReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7722 
7723             /**
7724              * Reads length value of a list header element from temporal buffer
7725              * of data assuming it has int16 data type. Value read from buffer
7726              * will be stored into this PLY loader iterator.
7727              *
7728              * @param buffer Temporal buffer of data.
7729              */
7730             @Override
7731             public void readValueFromBuffer(final ByteBuffer buffer) {
7732                 loaderIterator.listElems = buffer.getShort(0);
7733             }
7734         }
7735 
7736         /**
7737          * Reads length value of a list header element from temporal buffer of
7738          * data assuming it has uint16 data type.
7739          */
7740         private class FaceUint16ReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7741 
7742             /**
7743              * Reads length value of a list header element from temporal buffer
7744              * of data assuming it has uint16 data type. Value read from buffer
7745              * will be stored into this PLY loader iterator.
7746              *
7747              * @param buffer Temporal buffer of data.
7748              */
7749             @Override
7750             public void readValueFromBuffer(final ByteBuffer buffer) {
7751                 // Because Jave doesn't support unsigned types, we use next
7752                 // type capable of holding all values
7753                 loaderIterator.listElems = buffer.getInt(0);
7754             }
7755         }
7756 
7757         /**
7758          * Reads length value of a list header element from temporal buffer of
7759          * data assuming it has int32 data type.
7760          */
7761         private class FaceInt32ReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7762 
7763             /**
7764              * Reads length value of a list header element from temporal buffer
7765              * of data assuming it has int32 data type. Value read from buffer
7766              * will be stored into this PLY loader iterator
7767              *
7768              * @param buffer Temporal buffer of data.
7769              */
7770             @Override
7771             public void readValueFromBuffer(final ByteBuffer buffer) {
7772                 loaderIterator.listElems = buffer.getInt(0);
7773             }
7774         }
7775 
7776         /**
7777          * Reads length value of a list header element from temporal buffer of
7778          * data assuming it has uint32 data type.
7779          */
7780         private class FaceUint32ReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7781 
7782             /**
7783              * Reads length value of a list header element from temporal buffer
7784              * of data assuming it has uint32 data type. Value read from buffer
7785              * will be stored into this PLY loader iterator
7786              *
7787              * @param buffer Temporal buffer of data.
7788              */
7789             @Override
7790             public void readValueFromBuffer(final ByteBuffer buffer) {
7791                 // Because Jave doesn't support unsigned types, we use next
7792                 // type capable of holding all values
7793                 final var value = buffer.getLong(0);
7794 
7795                 loaderIterator.listElems = (int) value;
7796             }
7797         }
7798 
7799         /**
7800          * Reads length value of a list header element from temporal buffer of
7801          * data assuming it has float32 data type.
7802          */
7803         private class FaceFloat32ReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7804 
7805             /**
7806              * Reads length value of a list header element from temporal buffer
7807              * of data assuming it has float32 data type. Value read from buffer
7808              * will be stored into this PLY loader iterator.
7809              *
7810              * @param buffer Temporal buffer of data.
7811              */
7812             @Override
7813             public void readValueFromBuffer(final ByteBuffer buffer) {
7814                 final var value = buffer.getFloat(0);
7815 
7816                 loaderIterator.listElems = (int) value;
7817             }
7818         }
7819 
7820         /**
7821          * Reads length value of a list header element from temporal buffer of
7822          * data assuming it has float64 data type.
7823          */
7824         private class FaceFloat64ReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7825 
7826             /**
7827              * Reads length value of a list header element from temporal buffer
7828              * of data assuming it has float64 data type. Value read from buffer
7829              * will be stored into this PLY loader iterator.
7830              *
7831              * @param buffer Temporal buffer of data.
7832              */
7833             @Override
7834             public void readValueFromBuffer(final ByteBuffer buffer) {
7835                 final var value = buffer.getDouble(0);
7836 
7837                 loaderIterator.listElems = (int) value;
7838             }
7839         }
7840 
7841         /**
7842          * Reads length value of a list header element from temporal buffer of
7843          * data assuming it has char data type.
7844          */
7845         private class FaceCharReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7846 
7847             /**
7848              * Reads length value of a list header element from temporal buffer
7849              * of data assuming it has char data type. Value read from buffer
7850              * will be stored into this PLY loader iterator.
7851              *
7852              * @param buffer Temporal buffer of data.
7853              */
7854             @Override
7855             public void readValueFromBuffer(final ByteBuffer buffer) {
7856                 loaderIterator.listElems = buffer.get(0);
7857             }
7858         }
7859 
7860         /**
7861          * Reads length value of a list header element from temporal buffer of
7862          * data assuming it has uchar data type.
7863          */
7864         private class FaceUcharReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7865 
7866             /**
7867              * Reads length value of a list header element from temporal buffer
7868              * of data assuming it has uchar data type. Value read from buffer
7869              * will be stored into this PLY loader iterator.
7870              *
7871              * @param buffer Temporal buffer of data.
7872              */
7873             @Override
7874             public void readValueFromBuffer(final ByteBuffer buffer) {
7875                 // Because Jave doesn't support unsigned types, we use next
7876                 // type capable of holding all values
7877                 loaderIterator.listElems = buffer.getShort(0);
7878             }
7879         }
7880 
7881         /**
7882          * Reads length value of a list header element from temporal buffer of
7883          * data assuming it has short data type.
7884          */
7885         private class FaceShortReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7886 
7887             /**
7888              * Reads length value of a list header element from temporal buffer
7889              * of data assuming it has short data type. Value read from buffer
7890              * will be stored into this PLY loader iterator.
7891              *
7892              * @param buffer Temporal buffer of data.
7893              */
7894             @Override
7895             public void readValueFromBuffer(final ByteBuffer buffer) {
7896                 loaderIterator.listElems = buffer.getShort(0);
7897             }
7898         }
7899 
7900         /**
7901          * Reads length value of a list header element from temporal buffer of
7902          * data assuming it has ushort data type.
7903          */
7904         private class FaceUshortReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7905 
7906             /**
7907              * Reads length value of a list header element from temporal buffer
7908              * of data assuming it has ushort data type. Value read from buffer
7909              * will be stored into this PLY loader iterator.
7910              *
7911              * @param buffer Temporal buffer of data.
7912              */
7913             @Override
7914             public void readValueFromBuffer(final ByteBuffer buffer) {
7915                 // Because Jave doesn't support unsigned types, we use next
7916                 // type capable of holding all values
7917                 loaderIterator.listElems = buffer.getInt(0);
7918             }
7919         }
7920 
7921         /**
7922          * Reads length value of a list header element from temporal buffer of
7923          * data assuming it has int data type.
7924          */
7925         private class FaceIntReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7926 
7927             /**
7928              * Reads length value of a list header element from temporal buffer
7929              * of data assuming it has int data type. Value read from buffer
7930              * will be stored into this PLY loader iterator.
7931              *
7932              * @param buffer Temporal buffer of data.
7933              */
7934             @Override
7935             public void readValueFromBuffer(final ByteBuffer buffer) {
7936                 loaderIterator.listElems = buffer.getInt(0);
7937             }
7938         }
7939 
7940         /**
7941          * Reads length value of a list header element from temporal buffer of
7942          * data assuming it has uint data type.
7943          */
7944         private class FaceUintReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7945 
7946             /**
7947              * Reads length value of a list header element from temporal buffer
7948              * of data assuming it has uint data type. Value read from buffer
7949              * will be stored into this PLY loader iterator.
7950              *
7951              * @param buffer Temporal buffer of data.
7952              */
7953             @Override
7954             public void readValueFromBuffer(final ByteBuffer buffer) {
7955                 // Because Jave doesn't support unsigned types, we use next
7956                 // type capable of holding all values
7957                 final var value = buffer.getLong(0);
7958 
7959                 loaderIterator.listElems = (int) value;
7960             }
7961         }
7962 
7963         /**
7964          * Reads length value of a list header element from temporal buffer of
7965          * data assuming it has float data type.
7966          */
7967         private class FaceFloatReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7968 
7969             /**
7970              * Reads length value of a list header element from temporal buffer
7971              * of data assuming it has float data type. Value read from buffer
7972              * will be stored into this PLY loader iterator.
7973              *
7974              * @param buffer Temporal buffer of data.
7975              */
7976             @Override
7977             public void readValueFromBuffer(final ByteBuffer buffer) {
7978                 final var value = buffer.getFloat(0);
7979 
7980                 loaderIterator.listElems = (int) value;
7981             }
7982         }
7983 
7984         /**
7985          * Reads length value of a list header element from temporal buffer of
7986          * data assuming it has double data type.
7987          */
7988         private class FaceDoubleReadLengthValueFromBufferListener implements PLYReadValueFromBufferListener {
7989 
7990             /**
7991              * Reads length value of a list header element from temporal buffer
7992              * of data assuming it has double data type. Value read from buffer
7993              * will be stored into this PLY loader iterator.
7994              *
7995              * @param buffer Temporal buffer of data.
7996              */
7997             @Override
7998             public void readValueFromBuffer(final ByteBuffer buffer) {
7999                 final var value = buffer.getDouble(0);
8000 
8001                 loaderIterator.listElems = (int) value;
8002             }
8003         }
8004 
8005         /**
8006          * Sets the listener to read data from the file stream for a given
8007          * PLY header property and using provided storage mode.
8008          *
8009          * @param property    A PLY header property.
8010          * @param storageMode Storage mode of file.
8011          * @throws NotAvailableException Raised if the listener cannot be set
8012          *                               for provided property and storage mode.
8013          */
8014         private void setReadValueFromStreamListener(final PropertyPLY property, final PLYStorageMode storageMode)
8015                 throws NotAvailableException {
8016             property.setReadValueFromStreamListener(getReadFromStreamListener(property.getValueType(), storageMode));
8017         }
8018 
8019         /**
8020          * Sets the listener to read length value of a property from the file
8021          * stream for a given PLY header property and using provided storage
8022          * mode.
8023          *
8024          * @param property    A PLY header property.
8025          * @param storageMode Storage mode of file.
8026          * @throws NotAvailableException Raised if the listener cannot be set
8027          *                               for provided property and storage mode.
8028          */
8029         private void setReadLengthValueFromStreamListener(
8030                 final PropertyPLY property, final PLYStorageMode storageMode) throws NotAvailableException {
8031             property.setReadLengthValueFromStreamListener(
8032                     getReadFromStreamListener(property.getLengthType(), storageMode));
8033         }
8034 
8035         /**
8036          * Returns a listener to read data from the file stream using provided
8037          * data type (int8, uint8, int16, uint16, etc.) and storage mode (ascii,
8038          * little endian or big endian).
8039          *
8040          * @param dataType    Data type to read.
8041          * @param storageMode Storage mode of file.
8042          * @return A listener.
8043          */
8044         private PLYReadValueFromStreamListener getReadFromStreamListener(
8045                 final DataTypePLY dataType, final PLYStorageMode storageMode) {
8046             return switch (dataType) {
8047                 case PLY_INT8 -> switch (storageMode) {
8048                     case PLY_ASCII -> new AsciiInt8ReadValueFromStreamListener();
8049                     case PLY_LITTLE_ENDIAN, PLY_BIG_ENDIAN -> new BinaryInt8ReadValueFromStreamListener();
8050                 };
8051                 case PLY_UINT8 -> switch (storageMode) {
8052                     case PLY_ASCII -> new AsciiUint8ReadValueFromStreamListener();
8053                     case PLY_LITTLE_ENDIAN, PLY_BIG_ENDIAN -> new BinaryUint8ReadValueFromStreamListener();
8054                 };
8055                 case PLY_INT16 -> switch (storageMode) {
8056                     case PLY_ASCII -> new AsciiInt16ReadValueFromStreamListener();
8057                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianInt16ReadValueFromStreamListener();
8058                     case PLY_BIG_ENDIAN -> new BinaryBigEndianInt16ReadValueFromStreamListener();
8059                 };
8060                 case PLY_UINT16 -> switch (storageMode) {
8061                     case PLY_ASCII -> new AsciiUint16ReadValueFromStreamListener();
8062                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianUint16ReadValueFromStreamListener();
8063                     case PLY_BIG_ENDIAN -> new BinaryBigEndianUint16ReadValueFromStreamListener();
8064                 };
8065                 case PLY_INT32 -> switch (storageMode) {
8066                     case PLY_ASCII -> new AsciiInt32ReadValueFromStreamListener();
8067                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianInt32ReadValueFromStreamListener();
8068                     case PLY_BIG_ENDIAN -> new BinaryBigEndianInt32ReadValueFromStreamListener();
8069                 };
8070                 case PLY_UINT32 -> switch (storageMode) {
8071                     case PLY_ASCII -> new AsciiUint32ReadValueFromStreamListener();
8072                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianUint32ReadValueFromStreamListener();
8073                     case PLY_BIG_ENDIAN -> new BinaryBigEndianUint32ReadValueFromStreamListener();
8074                 };
8075                 case PLY_FLOAT32 -> switch (storageMode) {
8076                     case PLY_ASCII -> new AsciiFloat32ReadValueFromStreamListener();
8077                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianFloat32ReadValueFromStreamListener();
8078                     case PLY_BIG_ENDIAN -> new BinaryBigEndianFloat32ReadValueFromStreamListener();
8079                 };
8080                 case PLY_FLOAT64 -> switch (storageMode) {
8081                     case PLY_ASCII -> new AsciiFloat64ReadValueFromStreamListener();
8082                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianFloat64ReadValueFromStreamListener();
8083                     case PLY_BIG_ENDIAN -> new BinaryBigEndianFloat64ReadValueFromStreamListener();
8084                 };
8085                 case PLY_CHAR -> switch (storageMode) {
8086                     case PLY_ASCII -> new AsciiCharReadValueFromStreamListener();
8087                     case PLY_LITTLE_ENDIAN, PLY_BIG_ENDIAN -> new BinaryCharReadValueFromStreamListener();
8088                 };
8089                 case PLY_UCHAR -> switch (storageMode) {
8090                     case PLY_ASCII -> new AsciiUcharReadValueFromStreamListener();
8091                     case PLY_LITTLE_ENDIAN, PLY_BIG_ENDIAN -> new BinaryUcharReadValueFromStreamListener();
8092                 };
8093                 case PLY_SHORT -> switch (storageMode) {
8094                     case PLY_ASCII -> new AsciiShortReadValueFromStreamListener();
8095                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianShortReadValueFromStreamListener();
8096                     case PLY_BIG_ENDIAN -> new BinaryBigEndianShortReadValueFromStreamListener();
8097                 };
8098                 case PLY_USHORT -> switch (storageMode) {
8099                     case PLY_ASCII -> new AsciiUshortReadValueFromStreamListener();
8100                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianUshortReadValueFromStreamListener();
8101                     case PLY_BIG_ENDIAN -> new BinaryBigEndianUshortReadValueFromStreamListener();
8102                 };
8103                 case PLY_INT -> switch (storageMode) {
8104                     case PLY_ASCII -> new AsciiIntReadValueFromStreamListener();
8105                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianIntReadValueFromStreamListener();
8106                     case PLY_BIG_ENDIAN -> new BinaryBigEndianIntReadValueFromStreamListener();
8107                 };
8108                 case PLY_UINT -> switch (storageMode) {
8109                     case PLY_ASCII -> new AsciiUintReadValueFromStreamListener();
8110                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianUintReadValueFromStreamListener();
8111                     case PLY_BIG_ENDIAN -> new BinaryBigEndianUintReadValueFromStreamListener();
8112                 };
8113                 case PLY_FLOAT -> switch (storageMode) {
8114                     case PLY_ASCII -> new AsciiFloatReadValueFromStreamListener();
8115                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianFloatReadValueFromStreamListener();
8116                     case PLY_BIG_ENDIAN -> new BinaryBigEndianFloatReadValueFromStreamListener();
8117                 };
8118                 case PLY_DOUBLE -> switch (storageMode) {
8119                     case PLY_ASCII -> new AsciiDoubleReadValueFromStreamListener();
8120                     case PLY_LITTLE_ENDIAN -> new BinaryLittleEndianDoubleReadValueFromStreamListener();
8121                     case PLY_BIG_ENDIAN -> new BinaryBigEndianDoubleReadValueFromStreamListener();
8122                 };
8123             };
8124         }
8125 
8126         /**
8127          * Sets the listener to read length value from temporal buffer to
8128          * provided property.
8129          *
8130          * @param property A PLY header property.
8131          * @throws NotAvailableException Raised if a listener cannot be set
8132          *                               for given property because its data type is not supported.
8133          */
8134         private void setReadLengthValueFromBufferListener(final PropertyPLY property) throws NotAvailableException {
8135             switch (property.getLengthType()) {
8136                 case PLY_INT8:
8137                     property.setReadLengthValueFromBufferListener(new FaceInt8ReadLengthValueFromBufferListener());
8138                     break;
8139                 case PLY_UINT8:
8140                     property.setReadLengthValueFromBufferListener(new FaceUint8ReadLengthValueFromBufferListener());
8141                     break;
8142                 case PLY_INT16:
8143                     property.setReadLengthValueFromBufferListener(new FaceInt16ReadLengthValueFromBufferListener());
8144                     break;
8145                 case PLY_UINT16:
8146                     property.setReadLengthValueFromBufferListener(new FaceUint16ReadLengthValueFromBufferListener());
8147                     break;
8148                 case PLY_INT32:
8149                     property.setReadLengthValueFromBufferListener(new FaceInt32ReadLengthValueFromBufferListener());
8150                     break;
8151                 case PLY_UINT32:
8152                     property.setReadLengthValueFromBufferListener(new FaceUint32ReadLengthValueFromBufferListener());
8153                     break;
8154                 case PLY_FLOAT32:
8155                     property.setReadLengthValueFromBufferListener(new FaceFloat32ReadLengthValueFromBufferListener());
8156                     break;
8157                 case PLY_FLOAT64:
8158                     property.setReadLengthValueFromBufferListener(new FaceFloat64ReadLengthValueFromBufferListener());
8159                     break;
8160                 case PLY_CHAR:
8161                     property.setReadLengthValueFromBufferListener(new FaceCharReadLengthValueFromBufferListener());
8162                     break;
8163                 case PLY_UCHAR:
8164                     property.setReadLengthValueFromBufferListener(new FaceUcharReadLengthValueFromBufferListener());
8165                     break;
8166                 case PLY_SHORT:
8167                     property.setReadLengthValueFromBufferListener(new FaceShortReadLengthValueFromBufferListener());
8168                     break;
8169                 case PLY_USHORT:
8170                     property.setReadLengthValueFromBufferListener(new FaceUshortReadLengthValueFromBufferListener());
8171                     break;
8172                 case PLY_INT:
8173                     property.setReadLengthValueFromBufferListener(new FaceIntReadLengthValueFromBufferListener());
8174                     break;
8175                 case PLY_UINT:
8176                     property.setReadLengthValueFromBufferListener(new FaceUintReadLengthValueFromBufferListener());
8177                     break;
8178                 case PLY_FLOAT:
8179                     property.setReadLengthValueFromBufferListener(new FaceFloatReadLengthValueFromBufferListener());
8180                     break;
8181                 case PLY_DOUBLE:
8182                     property.setReadLengthValueFromBufferListener(new FaceDoubleReadLengthValueFromBufferListener());
8183                     break;
8184                 default:
8185                     throw new NotAvailableException();
8186             }
8187         }
8188     }
8189 }
8190 
8191 //TODO: add cancel method
8192 //TODO: add unit tests for loader ply