SYCL: Avoid using no_init read accessor in rocFFT
[alexxy/gromacs.git] / src / external / tng_io / src / lib / tng_io.c
1 /* This code is part of the tng binary trajectory format.
2  *
3  * Written by Magnus Lundborg
4  * Copyright (c) 2012-2017, The GROMACS development team.
5  * Check out http://www.gromacs.org for more information.
6  *
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the Revised BSD License.
10  */
11
12 /* These three definitions are required to enforce 64 bit file sizes. */
13 /* Force 64 bit variants of file access calls. */
14 #define _FILE_OFFSET_BITS 64
15 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
16 #define _LARGEFILE_SOURCE
17 /* Define for large files, on AIX-style hosts. */
18 #define _LARGE_FILES
19
20 #include "tng/tng_io.h"
21
22 #ifdef USE_STD_INTTYPES_H
23 #include <inttypes.h>
24 #endif
25
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30 #include <math.h>
31 #include <zlib.h>
32
33 #include "tng/md5.h"
34 #include "compression/tng_compress.h"
35 #include "tng/version.h"
36
37 #if defined( _WIN32 ) || defined( _WIN64 )
38     #ifndef fseeko
39         #define fseeko _fseeki64
40     #endif
41     #ifndef ftello
42         #ifdef __MINGW32__
43             #define ftello ftello64
44         #else
45             #define ftello _ftelli64
46         #endif
47     #endif
48 #endif
49
50 struct tng_bond {
51     /** One of the atoms of the bond */
52     int64_t from_atom_id;
53     /** The other atom of the bond */
54     int64_t to_atom_id;
55 };
56
57 struct tng_atom {
58     /** The residue containing this atom */
59     tng_residue_t residue;
60     /** A unique (per molecule) ID number of the atom */
61     int64_t id;
62     /** The atom_type (depending on the forcefield) */
63     char *atom_type;
64     /** The name of the atom */
65     char *name;
66 };
67
68 struct tng_residue {
69     /** The chain containing this residue */
70     tng_chain_t chain;
71     /** A unique (per chain) ID number of the residue */
72     int64_t id;
73     /** The name of the residue */
74     char *name;
75     /** The number of atoms in the residue */
76     int64_t n_atoms;
77     /** A list of atoms in the residue */
78     int64_t atoms_offset;
79 };
80
81 struct tng_chain {
82     /** The molecule containing this chain */
83     tng_molecule_t molecule;
84     /** A unique (per molecule) ID number of the chain */
85     int64_t id;
86     /** The name of the chain */
87     char *name;
88     /** The number of residues in the chain */
89     int64_t n_residues;
90     /** A list of residues in the chain */
91     tng_residue_t residues;
92 };
93
94 struct tng_molecule {
95     /** A unique ID number of the molecule */
96     int64_t id;
97     /** Quaternary structure of the molecule.
98      *  1 => monomeric
99      *  2 => dimeric
100      *  3 => trimeric
101      *  etc */
102     int64_t quaternary_str;
103     /** The number of chains in the molecule */
104     int64_t n_chains;
105     /** The number of residues in the molecule */
106     int64_t n_residues;
107     /** The number of atoms in the molecule */
108     int64_t n_atoms;
109     /** The number of bonds in the molecule. If the bonds are not specified this
110      * value can be 0. */
111     int64_t n_bonds;
112     /** The name of the molecule */
113     char *name;
114     /** A list of chains in the molecule */
115     tng_chain_t chains;
116     /** A list of residues in the molecule */
117     tng_residue_t residues;
118     /** A list of the atoms in the molecule */
119     tng_atom_t atoms;
120     /** A list of the bonds in the molecule */
121     tng_bond_t bonds;
122 };
123
124 struct tng_gen_block {
125     /** The size of the block header in bytes */
126     int64_t header_contents_size;
127     /** The size of the block contents in bytes */
128     int64_t block_contents_size;
129     /** The ID of the block to determine its type */
130     int64_t id;
131     /** The MD5 hash of the block to verify integrity */
132     char md5_hash[TNG_MD5_HASH_LEN];
133     /** The name of the block */
134     char *name;
135     /** The library version used to write the block */
136     int64_t block_version;
137     int64_t alt_hash_type;
138     int64_t alt_hash_len;
139     char *alt_hash;
140     int64_t signature_type;
141     int64_t signature_len;
142     char *signature;
143     /** The full block header contents */
144     char *header_contents;
145     /** The full block contents */
146     char *block_contents;
147 };
148
149 struct tng_particle_mapping {
150     /** The index number of the first particle in this mapping block */
151     int64_t num_first_particle;
152     /** The number of particles list in this mapping block */
153     int64_t n_particles;
154     /** the mapping of index numbers to the real particle numbers in the
155      * trajectory. real_particle_numbers[0] is the real particle number
156      * (as it is numbered in the molecular system) of the first particle
157      * in the data blocks covered by this particle mapping block */
158     int64_t *real_particle_numbers;
159 };
160
161 struct tng_trajectory_frame_set {
162     /** The number of different particle mapping blocks present. */
163     int64_t n_mapping_blocks;
164     /** The atom mappings of this frame set */
165     struct tng_particle_mapping *mappings;
166     /** The first frame of this frame set */
167     int64_t first_frame;
168     /** The number of frames in this frame set */
169     int64_t n_frames;
170     /** The number of written frames in this frame set (used when writing one
171      * frame at a time). */
172     int64_t n_written_frames;
173     /** The number of frames not yet written to file in this frame set
174      * (used from the utility functions to finish the writing properly. */
175     int64_t n_unwritten_frames;
176
177
178     /** A list of the number of each molecule type - only used when using
179      * variable number of atoms */
180     int64_t *molecule_cnt_list;
181     /** The number of particles/atoms - only used when using variable number
182      * of atoms */
183     int64_t n_particles;
184     /** The file position of the next frame set */
185     int64_t next_frame_set_file_pos;
186     /** The file position of the previous frame set */
187     int64_t prev_frame_set_file_pos;
188     /** The file position of the frame set one long stride step ahead */
189     int64_t medium_stride_next_frame_set_file_pos;
190     /** The file position of the frame set one long stride step behind */
191     int64_t medium_stride_prev_frame_set_file_pos;
192     /** The file position of the frame set one long stride step ahead */
193     int64_t long_stride_next_frame_set_file_pos;
194     /** The file position of the frame set one long stride step behind */
195     int64_t long_stride_prev_frame_set_file_pos;
196     /** Time stamp (in seconds) of first frame in frame set */
197     double first_frame_time;
198
199     /* The data blocks in a frame set are trajectory data blocks */
200     /** The number of trajectory data blocks of particle dependent data */
201     int n_particle_data_blocks;
202     /** A list of data blocks containing particle dependent data */
203     struct tng_data *tr_particle_data;
204     /** The number of trajectory data blocks independent of particles */
205     int n_data_blocks;
206     /** A list of data blocks containing particle indepdendent data */
207     struct tng_data *tr_data;
208 };
209
210 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
211 struct tng_data {
212     /** The block ID of the data block containing this particle data.
213      *  This is used to determine the kind of data that is stored */
214     int64_t block_id;
215     /** The name of the data block. This is used to determine the kind of
216      *  data that is stored */
217     char *block_name;
218     /** The type of data stored. */
219     char datatype;
220     /** A flag to indicate if this data block contains frame and/or particle dependent
221      * data */
222     char dependency;
223     /** The frame number of the first data value */
224     int64_t first_frame_with_data;
225     /** The number of frames in this frame set */
226     int64_t n_frames;
227     /** The number of values stored per frame */
228     int64_t n_values_per_frame;
229     /** The number of frames between each data point - e.g. when
230      *  storing sparse data. */
231     int64_t stride_length;
232     /** ID of the CODEC used for compression 0 == no compression. */
233     int64_t codec_id;
234     /** If reading one frame at a time this is the last read frame */
235     int64_t last_retrieved_frame;
236     /** The multiplier used for getting integer values for compression */
237     double compression_multiplier;
238     /** A 1-dimensional array of values of length
239      *  [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
240     void *values;
241     /** If storing character data store it in a 3-dimensional array */
242     char ****strings;
243 };
244
245
246 struct tng_trajectory {
247     /** The path of the input trajectory file */
248     char *input_file_path;
249     /** A handle to the input file */
250     FILE *input_file;
251     /** The length of the input file */
252     int64_t input_file_len;
253     /** The path of the output trajectory file */
254     char *output_file_path;
255     /** A handle to the output file */
256     FILE *output_file;
257     /** Function to swap 32 bit values to and from the endianness of the
258      * input file */
259     tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *);
260     /** Function to swap 64 bit values to and from the endianness of the
261      * input file */
262     tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *);
263     /** Function to swap 32 bit values to and from the endianness of the
264      * input file */
265     tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *);
266     /** Function to swap 64 bit values to and from the endianness of the
267      * input file */
268     tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *);
269     /** The endianness of 32 bit values of the current computer */
270     char endianness_32;
271     /** The endianness of 64 bit values of the current computer */
272     char endianness_64;
273
274     /** The name of the program producing this trajectory */
275     char *first_program_name;
276     /** The forcefield used in the simulations */
277     char *forcefield_name;
278     /** The name of the user running the simulations */
279     char *first_user_name;
280     /** The name of the computer on which the simulations were performed */
281     char *first_computer_name;
282     /** The PGP signature of the user creating the file. */
283     char *first_pgp_signature;
284     /** The name of the program used when making last modifications to the
285      *  file */
286     char *last_program_name;
287     /** The name of the user making the last modifications to the file */
288     char *last_user_name;
289     /** The name of the computer on which the last modifications were made */
290     char *last_computer_name;
291     /** The PGP signature of the user making the last modifications to the
292      *  file. */
293     char *last_pgp_signature;
294     /** The time (n seconds since 1970) when the file was created */
295     int64_t time;
296     /** The exponential of the value of the distance unit used. The default
297      * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
298      * the measurements are in Ã… the distance_unit_exponential = -10. */
299     int64_t distance_unit_exponential;
300
301     /** A flag indicating if the number of atoms can vary throughout the
302      *  simulation, e.g. using a grand canonical ensemble */
303     char var_num_atoms_flag;
304     /** The number of frames in a frame set. It is allowed to have frame sets
305      *  with fewer frames, but this will help searching for specific frames */
306     int64_t frame_set_n_frames;
307     /** The number of frame sets in a medium stride step */
308     int64_t medium_stride_length;
309     /** The number of frame sets in a long stride step */
310     int64_t long_stride_length;
311     /** The current (can change from one frame set to another) time length
312      *  (in seconds) of one frame */
313     double time_per_frame;
314
315     /** The number of different kinds of molecules in the trajectory */
316     int64_t n_molecules;
317     /** A list of molecules in the trajectory */
318     tng_molecule_t molecules;
319     /** A list of the count of each molecule - if using variable number of
320      *  particles this will be specified in each frame set */
321     int64_t *molecule_cnt_list;
322     /** The total number of particles/atoms. If using variable number of
323      *  particles this will be specified in each frame set */
324     int64_t n_particles;
325
326      /** The pos in the src file of the first frame set */
327     int64_t first_trajectory_frame_set_input_file_pos;
328     /** The pos in the dest file of the first frame set */
329     int64_t first_trajectory_frame_set_output_file_pos;
330     /** The pos in the src file of the last frame set */
331     int64_t last_trajectory_frame_set_input_file_pos;
332     /** The pos in the dest file of the last frame set */
333     int64_t last_trajectory_frame_set_output_file_pos;
334     /** The currently active frame set */
335     struct tng_trajectory_frame_set current_trajectory_frame_set;
336     /** The pos in the src file of the current frame set */
337     int64_t current_trajectory_frame_set_input_file_pos;
338     /** The pos in the dest file of the current frame set */
339     int64_t current_trajectory_frame_set_output_file_pos;
340     /** The number of frame sets in the trajectory N.B. Not saved in file and
341      *  cannot be trusted to be up-to-date */
342     int64_t n_trajectory_frame_sets;
343
344     /* These data blocks are non-trajectory data blocks */
345     /** The number of non-frame dependent particle dependent data blocks */
346     int n_particle_data_blocks;
347     /** A list of data blocks containing particle dependent data */
348     struct tng_data *non_tr_particle_data;
349
350     /** The number of frame and particle independent data blocks */
351     int n_data_blocks;
352     /** A list of frame and particle indepdendent data blocks */
353     struct tng_data *non_tr_data;
354
355     /** TNG compression algorithm for compressing positions */
356     int *compress_algo_pos;
357     /** TNG compression algorithm for compressing velocities */
358     int *compress_algo_vel;
359     /** The precision used for lossy compression */
360     double compression_precision;
361 };
362
363 #ifndef USE_WINDOWS
364 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
365 #define USE_WINDOWS
366 #endif /* win32... */
367 #endif /* not defined USE_WINDOWS */
368
369 #ifdef USE_WINDOWS
370 #define TNG_INLINE __inline
371 #define TNG_SNPRINTF _snprintf
372 #else
373 #define TNG_INLINE inline
374 #define TNG_SNPRINTF snprintf
375 #endif
376
377 static TNG_INLINE size_t tng_min_size(const size_t a, const size_t b)
378 {
379     return (a < b ? a : b);
380 }
381
382 static TNG_INLINE int64_t tng_min_i64(const int64_t a, const int64_t b)
383 {
384     return (a < b ? a : b);
385 }
386
387 static TNG_INLINE int64_t tng_max_i64(const int64_t a, const int64_t b)
388 {
389     return (a > b ? a : b);
390 }
391
392 /**
393  * @brief This function swaps the byte order of a 32 bit numerical variable
394  * to big endian.
395  * @param tng_data is a trajectory data container.
396  * @param v is a pointer to a 32 bit numerical value (float or integer).
397  * @details The function does not only work with integer, but e.g. floats need casting.
398  * If the byte order is already big endian no change is needed.
399  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
400  * byte order is not recognised.
401  */
402 static tng_function_status tng_swap_byte_order_big_endian_32
403                 (const tng_trajectory_t tng_data, uint32_t *v)
404 {
405     switch(tng_data->endianness_32)
406     {
407     case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
408         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
409              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
410              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
411              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
412
413         return(TNG_SUCCESS);
414
415     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
416         *v = ((*v & 0xFFFF0000) >> 16) |
417              ((*v & 0x0000FFFF) << 16);
418
419         return(TNG_SUCCESS);
420
421     case TNG_BIG_ENDIAN_32: /* Already correct */
422         return(TNG_SUCCESS);
423
424     default:
425         return(TNG_FAILURE);
426     }
427 }
428
429 /**
430  * @brief This function swaps the byte order of a 64 bit numerical variable
431  * to big endian.
432  * @param tng_data is a trajectory data container.
433  * @param v is a pointer to a 64 bit numerical value (double or integer).
434  * @details The function does not only work with integer, but e.g. floats need casting.
435  * The byte order swapping routine can convert four different byte
436  * orders to big endian.
437  * If the byte order is already big endian no change is needed.
438  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
439  * byte order is not recognised.
440  */
441 static tng_function_status tng_swap_byte_order_big_endian_64
442                 (const tng_trajectory_t tng_data, uint64_t *v)
443 {
444     switch(tng_data->endianness_64)
445     {
446     case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
447         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
448              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
449              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
450              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
451              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
452              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
453              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
454              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
455
456         return(TNG_SUCCESS);
457
458     case TNG_QUAD_SWAP_64: /* Byte quad swap */
459         *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
460              ((*v & 0x00000000FFFFFFFFLL) << 32);
461
462         return(TNG_SUCCESS);
463
464     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
465         *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
466              ((*v & 0x0000FFFF0000FFFFLL) << 16);
467
468         return(TNG_SUCCESS);
469
470     case TNG_BYTE_SWAP_64: /* Byte swap */
471         *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
472              ((*v & 0x00FF00FF00FF00FFLL) << 8);
473
474         return(TNG_SUCCESS);
475
476     case TNG_BIG_ENDIAN_64: /* Already correct */
477         return(TNG_SUCCESS);
478
479     default:
480         return(TNG_FAILURE);
481     }
482 }
483
484 /**
485  * @brief This function swaps the byte order of a 32 bit numerical variable
486  * to little endian.
487  * @param tng_data is a trajectory data container.
488  * @param v is a pointer to a 32 bit numerical value (float or integer).
489  * @details The function does not only work with integer, but e.g. floats need casting.
490  * If the byte order is already little endian no change is needed.
491  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
492  * byte order is not recognised.
493  */
494 static tng_function_status tng_swap_byte_order_little_endian_32
495                 (const tng_trajectory_t tng_data, uint32_t *v)
496 {
497     switch(tng_data->endianness_32)
498     {
499     case TNG_LITTLE_ENDIAN_32: /* Already correct */
500         return(TNG_SUCCESS);
501
502     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
503         *v = ((*v & 0xFF00FF00) >> 8) |
504              ((*v & 0x00FF00FF) << 8);
505
506         return(TNG_SUCCESS);
507
508     case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
509         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
510              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
511              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
512              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
513
514         return(TNG_SUCCESS);
515
516     default:
517         return(TNG_FAILURE);
518     }
519 }
520
521 /**
522  * @brief This function swaps the byte order of a 64 bit numerical variable
523  * to little endian.
524  * @param tng_data is a trajectory data container.
525  * @param v is a pointer to a 64 bit numerical value (double or integer).
526  * @details The function does not only work with integer, but e.g. floats need casting.
527  * The byte order swapping routine can convert four different byte
528  * orders to little endian.
529  * If the byte order is already little endian no change is needed.
530  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
531  * byte order is not recognised.
532  */
533 static tng_function_status tng_swap_byte_order_little_endian_64
534                 (const tng_trajectory_t tng_data, uint64_t *v)
535 {
536     switch(tng_data->endianness_64)
537     {
538     case TNG_LITTLE_ENDIAN_64: /* Already correct */
539         return(TNG_SUCCESS);
540
541     case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
542         *v = ((*v & 0xFF000000FF000000LL) >> 24) |
543              ((*v & 0x00FF000000FF0000LL) >> 8) |
544              ((*v & 0x0000FF000000FF00LL) << 8) |
545              ((*v & 0x000000FF000000FFLL) << 24);
546
547         return(TNG_SUCCESS);
548
549     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
550         *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
551              ((*v & 0x00FF00FF00000000LL) >> 24) |
552              ((*v & 0x00000000FF00FF00LL) << 24) |
553              ((*v & 0x0000000000FF00FFLL) << 40);
554
555         return(TNG_SUCCESS);
556
557     case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
558         *v = ((*v & 0xFFFF000000000000LL) >> 48) |
559              ((*v & 0x0000FFFF00000000LL) >> 16) |
560              ((*v & 0x00000000FFFF0000LL) << 16) |
561              ((*v & 0x000000000000FFFFLL) << 48);
562
563         return(TNG_SUCCESS);
564
565     case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
566         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
567              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
568              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
569              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
570              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
571              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
572              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
573              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
574
575         return(TNG_SUCCESS);
576
577     default:
578         return(TNG_FAILURE);
579     }
580 }
581
582 /**
583  * @brief Read a NULL terminated string from a file.
584  * @param tng_data is a trajectory data container
585  * @param str is a pointer to the character string that will
586  * contain the read string. *str is reallocated in the function
587  * and must be NULL or pointing at already allocated memory.
588  * @param hash_mode is an option to decide whether to use the md5 hash or not.
589  * @param md5_state is a pointer to the current md5 storage, which will be
590  * appended with str if hash_mode == TNG_USE_HASH.
591  * @param line_nr is the line number where this function was called, to be
592  * able to give more useful error messages.
593  */
594 static tng_function_status tng_freadstr(const tng_trajectory_t tng_data,
595                                         char **str,
596                                         const char hash_mode,
597                                         md5_state_t *md5_state,
598                                         const int line_nr)
599 {
600     char temp[TNG_MAX_STR_LEN], *temp_alloc;
601     int c, count = 0;
602
603     do
604     {
605         c = fgetc(tng_data->input_file);
606
607         if (c == EOF)
608         {
609             /* Clear file error flag and return -1 if EOF is read.*/
610             clearerr(tng_data->input_file);
611             return TNG_FAILURE;
612         }
613         else
614         {
615             /* Cast c to char */
616             temp[count++] = (char) c;
617         }
618     } while ((temp[count-1] != '\0') && (count < TNG_MAX_STR_LEN));
619
620     temp_alloc = (char *)realloc(*str, count);
621     if(!temp_alloc)
622     {
623         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, line_nr);
624         free(*str);
625         *str = 0;
626         return TNG_FAILURE;
627     }
628     *str = temp_alloc;
629
630     strncpy(*str, temp, count);
631
632     if(hash_mode == TNG_USE_HASH)
633     {
634         md5_append(md5_state, (md5_byte_t *)*str, count);
635     }
636
637     return TNG_SUCCESS;
638 }
639
640 /**
641  * @brief Write a NULL terminated string to a file.
642  * @param tng_data is a trajectory data container
643  * @param str is a pointer to the character string should be written.
644  * @param hash_mode is an option to decide whether to use the md5 hash or not.
645  * @param md5_state is a pointer to the current md5 storage, which will be
646  * appended with str if hash_mode == TNG_USE_HASH.
647  * @param line_nr is the line number where this function was called, to be
648  * able to give more useful error messages.
649  */
650 static TNG_INLINE tng_function_status tng_fwritestr(tng_trajectory_t tng_data,
651                                                 const char *str,
652                                                 const char hash_mode,
653                                                 md5_state_t *md5_state,
654                                                 const int line_nr)
655 {
656     size_t len;
657
658     len = tng_min_size(strlen(str) + 1, TNG_MAX_STR_LEN);
659
660     if(fwrite(str, len, 1, tng_data->output_file) != 1)
661     {
662         fprintf(stderr, "TNG library: Could not write block data. %s: %d\n", __FILE__, line_nr);
663         return(TNG_CRITICAL);
664     }
665
666     if(hash_mode == TNG_USE_HASH)
667     {
668         md5_append(md5_state, (md5_byte_t *)str, len);
669     }
670
671     return(TNG_SUCCESS);
672 }
673
674 /**
675  * @brief Read a numerical value from file.
676  * The byte order will be swapped if need be.
677  * @param tng_data is a trajectory data container
678  * @param dest is a pointer to where to store the read data.
679  * @param len is the length (in bytes) of the numerical data type. Should
680  * be 8 for 64 bit, 4 for 32 bit or 1 for a single byte flag.
681  * @param hash_mode is an option to decide whether to use the md5 hash or not.
682  * @param md5_state is a pointer to the current md5 storage, which will be
683  * appended with str if hash_mode == TNG_USE_HASH.
684  * @param line_nr is the line number where this function was called, to be
685  * able to give more useful error messages.
686  */
687 static TNG_INLINE tng_function_status tng_file_input_numerical
688                 (const tng_trajectory_t tng_data,
689                  void *dest,
690                  const size_t len,
691                  const char hash_mode,
692                  md5_state_t *md5_state,
693                  const int line_nr)
694 {
695     if(fread(dest, len, 1, tng_data->input_file) == 0)
696     {
697         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, line_nr);
698         return(TNG_CRITICAL);
699     }
700     if(hash_mode == TNG_USE_HASH)
701     {
702         md5_append(md5_state, (md5_byte_t *)dest, len);
703     }
704     switch(len)
705     {
706     case 8:
707         if(tng_data->input_endianness_swap_func_64 &&
708            tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)dest) != TNG_SUCCESS)
709         {
710             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
711                     __FILE__, line_nr);
712         }
713         break;
714     case 4:
715         if(tng_data->input_endianness_swap_func_32 &&
716            tng_data->input_endianness_swap_func_32(tng_data, (uint32_t *)dest) != TNG_SUCCESS)
717         {
718             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
719                     __FILE__, line_nr);
720         }
721         break;
722     default:
723         break;
724     }
725
726     return(TNG_SUCCESS);
727 }
728
729 /**
730  * @brief Write a numerical value to file.
731  * The byte order will be swapped if need be.
732  * @param tng_data is a trajectory data container
733  * @param src is a pointer to the data to write.
734  * @param len is the length (in bytes) of the numerical data type. Should
735  * be 8 for 64 bit, 4 for 32 bit or 1 for a single byte flag.
736  * @param hash_mode is an option to decide whether to use the md5 hash or not.
737  * @param md5_state is a pointer to the current md5 storage, which will be
738  * appended with str if hash_mode == TNG_USE_HASH.
739  * @param line_nr is the line number where this function was called, to be
740  * able to give more useful error messages.
741  */
742 static TNG_INLINE tng_function_status tng_file_output_numerical
743                 (const tng_trajectory_t tng_data,
744                  const void *src,
745                  const size_t len,
746                  const char hash_mode,
747                  md5_state_t *md5_state,
748                  const int line_nr)
749 {
750     uint32_t temp_i32;
751     uint64_t temp_i64;
752
753     switch(len)
754     {
755         case 8:
756             temp_i64 = *((uint64_t *)src);
757             if(tng_data->output_endianness_swap_func_64 &&
758             tng_data->output_endianness_swap_func_64(tng_data, &temp_i64) != TNG_SUCCESS)
759             {
760                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
761                         __FILE__, line_nr);
762             }
763             if(fwrite(&temp_i64, len, 1, tng_data->output_file) != 1)
764             {
765                 fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr);
766                 return(TNG_CRITICAL);
767             }
768             if(hash_mode == TNG_USE_HASH)
769             {
770                 md5_append(md5_state, (md5_byte_t *)&temp_i64, len);
771             }
772             break;
773         case 4:
774             temp_i32 = *((uint32_t *)src);
775             if(tng_data->output_endianness_swap_func_32 &&
776             tng_data->output_endianness_swap_func_32(tng_data, &temp_i32) != TNG_SUCCESS)
777             {
778                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
779                         __FILE__, line_nr);
780             }
781             if(fwrite(&temp_i32, len, 1, tng_data->output_file) != 1)
782             {
783                 fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr);
784                 return(TNG_CRITICAL);
785             }
786             if(hash_mode == TNG_USE_HASH)
787             {
788                 md5_append(md5_state, (md5_byte_t *)&temp_i32, len);
789             }
790             break;
791         default:
792             if(fwrite(src, len, 1, tng_data->output_file) != 1)
793             {
794                 fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr);
795                 return(TNG_CRITICAL);
796             }
797             if(hash_mode == TNG_USE_HASH)
798             {
799                 md5_append(md5_state, (md5_byte_t *)src, len);
800             }
801             break;
802     }
803
804     return(TNG_SUCCESS);
805 }
806
807 /**
808  * @brief Generate the md5 hash of a block.
809  * The hash is created based on the actual block contents.
810  * @param block is a general block container.
811  * @return TNG_SUCCESS (0) if successful.
812  */
813 static tng_function_status tng_block_md5_hash_generate(const tng_gen_block_t block)
814 {
815     md5_state_t md5_state;
816
817     md5_init(&md5_state);
818     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
819                (int)block->block_contents_size);
820     md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
821
822     return(TNG_SUCCESS);
823 }
824
825 /**
826  * @brief If there is data left in the block read that to append that to the MD5 hash.
827  * @param tng_data is a trajectory data container.
828  * @param block is the data block that is being read.
829  * @param start_pos is the file position where the block started.
830  * @param md5_state is the md5 to which the md5 of the remaining block
831  * will be appended.
832  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
833  * error has occured.
834  */
835 static tng_function_status tng_md5_remaining_append(const tng_trajectory_t tng_data,
836                                                     const tng_gen_block_t block,
837                                                     const int64_t start_pos,
838                                                     md5_state_t *md5_state)
839 {
840     int64_t curr_file_pos;
841     char *temp_data;
842
843     curr_file_pos = ftello(tng_data->input_file);
844     if(curr_file_pos < start_pos + block->block_contents_size)
845     {
846         temp_data = (char *)malloc(start_pos + block->block_contents_size - curr_file_pos);
847         if(!temp_data)
848         {
849             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
850                     __FILE__, __LINE__);
851             return(TNG_CRITICAL);
852         }
853         if(fread(temp_data, start_pos + block->block_contents_size - curr_file_pos,
854                     1, tng_data->input_file) == 0)
855         {
856             fprintf(stderr, "TNG library: Cannot read remaining part of block to generate MD5 sum. %s: %d\n", __FILE__, __LINE__);
857             free(temp_data);
858             return(TNG_CRITICAL);
859         }
860         md5_append(md5_state, (md5_byte_t *)temp_data,
861                    start_pos + block->block_contents_size - curr_file_pos);
862         free(temp_data);
863     }
864
865     return(TNG_SUCCESS);
866 }
867
868 /**
869  * @brief Open the input file if it is not already opened.
870  * @param tng_data is a trajectory data container.
871  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
872  * error has occured.
873  */
874 static tng_function_status tng_input_file_init(const tng_trajectory_t tng_data)
875 {
876     int64_t file_pos;
877
878     if(!tng_data->input_file)
879     {
880         if(!tng_data->input_file_path)
881         {
882             fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
883                    __FILE__, __LINE__);
884             return(TNG_CRITICAL);
885         }
886         tng_data->input_file = fopen(tng_data->input_file_path, "rb");
887         if(!tng_data->input_file)
888         {
889             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
890                    tng_data->input_file_path, __FILE__, __LINE__);
891             return(TNG_CRITICAL);
892         }
893     }
894
895     if(!tng_data->input_file_len)
896     {
897         file_pos = ftello(tng_data->input_file);
898         fseeko(tng_data->input_file, 0, SEEK_END);
899         tng_data->input_file_len = ftello(tng_data->input_file);
900         fseeko(tng_data->input_file, file_pos, SEEK_SET);
901     }
902
903     return(TNG_SUCCESS);
904 }
905
906 /**
907  * @brief Open the output file if it is not already opened
908  * @param tng_data is a trajectory data container.
909  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
910  * error has occured.
911  */
912 static tng_function_status tng_output_file_init(const tng_trajectory_t tng_data)
913 {
914     if(!tng_data->output_file)
915     {
916         if(!tng_data->output_file_path)
917         {
918             fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
919                    __FILE__, __LINE__);
920             return(TNG_CRITICAL);
921         }
922
923         tng_data->output_file = fopen(tng_data->output_file_path, "wb+");
924
925         if(!tng_data->output_file)
926         {
927             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
928                    tng_data->output_file_path, __FILE__, __LINE__);
929             return(TNG_CRITICAL);
930         }
931     }
932     return(TNG_SUCCESS);
933 }
934
935 /**
936  * @brief Setup a file block container.
937  * @param block_p a pointer to memory to initialise as a file block container.
938  * @details Memory is allocated during initialisation.
939  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
940  * error has occured.
941  */
942 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
943 {
944     tng_gen_block_t block;
945
946     *block_p = (struct tng_gen_block *)malloc(sizeof(struct tng_gen_block));
947     if(!*block_p)
948     {
949         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
950         return(TNG_CRITICAL);
951     }
952
953     block = *block_p;
954
955     block->id = -1;
956     /* Reset the md5_hash */
957     memset(block->md5_hash, '\0', TNG_MD5_HASH_LEN);
958     block->name = 0;
959     block->block_version = TNG_API_VERSION;
960     block->header_contents = 0;
961     block->header_contents_size = 0;
962     block->block_contents = 0;
963     block->block_contents_size = 0;
964
965     return(TNG_SUCCESS);
966 }
967
968 /**
969  * @brief Clean up a file block container.
970  * @param block_p a pointer to the file block container to destroy.
971  * @details All allocated memory in the data structure is freed, as well as
972  * block_p itself.
973  * @return TNG_SUCCESS (0) if successful.
974  */
975 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
976 {
977     tng_gen_block_t block = *block_p;
978
979     if(!*block_p)
980     {
981         return(TNG_SUCCESS);
982     }
983
984 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
985     if(block->name)
986     {
987         free(block->name);
988         block->name = 0;
989     }
990     if(block->header_contents)
991     {
992         free(block->header_contents);
993         block->header_contents = 0;
994     }
995     if(block->block_contents)
996     {
997         free(block->block_contents);
998         block->block_contents = 0;
999     }
1000
1001     free(*block_p);
1002     *block_p = 0;
1003
1004     return(TNG_SUCCESS);
1005 }
1006
1007 /**
1008  * @brief Read the header of a data block, regardless of its type
1009  * @param tng_data is a trajectory data container.
1010  * @param block is a general block container.
1011  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor
1012  * error has occured (not able to read the header size, thus skipping
1013  * the block) or TNG_CRITICAL (2) if a major error has occured.
1014  */
1015 static tng_function_status tng_block_header_read
1016                 (const tng_trajectory_t tng_data, const tng_gen_block_t block)
1017 {
1018     int64_t start_pos;
1019
1020     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
1021
1022     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1023     {
1024         return(TNG_CRITICAL);
1025     }
1026
1027     start_pos = ftello(tng_data->input_file);
1028
1029     /* First read the header size to be able to read the whole header. */
1030     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
1031         1, tng_data->input_file) == 0)
1032     {
1033         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
1034                __FILE__, __LINE__);
1035         return(TNG_CRITICAL);
1036     }
1037
1038     if(block->header_contents_size == 0)
1039     {
1040         block->id = -1;
1041         return(TNG_FAILURE);
1042     }
1043
1044     /* If this was the size of the general info block check the endianness */
1045     if(ftello(tng_data->input_file) < 9)
1046     {
1047         /* File is little endian */
1048         if ( *((const char*)&block->header_contents_size) != 0x00 &&
1049              *((const char*)(&block->header_contents_size) + 7) == 0x00)
1050         {
1051             /* If the architecture endianness is little endian no byte swap
1052              * will be needed. Otherwise use the functions to swap to little
1053              * endian */
1054             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
1055             {
1056                 tng_data->input_endianness_swap_func_32 = 0;
1057             }
1058             else
1059             {
1060                 tng_data->input_endianness_swap_func_32 =
1061                 &tng_swap_byte_order_little_endian_32;
1062             }
1063             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
1064             {
1065                 tng_data->input_endianness_swap_func_64 = 0;
1066             }
1067             else
1068             {
1069                 tng_data->input_endianness_swap_func_64 =
1070                 &tng_swap_byte_order_little_endian_64;
1071             }
1072         }
1073         /* File is big endian */
1074         else
1075         {
1076             /* If the architecture endianness is big endian no byte swap
1077              * will be needed. Otherwise use the functions to swap to big
1078              * endian */
1079             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
1080             {
1081                 tng_data->input_endianness_swap_func_32 = 0;
1082             }
1083             else
1084             {
1085                 tng_data->input_endianness_swap_func_32 =
1086                 &tng_swap_byte_order_big_endian_32;
1087             }
1088             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
1089             {
1090                 tng_data->input_endianness_swap_func_64 = 0;
1091             }
1092             else
1093             {
1094                 tng_data->input_endianness_swap_func_64 =
1095                 &tng_swap_byte_order_big_endian_64;
1096             }
1097         }
1098     }
1099
1100     if(tng_data->input_endianness_swap_func_64 &&
1101        tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)&block->header_contents_size) != TNG_SUCCESS)
1102     {
1103         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1104                 __FILE__, __LINE__);
1105     }
1106
1107     if(tng_file_input_numerical(tng_data, &block->block_contents_size,
1108                                 sizeof(block->block_contents_size),
1109                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
1110     {
1111         return(TNG_CRITICAL);
1112     }
1113
1114     if(tng_file_input_numerical(tng_data, &block->id,
1115                                 sizeof(block->id),
1116                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
1117     {
1118         return(TNG_CRITICAL);
1119     }
1120
1121     if(fread(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->input_file) == 0)
1122     {
1123         fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n", __FILE__, __LINE__);
1124         return(TNG_CRITICAL);
1125     }
1126
1127     tng_freadstr(tng_data, &block->name, TNG_SKIP_HASH, 0, __LINE__);
1128
1129     if(tng_file_input_numerical(tng_data, &block->block_version,
1130                                 sizeof(block->block_version),
1131                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
1132     {
1133         return(TNG_CRITICAL);
1134     }
1135
1136     fseeko(tng_data->input_file, start_pos + block->header_contents_size, SEEK_SET);
1137
1138     return(TNG_SUCCESS);
1139 }
1140
1141 /**
1142  * @brief Write a whole block, both header and contents, regardless of it type
1143  * @param tng_data is a trajectory data container.
1144  * @param block is a general block container.
1145  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
1146  * has occurred or TNG_CRITICAL (2) if a major error has occured.
1147  */
1148 /* Disabled until it is used.*/
1149 /*
1150 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1151 //                                                     tng_gen_block_t block)
1152 // {
1153 //     if(!block->header_contents)
1154 //     {
1155 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1156 //         return(TNG_FAILURE);
1157 //     }
1158 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1159 //                 tng_data->output_file) != 1)
1160 //     {
1161 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1162 //                 __FILE__, __LINE__);
1163 //         return(TNG_CRITICAL);
1164 //     }
1165 //
1166 //     if(!block->block_contents)
1167 //     {
1168 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1169 //                 __FILE__, __LINE__);
1170 //         return(TNG_FAILURE);
1171 //     }
1172 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1173 //                 tng_data->output_file) != 1)
1174 //     {
1175 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1176 //                 __FILE__, __LINE__);
1177 //         return(TNG_CRITICAL);
1178 //     }
1179 //     return(TNG_SUCCESS);
1180 // }
1181 */
1182
1183 /**
1184  * @brief Update the md5 hash of a block already written to the file
1185  * @param tng_data is a trajectory data container.
1186  * @param block is the block, of which to update the md5 hash.
1187  * @param header_start_pos is the file position where the block header starts.
1188  * @param contents_start_pos is the file position where the block contents
1189  * start.
1190  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1191  * error has occured.
1192  */
1193 static tng_function_status tng_md5_hash_update(const tng_trajectory_t tng_data,
1194                                                const tng_gen_block_t block,
1195                                                const int64_t header_start_pos,
1196                                                const int64_t contents_start_pos)
1197 {
1198     if(block->block_contents)
1199     {
1200         free(block->block_contents);
1201     }
1202
1203     block->block_contents = (char *)malloc(block->block_contents_size);
1204     if(!block->block_contents)
1205     {
1206         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
1207         return(TNG_CRITICAL);
1208     }
1209
1210     fseeko(tng_data->output_file, contents_start_pos, SEEK_SET);
1211     if(fread(block->block_contents, block->block_contents_size, 1,
1212             tng_data->output_file) == 0)
1213     {
1214         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1215         return(TNG_CRITICAL);
1216     }
1217
1218     tng_block_md5_hash_generate(block);
1219
1220     fseeko(tng_data->output_file, header_start_pos + 3 * sizeof(int64_t),
1221           SEEK_SET);
1222     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
1223
1224     return(TNG_SUCCESS);
1225 }
1226
1227 /**
1228  * @brief Update the frame set pointers in the file header (general info block),
1229  * already written to disk
1230  * @param tng_data is a trajectory data container.
1231  * @param hash_mode specifies whether to update the block md5 hash when
1232  * updating the pointers.
1233  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1234  * error has occured.
1235  */
1236 static tng_function_status tng_header_pointers_update
1237                 (const tng_trajectory_t tng_data, const char hash_mode)
1238 {
1239     tng_gen_block_t block;
1240     FILE *temp = tng_data->input_file;
1241     uint64_t output_file_pos, pos, contents_start_pos;
1242
1243     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1244     {
1245         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1246                __FILE__, __LINE__);
1247         return(TNG_CRITICAL);
1248     }
1249
1250     tng_data->input_file = tng_data->output_file;
1251
1252     tng_block_init(&block);
1253
1254     output_file_pos = ftello(tng_data->output_file);
1255     fseeko(tng_data->output_file, 0, SEEK_SET);
1256
1257     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1258     {
1259         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
1260                __FILE__, __LINE__);
1261         tng_data->input_file = temp;
1262         tng_block_destroy(&block);
1263         return(TNG_CRITICAL);
1264     }
1265
1266     contents_start_pos = ftello(tng_data->output_file);
1267
1268     fseeko(tng_data->output_file, block->block_contents_size - 5 *
1269            sizeof(int64_t), SEEK_CUR);
1270
1271     tng_data->input_file = temp;
1272
1273     pos = tng_data->first_trajectory_frame_set_output_file_pos;
1274
1275     if(tng_data->input_endianness_swap_func_64)
1276     {
1277         if(tng_data->input_endianness_swap_func_64(tng_data,
1278                                                     &pos)
1279             != TNG_SUCCESS)
1280         {
1281             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1282                     __FILE__, __LINE__);
1283         }
1284     }
1285
1286     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1287     {
1288         tng_block_destroy(&block);
1289         return(TNG_CRITICAL);
1290     }
1291
1292     pos = tng_data->last_trajectory_frame_set_output_file_pos;
1293
1294     if(tng_data->input_endianness_swap_func_64)
1295     {
1296         if(tng_data->input_endianness_swap_func_64(tng_data,
1297                                                     &pos)
1298             != TNG_SUCCESS)
1299         {
1300             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1301                     __FILE__, __LINE__);
1302         }
1303     }
1304
1305     if(fwrite(&pos,
1306         sizeof(int64_t), 1, tng_data->output_file) != 1)
1307     {
1308         tng_block_destroy(&block);
1309         return(TNG_CRITICAL);
1310     }
1311
1312     if(hash_mode == TNG_USE_HASH)
1313     {
1314         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
1315     }
1316
1317     tng_block_destroy(&block);
1318
1319     fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1320
1321     return(TNG_SUCCESS);
1322 }
1323
1324 /**
1325  * @brief Update the frame set pointers in the current frame set block, already
1326  * written to disk. It also updates the pointers of the blocks pointing to
1327  * the current frame set block.
1328  * @param tng_data is a trajectory data container.
1329  * @param hash_mode specifies whether to update the block md5 hash when
1330  * updating the pointers.
1331  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1332  * error has occured.
1333  */
1334 static tng_function_status tng_frame_set_pointers_update
1335                 (const tng_trajectory_t tng_data, const char hash_mode)
1336 {
1337     tng_gen_block_t block;
1338     tng_trajectory_frame_set_t frame_set;
1339     FILE *temp = tng_data->input_file;
1340     uint64_t pos, output_file_pos, contents_start_pos;
1341
1342     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1343     {
1344         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1345                __FILE__, __LINE__);
1346         return(TNG_CRITICAL);
1347     }
1348
1349     tng_block_init(&block);
1350     output_file_pos = ftello(tng_data->output_file);
1351
1352     tng_data->input_file = tng_data->output_file;
1353
1354     frame_set = &tng_data->current_trajectory_frame_set;
1355
1356     pos = tng_data->current_trajectory_frame_set_output_file_pos;
1357
1358     /* Update next frame set */
1359     if(frame_set->next_frame_set_file_pos > 0)
1360     {
1361         fseeko(tng_data->output_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1362
1363         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1364         {
1365             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1366                 __FILE__, __LINE__);
1367             tng_data->input_file = temp;
1368             tng_block_destroy(&block);
1369             return(TNG_CRITICAL);
1370         }
1371
1372         contents_start_pos = ftello(tng_data->output_file);
1373
1374         fseeko(tng_data->output_file, block->block_contents_size - (5 *
1375                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1376
1377         if(tng_data->input_endianness_swap_func_64)
1378         {
1379             if(tng_data->input_endianness_swap_func_64(tng_data,
1380                                                         &pos)
1381                 != TNG_SUCCESS)
1382             {
1383                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1384                         __FILE__, __LINE__);
1385             }
1386         }
1387
1388         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1389         {
1390             tng_data->input_file = temp;
1391             tng_block_destroy(&block);
1392             return(TNG_CRITICAL);
1393         }
1394
1395         if(hash_mode == TNG_USE_HASH)
1396         {
1397             tng_md5_hash_update(tng_data, block, frame_set->next_frame_set_file_pos,
1398                                 contents_start_pos);
1399         }
1400     }
1401     /* Update previous frame set */
1402     if(frame_set->prev_frame_set_file_pos > 0)
1403     {
1404         fseeko(tng_data->output_file, frame_set->prev_frame_set_file_pos,
1405               SEEK_SET);
1406
1407         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1408         {
1409             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1410                 __FILE__, __LINE__);
1411             tng_data->input_file = temp;
1412             tng_block_destroy(&block);
1413             return(TNG_CRITICAL);
1414         }
1415
1416         contents_start_pos = ftello(tng_data->output_file);
1417
1418         fseeko(tng_data->output_file, block->block_contents_size - (6 *
1419                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1420
1421         if(tng_data->input_endianness_swap_func_64)
1422         {
1423             if(tng_data->input_endianness_swap_func_64(tng_data,
1424                                                         &pos)
1425                 != TNG_SUCCESS)
1426             {
1427                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1428                         __FILE__, __LINE__);
1429             }
1430         }
1431
1432         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1433         {
1434             tng_data->input_file = temp;
1435             tng_block_destroy(&block);
1436             return(TNG_CRITICAL);
1437         }
1438
1439         if(hash_mode == TNG_USE_HASH)
1440         {
1441             tng_md5_hash_update(tng_data, block, frame_set->prev_frame_set_file_pos,
1442                                 contents_start_pos);
1443         }
1444     }
1445
1446     /* Update the frame set one medium stride step after */
1447     if(frame_set->medium_stride_next_frame_set_file_pos > 0)
1448     {
1449         fseeko(tng_data->output_file,
1450               frame_set->medium_stride_next_frame_set_file_pos,
1451               SEEK_SET);
1452
1453         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1454         {
1455             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1456                 __FILE__, __LINE__);
1457             tng_data->input_file = temp;
1458             tng_block_destroy(&block);
1459             return(TNG_CRITICAL);
1460         }
1461
1462         contents_start_pos = ftello(tng_data->output_file);
1463
1464         fseeko(tng_data->output_file, block->block_contents_size - (3 *
1465                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1466
1467         if(tng_data->input_endianness_swap_func_64)
1468         {
1469             if(tng_data->input_endianness_swap_func_64(tng_data,
1470                                                         &pos)
1471                 != TNG_SUCCESS)
1472             {
1473                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1474                         __FILE__, __LINE__);
1475             }
1476         }
1477
1478         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1479         {
1480             tng_data->input_file = temp;
1481             tng_block_destroy(&block);
1482             return(TNG_CRITICAL);
1483         }
1484
1485         if(hash_mode == TNG_USE_HASH)
1486         {
1487             tng_md5_hash_update(tng_data, block,
1488                                 frame_set->medium_stride_next_frame_set_file_pos,
1489                                 contents_start_pos);
1490         }
1491     }
1492     /* Update the frame set one medium stride step before */
1493     if(frame_set->medium_stride_prev_frame_set_file_pos > 0)
1494     {
1495         fseeko(tng_data->output_file,
1496                frame_set->medium_stride_prev_frame_set_file_pos,
1497                SEEK_SET);
1498
1499         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1500         {
1501             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1502                 __FILE__, __LINE__);
1503             tng_data->input_file = temp;
1504             tng_block_destroy(&block);
1505             return(TNG_CRITICAL);
1506         }
1507
1508         contents_start_pos = ftello(tng_data->output_file);
1509
1510         fseeko(tng_data->output_file, block->block_contents_size - (4 *
1511                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1512
1513         if(tng_data->input_endianness_swap_func_64)
1514         {
1515             if(tng_data->input_endianness_swap_func_64(tng_data,
1516                                                         &pos)
1517                 != TNG_SUCCESS)
1518             {
1519                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1520                         __FILE__, __LINE__);
1521             }
1522         }
1523
1524         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1525         {
1526             tng_data->input_file = temp;
1527             tng_block_destroy(&block);
1528             return(TNG_CRITICAL);
1529         }
1530
1531         if(hash_mode == TNG_USE_HASH)
1532         {
1533             tng_md5_hash_update(tng_data, block,
1534                                 frame_set->medium_stride_prev_frame_set_file_pos,
1535                                 contents_start_pos);
1536         }
1537     }
1538
1539     /* Update the frame set one long stride step after */
1540     if(frame_set->long_stride_next_frame_set_file_pos > 0)
1541     {
1542         fseeko(tng_data->output_file,
1543                frame_set->long_stride_next_frame_set_file_pos,
1544                SEEK_SET);
1545
1546         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1547         {
1548             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1549                 __FILE__, __LINE__);
1550             tng_data->input_file = temp;
1551             tng_block_destroy(&block);
1552             return(TNG_CRITICAL);
1553         }
1554
1555         contents_start_pos = ftello(tng_data->output_file);
1556
1557         fseeko(tng_data->output_file, block->block_contents_size - (1 *
1558                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1559
1560         if(tng_data->input_endianness_swap_func_64)
1561         {
1562             if(tng_data->input_endianness_swap_func_64(tng_data,
1563                                                         &pos)
1564                 != TNG_SUCCESS)
1565             {
1566                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1567                         __FILE__, __LINE__);
1568             }
1569         }
1570
1571         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1572         {
1573             tng_data->input_file = temp;
1574             tng_block_destroy(&block);
1575             return(TNG_CRITICAL);
1576         }
1577
1578         if(hash_mode == TNG_USE_HASH)
1579         {
1580             tng_md5_hash_update(tng_data, block,
1581                                 frame_set->long_stride_next_frame_set_file_pos,
1582                                 contents_start_pos);
1583         }
1584     }
1585     /* Update the frame set one long stride step before */
1586     if(frame_set->long_stride_prev_frame_set_file_pos > 0)
1587     {
1588         fseeko(tng_data->output_file,
1589                frame_set->long_stride_prev_frame_set_file_pos,
1590                SEEK_SET);
1591
1592         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1593         {
1594             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1595                 __FILE__, __LINE__);
1596             tng_data->input_file = temp;
1597             tng_block_destroy(&block);
1598             return(TNG_CRITICAL);
1599         }
1600
1601         contents_start_pos = ftello(tng_data->output_file);
1602
1603         fseeko(tng_data->output_file, block->block_contents_size - (2 *
1604                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1605
1606         if(tng_data->input_endianness_swap_func_64)
1607         {
1608             if(tng_data->input_endianness_swap_func_64(tng_data,
1609                                                         &pos)
1610                 != TNG_SUCCESS)
1611             {
1612                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1613                         __FILE__, __LINE__);
1614             }
1615         }
1616
1617         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1618         {
1619             tng_data->input_file = temp;
1620             tng_block_destroy(&block);
1621             return(TNG_CRITICAL);
1622         }
1623
1624         if(hash_mode == TNG_USE_HASH)
1625         {
1626             tng_md5_hash_update(tng_data, block,
1627                                 frame_set->long_stride_prev_frame_set_file_pos,
1628                                 contents_start_pos);
1629         }
1630     }
1631
1632     fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1633
1634     tng_data->input_file = temp;
1635
1636     tng_block_destroy(&block);
1637
1638     return(TNG_SUCCESS);
1639 }
1640
1641 static tng_function_status tng_reread_frame_set_at_file_pos
1642                 (const tng_trajectory_t tng_data,
1643                  const int64_t pos)
1644 {
1645     tng_gen_block_t block;
1646     tng_function_status stat;
1647
1648     tng_block_init(&block);
1649
1650     fseeko(tng_data->input_file, pos, SEEK_SET);
1651     if(pos > 0)
1652     {
1653         stat = tng_block_header_read(tng_data, block);
1654         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1655         {
1656             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos,
1657                     __FILE__, __LINE__);
1658             tng_block_destroy(&block);
1659             return(TNG_FAILURE);
1660         }
1661
1662         if(tng_block_read_next(tng_data, block,
1663                                TNG_SKIP_HASH) != TNG_SUCCESS)
1664         {
1665             tng_block_destroy(&block);
1666             return(TNG_CRITICAL);
1667         }
1668     }
1669
1670     tng_block_destroy(&block);
1671
1672     return(TNG_SUCCESS);
1673 }
1674
1675 static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
1676                 (const tng_trajectory_t tng_data,
1677                  int64_t *pos)
1678 {
1679     int64_t orig_pos, curr_frame_set_pos;
1680     tng_gen_block_t block;
1681     tng_function_status stat;
1682     tng_trajectory_frame_set_t frame_set =
1683     &tng_data->current_trajectory_frame_set;
1684
1685     orig_pos = ftello(tng_data->input_file);
1686     curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos;
1687
1688     *pos = tng_data->first_trajectory_frame_set_input_file_pos;
1689
1690     if(*pos <= 0)
1691     {
1692         return(TNG_SUCCESS);
1693     }
1694
1695     fseeko(tng_data->input_file, *pos, SEEK_SET);
1696
1697     tng_block_init(&block);
1698     /* Read block headers first to see that a frame set block is found. */
1699     stat = tng_block_header_read(tng_data, block);
1700     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1701     {
1702         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos,
1703                 __FILE__, __LINE__);
1704         tng_block_destroy(&block);
1705         return(TNG_FAILURE);
1706     }
1707
1708     if(tng_block_read_next(tng_data, block,
1709                            TNG_SKIP_HASH) != TNG_SUCCESS)
1710     {
1711         tng_block_destroy(&block);
1712         return(TNG_CRITICAL);
1713     }
1714
1715     /* Read all frame set blocks (not the blocks between them) */
1716     while(frame_set->next_frame_set_file_pos > 0)
1717     {
1718         fseeko(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1719         stat = tng_block_header_read(tng_data, block);
1720         if(stat == TNG_CRITICAL)
1721         {
1722             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos,
1723                     __FILE__, __LINE__);
1724             tng_block_destroy(&block);
1725             return(TNG_CRITICAL);
1726         }
1727         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1728         {
1729             return(TNG_FAILURE);
1730         }
1731
1732         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
1733         if(stat != TNG_SUCCESS)
1734         {
1735             tng_block_destroy(&block);
1736             return(stat);
1737         }
1738         /* Update *pos if this is the earliest frame set so far (after orig_pos) */
1739         if(tng_data->current_trajectory_frame_set_input_file_pos < *pos &&
1740            tng_data->current_trajectory_frame_set_input_file_pos > orig_pos)
1741         {
1742             *pos = tng_data->current_trajectory_frame_set_input_file_pos;
1743         }
1744     }
1745
1746     /* Re-read the frame set that used to be the current one */
1747     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1748
1749     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1750
1751     tng_block_destroy(&block);
1752
1753     return(TNG_SUCCESS);
1754 }
1755
1756 /**
1757  * @brief Migrate a whole frame set from one position in the file to another.
1758  * @param tng_data is a trajectory data container.
1759  * @param block_start_pos is the starting position in the file of the frame set.
1760  * @param block_len is the length of the whole frame set (including all data blocks etc).
1761  * @param new_pos is the new position in the file of the frame set.
1762  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
1763  */
1764 static tng_function_status tng_frame_set_complete_migrate
1765                 (const tng_trajectory_t tng_data,
1766                  const int64_t block_start_pos,
1767                  const int64_t block_len,
1768                  const int64_t new_pos,
1769                  const char hash_mode)
1770 {
1771     tng_bool updated = TNG_FALSE;
1772
1773     char *contents;
1774
1775     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1776     {
1777         return(TNG_CRITICAL);
1778     }
1779
1780     fseeko(tng_data->input_file, block_start_pos, SEEK_SET);
1781
1782     contents = (char *)malloc(block_len);
1783     if(!contents)
1784     {
1785         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
1786         return(TNG_CRITICAL);
1787     }
1788
1789     if(fread(contents, block_len, 1, tng_data->input_file) == 0)
1790     {
1791         fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n",
1792                __FILE__, __LINE__);
1793         free(contents);
1794         return(TNG_CRITICAL);
1795     }
1796     fseeko(tng_data->output_file, new_pos, SEEK_SET);
1797
1798     if(fwrite(contents, block_len, 1, tng_data->output_file) != 1)
1799     {
1800         fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n",
1801                 __FILE__, __LINE__);
1802         free(contents);
1803         return(TNG_CRITICAL);
1804     }
1805
1806     tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
1807     if(tng_data->input_file == tng_data->output_file)
1808     {
1809         tng_data->current_trajectory_frame_set_input_file_pos = new_pos;
1810     }
1811
1812     tng_frame_set_pointers_update(tng_data, hash_mode);
1813
1814     /* Update the general info block if needed */
1815     if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos)
1816     {
1817         tng_data->first_trajectory_frame_set_output_file_pos = new_pos;
1818         updated = TNG_TRUE;
1819     }
1820     if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos)
1821     {
1822         tng_data->last_trajectory_frame_set_output_file_pos = new_pos;
1823         updated = TNG_TRUE;
1824     }
1825     if(updated)
1826     {
1827         tng_header_pointers_update(tng_data, hash_mode);
1828     }
1829
1830     /* Fill the block with NULL to avoid confusion. */
1831     memset(contents, '\0', block_len);
1832     fseeko(tng_data->output_file, block_start_pos, SEEK_SET);
1833
1834     /* FIXME: casting block_len to size_t is dangerous */
1835     fwrite(contents, 1, block_len, tng_data->output_file);
1836
1837     free(contents);
1838
1839     return(TNG_SUCCESS);
1840 }
1841
1842 static tng_function_status tng_length_of_current_frame_set_contents_get
1843                 (const tng_trajectory_t tng_data,
1844                  int64_t *len)
1845 {
1846     int64_t orig_pos, pos, curr_frame_set_pos;
1847     tng_gen_block_t block;
1848     tng_function_status stat;
1849
1850     orig_pos = ftello(tng_data->input_file);
1851     curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos;
1852
1853     *len = 0;
1854
1855     fseeko(tng_data->input_file, curr_frame_set_pos, SEEK_SET);
1856
1857     tng_block_init(&block);
1858     /* Read block headers first to see that a frame set block is found. */
1859     stat = tng_block_header_read(tng_data, block);
1860     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1861     {
1862         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
1863                 curr_frame_set_pos, __FILE__, __LINE__);
1864         tng_block_destroy(&block);
1865         return(TNG_FAILURE);
1866     }
1867
1868     /* Read the headers of all blocks in the frame set (not the actual contents of them) */
1869     while(stat == TNG_SUCCESS)
1870     {
1871         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
1872         *len += block->header_contents_size + block->block_contents_size;
1873         pos += block->header_contents_size + block->block_contents_size;
1874         if(pos >= tng_data->input_file_len)
1875         {
1876             break;
1877         }
1878         stat = tng_block_header_read(tng_data, block);
1879         if(block->id == TNG_TRAJECTORY_FRAME_SET)
1880         {
1881             break;
1882         }
1883     }
1884
1885     /* Re-read the frame set that used to be the current one */
1886     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1887
1888     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1889
1890     tng_block_destroy(&block);
1891
1892     return(TNG_SUCCESS);
1893 }
1894
1895 /**
1896  * @brief Migrate blocks in the file to make room for new data in a block. This
1897  * is required e.g. when adding data to a block or extending strings in a
1898  * block.
1899  * @param tng_data is a trajectory data container.
1900  * @param start_pos is the position from which to start moving data, usually
1901  * the byte after the end of the block to which data was added.
1902  * @param offset is the number of bytes that were inserted.
1903  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
1904  * @details Trajectory blocks (frame sets and their related blocks) are moved
1905  * to the end of the file (if needed) in order to make room for non-trajectory
1906  * data.
1907  */
1908 static tng_function_status tng_migrate_data_in_file
1909                 (const tng_trajectory_t tng_data,
1910                  const int64_t start_pos,
1911                  const int64_t offset,
1912                  const char hash_mode)
1913 {
1914     int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length;
1915     tng_gen_block_t block;
1916     tng_function_status stat;
1917
1918     if(offset <= 0)
1919     {
1920         return(TNG_SUCCESS);
1921     }
1922
1923     stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos);
1924     if(stat != TNG_SUCCESS)
1925     {
1926         return(stat);
1927     }
1928
1929     tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos;
1930
1931     empty_space = traj_start_pos - (start_pos - 1);
1932
1933     if(empty_space >= offset)
1934     {
1935         return(TNG_SUCCESS);
1936     }
1937
1938     orig_file_pos = ftello(tng_data->input_file);
1939     tng_block_init(&block);
1940
1941     while(empty_space < offset)
1942     {
1943         fseeko(tng_data->input_file, traj_start_pos, SEEK_SET);
1944         stat = tng_block_header_read(tng_data, block);
1945         if(stat == TNG_CRITICAL)
1946         {
1947             fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
1948                     __FILE__, __LINE__);
1949             tng_block_destroy(&block);
1950             return(TNG_CRITICAL);
1951         }
1952         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1953         {
1954             tng_block_destroy(&block);
1955             return(TNG_FAILURE);
1956         }
1957         stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length);
1958         if(stat != TNG_SUCCESS)
1959         {
1960             tng_block_destroy(&block);
1961             return(stat);
1962         }
1963         stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos,
1964                                               frame_set_length, tng_data->input_file_len,
1965                                               hash_mode);
1966         if(stat != TNG_SUCCESS)
1967         {
1968             tng_block_destroy(&block);
1969             return(stat);
1970         }
1971
1972         empty_space += frame_set_length;
1973     }
1974     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
1975     tng_block_destroy(&block);
1976
1977     return(TNG_SUCCESS);
1978 }
1979
1980 static tng_function_status tng_block_header_len_calculate
1981                 (const tng_trajectory_t tng_data,
1982                  const tng_gen_block_t block,
1983                  int64_t *len)
1984 {
1985     int name_len;
1986     (void)tng_data;
1987
1988     /* If the string is unallocated allocate memory for just string
1989      * termination */
1990     if(!block->name)
1991     {
1992         block->name = (char *)malloc(1);
1993         if(!block->name)
1994         {
1995             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
1996                    __FILE__, __LINE__);
1997             return(TNG_CRITICAL);
1998         }
1999         block->name[0] = 0;
2000     }
2001
2002     name_len = tng_min_size(strlen(block->name) + 1, TNG_MAX_STR_LEN);
2003
2004     /* Calculate the size of the header to write */
2005     *len = sizeof(block->header_contents_size) +
2006                   sizeof(block->block_contents_size) +
2007                   sizeof(block->id) +
2008                   sizeof(block->block_version) +
2009                   TNG_MD5_HASH_LEN +
2010                   name_len;
2011
2012     return (TNG_SUCCESS);
2013 }
2014
2015 /**
2016  * @brief Write the header of a data block, regardless of its type
2017  * @param tng_data is a trajectory data container.
2018  * @param block is a general block container.
2019  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2020  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2021  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2022  * error has occured.
2023  */
2024 static tng_function_status tng_block_header_write
2025                 (const tng_trajectory_t tng_data,
2026                  const tng_gen_block_t block)
2027 {
2028     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
2029
2030     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2031     {
2032         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
2033                __FILE__, __LINE__);
2034         return(TNG_CRITICAL);
2035     }
2036
2037     if(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) !=
2038         TNG_SUCCESS)
2039     {
2040         fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n",
2041                 __FILE__, __LINE__);
2042         return(TNG_CRITICAL);
2043     }
2044
2045     if(tng_file_output_numerical(tng_data, &block->header_contents_size,
2046                                  sizeof(block->header_contents_size),
2047                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2048     {
2049         return(TNG_CRITICAL);
2050     }
2051
2052     if(tng_file_output_numerical(tng_data, &block->block_contents_size,
2053                                  sizeof(block->block_contents_size),
2054                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2055     {
2056         return(TNG_CRITICAL);
2057     }
2058
2059     if(tng_file_output_numerical(tng_data, &block->id,
2060                                  sizeof(block->id),
2061                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2062     {
2063         return(TNG_CRITICAL);
2064     }
2065
2066     if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
2067     {
2068         fprintf(stderr, "TNG library: Could not write header data. %s: %d\n", __FILE__, __LINE__);
2069         return(TNG_CRITICAL);
2070     }
2071
2072     if(tng_fwritestr(tng_data, block->name, TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2073     {
2074         return(TNG_CRITICAL);
2075     }
2076
2077     if(tng_file_output_numerical(tng_data, &block->block_version,
2078                                  sizeof(block->block_version),
2079                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2080     {
2081         return(TNG_CRITICAL);
2082     }
2083
2084     return(TNG_SUCCESS);
2085 }
2086
2087 static tng_function_status tng_general_info_block_len_calculate
2088                 (const tng_trajectory_t tng_data,
2089                  int64_t *len)
2090 {
2091     size_t first_program_name_len, first_user_name_len;
2092     size_t first_computer_name_len, first_pgp_signature_len;
2093     size_t last_program_name_len, last_user_name_len;
2094     size_t last_computer_name_len, last_pgp_signature_len;
2095     size_t forcefield_name_len;
2096
2097     /* If the strings are unallocated allocate memory for just string
2098      * termination */
2099     if(!tng_data->first_program_name)
2100     {
2101         tng_data->first_program_name = (char *)malloc(1);
2102         if(!tng_data->first_program_name)
2103         {
2104             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2105                    __FILE__, __LINE__);
2106             return(TNG_CRITICAL);
2107         }
2108         tng_data->first_program_name[0] = 0;
2109     }
2110     if(!tng_data->last_program_name)
2111     {
2112         tng_data->last_program_name = (char *)malloc(1);
2113         if(!tng_data->last_program_name)
2114         {
2115             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2116                    __FILE__, __LINE__);
2117             return(TNG_CRITICAL);
2118         }
2119         tng_data->last_program_name[0] = 0;
2120     }
2121     if(!tng_data->first_user_name)
2122     {
2123         tng_data->first_user_name = (char *)malloc(1);
2124         if(!tng_data->first_user_name)
2125         {
2126             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2127                    __FILE__, __LINE__);
2128             return(TNG_CRITICAL);
2129         }
2130         tng_data->first_user_name[0] = 0;
2131     }
2132     if(!tng_data->last_user_name)
2133     {
2134         tng_data->last_user_name = (char *)malloc(1);
2135         if(!tng_data->last_user_name)
2136         {
2137             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2138                    __FILE__, __LINE__);
2139             return(TNG_CRITICAL);
2140         }
2141         tng_data->last_user_name[0] = 0;
2142     }
2143     if(!tng_data->first_computer_name)
2144     {
2145         tng_data->first_computer_name = (char *)malloc(1);
2146         if(!tng_data->first_computer_name)
2147         {
2148             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2149                    __FILE__, __LINE__);
2150             return(TNG_CRITICAL);
2151         }
2152         tng_data->first_computer_name[0] = 0;
2153     }
2154     if(!tng_data->last_computer_name)
2155     {
2156         tng_data->last_computer_name = (char *)malloc(1);
2157         if(!tng_data->last_computer_name)
2158         {
2159             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2160                    __FILE__, __LINE__);
2161             return(TNG_CRITICAL);
2162         }
2163         tng_data->last_computer_name[0] = 0;
2164     }
2165     if(!tng_data->first_pgp_signature)
2166     {
2167         tng_data->first_pgp_signature = (char *)malloc(1);
2168         if(!tng_data->first_pgp_signature)
2169         {
2170             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2171                    __FILE__, __LINE__);
2172             return(TNG_CRITICAL);
2173         }
2174         tng_data->first_pgp_signature[0] = 0;
2175     }
2176     if(!tng_data->last_pgp_signature)
2177     {
2178         tng_data->last_pgp_signature = (char *)malloc(1);
2179         if(!tng_data->last_pgp_signature)
2180         {
2181             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2182                    __FILE__, __LINE__);
2183             return(TNG_CRITICAL);
2184         }
2185         tng_data->last_pgp_signature[0] = 0;
2186     }
2187     if(!tng_data->forcefield_name)
2188     {
2189         tng_data->forcefield_name = (char *)malloc(1);
2190         if(!tng_data->forcefield_name)
2191         {
2192             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2193                    __FILE__, __LINE__);
2194             return(TNG_CRITICAL);
2195         }
2196         tng_data->forcefield_name[0] = 0;
2197     }
2198
2199     first_program_name_len = tng_min_size(strlen(tng_data->first_program_name) + 1,
2200                            TNG_MAX_STR_LEN);
2201     last_program_name_len = tng_min_size(strlen(tng_data->last_program_name) + 1,
2202                            TNG_MAX_STR_LEN);
2203     first_user_name_len = tng_min_size(strlen(tng_data->first_user_name) + 1,
2204                         TNG_MAX_STR_LEN);
2205     last_user_name_len = tng_min_size(strlen(tng_data->last_user_name) + 1,
2206                         TNG_MAX_STR_LEN);
2207     first_computer_name_len = tng_min_size(strlen(tng_data->first_computer_name) + 1,
2208                             TNG_MAX_STR_LEN);
2209     last_computer_name_len = tng_min_size(strlen(tng_data->last_computer_name) + 1,
2210                             TNG_MAX_STR_LEN);
2211     first_pgp_signature_len = tng_min_size(strlen(tng_data->first_pgp_signature) + 1,
2212                             TNG_MAX_STR_LEN);
2213     last_pgp_signature_len = tng_min_size(strlen(tng_data->last_pgp_signature) + 1,
2214                             TNG_MAX_STR_LEN);
2215     forcefield_name_len = tng_min_size(strlen(tng_data->forcefield_name) + 1,
2216                               TNG_MAX_STR_LEN);
2217
2218     *len = sizeof(tng_data->time) +
2219                   sizeof(tng_data->var_num_atoms_flag) +
2220                   sizeof(tng_data->frame_set_n_frames) +
2221                   sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
2222                   sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
2223                   sizeof(tng_data->medium_stride_length) +
2224                   sizeof(tng_data->long_stride_length) +
2225                   sizeof(tng_data->distance_unit_exponential) +
2226                   first_program_name_len +
2227                   last_program_name_len +
2228                   first_user_name_len +
2229                   last_user_name_len +
2230                   first_computer_name_len +
2231                   last_computer_name_len +
2232                   first_pgp_signature_len +
2233                   last_pgp_signature_len +
2234                   forcefield_name_len;
2235
2236     return(TNG_SUCCESS);
2237 }
2238
2239 /**
2240  * @brief Read a general info block. This is the first block of a TNG file.
2241  * Populate the fields in tng_data.
2242  * @param tng_data is a trajectory data container.
2243  * @param block is a general block container.
2244  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2245  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2246  * compared to the md5 hash of the read contents to ensure valid data.
2247  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2248  * error has occured.
2249  */
2250 static tng_function_status tng_general_info_block_read
2251                 (const tng_trajectory_t tng_data,
2252                  const tng_gen_block_t block,
2253                  const char hash_mode)
2254 {
2255     int64_t start_pos;
2256     char hash[TNG_MD5_HASH_LEN];
2257     md5_state_t md5_state;
2258
2259     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
2260
2261     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2262     {
2263         return(TNG_CRITICAL);
2264     }
2265
2266     start_pos = ftello(tng_data->input_file);
2267
2268     if(hash_mode == TNG_USE_HASH)
2269     {
2270         md5_init(&md5_state);
2271     }
2272
2273     tng_freadstr(tng_data, &tng_data->first_program_name, hash_mode, &md5_state, __LINE__);
2274
2275     tng_freadstr(tng_data, &tng_data->last_program_name, hash_mode, &md5_state, __LINE__);
2276
2277     tng_freadstr(tng_data, &tng_data->first_user_name, hash_mode, &md5_state, __LINE__);
2278
2279     tng_freadstr(tng_data, &tng_data->last_user_name, hash_mode, &md5_state, __LINE__);
2280
2281     tng_freadstr(tng_data, &tng_data->first_computer_name, hash_mode, &md5_state, __LINE__);
2282
2283     tng_freadstr(tng_data, &tng_data->last_computer_name, hash_mode, &md5_state, __LINE__);
2284
2285     tng_freadstr(tng_data, &tng_data->first_pgp_signature, hash_mode, &md5_state, __LINE__);
2286
2287     tng_freadstr(tng_data, &tng_data->last_pgp_signature, hash_mode, &md5_state, __LINE__);
2288
2289     tng_freadstr(tng_data, &tng_data->forcefield_name, hash_mode, &md5_state, __LINE__);
2290
2291     if(tng_file_input_numerical(tng_data, &tng_data->time, sizeof(tng_data->time),
2292                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2293     {
2294         return(TNG_CRITICAL);
2295     }
2296
2297
2298     if(tng_file_input_numerical(tng_data, &tng_data->var_num_atoms_flag,
2299                                 sizeof(tng_data->var_num_atoms_flag),
2300                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2301     {
2302         return(TNG_CRITICAL);
2303     }
2304
2305     if(tng_file_input_numerical(tng_data, &tng_data->frame_set_n_frames,
2306                                 sizeof(tng_data->frame_set_n_frames),
2307                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2308     {
2309         return(TNG_CRITICAL);
2310     }
2311
2312     if(tng_file_input_numerical(tng_data,
2313                                 &tng_data->first_trajectory_frame_set_input_file_pos,
2314                                 sizeof(tng_data->first_trajectory_frame_set_input_file_pos),
2315                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2316     {
2317         return(TNG_CRITICAL);
2318     }
2319
2320     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
2321     tng_data->first_trajectory_frame_set_input_file_pos;
2322
2323     if(tng_file_input_numerical(tng_data,
2324                                 &tng_data->last_trajectory_frame_set_input_file_pos,
2325                                 sizeof(tng_data->last_trajectory_frame_set_input_file_pos),
2326                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2327     {
2328         return(TNG_CRITICAL);
2329     }
2330
2331     if(tng_file_input_numerical(tng_data,
2332                                 &tng_data->medium_stride_length,
2333                                 sizeof(tng_data->medium_stride_length),
2334                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2335     {
2336         return(TNG_CRITICAL);
2337     }
2338
2339     if(tng_file_input_numerical(tng_data,
2340                                 &tng_data->long_stride_length,
2341                                 sizeof(tng_data->long_stride_length),
2342                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2343     {
2344         return(TNG_CRITICAL);
2345     }
2346
2347     if(block->block_version >= 3)
2348     {
2349         if(tng_file_input_numerical(tng_data,
2350                                     &tng_data->distance_unit_exponential,
2351                                     sizeof(tng_data->distance_unit_exponential),
2352                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2353         {
2354             return(TNG_CRITICAL);
2355         }
2356     }
2357
2358     if(hash_mode == TNG_USE_HASH)
2359     {
2360         /* If there is data left in the block that the current version of the library
2361          * cannot interpret still read that to generate the MD5 hash. */
2362         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
2363
2364         md5_finish(&md5_state, (md5_byte_t *)hash);
2365         if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
2366         {
2367             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
2368             {
2369                 fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
2370                         "%s: %d\n", __FILE__, __LINE__);
2371             }
2372         }
2373     }
2374     else
2375     {
2376         /* Seek to the end of the block */
2377         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
2378     }
2379
2380     return(TNG_SUCCESS);
2381 }
2382
2383 /**
2384  * @brief Write a general info block. This is the first block of a TNG file.
2385  * @param tng_data is a trajectory data container.
2386  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2387  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2388  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2389  * error has occured.
2390  */
2391 static tng_function_status tng_general_info_block_write
2392                 (const tng_trajectory_t tng_data,
2393                  const char hash_mode)
2394 {
2395     int64_t header_file_pos, curr_file_pos;
2396     size_t name_len;
2397     tng_gen_block_t block;
2398     md5_state_t md5_state;
2399
2400     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2401     {
2402         return(TNG_CRITICAL);
2403     }
2404
2405     fseeko(tng_data->output_file, 0, SEEK_SET);
2406
2407     tng_block_init(&block);
2408
2409     name_len = strlen("GENERAL INFO");
2410
2411     block->name = (char *)malloc(name_len + 1);
2412     if(!block->name)
2413     {
2414         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
2415         tng_block_destroy(&block);
2416         return(TNG_CRITICAL);
2417     }
2418
2419     strcpy(block->name, "GENERAL INFO");
2420     block->id = TNG_GENERAL_INFO;
2421
2422     if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) !=
2423         TNG_SUCCESS)
2424     {
2425         fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n",
2426                 __FILE__, __LINE__);
2427         tng_block_destroy(&block);
2428         return(TNG_CRITICAL);
2429     }
2430
2431     header_file_pos = 0;
2432
2433     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
2434     {
2435         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2436                tng_data->output_file_path, __FILE__, __LINE__);
2437         tng_block_destroy(&block);
2438         return(TNG_CRITICAL);
2439     }
2440
2441     if(hash_mode == TNG_USE_HASH)
2442     {
2443         md5_init(&md5_state);
2444     }
2445
2446     if(tng_fwritestr(tng_data, tng_data->first_program_name,
2447                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2448     {
2449         return(TNG_CRITICAL);
2450     }
2451
2452     if(tng_fwritestr(tng_data, tng_data->last_program_name,
2453                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2454     {
2455         return(TNG_CRITICAL);
2456     }
2457
2458     if(tng_fwritestr(tng_data, tng_data->first_user_name,
2459                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2460     {
2461         return(TNG_CRITICAL);
2462     }
2463
2464     if(tng_fwritestr(tng_data, tng_data->last_user_name,
2465                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2466     {
2467         return(TNG_CRITICAL);
2468     }
2469
2470     if(tng_fwritestr(tng_data, tng_data->first_computer_name,
2471                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2472     {
2473         return(TNG_CRITICAL);
2474     }
2475
2476     if(tng_fwritestr(tng_data, tng_data->last_computer_name,
2477                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2478     {
2479         return(TNG_CRITICAL);
2480     }
2481
2482     if(tng_fwritestr(tng_data, tng_data->first_pgp_signature,
2483                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2484     {
2485         return(TNG_CRITICAL);
2486     }
2487
2488     if(tng_fwritestr(tng_data, tng_data->last_pgp_signature,
2489                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2490     {
2491         return(TNG_CRITICAL);
2492     }
2493
2494     if(tng_fwritestr(tng_data, tng_data->forcefield_name,
2495                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2496     {
2497         return(TNG_CRITICAL);
2498     }
2499
2500
2501     if(tng_file_output_numerical(tng_data, &tng_data->time, sizeof(tng_data->time),
2502                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2503     {
2504         return(TNG_CRITICAL);
2505     }
2506
2507     if(tng_file_output_numerical(tng_data, &tng_data->var_num_atoms_flag,
2508                                  sizeof(tng_data->var_num_atoms_flag),
2509                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2510     {
2511         return(TNG_CRITICAL);
2512     }
2513
2514     if(tng_file_output_numerical(tng_data, &tng_data->frame_set_n_frames,
2515                                  sizeof(tng_data->frame_set_n_frames),
2516                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2517     {
2518         return(TNG_CRITICAL);
2519     }
2520
2521     if(tng_file_output_numerical(tng_data, &tng_data->first_trajectory_frame_set_output_file_pos,
2522                                  sizeof(tng_data->first_trajectory_frame_set_output_file_pos),
2523                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2524     {
2525         return(TNG_CRITICAL);
2526     }
2527
2528     if(tng_file_output_numerical(tng_data, &tng_data->last_trajectory_frame_set_output_file_pos,
2529                                  sizeof(tng_data->last_trajectory_frame_set_output_file_pos),
2530                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2531     {
2532         return(TNG_CRITICAL);
2533     }
2534
2535     if(tng_file_output_numerical(tng_data, &tng_data->medium_stride_length,
2536                                  sizeof(tng_data->medium_stride_length),
2537                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2538     {
2539         return(TNG_CRITICAL);
2540     }
2541
2542     if(tng_file_output_numerical(tng_data, &tng_data->long_stride_length,
2543                                  sizeof(tng_data->long_stride_length),
2544                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2545     {
2546         return(TNG_CRITICAL);
2547     }
2548
2549     if(tng_file_output_numerical(tng_data, &tng_data->distance_unit_exponential,
2550                                  sizeof(tng_data->distance_unit_exponential),
2551                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2552     {
2553         return(TNG_CRITICAL);
2554     }
2555     if(hash_mode == TNG_USE_HASH)
2556     {
2557         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
2558         curr_file_pos = ftello(tng_data->output_file);
2559         fseeko(tng_data->output_file, header_file_pos +
2560                3 * sizeof(int64_t), SEEK_SET);
2561         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
2562         {
2563             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
2564                     __LINE__);
2565             return(TNG_CRITICAL);
2566         }
2567         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
2568     }
2569
2570     tng_block_destroy(&block);
2571
2572     return(TNG_SUCCESS);
2573 }
2574
2575 /**
2576  * @brief Read the chain data of a molecules block.
2577  * @param tng_data is a trajectory data container.
2578  * @param chain is the chain data container.
2579  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2580  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2581  * if hash_mode == TNG_USE_HASH.
2582  * @return TNG_SUCCESS(0) is successful.
2583  */
2584 static tng_function_status tng_chain_data_read(const tng_trajectory_t tng_data,
2585                                                const tng_chain_t chain,
2586                                                const char hash_mode,
2587                                                md5_state_t *md5_state)
2588 {
2589     if(tng_file_input_numerical(tng_data, &chain->id,
2590                                 sizeof(chain->id),
2591                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2592     {
2593         return(TNG_CRITICAL);
2594     }
2595
2596     tng_freadstr(tng_data, &chain->name, hash_mode, md5_state, __LINE__);
2597
2598     if(tng_file_input_numerical(tng_data, &chain->n_residues,
2599                                 sizeof(chain->n_residues),
2600                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2601     {
2602         return(TNG_CRITICAL);
2603     }
2604
2605     return(TNG_SUCCESS);
2606 }
2607
2608 /**
2609  * @brief Write the chain data of a molecules block.
2610  * @param tng_data is a trajectory data container.
2611  * @param chain is the chain data container.
2612  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2613  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2614  * if hash_mode == TNG_USE_HASH.
2615  * @return TNG_SUCCESS(0) is successful.
2616  */
2617 static tng_function_status tng_chain_data_write(const tng_trajectory_t tng_data,
2618                                                 const tng_chain_t chain,
2619                                                 const char hash_mode,
2620                                                 md5_state_t *md5_state)
2621 {
2622     if(tng_file_output_numerical(tng_data, &chain->id,
2623                                  sizeof(chain->id),
2624                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2625     {
2626         return(TNG_CRITICAL);
2627     }
2628
2629     if(tng_fwritestr(tng_data, chain->name, hash_mode,
2630                      md5_state, __LINE__) == TNG_CRITICAL)
2631     {
2632         return(TNG_CRITICAL);
2633     }
2634
2635     if(tng_file_output_numerical(tng_data, &chain->n_residues,
2636                                  sizeof(chain->n_residues),
2637                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2638     {
2639         return(TNG_CRITICAL);
2640     }
2641
2642     return(TNG_SUCCESS);
2643 }
2644
2645 /**
2646  * @brief Read the residue data of a molecules block.
2647  * @param tng_data is a trajectory data container.
2648  * @param residue is the residue data container.
2649  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2650  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2651  * if hash_mode == TNG_USE_HASH.
2652  * @return TNG_SUCCESS(0) is successful.
2653  */
2654 static tng_function_status tng_residue_data_read(const tng_trajectory_t tng_data,
2655                                                  const tng_residue_t residue,
2656                                                  const char hash_mode,
2657                                                  md5_state_t *md5_state)
2658 {
2659     if(tng_file_input_numerical(tng_data, &residue->id,
2660                                 sizeof(residue->id),
2661                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2662     {
2663         return(TNG_CRITICAL);
2664     }
2665
2666     tng_freadstr(tng_data, &residue->name, hash_mode, md5_state, __LINE__);
2667
2668     if(tng_file_input_numerical(tng_data, &residue->n_atoms,
2669                                 sizeof(residue->n_atoms),
2670                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2671     {
2672         return(TNG_CRITICAL);
2673     }
2674
2675     return(TNG_SUCCESS);
2676 }
2677
2678 /**
2679  * @brief Write the residue data of a molecules block.
2680  * @param tng_data is a trajectory data container.
2681  * @param residue is the residue data container.
2682  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2683  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2684  * if hash_mode == TNG_USE_HASH.
2685  * @return TNG_SUCCESS(0) is successful.
2686  */
2687 static tng_function_status tng_residue_data_write(const tng_trajectory_t tng_data,
2688                                                   const tng_residue_t residue,
2689                                                   const char hash_mode,
2690                                                   md5_state_t *md5_state)
2691 {
2692     if(tng_file_output_numerical(tng_data, &residue->id,
2693                                  sizeof(residue->id),
2694                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2695     {
2696         return(TNG_CRITICAL);
2697     }
2698
2699     if(tng_fwritestr(tng_data, residue->name, hash_mode,
2700                      md5_state, __LINE__) == TNG_CRITICAL)
2701     {
2702         return(TNG_CRITICAL);
2703     }
2704
2705     if(tng_file_output_numerical(tng_data, &residue->n_atoms,
2706                                  sizeof(residue->n_atoms),
2707                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2708     {
2709         return(TNG_CRITICAL);
2710     }
2711
2712     return(TNG_SUCCESS);
2713 }
2714
2715 /**
2716  * @brief Read the atom data of a molecules block.
2717  * @param tng_data is a trajectory data container.
2718  * @param atom is the atom data container.
2719  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2720  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2721  * if hash_mode == TNG_USE_HASH.
2722  * @return TNG_SUCCESS(0) is successful.
2723  */
2724 static tng_function_status tng_atom_data_read(const tng_trajectory_t tng_data,
2725                                               const tng_atom_t atom,
2726                                               const char hash_mode,
2727                                               md5_state_t *md5_state)
2728 {
2729     if(tng_file_input_numerical(tng_data, &atom->id,
2730                                 sizeof(atom->id),
2731                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2732     {
2733         return(TNG_CRITICAL);
2734     }
2735
2736     tng_freadstr(tng_data, &atom->name, hash_mode, md5_state, __LINE__);
2737
2738     tng_freadstr(tng_data, &atom->atom_type, hash_mode, md5_state, __LINE__);
2739
2740     return(TNG_SUCCESS);
2741 }
2742
2743 /**
2744  * @brief Write the atom data of a molecules block.
2745  * @param tng_data is a trajectory data container.
2746  * @param atom is the atom data container.
2747  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2748  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2749  * if hash_mode == TNG_USE_HASH.
2750  * @return TNG_SUCCESS(0) is successful.
2751  */
2752 static tng_function_status tng_atom_data_write(const tng_trajectory_t tng_data,
2753                                                const tng_atom_t atom,
2754                                                const char hash_mode,
2755                                                md5_state_t *md5_state)
2756 {
2757     if(tng_file_output_numerical(tng_data, &atom->id,
2758                                  sizeof(atom->id),
2759                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2760     {
2761         return(TNG_CRITICAL);
2762     }
2763
2764     if(tng_fwritestr(tng_data, atom->name, hash_mode,
2765                      md5_state, __LINE__) == TNG_CRITICAL)
2766     {
2767         return(TNG_CRITICAL);
2768     }
2769
2770     if(tng_fwritestr(tng_data, atom->atom_type, hash_mode,
2771                      md5_state, __LINE__) == TNG_CRITICAL)
2772     {
2773         return(TNG_CRITICAL);
2774     }
2775
2776     return(TNG_SUCCESS);
2777 }
2778
2779 static tng_function_status tng_molecules_block_len_calculate
2780                 (const tng_trajectory_t tng_data,
2781                  int64_t *len)
2782 {
2783     int64_t i, j;
2784     tng_molecule_t molecule;
2785     tng_chain_t chain;
2786     tng_residue_t residue;
2787     tng_atom_t atom;
2788     tng_bond_t bond;
2789
2790     *len = 0;
2791
2792     for(i = 0; i < tng_data->n_molecules; i++)
2793     {
2794         molecule = &tng_data->molecules[i];
2795         if(!molecule->name)
2796         {
2797             molecule->name = (char *)malloc(1);
2798             if(!molecule->name)
2799             {
2800                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2801                        __FILE__, __LINE__);
2802                 return(TNG_CRITICAL);
2803             }
2804             molecule->name[0] = 0;
2805         }
2806         *len += tng_min_size(strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
2807
2808         chain = molecule->chains;
2809         for(j = 0; j < molecule->n_chains; j++)
2810         {
2811             *len += sizeof(chain->id);
2812
2813             if(!chain->name)
2814             {
2815                 chain->name = (char *)malloc(1);
2816                 if(!chain->name)
2817                 {
2818                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2819                            __FILE__, __LINE__);
2820                     return(TNG_CRITICAL);
2821                 }
2822                 chain->name[0] = 0;
2823             }
2824             *len += tng_min_size(strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2825
2826             *len += sizeof(chain->n_residues);
2827
2828             chain++;
2829         }
2830
2831         residue = molecule->residues;
2832         for(j = 0; j < molecule->n_residues; j++)
2833         {
2834             *len += sizeof(residue->id);
2835
2836             if(!residue->name)
2837             {
2838                 residue->name = (char *)malloc(1);
2839                 if(!residue->name)
2840                 {
2841                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2842                            __FILE__, __LINE__);
2843                     return(TNG_CRITICAL);
2844                 }
2845                 residue->name[0] = 0;
2846             }
2847             *len += tng_min_size(strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2848
2849             *len += sizeof(residue->n_atoms);
2850
2851             residue++;
2852         }
2853
2854         atom = molecule->atoms;
2855         for(j = 0; j < molecule->n_atoms; j++)
2856         {
2857             *len += sizeof(atom->id);
2858             if(!atom->name)
2859             {
2860                 atom->name = (char *)malloc(1);
2861                 if(!atom->name)
2862                 {
2863                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2864                            __FILE__, __LINE__);
2865                     return(TNG_CRITICAL);
2866                 }
2867                 atom->name[0] = 0;
2868             }
2869             *len += tng_min_size(strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2870
2871             if(!atom->atom_type)
2872             {
2873                 atom->atom_type = (char *)malloc(1);
2874                 if(!atom->atom_type)
2875                 {
2876                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2877                            __FILE__, __LINE__);
2878                     return(TNG_CRITICAL);
2879                 }
2880                 atom->atom_type[0] = 0;
2881             }
2882             *len += tng_min_size(strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2883
2884             atom++;
2885         }
2886
2887         for(j = 0; j < molecule->n_bonds; j++)
2888         {
2889             *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
2890         }
2891     }
2892     *len += sizeof(tng_data->n_molecules) +
2893             (sizeof(molecule->id) +
2894             sizeof(molecule->quaternary_str) +
2895             sizeof(molecule->n_chains) +
2896             sizeof(molecule->n_residues) +
2897             sizeof(molecule->n_atoms) +
2898             sizeof(molecule->n_bonds)) *
2899             tng_data->n_molecules;
2900
2901     if(!tng_data->var_num_atoms_flag)
2902     {
2903         *len += tng_data->n_molecules * sizeof(int64_t);
2904     }
2905
2906     return(TNG_SUCCESS);
2907 }
2908
2909 /**
2910  * @brief Read a molecules block. Contains chain, residue and atom data
2911  * @param tng_data is a trajectory data container.
2912  * @param block is a general block container.
2913  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2914  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2915  * compared to the md5 hash of the read contents to ensure valid data.
2916  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2917  * error has occured.
2918  */
2919 static tng_function_status tng_molecules_block_read
2920                 (const tng_trajectory_t tng_data,
2921                  const tng_gen_block_t block,
2922                  const char hash_mode)
2923 {
2924     int64_t start_pos, i, j, k, l;
2925     tng_molecule_t molecule;
2926     tng_chain_t chain;
2927     tng_residue_t residue;
2928     tng_atom_t atom;
2929     tng_bond_t bond;
2930     char hash[TNG_MD5_HASH_LEN];
2931     md5_state_t md5_state;
2932
2933     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2934     {
2935         return(TNG_CRITICAL);
2936     }
2937
2938     start_pos = ftello(tng_data->input_file);
2939
2940     /* FIXME: Does not check if the size of the contents matches the expected
2941      * size or if the contents can be read. */
2942
2943     if(tng_data->molecules)
2944     {
2945         for(i=0; i<tng_data->n_molecules; i++)
2946         {
2947             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
2948         }
2949         free(tng_data->molecules);
2950         tng_data->molecules = 0;
2951         tng_data->n_molecules = 0;
2952     }
2953
2954     if(hash_mode == TNG_USE_HASH)
2955     {
2956         md5_init(&md5_state);
2957     }
2958
2959     if(tng_file_input_numerical(tng_data, &tng_data->n_molecules,
2960                                 sizeof(tng_data->n_molecules),
2961                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2962     {
2963         return(TNG_CRITICAL);
2964     }
2965
2966     if(tng_data->molecules)
2967     {
2968         free(tng_data->molecules);
2969     }
2970
2971     tng_data->n_particles = 0;
2972
2973     tng_data->molecules = (struct tng_molecule *)malloc(tng_data->n_molecules *
2974                                                         sizeof(struct tng_molecule));
2975     if(!tng_data->molecules)
2976     {
2977         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
2978         return(TNG_CRITICAL);
2979     }
2980
2981     if(!tng_data->var_num_atoms_flag)
2982     {
2983         if(tng_data->molecule_cnt_list)
2984         {
2985             free(tng_data->molecule_cnt_list);
2986         }
2987         tng_data->molecule_cnt_list = (int64_t *)malloc(sizeof(int64_t) *
2988                                                         tng_data->n_molecules);
2989         if(!tng_data->molecule_cnt_list)
2990         {
2991             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
2992             return(TNG_CRITICAL);
2993         }
2994     }
2995
2996     /* Read each molecule from file */
2997     for(i=0; i < tng_data->n_molecules; i++)
2998     {
2999         molecule = &tng_data->molecules[i];
3000
3001         molecule->name = 0;
3002
3003         if(tng_file_input_numerical(tng_data, &molecule->id,
3004                                     sizeof(molecule->id),
3005                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3006         {
3007             return(TNG_CRITICAL);
3008         }
3009
3010 /*         fprintf(stderr, "TNG library: Read id: %" PRId64 " offset: %d\n", molecule->id, offset);*/
3011         tng_freadstr(tng_data, &molecule->name, hash_mode, &md5_state, __LINE__);
3012
3013         if(tng_file_input_numerical(tng_data, &molecule->quaternary_str,
3014                                     sizeof(molecule->quaternary_str),
3015                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3016         {
3017             return(TNG_CRITICAL);
3018         }
3019
3020         if(!tng_data->var_num_atoms_flag)
3021         {
3022             if(tng_file_input_numerical(tng_data, &tng_data->molecule_cnt_list[i],
3023                                         sizeof(int64_t),
3024                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3025             {
3026                 return(TNG_CRITICAL);
3027             }
3028         }
3029
3030         if(tng_file_input_numerical(tng_data, &molecule->n_chains,
3031                                     sizeof(molecule->n_chains),
3032                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3033         {
3034             return(TNG_CRITICAL);
3035         }
3036
3037         if(tng_file_input_numerical(tng_data, &molecule->n_residues,
3038                                     sizeof(molecule->n_residues),
3039                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3040         {
3041             return(TNG_CRITICAL);
3042         }
3043
3044         if(tng_file_input_numerical(tng_data, &molecule->n_atoms,
3045                                     sizeof(molecule->n_atoms),
3046                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3047         {
3048             return(TNG_CRITICAL);
3049         }
3050
3051         tng_data->n_particles += molecule->n_atoms *
3052                                  tng_data->molecule_cnt_list[i];
3053
3054         if(molecule->n_chains > 0)
3055         {
3056             molecule->chains = (struct tng_chain *)malloc(molecule->n_chains *
3057                                                           sizeof(struct tng_chain));
3058             if(!molecule->chains)
3059             {
3060                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3061                         __FILE__, __LINE__);
3062                 return(TNG_CRITICAL);
3063             }
3064
3065             chain = molecule->chains;
3066         }
3067         else
3068         {
3069             chain = 0;
3070         }
3071
3072         if(molecule->n_residues > 0)
3073         {
3074             molecule->residues = (struct tng_residue *)malloc(molecule->n_residues *
3075                                                               sizeof(struct tng_residue));
3076             if(!molecule->residues)
3077             {
3078                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3079                         __FILE__, __LINE__);
3080                 if(molecule->chains)
3081                 {
3082                     free(molecule->chains);
3083                     molecule->chains = 0;
3084                 }
3085                 return(TNG_CRITICAL);
3086             }
3087
3088             residue = molecule->residues;
3089         }
3090         else
3091         {
3092             residue = 0;
3093         }
3094
3095         molecule->atoms = (struct tng_atom *)malloc(molecule->n_atoms *
3096                                                  sizeof(struct tng_atom));
3097         if(!molecule->atoms)
3098         {
3099             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3100                     __FILE__, __LINE__);
3101             if(molecule->chains)
3102             {
3103                 free(molecule->chains);
3104                 molecule->chains = 0;
3105             }
3106             if(molecule->residues)
3107             {
3108                 free(molecule->residues);
3109                 molecule->residues = 0;
3110             }
3111             return(TNG_CRITICAL);
3112         }
3113
3114         atom = molecule->atoms;
3115
3116         if(molecule->n_chains > 0)
3117         {
3118             /* Read the chains of the molecule */
3119             for(j=0; j<molecule->n_chains; j++)
3120             {
3121                 chain->molecule = molecule;
3122
3123                 chain->name = 0;
3124
3125                 tng_chain_data_read(tng_data, chain, hash_mode, &md5_state);
3126
3127                 if(j==0)
3128                 {
3129                     chain->residues = molecule->residues;
3130                     residue = chain->residues;
3131                 }
3132                 else
3133                 {
3134                     chain->residues = residue;
3135                 }
3136
3137                 /* Read the residues of the chain */
3138                 for(k=0; k<chain->n_residues; k++)
3139                 {
3140                     residue->chain = chain;
3141
3142                     residue->name = 0;
3143
3144                     tng_residue_data_read(tng_data, residue, hash_mode, &md5_state);
3145
3146                     residue->atoms_offset = atom - molecule->atoms;
3147                     /* Read the atoms of the residue */
3148                     for(l=0; l<residue->n_atoms; l++)
3149                     {
3150                         atom->residue = residue;
3151
3152                         atom->name = 0;
3153                         atom->atom_type = 0;
3154
3155                         tng_atom_data_read(tng_data,atom, hash_mode, &md5_state);
3156
3157                         atom++;
3158                     }
3159                     residue++;
3160                 }
3161                 chain++;
3162             }
3163         }
3164         else
3165         {
3166             if(molecule->n_residues > 0)
3167             {
3168                 for(k=0; k<molecule->n_residues; k++)
3169                 {
3170                     residue->chain = 0;
3171
3172                     residue->name = 0;
3173
3174                     tng_residue_data_read(tng_data, residue, hash_mode, &md5_state);
3175
3176                     residue->atoms_offset = atom - molecule->atoms;
3177                     /* Read the atoms of the residue */
3178                     for(l=0; l<residue->n_atoms; l++)
3179                     {
3180                         atom->residue = residue;
3181
3182                         tng_atom_data_read(tng_data, atom, hash_mode, &md5_state);
3183
3184                         atom++;
3185                     }
3186                     residue++;
3187                 }
3188             }
3189             else
3190             {
3191                 for(l=0; l<molecule->n_atoms; l++)
3192                 {
3193                     atom->residue = 0;
3194
3195                     atom->name = 0;
3196                     atom->atom_type = 0;
3197
3198                     tng_atom_data_read(tng_data, atom, hash_mode, &md5_state);
3199
3200                     atom++;
3201                 }
3202             }
3203         }
3204
3205         if(tng_file_input_numerical(tng_data, &molecule->n_bonds,
3206                                     sizeof(molecule->n_bonds),
3207                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3208         {
3209             return(TNG_CRITICAL);
3210         }
3211
3212         if(molecule->n_bonds > 0)
3213         {
3214             tng_data->molecules[i].bonds = (struct tng_bond *)malloc(molecule->n_bonds *
3215                                                                      sizeof(struct tng_bond));
3216             if(!molecule->bonds)
3217             {
3218                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3219                         __FILE__, __LINE__);
3220                 if(molecule->chains)
3221                 {
3222                     free(molecule->chains);
3223                     molecule->chains = 0;
3224                 }
3225                 if(molecule->residues)
3226                 {
3227                     free(molecule->residues);
3228                     molecule->residues = 0;
3229                 }
3230                 if(molecule->atoms)
3231                 {
3232                     free(molecule->atoms);
3233                     molecule->atoms = 0;
3234                 }
3235                 return(TNG_CRITICAL);
3236             }
3237
3238             bond = molecule->bonds;
3239
3240             for(j=0; j<molecule->n_bonds; j++)
3241             {
3242                 if(tng_file_input_numerical(tng_data, &bond->from_atom_id,
3243                                             sizeof(bond->from_atom_id),
3244                                             hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3245                 {
3246                     return(TNG_CRITICAL);
3247                 }
3248
3249                 if(tng_file_input_numerical(tng_data, &bond->to_atom_id,
3250                                             sizeof(bond->to_atom_id),
3251                                             hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3252                 {
3253                     return(TNG_CRITICAL);
3254                 }
3255
3256                 bond++;
3257             }
3258         }
3259         else
3260         {
3261             molecule->bonds = 0;
3262         }
3263     }
3264
3265     if(hash_mode == TNG_USE_HASH)
3266     {
3267         /* If there is data left in the block that the current version of the library
3268          * cannot interpret still read that to generate the MD5 hash. */
3269         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
3270
3271         md5_finish(&md5_state, (md5_byte_t *)hash);
3272         if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
3273         {
3274             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
3275             {
3276                 fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
3277                         "%s: %d\n", __FILE__, __LINE__);
3278             }
3279         }
3280     }
3281
3282     else
3283     {
3284         /* Seek to the end of the block */
3285         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
3286     }
3287
3288     return(TNG_SUCCESS);
3289 }
3290
3291 /**
3292  * @brief Write a molecules block.
3293  * @param tng_data is a trajectory data container.
3294  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3295  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3296  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3297  * error has occured.
3298  */
3299 static tng_function_status tng_molecules_block_write
3300                 (const tng_trajectory_t tng_data,
3301                  const char hash_mode)
3302 {
3303     int name_len;
3304     int64_t i, j, k, l, header_file_pos, curr_file_pos;
3305     tng_molecule_t molecule;
3306     tng_chain_t chain;
3307     tng_residue_t residue;
3308     tng_atom_t atom;
3309     tng_bond_t bond;
3310     tng_gen_block_t block;
3311     md5_state_t md5_state;
3312
3313     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3314     {
3315         return(TNG_CRITICAL);
3316     }
3317
3318     tng_block_init(&block);
3319
3320     name_len = (unsigned int)strlen("MOLECULES");
3321
3322     block->name = (char *)malloc(name_len + 1);
3323     if(!block->name)
3324     {
3325         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
3326         tng_block_destroy(&block);
3327         return(TNG_CRITICAL);
3328     }
3329
3330     strcpy(block->name, "MOLECULES");
3331     block->id = TNG_MOLECULES;
3332
3333     if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) !=
3334         TNG_SUCCESS)
3335     {
3336         fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n",
3337                 __FILE__, __LINE__);
3338         tng_block_destroy(&block);
3339         return(TNG_CRITICAL);
3340     }
3341
3342     header_file_pos = ftello(tng_data->output_file);
3343
3344     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
3345     {
3346         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3347                tng_data->output_file_path, __FILE__, __LINE__);
3348         tng_block_destroy(&block);
3349         return(TNG_CRITICAL);
3350     }
3351
3352     if(hash_mode == TNG_USE_HASH)
3353     {
3354         md5_init(&md5_state);
3355     }
3356
3357     if(tng_file_output_numerical(tng_data, &tng_data->n_molecules,
3358                                  sizeof(tng_data->n_molecules),
3359                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3360     {
3361         return(TNG_CRITICAL);
3362     }
3363
3364     for(i = 0; i < tng_data->n_molecules; i++)
3365     {
3366         molecule = &tng_data->molecules[i];
3367
3368         if(tng_file_output_numerical(tng_data, &molecule->id,
3369                                     sizeof(molecule->id),
3370                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3371         {
3372             return(TNG_CRITICAL);
3373         }
3374
3375         if(tng_fwritestr(tng_data, molecule->name, hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3376         {
3377             return(TNG_CRITICAL);
3378         }
3379
3380         if(tng_file_output_numerical(tng_data, &molecule->quaternary_str,
3381                                     sizeof(molecule->quaternary_str),
3382                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3383         {
3384             return(TNG_CRITICAL);
3385         }
3386
3387         if(!tng_data->var_num_atoms_flag)
3388         {
3389             if(tng_file_output_numerical(tng_data, &tng_data->molecule_cnt_list[i],
3390                                         sizeof(int64_t),
3391                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3392             {
3393                 return(TNG_CRITICAL);
3394             }
3395         }
3396
3397         if(tng_file_output_numerical(tng_data, &molecule->n_chains,
3398                                     sizeof(molecule->n_chains),
3399                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3400         {
3401             return(TNG_CRITICAL);
3402         }
3403
3404         if(tng_file_output_numerical(tng_data, &molecule->n_residues,
3405                                     sizeof(molecule->n_residues),
3406                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3407         {
3408             return(TNG_CRITICAL);
3409         }
3410
3411         if(tng_file_output_numerical(tng_data, &molecule->n_atoms,
3412                                     sizeof(molecule->n_atoms),
3413                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3414         {
3415             return(TNG_CRITICAL);
3416         }
3417
3418         if(molecule->n_chains > 0)
3419         {
3420             chain = molecule->chains;
3421             for(j = 0; j < molecule->n_chains; j++)
3422             {
3423                 tng_chain_data_write(tng_data, chain, hash_mode, &md5_state);
3424
3425                 residue = chain->residues;
3426                 for(k = 0; k < chain->n_residues; k++)
3427                 {
3428                     tng_residue_data_write(tng_data, residue, hash_mode, &md5_state);
3429
3430                     atom = molecule->atoms + residue->atoms_offset;
3431                     for(l = 0; l < residue->n_atoms; l++)
3432                     {
3433                         tng_atom_data_write(tng_data, atom, hash_mode, &md5_state);
3434
3435                         atom++;
3436                     }
3437                     residue++;
3438                 }
3439                 chain++;
3440             }
3441         }
3442         else
3443         {
3444             if(molecule->n_residues > 0)
3445             {
3446                 residue = molecule->residues;
3447                 for(k = 0; k < molecule->n_residues; k++)
3448                 {
3449                     tng_residue_data_write(tng_data, residue, hash_mode, &md5_state);
3450
3451                     atom = molecule->atoms + residue->atoms_offset;
3452                     for(l = 0; l < residue->n_atoms; l++)
3453                     {
3454                         tng_atom_data_write(tng_data, atom, hash_mode, &md5_state);
3455
3456                         atom++;
3457                     }
3458                     residue++;
3459                 }
3460             }
3461             else
3462             {
3463                 atom = molecule->atoms;
3464                 for(l = 0; l < molecule->n_atoms; l++)
3465                 {
3466                     tng_atom_data_write(tng_data, atom, hash_mode, &md5_state);
3467
3468                     atom++;
3469                 }
3470             }
3471         }
3472
3473         if(tng_file_output_numerical(tng_data, &molecule->n_bonds,
3474                                     sizeof(molecule->n_bonds),
3475                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3476         {
3477             return(TNG_CRITICAL);
3478         }
3479
3480         bond = molecule->bonds;
3481         for(j = 0; j < molecule->n_bonds; j++)
3482         {
3483             if(tng_file_output_numerical(tng_data, &bond->from_atom_id,
3484                                         sizeof(bond->from_atom_id),
3485                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3486             {
3487                 return(TNG_CRITICAL);
3488             }
3489
3490             if(tng_file_output_numerical(tng_data, &bond->to_atom_id,
3491                                         sizeof(bond->to_atom_id),
3492                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3493             {
3494                 return(TNG_CRITICAL);
3495             }
3496
3497             bond++;
3498         }
3499     }
3500     if(hash_mode == TNG_USE_HASH)
3501     {
3502         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
3503         curr_file_pos = ftello(tng_data->output_file);
3504         fseeko(tng_data->output_file, header_file_pos +
3505                3 * sizeof(int64_t), SEEK_SET);
3506         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
3507         {
3508             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
3509                     __LINE__);
3510             return(TNG_CRITICAL);
3511         }
3512         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
3513     }
3514
3515     tng_block_destroy(&block);
3516
3517     return(TNG_SUCCESS);
3518 }
3519
3520 static tng_function_status tng_frame_set_block_len_calculate
3521                 (const tng_trajectory_t tng_data,
3522                  int64_t *len)
3523 {
3524     *len = sizeof(int64_t) * 8;
3525     *len += sizeof(double) * 2;
3526
3527     if(tng_data->var_num_atoms_flag)
3528     {
3529         *len += sizeof(int64_t) * tng_data->n_molecules;
3530     }
3531     return(TNG_SUCCESS);
3532 }
3533
3534 /**
3535  * @brief Read a frame set block. Update tng_data->current_trajectory_frame_set
3536  * @param tng_data is a trajectory data container.
3537  * @param block is a general block container.
3538  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3539  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3540  * compared to the md5 hash of the read contents to ensure valid data.
3541  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3542  * error has occured.
3543  */
3544 static tng_function_status tng_frame_set_block_read
3545                 (tng_trajectory_t tng_data,
3546                  tng_gen_block_t block,
3547                  const char hash_mode)
3548 {
3549     int64_t file_pos, start_pos, i, prev_n_particles;
3550     tng_trajectory_frame_set_t frame_set =
3551     &tng_data->current_trajectory_frame_set;
3552     char hash[TNG_MD5_HASH_LEN];
3553     md5_state_t md5_state;
3554
3555     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3556     {
3557         return(TNG_CRITICAL);
3558     }
3559
3560     start_pos = ftello(tng_data->input_file);
3561
3562     /* FIXME: Does not check if the size of the contents matches the expected
3563      * size or if the contents can be read. */
3564
3565     file_pos = start_pos - block->header_contents_size;
3566
3567     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3568
3569     tng_frame_set_particle_mapping_free(tng_data);
3570
3571     if(hash_mode == TNG_USE_HASH)
3572     {
3573         md5_init(&md5_state);
3574     }
3575     if(tng_file_input_numerical(tng_data, &frame_set->first_frame,
3576                                 sizeof(frame_set->first_frame),
3577                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3578     {
3579         return(TNG_CRITICAL);
3580     }
3581
3582     if(tng_file_input_numerical(tng_data, &frame_set->n_frames,
3583                                 sizeof(frame_set->n_frames),
3584                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3585     {
3586         return(TNG_CRITICAL);
3587     }
3588
3589     if(tng_data->var_num_atoms_flag)
3590     {
3591         prev_n_particles = frame_set->n_particles;
3592         frame_set->n_particles = 0;
3593         /* If the list of molecule counts has already been created assume that
3594          * it is of correct size. */
3595         if(!frame_set->molecule_cnt_list)
3596         {
3597                 frame_set->molecule_cnt_list =
3598                 (int64_t *)malloc(sizeof(int64_t) * tng_data->n_molecules);
3599
3600                 if(!frame_set->molecule_cnt_list)
3601                 {
3602                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3603                             __FILE__, __LINE__);
3604                     return(TNG_CRITICAL);
3605                 }
3606         }
3607         for(i = 0; i < tng_data->n_molecules; i++)
3608         {
3609             if(tng_file_input_numerical(tng_data, &frame_set->molecule_cnt_list[i],
3610                                         sizeof(int64_t),
3611                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3612             {
3613                 return(TNG_CRITICAL);
3614             }
3615
3616             frame_set->n_particles += tng_data->molecules[i].n_atoms *
3617                                       frame_set->molecule_cnt_list[i];
3618         }
3619         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
3620         {
3621             /* FIXME: Particle dependent data memory management */
3622         }
3623     }
3624
3625     if(tng_file_input_numerical(tng_data, &frame_set->next_frame_set_file_pos,
3626                                 sizeof(frame_set->next_frame_set_file_pos),
3627                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3628     {
3629         return(TNG_CRITICAL);
3630     }
3631
3632     if(tng_file_input_numerical(tng_data, &frame_set->prev_frame_set_file_pos,
3633                                 sizeof(frame_set->prev_frame_set_file_pos),
3634                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3635     {
3636         return(TNG_CRITICAL);
3637     }
3638
3639     if(tng_file_input_numerical(tng_data, &frame_set->medium_stride_next_frame_set_file_pos,
3640                                 sizeof(frame_set->medium_stride_next_frame_set_file_pos),
3641                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3642     {
3643         return(TNG_CRITICAL);
3644     }
3645
3646     if(tng_file_input_numerical(tng_data, &frame_set->medium_stride_prev_frame_set_file_pos,
3647                                 sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
3648                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3649     {
3650         return(TNG_CRITICAL);
3651     }
3652
3653     if(tng_file_input_numerical(tng_data, &frame_set->long_stride_next_frame_set_file_pos,
3654                                 sizeof(frame_set->long_stride_next_frame_set_file_pos),
3655                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3656     {
3657         return(TNG_CRITICAL);
3658     }
3659
3660     if(tng_file_input_numerical(tng_data, &frame_set->long_stride_prev_frame_set_file_pos,
3661                                 sizeof(frame_set->long_stride_prev_frame_set_file_pos),
3662                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3663     {
3664         return(TNG_CRITICAL);
3665     }
3666
3667     if(block->block_version >= 3)
3668     {
3669         if(tng_file_input_numerical(tng_data, &frame_set->first_frame_time,
3670                                     sizeof(frame_set->first_frame_time),
3671                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3672         {
3673             return(TNG_CRITICAL);
3674         }
3675
3676         if(tng_file_input_numerical(tng_data, &tng_data->time_per_frame,
3677                                     sizeof(tng_data->time_per_frame),
3678                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3679         {
3680             return(TNG_CRITICAL);
3681         }
3682     }
3683     else
3684     {
3685         frame_set->first_frame_time = -1;
3686         tng_data->time_per_frame = -1;
3687     }
3688
3689     if(hash_mode == TNG_USE_HASH)
3690     {
3691         /* If there is data left in the block that the current version of the library
3692          * cannot interpret still read that to generate the MD5 hash. */
3693         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
3694
3695         md5_finish(&md5_state, (md5_byte_t *)hash);
3696         if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
3697         {
3698             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
3699             {
3700                 fprintf(stderr, "TNG library: Frame set block contents corrupt (first frame %" PRId64 "). Hashes do not match. "
3701                         "%s: %d\n", frame_set->first_frame, __FILE__, __LINE__);
3702             }
3703         }
3704     }
3705     else
3706     {
3707         /* Seek to the end of the block */
3708         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
3709     }
3710
3711     /* If the output file and the input files are the same the number of
3712      * frames in the file are the same number as has just been read.
3713      * This is updated here to later on see if there have been new frames
3714      * added and thereby the frame set needs to be rewritten. */
3715     if(tng_data->output_file == tng_data->input_file)
3716     {
3717         frame_set->n_written_frames = frame_set->n_frames;
3718     }
3719
3720     return(TNG_SUCCESS);
3721 }
3722
3723 /**
3724  * @brief Write tng_data->current_trajectory_frame_set to file
3725  * @param tng_data is a trajectory data container.
3726  * @param block is a general block container.
3727  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3728  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3729  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3730  * error has occured.
3731  */
3732 static tng_function_status tng_frame_set_block_write
3733                 (const tng_trajectory_t tng_data,
3734                  const tng_gen_block_t block,
3735                  const char hash_mode)
3736 {
3737     char *temp_name;
3738     int64_t i, header_file_pos, curr_file_pos;
3739     unsigned int name_len;
3740     tng_trajectory_frame_set_t frame_set =
3741     &tng_data->current_trajectory_frame_set;
3742     md5_state_t md5_state;
3743
3744     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3745     {
3746         return(TNG_CRITICAL);
3747     }
3748
3749     name_len = (unsigned int)strlen("TRAJECTORY FRAME SET");
3750
3751     if(!block->name || strlen(block->name) < name_len)
3752     {
3753         temp_name = (char *)realloc(block->name, name_len + 1);
3754         if(!temp_name)
3755         {
3756             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3757                     __FILE__, __LINE__);
3758             free(block->name);
3759             block->name = 0;
3760             return(TNG_CRITICAL);
3761         }
3762         block->name = temp_name;
3763     }
3764     strcpy(block->name, "TRAJECTORY FRAME SET");
3765     block->id = TNG_TRAJECTORY_FRAME_SET;
3766
3767     if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) !=
3768         TNG_SUCCESS)
3769     {
3770         fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n",
3771                 __FILE__, __LINE__);
3772         return(TNG_CRITICAL);
3773     }
3774
3775     header_file_pos = ftello(tng_data->output_file);
3776
3777     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
3778     {
3779         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3780                tng_data->output_file_path, __FILE__, __LINE__);
3781         return(TNG_CRITICAL);
3782     }
3783
3784     if(hash_mode == TNG_USE_HASH)
3785     {
3786         md5_init(&md5_state);
3787     }
3788     if(tng_file_output_numerical(tng_data, &frame_set->first_frame,
3789                                  sizeof(frame_set->first_frame),
3790                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3791     {
3792         return(TNG_CRITICAL);
3793     }
3794
3795     if(tng_file_output_numerical(tng_data, &frame_set->n_frames,
3796                                  sizeof(frame_set->n_frames),
3797                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3798     {
3799         return(TNG_CRITICAL);
3800     }
3801
3802     if(tng_data->var_num_atoms_flag)
3803     {
3804         for(i = 0; i < tng_data->n_molecules; i++)
3805         {
3806             if(tng_file_output_numerical(tng_data, &frame_set->molecule_cnt_list[i],
3807                                         sizeof(int64_t),
3808                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3809             {
3810                 return(TNG_CRITICAL);
3811             }
3812         }
3813     }
3814
3815     if(tng_file_output_numerical(tng_data, &frame_set->next_frame_set_file_pos,
3816                                  sizeof(frame_set->next_frame_set_file_pos),
3817                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3818     {
3819         return(TNG_CRITICAL);
3820     }
3821
3822     if(tng_file_output_numerical(tng_data, &frame_set->prev_frame_set_file_pos,
3823                                  sizeof(frame_set->prev_frame_set_file_pos),
3824                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3825     {
3826         return(TNG_CRITICAL);
3827     }
3828
3829     if(tng_file_output_numerical(tng_data, &frame_set->medium_stride_next_frame_set_file_pos,
3830                                  sizeof(frame_set->medium_stride_next_frame_set_file_pos),
3831                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3832     {
3833         return(TNG_CRITICAL);
3834     }
3835
3836     if(tng_file_output_numerical(tng_data, &frame_set->medium_stride_prev_frame_set_file_pos,
3837                                  sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
3838                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3839     {
3840         return(TNG_CRITICAL);
3841     }
3842
3843     if(tng_file_output_numerical(tng_data, &frame_set->long_stride_next_frame_set_file_pos,
3844                                  sizeof(frame_set->long_stride_next_frame_set_file_pos),
3845                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3846     {
3847         return(TNG_CRITICAL);
3848     }
3849
3850     if(tng_file_output_numerical(tng_data, &frame_set->long_stride_prev_frame_set_file_pos,
3851                                  sizeof(frame_set->long_stride_prev_frame_set_file_pos),
3852                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3853     {
3854         return(TNG_CRITICAL);
3855     }
3856
3857     if(tng_file_output_numerical(tng_data, &frame_set->first_frame_time,
3858                                  sizeof(frame_set->first_frame_time),
3859                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3860     {
3861         return(TNG_CRITICAL);
3862     }
3863
3864     if(tng_file_output_numerical(tng_data, &tng_data->time_per_frame,
3865                                  sizeof(tng_data->time_per_frame),
3866                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3867     {
3868         return(TNG_CRITICAL);
3869     }
3870     if(hash_mode == TNG_USE_HASH)
3871     {
3872         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
3873         curr_file_pos = ftello(tng_data->output_file);
3874         fseeko(tng_data->output_file, header_file_pos +
3875                3 * sizeof(int64_t), SEEK_SET);
3876         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
3877         {
3878             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
3879                     __LINE__);
3880             return(TNG_CRITICAL);
3881         }
3882         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
3883     }
3884
3885     return(TNG_SUCCESS);
3886 }
3887
3888 static tng_function_status tng_trajectory_mapping_block_len_calculate
3889                 (const tng_trajectory_t tng_data,
3890                  const int64_t n_particles,
3891                  int64_t *len)
3892 {
3893     (void)tng_data;
3894     *len = sizeof(int64_t) * (2 + n_particles);
3895
3896     return(TNG_SUCCESS);
3897 }
3898
3899 /**
3900  * @brief Read an atom mappings block (translating between real atom indexes and how
3901  *  the atom info is written in this frame set).
3902  * @param tng_data is a trajectory data container.
3903  * @param block is a general block container.
3904  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3905  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3906  * compared to the md5 hash of the read contents to ensure valid data.
3907  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3908  * error has occured.
3909  */
3910 static tng_function_status tng_trajectory_mapping_block_read
3911                 (const tng_trajectory_t tng_data,
3912                  const tng_gen_block_t block,
3913                  const char hash_mode)
3914 {
3915     int64_t start_pos, i;
3916     tng_trajectory_frame_set_t frame_set =
3917     &tng_data->current_trajectory_frame_set;
3918     tng_particle_mapping_t mapping, mappings;
3919     char hash[TNG_MD5_HASH_LEN];
3920     md5_state_t md5_state;
3921
3922     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3923     {
3924         return(TNG_CRITICAL);
3925     }
3926
3927     start_pos = ftello(tng_data->input_file);
3928
3929     /* FIXME: Does not check if the size of the contents matches the expected
3930      * size or if the contents can be read. */
3931
3932     frame_set->n_mapping_blocks++;
3933     mappings = (tng_particle_mapping_t)realloc(frame_set->mappings,
3934                                                sizeof(struct tng_particle_mapping) *
3935                                                frame_set->n_mapping_blocks);
3936     if(!mappings)
3937     {
3938         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3939                 __FILE__, __LINE__);
3940         free(frame_set->mappings);
3941         frame_set->mappings = 0;
3942         return(TNG_CRITICAL);
3943     }
3944     frame_set->mappings = mappings;
3945     mapping = &mappings[frame_set->n_mapping_blocks - 1];
3946
3947
3948     if(hash_mode == TNG_USE_HASH)
3949     {
3950         md5_init(&md5_state);
3951     }
3952
3953     if(tng_file_input_numerical(tng_data, &mapping->num_first_particle,
3954                                 sizeof(mapping->num_first_particle),
3955                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3956     {
3957         return(TNG_CRITICAL);
3958     }
3959
3960     if(tng_file_input_numerical(tng_data, &mapping->n_particles,
3961                                 sizeof(mapping->n_particles),
3962                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3963     {
3964         return(TNG_CRITICAL);
3965     }
3966
3967     mapping->real_particle_numbers = (int64_t *)malloc(mapping->n_particles *
3968                                                        sizeof(int64_t));
3969     if(!mapping->real_particle_numbers)
3970     {
3971         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3972                 __FILE__, __LINE__);
3973         return(TNG_CRITICAL);
3974     }
3975
3976     /* If the byte order needs to be swapped the data must be read one value at
3977      * a time and swapped */
3978     if(tng_data->input_endianness_swap_func_64)
3979     {
3980         for(i = 0; i < mapping->n_particles; i++)
3981         {
3982             if(tng_file_input_numerical(tng_data, &mapping->real_particle_numbers[i],
3983                                         sizeof(int64_t),
3984                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3985             {
3986                 return(TNG_CRITICAL);
3987             }
3988         }
3989     }
3990     /* Otherwise the data can be read all at once */
3991     else
3992     {
3993         if(fread(mapping->real_particle_numbers, mapping->n_particles * sizeof(int64_t),
3994                 1, tng_data->input_file) == 0)
3995         {
3996             fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3997             return(TNG_CRITICAL);
3998         }
3999         if(hash_mode == TNG_USE_HASH)
4000         {
4001             md5_append(&md5_state, (md5_byte_t *)mapping->real_particle_numbers, mapping->n_particles * sizeof(int64_t));
4002         }
4003     }
4004
4005     if(hash_mode == TNG_USE_HASH)
4006     {
4007         /* If there is data left in the block that the current version of the library
4008          * cannot interpret still read that to generate the MD5 hash. */
4009         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
4010
4011         md5_finish(&md5_state, (md5_byte_t *)hash);
4012         if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
4013         {
4014             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
4015             {
4016                 fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
4017                         "%s: %d\n", __FILE__, __LINE__);
4018             }
4019         }
4020     }
4021     else
4022     {
4023         /* Seek to the end of the block */
4024         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
4025     }
4026
4027     return(TNG_SUCCESS);
4028 }
4029
4030 /**
4031  * @brief Write the atom mappings of the current trajectory frame set
4032  * @param tng_data is a trajectory data container.
4033  * @param block is a general block container.
4034  * @param mapping_block_nr is the index of the mapping block to write.
4035  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4036  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4037  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
4038  * has occurred or TNG_CRITICAL (2) if a major error has occured.
4039  */
4040 static tng_function_status tng_trajectory_mapping_block_write
4041                 (const tng_trajectory_t tng_data,
4042                  const tng_gen_block_t block,
4043                  const int mapping_block_nr,
4044                  const char hash_mode)
4045 {
4046     int64_t header_file_pos, curr_file_pos;
4047     char *temp_name;
4048     int i;
4049     unsigned int name_len;
4050     md5_state_t md5_state;
4051     tng_particle_mapping_t mapping =
4052     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
4053
4054     if(mapping_block_nr >=
4055        tng_data->current_trajectory_frame_set.n_mapping_blocks)
4056     {
4057         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
4058                __FILE__, __LINE__);
4059         return(TNG_FAILURE);
4060     }
4061
4062     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4063     {
4064         return(TNG_CRITICAL);
4065     }
4066
4067     name_len = (unsigned int)strlen("PARTICLE MAPPING");
4068
4069     if(!block->name || strlen(block->name) < name_len)
4070     {
4071         temp_name = (char *)realloc(block->name, name_len + 1);
4072         if(!temp_name)
4073         {
4074             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4075                     __FILE__, __LINE__);
4076             free(block->name);
4077             block->name = 0;
4078             return(TNG_CRITICAL);
4079         }
4080         block->name = temp_name;
4081     }
4082     strcpy(block->name, "PARTICLE MAPPING");
4083     block->id = TNG_PARTICLE_MAPPING;
4084
4085     if(tng_trajectory_mapping_block_len_calculate(tng_data,
4086                                                   mapping->n_particles,
4087                                                   &block->block_contents_size) !=
4088         TNG_SUCCESS)
4089     {
4090         fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n",
4091                 __FILE__, __LINE__);
4092         return(TNG_CRITICAL);
4093     }
4094
4095     header_file_pos = ftello(tng_data->output_file);
4096
4097     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
4098     {
4099         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4100                tng_data->output_file_path, __FILE__, __LINE__);
4101         return(TNG_CRITICAL);
4102     }
4103
4104     if(hash_mode == TNG_USE_HASH)
4105     {
4106         md5_init(&md5_state);
4107     }
4108     if(tng_file_output_numerical(tng_data, &mapping->num_first_particle,
4109                                  sizeof(mapping->num_first_particle),
4110                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
4111     {
4112         return(TNG_CRITICAL);
4113     }
4114
4115     if(tng_file_output_numerical(tng_data, &mapping->n_particles,
4116                                  sizeof(mapping->n_particles),
4117                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
4118     {
4119         return(TNG_CRITICAL);
4120     }
4121
4122     if(tng_data->output_endianness_swap_func_64)
4123     {
4124         for(i = 0; i < mapping->n_particles; i++)
4125         {
4126             if(tng_file_output_numerical(tng_data, &mapping->real_particle_numbers[i],
4127                                         sizeof(int64_t),
4128                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
4129             {
4130                 return(TNG_CRITICAL);
4131             }
4132         }
4133     }
4134     else
4135     {
4136         if(fwrite(mapping->real_particle_numbers,
4137                   mapping->n_particles * sizeof(int64_t),
4138                   1, tng_data->output_file) != 1)
4139         {
4140             fprintf(stderr, "TNG library: Could not write block data. %s: %d\n", __FILE__, __LINE__);
4141             return(TNG_CRITICAL);
4142         }
4143         if(hash_mode == TNG_USE_HASH)
4144         {
4145             md5_append(&md5_state, (md5_byte_t *)mapping->real_particle_numbers,
4146                        mapping->n_particles * sizeof(int64_t));
4147         }
4148     }
4149
4150     if(hash_mode == TNG_USE_HASH)
4151     {
4152         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
4153         curr_file_pos = ftello(tng_data->output_file);
4154         fseeko(tng_data->output_file, header_file_pos +
4155                3 * sizeof(int64_t), SEEK_SET);
4156         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
4157         {
4158             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
4159                     __LINE__);
4160             return(TNG_CRITICAL);
4161         }
4162         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
4163     }
4164
4165     return(TNG_SUCCESS);
4166 }
4167
4168 /**
4169  * @brief Prepare a block for storing particle data
4170  * @param tng_data is a trajectory data container.
4171  * @param block_type_flag specifies if this is a trajectory block or a
4172  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
4173  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4174  * error has occured.
4175  */
4176 static tng_function_status tng_particle_data_block_create
4177                 (const tng_trajectory_t tng_data,
4178                  const char block_type_flag)
4179 {
4180     tng_trajectory_frame_set_t frame_set =
4181     &tng_data->current_trajectory_frame_set;
4182
4183     tng_data_t data;
4184
4185     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4186     {
4187         frame_set->n_particle_data_blocks++;
4188         data = (tng_data_t)realloc(frame_set->tr_particle_data,
4189                                    sizeof(struct tng_data) *
4190                                    frame_set->n_particle_data_blocks);
4191         if(!data)
4192         {
4193             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4194                     __FILE__, __LINE__);
4195             free(frame_set->tr_particle_data);
4196             frame_set->tr_particle_data = 0;
4197             return(TNG_CRITICAL);
4198         }
4199         frame_set->tr_particle_data = data;
4200     }
4201     else
4202     {
4203         tng_data->n_particle_data_blocks++;
4204         data = (tng_data_t)realloc(tng_data->non_tr_particle_data,
4205                                    sizeof(struct tng_data) *
4206                                    tng_data->n_particle_data_blocks);
4207         if(!data)
4208         {
4209             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4210                     __FILE__, __LINE__);
4211             free(tng_data->non_tr_particle_data);
4212             tng_data->non_tr_particle_data = 0;
4213             return(TNG_CRITICAL);
4214         }
4215         tng_data->non_tr_particle_data = data;
4216     }
4217
4218     return(TNG_SUCCESS);
4219 }
4220
4221 static tng_function_status tng_compress(const tng_trajectory_t tng_data,
4222                                         const tng_gen_block_t block,
4223                                         const int64_t n_frames,
4224                                         const int64_t n_particles,
4225                                         const char type,
4226                                         char **data,
4227                                         int64_t *new_len)
4228 {
4229     int nalgo;
4230     int compressed_len;
4231     int *alt_algo = 0;
4232     char *dest;
4233     int64_t algo_find_n_frames = -1;
4234     float f_precision;
4235     double d_precision;
4236
4237     if(block->id != TNG_TRAJ_POSITIONS &&
4238        block->id != TNG_TRAJ_VELOCITIES)
4239     {
4240         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
4241                "TNG method. %s: %d\n", __FILE__, __LINE__);
4242         return(TNG_FAILURE);
4243     }
4244     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4245     {
4246         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
4247         return(TNG_FAILURE);
4248     }
4249
4250     if(n_frames <= 0 || n_particles <= 0)
4251     {
4252         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
4253                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
4254         return(TNG_FAILURE);
4255     }
4256
4257     f_precision = 1/(float)tng_data->compression_precision;
4258     d_precision = 1/tng_data->compression_precision;
4259
4260     if(block->id == TNG_TRAJ_POSITIONS)
4261     {
4262         /* If there is only one frame in this frame set and there might be more
4263          * do not store the algorithm as the compression algorithm, but find
4264          * the best one without storing it */
4265         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4266         {
4267             nalgo = tng_compress_nalgo();
4268             alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4269
4270             /* If we have already determined the initial coding and
4271              * initial coding parameter do not determine them again. */
4272             if(tng_data->compress_algo_pos)
4273             {
4274                 alt_algo[0] = tng_data->compress_algo_pos[0];
4275                 alt_algo[1] = tng_data->compress_algo_pos[1];
4276                 alt_algo[2] = tng_data->compress_algo_pos[2];
4277                 alt_algo[3] = tng_data->compress_algo_pos[3];
4278             }
4279             else
4280             {
4281                 alt_algo[0] = -1;
4282                 alt_algo[1] = -1;
4283                 alt_algo[2] = -1;
4284                 alt_algo[3] = -1;
4285             }
4286
4287             /* If the initial coding and initial coding parameter are -1
4288              * they will be determined in tng_compress_pos/_float/. */
4289             if(type == TNG_FLOAT_DATA)
4290             {
4291                 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4292                                               (int)n_frames,
4293                                               f_precision,
4294                                               0, alt_algo,
4295                                               &compressed_len);
4296
4297             }
4298             else
4299             {
4300                 dest = tng_compress_pos((double *)*data, (int)n_particles,
4301                                         (int)n_frames,
4302                                         d_precision,
4303                                         0, alt_algo,
4304                                         &compressed_len);
4305             }
4306             /* If there had been no algorithm determined before keep the initial coding
4307              * and initial coding parameter so that they won't have to be determined again. */
4308             if(!tng_data->compress_algo_pos)
4309             {
4310                 nalgo = tng_compress_nalgo();
4311                 tng_data->compress_algo_pos = (int *)malloc(nalgo *
4312                                                             sizeof *tng_data->compress_algo_pos);
4313                 tng_data->compress_algo_pos[0] = alt_algo[0];
4314                 tng_data->compress_algo_pos[1] = alt_algo[1];
4315                 tng_data->compress_algo_pos[2] = -1;
4316                 tng_data->compress_algo_pos[3] = -1;
4317             }
4318         }
4319         else if(!tng_data->compress_algo_pos || tng_data->compress_algo_pos[2] == -1 ||
4320                 tng_data->compress_algo_pos[2] == -1)
4321         {
4322             if(n_frames > 6)
4323             {
4324                 algo_find_n_frames = 5;
4325             }
4326             else
4327             {
4328                 algo_find_n_frames = n_frames;
4329             }
4330
4331             /* If the algorithm parameters are -1 they will be determined during the
4332              * compression. */
4333             if(!tng_data->compress_algo_pos)
4334             {
4335                 nalgo = tng_compress_nalgo();
4336                 tng_data->compress_algo_pos = (int *)malloc(nalgo *
4337                                                             sizeof *tng_data->compress_algo_pos);
4338                 tng_data->compress_algo_pos[0] = -1;
4339                 tng_data->compress_algo_pos[1] = -1;
4340                 tng_data->compress_algo_pos[2] = -1;
4341                 tng_data->compress_algo_pos[3] = -1;
4342             }
4343             if(type == TNG_FLOAT_DATA)
4344             {
4345                 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4346                                               (int)algo_find_n_frames,
4347                                               f_precision,
4348                                               0, tng_data->
4349                                               compress_algo_pos,
4350                                               &compressed_len);
4351
4352                 if(algo_find_n_frames < n_frames)
4353                 {
4354                     free(dest);
4355                     dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4356                                                   (int)n_frames,
4357                                                   f_precision,
4358                                                   0, tng_data->compress_algo_pos,
4359                                                   &compressed_len);
4360                 }
4361             }
4362             else
4363             {
4364                 dest = tng_compress_pos((double *)*data, (int)n_particles,
4365                                         (int)algo_find_n_frames,
4366                                         d_precision,
4367                                         0, tng_data->
4368                                         compress_algo_pos,
4369                                         &compressed_len);
4370
4371                 if(algo_find_n_frames < n_frames)
4372                 {
4373                     free(dest);
4374                     dest = tng_compress_pos((double *)*data, (int)n_particles,
4375                                             (int)n_frames,
4376                                             d_precision, 0,
4377                                             tng_data->compress_algo_pos,
4378                                             &compressed_len);
4379                 }
4380             }
4381         }
4382         else
4383         {
4384             if(type == TNG_FLOAT_DATA)
4385             {
4386                 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4387                                               (int)n_frames,
4388                                               f_precision, 0,
4389                                               tng_data->compress_algo_pos, &compressed_len);
4390             }
4391             else
4392             {
4393                 dest = tng_compress_pos((double *)*data, (int)n_particles,
4394                                         (int)n_frames,
4395                                         d_precision, 0,
4396                                         tng_data->compress_algo_pos,
4397                                         &compressed_len);
4398             }
4399         }
4400     }
4401     else if(block->id == TNG_TRAJ_VELOCITIES)
4402     {
4403         /* If there is only one frame in this frame set and there might be more
4404          * do not store the algorithm as the compression algorithm, but find
4405          * the best one without storing it */
4406         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4407         {
4408             nalgo = tng_compress_nalgo();
4409             alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_vel);
4410
4411             /* If we have already determined the initial coding and
4412              * initial coding parameter do not determine them again. */
4413             if(tng_data->compress_algo_vel)
4414             {
4415                 alt_algo[0] = tng_data->compress_algo_vel[0];
4416                 alt_algo[1] = tng_data->compress_algo_vel[1];
4417                 alt_algo[2] = tng_data->compress_algo_vel[2];
4418                 alt_algo[3] = tng_data->compress_algo_vel[3];
4419             }
4420             else
4421             {
4422                 alt_algo[0] = -1;
4423                 alt_algo[1] = -1;
4424                 alt_algo[2] = -1;
4425                 alt_algo[3] = -1;
4426             }
4427
4428             /* If the initial coding and initial coding parameter are -1
4429              * they will be determined in tng_compress_pos/_float/. */
4430             if(type == TNG_FLOAT_DATA)
4431             {
4432                 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4433                                               (int)n_frames,
4434                                               f_precision,
4435                                               0, alt_algo,
4436                                               &compressed_len);
4437
4438             }
4439             else
4440             {
4441                 dest = tng_compress_vel((double *)*data, (int)n_particles,
4442                                         (int)n_frames,
4443                                         d_precision,
4444                                         0, alt_algo,
4445                                         &compressed_len);
4446             }
4447             /* If there had been no algorithm determined before keep the initial coding
4448              * and initial coding parameter so that they won't have to be determined again. */
4449             if(!tng_data->compress_algo_vel)
4450             {
4451                 nalgo = tng_compress_nalgo();
4452                 tng_data->compress_algo_vel = (int *)malloc(nalgo *
4453                                                             sizeof *tng_data->compress_algo_vel);
4454                 tng_data->compress_algo_vel[0] = alt_algo[0];
4455                 tng_data->compress_algo_vel[1] = alt_algo[1];
4456                 tng_data->compress_algo_vel[2] = -1;
4457                 tng_data->compress_algo_vel[3] = -1;
4458             }
4459         }
4460         else if(!tng_data->compress_algo_vel || tng_data->compress_algo_vel[2] == -1 ||
4461                 tng_data->compress_algo_vel[2] == -1)
4462         {
4463             if(n_frames > 6)
4464             {
4465                 algo_find_n_frames = 5;
4466             }
4467             else
4468             {
4469                 algo_find_n_frames = n_frames;
4470             }
4471
4472             /* If the algorithm parameters are -1 they will be determined during the
4473              * compression. */
4474             if(!tng_data->compress_algo_vel)
4475             {
4476                 nalgo = tng_compress_nalgo();
4477                 tng_data->compress_algo_vel = (int *)malloc(nalgo *
4478                                                             sizeof *tng_data->compress_algo_vel);
4479                 tng_data->compress_algo_vel[0] = -1;
4480                 tng_data->compress_algo_vel[1] = -1;
4481                 tng_data->compress_algo_vel[2] = -1;
4482                 tng_data->compress_algo_vel[3] = -1;
4483             }
4484             if(type == TNG_FLOAT_DATA)
4485             {
4486                 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4487                                               (int)algo_find_n_frames,
4488                                               f_precision,
4489                                               0, tng_data->
4490                                               compress_algo_vel,
4491                                               &compressed_len);
4492                 if(algo_find_n_frames < n_frames)
4493                 {
4494                     free(dest);
4495                     dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4496                                                   (int)n_frames,
4497                                                   f_precision,
4498                                                   0, tng_data->compress_algo_vel,
4499                                                   &compressed_len);
4500                 }
4501             }
4502             else
4503             {
4504                 dest = tng_compress_vel((double *)*data, (int)n_particles,
4505                                         (int)algo_find_n_frames,
4506                                         d_precision,
4507                                         0, tng_data->
4508                                         compress_algo_vel,
4509                                         &compressed_len);
4510                 if(algo_find_n_frames < n_frames)
4511                 {
4512                     free(dest);
4513                     dest = tng_compress_vel((double *)*data, (int)n_particles,
4514                                             (int)n_frames,
4515                                             d_precision,
4516                                             0, tng_data->compress_algo_vel,
4517                                             &compressed_len);
4518                 }
4519             }
4520         }
4521         else
4522         {
4523             if(type == TNG_FLOAT_DATA)
4524             {
4525                 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4526                                               (int)n_frames,
4527                                               f_precision,
4528                                               0, tng_data->
4529                                               compress_algo_vel,
4530                                               &compressed_len);
4531             }
4532             else
4533             {
4534                 dest = tng_compress_vel((double *)*data, (int)n_particles,
4535                                         (int)n_frames,
4536                                         d_precision,
4537                                         0, tng_data->
4538                                         compress_algo_vel,
4539                                         &compressed_len);
4540             }
4541         }
4542     }
4543     else
4544     {
4545         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
4546         return(TNG_FAILURE);
4547     }
4548
4549     if(alt_algo)
4550     {
4551         free(alt_algo);
4552     }
4553
4554     free(*data);
4555
4556     *data = (char *)dest;
4557
4558     *new_len = compressed_len;
4559
4560     return(TNG_SUCCESS);
4561 }
4562
4563 static tng_function_status tng_uncompress(const tng_trajectory_t tng_data,
4564                                           const tng_gen_block_t block,
4565                                           const char type,
4566                                           char **data,
4567                                           const int64_t uncompressed_len)
4568 {
4569     double *d_dest = 0;
4570     float *f_dest = 0;
4571     int result;
4572     (void)tng_data;
4573
4574     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
4575
4576     if(block->id != TNG_TRAJ_POSITIONS &&
4577        block->id != TNG_TRAJ_VELOCITIES)
4578     {
4579         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
4580                "TNG method.\n");
4581         return(TNG_FAILURE);
4582     }
4583     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4584     {
4585         fprintf(stderr, "TNG library: Data type not supported.\n");
4586         return(TNG_FAILURE);
4587     }
4588
4589     if(type == TNG_FLOAT_DATA)
4590     {
4591         f_dest = (float *)malloc(uncompressed_len);
4592         if(!f_dest)
4593         {
4594             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4595                     __FILE__, __LINE__);
4596             return(TNG_CRITICAL);
4597         }
4598         result = tng_compress_uncompress_float(*data, f_dest);
4599
4600         free(*data);
4601
4602         *data = (char *)f_dest;
4603     }
4604     else
4605     {
4606         d_dest = (double *)malloc(uncompressed_len);
4607         if(!d_dest)
4608         {
4609             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4610                     __FILE__, __LINE__);
4611             return(TNG_CRITICAL);
4612         }
4613         result = tng_compress_uncompress(*data, d_dest);
4614
4615         free(*data);
4616
4617         *data = (char *)d_dest;
4618     }
4619
4620     if(result == 1)
4621     {
4622         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
4623         return(TNG_FAILURE);
4624     }
4625
4626     return(TNG_SUCCESS);
4627 }
4628
4629 static tng_function_status tng_gzip_compress(const tng_trajectory_t tng_data,
4630                                              char **data, const int64_t len,
4631                                              int64_t *new_len)
4632 {
4633     Bytef *dest;
4634     uLongf stat, max_len;
4635     (void)tng_data;
4636
4637     max_len = compressBound(len);
4638     dest = (Bytef *)malloc(max_len);
4639     if(!dest)
4640     {
4641         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4642                 __FILE__, __LINE__);
4643         return(TNG_CRITICAL);
4644     }
4645
4646     stat = compress(dest, &max_len, (Bytef *)*data, len);
4647     if(stat != (unsigned long)Z_OK)
4648     {
4649         free(dest);
4650         if(stat == (unsigned long)Z_MEM_ERROR)
4651         {
4652             fprintf(stderr, "TNG library: Not enough memory. ");
4653         }
4654         else if(stat == (unsigned long)Z_BUF_ERROR)
4655         {
4656             fprintf(stderr, "TNG library: Destination buffer too small. ");
4657         }
4658         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
4659         return(TNG_FAILURE);
4660     }
4661
4662     *new_len = max_len;
4663
4664     free(*data);
4665
4666     *data = (char *)dest;
4667
4668     return(TNG_SUCCESS);
4669 }
4670
4671 static tng_function_status tng_gzip_uncompress(const tng_trajectory_t tng_data,
4672                                                char **data,
4673                                                const int64_t compressed_len,
4674                                                const int64_t uncompressed_len)
4675 {
4676     Bytef *dest;
4677     unsigned long stat;
4678     (void)tng_data;
4679     uLongf new_len = uncompressed_len;
4680
4681     dest = (Bytef *)malloc(uncompressed_len);
4682     if(!dest)
4683     {
4684         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4685                 __FILE__, __LINE__);
4686         return(TNG_CRITICAL);
4687     }
4688
4689     stat = uncompress(dest, &new_len, (Bytef *) *data,
4690                       compressed_len);
4691
4692     if(stat != Z_OK)
4693     {
4694         free(dest);
4695         if(stat == (unsigned long)Z_MEM_ERROR)
4696         {
4697             fprintf(stderr, "TNG library: Not enough memory. ");
4698         }
4699         else if(stat == (unsigned long)Z_BUF_ERROR)
4700         {
4701             fprintf(stderr, "TNG library: Destination buffer too small. ");
4702         }
4703         else if(stat == (unsigned long)Z_DATA_ERROR)
4704         {
4705             fprintf(stderr, "TNG library: Data corrupt. ");
4706         }
4707         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
4708                __LINE__);
4709         return(TNG_FAILURE);
4710     }
4711
4712     free(*data);
4713
4714     *data = (char *)dest;
4715
4716     return(TNG_SUCCESS);
4717 }
4718
4719 /**
4720  * @brief Allocate memory for storing particle data.
4721  * The allocated block will be refered to by data->values.
4722  * @param tng_data is a trajectory data container.
4723  * @param data is the data struct, which will contain the allocated memory in
4724  * data->values.
4725  * @param n_frames is the number of frames of data to store.
4726  * @param n_particles is the number of particles with data.
4727  * @param n_values_per_frame is the number of data values per particle and
4728  * frame.
4729  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4730  * error has occured.
4731  */
4732 static tng_function_status tng_allocate_particle_data_mem
4733                 (const tng_trajectory_t tng_data,
4734                  const tng_data_t data,
4735                  int64_t n_frames,
4736                  const int64_t stride_length,
4737                  const int64_t n_particles,
4738                  const int64_t n_values_per_frame)
4739 {
4740     void ***values;
4741     int64_t i, j, k, size, frame_alloc;
4742     (void)tng_data;
4743
4744     if(n_particles == 0 || n_values_per_frame == 0)
4745     {
4746         return(TNG_FAILURE);
4747     }
4748
4749     if(data->strings && data->datatype == TNG_CHAR_DATA)
4750     {
4751         for(i = 0; i < data->n_frames; i++)
4752         {
4753             for(j = 0; j < n_particles; j++)
4754             {
4755                 for(k = 0; k < data->n_values_per_frame; k++)
4756                 {
4757                     if(data->strings[i][j][k])
4758                     {
4759                         free(data->strings[i][j][k]);
4760                     }
4761                 }
4762                 free(data->strings[i][j]);
4763             }
4764             free(data->strings[i]);
4765         }
4766         free(data->strings);
4767     }
4768     data->n_frames = n_frames;
4769     n_frames = tng_max_i64(1, n_frames);
4770     data->stride_length = tng_max_i64(1, stride_length);
4771     data->n_values_per_frame = n_values_per_frame;
4772     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
4773
4774     if(data->datatype == TNG_CHAR_DATA)
4775     {
4776         data->strings = (char ****)malloc(sizeof(char ***) * frame_alloc);
4777         for(i = 0; i < frame_alloc; i++)
4778         {
4779             data->strings[i] = (char ***)malloc(sizeof(char **) *
4780                                     n_particles);
4781             if(!data->strings[i])
4782             {
4783                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4784                         __FILE__, __LINE__);
4785                 return(TNG_CRITICAL);
4786             }
4787             for(j = 0; j < n_particles; j++)
4788             {
4789                 data->strings[i][j] = (char **)malloc(sizeof(char *) *
4790                                             n_values_per_frame);
4791                 if(!data->strings[i][j])
4792                 {
4793                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4794                             __FILE__, __LINE__);
4795                     return(TNG_CRITICAL);
4796                 }
4797                 for(k = 0; k < n_values_per_frame; k++)
4798                 {
4799                     data->strings[i][j][k] = 0;
4800                 }
4801             }
4802         }
4803     }
4804     else
4805     {
4806         switch(data->datatype)
4807         {
4808         case TNG_INT_DATA:
4809             size = sizeof(int64_t);
4810             break;
4811         case TNG_FLOAT_DATA:
4812             size = sizeof(float);
4813             break;
4814         case TNG_DOUBLE_DATA:
4815         default:
4816             size = sizeof(double);
4817         }
4818
4819         values = (void ***)realloc(data->values,
4820                                    size * frame_alloc *
4821                                    n_particles * n_values_per_frame);
4822         if(!values)
4823         {
4824             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4825                     __FILE__, __LINE__);
4826             free(data->values);
4827             data->values = 0;
4828             return(TNG_CRITICAL);
4829         }
4830         data->values = values;
4831     }
4832     return(TNG_SUCCESS);
4833 }
4834
4835 static tng_function_status tng_particle_data_find
4836                 (const tng_trajectory_t tng_data,
4837                  const int64_t id,
4838                  tng_data_t *data)
4839 {
4840     int64_t block_index, i;
4841     tng_trajectory_frame_set_t frame_set = &tng_data->
4842                                            current_trajectory_frame_set;
4843     char block_type_flag;
4844
4845     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4846        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4847     {
4848         block_type_flag = TNG_TRAJECTORY_BLOCK;
4849     }
4850     else
4851     {
4852         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4853     }
4854
4855     block_index = -1;
4856     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4857     {
4858         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
4859         {
4860             *data = &frame_set->tr_particle_data[i];
4861             if((*data)->block_id == id)
4862             {
4863                 block_index = i;
4864                 break;
4865             }
4866         }
4867     }
4868     else
4869     {
4870         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
4871         {
4872             *data = &tng_data->non_tr_particle_data[i];
4873             if((*data)->block_id == id)
4874             {
4875                 block_index = i;
4876                 break;
4877             }
4878         }
4879     }
4880     if(block_index == -1)
4881     {
4882         return(TNG_FAILURE);
4883     }
4884     return(TNG_SUCCESS);
4885 }
4886
4887 static tng_function_status tng_data_find
4888                 (const tng_trajectory_t tng_data,
4889                  const int64_t id,
4890                  tng_data_t *data)
4891 {
4892     int64_t block_index, i;
4893     tng_trajectory_frame_set_t frame_set = &tng_data->
4894                                            current_trajectory_frame_set;
4895     char block_type_flag;
4896
4897     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4898        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4899     {
4900         block_type_flag = TNG_TRAJECTORY_BLOCK;
4901     }
4902     else
4903     {
4904         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4905     }
4906
4907     block_index = -1;
4908     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4909     {
4910         for(i = 0; i < frame_set->n_data_blocks; i++)
4911         {
4912             *data = &frame_set->tr_data[i];
4913             if((*data)->block_id == id)
4914             {
4915                 block_index = i;
4916                 break;
4917             }
4918         }
4919         if(block_index == -1)
4920         {
4921             for(i = 0; i < tng_data->n_data_blocks; i++)
4922             {
4923                 *data = &tng_data->non_tr_data[i];
4924                 if((*data)->block_id == id)
4925                 {
4926                     block_index = i;
4927                     break;
4928                 }
4929             }
4930         }
4931     }
4932     else
4933     {
4934         for(i = 0; i < tng_data->n_data_blocks; i++)
4935         {
4936             *data = &tng_data->non_tr_data[i];
4937             if((*data)->block_id == id)
4938             {
4939                 block_index = i;
4940                 break;
4941             }
4942         }
4943     }
4944     if(block_index == -1)
4945     {
4946         return(TNG_FAILURE);
4947     }
4948     return(TNG_SUCCESS);
4949 }
4950
4951 static tng_function_status tng_data_block_len_calculate
4952                 (const tng_trajectory_t tng_data,
4953                  const tng_data_t data,
4954                  const tng_bool is_particle_data,
4955                  const int64_t n_frames,
4956                  const int64_t frame_step,
4957                  const int64_t stride_length,
4958                  const int64_t num_first_particle,
4959                  const int64_t n_particles,
4960                  int64_t *data_start_pos,
4961                  int64_t *len)
4962 {
4963     int size;
4964     int64_t i, j, k;
4965     char ***first_dim_values, **second_dim_values;
4966     (void)tng_data;
4967
4968     if(data == 0)
4969     {
4970         return(TNG_SUCCESS);
4971     }
4972
4973     switch(data->datatype)
4974     {
4975     case TNG_CHAR_DATA:
4976         size = 1;
4977         break;
4978     case TNG_INT_DATA:
4979         size = sizeof(int64_t);
4980         break;
4981     case TNG_FLOAT_DATA:
4982         size = sizeof(float);
4983         break;
4984     case TNG_DOUBLE_DATA:
4985     default:
4986         size = sizeof(double);
4987     }
4988
4989     *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
4990            sizeof(data->codec_id);
4991     if(is_particle_data)
4992     {
4993         *len += sizeof(num_first_particle) + sizeof(n_particles);
4994     }
4995
4996     if(stride_length > 1)
4997     {
4998         *len += sizeof(data->first_frame_with_data) +
4999                 sizeof(data->stride_length);
5000     }
5001
5002     if(data->codec_id != TNG_UNCOMPRESSED)
5003     {
5004         *len += sizeof(data->compression_multiplier);
5005     }
5006
5007     if(data->dependency & TNG_FRAME_DEPENDENT)
5008     {
5009         *len += sizeof(char);
5010     }
5011
5012     *data_start_pos = *len;
5013
5014     if(data->datatype == TNG_CHAR_DATA)
5015     {
5016         if(is_particle_data)
5017         {
5018             for(i = 0; i < n_frames; i++)
5019             {
5020                 first_dim_values = data->strings[i];
5021                 for(j = num_first_particle; j < num_first_particle + n_particles;
5022                     j++)
5023                 {
5024                     second_dim_values = first_dim_values[j];
5025                     for(k = 0; k < data->n_values_per_frame; k++)
5026                     {
5027                         *len += strlen(second_dim_values[k]) + 1;
5028                     }
5029                 }
5030             }
5031         }
5032         else
5033         {
5034             for(i = 0; i < n_frames; i++)
5035             {
5036                 second_dim_values = data->strings[0][i];
5037                 for(j = 0; j < data->n_values_per_frame; j++)
5038                 {
5039                     *len += strlen(second_dim_values[j]) + 1;
5040                 }
5041             }
5042         }
5043     }
5044     else
5045     {
5046         *len += size * frame_step * n_particles * data->n_values_per_frame;
5047     }
5048
5049     return(TNG_SUCCESS);
5050 }
5051
5052 /* TEST: */
5053 /**
5054  * @brief Create a non-particle data block
5055  * @param tng_data is a trajectory data container.
5056  * @param block_type_flag specifies if this is a trajectory block or a
5057  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
5058  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5059  * error has occured.
5060  */
5061 static tng_function_status tng_data_block_create
5062                 (const tng_trajectory_t tng_data,
5063                  const char block_type_flag)
5064 {
5065     tng_trajectory_frame_set_t frame_set =
5066     &tng_data->current_trajectory_frame_set;
5067
5068     tng_data_t data;
5069
5070     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5071     {
5072         frame_set->n_data_blocks++;
5073         data = (tng_data_t)realloc(frame_set->tr_data, sizeof(struct tng_data) *
5074                                    frame_set->n_data_blocks);
5075         if(!data)
5076         {
5077             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5078                     __FILE__, __LINE__);
5079             free(frame_set->tr_data);
5080             frame_set->tr_data = 0;
5081             return(TNG_CRITICAL);
5082         }
5083         frame_set->tr_data = data;
5084     }
5085     else
5086     {
5087         tng_data->n_data_blocks++;
5088         data = (tng_data_t)realloc(tng_data->non_tr_data, sizeof(struct tng_data) *
5089                                    tng_data->n_data_blocks);
5090         if(!data)
5091         {
5092             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5093                     __FILE__, __LINE__);
5094             free(tng_data->non_tr_data);
5095             tng_data->non_tr_data = 0;
5096             return(TNG_CRITICAL);
5097         }
5098         tng_data->non_tr_data = data;
5099     }
5100
5101     return(TNG_SUCCESS);
5102 }
5103
5104 /* TEST: */
5105 /**
5106  * @brief Allocate memory for storing non-particle data.
5107  * The allocated block will be refered to by data->values.
5108  * @param tng_data is a trajectory data container.
5109  * @param data is the data struct, which will contain the allocated memory in
5110  * data->values.
5111  * @param n_frames is the number of frames of data to store.
5112  * @param n_values_per_frame is the number of data values per frame.
5113  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5114  * error has occured.
5115  */
5116 static tng_function_status tng_allocate_data_mem
5117                 (const tng_trajectory_t tng_data,
5118                  const tng_data_t data,
5119                  int64_t n_frames,
5120                  const int64_t stride_length,
5121                  const int64_t n_values_per_frame)
5122 {
5123     void **values;
5124     int64_t i, j, size, frame_alloc;
5125     (void)tng_data;
5126
5127     if(n_values_per_frame == 0)
5128     {
5129         return(TNG_FAILURE);
5130     }
5131
5132     if(data->strings && data->datatype == TNG_CHAR_DATA)
5133     {
5134         for(i = 0; i < data->n_frames; i++)
5135         {
5136             for(j = 0; j < data->n_values_per_frame; j++)
5137             {
5138                 if(data->strings[0][i][j])
5139                 {
5140                     free(data->strings[0][i][j]);
5141                     data->strings[0][i][j] = 0;
5142                 }
5143             }
5144             free(data->strings[0][i]);
5145             data->strings[0][i] = 0;
5146         }
5147         free(data->strings[0]);
5148         data->strings[0] = 0;
5149         free(data->strings);
5150     }
5151     data->n_frames = n_frames;
5152     data->stride_length = tng_max_i64(1, stride_length);
5153     n_frames = tng_max_i64(1, n_frames);
5154     data->n_values_per_frame = n_values_per_frame;
5155     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5156
5157     if(data->datatype == TNG_CHAR_DATA)
5158     {
5159         data->strings = (char ****)malloc(sizeof(char ***));
5160         data->strings[0] = (char ***)malloc(sizeof(char **) * frame_alloc);
5161         for(i = 0; i < frame_alloc; i++)
5162         {
5163             data->strings[0][i] = (char **)malloc(sizeof(char *) * n_values_per_frame);
5164             if(!data->strings[0][i])
5165             {
5166                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5167                         __FILE__, __LINE__);
5168                 return(TNG_CRITICAL);
5169             }
5170             for(j = 0; j < n_values_per_frame; j++)
5171             {
5172                 data->strings[0][i][j] = 0;
5173             }
5174         }
5175     }
5176     else
5177     {
5178         switch(data->datatype)
5179         {
5180         case TNG_INT_DATA:
5181             size = sizeof(int64_t);
5182             break;
5183         case TNG_FLOAT_DATA:
5184             size = sizeof(float);
5185             break;
5186         case TNG_DOUBLE_DATA:
5187         default:
5188             size = sizeof(double);
5189         }
5190
5191         values = (void **)realloc(data->values,
5192                                   size * frame_alloc *
5193                                   n_values_per_frame);
5194         if(!values)
5195         {
5196             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5197                     __FILE__, __LINE__);
5198             free(data->values);
5199             data->values = 0;
5200             return(TNG_CRITICAL);
5201         }
5202         data->values = values;
5203     }
5204
5205     return(TNG_SUCCESS);
5206 }
5207
5208 /**
5209  * @brief Read the values of a data block
5210  * @param tng_data is a trajectory data container.
5211  * @param block is the block to store the data (should already contain
5212  * the block headers and the block contents).
5213  * @param block_data_len is the length of the data contents of the block.
5214  * @param datatype is the type of data of the data block (char, int, float or
5215  * double).
5216  * @param num_first_particle is the number of the first particle in the data
5217  * block. This should be the same as in the corresponding particle mapping
5218  * block. Only used if reading particle dependent data.
5219  * @param n_particles is the number of particles in the data block. This should
5220  * be the same as in the corresponding particle mapping block. Only used if
5221  * reading particle dependent data.
5222  * @param first_frame_with_data is the frame number of the first frame with data
5223  * in this data block.
5224  * @param stride_length is the number of frames between each data entry.
5225  * @param n_frames is the number of frames in this data block.
5226  * @param n_values is the number of values per frame stored in this data block.
5227  * @param codec_id is the ID of the codec to compress the data.
5228  * @param multiplier is the multiplication factor applied to each data value
5229  * before compression. This factor is applied since some compression algorithms
5230  * work only on integers.
5231  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
5232  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
5233  * if hash_mode == TNG_USE_HASH.
5234  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5235  * error has occured.
5236  */
5237 static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
5238                                          const tng_gen_block_t block,
5239                                          const int64_t block_data_len,
5240                                          const char datatype,
5241                                          const int64_t num_first_particle,
5242                                          const int64_t n_particles,
5243                                          const int64_t first_frame_with_data,
5244                                          const int64_t stride_length,
5245                                          int64_t n_frames,
5246                                          const int64_t n_values,
5247                                          const int64_t codec_id,
5248                                          const double multiplier,
5249                                          const char hash_mode,
5250                                          md5_state_t *md5_state)
5251 {
5252     int64_t i, j, k, tot_n_particles, n_frames_div, offset;
5253     int64_t full_data_len;
5254     int size, len;
5255     char ***first_dim_values, **second_dim_values;
5256     tng_data_t data;
5257     tng_trajectory_frame_set_t frame_set =
5258     &tng_data->current_trajectory_frame_set;
5259     char block_type_flag, *contents;
5260     tng_bool is_particle_data;
5261     tng_function_status stat;
5262
5263 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
5264
5265     switch(datatype)
5266     {
5267     case TNG_CHAR_DATA:
5268         size = 1;
5269         break;
5270     case TNG_INT_DATA:
5271         size = sizeof(int64_t);
5272         break;
5273     case TNG_FLOAT_DATA:
5274         size = sizeof(float);
5275         break;
5276     case TNG_DOUBLE_DATA:
5277     default:
5278         size = sizeof(double);
5279     }
5280
5281     if(n_particles > 0)
5282     {
5283         is_particle_data = TNG_TRUE;
5284     }
5285     else
5286     {
5287         if(codec_id == TNG_XTC_COMPRESSION || codec_id == TNG_TNG_COMPRESSION)
5288         {
5289             fprintf(stderr, "TNG library: Cannot uncompress data block. %s: %d\n", __FILE__,
5290                     __LINE__);
5291             return(TNG_FAILURE);
5292         }
5293         is_particle_data = TNG_FALSE;
5294     }
5295
5296     if(is_particle_data == TNG_TRUE)
5297     {
5298         stat = tng_particle_data_find(tng_data, block->id, &data);
5299     }
5300     else
5301     {
5302         stat = tng_data_find(tng_data, block->id, &data);
5303     }
5304
5305     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5306     {
5307         block_type_flag = TNG_TRAJECTORY_BLOCK;
5308     }
5309     else
5310     {
5311         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5312     }
5313
5314     /* If the block does not exist, create it */
5315     if(stat != TNG_SUCCESS)
5316     {
5317         if(is_particle_data == TNG_TRUE)
5318         {
5319             stat = tng_particle_data_block_create(tng_data, block_type_flag);
5320         }
5321         else
5322         {
5323             stat = tng_data_block_create(tng_data, block_type_flag);
5324         }
5325
5326         if(stat != TNG_SUCCESS)
5327         {
5328             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
5329                    __FILE__, __LINE__);
5330             return(TNG_CRITICAL);
5331         }
5332
5333         if(is_particle_data == TNG_TRUE)
5334         {
5335             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5336             {
5337                 data = &frame_set->tr_particle_data[frame_set->
5338                                                     n_particle_data_blocks - 1];
5339             }
5340             else
5341             {
5342                 data = &tng_data->non_tr_particle_data[tng_data->
5343                                                        n_particle_data_blocks - 1];
5344             }
5345         }
5346         else
5347         {
5348             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5349             {
5350                 data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
5351             }
5352             else
5353             {
5354                 data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
5355             }
5356         }
5357
5358         data->block_id = block->id;
5359
5360         data->block_name = (char *)malloc(strlen(block->name) + 1);
5361         if(!data->block_name)
5362         {
5363             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5364                     __FILE__, __LINE__);
5365             return(TNG_CRITICAL);
5366         }
5367         strcpy(data->block_name, block->name);
5368
5369         data->datatype = datatype;
5370
5371         data->values = 0;
5372         /* FIXME: Memory leak from strings. */
5373         data->strings = 0;
5374         data->n_frames = 0;
5375         data->dependency = 0;
5376         if(is_particle_data == TNG_TRUE)
5377         {
5378             data->dependency += TNG_PARTICLE_DEPENDENT;
5379         }
5380         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
5381                               (n_frames > 1 ||
5382                                frame_set->n_frames == n_frames ||
5383                                stride_length > 1))
5384         {
5385             data->dependency += TNG_FRAME_DEPENDENT;
5386         }
5387         data->codec_id = codec_id;
5388         data->compression_multiplier = multiplier;
5389         data->last_retrieved_frame = -1;
5390     }
5391
5392     if(is_particle_data == TNG_TRUE)
5393     {
5394         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
5395            tng_data->var_num_atoms_flag)
5396         {
5397             tot_n_particles = frame_set->n_particles;
5398         }
5399         else
5400         {
5401             tot_n_particles = tng_data->n_particles;
5402         }
5403     }
5404     /* If there are no particles in this data block, still set tot_n_particles = 1
5405      * to calculate block lengths etc properly. */
5406     else
5407     {
5408         tot_n_particles = 1;
5409     }
5410
5411     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5412
5413     contents = (char *)malloc(block_data_len);
5414     if(!contents)
5415     {
5416         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5417                 __FILE__, __LINE__);
5418         return(TNG_CRITICAL);
5419     }
5420
5421     if(fread(contents, block_data_len, 1, tng_data->input_file) == 0)
5422     {
5423         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
5424         return(TNG_CRITICAL);
5425     }
5426
5427     if(hash_mode == TNG_USE_HASH)
5428     {
5429         md5_append(md5_state, (md5_byte_t *)contents, block_data_len);
5430     }
5431
5432     if(codec_id != TNG_UNCOMPRESSED)
5433     {
5434         full_data_len = n_frames_div * size * n_values;
5435         if(is_particle_data == TNG_TRUE)
5436         {
5437             full_data_len *= n_particles;
5438         }
5439         switch(codec_id)
5440         {
5441         case TNG_XTC_COMPRESSION:
5442             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5443             break;
5444         case TNG_TNG_COMPRESSION:
5445 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/
5446             if(tng_uncompress(tng_data, block, datatype,
5447                               &contents, full_data_len) != TNG_SUCCESS)
5448             {
5449                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5450                        __FILE__, __LINE__);
5451                 free(contents);
5452                 return(TNG_CRITICAL);
5453             }
5454 /*            fprintf(stderr, "TNG library: After TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/
5455             break;
5456         case TNG_GZIP_COMPRESSION:
5457     /*         fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */
5458             if(tng_gzip_uncompress(tng_data, &contents,
5459                                    block_data_len, full_data_len) != TNG_SUCCESS)
5460             {
5461                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5462                     __LINE__);
5463                 free(contents);
5464                 return(TNG_CRITICAL);
5465             }
5466     /*         fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */
5467             break;
5468         }
5469     }
5470     else
5471     {
5472         full_data_len = block_data_len;
5473     }
5474
5475     /* Allocate memory */
5476     if(!data->values || data->n_frames != n_frames ||
5477        data->n_values_per_frame != n_values)
5478     {
5479         if(is_particle_data == TNG_TRUE)
5480         {
5481             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
5482                                                   stride_length,
5483                                                   tot_n_particles, n_values);
5484         }
5485         else
5486         {
5487             stat = tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
5488                                          n_values);
5489         }
5490         if(stat != TNG_SUCCESS)
5491         {
5492             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
5493                    __FILE__, __LINE__);
5494             free(contents);
5495             return(TNG_CRITICAL);
5496         }
5497     }
5498
5499     data->first_frame_with_data = first_frame_with_data;
5500
5501     if(datatype == TNG_CHAR_DATA)
5502     {
5503         offset = 0;
5504         /* Strings are stores slightly differently if the data block contains particle
5505          * data (frames * particles * n_values) or not (frames * n_values). */
5506         if(is_particle_data == TNG_TRUE)
5507         {
5508             for(i = 0; i < n_frames_div; i++)
5509             {
5510                 first_dim_values = data->strings[i];
5511                 for(j = num_first_particle; j < num_first_particle + n_particles;
5512                     j++)
5513                 {
5514                     second_dim_values = first_dim_values[j];
5515                     for(k = 0; k < n_values; k++)
5516                     {
5517                         len = tng_min_size(strlen(contents+offset) + 1,
5518                                   TNG_MAX_STR_LEN);
5519                         if(second_dim_values[k])
5520                         {
5521                             free(second_dim_values[k]);
5522                         }
5523                         second_dim_values[k] = (char *)malloc(len);
5524                         if(!second_dim_values[k])
5525                         {
5526                             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5527                                     __FILE__, __LINE__);
5528                             free(contents);
5529                             return(TNG_CRITICAL);
5530                         }
5531                         strncpy(second_dim_values[k], contents+offset, len);
5532                         offset += len;
5533                     }
5534                 }
5535             }
5536         }
5537         else
5538         {
5539             for(i = 0; i < n_frames_div; i++)
5540             {
5541                 for(j = 0; j < n_values; j++)
5542                 {
5543                     len = tng_min_size(strlen(contents+offset) + 1,
5544                                      TNG_MAX_STR_LEN);
5545                     if(data->strings[0][i][j])
5546                     {
5547                         free(data->strings[0][i][j]);
5548                     }
5549                     data->strings[0][i][j] = (char *)malloc(len);
5550                     if(!data->strings[0][i][j])
5551                     {
5552                         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5553                                 __FILE__, __LINE__);
5554                         free(contents);
5555                         return(TNG_CRITICAL);
5556                     }
5557                     strncpy(data->strings[0][i][j], contents+offset, len);
5558                     offset += len;
5559                 }
5560             }
5561         }
5562     }
5563     else
5564     {
5565         if(is_particle_data)
5566         {
5567             memcpy((char *)data->values + n_frames_div * size * n_values *
5568                    num_first_particle, contents, full_data_len);
5569         }
5570         else
5571         {
5572             memcpy(data->values, contents, full_data_len);
5573         }
5574         /* Endianness is handled by the TNG compression library. TNG compressed blocks are always written
5575          * as little endian by the compression library. */
5576         if(codec_id != TNG_TNG_COMPRESSION)
5577         {
5578             switch(datatype)
5579             {
5580             case TNG_FLOAT_DATA:
5581                 if(tng_data->input_endianness_swap_func_32)
5582                 {
5583                     for(i = 0; i < full_data_len; i+=size)
5584                     {
5585                         if(tng_data->input_endianness_swap_func_32(tng_data,
5586                             (uint32_t *)((char *)data->values + i))
5587                             != TNG_SUCCESS)
5588                         {
5589                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5590                                     __FILE__, __LINE__);
5591                         }
5592                     }
5593                 }
5594                 break;
5595             case TNG_INT_DATA:
5596             case TNG_DOUBLE_DATA:
5597                 if(tng_data->input_endianness_swap_func_64)
5598                 {
5599                     for(i = 0; i < full_data_len; i+=size)
5600                     {
5601                         if(tng_data->input_endianness_swap_func_64(tng_data,
5602                             (uint64_t *)((char *)data->values + i))
5603                             != TNG_SUCCESS)
5604                         {
5605                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5606                                     __FILE__, __LINE__);
5607                         }
5608                     }
5609                 }
5610                 break;
5611             case TNG_CHAR_DATA:
5612                 break;
5613             }
5614         }
5615     }
5616
5617     free(contents);
5618
5619     return(TNG_SUCCESS);
5620 }
5621
5622 /**
5623  * @brief Write a data block (particle or non-particle data)
5624  * @param tng_data is a trajectory data container.
5625  * @param block is the block to store the data (should already contain
5626  * the block headers and the block contents).
5627  * @param block_index is the index number of the data block in the frame set.
5628  * @param is_particle_data is a flag to specify if the data to write is
5629  * particle dependent or not.
5630  * @param mapping is the particle mapping that is relevant for the data block.
5631  * Only relevant if writing particle dependent data.
5632  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5633  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5634  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5635  * error has occured.
5636  */
5637 static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
5638                                                 const tng_gen_block_t block,
5639                                                 const int64_t block_index,
5640                                                 const tng_bool is_particle_data,
5641                                                 const tng_particle_mapping_t mapping,
5642                                                 const char hash_mode)
5643 {
5644     int64_t n_particles, num_first_particle, n_frames, stride_length;
5645     int64_t full_data_len, block_data_len, frame_step, data_start_pos;
5646     int64_t i, j, k, curr_file_pos, header_file_pos;
5647     int size;
5648     size_t len;
5649     tng_function_status stat;
5650     char temp, *temp_name, ***first_dim_values, **second_dim_values, *contents;
5651     double multiplier;
5652     tng_trajectory_frame_set_t frame_set =
5653     &tng_data->current_trajectory_frame_set;
5654     tng_data_t data;
5655     char block_type_flag;
5656     md5_state_t md5_state;
5657
5658     /* If we have already started writing frame sets it is too late to write
5659      * non-trajectory data blocks */
5660     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5661     {
5662         block_type_flag = TNG_TRAJECTORY_BLOCK;
5663     }
5664     else
5665     {
5666         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5667     }
5668
5669     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5670     {
5671         return(TNG_CRITICAL);
5672     }
5673
5674     if(is_particle_data == TNG_TRUE)
5675     {
5676         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5677         {
5678             data = &frame_set->tr_particle_data[block_index];
5679
5680             /* If this data block has not had any data added in this frame set
5681              * do not write it. */
5682             if(data->first_frame_with_data < frame_set->first_frame)
5683             {
5684                 return(TNG_SUCCESS);
5685             }
5686
5687             stride_length = tng_max_i64(1, data->stride_length);
5688         }
5689         else
5690         {
5691             data = &tng_data->non_tr_particle_data[block_index];
5692             stride_length = 1;
5693         }
5694     }
5695     else
5696     {
5697         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5698         {
5699             data = &frame_set->tr_data[block_index];
5700
5701             /* If this data block has not had any data added in this frame set
5702              * do not write it. */
5703             if(data->first_frame_with_data < frame_set->first_frame)
5704             {
5705                 return(TNG_SUCCESS);
5706             }
5707
5708             stride_length = tng_max_i64(1, data->stride_length);
5709         }
5710         else
5711         {
5712             data = &tng_data->non_tr_data[block_index];
5713             stride_length = 1;
5714         }
5715     }
5716
5717     switch(data->datatype)
5718     {
5719     case TNG_CHAR_DATA:
5720         size = 1;
5721         break;
5722     case TNG_INT_DATA:
5723         size = sizeof(int64_t);
5724         break;
5725     case TNG_FLOAT_DATA:
5726         size = sizeof(float);
5727         break;
5728     case TNG_DOUBLE_DATA:
5729     default:
5730         size = sizeof(double);
5731     }
5732
5733     len = strlen(data->block_name) + 1;
5734
5735     if(!block->name || strlen(block->name) < len)
5736     {
5737         temp_name = (char *)realloc(block->name, len);
5738         if(!temp_name)
5739         {
5740             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5741                    __FILE__, __LINE__);
5742             free(block->name);
5743             block->name = 0;
5744             return(TNG_CRITICAL);
5745         }
5746         block->name = temp_name;
5747     }
5748     strncpy(block->name, data->block_name, len);
5749     block->id = data->block_id;
5750
5751     /* If writing frame independent data data->n_frames is 0, but n_frames
5752        is used for the loop writing the data (and reserving memory) and needs
5753        to be at least 1 */
5754     n_frames = tng_max_i64(1, data->n_frames);
5755
5756     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5757     {
5758         /* If the frame set is finished before writing the full number of frames
5759            make sure the data block is not longer than the frame set. */
5760         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5761
5762         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5763     }
5764
5765     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
5766                  n_frames / stride_length;
5767
5768     /* TNG compression will use compression precision to get integers from
5769      * floating point data. The compression multiplier stores that information
5770      * to be able to return the precision of the compressed data. */
5771     if(data->codec_id == TNG_TNG_COMPRESSION)
5772     {
5773         data->compression_multiplier = tng_data->compression_precision;
5774     }
5775     /* Uncompressed data blocks do not use compression multipliers at all.
5776      * GZip compression does not need it either. */
5777     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
5778     {
5779         data->compression_multiplier = 1.0;
5780     }
5781
5782     if(data->dependency & TNG_PARTICLE_DEPENDENT)
5783     {
5784         if(mapping && mapping->n_particles != 0)
5785         {
5786             n_particles = mapping->n_particles;
5787             num_first_particle = mapping->num_first_particle;
5788         }
5789         else
5790         {
5791             num_first_particle = 0;
5792             if(tng_data->var_num_atoms_flag)
5793             {
5794                 n_particles = frame_set->n_particles;
5795             }
5796             else
5797             {
5798                 n_particles = tng_data->n_particles;
5799             }
5800         }
5801     }
5802     else
5803     {
5804         /* This just appeases gcc-7 -Wmaybe-uninitialized.
5805          * FIXME: It would be better to refactor so that
5806          * TNG_PARTICLE_DEPENDENT triggers two distinct code paths.
5807          */
5808         num_first_particle = -1;
5809         n_particles = -1;
5810     }
5811
5812     if(data->dependency & TNG_PARTICLE_DEPENDENT)
5813     {
5814         if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
5815                                         frame_step, stride_length, num_first_particle,
5816                                         n_particles, &data_start_pos,
5817                                         &block->block_contents_size) != TNG_SUCCESS)
5818         {
5819             fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
5820                     __FILE__, __LINE__);
5821             return(TNG_CRITICAL);
5822         }
5823     }
5824     else
5825     {
5826         if(tng_data_block_len_calculate(tng_data, data, TNG_FALSE, n_frames,
5827                                         frame_step, stride_length, 0,
5828                                         1, &data_start_pos,
5829                                         &block->block_contents_size) != TNG_SUCCESS)
5830         {
5831             fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
5832                     __FILE__, __LINE__);
5833             return(TNG_CRITICAL);
5834         }
5835     }
5836
5837     header_file_pos = ftello(tng_data->output_file);
5838
5839     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
5840     {
5841         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
5842                tng_data->output_file_path, __FILE__, __LINE__);
5843         return(TNG_CRITICAL);
5844     }
5845
5846     if(hash_mode == TNG_USE_HASH)
5847     {
5848         md5_init(&md5_state);
5849     }
5850
5851     if(tng_file_output_numerical(tng_data, &data->datatype,
5852                                  sizeof(data->datatype),
5853                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5854     {
5855         return(TNG_CRITICAL);
5856     }
5857
5858     if(tng_file_output_numerical(tng_data, &data->dependency,
5859                                  sizeof(data->dependency),
5860                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5861     {
5862         return(TNG_CRITICAL);
5863     }
5864
5865     if(data->dependency & TNG_FRAME_DEPENDENT)
5866     {
5867         if(stride_length > 1)
5868         {
5869             temp = 1;
5870         }
5871         else
5872         {
5873             temp = 0;
5874         }
5875         if(tng_file_output_numerical(tng_data, &temp,
5876                                     sizeof(temp),
5877                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5878         {
5879             return(TNG_CRITICAL);
5880         }
5881     }
5882
5883     if(tng_file_output_numerical(tng_data, &data->n_values_per_frame,
5884                                  sizeof(data->n_values_per_frame),
5885                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5886     {
5887         return(TNG_CRITICAL);
5888     }
5889
5890     if(tng_file_output_numerical(tng_data, &data->codec_id,
5891                                  sizeof(data->codec_id),
5892                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5893     {
5894         return(TNG_CRITICAL);
5895     }
5896
5897     if(data->codec_id != TNG_UNCOMPRESSED)
5898     {
5899         if(tng_file_output_numerical(tng_data, &data->compression_multiplier,
5900                                     sizeof(data->compression_multiplier),
5901                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5902         {
5903             return(TNG_CRITICAL);
5904         }
5905     }
5906
5907     if(data->n_frames > 0 && stride_length > 1)
5908     {
5909         /* FIXME: first_frame_with_data is not reliably set */
5910         if(data->first_frame_with_data == 0)
5911         {
5912             data->first_frame_with_data = frame_set->first_frame;
5913         }
5914         if(tng_file_output_numerical(tng_data, &data->first_frame_with_data,
5915                                     sizeof(data->first_frame_with_data),
5916                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5917         {
5918             return(TNG_CRITICAL);
5919         }
5920
5921         if(tng_file_output_numerical(tng_data, &stride_length,
5922                                     sizeof(stride_length),
5923                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5924         {
5925             return(TNG_CRITICAL);
5926         }
5927     }
5928
5929     if(data->dependency & TNG_PARTICLE_DEPENDENT)
5930     {
5931         if(tng_file_output_numerical(tng_data, &num_first_particle,
5932                                      sizeof(num_first_particle),
5933                                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5934         {
5935             return(TNG_CRITICAL);
5936         }
5937
5938         if(tng_file_output_numerical(tng_data, &n_particles,
5939                                      sizeof(n_particles),
5940                                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5941         {
5942             return(TNG_CRITICAL);
5943         }
5944     }
5945
5946     if(data->datatype == TNG_CHAR_DATA)
5947     {
5948         if(data->strings)
5949         {
5950             if(data->dependency & TNG_PARTICLE_DEPENDENT)
5951             {
5952                 for(i = 0; i < frame_step; i++)
5953                 {
5954                     first_dim_values = data->strings[i];
5955                     for(j = num_first_particle; j < num_first_particle + n_particles;
5956                         j++)
5957                     {
5958                         second_dim_values = first_dim_values[j];
5959                         for(k = 0; k < data->n_values_per_frame; k++)
5960                         {
5961                             if(tng_fwritestr(tng_data, second_dim_values[k],
5962                                             hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5963                             {
5964                                 return(TNG_CRITICAL);
5965                             }
5966                         }
5967                     }
5968                 }
5969             }
5970             else
5971             {
5972                 for(i = 0; i < frame_step; i++)
5973                 {
5974                     for(j = 0; j < data->n_values_per_frame; j++)
5975                     {
5976                         if(tng_fwritestr(tng_data, data->strings[0][i][j],
5977                                          hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5978                         {
5979                             return(TNG_CRITICAL);
5980                         }
5981                     }
5982                 }
5983             }
5984         }
5985     }
5986     else
5987     {
5988         if(data->dependency & TNG_PARTICLE_DEPENDENT)
5989         {
5990             full_data_len = size * frame_step * n_particles * data->n_values_per_frame;
5991         }
5992         else
5993         {
5994             full_data_len = size * frame_step * data->n_values_per_frame;
5995         }
5996         contents = (char *)malloc(full_data_len);
5997         if(!contents)
5998         {
5999             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6000                     __FILE__, __LINE__);
6001             return(TNG_CRITICAL);
6002         }
6003
6004         if(data->values)
6005         {
6006             memcpy(contents, data->values, full_data_len);
6007             /* If writing TNG compressed data the endianness is taken into account by the compression
6008              * routines. TNG compressed data is always written as little endian. */
6009             if(data->codec_id != TNG_TNG_COMPRESSION)
6010             {
6011                 switch(data->datatype)
6012                 {
6013                 case TNG_FLOAT_DATA:
6014                     if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6015                     {
6016                         if(tng_data->output_endianness_swap_func_32)
6017                         {
6018                             for(i = 0; i < full_data_len; i+=size)
6019                             {
6020                                 if(tng_data->output_endianness_swap_func_32(tng_data,
6021                                 (uint32_t *)(contents + i))
6022                                 != TNG_SUCCESS)
6023                                 {
6024                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6025                                             __FILE__, __LINE__);
6026                                 }
6027                             }
6028                         }
6029                     }
6030                     else
6031                     {
6032                         multiplier = data->compression_multiplier;
6033                         if(fabs(multiplier - 1.0) > 0.00001 ||
6034                         tng_data->output_endianness_swap_func_32)
6035                         {
6036                             for(i = 0; i < full_data_len; i+=size)
6037                             {
6038                                 *(float *)(contents + i) *= (float)multiplier;
6039                                 if(tng_data->output_endianness_swap_func_32 &&
6040                                 tng_data->output_endianness_swap_func_32(tng_data,
6041                                 (uint32_t *)(contents + i))
6042                                 != TNG_SUCCESS)
6043                                 {
6044                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6045                                             __FILE__, __LINE__);
6046                                 }
6047                             }
6048                         }
6049                     }
6050                     break;
6051                 case TNG_INT_DATA:
6052                     if(tng_data->output_endianness_swap_func_64)
6053                     {
6054                         for(i = 0; i < full_data_len; i+=size)
6055                         {
6056                             if(tng_data->output_endianness_swap_func_64(tng_data,
6057                             (uint64_t *)(contents + i))
6058                             != TNG_SUCCESS)
6059                             {
6060                                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6061                                         __FILE__, __LINE__);
6062                             }
6063                         }
6064                     }
6065                     break;
6066                 case TNG_DOUBLE_DATA:
6067                     if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION)
6068                     {
6069                         if(tng_data->output_endianness_swap_func_64)
6070                         {
6071                             for(i = 0; i < full_data_len; i+=size)
6072                             {
6073                                 if(tng_data->output_endianness_swap_func_64(tng_data,
6074                                 (uint64_t *)(contents + i))
6075                                 != TNG_SUCCESS)
6076                                 {
6077                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6078                                             __FILE__, __LINE__);
6079                                 }
6080                             }
6081                         }
6082                     }
6083                     else
6084                     {
6085                         multiplier = data->compression_multiplier;
6086                         if(fabs(multiplier - 1.0) > 0.00001 ||
6087                         tng_data->output_endianness_swap_func_64)
6088                         {
6089                             for(i = 0; i < full_data_len; i+=size)
6090                             {
6091                                 *(double *)(contents + i) *= multiplier;
6092                                 if(tng_data->output_endianness_swap_func_64 &&
6093                                 tng_data->output_endianness_swap_func_64(tng_data,
6094                                 (uint64_t *)(contents + i))
6095                                 != TNG_SUCCESS)
6096                                 {
6097                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6098                                             __FILE__, __LINE__);
6099                                 }
6100                             }
6101                         }
6102                     }
6103                     break;
6104                 case TNG_CHAR_DATA:
6105                     break;
6106                 }
6107             }
6108         }
6109         else
6110         {
6111             memset(contents, 0, full_data_len);
6112         }
6113
6114         block_data_len = full_data_len;
6115
6116         switch(data->codec_id)
6117         {
6118         case TNG_XTC_COMPRESSION:
6119             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6120             data->codec_id = TNG_UNCOMPRESSED;
6121             break;
6122         case TNG_TNG_COMPRESSION:
6123             stat = tng_compress(tng_data, block, frame_step,
6124                                 n_particles, data->datatype,
6125                                 &contents, &block_data_len);
6126             if(stat != TNG_SUCCESS)
6127             {
6128                 fprintf(stderr, "TNG library: Could not write TNG compressed block data. %s: %d\n",
6129                     __FILE__, __LINE__);
6130                 if(stat == TNG_CRITICAL)
6131                 {
6132                     return(TNG_CRITICAL);
6133                 }
6134                 /* Set the data again, but with no compression (to write only
6135                  * the relevant data) */
6136                 data->codec_id = TNG_UNCOMPRESSED;
6137                 stat = tng_data_block_write(tng_data, block,
6138                                             block_index, is_particle_data, mapping,
6139                                             hash_mode);
6140                 free(contents);
6141                 return(stat);
6142             }
6143             break;
6144         case TNG_GZIP_COMPRESSION:
6145     /*         fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */
6146             stat = tng_gzip_compress(tng_data,
6147                                      &contents,
6148                                      full_data_len,
6149                                      &block_data_len);
6150             if(stat != TNG_SUCCESS)
6151             {
6152                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6153                     __LINE__);
6154                 if(stat == TNG_CRITICAL)
6155                 {
6156                     return(TNG_CRITICAL);
6157                 }
6158                 data->codec_id = TNG_UNCOMPRESSED;
6159             }
6160     /*         fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */
6161             break;
6162         }
6163         if(block_data_len != full_data_len)
6164         {
6165             block->block_contents_size -= full_data_len - block_data_len;
6166
6167             curr_file_pos = ftello(tng_data->output_file);
6168             fseeko(tng_data->output_file, header_file_pos + sizeof(block->header_contents_size), SEEK_SET);
6169
6170             if(tng_file_output_numerical(tng_data, &block->block_contents_size,
6171                                          sizeof(block->block_contents_size),
6172                                          TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
6173             {
6174                 return(TNG_CRITICAL);
6175             }
6176             fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
6177         }
6178         if(fwrite(contents, block_data_len, 1, tng_data->output_file) != 1)
6179         {
6180             fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6181                     __LINE__);
6182             return(TNG_CRITICAL);
6183         }
6184         if(hash_mode == TNG_USE_HASH)
6185         {
6186             md5_append(&md5_state, (md5_byte_t *)contents, block_data_len);
6187         }
6188
6189         free(contents);
6190     }
6191
6192     if(hash_mode == TNG_USE_HASH)
6193     {
6194         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
6195         curr_file_pos = ftello(tng_data->output_file);
6196         fseeko(tng_data->output_file, header_file_pos +
6197                 3 * sizeof(int64_t), SEEK_SET);
6198         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
6199         {
6200             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
6201                     __LINE__);
6202             return(TNG_CRITICAL);
6203         }
6204         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
6205     }
6206
6207     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6208     frame_set->n_unwritten_frames = 0;
6209
6210     return(TNG_SUCCESS);
6211 }
6212
6213 /**
6214  * @brief Read the meta information of a data block (particle or non-particle data).
6215  * @param tng_data is a trajectory data container.
6216  * @param datatype is set to the datatype of the data block.
6217  * @param dependency is set to the dependency (particle and/or frame dependent)
6218  * @param sparse_data is set to TRUE if data is not written every frame.
6219  * @param n_values is set to the number of values per frame of the data.
6220  * @param codec_id is set to the ID of the codec used to compress the data.
6221  * @param first_frame_with_data is set to the first frame with data (only relevant if
6222  * sparse_data == TRUE).
6223  * @param stride_length is set to the writing interval of the data (1 if sparse_data
6224  * == FALSE).
6225  * @param num_first_particle is set to the number of the first particle with data written
6226  * in this block.
6227  * @param block_n_particles is set to the number of particles in this data block.
6228  * @param multiplier is set to the compression multiplier.
6229  * @param hash_mode specifies whether to check if the hash matches the contents or not.
6230  * @param md5_state is the md5 hash of the block (only used if hash_mode == TNG_USE_HASH).
6231  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6232  * error has occured.
6233  */
6234 static tng_function_status tng_data_block_meta_information_read
6235                 (const tng_trajectory_t tng_data,
6236                  char *datatype,
6237                  char *dependency,
6238                  char *sparse_data,
6239                  int64_t *n_values,
6240                  int64_t *codec_id,
6241                  int64_t *first_frame_with_data,
6242                  int64_t *stride_length,
6243                  int64_t *n_frames,
6244                  int64_t *num_first_particle,
6245                  int64_t *block_n_particles,
6246                  double *multiplier,
6247                  const char hash_mode,
6248                  md5_state_t *md5_state)
6249 {
6250     if(tng_file_input_numerical(tng_data, datatype,
6251                                 sizeof(*datatype),
6252                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6253     {
6254         return(TNG_CRITICAL);
6255     }
6256
6257     if(tng_file_input_numerical(tng_data, dependency,
6258                                 sizeof(*dependency),
6259                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6260     {
6261         return(TNG_CRITICAL);
6262     }
6263
6264     if(*dependency & TNG_FRAME_DEPENDENT)
6265     {
6266         if(tng_file_input_numerical(tng_data, sparse_data,
6267                                     sizeof(*sparse_data),
6268                                     hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6269         {
6270             return(TNG_CRITICAL);
6271         }
6272     }
6273
6274     if(tng_file_input_numerical(tng_data, n_values,
6275                                 sizeof(*n_values),
6276                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6277     {
6278         return(TNG_CRITICAL);
6279     }
6280
6281     if(tng_file_input_numerical(tng_data, codec_id,
6282                                 sizeof(*codec_id),
6283                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6284     {
6285         return(TNG_CRITICAL);
6286     }
6287
6288     if(*codec_id != TNG_UNCOMPRESSED)
6289     {
6290         if(tng_file_input_numerical(tng_data, multiplier,
6291                                     sizeof(*multiplier),
6292                                     hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6293         {
6294             return(TNG_CRITICAL);
6295         }
6296     }
6297     else
6298     {
6299         *multiplier = 1;
6300     }
6301
6302     if(*dependency & TNG_FRAME_DEPENDENT)
6303     {
6304         if(*sparse_data)
6305         {
6306             if(tng_file_input_numerical(tng_data, first_frame_with_data,
6307                                         sizeof(*first_frame_with_data),
6308                                         hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6309             {
6310                 return(TNG_CRITICAL);
6311             }
6312
6313             if(tng_file_input_numerical(tng_data, stride_length,
6314                                         sizeof(*stride_length),
6315                                         hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6316             {
6317                 return(TNG_CRITICAL);
6318             }
6319
6320             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
6321                         (*first_frame_with_data -
6322                         tng_data->current_trajectory_frame_set.first_frame);
6323         }
6324         else
6325         {
6326             *first_frame_with_data = tng_data->current_trajectory_frame_set.first_frame;
6327             *stride_length = 1;
6328             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
6329         }
6330     }
6331     else
6332     {
6333         *first_frame_with_data = 0;
6334         *stride_length = 1;
6335         *n_frames = 1;
6336     }
6337
6338     if (*dependency & TNG_PARTICLE_DEPENDENT)
6339     {
6340         if(tng_file_input_numerical(tng_data, num_first_particle,
6341                                     sizeof(*num_first_particle),
6342                                     hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6343         {
6344             return(TNG_CRITICAL);
6345         }
6346
6347         if(tng_file_input_numerical(tng_data, block_n_particles,
6348                                     sizeof(*block_n_particles),
6349                                     hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6350         {
6351             return(TNG_CRITICAL);
6352         }
6353     }
6354     else
6355     {
6356         *num_first_particle = -1;
6357         *block_n_particles = 0;
6358     }
6359
6360     return(TNG_SUCCESS);
6361 }
6362
6363 /**
6364  * @brief Read the contents of a data block (particle or non-particle data).
6365  * @param tng_data is a trajectory data container.
6366  * @param block is the block to store the data (should already contain
6367  * the block headers).
6368  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6369  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
6370  * compared to the md5 hash of the read contents to ensure valid data.
6371  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6372  * error has occured.
6373  */
6374 static tng_function_status tng_data_block_contents_read
6375                 (const tng_trajectory_t tng_data,
6376                  const tng_gen_block_t block,
6377                  const char hash_mode)
6378 {
6379     int64_t start_pos, n_values, codec_id, n_frames, first_frame_with_data;
6380     int64_t remaining_len, stride_length, block_n_particles, num_first_particle;
6381     double multiplier;
6382     char datatype, dependency, sparse_data;
6383     tng_function_status stat = TNG_SUCCESS;
6384     char hash[TNG_MD5_HASH_LEN];
6385     md5_state_t md5_state;
6386
6387     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
6388     {
6389         return(TNG_CRITICAL);
6390     }
6391
6392     start_pos = ftello(tng_data->input_file);
6393
6394     if(hash_mode == TNG_USE_HASH)
6395     {
6396         md5_init(&md5_state);
6397     }
6398
6399     /* FIXME: Does not check if the size of the contents matches the expected
6400      * size or if the contents can be read. */
6401
6402     if(tng_data_block_meta_information_read(tng_data,
6403                                             &datatype,
6404                                             &dependency, &sparse_data,
6405                                             &n_values, &codec_id,
6406                                             &first_frame_with_data,
6407                                             &stride_length, &n_frames,
6408                                             &num_first_particle,
6409                                             &block_n_particles,
6410                                             &multiplier,
6411                                             hash_mode,
6412                                             &md5_state) == TNG_CRITICAL)
6413     {
6414         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
6415             block->name, __FILE__, __LINE__);
6416         return(TNG_CRITICAL);
6417     }
6418
6419     remaining_len = block->block_contents_size - (ftello(tng_data->input_file) - start_pos);
6420
6421     stat = tng_data_read(tng_data, block,
6422                          remaining_len,
6423                          datatype,
6424                          num_first_particle,
6425                          block_n_particles,
6426                          first_frame_with_data,
6427                          stride_length,
6428                          n_frames, n_values,
6429                          codec_id, multiplier,
6430                          hash_mode,
6431                          &md5_state);
6432
6433     if(hash_mode == TNG_USE_HASH)
6434     {
6435         /* If there is data left in the block that the current version of the library
6436          * cannot interpret still read that to generate the MD5 hash. */
6437         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
6438
6439         md5_finish(&md5_state, (md5_byte_t *)hash);
6440         if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
6441         {
6442             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
6443             {
6444                 fprintf(stderr, "TNG library: Data block contents corrupt (%s). Hashes do not match. "
6445                         "%s: %d\n", block->name, __FILE__, __LINE__);
6446             }
6447         }
6448     }
6449     else
6450     {
6451         /* Seek to the end of the block */
6452         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
6453     }
6454
6455     return(stat);
6456 }
6457
6458 /*
6459 // ** Move the blocks in a frame set so that there is no unused space between
6460 //  * them. This can only be done on the last frame set in the file and should
6461 //  * be done e.g. if the last frame set in the file has fewer frames than
6462 //  * default or after compressing data blocks in a frame set.
6463 //  * @param tng_data is a trajectory data container.
6464 //  * @details the current_trajectory_frame_set is the one that will be modified.
6465 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
6466 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
6467 //  * FIXME: This function is not finished!!!
6468 //  *
6469 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
6470 // {
6471 //     tng_gen_block_t block;
6472 //     tng_trajectory_frame_set_t frame_set;
6473 //     FILE *temp = tng_data->input_file;
6474 //     int64_t pos, contents_start_pos, output_file_len;
6475 //
6476 //     frame_set = &tng_data->current_trajectory_frame_set;
6477 //
6478 //     if(frame_set->n_written_frames == frame_set->n_frames)
6479 //     {
6480 //         return(TNG_SUCCESS);
6481 //     }
6482 //
6483 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
6484 //        tng_data->last_trajectory_frame_set_output_file_pos)
6485 //     {
6486 //     }
6487 //
6488 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6489 //     {
6490 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6491 //                __FILE__, __LINE__);
6492 //         return(TNG_CRITICAL);
6493 //     }
6494 //
6495 //     tng_block_init(&block);
6496 // //     output_file_pos = ftello(tng_data->output_file);
6497 //
6498 //     tng_data->input_file = tng_data->output_file;
6499 //
6500 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
6501 //
6502 //     fseeko(tng_data->output_file, pos, SEEK_SET);
6503 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6504 //     {
6505 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6506 //             __FILE__, __LINE__);
6507 //         tng_data->input_file = temp;
6508 //         tng_block_destroy(&block);
6509 //         return(TNG_CRITICAL);
6510 //     }
6511 //
6512 //     contents_start_pos = ftello(tng_data->output_file);
6513 //
6514 //     fseeko(tng_data->output_file, 0, SEEK_END);
6515 //     output_file_len = ftello(tng_data->output_file);
6516 //     pos = contents_start_pos + block->block_contents_size;
6517 //     fseeko(tng_data->output_file, pos,
6518 //           SEEK_SET);
6519 //
6520 //     while(pos < output_file_len)
6521 //     {
6522 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6523 //         {
6524 //             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos,
6525 //                    __FILE__, __LINE__);
6526 //             tng_data->input_file = temp;
6527 //             tng_block_destroy(&block);
6528 //             return(TNG_CRITICAL);
6529 //         }
6530 //         pos += block->header_contents_size + block->block_contents_size;
6531 //         fseeko(tng_data->output_file, pos, SEEK_SET);
6532 //     }
6533 //
6534 //     return(TNG_SUCCESS);
6535 // }
6536 */
6537 /**
6538  * @brief Finish writing the current frame set. Update the number of frames
6539  * and the hashes of the frame set and all its data blocks (if hash_mode
6540  * == TNG_USE_HASH).
6541  * @param tng_data is a trajectory data container.
6542  * @param hash_mode specifies whether to update the block md5 hash when
6543  * updating the pointers.
6544  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6545  * error has occured.
6546  */
6547 static tng_function_status tng_frame_set_finalize
6548                 (const tng_trajectory_t tng_data,
6549                  const char hash_mode)
6550 {
6551     tng_gen_block_t block;
6552     tng_trajectory_frame_set_t frame_set;
6553     FILE *temp = tng_data->input_file;
6554     int64_t pos, curr_file_pos;
6555
6556     frame_set = &tng_data->current_trajectory_frame_set;
6557
6558     if(frame_set->n_written_frames == frame_set->n_frames)
6559     {
6560         return(TNG_SUCCESS);
6561     }
6562
6563     frame_set->n_written_frames = frame_set->n_frames;
6564
6565     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6566     {
6567         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6568                __FILE__, __LINE__);
6569         return(TNG_CRITICAL);
6570     }
6571
6572     tng_block_init(&block);
6573 /*     output_file_pos = ftello(tng_data->output_file); */
6574
6575     tng_data->input_file = tng_data->output_file;
6576
6577     curr_file_pos = ftello(tng_data->output_file);
6578
6579     pos = tng_data->current_trajectory_frame_set_output_file_pos;
6580
6581     fseeko(tng_data->output_file, pos, SEEK_SET);
6582
6583     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6584     {
6585         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6586             __FILE__, __LINE__);
6587         tng_data->input_file = temp;
6588         tng_block_destroy(&block);
6589         return(TNG_CRITICAL);
6590     }
6591
6592 //     contents_start_pos = ftello(tng_data->output_file);
6593
6594     fseeko(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
6595     if(fwrite(&frame_set->n_frames, sizeof(frame_set->n_frames),
6596               1, tng_data->output_file) != 1)
6597     {
6598         tng_data->input_file = temp;
6599         tng_block_destroy(&block);
6600         return(TNG_CRITICAL);
6601     }
6602
6603     if(hash_mode == TNG_USE_HASH)
6604     {
6605         tng_md5_hash_update(tng_data, block, pos,
6606                             pos + block->header_contents_size);
6607     }
6608
6609     fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
6610
6611     tng_data->input_file = temp;
6612     tng_block_destroy(&block);
6613     return(TNG_SUCCESS);
6614 }
6615
6616 /*
6617 // ** Sets the name of a file contents block
6618 //  * @param tng_data is a trajectory data container.
6619 //  * @param block is the block, of which to change names.
6620 //  * @param new_name is the new name of the block.
6621 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6622 //  * error has occured.
6623 //
6624 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
6625 //                                               tng_gen_block_t block,
6626 //                                               const char *new_name)
6627 // {
6628 //     int len;
6629 //
6630 //     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
6631 //
6632 //      * If the currently stored string length is not enough to store the new
6633 //      * string it is freed and reallocated. *
6634 //     if(block->name && strlen(block->name) < len)
6635 //     {
6636 //         free(block->name);
6637 //         block->name = 0;
6638 //     }
6639 //     if(!block->name)
6640 //     {
6641 //         block->name = (char *)malloc(len);
6642 //         if(!block->name)
6643 //         {
6644 //             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6645 //                    __FILE__, __LINE__);
6646 //             return(TNG_CRITICAL);
6647 //         }
6648 //     }
6649 //
6650 //     strncpy(block->name, new_name, len);
6651 //
6652 //     return(TNG_SUCCESS);
6653 // }
6654 */
6655
6656 tng_function_status DECLSPECDLLEXPORT tng_atom_residue_get
6657                 (const tng_trajectory_t tng_data,
6658                  const tng_atom_t atom,
6659                  tng_residue_t *residue)
6660 {
6661     (void) tng_data;
6662
6663     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
6664
6665     *residue = atom->residue;
6666
6667     return(TNG_SUCCESS);
6668 }
6669
6670 tng_function_status DECLSPECDLLEXPORT tng_atom_name_get
6671                 (const tng_trajectory_t tng_data,
6672                  const tng_atom_t atom,
6673                  char *name,
6674                  const int max_len)
6675 {
6676     (void) tng_data;
6677     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
6678     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
6679
6680     strncpy(name, atom->name, max_len - 1);
6681     name[max_len - 1] = 0;
6682
6683     if(strlen(atom->name) > (unsigned int)max_len - 1)
6684     {
6685         return(TNG_FAILURE);
6686     }
6687     return(TNG_SUCCESS);
6688 }
6689
6690 tng_function_status DECLSPECDLLEXPORT tng_atom_name_set
6691                 (const tng_trajectory_t tng_data,
6692                  const tng_atom_t atom,
6693                  const char *new_name)
6694 {
6695     unsigned int len;
6696     (void)tng_data;
6697
6698     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6699     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
6700
6701     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
6702
6703     /* If the currently stored string length is not enough to store the new
6704      * string it is freed and reallocated. */
6705     if(atom->name && strlen(atom->name) < len)
6706     {
6707         free(atom->name);
6708         atom->name = 0;
6709     }
6710     if(!atom->name)
6711     {
6712         atom->name = (char *)malloc(len);
6713         if(!atom->name)
6714         {
6715             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6716                     __FILE__, __LINE__);
6717             return(TNG_CRITICAL);
6718         }
6719     }
6720
6721     strncpy(atom->name, new_name, len);
6722
6723     return(TNG_SUCCESS);
6724 }
6725
6726 tng_function_status DECLSPECDLLEXPORT tng_atom_type_get
6727                 (const tng_trajectory_t tng_data,
6728                  const tng_atom_t atom,
6729                  char *type,
6730                  const int max_len)
6731 {
6732     (void) tng_data;
6733     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
6734     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
6735
6736     strncpy(type, atom->atom_type, max_len - 1);
6737     type[max_len - 1] = 0;
6738
6739     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
6740     {
6741         return(TNG_FAILURE);
6742     }
6743     return(TNG_SUCCESS);
6744 }
6745
6746 tng_function_status DECLSPECDLLEXPORT tng_atom_type_set
6747                 (const tng_trajectory_t tng_data,
6748                  const tng_atom_t atom,
6749                  const char *new_type)
6750 {
6751     unsigned int len;
6752     (void)tng_data;
6753
6754     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6755     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
6756
6757     len = tng_min_size(strlen(new_type) + 1, TNG_MAX_STR_LEN);
6758
6759     /* If the currently stored string length is not enough to store the new
6760      * string it is freed and reallocated. */
6761     if(atom->atom_type && strlen(atom->atom_type) < len)
6762     {
6763         free(atom->atom_type);
6764         atom->atom_type = 0;
6765     }
6766     if(!atom->atom_type)
6767     {
6768         atom->atom_type = (char *)malloc(len);
6769         if(!atom->atom_type)
6770         {
6771             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6772                     __FILE__, __LINE__);
6773             return(TNG_CRITICAL);
6774         }
6775     }
6776
6777     strncpy(atom->atom_type, new_type, len);
6778
6779     return(TNG_SUCCESS);
6780 }
6781
6782 /**
6783  * @brief Initialise an atom struct
6784  * @param atom is the atom to initialise.
6785  * @return TNG_SUCCESS (0) if successful.
6786  */
6787 static tng_function_status tng_atom_init(const tng_atom_t atom)
6788 {
6789     atom->name = 0;
6790     atom->atom_type = 0;
6791
6792     return(TNG_SUCCESS);
6793 }
6794
6795 /**
6796  * @brief Free the memory in an atom struct
6797  * @param atom is the atom to destroy.
6798  * @return TNG_SUCCESS (0) if successful.
6799  */
6800 static tng_function_status tng_atom_destroy(const tng_atom_t atom)
6801 {
6802     if(atom->name)
6803     {
6804         free(atom->name);
6805         atom->name = 0;
6806     }
6807     if(atom->atom_type)
6808     {
6809         free(atom->atom_type);
6810         atom->atom_type = 0;
6811     }
6812
6813     return(TNG_SUCCESS);
6814 }
6815
6816 /**
6817  * @brief Update chain->residue pointers (after new memory for
6818  * molecule->residues has been allocated).
6819  * @param tng_data The trajectory container containing the molecule.
6820  * @param mol The molecule that contains the chains that need to be
6821  * updated.
6822  * @returns TNG_SUCCESS (0) if successful.
6823  */
6824 static tng_function_status tng_molecule_chains_residue_pointers_update
6825                 (const tng_trajectory_t tng_data,
6826                  const tng_molecule_t mol)
6827 {
6828     tng_chain_t chain;
6829     int64_t i, res_cnt = 0;
6830     (void)tng_data;
6831
6832     for(i = 0; i < mol->n_chains; i++)
6833     {
6834         chain = &mol->chains[i];
6835         chain->residues = mol->residues + res_cnt;
6836         res_cnt += chain->n_residues;
6837     }
6838     return(TNG_SUCCESS);
6839 }
6840
6841 /**
6842  * @brief Update atoms->residue pointers (after new memory for
6843  * molecule->residues has been allocated).
6844  * @param tng_data The trajectory container containing the molecule.
6845  * @param mol The molecule that contains the chains that need to be
6846  * updated.
6847  * @returns TNG_SUCCESS (0) if successful.
6848  */
6849 static tng_function_status tng_molecule_atoms_residue_pointers_update
6850                 (const tng_trajectory_t tng_data,
6851                  const tng_molecule_t mol)
6852 {
6853     tng_atom_t atom;
6854     tng_residue_t residue;
6855     int64_t i, j, atom_offset = 0;
6856     (void)tng_data;
6857
6858     for(i = 0; i < mol->n_residues; i++)
6859     {
6860         residue = &mol->residues[i];
6861         for(j = 0; j < residue->n_atoms; j++)
6862         {
6863             atom = &mol->atoms[j + atom_offset];
6864             atom->residue = residue;
6865         }
6866         atom_offset += residue->n_atoms;
6867     }
6868     return(TNG_SUCCESS);
6869 }
6870
6871 tng_function_status DECLSPECDLLEXPORT tng_version_major
6872                 (const tng_trajectory_t tng_data,
6873                  int *version)
6874 {
6875     (void)tng_data;
6876
6877     *version = TNG_VERSION_MAJOR;
6878
6879     return(TNG_SUCCESS);
6880 }
6881
6882 tng_function_status DECLSPECDLLEXPORT tng_version_minor
6883                 (const tng_trajectory_t tng_data,
6884                  int *version)
6885 {
6886     (void)tng_data;
6887
6888     *version = TNG_VERSION_MINOR;
6889
6890     return(TNG_SUCCESS);
6891 }
6892
6893 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
6894                 (const tng_trajectory_t tng_data,
6895                  int *patch_level)
6896 {
6897     (void)tng_data;
6898
6899     *patch_level = TNG_VERSION_PATCHLEVEL;
6900
6901     return(TNG_SUCCESS);
6902 }
6903
6904 tng_function_status DECLSPECDLLEXPORT tng_version
6905                 (const tng_trajectory_t tng_data,
6906                  char *version,
6907                  const int max_len)
6908 {
6909     (void)tng_data;
6910     TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
6911
6912     TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
6913
6914     return(TNG_SUCCESS);
6915 }
6916
6917 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
6918                 (const tng_trajectory_t tng_data,
6919                  const char *name,
6920                  tng_molecule_t *molecule)
6921 {
6922     int64_t id;
6923
6924     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6925     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
6926
6927     /* Set ID to the ID of the last molecule + 1 */
6928     if(tng_data->n_molecules)
6929     {
6930         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
6931     }
6932     else
6933     {
6934         id = 1;
6935     }
6936
6937     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
6938 }
6939
6940 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
6941                 (const tng_trajectory_t tng_data,
6942                  const char *name,
6943                  const int64_t id,
6944                  tng_molecule_t *molecule)
6945 {
6946     tng_molecule_t new_molecules;
6947     int64_t *new_molecule_cnt_list;
6948     tng_function_status stat = TNG_SUCCESS;
6949
6950     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6951     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
6952
6953     new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
6954                                             sizeof(struct tng_molecule) *
6955                                             (tng_data->n_molecules + 1));
6956
6957     if(!new_molecules)
6958     {
6959         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6960                 __FILE__, __LINE__);
6961         free(tng_data->molecules);
6962         tng_data->molecules = 0;
6963         return(TNG_CRITICAL);
6964     }
6965
6966     new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
6967                                                sizeof(int64_t) *
6968                                                (tng_data->n_molecules + 1));
6969
6970     if(!new_molecule_cnt_list)
6971     {
6972         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6973                 __FILE__, __LINE__);
6974         free(tng_data->molecule_cnt_list);
6975         tng_data->molecule_cnt_list = 0;
6976         free(new_molecules);
6977         return(TNG_CRITICAL);
6978     }
6979
6980     tng_data->molecules = new_molecules;
6981     tng_data->molecule_cnt_list = new_molecule_cnt_list;
6982
6983     *molecule = &new_molecules[tng_data->n_molecules];
6984
6985     tng_molecule_init(tng_data, *molecule);
6986     tng_molecule_name_set(tng_data, *molecule, name);
6987
6988     /* FIXME: Should this be a function argument instead? */
6989     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
6990
6991     (*molecule)->id = id;
6992
6993     tng_data->n_molecules++;
6994
6995     return(stat);
6996 }
6997
6998 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
6999                 (const tng_trajectory_t tng_data,
7000                  tng_molecule_t *molecule_p)
7001 {
7002     int64_t *new_molecule_cnt_list, id;
7003     tng_molecule_t new_molecules, molecule;
7004
7005     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7006
7007     /* Set ID to the ID of the last molecule + 1 */
7008     if(tng_data->n_molecules)
7009     {
7010         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7011     }
7012     else
7013     {
7014         id = 1;
7015     }
7016
7017     new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
7018                                             sizeof(struct tng_molecule) *
7019                                             (tng_data->n_molecules + 1));
7020
7021     if(!new_molecules)
7022     {
7023         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7024                 __FILE__, __LINE__);
7025         free(tng_data->molecules);
7026         tng_data->molecules = 0;
7027         return(TNG_CRITICAL);
7028     }
7029
7030     new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
7031                                                sizeof(int64_t) *
7032                                                (tng_data->n_molecules + 1));
7033
7034     if(!new_molecule_cnt_list)
7035     {
7036         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7037                 __FILE__, __LINE__);
7038         free(tng_data->molecule_cnt_list);
7039         tng_data->molecule_cnt_list = 0;
7040         free(new_molecules);
7041         return(TNG_CRITICAL);
7042     }
7043
7044     molecule = *molecule_p;
7045
7046     tng_data->molecules = new_molecules;
7047     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7048
7049     new_molecules[tng_data->n_molecules] = *molecule;
7050
7051     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7052
7053     free(*molecule_p);
7054
7055     molecule = &new_molecules[tng_data->n_molecules];
7056
7057     *molecule_p = molecule;
7058
7059     molecule->id = id;
7060
7061     tng_data->n_molecules++;
7062
7063     return(TNG_SUCCESS);
7064 }
7065
7066 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
7067                                           const tng_molecule_t molecule,
7068                                           char *name,
7069                                           const int max_len)
7070 {
7071     (void) tng_data;
7072     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7073     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7074
7075     strncpy(name, molecule->name, max_len - 1);
7076     name[max_len - 1] = 0;
7077
7078     if(strlen(molecule->name) > (unsigned int)max_len - 1)
7079     {
7080         return(TNG_FAILURE);
7081     }
7082     return(TNG_SUCCESS);
7083 }
7084
7085 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
7086                 (const tng_trajectory_t tng_data,
7087                  const tng_molecule_t molecule,
7088                  const char *new_name)
7089 {
7090     unsigned int len;
7091     (void)tng_data;
7092
7093     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7094     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7095
7096     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7097
7098     /* If the currently stored string length is not enough to store the new
7099      * string it is freed and reallocated. */
7100     if(molecule->name && strlen(molecule->name) < len)
7101     {
7102         free(molecule->name);
7103         molecule->name = 0;
7104     }
7105     if(!molecule->name)
7106     {
7107         molecule->name = (char *)malloc(len);
7108         if(!molecule->name)
7109         {
7110             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7111                     __FILE__, __LINE__);
7112             return(TNG_CRITICAL);
7113         }
7114     }
7115
7116     strncpy(molecule->name, new_name, len);
7117
7118     return(TNG_SUCCESS);
7119 }
7120
7121 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
7122                 (const tng_trajectory_t tng_data,
7123                  const tng_molecule_t molecule,
7124                  int64_t *cnt)
7125 {
7126     int64_t i, index = -1;
7127
7128     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7129     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
7130
7131     for(i = 0; i < tng_data->n_molecules; i++)
7132     {
7133         if(&tng_data->molecules[i] == molecule)
7134         {
7135             index = i;
7136             break;
7137         }
7138     }
7139     if(index == -1)
7140     {
7141         return(TNG_FAILURE);
7142     }
7143     *cnt = tng_data->molecule_cnt_list[index];
7144
7145     return(TNG_SUCCESS);
7146 }
7147
7148 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
7149                 (const tng_trajectory_t tng_data,
7150                  const tng_molecule_t molecule,
7151                  const int64_t cnt)
7152 {
7153     int64_t i, old_cnt, index = -1;
7154
7155     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7156
7157     for(i = 0; i < tng_data->n_molecules; i++)
7158     {
7159         if(&tng_data->molecules[i] == molecule)
7160         {
7161             index = i;
7162             break;
7163         }
7164     }
7165     if(index == -1)
7166     {
7167         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
7168                __FILE__, __LINE__);
7169         return(TNG_FAILURE);
7170     }
7171     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
7172     {
7173         old_cnt = tng_data->molecule_cnt_list[index];
7174         tng_data->molecule_cnt_list[index] = cnt;
7175
7176         tng_data->n_particles += (cnt-old_cnt) *
7177                                  tng_data->molecules[index].n_atoms;
7178     }
7179     else
7180     {
7181         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
7182         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
7183
7184         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
7185                 tng_data->molecules[index].n_atoms;
7186     }
7187
7188     return(TNG_SUCCESS);
7189 }
7190
7191 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
7192                 (const tng_trajectory_t tng_data,
7193                  const char *name,
7194                  const int64_t nr,
7195                  tng_molecule_t *molecule)
7196 {
7197     int64_t i, n_molecules;
7198
7199     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7200     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7201     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7202
7203     n_molecules = tng_data->n_molecules;
7204
7205     for(i = n_molecules - 1; i >= 0; i--)
7206     {
7207         *molecule = &tng_data->molecules[i];
7208         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
7209         {
7210             if(nr == -1 || nr == (*molecule)->id)
7211             {
7212                 return(TNG_SUCCESS);
7213             }
7214         }
7215     }
7216
7217     *molecule = 0;
7218
7219     return(TNG_FAILURE);
7220 }
7221
7222 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
7223                 (const tng_trajectory_t tng_data,
7224                  const int64_t index,
7225                  tng_molecule_t *molecule)
7226 {
7227     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7228     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7229
7230     if(index >= tng_data->n_molecules)
7231     {
7232         *molecule = 0;
7233         return(TNG_FAILURE);
7234     }
7235     *molecule = &tng_data->molecules[index];
7236     return(TNG_SUCCESS);
7237 }
7238
7239 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(const tng_trajectory_t tng_data_src,
7240                                                                const tng_trajectory_t tng_data_dest)
7241 {
7242     tng_molecule_t molecule, molecule_temp;
7243     tng_chain_t chain, chain_temp;
7244     tng_residue_t residue, residue_temp;
7245     tng_atom_t atom, atom_temp;
7246     tng_bond_t bond_temp;
7247     tng_function_status stat;
7248     int64_t i, j, k, l, *list_temp;
7249
7250     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
7251     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
7252
7253     for(i = 0; i < tng_data_dest->n_molecules; i++)
7254     {
7255         molecule = &tng_data_dest->molecules[i];
7256         tng_molecule_destroy(tng_data_dest, molecule);
7257     }
7258
7259     tng_data_dest->n_molecules = 0;
7260     tng_data_dest->n_particles = 0;
7261
7262     molecule_temp = (tng_molecule_t)realloc(tng_data_dest->molecules,
7263                                             sizeof(struct tng_molecule) * tng_data_src->n_molecules);
7264     if(!molecule_temp)
7265     {
7266         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7267                 __FILE__, __LINE__);
7268         free(tng_data_dest->molecules);
7269         tng_data_dest->molecules = 0;
7270         return(TNG_CRITICAL);
7271     }
7272     list_temp = (int64_t *)realloc(tng_data_dest->molecule_cnt_list,
7273                                    sizeof(int64_t) * tng_data_src->n_molecules);
7274     if(!list_temp)
7275     {
7276         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7277                 __FILE__, __LINE__);
7278         free(tng_data_dest->molecule_cnt_list);
7279         tng_data_dest->molecule_cnt_list = 0;
7280         free(molecule_temp);
7281         return(TNG_CRITICAL);
7282     }
7283
7284     tng_data_dest->molecules = molecule_temp;
7285     tng_data_dest->molecule_cnt_list = list_temp;
7286
7287     for(i = 0; i < tng_data_src->n_molecules; i++)
7288     {
7289         molecule = &tng_data_src->molecules[i];
7290         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
7291                                      &molecule_temp);
7292         if(stat != TNG_SUCCESS)
7293         {
7294             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
7295                    __FILE__, __LINE__);
7296             return(stat);
7297         }
7298         molecule_temp->quaternary_str = molecule->quaternary_str;
7299         for(j = 0; j < molecule->n_chains; j++)
7300         {
7301             chain = &molecule->chains[j];
7302             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
7303                                                chain->name, chain->id,
7304                                                &chain_temp);
7305             if(stat != TNG_SUCCESS)
7306             {
7307                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
7308                        __FILE__, __LINE__);
7309                 return(stat);
7310             }
7311             for(k = 0; k < chain->n_residues; k++)
7312             {
7313                 residue = &chain->residues[k];
7314                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
7315                                                   residue->name, residue->id,
7316                                                   &residue_temp);
7317                 if(stat != TNG_SUCCESS)
7318                 {
7319                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
7320                            __FILE__, __LINE__);
7321                     return(stat);
7322                 }
7323                 for(l = 0; l < residue->n_atoms; l++)
7324                 {
7325                     atom = &molecule->atoms[residue->atoms_offset + l];
7326                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
7327                                                      atom->name, atom->atom_type,
7328                                                      atom->id, &atom_temp);
7329                     if(stat != TNG_SUCCESS)
7330                     {
7331                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
7332                            __FILE__, __LINE__);
7333                         return(stat);
7334                     }
7335                 }
7336             }
7337         }
7338         molecule_temp->n_bonds = molecule->n_bonds;
7339         if(molecule->n_bonds > 0)
7340         {
7341             bond_temp = (tng_bond_t)realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
7342                                             molecule->n_bonds);
7343             if(!bond_temp)
7344             {
7345                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7346                         __FILE__, __LINE__);
7347                 free(molecule_temp->bonds);
7348                 molecule_temp->n_bonds = 0;
7349                 return(TNG_CRITICAL);
7350             }
7351             molecule_temp->bonds = bond_temp;
7352             for(j = 0; j < molecule->n_bonds; j++)
7353             {
7354                 molecule_temp->bonds[j] = molecule->bonds[j];
7355             }
7356         }
7357         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
7358                                     tng_data_src->molecule_cnt_list[i]);
7359         if(stat != TNG_SUCCESS)
7360         {
7361             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
7362                    __FILE__, __LINE__);
7363             return(stat);
7364         }
7365     }
7366     return(TNG_SUCCESS);
7367 }
7368
7369 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
7370                 (const tng_trajectory_t tng_data,
7371                  const tng_molecule_t molecule,
7372                  int64_t *n)
7373 {
7374     (void) tng_data;
7375     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7376     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7377
7378     *n = molecule->n_chains;
7379
7380     return(TNG_SUCCESS);
7381 }
7382
7383 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
7384                 (const tng_trajectory_t tng_data,
7385                  const tng_molecule_t molecule,
7386                  const int64_t index,
7387                  tng_chain_t *chain)
7388 {
7389     (void) tng_data;
7390     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7391     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7392
7393     if(index >= molecule->n_chains)
7394     {
7395         *chain = 0;
7396         return(TNG_FAILURE);
7397     }
7398     *chain = &molecule->chains[index];
7399     return(TNG_SUCCESS);
7400 }
7401
7402 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
7403                 (const tng_trajectory_t tng_data,
7404                  const tng_molecule_t molecule,
7405                  int64_t *n)
7406 {
7407     (void) tng_data;
7408     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7409     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7410
7411     *n = molecule->n_residues;
7412
7413     return(TNG_SUCCESS);
7414 }
7415
7416 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
7417                 (const tng_trajectory_t tng_data,
7418                  const tng_molecule_t molecule,
7419                  const int64_t index,
7420                  tng_residue_t *residue)
7421 {
7422     (void) tng_data;
7423     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7424     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7425
7426     if(index >= molecule->n_residues)
7427     {
7428         *residue = 0;
7429         return(TNG_FAILURE);
7430     }
7431     *residue = &molecule->residues[index];
7432     return(TNG_SUCCESS);
7433 }
7434
7435 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
7436                 (const tng_trajectory_t tng_data,
7437                  const tng_molecule_t molecule,
7438                  int64_t *n)
7439 {
7440     (void) tng_data;
7441     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7442     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7443
7444     *n = molecule->n_atoms;
7445
7446     return(TNG_SUCCESS);
7447 }
7448
7449 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
7450                 (const tng_trajectory_t tng_data,
7451                  const tng_molecule_t molecule,
7452                  const int64_t index,
7453                  tng_atom_t *atom)
7454 {
7455     (void) tng_data;
7456     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7457     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7458
7459     if(index >= molecule->n_atoms)
7460     {
7461         *atom = 0;
7462         return(TNG_FAILURE);
7463     }
7464     *atom = &molecule->atoms[index];
7465     return(TNG_SUCCESS);
7466 }
7467
7468 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
7469                 (const tng_trajectory_t tng_data,
7470                  const tng_molecule_t molecule,
7471                  const char *name,
7472                  const int64_t nr,
7473                  tng_chain_t *chain)
7474 {
7475     int64_t i, n_chains;
7476     (void)tng_data;
7477
7478     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7479     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7480
7481     n_chains = molecule->n_chains;
7482
7483     for(i = n_chains - 1; i >= 0; i--)
7484     {
7485         *chain = &molecule->chains[i];
7486         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
7487         {
7488             if(nr == -1 || nr == (*chain)->id)
7489             {
7490                 return(TNG_SUCCESS);
7491             }
7492         }
7493     }
7494
7495     *chain = 0;
7496
7497     return(TNG_FAILURE);
7498 }
7499
7500 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
7501                 (const tng_trajectory_t tng_data,
7502                  const tng_molecule_t molecule,
7503                  const char *name,
7504                  tng_chain_t *chain)
7505 {
7506     int64_t id;
7507
7508     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7509     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7510
7511     /* Set ID to the ID of the last chain + 1 */
7512     if(molecule->n_chains)
7513     {
7514         id = molecule->chains[molecule->n_chains-1].id + 1;
7515     }
7516     else
7517     {
7518         id = 1;
7519     }
7520
7521     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
7522                                        id, chain));
7523 }
7524
7525 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
7526                 (const tng_trajectory_t tng_data,
7527                  const tng_molecule_t molecule,
7528                  const char *name,
7529                  const int64_t id,
7530                  tng_chain_t *chain)
7531 {
7532     tng_chain_t new_chains;
7533     tng_function_status stat = TNG_SUCCESS;
7534
7535     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7536     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7537
7538     new_chains = (tng_chain_t)realloc(molecule->chains,
7539                                       sizeof(struct tng_chain) *
7540                                       (molecule->n_chains + 1));
7541
7542     if(!new_chains)
7543     {
7544         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7545                 __FILE__, __LINE__);
7546         free(molecule->chains);
7547         molecule->chains = 0;
7548         return(TNG_CRITICAL);
7549     }
7550
7551     molecule->chains = new_chains;
7552
7553     *chain = &new_chains[molecule->n_chains];
7554     (*chain)->name = 0;
7555
7556     tng_chain_name_set(tng_data, *chain, name);
7557
7558     (*chain)->molecule = molecule;
7559     (*chain)->n_residues = 0;
7560
7561     molecule->n_chains++;
7562
7563     (*chain)->id = id;
7564
7565     return(stat);
7566 }
7567
7568 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
7569                 (const tng_trajectory_t tng_data,
7570                  const tng_molecule_t molecule,
7571                  const int64_t from_atom_id,
7572                  const int64_t to_atom_id,
7573                  tng_bond_t *bond)
7574 {
7575     tng_bond_t new_bonds;
7576     (void)tng_data;
7577
7578     new_bonds = (tng_bond_t)realloc(molecule->bonds,
7579                                     sizeof(struct tng_bond) *
7580                                     (molecule->n_bonds + 1));
7581
7582     if(!new_bonds)
7583     {
7584         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7585                 __FILE__, __LINE__);
7586         *bond = 0;
7587         free(molecule->bonds);
7588         molecule->bonds = 0;
7589         return(TNG_CRITICAL);
7590     }
7591
7592     molecule->bonds = new_bonds;
7593
7594     *bond = &new_bonds[molecule->n_bonds];
7595
7596     (*bond)->from_atom_id = from_atom_id;
7597     (*bond)->to_atom_id = to_atom_id;
7598
7599     molecule->n_bonds++;
7600
7601     return(TNG_SUCCESS);
7602 }
7603
7604 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
7605                 (const tng_trajectory_t tng_data,
7606                  const tng_molecule_t molecule,
7607                  const char *name,
7608                  const int64_t id,
7609                  tng_atom_t *atom)
7610 {
7611     int64_t i, n_atoms;
7612     (void)tng_data;
7613
7614     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7615
7616     n_atoms = molecule->n_atoms;
7617
7618     for(i = n_atoms - 1; i >= 0; i--)
7619     {
7620         *atom = &molecule->atoms[i];
7621         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
7622         {
7623             if(id == -1 || id == (*atom)->id)
7624             {
7625                 return(TNG_SUCCESS);
7626             }
7627         }
7628     }
7629
7630     *atom = 0;
7631
7632     return(TNG_FAILURE);
7633 }
7634
7635 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
7636                                        const tng_chain_t chain,
7637                                        char *name,
7638                                        const int max_len)
7639 {
7640     (void) tng_data;
7641     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7642     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7643
7644     strncpy(name, chain->name, max_len - 1);
7645     name[max_len - 1] = 0;
7646
7647     if(strlen(chain->name) > (unsigned int)max_len - 1)
7648     {
7649         return(TNG_FAILURE);
7650     }
7651     return(TNG_SUCCESS);
7652 }
7653
7654 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
7655                 (const tng_trajectory_t tng_data,
7656                  const tng_chain_t chain,
7657                  const char *new_name)
7658 {
7659     unsigned int len;
7660     (void)tng_data;
7661
7662     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7663
7664     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7665
7666     /* If the currently stored string length is not enough to store the new
7667      * string it is freed and reallocated. */
7668     if(chain->name && strlen(chain->name) < len)
7669     {
7670         free(chain->name);
7671         chain->name = 0;
7672     }
7673     if(!chain->name)
7674     {
7675         chain->name = (char *)malloc(len);
7676         if(!chain->name)
7677         {
7678             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7679                     __FILE__, __LINE__);
7680             return(TNG_CRITICAL);
7681         }
7682     }
7683
7684     strncpy(chain->name, new_name, len);
7685
7686     return(TNG_SUCCESS);
7687 }
7688
7689 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
7690                 (const tng_trajectory_t tng_data,
7691                  const tng_chain_t chain,
7692                  int64_t *n)
7693 {
7694     (void) tng_data;
7695     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7696     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7697
7698     *n = chain->n_residues;
7699
7700     return(TNG_SUCCESS);
7701 }
7702
7703 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
7704                 (const tng_trajectory_t tng_data,
7705                  const tng_chain_t chain,
7706                  const int64_t index,
7707                  tng_residue_t *residue)
7708 {
7709     (void) tng_data;
7710     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7711     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7712
7713     if(index >= chain->n_residues)
7714     {
7715         *residue = 0;
7716         return(TNG_FAILURE);
7717     }
7718     *residue = &chain->residues[index];
7719     return(TNG_SUCCESS);
7720 }
7721
7722 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
7723                 (const tng_trajectory_t tng_data,
7724                  const tng_chain_t chain,
7725                  const char *name,
7726                  const int64_t id,
7727                  tng_residue_t *residue)
7728 {
7729     int64_t i, n_residues;
7730     (void)tng_data;
7731
7732     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7733
7734     n_residues = chain->n_residues;
7735
7736     for(i = n_residues - 1; i >= 0; i--)
7737     {
7738         *residue = &chain->residues[i];
7739         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
7740         {
7741             if(id == -1 || id == (*residue)->id)
7742             {
7743                 return(TNG_SUCCESS);
7744             }
7745         }
7746     }
7747
7748     *residue = 0;
7749
7750     return(TNG_FAILURE);
7751 }
7752
7753 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
7754                 (const tng_trajectory_t tng_data,
7755                  const tng_chain_t chain,
7756                  const char *name,
7757                  tng_residue_t *residue)
7758 {
7759     int64_t id;
7760
7761     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7762     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7763
7764     /* Set ID to the ID of the last residue + 1 */
7765     if(chain->n_residues)
7766     {
7767         id = chain->residues[chain->n_residues-1].id + 1;
7768     }
7769     else
7770     {
7771         id = 0;
7772     }
7773
7774     return(tng_chain_residue_w_id_add(tng_data, chain, name,
7775                                       id, residue));
7776 }
7777
7778 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
7779                 (const tng_trajectory_t tng_data,
7780                  const tng_chain_t chain,
7781                  const char *name,
7782                  const int64_t id,
7783                  tng_residue_t *residue)
7784 {
7785     int64_t curr_index;
7786     tng_residue_t new_residues, temp_residue, last_residue;
7787     tng_molecule_t molecule = chain->molecule;
7788     tng_function_status stat = TNG_SUCCESS;
7789
7790     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7791     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7792
7793     if(chain->n_residues)
7794     {
7795         curr_index = chain->residues - molecule->residues;
7796     }
7797     else
7798     {
7799         curr_index = -1;
7800     }
7801
7802     new_residues = (tng_residue_t)realloc(molecule->residues,
7803                                           sizeof(struct tng_residue) *
7804                                           (molecule->n_residues + 1));
7805
7806     if(!new_residues)
7807     {
7808         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7809                 __FILE__, __LINE__);
7810         free(molecule->residues);
7811         molecule->residues = 0;
7812         return(TNG_CRITICAL);
7813     }
7814
7815     molecule->residues = new_residues;
7816
7817     if(curr_index != -1)
7818     {
7819         chain->residues = new_residues + curr_index;
7820         if(molecule->n_residues)
7821         {
7822             last_residue = &new_residues[molecule->n_residues - 1];
7823
7824             temp_residue = chain->residues + (chain->n_residues - 1);
7825             /* Make space in list of residues to add the new residues together with the other
7826             * residues of this chain */
7827             if(temp_residue != last_residue)
7828             {
7829                 ++temp_residue;
7830                 memmove(temp_residue + 1, temp_residue,
7831                         last_residue - temp_residue);
7832             }
7833         }
7834     }
7835     else
7836     {
7837         curr_index = molecule->n_residues;
7838     }
7839
7840     *residue = &molecule->residues[curr_index + chain->n_residues];
7841
7842     tng_molecule_chains_residue_pointers_update(tng_data, molecule);
7843     tng_molecule_atoms_residue_pointers_update(tng_data, molecule);
7844
7845     (*residue)->name = 0;
7846     tng_residue_name_set(tng_data, *residue, name);
7847
7848     (*residue)->chain = chain;
7849     (*residue)->n_atoms = 0;
7850     (*residue)->atoms_offset = 0;
7851
7852     chain->n_residues++;
7853     molecule->n_residues++;
7854
7855     (*residue)->id = id;
7856
7857     return(stat);
7858 }
7859
7860 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
7861                                          const tng_residue_t residue,
7862                                          char *name,
7863                                          const int max_len)
7864 {
7865     (void) tng_data;
7866     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
7867     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7868
7869     strncpy(name, residue->name, max_len - 1);
7870     name[max_len - 1] = 0;
7871
7872     if(strlen(residue->name) > (unsigned int)max_len - 1)
7873     {
7874         return(TNG_FAILURE);
7875     }
7876     return(TNG_SUCCESS);
7877 }
7878
7879 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(const tng_trajectory_t tng_data,
7880                                                            const tng_residue_t residue,
7881                                                            const char *new_name)
7882 {
7883     unsigned int len;
7884     (void)tng_data;
7885
7886     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7887     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
7888
7889     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7890
7891     /* If the currently stored string length is not enough to store the new
7892      * string it is freed and reallocated. */
7893     if(residue->name && strlen(residue->name) < len)
7894     {
7895         free(residue->name);
7896         residue->name = 0;
7897     }
7898     if(!residue->name)
7899     {
7900         residue->name = (char *)malloc(len);
7901         if(!residue->name)
7902         {
7903             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7904                     __FILE__, __LINE__);
7905             return(TNG_CRITICAL);
7906         }
7907     }
7908
7909     strncpy(residue->name, new_name, len);
7910
7911     return(TNG_SUCCESS);
7912 }
7913
7914 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
7915                 (const tng_trajectory_t tng_data,
7916                  const tng_residue_t residue,
7917                  int64_t *n)
7918 {
7919     (void) tng_data;
7920     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
7921     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7922
7923     *n = residue->n_atoms;
7924
7925     return(TNG_SUCCESS);
7926 }
7927
7928 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
7929                 (const tng_trajectory_t tng_data,
7930                  const tng_residue_t residue,
7931                  const int64_t index,
7932                  tng_atom_t *atom)
7933 {
7934     tng_chain_t chain;
7935     tng_molecule_t molecule;
7936
7937     (void) tng_data;
7938     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7939     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7940
7941     if(index >= residue->n_atoms)
7942     {
7943         *atom = 0;
7944         return(TNG_FAILURE);
7945     }
7946     chain = residue->chain;
7947     molecule = chain->molecule;
7948
7949     if(index + residue->atoms_offset >= molecule->n_atoms)
7950     {
7951         *atom = 0;
7952         return(TNG_FAILURE);
7953     }
7954
7955     *atom = &molecule->atoms[residue->atoms_offset + index];
7956     return(TNG_SUCCESS);
7957 }
7958
7959 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
7960                 (const tng_trajectory_t tng_data,
7961                  const tng_residue_t residue,
7962                  const char *atom_name,
7963                  const char *atom_type,
7964                  tng_atom_t *atom)
7965 {
7966     int64_t id;
7967
7968     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7969     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
7970     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
7971
7972     /* Set ID to the ID of the last atom + 1 */
7973     if(residue->chain->molecule->n_atoms)
7974     {
7975         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
7976     }
7977     else
7978     {
7979         id = 0;
7980     }
7981
7982     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
7983                                      id, atom));
7984 }
7985
7986 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
7987                 (const tng_trajectory_t tng_data,
7988                  const tng_residue_t residue,
7989                  const char *atom_name,
7990                  const char *atom_type,
7991                  const int64_t id,
7992                  tng_atom_t *atom)
7993 {
7994     tng_atom_t new_atoms;
7995     tng_molecule_t molecule = residue->chain->molecule;
7996     tng_function_status stat = TNG_SUCCESS;
7997
7998     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7999     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8000     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8001
8002     if(!residue->n_atoms)
8003     {
8004         residue->atoms_offset = molecule->n_atoms;
8005     }
8006
8007     new_atoms = (tng_atom_t)realloc(molecule->atoms,
8008                                     sizeof(struct tng_atom) *
8009                                     (molecule->n_atoms + 1));
8010
8011     if(!new_atoms)
8012     {
8013         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8014                 __FILE__, __LINE__);
8015         free(molecule->atoms);
8016         molecule->atoms = 0;
8017         return(TNG_CRITICAL);
8018     }
8019
8020     molecule->atoms = new_atoms;
8021
8022     *atom = &new_atoms[molecule->n_atoms];
8023
8024     tng_atom_init(*atom);
8025     tng_atom_name_set(tng_data, *atom, atom_name);
8026     tng_atom_type_set(tng_data, *atom, atom_type);
8027
8028     (*atom)->residue = residue;
8029
8030     residue->n_atoms++;
8031     molecule->n_atoms++;
8032
8033     (*atom)->id = id;
8034
8035     return(stat);
8036 }
8037
8038 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
8039                                                          tng_molecule_t *molecule_p)
8040 {
8041     *molecule_p = (tng_molecule_t)malloc(sizeof(struct tng_molecule));
8042     if(!*molecule_p)
8043     {
8044         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8045                 __FILE__, __LINE__);
8046         return(TNG_CRITICAL);
8047     }
8048
8049     tng_molecule_init(tng_data, *molecule_p);
8050
8051     return(TNG_SUCCESS);
8052 }
8053
8054 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
8055                                                         tng_molecule_t *molecule_p)
8056 {
8057     if(!*molecule_p)
8058     {
8059         return(TNG_SUCCESS);
8060     }
8061
8062     tng_molecule_destroy(tng_data, *molecule_p);
8063
8064     free(*molecule_p);
8065     *molecule_p = 0;
8066
8067     return(TNG_SUCCESS);
8068 }
8069
8070 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
8071                                                         const tng_molecule_t molecule)
8072 {
8073     (void)tng_data;
8074     molecule->quaternary_str = 1;
8075     molecule->name = 0;
8076     molecule->n_chains = 0;
8077     molecule->chains = 0;
8078     molecule->n_residues = 0;
8079     molecule->residues = 0;
8080     molecule->n_atoms = 0;
8081     molecule->atoms = 0;
8082     molecule->n_bonds = 0;
8083     molecule->bonds = 0;
8084
8085     return(TNG_SUCCESS);
8086 }
8087
8088 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
8089                                                            const tng_molecule_t molecule)
8090 {
8091     int64_t i;
8092     (void)tng_data;
8093
8094     if(molecule->name)
8095     {
8096         free(molecule->name);
8097         molecule->name = 0;
8098     }
8099
8100     if(molecule->chains)
8101     {
8102         for(i = 0; i < molecule->n_chains; i++)
8103         {
8104             if(molecule->chains[i].name)
8105             {
8106                 free(molecule->chains[i].name);
8107                 molecule->chains[i].name = 0;
8108             }
8109         }
8110         free(molecule->chains);
8111         molecule->chains = 0;
8112     }
8113     molecule->n_chains = 0;
8114
8115     if(molecule->residues)
8116     {
8117         for(i = 0; i < molecule->n_residues; i++)
8118         {
8119             if(molecule->residues[i].name)
8120             {
8121                 free(molecule->residues[i].name);
8122                 molecule->residues[i].name = 0;
8123             }
8124         }
8125         free(molecule->residues);
8126         molecule->residues = 0;
8127     }
8128     molecule->n_residues = 0;
8129
8130     if(molecule->atoms)
8131     {
8132         for(i = 0; i < molecule->n_atoms; i++)
8133         {
8134             tng_atom_destroy(&molecule->atoms[i]);
8135         }
8136         free(molecule->atoms);
8137         molecule->atoms = 0;
8138     }
8139     molecule->n_atoms = 0;
8140
8141     if(molecule->bonds)
8142     {
8143         free(molecule->bonds);
8144         molecule->bonds = 0;
8145     }
8146     molecule->n_bonds = 0;
8147
8148     return(TNG_SUCCESS);
8149 }
8150
8151 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
8152                 (const tng_trajectory_t tng_data,
8153                  const int64_t nr,
8154                  char *name,
8155                  const int max_len)
8156 {
8157     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8158     tng_molecule_t mol;
8159     tng_bool found = TNG_FALSE;
8160
8161     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8162     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8163
8164     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8165
8166     if(!molecule_cnt_list)
8167     {
8168         return(TNG_FAILURE);
8169     }
8170
8171     for(i = 0; i < tng_data->n_molecules; i++)
8172     {
8173         mol = &tng_data->molecules[i];
8174         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8175         {
8176             cnt += mol->n_atoms * molecule_cnt_list[i];
8177             continue;
8178         }
8179         found = TNG_TRUE;
8180         break;
8181     }
8182     if(!found)
8183     {
8184         return(TNG_FAILURE);
8185     }
8186
8187     strncpy(name, mol->name, max_len - 1);
8188     name[max_len - 1] = 0;
8189
8190     if(strlen(mol->name) > (unsigned int)max_len - 1)
8191     {
8192         return(TNG_FAILURE);
8193     }
8194     return(TNG_SUCCESS);
8195 }
8196
8197 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
8198                 (const tng_trajectory_t tng_data,
8199                  const int64_t nr,
8200                  int64_t *id)
8201 {
8202     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8203     tng_molecule_t mol;
8204     tng_bool found = TNG_FALSE;
8205
8206     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8207     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8208
8209     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8210
8211     if(!molecule_cnt_list)
8212     {
8213         return(TNG_FAILURE);
8214     }
8215
8216     for(i = 0; i < tng_data->n_molecules; i++)
8217     {
8218         mol = &tng_data->molecules[i];
8219         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8220         {
8221             cnt += mol->n_atoms * molecule_cnt_list[i];
8222             continue;
8223         }
8224         found = TNG_TRUE;
8225         break;
8226     }
8227     if(!found)
8228     {
8229         return(TNG_FAILURE);
8230     }
8231
8232     *id = mol->id;
8233
8234     return(TNG_SUCCESS);
8235 }
8236
8237 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
8238                 (const tng_trajectory_t tng_data,
8239                  int64_t *n_bonds,
8240                  int64_t **from_atoms,
8241                  int64_t **to_atoms)
8242 {
8243     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
8244     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
8245     tng_molecule_t mol;
8246     tng_bond_t bond;
8247
8248     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8249     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
8250     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
8251     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
8252
8253     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8254
8255     if(!molecule_cnt_list)
8256     {
8257         return(TNG_FAILURE);
8258     }
8259
8260     *n_bonds = 0;
8261     /* First count the total number of bonds to allocate memory */
8262     for(i = 0; i < tng_data->n_molecules; i++)
8263     {
8264         mol = &tng_data->molecules[i];
8265         mol_cnt = molecule_cnt_list[i];
8266         *n_bonds += mol_cnt * mol->n_bonds;
8267     }
8268     if(*n_bonds == 0)
8269     {
8270         return(TNG_SUCCESS);
8271     }
8272
8273     *from_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
8274     if(!*from_atoms)
8275     {
8276         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8277                 __FILE__, __LINE__);
8278         return(TNG_CRITICAL);
8279     }
8280     *to_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
8281     if(!*to_atoms)
8282     {
8283         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8284                 __FILE__, __LINE__);
8285         free(*from_atoms);
8286         *from_atoms = 0;
8287         return(TNG_CRITICAL);
8288     }
8289
8290     cnt = 0;
8291     for(i = 0; i < tng_data->n_molecules; i++)
8292     {
8293         mol = &tng_data->molecules[i];
8294         mol_cnt = molecule_cnt_list[i];
8295         for(j = 0; j < mol_cnt; j++)
8296         {
8297             for(k = 0; k < mol->n_bonds; k++)
8298             {
8299                 bond = &mol->bonds[k];
8300                 from_atom = atom_cnt + bond->from_atom_id;
8301                 to_atom = atom_cnt + bond->to_atom_id;
8302                 (*from_atoms)[cnt] = from_atom;
8303                 (*to_atoms)[cnt++] = to_atom;
8304             }
8305             atom_cnt += mol->n_atoms;
8306         }
8307     }
8308
8309     return(TNG_SUCCESS);
8310 }
8311
8312 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
8313                 (const tng_trajectory_t tng_data,
8314                  const int64_t nr,
8315                  char *name,
8316                  const int max_len)
8317 {
8318     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8319     tng_molecule_t mol;
8320     tng_atom_t atom;
8321     tng_bool found = TNG_FALSE;
8322
8323     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8324     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8325
8326     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8327
8328     if(!molecule_cnt_list)
8329     {
8330         return(TNG_FAILURE);
8331     }
8332
8333     for(i = 0; i < tng_data->n_molecules; i++)
8334     {
8335         mol = &tng_data->molecules[i];
8336         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8337         {
8338             cnt += mol->n_atoms * molecule_cnt_list[i];
8339             continue;
8340         }
8341         atom = &mol->atoms[nr % mol->n_atoms];
8342         found = TNG_TRUE;
8343         break;
8344     }
8345     if(!found)
8346     {
8347         return(TNG_FAILURE);
8348     }
8349     if(!atom->residue || !atom->residue->chain)
8350     {
8351         return(TNG_FAILURE);
8352     }
8353
8354     strncpy(name, atom->residue->chain->name, max_len - 1);
8355     name[max_len - 1] = 0;
8356
8357     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
8358     {
8359         return(TNG_FAILURE);
8360     }
8361     return(TNG_SUCCESS);
8362 }
8363
8364 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
8365                 (const tng_trajectory_t tng_data,
8366                  const int64_t nr,
8367                  char *name,
8368                  const int max_len)
8369 {
8370     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8371     tng_molecule_t mol;
8372     tng_atom_t atom;
8373     tng_bool found = TNG_FALSE;
8374
8375     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8376     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8377
8378     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8379
8380     if(!molecule_cnt_list)
8381     {
8382         return(TNG_FAILURE);
8383     }
8384
8385     for(i = 0; i < tng_data->n_molecules; i++)
8386     {
8387         mol = &tng_data->molecules[i];
8388         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8389         {
8390             cnt += mol->n_atoms * molecule_cnt_list[i];
8391             continue;
8392         }
8393         atom = &mol->atoms[nr % mol->n_atoms];
8394         found = TNG_TRUE;
8395         break;
8396     }
8397     if(!found)
8398     {
8399         return(TNG_FAILURE);
8400     }
8401     if(!atom->residue)
8402     {
8403         return(TNG_FAILURE);
8404     }
8405
8406     strncpy(name, atom->residue->name, max_len - 1);
8407     name[max_len - 1] = 0;
8408
8409     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
8410     {
8411         return(TNG_FAILURE);
8412     }
8413     return(TNG_SUCCESS);
8414 }
8415
8416 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
8417                 (const tng_trajectory_t tng_data,
8418                  const int64_t nr,
8419                  int64_t *id)
8420 {
8421     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8422     tng_molecule_t mol;
8423     tng_atom_t atom;
8424     tng_bool found = TNG_FALSE;
8425
8426     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8427     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8428
8429     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8430
8431     if(!molecule_cnt_list)
8432     {
8433         return(TNG_FAILURE);
8434     }
8435
8436     for(i = 0; i < tng_data->n_molecules; i++)
8437     {
8438         mol = &tng_data->molecules[i];
8439         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8440         {
8441             cnt += mol->n_atoms * molecule_cnt_list[i];
8442             continue;
8443         }
8444         atom = &mol->atoms[nr % mol->n_atoms];
8445         found = TNG_TRUE;
8446         break;
8447     }
8448     if(!found)
8449     {
8450         return(TNG_FAILURE);
8451     }
8452     if(!atom->residue)
8453     {
8454         return(TNG_FAILURE);
8455     }
8456
8457     *id = atom->residue->id;
8458
8459     return(TNG_SUCCESS);
8460 }
8461
8462 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
8463                 (const tng_trajectory_t tng_data,
8464                  const int64_t nr,
8465                  int64_t *id)
8466 {
8467     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
8468     tng_molecule_t mol;
8469     tng_atom_t atom;
8470     tng_bool found = TNG_FALSE;
8471
8472     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8473     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8474
8475     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8476
8477     if(!molecule_cnt_list)
8478     {
8479         return(TNG_FAILURE);
8480     }
8481
8482     for(i = 0; i < tng_data->n_molecules; i++)
8483     {
8484         mol = &tng_data->molecules[i];
8485         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8486         {
8487             cnt += mol->n_atoms * molecule_cnt_list[i];
8488             offset += mol->n_residues * molecule_cnt_list[i];
8489             continue;
8490         }
8491         atom = &mol->atoms[nr % mol->n_atoms];
8492         found = TNG_TRUE;
8493         break;
8494     }
8495     if(!found)
8496     {
8497         return(TNG_FAILURE);
8498     }
8499     if(!atom->residue)
8500     {
8501         return(TNG_FAILURE);
8502     }
8503
8504     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
8505
8506     *id = atom->residue->id + offset;
8507
8508     return(TNG_SUCCESS);
8509 }
8510
8511 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
8512                 (const tng_trajectory_t tng_data,
8513                  const int64_t nr,
8514                  char *name,
8515                  const int max_len)
8516 {
8517     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8518     tng_molecule_t mol;
8519     tng_atom_t atom;
8520     tng_bool found = TNG_FALSE;
8521
8522     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8523     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8524
8525     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8526
8527     if(!molecule_cnt_list)
8528     {
8529         return(TNG_FAILURE);
8530     }
8531
8532     for(i = 0; i < tng_data->n_molecules; i++)
8533     {
8534         mol = &tng_data->molecules[i];
8535         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8536         {
8537             cnt += mol->n_atoms * molecule_cnt_list[i];
8538             continue;
8539         }
8540         atom = &mol->atoms[nr % mol->n_atoms];
8541         found = TNG_TRUE;
8542         break;
8543     }
8544     if(!found)
8545     {
8546         return(TNG_FAILURE);
8547     }
8548
8549     strncpy(name, atom->name, max_len - 1);
8550     name[max_len - 1] = 0;
8551
8552     if(strlen(atom->name) > (unsigned int)max_len - 1)
8553     {
8554         return(TNG_FAILURE);
8555     }
8556     return(TNG_SUCCESS);
8557 }
8558
8559 tng_function_status tng_atom_type_of_particle_nr_get
8560                 (const tng_trajectory_t tng_data,
8561                  const int64_t nr,
8562                  char *type,
8563                  const int max_len)
8564 {
8565     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8566     tng_molecule_t mol;
8567     tng_atom_t atom;
8568     tng_bool found = TNG_FALSE;
8569
8570     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8571     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
8572
8573     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8574
8575     if(!molecule_cnt_list)
8576     {
8577         return(TNG_FAILURE);
8578     }
8579
8580     for(i = 0; i < tng_data->n_molecules; i++)
8581     {
8582         mol = &tng_data->molecules[i];
8583         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8584         {
8585             cnt += mol->n_atoms * molecule_cnt_list[i];
8586             continue;
8587         }
8588         atom = &mol->atoms[nr % mol->n_atoms];
8589         found = TNG_TRUE;
8590         break;
8591     }
8592     if(!found)
8593     {
8594         return(TNG_FAILURE);
8595     }
8596
8597     strncpy(type, atom->atom_type, max_len - 1);
8598     type[max_len - 1] = 0;
8599
8600     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
8601     {
8602         return(TNG_FAILURE);
8603     }
8604     return(TNG_SUCCESS);
8605 }
8606
8607 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
8608                 (const tng_trajectory_t tng_data,
8609                  const int64_t num_first_particle,
8610                  const int64_t n_particles,
8611                  const int64_t *mapping_table)
8612 {
8613     int64_t i;
8614     tng_particle_mapping_t mapping;
8615     tng_trajectory_frame_set_t frame_set;
8616
8617     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8618
8619     frame_set = &tng_data->current_trajectory_frame_set;
8620
8621     /* Sanity check of the particle ranges. Split into multiple if
8622      * statements for improved readability */
8623     for(i = 0; i < frame_set->n_mapping_blocks; i++)
8624     {
8625         mapping = &frame_set->mappings[i];
8626         if(num_first_particle >= mapping->num_first_particle &&
8627            num_first_particle < mapping->num_first_particle +
8628                                    mapping->n_particles)
8629         {
8630             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8631             return(TNG_FAILURE);
8632         }
8633         if(num_first_particle + n_particles >=
8634            mapping->num_first_particle &&
8635            num_first_particle + n_particles <
8636            mapping->num_first_particle + mapping->n_particles)
8637         {
8638             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8639             return(TNG_FAILURE);
8640         }
8641         if(mapping->num_first_particle >= num_first_particle &&
8642            mapping->num_first_particle < num_first_particle +
8643                                             n_particles)
8644         {
8645             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8646             return(TNG_FAILURE);
8647         }
8648         if(mapping->num_first_particle + mapping->n_particles >
8649            num_first_particle &&
8650            mapping->num_first_particle + mapping->n_particles <
8651            num_first_particle + n_particles)
8652         {
8653             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8654             return(TNG_FAILURE);
8655         }
8656     }
8657
8658     frame_set->n_mapping_blocks++;
8659
8660     mapping = (tng_particle_mapping_t)realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
8661                                               frame_set->n_mapping_blocks);
8662
8663     if(!mapping)
8664     {
8665         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8666                 __FILE__, __LINE__);
8667         free(frame_set->mappings);
8668         frame_set->mappings = 0;
8669         return(TNG_CRITICAL);
8670     }
8671     frame_set->mappings = mapping;
8672
8673     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
8674     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
8675
8676     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = (int64_t *)malloc(sizeof(int64_t) * n_particles);
8677     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
8678     {
8679         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8680                 __FILE__, __LINE__);
8681         return(TNG_CRITICAL);
8682     }
8683
8684     for(i=0; i<n_particles; i++)
8685     {
8686         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
8687     }
8688
8689     return(TNG_SUCCESS);
8690 }
8691
8692 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(const tng_trajectory_t tng_data)
8693 {
8694     tng_trajectory_frame_set_t frame_set;
8695     tng_particle_mapping_t mapping;
8696     int64_t i;
8697
8698     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8699
8700     frame_set = &tng_data->current_trajectory_frame_set;
8701
8702     if(frame_set->n_mapping_blocks && frame_set->mappings)
8703     {
8704         for(i = 0; i < frame_set->n_mapping_blocks; i++)
8705         {
8706             mapping = &frame_set->mappings[i];
8707             if(mapping->real_particle_numbers)
8708             {
8709                 free(mapping->real_particle_numbers);
8710                 mapping->real_particle_numbers = 0;
8711             }
8712         }
8713         free(frame_set->mappings);
8714         frame_set->mappings = 0;
8715         frame_set->n_mapping_blocks = 0;
8716     }
8717
8718     return(TNG_SUCCESS);
8719 }
8720
8721 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
8722 {
8723     time_t seconds;
8724     tng_trajectory_frame_set_t frame_set;
8725     tng_trajectory_t tng_data;
8726
8727     *tng_data_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
8728     if(!*tng_data_p)
8729     {
8730         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8731                 __FILE__, __LINE__);
8732         return(TNG_CRITICAL);
8733     }
8734
8735     tng_data = *tng_data_p;
8736
8737     frame_set = &tng_data->current_trajectory_frame_set;
8738
8739     tng_data->input_file_path = 0;
8740     tng_data->input_file = 0;
8741     tng_data->input_file_len = 0;
8742     tng_data->output_file_path = 0;
8743     tng_data->output_file = 0;
8744
8745     tng_data->first_program_name = 0;
8746     tng_data->first_user_name = 0;
8747     tng_data->first_computer_name = 0;
8748     tng_data->first_pgp_signature = 0;
8749     tng_data->last_program_name = 0;
8750     tng_data->last_user_name = 0;
8751     tng_data->last_computer_name = 0;
8752     tng_data->last_pgp_signature = 0;
8753     tng_data->forcefield_name = 0;
8754
8755     seconds = time(0);
8756     if ( seconds == -1)
8757     {
8758         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
8759     }
8760     else
8761     {
8762         tng_data->time = seconds;
8763     }
8764
8765     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
8766     tng_data->first_trajectory_frame_set_input_file_pos = -1;
8767     tng_data->last_trajectory_frame_set_input_file_pos = -1;
8768     tng_data->current_trajectory_frame_set_input_file_pos = -1;
8769     tng_data->first_trajectory_frame_set_output_file_pos = -1;
8770     tng_data->last_trajectory_frame_set_output_file_pos = -1;
8771     tng_data->current_trajectory_frame_set_output_file_pos = -1;
8772     tng_data->frame_set_n_frames = 100;
8773     tng_data->n_trajectory_frame_sets = 0;
8774     tng_data->medium_stride_length = 100;
8775     tng_data->long_stride_length = 10000;
8776
8777     tng_data->time_per_frame = -1;
8778
8779     tng_data->n_particle_data_blocks = 0;
8780     tng_data->n_data_blocks = 0;
8781
8782     tng_data->non_tr_particle_data = 0;
8783     tng_data->non_tr_data = 0;
8784
8785     tng_data->compress_algo_pos = 0;
8786     tng_data->compress_algo_vel = 0;
8787     tng_data->compression_precision = 1000;
8788     tng_data->distance_unit_exponential = -9;
8789
8790     frame_set->first_frame = -1;
8791     frame_set->n_mapping_blocks = 0;
8792     frame_set->mappings = 0;
8793     frame_set->molecule_cnt_list = 0;
8794
8795     frame_set->n_particle_data_blocks = 0;
8796     frame_set->n_data_blocks = 0;
8797
8798     frame_set->tr_particle_data = 0;
8799     frame_set->tr_data = 0;
8800
8801     frame_set->n_written_frames = 0;
8802     frame_set->n_unwritten_frames = 0;
8803
8804     frame_set->next_frame_set_file_pos = -1;
8805     frame_set->prev_frame_set_file_pos = -1;
8806     frame_set->medium_stride_next_frame_set_file_pos = -1;
8807     frame_set->medium_stride_prev_frame_set_file_pos = -1;
8808     frame_set->long_stride_next_frame_set_file_pos = -1;
8809     frame_set->long_stride_prev_frame_set_file_pos = -1;
8810
8811     frame_set->first_frame_time = -1;
8812
8813     tng_data->n_molecules = 0;
8814     tng_data->molecules = 0;
8815     tng_data->molecule_cnt_list = 0;
8816     tng_data->n_particles = 0;
8817
8818     {
8819       /* Check the endianness of the computer */
8820       static int32_t endianness_32 = 0x01234567;
8821       /* 0x01234567 */
8822       if ( *(const unsigned char*)&endianness_32 == 0x01 )
8823         {
8824           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
8825         }
8826
8827       /* 0x67452301 */
8828       else if( *(const unsigned char*)&endianness_32 == 0x67 )
8829         {
8830           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
8831
8832         }
8833
8834       /* 0x45670123 */
8835       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
8836         {
8837           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
8838         }
8839     }
8840     {
8841       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
8842       /* 0x0123456789ABCDEF */
8843       if ( *(const unsigned char*)&endianness_64 == 0x01 )
8844         {
8845           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
8846         }
8847
8848       /* 0xEFCDAB8967452301 */
8849       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
8850         {
8851           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
8852         }
8853
8854       /* 0x89ABCDEF01234567 */
8855       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
8856         {
8857           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
8858         }
8859
8860       /* 0x45670123CDEF89AB */
8861       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
8862         {
8863           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
8864         }
8865
8866       /* 0x23016745AB89EFCD */
8867       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
8868         {
8869           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
8870         }
8871     }
8872
8873     /* By default do not swap the byte order, i.e. keep the byte order of the
8874      * architecture. The input file endianness will be set when reading the
8875      * header. The output endianness can be changed - before the file is
8876      * written. */
8877     tng_data->input_endianness_swap_func_32 = 0;
8878     tng_data->input_endianness_swap_func_64 = 0;
8879     tng_data->output_endianness_swap_func_32 = 0;
8880     tng_data->output_endianness_swap_func_64 = 0;
8881
8882     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
8883     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
8884     tng_data->current_trajectory_frame_set.n_frames = 0;
8885
8886     return(TNG_SUCCESS);
8887 }
8888
8889 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
8890 {
8891     int64_t i, j, k, l;
8892     int64_t n_particles, n_values_per_frame;
8893     tng_trajectory_t tng_data = *tng_data_p;
8894     tng_trajectory_frame_set_t frame_set;
8895
8896     if(!*tng_data_p)
8897     {
8898         return(TNG_SUCCESS);
8899     }
8900
8901     frame_set = &tng_data->current_trajectory_frame_set;
8902
8903     if(tng_data->input_file)
8904     {
8905         if(tng_data->output_file == tng_data->input_file)
8906         {
8907             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
8908             tng_data->output_file = 0;
8909         }
8910         fclose(tng_data->input_file);
8911         tng_data->input_file = 0;
8912     }
8913
8914     if(tng_data->input_file_path)
8915     {
8916         free(tng_data->input_file_path);
8917         tng_data->input_file_path = 0;
8918     }
8919
8920     if(tng_data->output_file)
8921     {
8922         /* FIXME: Do not always write the hash */
8923         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
8924         fclose(tng_data->output_file);
8925         tng_data->output_file = 0;
8926     }
8927
8928     if(tng_data->output_file_path)
8929     {
8930         free(tng_data->output_file_path);
8931         tng_data->output_file_path = 0;
8932     }
8933
8934     if(tng_data->first_program_name)
8935     {
8936         free(tng_data->first_program_name);
8937         tng_data->first_program_name = 0;
8938     }
8939
8940     if(tng_data->last_program_name)
8941     {
8942         free(tng_data->last_program_name);
8943         tng_data->last_program_name = 0;
8944     }
8945
8946     if(tng_data->first_user_name)
8947     {
8948         free(tng_data->first_user_name);
8949         tng_data->first_user_name = 0;
8950     }
8951
8952     if(tng_data->last_user_name)
8953     {
8954         free(tng_data->last_user_name);
8955         tng_data->last_user_name = 0;
8956     }
8957
8958     if(tng_data->first_computer_name)
8959     {
8960         free(tng_data->first_computer_name);
8961         tng_data->first_computer_name = 0;
8962     }
8963
8964     if(tng_data->last_computer_name)
8965     {
8966         free(tng_data->last_computer_name);
8967         tng_data->last_computer_name = 0;
8968     }
8969
8970     if(tng_data->first_pgp_signature)
8971     {
8972         free(tng_data->first_pgp_signature);
8973         tng_data->first_pgp_signature = 0;
8974     }
8975
8976     if(tng_data->last_pgp_signature)
8977     {
8978         free(tng_data->last_pgp_signature);
8979         tng_data->last_pgp_signature = 0;
8980     }
8981
8982     if(tng_data->forcefield_name)
8983     {
8984         free(tng_data->forcefield_name);
8985         tng_data->forcefield_name = 0;
8986     }
8987
8988     tng_frame_set_particle_mapping_free(tng_data);
8989
8990     if(frame_set->molecule_cnt_list)
8991     {
8992         free(frame_set->molecule_cnt_list);
8993         frame_set->molecule_cnt_list = 0;
8994     }
8995
8996     if(tng_data->var_num_atoms_flag)
8997     {
8998         n_particles = frame_set->n_particles;
8999     }
9000     else
9001     {
9002         n_particles = tng_data->n_particles;
9003     }
9004
9005     if(tng_data->non_tr_particle_data)
9006     {
9007         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
9008         {
9009             if(tng_data->non_tr_particle_data[i].values)
9010             {
9011                 free(tng_data->non_tr_particle_data[i].values);
9012                 tng_data->non_tr_particle_data[i].values = 0;
9013             }
9014
9015             if(tng_data->non_tr_particle_data[i].strings)
9016             {
9017                 n_values_per_frame = tng_data->non_tr_particle_data[i].
9018                                      n_values_per_frame;
9019                 if(tng_data->non_tr_particle_data[i].strings[0])
9020                 {
9021                     for(j = 0; j < n_particles; j++)
9022                     {
9023                         if(tng_data->non_tr_particle_data[i].strings[0][j])
9024                         {
9025                             for(k = 0; k < n_values_per_frame; k++)
9026                             {
9027                                 if(tng_data->non_tr_particle_data[i].
9028                                    strings[0][j][k])
9029                                 {
9030                                     free(tng_data->non_tr_particle_data[i].
9031                                          strings[0][j][k]);
9032                                     tng_data->non_tr_particle_data[i].
9033                                     strings[0][j][k] = 0;
9034                                 }
9035                             }
9036                             free(tng_data->non_tr_particle_data[i].
9037                                  strings[0][j]);
9038                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
9039                         }
9040                     }
9041                     free(tng_data->non_tr_particle_data[i].strings[0]);
9042                     tng_data->non_tr_particle_data[i].strings[0] = 0;
9043                 }
9044                 free(tng_data->non_tr_particle_data[i].strings);
9045                 tng_data->non_tr_particle_data[i].strings = 0;
9046             }
9047
9048             if(tng_data->non_tr_particle_data[i].block_name)
9049             {
9050                 free(tng_data->non_tr_particle_data[i].block_name);
9051                 tng_data->non_tr_particle_data[i].block_name = 0;
9052             }
9053         }
9054         free(tng_data->non_tr_particle_data);
9055         tng_data->non_tr_particle_data = 0;
9056     }
9057
9058     if(tng_data->non_tr_data)
9059     {
9060         for(i = 0; i < tng_data->n_data_blocks; i++)
9061         {
9062             if(tng_data->non_tr_data[i].values)
9063             {
9064                 free(tng_data->non_tr_data[i].values);
9065                 tng_data->non_tr_data[i].values = 0;
9066             }
9067
9068             if(tng_data->non_tr_data[i].strings)
9069             {
9070                 n_values_per_frame = tng_data->non_tr_data[i].
9071                                      n_values_per_frame;
9072                 if(tng_data->non_tr_data[i].strings[0][0])
9073                 {
9074                     for(j = 0; j < n_values_per_frame; j++)
9075                     {
9076                         if(tng_data->non_tr_data[i].strings[0][0][j])
9077                         {
9078                             free(tng_data->non_tr_data[i].strings[0][0][j]);
9079                             tng_data->non_tr_data[i].strings[0][0][j] = 0;
9080                         }
9081                     }
9082                     free(tng_data->non_tr_data[i].strings[0][0]);
9083                     tng_data->non_tr_data[i].strings[0][0] = 0;
9084                 }
9085                 free(tng_data->non_tr_data[i].strings[0]);
9086                 tng_data->non_tr_data[i].strings[0] = 0;
9087                 free(tng_data->non_tr_data[i].strings);
9088                 tng_data->non_tr_data[i].strings = 0;
9089             }
9090
9091             if(tng_data->non_tr_data[i].block_name)
9092             {
9093                 free(tng_data->non_tr_data[i].block_name);
9094                 tng_data->non_tr_data[i].block_name = 0;
9095             }
9096         }
9097         free(tng_data->non_tr_data);
9098         tng_data->non_tr_data = 0;
9099     }
9100
9101     tng_data->n_particle_data_blocks = 0;
9102     tng_data->n_data_blocks = 0;
9103
9104     if(tng_data->compress_algo_pos)
9105     {
9106         free(tng_data->compress_algo_pos);
9107         tng_data->compress_algo_pos = 0;
9108     }
9109     if(tng_data->compress_algo_vel)
9110     {
9111         free(tng_data->compress_algo_vel);
9112         tng_data->compress_algo_vel = 0;
9113     }
9114
9115     if(frame_set->tr_particle_data)
9116     {
9117         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
9118         {
9119             if(frame_set->tr_particle_data[i].values)
9120             {
9121                 free(frame_set->tr_particle_data[i].values);
9122                 frame_set->tr_particle_data[i].values = 0;
9123             }
9124
9125             if(frame_set->tr_particle_data[i].strings)
9126             {
9127                 n_values_per_frame = frame_set->tr_particle_data[i].
9128                                      n_values_per_frame;
9129                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
9130                 {
9131                     if(frame_set->tr_particle_data[i].strings[j])
9132                     {
9133                         for(k = 0; k < n_particles; k++)
9134                         {
9135                             if(frame_set->tr_particle_data[i].
9136                                 strings[j][k])
9137                             {
9138                                 for(l = 0; l < n_values_per_frame; l++)
9139                                 {
9140                                     if(frame_set->tr_particle_data[i].
9141                                         strings[j][k][l])
9142                                     {
9143                                         free(frame_set->tr_particle_data[i].
9144                                                 strings[j][k][l]);
9145                                         frame_set->tr_particle_data[i].
9146                                         strings[j][k][l] = 0;
9147                                     }
9148                                 }
9149                                 free(frame_set->tr_particle_data[i].
9150                                         strings[j][k]);
9151                                 frame_set->tr_particle_data[i].
9152                                 strings[j][k] = 0;
9153                             }
9154                         }
9155                         free(frame_set->tr_particle_data[i].strings[j]);
9156                         frame_set->tr_particle_data[i].strings[j] = 0;
9157                     }
9158                 }
9159                 free(frame_set->tr_particle_data[i].strings);
9160                 frame_set->tr_particle_data[i].strings = 0;
9161             }
9162
9163             if(frame_set->tr_particle_data[i].block_name)
9164             {
9165                 free(frame_set->tr_particle_data[i].block_name);
9166                 frame_set->tr_particle_data[i].block_name = 0;
9167             }
9168         }
9169         free(frame_set->tr_particle_data);
9170         frame_set->tr_particle_data = 0;
9171     }
9172
9173     if(frame_set->tr_data)
9174     {
9175         for(i = 0; i < frame_set->n_data_blocks; i++)
9176         {
9177             if(frame_set->tr_data[i].values)
9178             {
9179                 free(frame_set->tr_data[i].values);
9180                 frame_set->tr_data[i].values = 0;
9181             }
9182
9183             if(frame_set->tr_data[i].strings)
9184             {
9185                 n_values_per_frame = frame_set->tr_data[i].
9186                                      n_values_per_frame;
9187                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
9188                 {
9189                     if(frame_set->tr_data[i].strings[j])
9190                     {
9191                         for(k = 0; k < n_values_per_frame; k++)
9192                         {
9193                             if(frame_set->tr_data[i].strings[j][k])
9194                             {
9195                                 free(frame_set->tr_data[i].strings[j][k]);
9196                                 frame_set->tr_data[i].strings[j][k] = 0;
9197                             }
9198                         }
9199                         free(frame_set->tr_data[i].strings[j]);
9200                         frame_set->tr_data[i].strings[j] = 0;
9201                     }
9202                 }
9203                 free(frame_set->tr_data[i].strings);
9204                 frame_set->tr_data[i].strings = 0;
9205             }
9206
9207             if(frame_set->tr_data[i].block_name)
9208             {
9209                 free(frame_set->tr_data[i].block_name);
9210                 frame_set->tr_data[i].block_name = 0;
9211             }
9212         }
9213         free(frame_set->tr_data);
9214         frame_set->tr_data = 0;
9215     }
9216
9217     frame_set->n_particle_data_blocks = 0;
9218     frame_set->n_data_blocks = 0;
9219
9220     if(tng_data->molecules)
9221     {
9222         for(i = 0; i < tng_data->n_molecules; i++)
9223         {
9224             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
9225         }
9226         free(tng_data->molecules);
9227         tng_data->molecules = 0;
9228         tng_data->n_molecules = 0;
9229     }
9230     if(tng_data->molecule_cnt_list)
9231     {
9232         free(tng_data->molecule_cnt_list);
9233         tng_data->molecule_cnt_list = 0;
9234     }
9235
9236     free(*tng_data_p);
9237     *tng_data_p = 0;
9238
9239     return(TNG_SUCCESS);
9240 }
9241
9242 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src
9243                 (const tng_trajectory_t src,
9244                  tng_trajectory_t *dest_p)
9245 {
9246     tng_trajectory_frame_set_t frame_set;
9247     tng_trajectory_t dest;
9248
9249     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
9250
9251     *dest_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
9252     if(!*dest_p)
9253     {
9254         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9255                 __FILE__, __LINE__);
9256         return(TNG_CRITICAL);
9257     }
9258
9259     dest = *dest_p;
9260
9261     frame_set = &dest->current_trajectory_frame_set;
9262
9263     if(src->input_file_path)
9264     {
9265         dest->input_file_path = (char *)malloc(strlen(src->input_file_path) + 1);
9266         if(!dest->input_file_path)
9267         {
9268             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9269                     __FILE__, __LINE__);
9270             return(TNG_CRITICAL);
9271         }
9272         strcpy(dest->input_file_path, src->input_file_path);
9273         dest->input_file_len = src->input_file_len;
9274     }
9275     else
9276     {
9277         dest->input_file_path = 0;
9278     }
9279     dest->input_file = 0;
9280     if(src->output_file_path)
9281     {
9282         dest->output_file_path = (char *)malloc(strlen(src->output_file_path) + 1);
9283         if(!dest->output_file_path)
9284         {
9285             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9286                     __FILE__, __LINE__);
9287             return(TNG_CRITICAL);
9288         }
9289         strcpy(dest->output_file_path, src->output_file_path);
9290     }
9291     else
9292     {
9293         dest->output_file_path = 0;
9294     }
9295     dest->output_file = 0;
9296
9297     dest->first_program_name = 0;
9298     dest->first_user_name = 0;
9299     dest->first_computer_name = 0;
9300     dest->first_pgp_signature = 0;
9301     dest->last_program_name = 0;
9302     dest->last_user_name = 0;
9303     dest->last_computer_name = 0;
9304     dest->last_pgp_signature = 0;
9305     dest->forcefield_name = 0;
9306
9307     dest->var_num_atoms_flag = src->var_num_atoms_flag;
9308     dest->first_trajectory_frame_set_input_file_pos =
9309     src->first_trajectory_frame_set_input_file_pos;
9310     dest->last_trajectory_frame_set_input_file_pos =
9311     src->last_trajectory_frame_set_input_file_pos;
9312     dest->current_trajectory_frame_set_input_file_pos =
9313     src->current_trajectory_frame_set_input_file_pos;
9314     dest->first_trajectory_frame_set_output_file_pos =
9315     src->first_trajectory_frame_set_output_file_pos;
9316     dest->last_trajectory_frame_set_output_file_pos =
9317     src->last_trajectory_frame_set_output_file_pos;
9318     dest->current_trajectory_frame_set_output_file_pos =
9319     src->current_trajectory_frame_set_output_file_pos;
9320     dest->frame_set_n_frames = src->frame_set_n_frames;
9321     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
9322     dest->medium_stride_length = src->medium_stride_length;
9323     dest->long_stride_length = src->long_stride_length;
9324
9325     dest->time_per_frame = src->time_per_frame;
9326
9327     /* Currently the non trajectory data blocks are not copied since it
9328      * can lead to problems when freeing memory in a parallel block. */
9329     dest->n_particle_data_blocks = 0;
9330     dest->n_data_blocks = 0;
9331     dest->non_tr_particle_data = 0;
9332     dest->non_tr_data = 0;
9333
9334     dest->compress_algo_pos = 0;
9335     dest->compress_algo_vel = 0;
9336     dest->distance_unit_exponential = -9;
9337     dest->compression_precision = 1000;
9338
9339     frame_set->n_mapping_blocks = 0;
9340     frame_set->mappings = 0;
9341     frame_set->molecule_cnt_list = 0;
9342
9343     frame_set->n_particle_data_blocks = 0;
9344     frame_set->n_data_blocks = 0;
9345
9346     frame_set->tr_particle_data = 0;
9347     frame_set->tr_data = 0;
9348
9349     frame_set->n_written_frames = 0;
9350     frame_set->n_unwritten_frames = 0;
9351
9352     frame_set->next_frame_set_file_pos = -1;
9353     frame_set->prev_frame_set_file_pos = -1;
9354     frame_set->medium_stride_next_frame_set_file_pos = -1;
9355     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9356     frame_set->long_stride_next_frame_set_file_pos = -1;
9357     frame_set->long_stride_prev_frame_set_file_pos = -1;
9358     frame_set->first_frame = -1;
9359
9360     dest->n_molecules = 0;
9361     dest->molecules = 0;
9362     dest->molecule_cnt_list = 0;
9363     dest->n_particles = src->n_particles;
9364
9365     dest->endianness_32 = src->endianness_32;
9366     dest->endianness_64 = src->endianness_64;
9367     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
9368     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
9369     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
9370     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
9371
9372     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9373     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9374     dest->current_trajectory_frame_set.n_frames = 0;
9375
9376     return(TNG_SUCCESS);
9377 }
9378
9379 tng_function_status DECLSPECDLLEXPORT tng_input_file_get
9380                 (const tng_trajectory_t tng_data,
9381                  char *file_name,
9382                  const int max_len)
9383 {
9384     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9385     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9386
9387     strncpy(file_name, tng_data->input_file_path, max_len - 1);
9388     file_name[max_len - 1] = 0;
9389
9390     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
9391     {
9392         return(TNG_FAILURE);
9393     }
9394     return(TNG_SUCCESS);
9395 }
9396
9397 tng_function_status DECLSPECDLLEXPORT tng_input_file_set
9398                 (const tng_trajectory_t tng_data,
9399                  const char *file_name)
9400 {
9401     unsigned int len;
9402     char *temp;
9403
9404     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9405     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9406
9407
9408     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
9409                                            file_name) == 0)
9410     {
9411         return(TNG_SUCCESS);
9412     }
9413
9414     if(tng_data->input_file)
9415     {
9416         fclose(tng_data->input_file);
9417     }
9418
9419     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9420     temp = (char *)realloc(tng_data->input_file_path, len);
9421     if(!temp)
9422     {
9423         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9424                 __FILE__, __LINE__);
9425         free(tng_data->input_file_path);
9426         tng_data->input_file_path = 0;
9427         return(TNG_CRITICAL);
9428     }
9429     tng_data->input_file_path = temp;
9430
9431     strncpy(tng_data->input_file_path, file_name, len);
9432
9433     return(tng_input_file_init(tng_data));
9434 }
9435
9436 tng_function_status tng_output_file_get
9437                 (const tng_trajectory_t tng_data,
9438                  char *file_name,
9439                  const int max_len)
9440 {
9441     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9442     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9443
9444     strncpy(file_name, tng_data->output_file_path, max_len - 1);
9445     file_name[max_len - 1] = 0;
9446
9447     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
9448     {
9449         return(TNG_FAILURE);
9450     }
9451     return(TNG_SUCCESS);
9452 }
9453
9454 tng_function_status DECLSPECDLLEXPORT tng_output_file_set
9455                 (const tng_trajectory_t tng_data,
9456                  const char *file_name)
9457 {
9458     int len;
9459     char *temp;
9460
9461     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9462     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9463
9464     if(tng_data->output_file_path &&
9465        strcmp(tng_data->output_file_path, file_name) == 0)
9466     {
9467         return(TNG_SUCCESS);
9468     }
9469
9470     if(tng_data->output_file)
9471     {
9472         fclose(tng_data->output_file);
9473     }
9474
9475     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9476     temp = (char *)realloc(tng_data->output_file_path, len);
9477     if(!temp)
9478     {
9479         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9480                 __FILE__, __LINE__);
9481         free(tng_data->output_file_path);
9482         tng_data->output_file_path = 0;
9483         return(TNG_CRITICAL);
9484     }
9485     tng_data->output_file_path = temp;
9486
9487     strncpy(tng_data->output_file_path, file_name, len);
9488
9489     return(tng_output_file_init(tng_data));
9490 }
9491
9492 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
9493                 (const tng_trajectory_t tng_data,
9494                  const char *file_name)
9495 {
9496     int len;
9497     char *temp;
9498
9499     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9500     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9501
9502     if(tng_data->output_file_path &&
9503        strcmp(tng_data->output_file_path, file_name) == 0)
9504     {
9505         return(TNG_SUCCESS);
9506     }
9507
9508     if(tng_data->output_file)
9509     {
9510         fclose(tng_data->output_file);
9511     }
9512
9513     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9514     temp = (char *)realloc(tng_data->output_file_path, len);
9515     if(!temp)
9516     {
9517         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9518                 __FILE__, __LINE__);
9519         free(tng_data->output_file_path);
9520         tng_data->output_file_path = 0;
9521         return(TNG_CRITICAL);
9522     }
9523     tng_data->output_file_path = temp;
9524
9525     strncpy(tng_data->output_file_path, file_name, len);
9526
9527     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
9528     if(!tng_data->output_file)
9529     {
9530         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
9531                 tng_data->output_file_path, __FILE__, __LINE__);
9532         return(TNG_CRITICAL);
9533     }
9534     tng_data->input_file = tng_data->output_file;
9535
9536     return(TNG_SUCCESS);
9537 }
9538
9539 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
9540                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
9541 {
9542     tng_endianness_32 end_32;
9543     tng_endianness_64 end_64;
9544
9545     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9546     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
9547
9548     if(tng_data->output_endianness_swap_func_32)
9549     {
9550         /* If other endianness variants are added they must be added here as well */
9551         if(tng_data->output_endianness_swap_func_32 ==
9552            &tng_swap_byte_order_big_endian_32)
9553         {
9554             end_32 = TNG_BIG_ENDIAN_32;
9555         }
9556         else if(tng_data->output_endianness_swap_func_32 ==
9557                 &tng_swap_byte_order_little_endian_32)
9558         {
9559             end_32 = TNG_LITTLE_ENDIAN_32;
9560         }
9561         else
9562         {
9563             return(TNG_FAILURE);
9564         }
9565     }
9566     else
9567     {
9568         end_32 = (tng_endianness_32)tng_data->endianness_32;
9569     }
9570
9571     if(tng_data->output_endianness_swap_func_64)
9572     {
9573         /* If other endianness variants are added they must be added here as well */
9574         if(tng_data->output_endianness_swap_func_64 ==
9575            &tng_swap_byte_order_big_endian_64)
9576         {
9577             end_64 = TNG_BIG_ENDIAN_64;
9578         }
9579         else if(tng_data->output_endianness_swap_func_64 ==
9580                 &tng_swap_byte_order_little_endian_64)
9581         {
9582             end_64 = TNG_LITTLE_ENDIAN_64;
9583         }
9584         else
9585         {
9586             return(TNG_FAILURE);
9587         }
9588     }
9589     else
9590     {
9591         end_64 = (tng_endianness_64)tng_data->endianness_64;
9592     }
9593
9594     if((int)end_32 != (int)end_64)
9595     {
9596         return(TNG_FAILURE);
9597     }
9598
9599     if(end_32 == TNG_LITTLE_ENDIAN_32)
9600     {
9601         *endianness = TNG_LITTLE_ENDIAN;
9602     }
9603
9604     else if(end_32 == TNG_BIG_ENDIAN_32)
9605     {
9606         *endianness = TNG_BIG_ENDIAN;
9607     }
9608     else
9609     {
9610         return(TNG_FAILURE);
9611     }
9612
9613     return(TNG_SUCCESS);
9614 }
9615
9616 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
9617                 (const tng_trajectory_t tng_data,
9618                  const tng_file_endianness endianness)
9619 {
9620     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9621
9622     /* Tne endianness cannot be changed if the data has already been written
9623      * to the output file. */
9624     if(ftello(tng_data->output_file) > 0)
9625     {
9626         return(TNG_FAILURE);
9627     }
9628
9629     if(endianness == TNG_BIG_ENDIAN)
9630     {
9631         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
9632         {
9633             tng_data->output_endianness_swap_func_32 = 0;
9634         }
9635         else
9636         {
9637             tng_data->output_endianness_swap_func_32 =
9638             &tng_swap_byte_order_big_endian_32;
9639         }
9640         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
9641         {
9642             tng_data->output_endianness_swap_func_64 = 0;
9643         }
9644         else
9645         {
9646             tng_data->output_endianness_swap_func_64 =
9647             &tng_swap_byte_order_big_endian_64;
9648         }
9649         return(TNG_SUCCESS);
9650     }
9651     else if(endianness == TNG_LITTLE_ENDIAN)
9652     {
9653         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
9654         {
9655             tng_data->output_endianness_swap_func_32 = 0;
9656         }
9657         else
9658         {
9659             tng_data->output_endianness_swap_func_32 =
9660             &tng_swap_byte_order_little_endian_32;
9661         }
9662         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
9663         {
9664             tng_data->output_endianness_swap_func_64 = 0;
9665         }
9666         else
9667         {
9668             tng_data->output_endianness_swap_func_64 =
9669             &tng_swap_byte_order_little_endian_64;
9670         }
9671         return(TNG_SUCCESS);
9672     }
9673
9674     /* If the specified endianness is neither big nor little endian return a
9675      * failure. */
9676     return(TNG_FAILURE);
9677 }
9678
9679 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
9680                     (const tng_trajectory_t tng_data,
9681                      char *name,
9682                      const int max_len)
9683 {
9684     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9685     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9686
9687     strncpy(name, tng_data->first_program_name, max_len - 1);
9688     name[max_len - 1] = 0;
9689
9690     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
9691     {
9692         return(TNG_FAILURE);
9693     }
9694     return(TNG_SUCCESS);
9695 }
9696
9697 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set
9698                 (const tng_trajectory_t tng_data,
9699                  const char *new_name)
9700 {
9701     unsigned int len;
9702
9703     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9704     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9705
9706     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9707
9708     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
9709     {
9710         free(tng_data->first_program_name);
9711         tng_data->first_program_name = 0;
9712     }
9713     if(!tng_data->first_program_name)
9714     {
9715         tng_data->first_program_name = (char *)malloc(len);
9716         if(!tng_data->first_program_name)
9717         {
9718             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9719                     __FILE__, __LINE__);
9720             return(TNG_CRITICAL);
9721         }
9722     }
9723
9724     strncpy(tng_data->first_program_name, new_name, len);
9725
9726     return(TNG_SUCCESS);
9727 }
9728
9729 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
9730                     (const tng_trajectory_t tng_data,
9731                      char *name, const int max_len)
9732 {
9733     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9734     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9735
9736     strncpy(name, tng_data->last_program_name, max_len - 1);
9737     name[max_len - 1] = 0;
9738
9739     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
9740     {
9741         return(TNG_FAILURE);
9742     }
9743     return(TNG_SUCCESS);
9744 }
9745
9746 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
9747                     (const tng_trajectory_t tng_data,
9748                      const char *new_name)
9749 {
9750     unsigned int len;
9751
9752     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9753     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9754
9755     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9756
9757     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
9758     {
9759         free(tng_data->last_program_name);
9760         tng_data->last_program_name = 0;
9761     }
9762     if(!tng_data->last_program_name)
9763     {
9764         tng_data->last_program_name = (char *)malloc(len);
9765         if(!tng_data->last_program_name)
9766         {
9767             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9768                     __FILE__, __LINE__);
9769             return(TNG_CRITICAL);
9770         }
9771     }
9772
9773     strncpy(tng_data->last_program_name, new_name, len);
9774
9775     return(TNG_SUCCESS);
9776 }
9777
9778 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
9779                     (const tng_trajectory_t tng_data,
9780                      char *name, const int max_len)
9781 {
9782     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9783     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9784
9785     strncpy(name, tng_data->first_user_name, max_len - 1);
9786     name[max_len - 1] = 0;
9787
9788     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
9789     {
9790         return(TNG_FAILURE);
9791     }
9792     return(TNG_SUCCESS);
9793 }
9794
9795 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
9796                     (const tng_trajectory_t tng_data,
9797                      const char *new_name)
9798 {
9799     unsigned int len;
9800
9801     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9802     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9803
9804     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9805
9806     /* If the currently stored string length is not enough to store the new
9807      * string it is freed and reallocated. */
9808     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
9809     {
9810         free(tng_data->first_user_name);
9811         tng_data->first_user_name = 0;
9812     }
9813     if(!tng_data->first_user_name)
9814     {
9815         tng_data->first_user_name = (char *)malloc(len);
9816         if(!tng_data->first_user_name)
9817         {
9818             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9819                     __FILE__, __LINE__);
9820             return(TNG_CRITICAL);
9821         }
9822     }
9823
9824     strncpy(tng_data->first_user_name, new_name, len);
9825
9826     return(TNG_SUCCESS);
9827 }
9828
9829 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
9830                     (const tng_trajectory_t tng_data,
9831                      char *name, const int max_len)
9832 {
9833     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9834     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9835
9836     strncpy(name, tng_data->last_user_name, max_len - 1);
9837     name[max_len - 1] = 0;
9838
9839     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
9840     {
9841         return(TNG_FAILURE);
9842     }
9843     return(TNG_SUCCESS);
9844 }
9845
9846 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
9847                     (const tng_trajectory_t tng_data,
9848                      const char *new_name)
9849 {
9850     unsigned int len;
9851
9852     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9853     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9854
9855     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9856
9857     /* If the currently stored string length is not enough to store the new
9858      * string it is freed and reallocated. */
9859     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
9860     {
9861         free(tng_data->last_user_name);
9862         tng_data->last_user_name = 0;
9863     }
9864     if(!tng_data->last_user_name)
9865     {
9866         tng_data->last_user_name = (char *)malloc(len);
9867         if(!tng_data->last_user_name)
9868         {
9869             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9870                     __FILE__, __LINE__);
9871             return(TNG_CRITICAL);
9872         }
9873     }
9874
9875     strncpy(tng_data->last_user_name, new_name, len);
9876
9877     return(TNG_SUCCESS);
9878 }
9879
9880 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
9881                     (const tng_trajectory_t tng_data,
9882                      char *name, const int max_len)
9883 {
9884     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9885     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9886
9887     strncpy(name, tng_data->first_computer_name, max_len - 1);
9888     name[max_len - 1] = 0;
9889
9890     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
9891     {
9892         return(TNG_FAILURE);
9893     }
9894     return(TNG_SUCCESS);
9895 }
9896
9897 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
9898                     (const tng_trajectory_t tng_data,
9899                      const char *new_name)
9900 {
9901     unsigned int len;
9902
9903     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9904     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9905
9906     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9907
9908     /* If the currently stored string length is not enough to store the new
9909      * string it is freed and reallocated. */
9910     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
9911     {
9912         free(tng_data->first_computer_name);
9913         tng_data->first_computer_name = 0;
9914     }
9915     if(!tng_data->first_computer_name)
9916     {
9917         tng_data->first_computer_name = (char *)malloc(len);
9918         if(!tng_data->first_computer_name)
9919         {
9920             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9921                     __FILE__, __LINE__);
9922             return(TNG_CRITICAL);
9923         }
9924     }
9925
9926     strncpy(tng_data->first_computer_name, new_name, len);
9927
9928     return(TNG_SUCCESS);
9929 }
9930
9931 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
9932                     (const tng_trajectory_t tng_data,
9933                      char *name, const int max_len)
9934 {
9935     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9936     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9937
9938     strncpy(name, tng_data->last_computer_name, max_len - 1);
9939     name[max_len - 1] = 0;
9940
9941     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
9942     {
9943         return(TNG_FAILURE);
9944     }
9945     return(TNG_SUCCESS);
9946 }
9947
9948 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
9949                     (const tng_trajectory_t tng_data,
9950                      const char *new_name)
9951 {
9952     unsigned int len;
9953
9954     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9955     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9956
9957     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9958
9959     /* If the currently stored string length is not enough to store the new
9960      * string it is freed and reallocated. */
9961     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
9962         len)
9963     {
9964         free(tng_data->last_computer_name);
9965         tng_data->last_computer_name = 0;
9966     }
9967     if(!tng_data->last_computer_name)
9968     {
9969         tng_data->last_computer_name = (char *)malloc(len);
9970         if(!tng_data->last_computer_name)
9971         {
9972             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9973                     __FILE__, __LINE__);
9974             return(TNG_CRITICAL);
9975         }
9976     }
9977
9978     strncpy(tng_data->last_computer_name, new_name, len);
9979
9980     return(TNG_SUCCESS);
9981 }
9982
9983 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
9984                     (const tng_trajectory_t tng_data,
9985                      char *signature, const int max_len)
9986 {
9987     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9988     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
9989
9990     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
9991     signature[max_len - 1] = 0;
9992
9993     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
9994     {
9995         return(TNG_FAILURE);
9996     }
9997     return(TNG_SUCCESS);
9998 }
9999
10000 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
10001                     (const tng_trajectory_t tng_data,
10002                      const char *signature)
10003 {
10004     unsigned int len;
10005
10006     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10007     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10008
10009     len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN);
10010
10011     /* If the currently stored string length is not enough to store the new
10012      * string it is freed and reallocated. */
10013     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
10014         len)
10015     {
10016         free(tng_data->first_pgp_signature);
10017         tng_data->first_pgp_signature = 0;
10018     }
10019     if(!tng_data->first_pgp_signature)
10020     {
10021         tng_data->first_pgp_signature = (char *)malloc(len);
10022         if(!tng_data->first_pgp_signature)
10023         {
10024             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
10025                     __FILE__, __LINE__);
10026             return(TNG_CRITICAL);
10027         }
10028     }
10029
10030     strncpy(tng_data->first_pgp_signature, signature, len);
10031
10032     return(TNG_SUCCESS);
10033 }
10034
10035 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
10036                     (const tng_trajectory_t tng_data,
10037                      char *signature, const int max_len)
10038 {
10039     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10040     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10041
10042     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
10043     signature[max_len - 1] = 0;
10044
10045     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
10046     {
10047         return(TNG_FAILURE);
10048     }
10049     return(TNG_SUCCESS);
10050 }
10051
10052 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
10053                     (const tng_trajectory_t tng_data,
10054                      const char *signature)
10055 {
10056     unsigned int len;
10057
10058     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10059     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10060
10061     len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN);
10062
10063     /* If the currently stored string length is not enough to store the new
10064      * string it is freed and reallocated. */
10065     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
10066         len)
10067     {
10068         free(tng_data->last_pgp_signature);
10069         tng_data->last_pgp_signature = 0;
10070     }
10071     if(!tng_data->last_pgp_signature)
10072     {
10073         tng_data->last_pgp_signature = (char *)malloc(len);
10074         if(!tng_data->last_pgp_signature)
10075         {
10076             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
10077                     __FILE__, __LINE__);
10078             return(TNG_CRITICAL);
10079         }
10080     }
10081
10082     strncpy(tng_data->last_pgp_signature, signature, len);
10083
10084     return(TNG_SUCCESS);
10085 }
10086
10087 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
10088                     (const tng_trajectory_t tng_data,
10089                      char *name, const int max_len)
10090 {
10091     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10092     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10093
10094     strncpy(name, tng_data->forcefield_name, max_len - 1);
10095     name[max_len - 1] = 0;
10096
10097     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
10098     {
10099         return(TNG_FAILURE);
10100     }
10101     return(TNG_SUCCESS);
10102 }
10103
10104 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
10105                     (const tng_trajectory_t tng_data,
10106                      const char *new_name)
10107 {
10108     unsigned int len;
10109
10110     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10111     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10112
10113     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
10114
10115     /* If the currently stored string length is not enough to store the new
10116      * string it is freed and reallocated. */
10117     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
10118     {
10119         free(tng_data->forcefield_name);
10120         tng_data->forcefield_name = 0;
10121     }
10122     if(!tng_data->forcefield_name)
10123     {
10124         tng_data->forcefield_name = (char *)malloc(len);
10125         if(!tng_data->forcefield_name)
10126         {
10127             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
10128                     __FILE__, __LINE__);
10129             return(TNG_CRITICAL);
10130         }
10131     }
10132
10133     strncpy(tng_data->forcefield_name, new_name, len);
10134
10135     return(TNG_SUCCESS);
10136 }
10137
10138 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
10139                     (const tng_trajectory_t tng_data,
10140                      int64_t *len)
10141 {
10142     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10143     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10144
10145     *len = tng_data->medium_stride_length;
10146
10147     return(TNG_SUCCESS);
10148 }
10149
10150 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
10151                     (const tng_trajectory_t tng_data,
10152                      const int64_t len)
10153 {
10154     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10155
10156     if(len >= tng_data->long_stride_length)
10157     {
10158         return(TNG_FAILURE);
10159     }
10160     tng_data->medium_stride_length = len;
10161
10162     return(TNG_SUCCESS);
10163 }
10164
10165 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
10166                 (const tng_trajectory_t tng_data,
10167                  int64_t *len)
10168 {
10169     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10170     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10171
10172     *len = tng_data->long_stride_length;
10173
10174     return(TNG_SUCCESS);
10175 }
10176
10177 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
10178                 (const tng_trajectory_t tng_data,
10179                  const int64_t len)
10180 {
10181     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10182
10183     if(len <= tng_data->medium_stride_length)
10184     {
10185         return(TNG_FAILURE);
10186     }
10187     tng_data->long_stride_length = len;
10188
10189     return(TNG_SUCCESS);
10190 }
10191
10192 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
10193                 (const tng_trajectory_t tng_data,
10194                  double *time)
10195 {
10196     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10197     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
10198
10199     *time = tng_data->time_per_frame;
10200
10201     return(TNG_SUCCESS);
10202 }
10203
10204 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
10205                 (const tng_trajectory_t tng_data,
10206                  const double time)
10207 {
10208     tng_trajectory_frame_set_t frame_set;
10209
10210     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10211     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
10212
10213     if(fabs(time - tng_data->time_per_frame) < 0.00001)
10214     {
10215         return(TNG_SUCCESS);
10216     }
10217
10218     frame_set = &tng_data->current_trajectory_frame_set;
10219
10220     /* If the current frame set is not finished write it to disk before
10221        changing time per frame. */
10222     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
10223     {
10224         frame_set->n_frames = frame_set->n_unwritten_frames;
10225         tng_frame_set_write(tng_data, TNG_USE_HASH);
10226     }
10227     tng_data->time_per_frame = time;
10228
10229     return(TNG_SUCCESS);
10230 }
10231
10232 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
10233                     (const tng_trajectory_t tng_data,
10234                      int64_t *len)
10235 {
10236     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10237     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10238
10239     *len = tng_data->input_file_len;
10240
10241     return(TNG_SUCCESS);
10242 }
10243
10244 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
10245                     (const tng_trajectory_t tng_data,
10246                      int64_t *n)
10247 {
10248     tng_gen_block_t block;
10249     tng_function_status stat;
10250     int64_t file_pos, last_file_pos, first_frame, n_frames;
10251
10252     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10253     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
10254     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10255
10256     file_pos = ftello(tng_data->input_file);
10257     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10258
10259     if(last_file_pos <= 0)
10260     {
10261         return(TNG_FAILURE);
10262     }
10263
10264     tng_block_init(&block);
10265     fseeko(tng_data->input_file,
10266            last_file_pos,
10267            SEEK_SET);
10268     /* Read block headers first to see that a frame set block is found. */
10269     stat = tng_block_header_read(tng_data, block);
10270     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10271     {
10272         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", last_file_pos,
10273                 __FILE__, __LINE__);
10274         tng_block_destroy(&block);
10275         return(TNG_FAILURE);
10276     }
10277     tng_block_destroy(&block);
10278
10279     if(tng_file_input_numerical(tng_data, &first_frame,
10280                                 sizeof(first_frame),
10281                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
10282     {
10283         return(TNG_CRITICAL);
10284     }
10285
10286     if(tng_file_input_numerical(tng_data, &n_frames,
10287                                 sizeof(n_frames),
10288                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
10289     {
10290         return(TNG_CRITICAL);
10291     }
10292
10293     fseeko(tng_data->input_file, file_pos, SEEK_SET);
10294
10295     *n = first_frame + n_frames;
10296
10297     return(TNG_SUCCESS);
10298 }
10299
10300 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
10301                 (const tng_trajectory_t tng_data,
10302                  double *precision)
10303 {
10304     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10305
10306     *precision = tng_data->compression_precision;
10307
10308     return(TNG_SUCCESS);
10309 }
10310
10311 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
10312                 (const tng_trajectory_t tng_data,
10313                  const double precision)
10314 {
10315     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10316
10317     tng_data->compression_precision = precision;
10318
10319     return(TNG_SUCCESS);
10320 }
10321
10322 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
10323                 (const tng_trajectory_t tng_data,
10324                  const int64_t n)
10325 {
10326     tng_molecule_t mol;
10327     tng_chain_t chain;
10328     tng_residue_t res;
10329     tng_atom_t atom;
10330     tng_function_status stat;
10331     int64_t diff, n_mod, n_impl;
10332
10333     TNG_ASSERT(n >= 0, "TNG library: The requested number of particles must be >= 0");
10334
10335     diff = n - tng_data->n_particles;
10336
10337     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
10338     if(stat == TNG_SUCCESS)
10339     {
10340         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
10341         {
10342             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
10343                     __FILE__, __LINE__);
10344             return(TNG_FAILURE);
10345         }
10346         diff -= n_impl * mol->n_atoms;
10347     }
10348
10349     if(diff == 0)
10350     {
10351         if(stat == TNG_SUCCESS)
10352         {
10353             stat = tng_molecule_cnt_set(tng_data, mol, 0);
10354             return(stat);
10355         }
10356         return(TNG_SUCCESS);
10357     }
10358     else if(diff < 0)
10359     {
10360         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
10361         fprintf(stderr, "particle count.\n");
10362         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10363                 __FILE__, __LINE__);
10364         /* FIXME: Should we set the count of all other molecules to 0 and add
10365          * implicit molecules? */
10366         return(TNG_FAILURE);
10367     }
10368     if(stat != TNG_SUCCESS)
10369     {
10370         stat = tng_molecule_add(tng_data,
10371                                 "TNG_IMPLICIT_MOL",
10372                                 &mol);
10373         if(stat != TNG_SUCCESS)
10374         {
10375             return(stat);
10376         }
10377         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
10378         if(stat != TNG_SUCCESS)
10379         {
10380             return(stat);
10381         }
10382         stat = tng_chain_residue_add(tng_data, chain, "", &res);
10383         if(stat != TNG_SUCCESS)
10384         {
10385             return(stat);
10386         }
10387         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
10388         if(stat != TNG_SUCCESS)
10389         {
10390             return(stat);
10391         }
10392     }
10393     else
10394     {
10395         if(mol->n_atoms > 1)
10396         {
10397             n_mod = diff % mol->n_atoms;
10398             if(n_mod != 0)
10399             {
10400                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
10401                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
10402                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10403                         __FILE__, __LINE__);
10404                 return(TNG_FAILURE);
10405             }
10406             diff /= mol->n_atoms;
10407         }
10408     }
10409     stat = tng_molecule_cnt_set(tng_data, mol, diff);
10410
10411     return(stat);
10412 }
10413
10414 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
10415                 (const tng_trajectory_t tng_data,
10416                  int64_t *n)
10417 {
10418     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10419     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10420
10421     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
10422     {
10423         *n = tng_data->n_particles;
10424     }
10425     else
10426     {
10427         *n = tng_data->current_trajectory_frame_set.n_particles;
10428     }
10429
10430     return(TNG_SUCCESS);
10431 }
10432
10433 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
10434                 (const tng_trajectory_t tng_data,
10435                  char *variable)
10436 {
10437     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10438     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
10439
10440     *variable = tng_data->var_num_atoms_flag;
10441
10442     return(TNG_SUCCESS);
10443 }
10444
10445 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
10446                     (const tng_trajectory_t tng_data,
10447                      int64_t *n)
10448 {
10449     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10450     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10451
10452     *n = tng_data->n_molecules;
10453
10454     return(TNG_SUCCESS);
10455 }
10456
10457 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
10458                     (const tng_trajectory_t tng_data,
10459                      int64_t *n)
10460 {
10461     int64_t *cnt_list = 0, cnt = 0, i;
10462
10463     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10464     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10465
10466     tng_molecule_cnt_list_get(tng_data, &cnt_list);
10467
10468     if(!cnt_list)
10469     {
10470         return(TNG_FAILURE);
10471     }
10472
10473     for(i = 0; i < tng_data->n_molecules; i++)
10474     {
10475         cnt += cnt_list[i];
10476     }
10477
10478     *n = cnt;
10479
10480     return(TNG_SUCCESS);
10481 }
10482
10483 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
10484                 (const tng_trajectory_t tng_data,
10485                  int64_t **mol_cnt_list)
10486 {
10487     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10488
10489     if(tng_data->var_num_atoms_flag)
10490     {
10491         *mol_cnt_list = tng_data->current_trajectory_frame_set.
10492                        molecule_cnt_list;
10493     }
10494     else
10495     {
10496         *mol_cnt_list = tng_data->molecule_cnt_list;
10497     }
10498     if(*mol_cnt_list == 0)
10499     {
10500         return(TNG_FAILURE);
10501     }
10502     return(TNG_SUCCESS);
10503 }
10504
10505 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
10506                 (const tng_trajectory_t tng_data,
10507                  int64_t *exp)
10508 {
10509     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10510     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
10511
10512     *exp = tng_data->distance_unit_exponential;
10513
10514     return(TNG_SUCCESS);
10515 }
10516
10517 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
10518                 (const tng_trajectory_t tng_data,
10519                  const int64_t exp)
10520 {
10521     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10522
10523     tng_data->distance_unit_exponential = exp;
10524
10525     return(TNG_SUCCESS);
10526 }
10527
10528 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
10529                 (const tng_trajectory_t tng_data,
10530                  int64_t *n)
10531 {
10532     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10533     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10534
10535     *n = tng_data->frame_set_n_frames;
10536
10537     return(TNG_SUCCESS);
10538 }
10539
10540 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
10541                 (const tng_trajectory_t tng_data,
10542                  const int64_t n)
10543 {
10544     tng_trajectory_frame_set_t frame_set;
10545     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10546
10547     tng_data->frame_set_n_frames = n;
10548     frame_set = &tng_data->current_trajectory_frame_set;
10549     if(frame_set)
10550     {
10551         frame_set->n_frames = n;
10552     }
10553
10554     return(TNG_SUCCESS);
10555 }
10556
10557 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
10558                 (const tng_trajectory_t tng_data,
10559                  int64_t *n)
10560 {
10561     int64_t long_stride_length, medium_stride_length;
10562     int64_t file_pos, orig_frame_set_file_pos;
10563     tng_trajectory_frame_set_t frame_set;
10564     struct tng_trajectory_frame_set orig_frame_set;
10565     tng_gen_block_t block;
10566     tng_function_status stat;
10567     int64_t cnt = 0;
10568
10569     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10570     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10571
10572     orig_frame_set = tng_data->current_trajectory_frame_set;
10573
10574     frame_set = &tng_data->current_trajectory_frame_set;
10575
10576     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10577     file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
10578
10579     if(file_pos < 0)
10580     {
10581         *n = tng_data->n_trajectory_frame_sets = cnt;
10582         return(TNG_SUCCESS);
10583     }
10584
10585     tng_block_init(&block);
10586     fseeko(tng_data->input_file,
10587            file_pos,
10588            SEEK_SET);
10589     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10590     /* Read block headers first to see what block is found. */
10591     stat = tng_block_header_read(tng_data, block);
10592     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10593     {
10594         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
10595                 __FILE__, __LINE__);
10596         tng_block_destroy(&block);
10597         return(TNG_CRITICAL);
10598     }
10599
10600     if(tng_block_read_next(tng_data, block,
10601                         TNG_SKIP_HASH) != TNG_SUCCESS)
10602     {
10603         tng_block_destroy(&block);
10604         return(TNG_CRITICAL);
10605     }
10606
10607     ++cnt;
10608
10609     long_stride_length = tng_data->long_stride_length;
10610     medium_stride_length = tng_data->medium_stride_length;
10611
10612     /* Take long steps forward until a long step forward would be too long or
10613      * the last frame set is found */
10614     file_pos = frame_set->long_stride_next_frame_set_file_pos;
10615     while(file_pos > 0)
10616     {
10617         if(file_pos > 0)
10618         {
10619             cnt += long_stride_length;
10620             fseeko(tng_data->input_file, file_pos, SEEK_SET);
10621             /* Read block headers first to see what block is found. */
10622             stat = tng_block_header_read(tng_data, block);
10623             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10624             {
10625                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10626                        file_pos, __FILE__, __LINE__);
10627                 tng_block_destroy(&block);
10628                 return(TNG_CRITICAL);
10629             }
10630
10631             if(tng_block_read_next(tng_data, block,
10632                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10633             {
10634                 tng_block_destroy(&block);
10635                 return(TNG_CRITICAL);
10636             }
10637         }
10638         file_pos = frame_set->long_stride_next_frame_set_file_pos;
10639     }
10640
10641     /* Take medium steps forward until a medium step forward would be too long
10642      * or the last frame set is found */
10643     file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10644     while(file_pos > 0)
10645     {
10646         if(file_pos > 0)
10647         {
10648             cnt += medium_stride_length;
10649             fseeko(tng_data->input_file,
10650                    file_pos,
10651                    SEEK_SET);
10652             /* Read block headers first to see what block is found. */
10653             stat = tng_block_header_read(tng_data, block);
10654             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10655             {
10656                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10657                        file_pos, __FILE__, __LINE__);
10658                 tng_block_destroy(&block);
10659                 return(TNG_CRITICAL);
10660             }
10661
10662             if(tng_block_read_next(tng_data, block,
10663                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10664             {
10665                 tng_block_destroy(&block);
10666                 return(TNG_CRITICAL);
10667             }
10668         }
10669         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10670     }
10671
10672     /* Take one step forward until the last frame set is found */
10673     file_pos = frame_set->next_frame_set_file_pos;
10674     while(file_pos > 0)
10675     {
10676         if(file_pos > 0)
10677         {
10678             ++cnt;
10679             fseeko(tng_data->input_file,
10680                    file_pos,
10681                    SEEK_SET);
10682             /* Read block headers first to see what block is found. */
10683             stat = tng_block_header_read(tng_data, block);
10684             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10685             {
10686                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10687                        file_pos, __FILE__, __LINE__);
10688                 tng_block_destroy(&block);
10689                 return(TNG_CRITICAL);
10690             }
10691
10692             if(tng_block_read_next(tng_data, block,
10693                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10694             {
10695                 tng_block_destroy(&block);
10696                 return(TNG_CRITICAL);
10697             }
10698         }
10699         file_pos = frame_set->next_frame_set_file_pos;
10700     }
10701
10702     tng_block_destroy(&block);
10703
10704     *n = tng_data->n_trajectory_frame_sets = cnt;
10705
10706     *frame_set = orig_frame_set;
10707     /* The mapping block in the original frame set has been freed when reading
10708      * other frame sets. */
10709     frame_set->mappings = 0;
10710     frame_set->n_mapping_blocks = 0;
10711
10712     fseeko(tng_data->input_file,
10713            tng_data->first_trajectory_frame_set_input_file_pos,
10714            SEEK_SET);
10715
10716     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
10717
10718     return(TNG_SUCCESS);
10719 }
10720
10721 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
10722                 (const tng_trajectory_t tng_data,
10723                  tng_trajectory_frame_set_t *frame_set_p)
10724 {
10725     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10726
10727     *frame_set_p = &tng_data->current_trajectory_frame_set;
10728
10729     return(TNG_SUCCESS);
10730 }
10731
10732 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
10733                 (const tng_trajectory_t tng_data,
10734                  const int64_t nr)
10735 {
10736     int64_t long_stride_length, medium_stride_length;
10737     int64_t file_pos, curr_nr = 0, n_frame_sets;
10738     tng_trajectory_frame_set_t frame_set;
10739     tng_gen_block_t block;
10740     tng_function_status stat;
10741
10742     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10743     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
10744
10745     frame_set = &tng_data->current_trajectory_frame_set;
10746
10747     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
10748
10749     if(stat != TNG_SUCCESS)
10750     {
10751         return(stat);
10752     }
10753
10754     if(nr >= n_frame_sets)
10755     {
10756         return(TNG_FAILURE);
10757     }
10758
10759     long_stride_length = tng_data->long_stride_length;
10760     medium_stride_length = tng_data->medium_stride_length;
10761
10762     /* FIXME: The frame set number of the current frame set is not stored */
10763
10764     if(nr < n_frame_sets - 1 - nr)
10765     {
10766         /* Start from the beginning */
10767         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
10768     }
10769     else
10770     {
10771         /* Start from the end */
10772         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10773         curr_nr = n_frame_sets - 1;
10774     }
10775     if(file_pos <= 0)
10776     {
10777         return(TNG_FAILURE);
10778     }
10779
10780     tng_block_init(&block);
10781     fseeko(tng_data->input_file,
10782            file_pos,
10783            SEEK_SET);
10784     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10785     /* Read block headers first to see what block is found. */
10786     stat = tng_block_header_read(tng_data, block);
10787     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10788     {
10789         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
10790                 __FILE__, __LINE__);
10791         tng_block_destroy(&block);
10792         return(TNG_CRITICAL);
10793     }
10794
10795     if(tng_block_read_next(tng_data, block,
10796                         TNG_SKIP_HASH) != TNG_SUCCESS)
10797     {
10798         tng_block_destroy(&block);
10799         return(TNG_CRITICAL);
10800     }
10801
10802     if(curr_nr == nr)
10803     {
10804         tng_block_destroy(&block);
10805         return(TNG_SUCCESS);
10806     }
10807
10808     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10809
10810     /* Take long steps forward until a long step forward would be too long or
10811      * the right frame set is found */
10812     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
10813     {
10814         file_pos = frame_set->long_stride_next_frame_set_file_pos;
10815         if(file_pos > 0)
10816         {
10817             curr_nr += long_stride_length;
10818             fseeko(tng_data->input_file, file_pos, SEEK_SET);
10819             /* Read block headers first to see what block is found. */
10820             stat = tng_block_header_read(tng_data, block);
10821             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10822             {
10823                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10824                        file_pos,  __FILE__, __LINE__);
10825                 tng_block_destroy(&block);
10826                 return(TNG_CRITICAL);
10827             }
10828
10829             if(tng_block_read_next(tng_data, block,
10830                                    TNG_SKIP_HASH) != TNG_SUCCESS)
10831             {
10832                 tng_block_destroy(&block);
10833                 return(TNG_CRITICAL);
10834             }
10835             if(curr_nr == nr)
10836             {
10837                 tng_block_destroy(&block);
10838                 return(TNG_SUCCESS);
10839             }
10840         }
10841     }
10842
10843     /* Take medium steps forward until a medium step forward would be too long
10844      * or the right frame set is found */
10845     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
10846     {
10847         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10848         if(file_pos > 0)
10849         {
10850             curr_nr += medium_stride_length;
10851             fseeko(tng_data->input_file,
10852                    file_pos,
10853                    SEEK_SET);
10854             /* Read block headers first to see what block is found. */
10855             stat = tng_block_header_read(tng_data, block);
10856             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10857             {
10858                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10859                        file_pos, __FILE__, __LINE__);
10860                 tng_block_destroy(&block);
10861                 return(TNG_CRITICAL);
10862             }
10863
10864             if(tng_block_read_next(tng_data, block,
10865                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10866             {
10867                 tng_block_destroy(&block);
10868                 return(TNG_CRITICAL);
10869             }
10870             if(curr_nr == nr)
10871             {
10872                 tng_block_destroy(&block);
10873                 return(TNG_SUCCESS);
10874             }
10875         }
10876     }
10877
10878     /* Take one step forward until the right frame set is found */
10879     while(file_pos > 0 && curr_nr < nr)
10880     {
10881         file_pos = frame_set->next_frame_set_file_pos;
10882
10883         if(file_pos > 0)
10884         {
10885             ++curr_nr;
10886             fseeko(tng_data->input_file,
10887                    file_pos,
10888                    SEEK_SET);
10889             /* Read block headers first to see what block is found. */
10890             stat = tng_block_header_read(tng_data, block);
10891             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10892             {
10893                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10894                        file_pos, __FILE__, __LINE__);
10895                 tng_block_destroy(&block);
10896                 return(TNG_CRITICAL);
10897             }
10898
10899             if(tng_block_read_next(tng_data, block,
10900                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10901             {
10902                 tng_block_destroy(&block);
10903                 return(TNG_CRITICAL);
10904             }
10905             if(curr_nr == nr)
10906             {
10907                 tng_block_destroy(&block);
10908                 return(TNG_SUCCESS);
10909             }
10910         }
10911     }
10912
10913     /* Take long steps backward until a long step backward would be too long
10914      * or the right frame set is found */
10915     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
10916     {
10917         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
10918         if(file_pos > 0)
10919         {
10920             curr_nr -= long_stride_length;
10921             fseeko(tng_data->input_file,
10922                    file_pos,
10923                    SEEK_SET);
10924             /* Read block headers first to see what block is found. */
10925             stat = tng_block_header_read(tng_data, block);
10926             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10927             {
10928                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10929                        file_pos, __FILE__, __LINE__);
10930                 tng_block_destroy(&block);
10931                 return(TNG_CRITICAL);
10932             }
10933
10934             if(tng_block_read_next(tng_data, block,
10935                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10936             {
10937                 tng_block_destroy(&block);
10938                 return(TNG_CRITICAL);
10939             }
10940             if(curr_nr == nr)
10941             {
10942                 tng_block_destroy(&block);
10943                 return(TNG_SUCCESS);
10944             }
10945         }
10946     }
10947
10948     /* Take medium steps backward until a medium step backward would be too long
10949      * or the right frame set is found */
10950     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
10951     {
10952         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
10953         if(file_pos > 0)
10954         {
10955             curr_nr -= medium_stride_length;
10956             fseeko(tng_data->input_file,
10957                    file_pos,
10958                    SEEK_SET);
10959             /* Read block headers first to see what block is found. */
10960             stat = tng_block_header_read(tng_data, block);
10961             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10962             {
10963                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10964                        file_pos, __FILE__, __LINE__);
10965                 tng_block_destroy(&block);
10966                 return(TNG_CRITICAL);
10967             }
10968
10969             if(tng_block_read_next(tng_data, block,
10970                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10971             {
10972                 tng_block_destroy(&block);
10973                 return(TNG_CRITICAL);
10974             }
10975             if(curr_nr == nr)
10976             {
10977                 tng_block_destroy(&block);
10978                 return(TNG_SUCCESS);
10979             }
10980         }
10981     }
10982
10983     /* Take one step backward until the right frame set is found */
10984     while(file_pos > 0 && curr_nr > nr)
10985     {
10986         file_pos = frame_set->prev_frame_set_file_pos;
10987         if(file_pos > 0)
10988         {
10989             --curr_nr;
10990             fseeko(tng_data->input_file,
10991                    file_pos,
10992                    SEEK_SET);
10993             /* Read block headers first to see what block is found. */
10994             stat = tng_block_header_read(tng_data, block);
10995             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10996             {
10997                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10998                        file_pos, __FILE__, __LINE__);
10999                 tng_block_destroy(&block);
11000                 return(TNG_CRITICAL);
11001             }
11002
11003             if(tng_block_read_next(tng_data, block,
11004                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11005             {
11006                 tng_block_destroy(&block);
11007                 return(TNG_CRITICAL);
11008             }
11009             if(curr_nr == nr)
11010             {
11011                 tng_block_destroy(&block);
11012                 return(TNG_SUCCESS);
11013             }
11014         }
11015     }
11016
11017     /* If for some reason the current frame set is not yet found,
11018      * take one step forward until the right frame set is found */
11019     while(file_pos > 0 && curr_nr < nr)
11020     {
11021         file_pos = frame_set->next_frame_set_file_pos;
11022         if(file_pos > 0)
11023         {
11024             ++curr_nr;
11025             fseeko(tng_data->input_file,
11026                    file_pos,
11027                    SEEK_SET);
11028             /* Read block headers first to see what block is found. */
11029             stat = tng_block_header_read(tng_data, block);
11030             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11031             {
11032                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11033                        file_pos, __FILE__, __LINE__);
11034                 tng_block_destroy(&block);
11035                 return(TNG_CRITICAL);
11036             }
11037
11038             if(tng_block_read_next(tng_data, block,
11039                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11040             {
11041                 tng_block_destroy(&block);
11042                 return(TNG_CRITICAL);
11043             }
11044             if(curr_nr == nr)
11045             {
11046                 tng_block_destroy(&block);
11047                 return(TNG_SUCCESS);
11048             }
11049         }
11050     }
11051
11052     tng_block_destroy(&block);
11053     return(TNG_FAILURE);
11054 }
11055
11056 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
11057                 (const tng_trajectory_t tng_data,
11058                  const int64_t frame)
11059 {
11060     int64_t first_frame, last_frame, n_frames_per_frame_set;
11061     int64_t long_stride_length, medium_stride_length;
11062     int64_t file_pos, temp_frame, n_frames;
11063     tng_trajectory_frame_set_t frame_set;
11064     tng_gen_block_t block;
11065     tng_function_status stat;
11066
11067     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11068     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
11069
11070     frame_set = &tng_data->current_trajectory_frame_set;
11071
11072     tng_block_init(&block);
11073
11074     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
11075     {
11076         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11077         fseeko(tng_data->input_file,
11078                file_pos,
11079                SEEK_SET);
11080         tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11081         /* Read block headers first to see what block is found. */
11082         stat = tng_block_header_read(tng_data, block);
11083         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11084         {
11085             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11086                     file_pos, __FILE__, __LINE__);
11087             tng_block_destroy(&block);
11088             return(TNG_CRITICAL);
11089         }
11090
11091         if(tng_block_read_next(tng_data, block,
11092                             TNG_SKIP_HASH) != TNG_SUCCESS)
11093         {
11094             tng_block_destroy(&block);
11095             return(TNG_CRITICAL);
11096         }
11097     }
11098
11099     first_frame = tng_max_i64(frame_set->first_frame, 0);
11100     last_frame = first_frame + frame_set->n_frames - 1;
11101     /* Is this the right frame set? */
11102     if(first_frame <= frame && frame <= last_frame)
11103     {
11104         tng_block_destroy(&block);
11105         return(TNG_SUCCESS);
11106     }
11107
11108     n_frames_per_frame_set = tng_data->frame_set_n_frames;
11109     long_stride_length = tng_data->long_stride_length;
11110     medium_stride_length = tng_data->medium_stride_length;
11111
11112     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
11113        TNG_SUCCESS)
11114     {
11115         if(temp_frame - first_frame > n_frames_per_frame_set)
11116         {
11117             n_frames_per_frame_set = temp_frame - first_frame;
11118         }
11119     }
11120
11121     tng_num_frames_get(tng_data, &n_frames);
11122
11123     if(frame >= n_frames)
11124     {
11125         tng_block_destroy(&block);
11126         return(TNG_FAILURE);
11127     }
11128
11129     if(first_frame - frame >= frame ||
11130        frame - last_frame >
11131        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
11132     {
11133         /* Start from the beginning */
11134         if(first_frame - frame >= frame)
11135         {
11136             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11137
11138             if(file_pos <= 0)
11139             {
11140                 tng_block_destroy(&block);
11141                 return(TNG_FAILURE);
11142             }
11143         }
11144         /* Start from the end */
11145         else if(frame - first_frame > (n_frames - 1) - frame)
11146         {
11147             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11148
11149             /* If the last frame set position is not set start from the current
11150              * frame set, since it will be closer than the first frame set. */
11151         }
11152         /* Start from current */
11153         else
11154         {
11155             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11156         }
11157
11158         if(file_pos > 0)
11159         {
11160             fseeko(tng_data->input_file,
11161                    file_pos,
11162                    SEEK_SET);
11163             tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11164             /* Read block headers first to see what block is found. */
11165             stat = tng_block_header_read(tng_data, block);
11166             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11167             {
11168                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11169                        file_pos, __FILE__, __LINE__);
11170                 tng_block_destroy(&block);
11171                 return(TNG_CRITICAL);
11172             }
11173
11174             if(tng_block_read_next(tng_data, block,
11175                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11176             {
11177                 tng_block_destroy(&block);
11178                 return(TNG_CRITICAL);
11179             }
11180         }
11181     }
11182
11183     first_frame = tng_max_i64(frame_set->first_frame, 0);
11184     last_frame = first_frame + frame_set->n_frames - 1;
11185
11186     if(frame >= first_frame && frame <= last_frame)
11187     {
11188         tng_block_destroy(&block);
11189         return(TNG_SUCCESS);
11190     }
11191
11192     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11193
11194     /* Take long steps forward until a long step forward would be too long or
11195      * the right frame set is found */
11196     while(file_pos > 0 && first_frame + long_stride_length *
11197           n_frames_per_frame_set <= frame)
11198     {
11199         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11200         if(file_pos > 0)
11201         {
11202             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11203             /* Read block headers first to see what block is found. */
11204             stat = tng_block_header_read(tng_data, block);
11205             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11206             {
11207                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11208                        file_pos, __FILE__, __LINE__);
11209                 tng_block_destroy(&block);
11210                 return(TNG_CRITICAL);
11211             }
11212
11213             if(tng_block_read_next(tng_data, block,
11214                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11215             {
11216                 tng_block_destroy(&block);
11217                 return(TNG_CRITICAL);
11218             }
11219         }
11220         first_frame = tng_max_i64(frame_set->first_frame, 0);
11221         last_frame = first_frame + frame_set->n_frames - 1;
11222         if(frame >= first_frame && frame <= last_frame)
11223         {
11224             tng_block_destroy(&block);
11225             return(TNG_SUCCESS);
11226         }
11227     }
11228
11229     /* Take medium steps forward until a medium step forward would be too long
11230      * or the right frame set is found */
11231     while(file_pos > 0 && first_frame + medium_stride_length *
11232           n_frames_per_frame_set <= frame)
11233     {
11234         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11235         if(file_pos > 0)
11236         {
11237             fseeko(tng_data->input_file,
11238                    file_pos,
11239                    SEEK_SET);
11240             /* Read block headers first to see what block is found. */
11241             stat = tng_block_header_read(tng_data, block);
11242             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11243             {
11244                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11245                        file_pos, __FILE__, __LINE__);
11246                 tng_block_destroy(&block);
11247                 return(TNG_CRITICAL);
11248             }
11249
11250             if(tng_block_read_next(tng_data, block,
11251                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11252             {
11253                 tng_block_destroy(&block);
11254                 return(TNG_CRITICAL);
11255             }
11256         }
11257         first_frame = tng_max_i64(frame_set->first_frame, 0);
11258         last_frame = first_frame + frame_set->n_frames - 1;
11259         if(frame >= first_frame && frame <= last_frame)
11260         {
11261             tng_block_destroy(&block);
11262             return(TNG_SUCCESS);
11263         }
11264     }
11265
11266     /* Take one step forward until the right frame set is found */
11267     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11268     {
11269         file_pos = frame_set->next_frame_set_file_pos;
11270         if(file_pos > 0)
11271         {
11272             fseeko(tng_data->input_file,
11273                    file_pos,
11274                    SEEK_SET);
11275             /* Read block headers first to see what block is found. */
11276             stat = tng_block_header_read(tng_data, block);
11277             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11278             {
11279                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11280                        file_pos, __FILE__, __LINE__);
11281                 tng_block_destroy(&block);
11282                 return(TNG_CRITICAL);
11283             }
11284
11285             if(tng_block_read_next(tng_data, block,
11286                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11287             {
11288                 tng_block_destroy(&block);
11289                 return(TNG_CRITICAL);
11290             }
11291         }
11292         first_frame = tng_max_i64(frame_set->first_frame, 0);
11293         last_frame = first_frame + frame_set->n_frames - 1;
11294         if(frame >= first_frame && frame <= last_frame)
11295         {
11296             tng_block_destroy(&block);
11297             return(TNG_SUCCESS);
11298         }
11299     }
11300
11301     /* Take long steps backward until a long step backward would be too long
11302      * or the right frame set is found */
11303     while(file_pos > 0 && first_frame - long_stride_length *
11304           n_frames_per_frame_set >= frame)
11305     {
11306         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11307         if(file_pos > 0)
11308         {
11309             fseeko(tng_data->input_file,
11310                    file_pos,
11311                    SEEK_SET);
11312             /* Read block headers first to see what block is found. */
11313             stat = tng_block_header_read(tng_data, block);
11314             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11315             {
11316                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11317                        file_pos, __FILE__, __LINE__);
11318                 tng_block_destroy(&block);
11319                 return(TNG_CRITICAL);
11320             }
11321
11322             if(tng_block_read_next(tng_data, block,
11323                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11324             {
11325                 tng_block_destroy(&block);
11326                 return(TNG_CRITICAL);
11327             }
11328         }
11329         first_frame = tng_max_i64(frame_set->first_frame, 0);
11330         last_frame = first_frame + frame_set->n_frames - 1;
11331         if(frame >= first_frame && frame <= last_frame)
11332         {
11333             tng_block_destroy(&block);
11334             return(TNG_SUCCESS);
11335         }
11336     }
11337
11338     /* Take medium steps backward until a medium step backward would be too long
11339      * or the right frame set is found */
11340     while(file_pos > 0 && first_frame - medium_stride_length *
11341           n_frames_per_frame_set >= frame)
11342     {
11343         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11344         if(file_pos > 0)
11345         {
11346             fseeko(tng_data->input_file,
11347                    file_pos,
11348                    SEEK_SET);
11349             /* Read block headers first to see what block is found. */
11350             stat = tng_block_header_read(tng_data, block);
11351             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11352             {
11353                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11354                        file_pos, __FILE__, __LINE__);
11355                 tng_block_destroy(&block);
11356                 return(TNG_CRITICAL);
11357             }
11358
11359             if(tng_block_read_next(tng_data, block,
11360                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11361             {
11362                 tng_block_destroy(&block);
11363                 return(TNG_CRITICAL);
11364             }
11365         }
11366         first_frame = tng_max_i64(frame_set->first_frame, 0);
11367         last_frame = first_frame + frame_set->n_frames - 1;
11368         if(frame >= first_frame && frame <= last_frame)
11369         {
11370             tng_block_destroy(&block);
11371             return(TNG_SUCCESS);
11372         }
11373     }
11374
11375     /* Take one step backward until the right frame set is found */
11376     while(file_pos > 0 && first_frame > frame && last_frame > frame)
11377     {
11378         file_pos = frame_set->prev_frame_set_file_pos;
11379         if(file_pos > 0)
11380         {
11381             fseeko(tng_data->input_file,
11382                    file_pos,
11383                    SEEK_SET);
11384             /* Read block headers first to see what block is found. */
11385             stat = tng_block_header_read(tng_data, block);
11386             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11387             {
11388                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11389                        file_pos, __FILE__, __LINE__);
11390                 tng_block_destroy(&block);
11391                 return(TNG_CRITICAL);
11392             }
11393
11394             if(tng_block_read_next(tng_data, block,
11395                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11396             {
11397                 tng_block_destroy(&block);
11398                 return(TNG_CRITICAL);
11399             }
11400         }
11401         first_frame = tng_max_i64(frame_set->first_frame, 0);
11402         last_frame = first_frame + frame_set->n_frames - 1;
11403         if(frame >= first_frame && frame <= last_frame)
11404         {
11405             tng_block_destroy(&block);
11406             return(TNG_SUCCESS);
11407         }
11408     }
11409
11410     /* If for some reason the current frame set is not yet found,
11411      * take one step forward until the right frame set is found */
11412     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11413     {
11414         file_pos = frame_set->next_frame_set_file_pos;
11415         if(file_pos > 0)
11416         {
11417             fseeko(tng_data->input_file,
11418                    file_pos,
11419                    SEEK_SET);
11420             /* Read block headers first to see what block is found. */
11421             stat = tng_block_header_read(tng_data, block);
11422             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11423             {
11424                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11425                        file_pos, __FILE__, __LINE__);
11426                 tng_block_destroy(&block);
11427                 return(TNG_CRITICAL);
11428             }
11429
11430             if(tng_block_read_next(tng_data, block,
11431                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11432             {
11433                 tng_block_destroy(&block);
11434                 return(TNG_CRITICAL);
11435             }
11436         }
11437         first_frame = tng_max_i64(frame_set->first_frame, 0);
11438         last_frame = first_frame + frame_set->n_frames - 1;
11439         if(frame >= first_frame && frame <= last_frame)
11440         {
11441             tng_block_destroy(&block);
11442             return(TNG_SUCCESS);
11443         }
11444     }
11445
11446     tng_block_destroy(&block);
11447     return(TNG_FAILURE);
11448 }
11449
11450 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
11451                 (const tng_trajectory_t tng_data,
11452                  const tng_trajectory_frame_set_t frame_set,
11453                  int64_t *pos)
11454 {
11455     (void)tng_data;
11456
11457     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11458     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11459
11460     *pos = frame_set->next_frame_set_file_pos;
11461
11462     return(TNG_SUCCESS);
11463 }
11464
11465 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
11466                 (const tng_trajectory_t tng_data,
11467                  const tng_trajectory_frame_set_t frame_set,
11468                  int64_t *pos)
11469 {
11470     (void)tng_data;
11471
11472     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11473     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11474
11475     *pos = frame_set->prev_frame_set_file_pos;
11476
11477     return(TNG_SUCCESS);
11478 }
11479
11480 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
11481                 (const tng_trajectory_t tng_data,
11482                  const tng_trajectory_frame_set_t frame_set,
11483                  int64_t *first_frame,
11484                  int64_t *last_frame)
11485 {
11486     (void)tng_data;
11487
11488     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
11489     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
11490     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
11491
11492     *first_frame = frame_set->first_frame;
11493     *last_frame = *first_frame + frame_set->n_frames - 1;
11494
11495     return(TNG_SUCCESS);
11496 }
11497
11498 /**
11499  * @brief Translate from the particle numbering used in a frame set to the real
11500  *  particle numbering - used in the molecule description.
11501  * @param frame_set is the frame_set containing the mappings to use.
11502  * @param local is the index number of the atom in this frame set
11503  * @param real is set to the index of the atom in the molecular system.
11504  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11505  * cannot be found.
11506  */
11507 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
11508                 (const tng_trajectory_frame_set_t frame_set,
11509                  const int64_t local,
11510                  int64_t *real)
11511 {
11512     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
11513     tng_particle_mapping_t mapping;
11514     if(n_blocks <= 0)
11515     {
11516         *real = local;
11517         return(TNG_SUCCESS);
11518     }
11519     for(i = 0; i < n_blocks; i++)
11520     {
11521         mapping = &frame_set->mappings[i];
11522         first = mapping->num_first_particle;
11523         if(local < first ||
11524            local >= first + mapping->n_particles)
11525         {
11526             continue;
11527         }
11528         *real = mapping->real_particle_numbers[local-first];
11529         return(TNG_SUCCESS);
11530     }
11531     *real = local;
11532     return(TNG_FAILURE);
11533 }
11534
11535 /**
11536  * @brief Translate from the real particle numbering to the particle numbering
11537  *  used in a frame set.
11538  * @param frame_set is the frame_set containing the mappings to use.
11539  * @param real is the index number of the atom in the molecular system.
11540  * @param local is set to the index of the atom in this frame set.
11541  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11542  * cannot be found.
11543  */
11544 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
11545                 (const tng_trajectory_frame_set_t frame_set,
11546                  const int64_t real,
11547                  int64_t *local)
11548 {
11549     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
11550     tng_particle_mapping_t mapping;
11551     if(n_blocks <= 0)
11552     {
11553         *local = real;
11554         return(TNG_SUCCESS);
11555     }
11556     for(i = 0; i < n_blocks; i++)
11557     {
11558         mapping = &frame_set->mappings[i];
11559         for(j = mapping->n_particles; j--;)
11560         {
11561             if(mapping->real_particle_numbers[j] == real)
11562             {
11563                 *local = j;
11564                 return(TNG_SUCCESS);
11565             }
11566         }
11567     }
11568     return(TNG_FAILURE);
11569 }
11570 */
11571
11572 static tng_function_status tng_file_headers_len_get
11573                 (const tng_trajectory_t tng_data,
11574                  int64_t *len)
11575 {
11576     int64_t orig_pos;
11577     tng_gen_block_t block;
11578
11579     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11580
11581     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11582     {
11583         return(TNG_CRITICAL);
11584     }
11585
11586     *len = 0;
11587
11588     orig_pos = ftello(tng_data->input_file);
11589
11590     fseeko(tng_data->input_file, 0, SEEK_SET);
11591
11592     tng_block_init(&block);
11593     /* Read through the headers of non-trajectory blocks (they come before the
11594      * trajectory blocks in the file) */
11595     while (*len < tng_data->input_file_len &&
11596            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11597            block->id != -1 &&
11598            block->id != TNG_TRAJECTORY_FRAME_SET)
11599     {
11600         *len += block->header_contents_size + block->block_contents_size;
11601         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11602     }
11603
11604     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
11605
11606     tng_block_destroy(&block);
11607
11608     return(TNG_SUCCESS);
11609 }
11610
11611 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
11612                 (const tng_trajectory_t tng_data,
11613                  const char hash_mode)
11614 {
11615     int64_t prev_pos = 0;
11616     tng_gen_block_t block;
11617
11618     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11619
11620     tng_data->n_trajectory_frame_sets = 0;
11621
11622     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11623     {
11624         return(TNG_CRITICAL);
11625     }
11626
11627     fseeko(tng_data->input_file, 0, SEEK_SET);
11628
11629     tng_block_init(&block);
11630     /* Non trajectory blocks (they come before the trajectory
11631      * blocks in the file) */
11632     while (prev_pos < tng_data->input_file_len &&
11633            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11634            block->id != -1 &&
11635            block->id != TNG_TRAJECTORY_FRAME_SET)
11636     {
11637         tng_block_read_next(tng_data, block, hash_mode);
11638         prev_pos = ftello(tng_data->input_file);
11639     }
11640
11641     /* Go back if a trajectory block was encountered */
11642     if(block->id == TNG_TRAJECTORY_FRAME_SET)
11643     {
11644         fseeko(tng_data->input_file, prev_pos, SEEK_SET);
11645     }
11646
11647     tng_block_destroy(&block);
11648
11649     return(TNG_SUCCESS);
11650 }
11651
11652 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
11653                 (const tng_trajectory_t tng_data,
11654                  const char hash_mode)
11655 {
11656     int i;
11657     int64_t len, orig_len, tot_len = 0, data_start_pos, temp_pos = -1;
11658     tng_function_status stat;
11659     tng_gen_block_t block;
11660
11661     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11662
11663     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
11664     {
11665         return(TNG_CRITICAL);
11666     }
11667
11668     if(tng_data->n_trajectory_frame_sets > 0)
11669     {
11670         stat = tng_file_headers_len_get(tng_data, &orig_len);
11671         if(stat != TNG_SUCCESS)
11672         {
11673             return(stat);
11674         }
11675
11676         tng_block_init(&block);
11677         block->name = (char *)malloc(TNG_MAX_STR_LEN);
11678         if(!block->name)
11679         {
11680             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
11681                     __FILE__, __LINE__);
11682             tng_block_destroy(&block);
11683             return(TNG_CRITICAL);
11684         }
11685         strcpy(block->name, "GENERAL INFO");
11686         tng_block_header_len_calculate(tng_data, block, &len);
11687         tot_len += len;
11688         tng_general_info_block_len_calculate(tng_data, &len);
11689         tot_len += len;
11690         strcpy(block->name, "MOLECULES");
11691         tng_block_header_len_calculate(tng_data, block, &len);
11692         tot_len += len;
11693         tng_molecules_block_len_calculate(tng_data, &len);
11694         tot_len += len;
11695
11696         for(i = 0; i < tng_data->n_data_blocks; i++)
11697         {
11698             strcpy(block->name, tng_data->non_tr_data[i].block_name);
11699             tng_block_header_len_calculate(tng_data, block, &len);
11700             tot_len += len;
11701             tng_data_block_len_calculate(tng_data,
11702                                         (tng_data_t)&tng_data->non_tr_data[i],
11703                                          TNG_FALSE, 1, 1, 1, 0, 1,
11704                                          &data_start_pos,
11705                                          &len);
11706             tot_len += len;
11707         }
11708         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11709         {
11710             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
11711             tng_block_header_len_calculate(tng_data, block, &len);
11712             tot_len += len;
11713             tng_data_block_len_calculate(tng_data,
11714                                          &tng_data->non_tr_particle_data[i],
11715                                          TNG_TRUE, 1, 1, 1, 0,
11716                                          tng_data->n_particles,
11717                                          &data_start_pos,
11718                                          &len);
11719             tot_len += len;
11720         }
11721         tng_block_destroy(&block);
11722
11723         if(tot_len > orig_len)
11724         {
11725             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len, hash_mode);
11726             tng_data->last_trajectory_frame_set_input_file_pos = tng_data->last_trajectory_frame_set_output_file_pos;
11727         }
11728
11729         stat = tng_reread_frame_set_at_file_pos(tng_data, tng_data->last_trajectory_frame_set_input_file_pos);
11730         if(stat == TNG_CRITICAL)
11731         {
11732             fprintf(stderr, "TNG library: Cannot read frame set. %s: %d\n",
11733                     __FILE__, __LINE__);
11734             return(TNG_CRITICAL);
11735         }
11736
11737         /* In order to write non-trajectory data the current_trajectory_frame_set_output_file_pos
11738          * must temporarily be reset */
11739         temp_pos = tng_data->current_trajectory_frame_set_output_file_pos;
11740         tng_data->current_trajectory_frame_set_output_file_pos = -1;
11741     }
11742
11743     if(tng_general_info_block_write(tng_data, hash_mode)
11744        != TNG_SUCCESS)
11745     {
11746         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
11747                 tng_data->input_file_path, __FILE__, __LINE__);
11748         return(TNG_CRITICAL);
11749     }
11750
11751     if(tng_molecules_block_write(tng_data, hash_mode)
11752         != TNG_SUCCESS)
11753     {
11754         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
11755                 tng_data->input_file_path, __FILE__, __LINE__);
11756         return(TNG_CRITICAL);
11757     }
11758
11759     /* FIXME: Currently writing non-trajectory data blocks here.
11760      * Should perhaps be moved. */
11761     tng_block_init(&block);
11762     for(i = 0; i < tng_data->n_data_blocks; i++)
11763     {
11764         block->id = tng_data->non_tr_data[i].block_id;
11765         tng_data_block_write(tng_data, block,
11766                              i, TNG_FALSE, 0, hash_mode);
11767     }
11768
11769     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11770     {
11771         block->id = tng_data->non_tr_particle_data[i].block_id;
11772         tng_data_block_write(tng_data, block,
11773                              i, TNG_TRUE, 0, hash_mode);
11774     }
11775
11776     tng_block_destroy(&block);
11777
11778     /* Continue writing at the end of the file. */
11779     fseeko(tng_data->output_file, 0, SEEK_END);
11780     if(temp_pos > 0)
11781     {
11782         tng_data->current_trajectory_frame_set_output_file_pos = temp_pos;
11783     }
11784
11785     return(TNG_SUCCESS);
11786 }
11787
11788 tng_function_status DECLSPECDLLEXPORT tng_block_read_next
11789                 (const tng_trajectory_t tng_data,
11790                  const tng_gen_block_t block,
11791                  const char hash_mode)
11792 {
11793     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11794     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
11795
11796     switch(block->id)
11797     {
11798     case TNG_TRAJECTORY_FRAME_SET:
11799         return(tng_frame_set_block_read(tng_data, block, hash_mode));
11800     case TNG_PARTICLE_MAPPING:
11801         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
11802     case TNG_GENERAL_INFO:
11803         return(tng_general_info_block_read(tng_data, block, hash_mode));
11804     case TNG_MOLECULES:
11805         return(tng_molecules_block_read(tng_data, block, hash_mode));
11806     default:
11807         if(block->id >= TNG_TRAJ_BOX_SHAPE)
11808         {
11809             return(tng_data_block_contents_read(tng_data, block, hash_mode));
11810         }
11811         else
11812         {
11813             /* Skip to the next block */
11814             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11815             return(TNG_FAILURE);
11816         }
11817     }
11818 }
11819
11820 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
11821                 (const tng_trajectory_t tng_data,
11822                  const char hash_mode)
11823 {
11824     int64_t file_pos;
11825     tng_gen_block_t block;
11826     tng_function_status stat;
11827
11828     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11829
11830     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11831     {
11832         return(TNG_CRITICAL);
11833     }
11834
11835     file_pos = ftello(tng_data->input_file);
11836
11837     tng_block_init(&block);
11838
11839     /* Read block headers first to see what block is found. */
11840     stat = tng_block_header_read(tng_data, block);
11841     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
11842        block->id == -1)
11843     {
11844         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11845                file_pos, __FILE__, __LINE__);
11846         tng_block_destroy(&block);
11847         return(TNG_CRITICAL);
11848     }
11849
11850     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11851
11852     if(tng_block_read_next(tng_data, block,
11853                            hash_mode) == TNG_SUCCESS)
11854     {
11855         tng_data->n_trajectory_frame_sets++;
11856         file_pos = ftello(tng_data->input_file);
11857         /* Read all blocks until next frame set block */
11858         stat = tng_block_header_read(tng_data, block);
11859         while(file_pos < tng_data->input_file_len &&
11860               stat != TNG_CRITICAL &&
11861               block->id != TNG_TRAJECTORY_FRAME_SET &&
11862               block->id != -1)
11863         {
11864             stat = tng_block_read_next(tng_data, block,
11865                                        hash_mode);
11866             if(stat != TNG_CRITICAL)
11867             {
11868                 file_pos = ftello(tng_data->input_file);
11869                 if(file_pos < tng_data->input_file_len)
11870                 {
11871                     stat = tng_block_header_read(tng_data, block);
11872                 }
11873             }
11874         }
11875         if(stat == TNG_CRITICAL)
11876         {
11877             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11878                    file_pos, __FILE__, __LINE__);
11879             tng_block_destroy(&block);
11880             return(stat);
11881         }
11882
11883         if(block->id == TNG_TRAJECTORY_FRAME_SET)
11884         {
11885             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11886         }
11887     }
11888
11889     tng_block_destroy(&block);
11890
11891     return(TNG_SUCCESS);
11892 }
11893
11894
11895 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
11896                 (const tng_trajectory_t tng_data,
11897                  const char hash_mode,
11898                  const int64_t block_id)
11899 {
11900     int64_t file_pos;
11901     tng_gen_block_t block;
11902     tng_function_status stat;
11903     int found_flag = 1;
11904
11905     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11906
11907     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11908     {
11909         return(TNG_CRITICAL);
11910     }
11911
11912     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11913
11914     if(file_pos < 0)
11915     {
11916         /* No current frame set. This means that the first frame set must be
11917          * read */
11918         found_flag = 0;
11919         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11920     }
11921
11922     if(file_pos > 0)
11923     {
11924         fseeko(tng_data->input_file,
11925               file_pos,
11926               SEEK_SET);
11927     }
11928     else
11929     {
11930         return(TNG_FAILURE);
11931     }
11932
11933     tng_block_init(&block);
11934
11935     /* Read block headers first to see what block is found. */
11936     stat = tng_block_header_read(tng_data, block);
11937     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11938     {
11939         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11940                file_pos, __FILE__, __LINE__);
11941         tng_block_destroy(&block);
11942         return(TNG_CRITICAL);
11943     }
11944     /* If the current frame set had already been read skip its block contents */
11945     if(found_flag)
11946     {
11947         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11948     }
11949     /* Otherwise read the frame set block */
11950     else
11951     {
11952         stat = tng_block_read_next(tng_data, block,
11953                                    hash_mode);
11954         if(stat != TNG_SUCCESS)
11955         {
11956             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
11957             tng_block_destroy(&block);
11958             return(stat);
11959         }
11960     }
11961     file_pos = ftello(tng_data->input_file);
11962
11963     found_flag = 0;
11964
11965     /* Read only blocks of the requested ID
11966         * until next frame set block */
11967     stat = tng_block_header_read(tng_data, block);
11968     while(file_pos < tng_data->input_file_len &&
11969           stat != TNG_CRITICAL &&
11970           block->id != TNG_TRAJECTORY_FRAME_SET &&
11971           block->id != -1)
11972     {
11973         if(block->id == block_id)
11974         {
11975             stat = tng_block_read_next(tng_data, block,
11976                                        hash_mode);
11977             if(stat != TNG_CRITICAL)
11978             {
11979                 file_pos = ftello(tng_data->input_file);
11980                 found_flag = 1;
11981                 if(file_pos < tng_data->input_file_len)
11982                 {
11983                     stat = tng_block_header_read(tng_data, block);
11984                 }
11985             }
11986         }
11987         else
11988         {
11989             file_pos += block->block_contents_size + block->header_contents_size;
11990             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11991             if(file_pos < tng_data->input_file_len)
11992             {
11993                 stat = tng_block_header_read(tng_data, block);
11994             }
11995         }
11996     }
11997     if(stat == TNG_CRITICAL)
11998     {
11999         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
12000                 file_pos, __FILE__, __LINE__);
12001         tng_block_destroy(&block);
12002         return(stat);
12003     }
12004
12005     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12006     {
12007         fseeko(tng_data->input_file, file_pos, SEEK_SET);
12008     }
12009
12010     tng_block_destroy(&block);
12011
12012     if(found_flag)
12013     {
12014         return(TNG_SUCCESS);
12015     }
12016     else
12017     {
12018         return(TNG_FAILURE);
12019     }
12020 }
12021
12022 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
12023                 (const tng_trajectory_t tng_data,
12024                  const char hash_mode)
12025 {
12026     int64_t file_pos;
12027
12028     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12029
12030     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12031     {
12032         return(TNG_CRITICAL);
12033     }
12034
12035     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12036
12037     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12038     {
12039         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12040     }
12041
12042     if(file_pos > 0)
12043     {
12044         fseeko(tng_data->input_file,
12045                file_pos,
12046                SEEK_SET);
12047     }
12048     else
12049     {
12050         return(TNG_FAILURE);
12051     }
12052
12053     return(tng_frame_set_read(tng_data, hash_mode));
12054 }
12055
12056 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
12057                 (const tng_trajectory_t tng_data,
12058                  const char hash_mode,
12059                  const int64_t block_id)
12060 {
12061     int64_t file_pos;
12062     tng_gen_block_t block;
12063     tng_function_status stat;
12064
12065     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12066
12067     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12068     {
12069         return(TNG_CRITICAL);
12070     }
12071
12072     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12073
12074     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12075     {
12076         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12077     }
12078
12079     if(file_pos > 0)
12080     {
12081         fseeko(tng_data->input_file,
12082                file_pos,
12083                SEEK_SET);
12084     }
12085     else
12086     {
12087         return(TNG_FAILURE);
12088     }
12089
12090     tng_block_init(&block);
12091
12092     /* Read block headers first to see what block is found. */
12093     stat = tng_block_header_read(tng_data, block);
12094     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12095     {
12096         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
12097                 file_pos, __FILE__, __LINE__);
12098         tng_block_destroy(&block);
12099         return(TNG_CRITICAL);
12100     }
12101
12102     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12103
12104     if(tng_block_read_next(tng_data, block,
12105                            hash_mode) == TNG_SUCCESS)
12106     {
12107         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
12108     }
12109
12110     tng_block_destroy(&block);
12111
12112     return(stat);
12113 }
12114
12115 tng_function_status tng_frame_set_write
12116                 (const tng_trajectory_t tng_data,
12117                  const char hash_mode)
12118 {
12119     int i, j;
12120     tng_gen_block_t block;
12121     tng_trajectory_frame_set_t frame_set;
12122     tng_function_status stat;
12123
12124     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12125
12126     frame_set = &tng_data->current_trajectory_frame_set;
12127
12128     if(frame_set->n_written_frames == frame_set->n_frames)
12129     {
12130         return(TNG_SUCCESS);
12131     }
12132
12133     tng_data->current_trajectory_frame_set_output_file_pos =
12134     ftello(tng_data->output_file);
12135     tng_data->last_trajectory_frame_set_output_file_pos =
12136     tng_data->current_trajectory_frame_set_output_file_pos;
12137
12138     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
12139     {
12140         return(TNG_FAILURE);
12141     }
12142
12143     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
12144     {
12145         tng_data->first_trajectory_frame_set_output_file_pos =
12146         tng_data->current_trajectory_frame_set_output_file_pos;
12147     }
12148
12149     tng_block_init(&block);
12150
12151     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
12152     {
12153         tng_block_destroy(&block);
12154         return(TNG_FAILURE);
12155     }
12156
12157     /* Write non-particle data blocks */
12158     for(i = 0; i<frame_set->n_data_blocks; i++)
12159     {
12160         block->id = frame_set->tr_data[i].block_id;
12161         tng_data_block_write(tng_data, block, i, TNG_FALSE, 0, hash_mode);
12162     }
12163     /* Write the mapping blocks and particle data blocks*/
12164     if(frame_set->n_mapping_blocks)
12165     {
12166         for(i = 0; i < frame_set->n_mapping_blocks; i++)
12167         {
12168             block->id = TNG_PARTICLE_MAPPING;
12169             if(frame_set->mappings[i].n_particles > 0)
12170             {
12171                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
12172                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
12173                 {
12174                     block->id = frame_set->tr_particle_data[j].block_id;
12175                     tng_data_block_write(tng_data, block,
12176                                          j, TNG_TRUE, &frame_set->mappings[i],
12177                                          hash_mode);
12178                 }
12179             }
12180         }
12181     }
12182     else
12183     {
12184         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
12185         {
12186             block->id = frame_set->tr_particle_data[i].block_id;
12187             tng_data_block_write(tng_data, block,
12188                                  i, TNG_TRUE, 0, hash_mode);
12189         }
12190     }
12191
12192
12193     /* Update pointers in the general info block */
12194     stat = tng_header_pointers_update(tng_data, hash_mode);
12195
12196     if(stat == TNG_SUCCESS)
12197     {
12198         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
12199     }
12200
12201     tng_block_destroy(&block);
12202
12203     frame_set->n_unwritten_frames = 0;
12204
12205     fflush(tng_data->output_file);
12206
12207     return(stat);
12208 }
12209
12210 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
12211                 (const tng_trajectory_t tng_data,
12212                  const char hash_mode)
12213 {
12214     tng_trajectory_frame_set_t frame_set;
12215
12216     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12217
12218     frame_set = &tng_data->current_trajectory_frame_set;
12219
12220     if(frame_set->n_unwritten_frames == 0)
12221     {
12222         return(TNG_SUCCESS);
12223     }
12224     frame_set->n_frames = frame_set->n_unwritten_frames;
12225
12226     return(tng_frame_set_write(tng_data, hash_mode));
12227 }
12228
12229 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
12230                 (const tng_trajectory_t tng_data,
12231                  const int64_t first_frame,
12232                  const int64_t n_frames)
12233 {
12234     tng_gen_block_t block;
12235     tng_trajectory_frame_set_t frame_set;
12236     FILE *temp = tng_data->input_file;
12237     int64_t curr_file_pos;
12238
12239     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12240     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12241     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12242
12243     frame_set = &tng_data->current_trajectory_frame_set;
12244
12245     curr_file_pos = ftello(tng_data->output_file);
12246
12247     if(curr_file_pos <= 10)
12248     {
12249         tng_file_headers_write(tng_data, TNG_USE_HASH);
12250     }
12251
12252     /* Set pointer to previous frame set to the one that was loaded
12253      * before.
12254      * FIXME: This is a bit risky. If they are not added in order
12255      * it will be wrong. */
12256     if(tng_data->n_trajectory_frame_sets)
12257     {
12258         frame_set->prev_frame_set_file_pos =
12259         tng_data->last_trajectory_frame_set_output_file_pos;
12260     }
12261
12262     frame_set->next_frame_set_file_pos = -1;
12263
12264     tng_data->current_trajectory_frame_set_output_file_pos =
12265     ftello(tng_data->output_file);
12266
12267     tng_data->n_trajectory_frame_sets++;
12268
12269     /* Set the medium range pointers */
12270     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
12271     {
12272         frame_set->medium_stride_prev_frame_set_file_pos =
12273         tng_data->first_trajectory_frame_set_output_file_pos;
12274     }
12275     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12276     {
12277         /* FIXME: Currently only working if the previous frame set has its
12278          * medium stride pointer already set. This might need some fixing. */
12279         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
12280            frame_set->medium_stride_prev_frame_set_file_pos != 0)
12281         {
12282             tng_block_init(&block);
12283             tng_data->input_file = tng_data->output_file;
12284
12285             curr_file_pos = ftello(tng_data->output_file);
12286             fseeko(tng_data->output_file,
12287                    frame_set->medium_stride_prev_frame_set_file_pos,
12288                    SEEK_SET);
12289
12290             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12291             {
12292                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12293                     __FILE__, __LINE__);
12294                 tng_data->input_file = temp;
12295                 tng_block_destroy(&block);
12296                 return(TNG_CRITICAL);
12297             }
12298
12299             /* Read the next frame set from the previous frame set and one
12300              * medium stride step back */
12301             fseeko(tng_data->output_file, block->block_contents_size - (6 *
12302             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
12303             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
12304                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
12305                1, tng_data->output_file) == 0)
12306             {
12307                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12308                 tng_data->input_file = temp;
12309                 tng_block_destroy(&block);
12310                 return(TNG_CRITICAL);
12311             }
12312
12313             if(tng_data->input_endianness_swap_func_64)
12314             {
12315                 if(tng_data->input_endianness_swap_func_64(tng_data,
12316                    (uint64_t *)&frame_set->medium_stride_prev_frame_set_file_pos)
12317                     != TNG_SUCCESS)
12318                 {
12319                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12320                             __FILE__, __LINE__);
12321                 }
12322             }
12323
12324             tng_block_destroy(&block);
12325
12326             /* Set the long range pointers */
12327             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
12328             {
12329                 frame_set->long_stride_prev_frame_set_file_pos =
12330                 tng_data->first_trajectory_frame_set_output_file_pos;
12331             }
12332             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12333             {
12334                 /* FIXME: Currently only working if the previous frame set has its
12335                 * long stride pointer already set. This might need some fixing. */
12336                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
12337                 frame_set->long_stride_prev_frame_set_file_pos != 0)
12338                 {
12339                     tng_block_init(&block);
12340                     tng_data->input_file = tng_data->output_file;
12341
12342                     fseeko(tng_data->output_file,
12343                            frame_set->long_stride_prev_frame_set_file_pos,
12344                            SEEK_SET);
12345
12346                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12347                     {
12348                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12349                             __FILE__, __LINE__);
12350                         tng_data->input_file = temp;
12351                         tng_block_destroy(&block);
12352                         return(TNG_CRITICAL);
12353                     }
12354
12355                     /* Read the next frame set from the previous frame set and one
12356                     * long stride step back */
12357                     fseeko(tng_data->output_file, block->block_contents_size - (6 *
12358                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
12359
12360                     tng_block_destroy(&block);
12361
12362                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
12363                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
12364                     1, tng_data->output_file) == 0)
12365                     {
12366                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12367                         tng_data->input_file = temp;
12368                         return(TNG_CRITICAL);
12369                     }
12370
12371                     if(tng_data->input_endianness_swap_func_64)
12372                     {
12373                         if(tng_data->input_endianness_swap_func_64(tng_data,
12374                            (uint64_t *)&frame_set->long_stride_prev_frame_set_file_pos)
12375                             != TNG_SUCCESS)
12376                         {
12377                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12378                                     __FILE__, __LINE__);
12379                         }
12380                     }
12381
12382                 }
12383             }
12384
12385             tng_data->input_file = temp;
12386             fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
12387         }
12388     }
12389
12390     frame_set->first_frame = first_frame;
12391     frame_set->n_frames = n_frames;
12392     frame_set->n_written_frames = 0;
12393     frame_set->n_unwritten_frames = 0;
12394     frame_set->first_frame_time = -1;
12395
12396     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
12397        tng_data->first_trajectory_frame_set_output_file_pos == 0)
12398     {
12399         tng_data->first_trajectory_frame_set_output_file_pos =
12400         tng_data->current_trajectory_frame_set_output_file_pos;
12401     }
12402     /* FIXME: Should check the frame number instead of the file_pos,
12403      * in case frame sets are not in order */
12404     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
12405        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
12406        tng_data->last_trajectory_frame_set_output_file_pos <
12407        tng_data->current_trajectory_frame_set_output_file_pos)
12408     {
12409         tng_data->last_trajectory_frame_set_output_file_pos =
12410         tng_data->current_trajectory_frame_set_output_file_pos;
12411     }
12412
12413     return(TNG_SUCCESS);
12414 }
12415
12416 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
12417                 (const tng_trajectory_t tng_data,
12418                  const int64_t first_frame,
12419                  const int64_t n_frames,
12420                  const double first_frame_time)
12421 {
12422     tng_function_status stat;
12423
12424     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12425     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12426     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12427     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12428
12429
12430     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
12431     if(stat != TNG_SUCCESS)
12432     {
12433         return(stat);
12434     }
12435     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
12436
12437     return(stat);
12438 }
12439
12440 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
12441                 (const tng_trajectory_t tng_data,
12442                  const double first_frame_time)
12443 {
12444     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12445     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12446
12447     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
12448
12449     return(TNG_SUCCESS);
12450 }
12451
12452 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
12453                 (const tng_trajectory_t tng_data,
12454                  int64_t *frame)
12455 {
12456     int64_t file_pos, next_frame_set_file_pos;
12457     tng_gen_block_t block;
12458     tng_function_status stat;
12459
12460     tng_trajectory_frame_set_t frame_set;
12461
12462     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12463     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
12464     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
12465
12466     file_pos = ftello(tng_data->input_file);
12467
12468     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12469     {
12470         next_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12471     }
12472     else
12473     {
12474         frame_set = &tng_data->current_trajectory_frame_set;
12475         next_frame_set_file_pos = frame_set->next_frame_set_file_pos;
12476     }
12477
12478     if(next_frame_set_file_pos <= 0)
12479     {
12480         return(TNG_FAILURE);
12481     }
12482
12483     fseeko(tng_data->input_file, next_frame_set_file_pos, SEEK_SET);
12484     /* Read block headers first to see that a frame set block is found. */
12485     tng_block_init(&block);
12486     stat = tng_block_header_read(tng_data, block);
12487     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12488     {
12489         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
12490                file_pos, __FILE__, __LINE__);
12491         return(TNG_CRITICAL);
12492     }
12493 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12494     {
12495         tng_block_read_next(tng_data, block, TNG_USE_HASH);
12496     }*/
12497     tng_block_destroy(&block);
12498
12499     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
12500     {
12501         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
12502                __FILE__, __LINE__);
12503         return(TNG_CRITICAL);
12504     }
12505     fseeko(tng_data->input_file, file_pos, SEEK_SET);
12506
12507     return(TNG_SUCCESS);
12508 }
12509
12510 static tng_function_status tng_gen_data_block_add
12511                 (const tng_trajectory_t tng_data,
12512                  const int64_t id,
12513                  const tng_bool is_particle_data,
12514                  const char *block_name,
12515                  const char datatype,
12516                  const char block_type_flag,
12517                  int64_t n_frames,
12518                  const int64_t n_values_per_frame,
12519                  int64_t stride_length,
12520                  const int64_t num_first_particle,
12521                  const int64_t n_particles,
12522                  const int64_t codec_id,
12523                  void *new_data)
12524 {
12525     int i, size, len;
12526     int64_t j, k;
12527     int64_t tot_n_particles, n_frames_div;
12528     char ***first_dim_values, **second_dim_values;
12529     tng_trajectory_frame_set_t frame_set;
12530     tng_data_t data;
12531     char *new_data_c = (char *)new_data;
12532     tng_function_status stat;
12533
12534     frame_set = &tng_data->current_trajectory_frame_set;
12535
12536     if(stride_length <= 0)
12537     {
12538         stride_length = 1;
12539     }
12540
12541     if(is_particle_data)
12542     {
12543         stat = tng_particle_data_find(tng_data, id, &data);
12544     }
12545     else
12546     {
12547         stat = tng_data_find(tng_data, id, &data);
12548     }
12549     /* If the block does not exist, create it */
12550     if(stat != TNG_SUCCESS)
12551     {
12552         if(is_particle_data)
12553         {
12554             stat = tng_particle_data_block_create(tng_data, block_type_flag);
12555         }
12556         else
12557         {
12558             stat = tng_data_block_create(tng_data, block_type_flag);
12559         }
12560
12561         if(stat != TNG_SUCCESS)
12562         {
12563             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
12564                    __FILE__, __LINE__);
12565             return(TNG_CRITICAL);
12566         }
12567         if(is_particle_data)
12568         {
12569             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12570             {
12571                 data = &frame_set->tr_particle_data[frame_set->
12572                                                     n_particle_data_blocks - 1];
12573             }
12574             else
12575             {
12576                 data = &tng_data->non_tr_particle_data[tng_data->
12577                                                     n_particle_data_blocks - 1];
12578             }
12579         }
12580         else
12581         {
12582             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12583             {
12584                 data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
12585             }
12586             else
12587             {
12588                 data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
12589             }
12590         }
12591         data->block_id = id;
12592
12593         len = tng_min_size(strlen(block_name) + 1, TNG_MAX_STR_LEN);
12594         data->block_name = (char *)malloc(len);
12595         if(!data->block_name)
12596         {
12597             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
12598                     __FILE__, __LINE__);
12599             return(TNG_CRITICAL);
12600         }
12601         strncpy(data->block_name, block_name, len);
12602
12603         data->values = 0;
12604         /* FIXME: Memory leak from strings. */
12605         data->strings = 0;
12606         data->last_retrieved_frame = -1;
12607     }
12608
12609     data->datatype = datatype;
12610     data->stride_length = tng_max_i64(stride_length, 1);
12611     data->n_values_per_frame = n_values_per_frame;
12612     data->n_frames = n_frames;
12613     if(is_particle_data)
12614     {
12615         data->dependency = TNG_PARTICLE_DEPENDENT;
12616     }
12617     else
12618     {
12619         data->dependency = 0;
12620     }
12621     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
12622                           (n_frames > 1 ||
12623                            frame_set->n_frames == n_frames ||
12624                            stride_length > 1))
12625     {
12626         data->dependency += TNG_FRAME_DEPENDENT;
12627     }
12628     data->codec_id = codec_id;
12629     data->compression_multiplier = 1.0;
12630     /* FIXME: This can cause problems. */
12631     data->first_frame_with_data = frame_set->first_frame;
12632
12633     if(is_particle_data)
12634     {
12635         if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
12636         {
12637             tot_n_particles = frame_set->n_particles;
12638         }
12639         else
12640         {
12641             tot_n_particles = tng_data->n_particles;
12642         }
12643     }
12644     /* This is just to keep the compiler happy - avoid it considering tot_n_particles
12645      * uninitialized. */
12646     else
12647     {
12648         tot_n_particles = 0;
12649     }
12650
12651     /* If data values are supplied add that data to the data block. */
12652     if(new_data_c)
12653     {
12654         /* Allocate memory */
12655         if(is_particle_data)
12656         {
12657             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
12658                                             stride_length, tot_n_particles,
12659                                             n_values_per_frame);
12660         }
12661         else
12662         {
12663             stat = tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
12664                                  n_values_per_frame);
12665         }
12666         if(stat != TNG_SUCCESS)
12667         {
12668             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
12669                 __FILE__, __LINE__);
12670             return(TNG_CRITICAL);
12671         }
12672
12673         if(n_frames > frame_set->n_unwritten_frames)
12674         {
12675             frame_set->n_unwritten_frames = n_frames;
12676         }
12677
12678         n_frames_div = (n_frames % stride_length) ?
12679                      n_frames / stride_length + 1:
12680                      n_frames / stride_length;
12681
12682         if(datatype == TNG_CHAR_DATA)
12683         {
12684             if(is_particle_data)
12685             {
12686                 for(i = 0; i < n_frames_div; i++)
12687                 {
12688                     first_dim_values = data->strings[i];
12689                     for(j = num_first_particle; j < num_first_particle + n_particles;
12690                         j++)
12691                     {
12692                         second_dim_values = first_dim_values[j];
12693                         for(k = 0; k < n_values_per_frame; k++)
12694                         {
12695                             len = tng_min_size(strlen(new_data_c) + 1,
12696                                     TNG_MAX_STR_LEN);
12697                             if(second_dim_values[k])
12698                             {
12699                                 free(second_dim_values[k]);
12700                             }
12701                             second_dim_values[k] = (char *)malloc(len);
12702                             if(!second_dim_values[k])
12703                             {
12704                                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
12705                                         __FILE__, __LINE__);
12706                                 return(TNG_CRITICAL);
12707                             }
12708                             strncpy(second_dim_values[k],
12709                                     new_data_c, len);
12710                             new_data_c += len;
12711                         }
12712                     }
12713                 }
12714             }
12715             else
12716             {
12717                 for(i = 0; i < n_frames_div; i++)
12718                 {
12719                     second_dim_values = data->strings[0][i];
12720                     for(j = 0; j < n_values_per_frame; j++)
12721                     {
12722                         len = tng_min_size(strlen(new_data_c) + 1,
12723                                     TNG_MAX_STR_LEN);
12724                         if(second_dim_values[j])
12725                         {
12726                             free(second_dim_values[j]);
12727                         }
12728                         second_dim_values[j] = (char *)malloc(len);
12729                         if(!second_dim_values[j])
12730                         {
12731                             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
12732                                     __FILE__, __LINE__);
12733                             return(TNG_CRITICAL);
12734                         }
12735                         strncpy(second_dim_values[j],
12736                                 new_data_c, len);
12737                         new_data_c += len;
12738                     }
12739                 }
12740             }
12741         }
12742         else
12743         {
12744             switch(datatype)
12745             {
12746             case TNG_INT_DATA:
12747                 size = sizeof(int64_t);
12748                 break;
12749             case TNG_FLOAT_DATA:
12750                 size = sizeof(float);
12751                 break;
12752             case TNG_DOUBLE_DATA:
12753             default:
12754                 size = sizeof(double);
12755             }
12756
12757             if(is_particle_data)
12758             {
12759                 memcpy(data->values, new_data, size * n_frames_div *
12760                     n_particles * n_values_per_frame);
12761             }
12762             else
12763             {
12764                 memcpy(data->values, new_data, size * n_frames_div *
12765                     n_values_per_frame);
12766             }
12767         }
12768     }
12769
12770     return(TNG_SUCCESS);
12771 }
12772
12773 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
12774                 (const tng_trajectory_t tng_data,
12775                  const int64_t id,
12776                  const char *block_name,
12777                  const char datatype,
12778                  const char block_type_flag,
12779                  int64_t n_frames,
12780                  const int64_t n_values_per_frame,
12781                  int64_t stride_length,
12782                  const int64_t codec_id,
12783                  void *new_data)
12784 {
12785     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12786     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
12787     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12788
12789     return(tng_gen_data_block_add(tng_data, id, TNG_FALSE, block_name, datatype,
12790                                   block_type_flag, n_frames, n_values_per_frame,
12791                                   stride_length, 0, 0, codec_id, new_data));
12792 }
12793
12794 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
12795                 (const tng_trajectory_t tng_data,
12796                  const int64_t id,
12797                  const char *block_name,
12798                  const char datatype,
12799                  const char block_type_flag,
12800                  int64_t n_frames,
12801                  const int64_t n_values_per_frame,
12802                  int64_t stride_length,
12803                  const int64_t num_first_particle,
12804                  const int64_t n_particles,
12805                  const int64_t codec_id,
12806                  void *new_data)
12807 {
12808     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12809     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
12810     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12811     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
12812     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
12813
12814     return(tng_gen_data_block_add(tng_data, id, TNG_TRUE, block_name, datatype,
12815                                   block_type_flag, n_frames, n_values_per_frame,
12816                                   stride_length, num_first_particle, n_particles,
12817                                   codec_id, new_data));
12818 }
12819
12820 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
12821                 (const tng_trajectory_t tng_data,
12822                  const int64_t block_id,
12823                  char *name,
12824                  const int max_len)
12825 {
12826     int64_t i;
12827     tng_trajectory_frame_set_t frame_set;
12828     tng_function_status stat;
12829     tng_data_t data;
12830     int block_type = -1;
12831
12832     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12833     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
12834
12835     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12836     {
12837         data = &tng_data->non_tr_particle_data[i];
12838         if(data->block_id == block_id)
12839         {
12840             strncpy(name, data->block_name, max_len);
12841             name[max_len - 1] = '\0';
12842             return(TNG_SUCCESS);
12843         }
12844     }
12845     for(i = 0; i < tng_data->n_data_blocks; i++)
12846     {
12847         data = &tng_data->non_tr_data[i];
12848         if(data->block_id == block_id)
12849         {
12850             strncpy(name, data->block_name, max_len);
12851             name[max_len - 1] = '\0';
12852             return(TNG_SUCCESS);
12853         }
12854     }
12855
12856     frame_set = &tng_data->current_trajectory_frame_set;
12857
12858     stat = tng_particle_data_find(tng_data, block_id, &data);
12859     if(stat == TNG_SUCCESS)
12860     {
12861         block_type = TNG_PARTICLE_BLOCK_DATA;
12862     }
12863     else
12864     {
12865         stat = tng_data_find(tng_data, block_id, &data);
12866         if(stat == TNG_SUCCESS)
12867         {
12868             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
12869         }
12870         else
12871         {
12872             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
12873             if(stat != TNG_SUCCESS)
12874             {
12875                 return(stat);
12876             }
12877             stat = tng_particle_data_find(tng_data, block_id, &data);
12878             if(stat == TNG_SUCCESS)
12879             {
12880                 block_type = TNG_PARTICLE_BLOCK_DATA;
12881             }
12882             else
12883             {
12884                 stat = tng_data_find(tng_data, block_id, &data);
12885                 if(stat == TNG_SUCCESS)
12886                 {
12887                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
12888                 }
12889             }
12890         }
12891     }
12892     if(block_type == TNG_PARTICLE_BLOCK_DATA)
12893     {
12894         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
12895         {
12896             data = &frame_set->tr_particle_data[i];
12897             if(data->block_id == block_id)
12898             {
12899                 strncpy(name, data->block_name, max_len);
12900                 name[max_len - 1] = '\0';
12901                 return(TNG_SUCCESS);
12902             }
12903         }
12904     }
12905     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
12906     {
12907         for(i = 0; i < frame_set->n_data_blocks; i++)
12908         {
12909             data = &frame_set->tr_data[i];
12910             if(data->block_id == block_id)
12911             {
12912                 strncpy(name, data->block_name, max_len);
12913                 name[max_len - 1] = '\0';
12914                 return(TNG_SUCCESS);
12915             }
12916         }
12917     }
12918
12919     return(TNG_FAILURE);
12920 }
12921
12922 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
12923                 (const tng_trajectory_t tng_data,
12924                  const int64_t block_id,
12925                  int *block_dependency)
12926 {
12927     int64_t i;
12928     tng_function_status stat;
12929     tng_data_t data;
12930
12931     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12932     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
12933
12934     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12935     {
12936         data = &tng_data->non_tr_particle_data[i];
12937         if(data->block_id == block_id)
12938         {
12939             *block_dependency = TNG_PARTICLE_DEPENDENT;
12940             return(TNG_SUCCESS);
12941         }
12942     }
12943     for(i = 0; i < tng_data->n_data_blocks; i++)
12944     {
12945         data = &tng_data->non_tr_data[i];
12946         if(data->block_id == block_id)
12947         {
12948             *block_dependency = 0;
12949             return(TNG_SUCCESS);
12950         }
12951     }
12952
12953     stat = tng_particle_data_find(tng_data, block_id, &data);
12954     if(stat == TNG_SUCCESS)
12955     {
12956         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
12957         return(TNG_SUCCESS);
12958     }
12959     else
12960     {
12961         stat = tng_data_find(tng_data, block_id, &data);
12962         if(stat == TNG_SUCCESS)
12963         {
12964             *block_dependency = TNG_FRAME_DEPENDENT;
12965             return(TNG_SUCCESS);
12966         }
12967         else
12968         {
12969             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
12970             if(stat != TNG_SUCCESS)
12971             {
12972                 return(stat);
12973             }
12974             stat = tng_particle_data_find(tng_data, block_id, &data);
12975             if(stat == TNG_SUCCESS)
12976             {
12977                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
12978                 return(TNG_SUCCESS);
12979             }
12980             else
12981             {
12982                 stat = tng_data_find(tng_data, block_id, &data);
12983                 if(stat == TNG_SUCCESS)
12984                 {
12985                     *block_dependency = TNG_FRAME_DEPENDENT;
12986                     return(TNG_SUCCESS);
12987                 }
12988             }
12989         }
12990     }
12991
12992     return(TNG_FAILURE);
12993 }
12994
12995 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
12996                 (const tng_trajectory_t tng_data,
12997                  const int64_t block_id,
12998                  int64_t *n_values_per_frame)
12999 {
13000     int64_t i;
13001     tng_function_status stat;
13002     tng_data_t data;
13003
13004     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13005     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
13006
13007     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13008     {
13009         data = &tng_data->non_tr_particle_data[i];
13010         if(data->block_id == block_id)
13011         {
13012             *n_values_per_frame = data->n_values_per_frame;
13013             return(TNG_SUCCESS);
13014         }
13015     }
13016     for(i = 0; i < tng_data->n_data_blocks; i++)
13017     {
13018         data = &tng_data->non_tr_data[i];
13019         if(data->block_id == block_id)
13020         {
13021             *n_values_per_frame = data->n_values_per_frame;
13022             return(TNG_SUCCESS);
13023         }
13024     }
13025
13026     stat = tng_particle_data_find(tng_data, block_id, &data);
13027     if(stat == TNG_SUCCESS)
13028     {
13029         *n_values_per_frame = data->n_values_per_frame;
13030         return(TNG_SUCCESS);
13031     }
13032     else
13033     {
13034         stat = tng_data_find(tng_data, block_id, &data);
13035         if(stat == TNG_SUCCESS)
13036         {
13037             *n_values_per_frame = data->n_values_per_frame;
13038             return(TNG_SUCCESS);
13039         }
13040         else
13041         {
13042             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13043             if(stat != TNG_SUCCESS)
13044             {
13045                 return(stat);
13046             }
13047             stat = tng_particle_data_find(tng_data, block_id, &data);
13048             if(stat == TNG_SUCCESS)
13049             {
13050                 *n_values_per_frame = data->n_values_per_frame;
13051                 return(TNG_SUCCESS);
13052             }
13053             else
13054             {
13055                 stat = tng_data_find(tng_data, block_id, &data);
13056                 if(stat == TNG_SUCCESS)
13057                 {
13058                     *n_values_per_frame = data->n_values_per_frame;
13059                     return(TNG_SUCCESS);
13060                 }
13061             }
13062         }
13063     }
13064
13065     return(TNG_FAILURE);
13066 }
13067
13068 tng_function_status DECLSPECDLLEXPORT tng_frame_set_n_frames_of_data_block_get
13069                 (const tng_trajectory_t tng_data,
13070                  const int64_t block_id,
13071                  int64_t *n_frames)
13072 {
13073     tng_gen_block_t block;
13074     tng_function_status stat;
13075     char datatype, dependency, sparse_data;
13076     int64_t n_values, codec_id, first_frame_with_data, stride_length, curr_n_frames;
13077     int64_t num_first_particle, block_n_particles;
13078     double multiplier;
13079     md5_state_t md5_state;
13080     int found = TNG_FALSE;
13081
13082     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13083
13084     tng_block_init(&block);
13085
13086     stat = tng_block_header_read(tng_data, block);
13087     /* If the block header could not be read the reading position might not have been
13088      * at the start of a block. Try again from the file position of the current frame
13089      * set. */
13090     if(stat != TNG_SUCCESS)
13091     {
13092         fseeko(tng_data->input_file, tng_data->current_trajectory_frame_set_input_file_pos, SEEK_SET);
13093         stat = tng_block_header_read(tng_data, block);
13094         if(stat != TNG_SUCCESS)
13095         {
13096             tng_block_destroy(&block);
13097             return(stat);
13098         }
13099     }
13100     if(block->id == TNG_TRAJECTORY_FRAME_SET)
13101     {
13102         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
13103         if(stat != TNG_SUCCESS)
13104         {
13105             tng_block_destroy(&block);
13106             return(stat);
13107         }
13108         stat = tng_block_header_read(tng_data, block);
13109     }
13110     while(stat == TNG_SUCCESS && block->id != TNG_TRAJECTORY_FRAME_SET && found == TNG_FALSE)
13111     {
13112         if(block->id == block_id)
13113         {
13114             stat = tng_data_block_meta_information_read(tng_data, &datatype,
13115                                                         &dependency, &sparse_data,
13116                                                         &n_values, &codec_id,
13117                                                         &first_frame_with_data,
13118                                                         &stride_length, &curr_n_frames,
13119                                                         &num_first_particle,
13120                                                         &block_n_particles,
13121                                                         &multiplier, TNG_SKIP_HASH,
13122                                                         &md5_state);
13123             if(stat == TNG_SUCCESS)
13124             {
13125                 found = TNG_TRUE;
13126             }
13127         }
13128         else
13129         {
13130             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
13131             stat = tng_block_header_read(tng_data, block);
13132         }
13133     }
13134     if(found == TNG_TRUE)
13135     {
13136         *n_frames = (tng_data->current_trajectory_frame_set.n_frames -
13137                      (tng_data->current_trajectory_frame_set.first_frame - first_frame_with_data)) / stride_length;
13138     }
13139     else if(stat == TNG_SUCCESS)
13140     {
13141         *n_frames = 0;
13142     }
13143
13144     tng_block_destroy(&block);
13145
13146     return(stat);
13147 }
13148
13149 static tng_function_status tng_frame_gen_data_write
13150                 (const tng_trajectory_t tng_data,
13151                  const int64_t frame_nr,
13152                  const int64_t block_id,
13153                  const tng_bool is_particle_data,
13154                  const int64_t val_first_particle,
13155                  const int64_t val_n_particles,
13156                  const void *values,
13157                  const char hash_mode)
13158 {
13159     int64_t header_pos, file_pos, tot_n_particles;
13160     int64_t output_file_len, n_values_per_frame, size, contents_size;
13161     int64_t header_size, temp_first, temp_last;
13162     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
13163     int64_t i, last_frame, temp_current, write_n_particles;
13164     tng_gen_block_t block;
13165     tng_trajectory_frame_set_t frame_set;
13166     FILE *temp = tng_data->input_file;
13167     struct tng_data data;
13168     tng_function_status stat;
13169     tng_particle_mapping_t mapping;
13170     char dependency, sparse_data, datatype;
13171     void *copy;
13172
13173     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13174     {
13175         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13176                __FILE__, __LINE__);
13177         return(TNG_CRITICAL);
13178     }
13179
13180     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13181     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13182     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13183     tng_data->first_trajectory_frame_set_input_file_pos =
13184     tng_data->first_trajectory_frame_set_output_file_pos;
13185     tng_data->last_trajectory_frame_set_input_file_pos =
13186     tng_data->last_trajectory_frame_set_output_file_pos;
13187     tng_data->current_trajectory_frame_set_input_file_pos =
13188     tng_data->current_trajectory_frame_set_output_file_pos;
13189
13190     tng_data->input_file = tng_data->output_file;
13191
13192     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13193
13194     frame_set = &tng_data->current_trajectory_frame_set;
13195
13196     if(stat != TNG_SUCCESS)
13197     {
13198         last_frame = frame_set->first_frame +
13199                      frame_set->n_frames - 1;
13200         /* If the wanted frame would be in the frame set after the last
13201             * frame set create a new frame set. */
13202         if(stat == TNG_FAILURE &&
13203             last_frame < frame_nr)
13204 /*           (last_frame < frame_nr &&
13205             tng_data->current_trajectory_frame_set.first_frame +
13206             tng_data->frame_set_n_frames >= frame_nr))*/
13207         {
13208             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13209             {
13210                 last_frame = frame_nr - 1;
13211             }
13212             tng_frame_set_new(tng_data,
13213                               last_frame+1,
13214                               tng_data->frame_set_n_frames);
13215             file_pos = ftello(tng_data->output_file);
13216             fseeko(tng_data->output_file, 0, SEEK_END);
13217             output_file_len = ftello(tng_data->output_file);
13218             fseeko(tng_data->output_file, file_pos, SEEK_SET);
13219
13220             /* Read mapping blocks from the last frame set */
13221             tng_block_init(&block);
13222
13223             stat = tng_block_header_read(tng_data, block);
13224             while(file_pos < output_file_len &&
13225                   stat != TNG_CRITICAL &&
13226                   block->id != TNG_TRAJECTORY_FRAME_SET &&
13227                   block->id != -1)
13228             {
13229                 if(block->id == TNG_PARTICLE_MAPPING)
13230                 {
13231                     tng_trajectory_mapping_block_read(tng_data, block,
13232                                                       hash_mode);
13233                 }
13234                 else
13235                 {
13236                     fseeko(tng_data->output_file, block->block_contents_size,
13237                         SEEK_CUR);
13238                 }
13239                 file_pos = ftello(tng_data->output_file);
13240                 if(file_pos < output_file_len)
13241                 {
13242                     stat = tng_block_header_read(tng_data, block);
13243                 }
13244             }
13245
13246             tng_block_destroy(&block);
13247             /* Write the frame set to disk */
13248             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13249             {
13250                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13251                 return(TNG_CRITICAL);
13252             }
13253         }
13254         else
13255         {
13256             tng_data->input_file = temp;
13257             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13258             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13259             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13260             return(stat);
13261         }
13262     }
13263
13264     tng_block_init(&block);
13265
13266     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13267
13268     fseeko(tng_data->output_file, 0, SEEK_END);
13269     output_file_len = ftello(tng_data->output_file);
13270     fseeko(tng_data->output_file, file_pos, SEEK_SET);
13271
13272     /* Read past the frame set block first */
13273     stat = tng_block_header_read(tng_data, block);
13274     if(stat == TNG_CRITICAL)
13275     {
13276         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13277                file_pos, __FILE__, __LINE__);
13278         tng_block_destroy(&block);
13279         tng_data->input_file = temp;
13280
13281         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13282         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13283         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13284         return(stat);
13285     }
13286     fseeko(tng_data->output_file, block->block_contents_size,
13287             SEEK_CUR);
13288
13289     if(is_particle_data == TNG_TRUE)
13290     {
13291         if(tng_data->var_num_atoms_flag)
13292         {
13293             tot_n_particles = frame_set->n_particles;
13294         }
13295         else
13296         {
13297             tot_n_particles = tng_data->n_particles;
13298         }
13299
13300         if(val_n_particles < tot_n_particles)
13301         {
13302             mapping_block_end_pos = -1;
13303             /* Read all mapping blocks to find the right place to put the data */
13304             stat = tng_block_header_read(tng_data, block);
13305             while(file_pos < output_file_len &&
13306                     stat != TNG_CRITICAL &&
13307                     block->id != TNG_TRAJECTORY_FRAME_SET &&
13308                     block->id != -1)
13309             {
13310                 if(block->id == TNG_PARTICLE_MAPPING)
13311                 {
13312                     tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
13313                 }
13314                 else
13315                 {
13316                     fseeko(tng_data->output_file, block->block_contents_size,
13317                            SEEK_CUR);
13318                 }
13319                 file_pos = ftello(tng_data->output_file);
13320                 if(block->id == TNG_PARTICLE_MAPPING)
13321                 {
13322                     mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
13323                     if(val_first_particle >= mapping->num_first_particle &&
13324                        val_first_particle < mapping->num_first_particle +
13325                        mapping->n_particles &&
13326                        val_first_particle + val_n_particles <=
13327                        mapping->num_first_particle + mapping->n_particles)
13328                     {
13329                         mapping_block_end_pos = file_pos;
13330                     }
13331                 }
13332                 if(file_pos < output_file_len)
13333                 {
13334                     stat = tng_block_header_read(tng_data, block);
13335                 }
13336             }
13337             if(stat == TNG_CRITICAL)
13338             {
13339                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13340                        file_pos, __FILE__, __LINE__);
13341                 tng_block_destroy(&block);
13342                 tng_data->input_file = temp;
13343
13344                 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13345                 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13346                 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13347                 return(stat);
13348             }
13349             if(mapping_block_end_pos < 0)
13350             {
13351                 tng_block_destroy(&block);
13352                 tng_data->input_file = temp;
13353
13354                 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13355                 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13356                 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13357                 return(TNG_FAILURE);
13358             }
13359             fseeko(tng_data->output_file, mapping_block_end_pos, SEEK_SET);
13360         }
13361     }
13362
13363     /* Read all block headers until next frame set block or
13364      * until the wanted block id is found */
13365     stat = tng_block_header_read(tng_data, block);
13366     while(file_pos < output_file_len &&
13367             stat != TNG_CRITICAL &&
13368             block->id != block_id &&
13369             (is_particle_data != TNG_TRUE || block->id != TNG_PARTICLE_MAPPING) &&
13370             block->id != TNG_TRAJECTORY_FRAME_SET &&
13371             block->id != -1)
13372     {
13373         fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
13374         file_pos = ftello(tng_data->output_file);
13375         if(file_pos < output_file_len)
13376         {
13377             stat = tng_block_header_read(tng_data, block);
13378         }
13379     }
13380     if(stat == TNG_CRITICAL)
13381     {
13382         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13383                file_pos, __FILE__, __LINE__);
13384         tng_block_destroy(&block);
13385         tng_data->input_file = temp;
13386         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13387         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13388         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13389         return(stat);
13390     }
13391
13392     contents_size = block->block_contents_size;
13393     header_size = block->header_contents_size;
13394
13395     header_pos = ftello(tng_data->output_file) - header_size;
13396     frame_set = &tng_data->current_trajectory_frame_set;
13397
13398     if(tng_file_input_numerical(tng_data, &datatype,
13399                                  sizeof(datatype),
13400                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13401     {
13402         tng_block_destroy(&block);
13403         return(TNG_CRITICAL);
13404     }
13405     if(tng_file_input_numerical(tng_data, &dependency,
13406                                  sizeof(dependency),
13407                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13408     {
13409         tng_block_destroy(&block);
13410         return(TNG_CRITICAL);
13411     }
13412     data.datatype = datatype;
13413
13414     if(!(dependency & TNG_FRAME_DEPENDENT) ||
13415        (is_particle_data == TNG_FALSE && dependency & TNG_PARTICLE_DEPENDENT) ||
13416        (is_particle_data == TNG_TRUE && !(dependency & TNG_PARTICLE_DEPENDENT)))
13417     {
13418         tng_block_destroy(&block);
13419         tng_data->input_file = temp;
13420
13421         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13422         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13423         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13424         return(TNG_FAILURE);
13425     }
13426
13427     if(tng_file_input_numerical(tng_data, &sparse_data,
13428                                  sizeof(sparse_data),
13429                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13430     {
13431         tng_block_destroy(&block);
13432         return(TNG_CRITICAL);
13433     }
13434
13435     if(tng_file_input_numerical(tng_data, &data.n_values_per_frame,
13436                                  sizeof(data.n_values_per_frame),
13437                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13438     {
13439         tng_block_destroy(&block);
13440         return(TNG_CRITICAL);
13441     }
13442
13443     if(tng_file_input_numerical(tng_data, &data.codec_id,
13444                                  sizeof(data.codec_id),
13445                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13446     {
13447         tng_block_destroy(&block);
13448         return(TNG_CRITICAL);
13449     }
13450
13451     if(data.codec_id != TNG_UNCOMPRESSED)
13452     {
13453         if(tng_file_input_numerical(tng_data, &data.compression_multiplier,
13454                                      sizeof(data.compression_multiplier),
13455                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13456         {
13457             tng_block_destroy(&block);
13458             return(TNG_CRITICAL);
13459         }
13460     }
13461     else
13462     {
13463         data.compression_multiplier = 1;
13464     }
13465
13466     if(sparse_data)
13467     {
13468         if(tng_file_input_numerical(tng_data, &data.first_frame_with_data,
13469                                      sizeof(data.first_frame_with_data),
13470                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13471         {
13472             tng_block_destroy(&block);
13473             return(TNG_CRITICAL);
13474         }
13475
13476         if(tng_file_input_numerical(tng_data, &data.stride_length,
13477                                      sizeof(data.stride_length),
13478                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13479         {
13480             tng_block_destroy(&block);
13481             return(TNG_CRITICAL);
13482         }
13483     }
13484     else
13485     {
13486         data.first_frame_with_data = 0;
13487         data.stride_length = 1;
13488     }
13489     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
13490
13491     if(is_particle_data == TNG_TRUE)
13492     {
13493         if(tng_file_input_numerical(tng_data, &num_first_particle,
13494                                      sizeof(num_first_particle),
13495                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13496         {
13497             tng_block_destroy(&block);
13498             return(TNG_CRITICAL);
13499         }
13500
13501         if(tng_file_input_numerical(tng_data, &block_n_particles,
13502                                      sizeof(block_n_particles),
13503                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13504         {
13505             tng_block_destroy(&block);
13506             return(TNG_CRITICAL);
13507         }
13508     }
13509
13510     tng_data->input_file = temp;
13511
13512     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13513     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13514     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13515
13516     switch(data.datatype)
13517     {
13518         case(TNG_INT_DATA):
13519             size = sizeof(int64_t);
13520             break;
13521         case(TNG_FLOAT_DATA):
13522             size = sizeof(float);
13523             break;
13524         case(TNG_DOUBLE_DATA):
13525             size = sizeof(double);
13526             break;
13527         default:
13528             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
13529                    __LINE__);
13530             tng_block_destroy(&block);
13531             return(TNG_FAILURE);
13532     }
13533
13534     n_values_per_frame = data.n_values_per_frame;
13535
13536     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
13537                                data.first_frame_with_data)) /
13538                 data.stride_length;
13539     if(is_particle_data == TNG_TRUE)
13540     {
13541         file_pos *= block_n_particles * size * n_values_per_frame;
13542     }
13543     else
13544     {
13545         file_pos *= size * n_values_per_frame;
13546     }
13547
13548     if(file_pos > contents_size)
13549     {
13550         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
13551                __LINE__);
13552         tng_block_destroy(&block);
13553         return(TNG_FAILURE);
13554     }
13555
13556     fseeko(tng_data->output_file, file_pos, SEEK_CUR);
13557
13558     if(is_particle_data == TNG_TRUE)
13559     {
13560         write_n_particles = val_n_particles;
13561     }
13562     else
13563     {
13564         write_n_particles = 1;
13565     }
13566
13567     /* If the endianness is not big endian the data needs to be swapped */
13568     if((data.datatype == TNG_INT_DATA ||
13569         data.datatype == TNG_DOUBLE_DATA) &&
13570        tng_data->output_endianness_swap_func_64)
13571     {
13572         copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
13573         memcpy(copy, values, write_n_particles * n_values_per_frame * size);
13574         for(i = 0; i < write_n_particles * n_values_per_frame; i++)
13575         {
13576             if(tng_data->output_endianness_swap_func_64(tng_data,
13577                 (uint64_t *) copy+i)
13578                 != TNG_SUCCESS)
13579             {
13580                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13581                         __FILE__, __LINE__);
13582             }
13583         }
13584         fwrite(copy, write_n_particles * n_values_per_frame, size,
13585                tng_data->output_file);
13586         free(copy);
13587     }
13588     else if(data.datatype == TNG_FLOAT_DATA &&
13589             tng_data->output_endianness_swap_func_32)
13590     {
13591         copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
13592         memcpy(copy, values, write_n_particles * n_values_per_frame * size);
13593         for(i = 0; i < write_n_particles * n_values_per_frame; i++)
13594         {
13595             if(tng_data->output_endianness_swap_func_32(tng_data,
13596                 (uint32_t *) copy+i)
13597                 != TNG_SUCCESS)
13598             {
13599                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13600                         __FILE__, __LINE__);
13601             }
13602         }
13603         fwrite(copy, write_n_particles * n_values_per_frame, size,
13604                tng_data->output_file);
13605         free(copy);
13606     }
13607
13608     else
13609     {
13610         fwrite(values, write_n_particles * n_values_per_frame, size, tng_data->output_file);
13611     }
13612
13613     fflush(tng_data->output_file);
13614
13615     /* Update the number of written frames in the frame set. */
13616     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
13617     {
13618         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
13619     }
13620
13621     /* If the last frame has been written update the hash */
13622     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
13623        data.first_frame_with_data) >=
13624        frame_set->n_frames)
13625     {
13626         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
13627                             header_size);
13628     }
13629
13630     tng_block_destroy(&block);
13631
13632     return(TNG_SUCCESS);
13633 }
13634
13635 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
13636                 (const tng_trajectory_t tng_data,
13637                  const int64_t frame_nr,
13638                  const int64_t block_id,
13639                  const void *values,
13640                  const char hash_mode)
13641 {
13642     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13643     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13644     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13645
13646     /* This is now just calling the generic data writing function. This
13647      * function must keep its signature to let the API be backwards
13648      * compatible. */
13649     return(tng_frame_gen_data_write(tng_data, frame_nr, block_id,
13650                                     TNG_FALSE, 0, 0, values, hash_mode));
13651 }
13652
13653 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
13654                 (const tng_trajectory_t tng_data,
13655                  const int64_t frame_nr,
13656                  const int64_t block_id,
13657                  const int64_t val_first_particle,
13658                  const int64_t val_n_particles,
13659                  const void *values,
13660                  const char hash_mode)
13661 {
13662     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13663     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13664     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13665     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
13666     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
13667
13668     /* This is now just calling the generic data writing function. This
13669      * function must keep its signature to let the API be backwards
13670      * compatible. */
13671     return(tng_frame_gen_data_write(tng_data, frame_nr, block_id,
13672                                     TNG_TRUE, val_first_particle, val_n_particles,
13673                                     values, hash_mode));
13674 }
13675
13676 static tng_function_status tng_data_values_alloc
13677                 (const tng_trajectory_t tng_data,
13678                  union data_values ***values,
13679                  const int64_t n_frames,
13680                  const int64_t n_values_per_frame,
13681                  const char type)
13682 {
13683     int64_t i;
13684     tng_function_status stat;
13685
13686     if(n_frames <= 0 || n_values_per_frame <= 0)
13687     {
13688         return(TNG_FAILURE);
13689     }
13690
13691     if(*values)
13692     {
13693         stat = tng_data_values_free(tng_data, *values, n_frames,
13694                                     n_values_per_frame,
13695                                     type);
13696         if(stat != TNG_SUCCESS)
13697         {
13698             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
13699                    __FILE__, __LINE__);
13700             return(stat);
13701         }
13702     }
13703     *values = (union data_values **)malloc(sizeof(union data_values *) * n_frames);
13704     if(!*values)
13705     {
13706         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13707                 __FILE__, __LINE__);
13708         return(TNG_CRITICAL);
13709
13710     }
13711
13712     for(i = 0; i < n_frames; i++)
13713     {
13714         (*values)[i] = (union data_values *)malloc(sizeof(union data_values) *
13715                            n_values_per_frame);
13716         if(!(*values)[i])
13717         {
13718             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13719                     __FILE__, __LINE__);
13720             free(values);
13721             values = 0;
13722             return(TNG_CRITICAL);
13723         }
13724     }
13725     return(TNG_SUCCESS);
13726 }
13727
13728 /* FIXME: This needs ***values */
13729 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
13730                 (const tng_trajectory_t tng_data,
13731                  union data_values **values,
13732                  const int64_t n_frames,
13733                  const int64_t n_values_per_frame,
13734                  const char type)
13735 {
13736     int64_t i, j;
13737     (void)tng_data;
13738
13739     if(values)
13740     {
13741         for(i = 0; i < n_frames; i++)
13742         {
13743             if(values[i])
13744             {
13745                 if(type == TNG_CHAR_DATA)
13746                 {
13747                     for(j = 0; j < n_values_per_frame; j++)
13748                     {
13749                         if(values[i][j].c)
13750                         {
13751                             free(values[i][j].c);
13752                             values[i][j].c = 0;
13753                         }
13754                     }
13755                 }
13756                 free(values[i]);
13757                 values[i] = 0;
13758             }
13759         }
13760         free(values);
13761         values = 0;
13762     }
13763
13764     return(TNG_SUCCESS);
13765 }
13766
13767 static tng_function_status tng_particle_data_values_alloc
13768                 (const tng_trajectory_t tng_data,
13769                  union data_values ****values,
13770                  const int64_t n_frames,
13771                  const int64_t n_particles,
13772                  const int64_t n_values_per_frame,
13773                  const char type)
13774 {
13775     int64_t i, j;
13776     tng_function_status stat;
13777
13778     if(n_particles == 0 || n_values_per_frame == 0)
13779     {
13780         return(TNG_FAILURE);
13781     }
13782
13783     if(*values)
13784     {
13785         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
13786                                              n_particles, n_values_per_frame,
13787                                              type);
13788         if(stat != TNG_SUCCESS)
13789         {
13790             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
13791                    __FILE__, __LINE__);
13792             return(stat);
13793         }
13794     }
13795     *values = (union data_values ***)malloc(sizeof(union data_values **) * n_frames);
13796     if(!*values)
13797     {
13798         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13799                 __FILE__, __LINE__);
13800         return(TNG_CRITICAL);
13801
13802     }
13803
13804     for(i = 0; i < n_frames; i++)
13805     {
13806         (*values)[i] = (union data_values **)malloc(sizeof(union data_values *) *
13807                            n_particles);
13808         if(!(*values)[i])
13809         {
13810             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13811                     __FILE__, __LINE__);
13812             free(*values);
13813             *values = 0;
13814             return(TNG_CRITICAL);
13815         }
13816         for(j = 0; j < n_particles; j++)
13817         {
13818             (*values)[i][j] = (union data_values *)malloc(sizeof(union data_values) *
13819                                   n_values_per_frame);
13820             if(!(*values)[i][j])
13821             {
13822                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13823                         __FILE__, __LINE__);
13824                 tng_particle_data_values_free(tng_data, *values, n_frames,
13825                                               n_particles, n_values_per_frame,
13826                                               type);
13827                 *values = 0;
13828                 return(TNG_CRITICAL);
13829             }
13830         }
13831     }
13832     return(TNG_SUCCESS);
13833 }
13834
13835 /* FIXME: This needs ****values */
13836 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
13837                 (const tng_trajectory_t tng_data,
13838                  union data_values ***values,
13839                  const int64_t n_frames,
13840                  const int64_t n_particles,
13841                  const int64_t n_values_per_frame,
13842                  const char type)
13843 {
13844     int64_t i, j, k;
13845     (void)tng_data;
13846
13847     if(values)
13848     {
13849         for(i = 0; i < n_frames; i++)
13850         {
13851             if(values[i])
13852             {
13853                 for(j = 0; j < n_particles; j++)
13854                 {
13855                     if(type == TNG_CHAR_DATA)
13856                     {
13857                         for(k = 0; k < n_values_per_frame; k++)
13858                         {
13859                             if(values[i][j][k].c)
13860                             {
13861                                 free(values[i][j][k].c);
13862                                 values[i][j][k].c = 0;
13863                             }
13864                         }
13865                     }
13866                     free(values[i][j]);
13867                     values[i][j] = 0;
13868                 }
13869                 free(values[i]);
13870                 values[i] = 0;
13871             }
13872         }
13873         free(values);
13874         values = 0;
13875     }
13876
13877     return(TNG_SUCCESS);
13878 }
13879
13880 static tng_function_status tng_gen_data_get
13881                 (const tng_trajectory_t tng_data,
13882                  const int64_t block_id,
13883                  const tng_bool is_particle_data,
13884                  union data_values ****values,
13885                  int64_t *n_frames,
13886                  int64_t *n_particles,
13887                  int64_t *n_values_per_frame,
13888                  char *type)
13889 {
13890     int64_t i, j, k, mapping, file_pos, i_step, block_index;
13891     int size;
13892     size_t len;
13893     tng_data_t data;
13894     tng_trajectory_frame_set_t frame_set;
13895     tng_gen_block_t block;
13896     char block_type_flag;
13897     tng_function_status stat;
13898
13899     frame_set = &tng_data->current_trajectory_frame_set;
13900
13901     block_index = -1;
13902     data = 0;
13903
13904     if(is_particle_data == TNG_TRUE)
13905     {
13906         stat = tng_particle_data_find(tng_data, block_id, &data);
13907     }
13908     else
13909     {
13910         stat = tng_data_find(tng_data, block_id, &data);
13911     }
13912
13913     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
13914     {
13915         block_type_flag = TNG_TRAJECTORY_BLOCK;
13916     }
13917     else
13918     {
13919         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
13920     }
13921
13922     if(stat != TNG_SUCCESS)
13923     {
13924         tng_block_init(&block);
13925         file_pos = ftello(tng_data->input_file);
13926         /* Read all blocks until next frame set block */
13927         stat = tng_block_header_read(tng_data, block);
13928         while(file_pos < tng_data->input_file_len &&
13929                 stat != TNG_CRITICAL &&
13930                 block->id != TNG_TRAJECTORY_FRAME_SET &&
13931                 block->id != -1)
13932         {
13933             /* Use hash by default */
13934             stat = tng_block_read_next(tng_data, block,
13935                                     TNG_USE_HASH);
13936             if(stat != TNG_CRITICAL)
13937             {
13938                 file_pos = ftello(tng_data->input_file);
13939                 if(file_pos < tng_data->input_file_len)
13940                 {
13941                     stat = tng_block_header_read(tng_data, block);
13942                 }
13943             }
13944         }
13945         tng_block_destroy(&block);
13946         if(stat == TNG_CRITICAL)
13947         {
13948             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13949                     file_pos, __FILE__, __LINE__);
13950             return(stat);
13951         }
13952
13953         if(is_particle_data == TNG_TRUE)
13954         {
13955             for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13956             {
13957                 data = &frame_set->tr_particle_data[i];
13958                 if(data->block_id == block_id)
13959                 {
13960                     block_index = i;
13961                     block_type_flag = TNG_TRAJECTORY_BLOCK;
13962                     break;
13963                 }
13964             }
13965         }
13966         else
13967         {
13968             for(i = 0; i < frame_set->n_data_blocks; i++)
13969             {
13970                 data = &frame_set->tr_data[i];
13971                 if(data->block_id == block_id)
13972                 {
13973                     block_index = i;
13974                     break;
13975                 }
13976             }
13977         }
13978         if(block_index < 0)
13979         {
13980             return(TNG_FAILURE);
13981         }
13982     }
13983
13984     if(is_particle_data == TNG_TRUE)
13985     {
13986         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
13987            tng_data->var_num_atoms_flag)
13988         {
13989             *n_particles = frame_set->n_particles;
13990         }
13991         else
13992         {
13993             *n_particles = tng_data->n_particles;
13994         }
13995     }
13996
13997     *n_frames = tng_max_i64(1, data->n_frames);
13998     *n_values_per_frame = data->n_values_per_frame;
13999     *type = data->datatype;
14000
14001     if(is_particle_data == TNG_TRUE)
14002     {
14003         if(*values == 0)
14004         {
14005             if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
14006                                              *n_particles, *n_values_per_frame,
14007                                              *type) != TNG_SUCCESS)
14008             {
14009                 return(TNG_CRITICAL);
14010             }
14011         }
14012
14013         i_step = (*n_particles) * (*n_values_per_frame);
14014
14015         /* It's not very elegant to reuse so much of the code in the different case
14016          * statements, but it's unnecessarily slow to have the switch-case block
14017          * inside the for loops. */
14018         switch(*type)
14019         {
14020         case TNG_CHAR_DATA:
14021             for(i = 0; i < *n_frames; i++)
14022             {
14023                 for(j = 0; j < *n_particles; j++)
14024                 {
14025                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14026                     for(k = 0; k < *n_values_per_frame; k++)
14027                     {
14028                         len = strlen(data->strings[i][j][k]) + 1;
14029                         (*values)[i][mapping][k].c = (char *)malloc(len);
14030                         strncpy((*values)[i][mapping][k].c,
14031                                 data->strings[i][j][k], len);
14032                     }
14033                 }
14034             }
14035             break;
14036         case TNG_INT_DATA:
14037             size = sizeof(int);
14038             for(i = 0; i < *n_frames; i++)
14039             {
14040                 for(j = 0; j < *n_particles; j++)
14041                 {
14042                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14043                     for(k = 0; k < *n_values_per_frame; k++)
14044                     {
14045                         (*values)[i][mapping][k].i = *(int *)
14046                                                      ((char *)data->values + size *
14047                                                      (i * i_step + j *
14048                                                       (*n_values_per_frame) + k));
14049                     }
14050                 }
14051             }
14052             break;
14053         case TNG_FLOAT_DATA:
14054             size = sizeof(float);
14055             for(i = 0; i < *n_frames; i++)
14056             {
14057                 for(j = 0; j < *n_particles; j++)
14058                 {
14059                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14060                     for(k = 0; k < *n_values_per_frame; k++)
14061                     {
14062                         (*values)[i][mapping][k].f = *(float *)
14063                                                      ((char *)data->values + size *
14064                                                      (i * i_step + j *
14065                                                       (*n_values_per_frame) + k));
14066                     }
14067                 }
14068             }
14069             break;
14070         case TNG_DOUBLE_DATA:
14071         default:
14072             size = sizeof(double);
14073             for(i = 0; i < *n_frames; i++)
14074             {
14075                 for(j = 0; j < *n_particles; j++)
14076                 {
14077                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14078                     for(k = 0; k < *n_values_per_frame; k++)
14079                     {
14080                         (*values)[i][mapping][k].d = *(double *)
14081                                                      ((char *)data->values + size *
14082                                                      (i * i_step + j *
14083                                                       (*n_values_per_frame) + k));
14084                     }
14085                 }
14086             }
14087         }
14088     }
14089     else
14090     {
14091         if(*(values[0]) == 0)
14092         {
14093             if(tng_data_values_alloc(tng_data, values[0], *n_frames,
14094                                      *n_values_per_frame,
14095                                      *type) != TNG_SUCCESS)
14096             {
14097                 return(TNG_CRITICAL);
14098             }
14099         }
14100         switch(*type)
14101         {
14102         case TNG_CHAR_DATA:
14103             for(i = 0; i < *n_frames; i++)
14104             {
14105                 for(j = 0; j < *n_values_per_frame; j++)
14106                 {
14107                     len = strlen(data->strings[0][i][j]) + 1;
14108                     (*values)[0][i][j].c = (char *)malloc(len);
14109                     strncpy((*values)[0][i][j].c, data->strings[0][i][j], len);
14110                 }
14111             }
14112             break;
14113         case TNG_INT_DATA:
14114             size = sizeof(int);
14115             for(i = 0; i < *n_frames; i++)
14116             {
14117                 for(j = 0; j < *n_values_per_frame; j++)
14118                 {
14119                     (*values)[0][i][j].i = *(int *)((char *)data->values + size *
14120                                                     (i*(*n_values_per_frame) + j));
14121                 }
14122             }
14123             break;
14124         case TNG_FLOAT_DATA:
14125             size = sizeof(float);
14126             for(i = 0; i < *n_frames; i++)
14127             {
14128                 for(j = 0; j < *n_values_per_frame; j++)
14129                 {
14130                     (*values)[0][i][j].f = *(float *)((char *)data->values + size *
14131                                                    (i*(*n_values_per_frame) + j));
14132                 }
14133             }
14134             break;
14135         case TNG_DOUBLE_DATA:
14136         default:
14137             size = sizeof(double);
14138             for(i = 0; i < *n_frames; i++)
14139             {
14140                 for(j = 0; j < *n_values_per_frame; j++)
14141                 {
14142                     (*values)[0][i][j].d = *(double *)((char *)data->values + size *
14143                                                        (i*(*n_values_per_frame) + j));
14144                 }
14145             }
14146         }
14147     }
14148
14149     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14150
14151     return(TNG_SUCCESS);
14152 }
14153
14154 tng_function_status DECLSPECDLLEXPORT tng_data_get
14155                 (const tng_trajectory_t tng_data,
14156                  const int64_t block_id,
14157                  union data_values ***values,
14158                  int64_t *n_frames,
14159                  int64_t *n_values_per_frame,
14160                  char *type)
14161 {
14162     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14163     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14164     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14165     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14166
14167     return(tng_gen_data_get(tng_data, block_id, TNG_FALSE, &values, n_frames, 0,
14168                             n_values_per_frame, type));
14169 }
14170
14171 static tng_function_status tng_gen_data_vector_get
14172                 (const tng_trajectory_t tng_data,
14173                  const int64_t block_id,
14174                  const tng_bool is_particle_data,
14175                  void **values,
14176                  int64_t *n_frames,
14177                  int64_t *stride_length,
14178                  int64_t *n_particles,
14179                  int64_t *n_values_per_frame,
14180                  char *type)
14181 {
14182     int64_t i, j, mapping, file_pos, i_step, full_data_len, n_frames_div;
14183     int64_t block_index;
14184     int size;
14185     tng_data_t data;
14186     tng_trajectory_frame_set_t frame_set;
14187     tng_gen_block_t block;
14188     void *temp;
14189     char block_type_flag;
14190     tng_function_status stat;
14191
14192     frame_set = &tng_data->current_trajectory_frame_set;
14193
14194     block_index = -1;
14195     data = 0;
14196
14197     if(is_particle_data == TNG_TRUE)
14198     {
14199         stat = tng_particle_data_find(tng_data, block_id, &data);
14200     }
14201     else
14202     {
14203         stat = tng_data_find(tng_data, block_id, &data);
14204     }
14205
14206     if(stat != TNG_SUCCESS)
14207     {
14208         tng_block_init(&block);
14209         file_pos = ftello(tng_data->input_file);
14210         /* Read all blocks until next frame set block */
14211         stat = tng_block_header_read(tng_data, block);
14212         while(file_pos < tng_data->input_file_len &&
14213                 stat != TNG_CRITICAL &&
14214                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14215                 block->id != -1)
14216         {
14217             /* Use hash by default */
14218             stat = tng_block_read_next(tng_data, block,
14219                                     TNG_USE_HASH);
14220             if(stat != TNG_CRITICAL)
14221             {
14222                 file_pos = ftello(tng_data->input_file);
14223                 if(file_pos < tng_data->input_file_len)
14224                 {
14225                     stat = tng_block_header_read(tng_data, block);
14226                 }
14227             }
14228         }
14229         tng_block_destroy(&block);
14230         if(stat == TNG_CRITICAL)
14231         {
14232             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
14233                     file_pos, __FILE__, __LINE__);
14234             return(stat);
14235         }
14236
14237         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
14238         {
14239             data = &frame_set->tr_particle_data[i];
14240             if(data->block_id == block_id)
14241             {
14242                 block_index = i;
14243                 break;
14244             }
14245         }
14246         if(block_index < 0)
14247         {
14248             return(TNG_FAILURE);
14249         }
14250     }
14251
14252     if(is_particle_data == TNG_TRUE)
14253     {
14254         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
14255         {
14256             block_type_flag = TNG_TRAJECTORY_BLOCK;
14257         }
14258         else
14259         {
14260             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
14261         }
14262
14263        if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
14264           tng_data->var_num_atoms_flag)
14265         {
14266             *n_particles = frame_set->n_particles;
14267         }
14268         else
14269         {
14270             *n_particles = tng_data->n_particles;
14271         }
14272     }
14273
14274     *type = data->datatype;
14275
14276     switch(*type)
14277     {
14278     case TNG_CHAR_DATA:
14279         return(TNG_FAILURE);
14280     case TNG_INT_DATA:
14281         size = sizeof(int64_t);
14282         break;
14283     case TNG_FLOAT_DATA:
14284         size = sizeof(float);
14285         break;
14286     case TNG_DOUBLE_DATA:
14287     default:
14288         size = sizeof(double);
14289     }
14290
14291     *n_frames = tng_max_i64(1, data->n_frames);
14292     *n_values_per_frame = data->n_values_per_frame;
14293     *stride_length = data->stride_length;
14294
14295     n_frames_div = (*n_frames % *stride_length) ?
14296                    *n_frames / *stride_length + 1:
14297                    *n_frames / *stride_length;
14298
14299     full_data_len = n_frames_div * size *
14300                 (*n_values_per_frame);
14301     if(is_particle_data == TNG_TRUE)
14302     {
14303         full_data_len *= (*n_particles);
14304     }
14305
14306     temp = (char *)realloc(*values, full_data_len);
14307     if(!temp)
14308     {
14309         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
14310                 __FILE__, __LINE__);
14311         free(*values);
14312         *values = 0;
14313         return(TNG_CRITICAL);
14314     }
14315
14316     *values = temp;
14317
14318     if(is_particle_data != TNG_TRUE || frame_set->n_mapping_blocks <= 0)
14319     {
14320         memcpy(*values, data->values, full_data_len);
14321     }
14322     else
14323     {
14324         i_step = (*n_particles) * (*n_values_per_frame);
14325         for(i = 0; i < *n_frames; i++)
14326         {
14327             for(j = 0; j < *n_particles; j++)
14328             {
14329                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14330                 memcpy(((char *)*values) + size * (i * i_step + mapping *
14331                        (*n_values_per_frame)),
14332                        (char *)data->values + size *
14333                        (i * i_step + j * (*n_values_per_frame)),
14334                        size * (*n_values_per_frame));
14335             }
14336         }
14337     }
14338
14339     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14340
14341     return(TNG_SUCCESS);
14342 }
14343
14344 tng_function_status DECLSPECDLLEXPORT tng_data_vector_get
14345                 (const tng_trajectory_t tng_data,
14346                  const int64_t block_id,
14347                  void **values,
14348                  int64_t *n_frames,
14349                  int64_t *stride_length,
14350                  int64_t *n_values_per_frame,
14351                  char *type)
14352 {
14353     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14354     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14355     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14356     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14357     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14358
14359     return(tng_gen_data_vector_get(tng_data, block_id, TNG_FALSE, values,
14360                                    n_frames, stride_length, 0, n_values_per_frame,
14361                                    type));
14362 }
14363
14364 static tng_function_status tng_gen_data_interval_get
14365                 (const tng_trajectory_t tng_data,
14366                  const int64_t block_id,
14367                  const tng_bool is_particle_data,
14368                  const int64_t start_frame_nr,
14369                  const int64_t end_frame_nr,
14370                  const char hash_mode,
14371                  union data_values ****values,
14372                  int64_t *n_particles,
14373                  int64_t *n_values_per_frame,
14374                  char *type)
14375 {
14376     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
14377     int64_t first_frame, block_index;
14378     int size;
14379     size_t len;
14380     tng_data_t data;
14381     tng_trajectory_frame_set_t frame_set;
14382     tng_gen_block_t block;
14383     char block_type_flag;
14384     tng_function_status stat;
14385
14386     block_index = -1;
14387
14388     frame_set = &tng_data->current_trajectory_frame_set;
14389     first_frame = frame_set->first_frame;
14390
14391     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14392     if(stat != TNG_SUCCESS)
14393     {
14394         return(stat);
14395     }
14396
14397     /* Do not re-read the frame set. */
14398     if((is_particle_data == TNG_TRUE &&
14399        (first_frame != frame_set->first_frame ||
14400         frame_set->n_particle_data_blocks <= 0)) ||
14401        (is_particle_data == TNG_FALSE &&
14402        (first_frame != frame_set->first_frame ||
14403         frame_set->n_data_blocks <= 0)))
14404     {
14405         tng_block_init(&block);
14406         file_pos = ftello(tng_data->input_file);
14407         /* Read all blocks until next frame set block */
14408         stat = tng_block_header_read(tng_data, block);
14409         while(file_pos < tng_data->input_file_len &&
14410                 stat != TNG_CRITICAL &&
14411                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14412                 block->id != -1)
14413         {
14414             stat = tng_block_read_next(tng_data, block,
14415                                     hash_mode);
14416             if(stat != TNG_CRITICAL)
14417             {
14418                 file_pos = ftello(tng_data->input_file);
14419                 if(file_pos < tng_data->input_file_len)
14420                 {
14421                     stat = tng_block_header_read(tng_data, block);
14422                 }
14423             }
14424         }
14425         tng_block_destroy(&block);
14426         if(stat == TNG_CRITICAL)
14427         {
14428             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
14429                     file_pos, __FILE__, __LINE__);
14430             return(stat);
14431         }
14432     }
14433
14434     /* See if there is already a data block of this ID.
14435      * Start checking the last read frame set */
14436     if(is_particle_data == TNG_TRUE)
14437     {
14438         for(i = frame_set->n_particle_data_blocks; i-- ;)
14439         {
14440             data = &frame_set->tr_particle_data[i];
14441             if(data->block_id == block_id)
14442             {
14443                 block_index = i;
14444                 block_type_flag = TNG_TRAJECTORY_BLOCK;
14445                 break;
14446             }
14447         }
14448     }
14449     else
14450     {
14451         for(i = 0; i < frame_set->n_data_blocks; i++)
14452         {
14453             data = &frame_set->tr_data[i];
14454             if(data->block_id == block_id)
14455             {
14456                 block_index = i;
14457                 break;
14458             }
14459         }
14460     }
14461
14462     if(block_index < 0)
14463     {
14464         fprintf(stderr, "TNG library: Could not find particle data block with id %" PRId64 ". %s: %d\n",
14465                 block_id, __FILE__, __LINE__);
14466         return(TNG_FAILURE);
14467     }
14468
14469     if(is_particle_data ==  TNG_TRUE)
14470     {
14471         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
14472            tng_data->var_num_atoms_flag)
14473         {
14474             *n_particles = frame_set->n_particles;
14475         }
14476         else
14477         {
14478             *n_particles = tng_data->n_particles;
14479         }
14480     }
14481
14482     n_frames = end_frame_nr - start_frame_nr + 1;
14483     *n_values_per_frame = data->n_values_per_frame;
14484     *type = data->datatype;
14485
14486     if(*values == 0)
14487     {
14488         if(is_particle_data == TNG_TRUE)
14489         {
14490             if(tng_particle_data_values_alloc(tng_data, values, n_frames,
14491                                              *n_particles, *n_values_per_frame,
14492                                              *type) != TNG_SUCCESS)
14493             {
14494                 return(TNG_CRITICAL);
14495             }
14496         }
14497         else
14498         {
14499             if(tng_data_values_alloc(tng_data, *values, n_frames,
14500                                      *n_values_per_frame,
14501                                      *type) != TNG_SUCCESS)
14502             {
14503                 return(TNG_CRITICAL);
14504             }
14505         }
14506     }
14507
14508     current_frame_pos = start_frame_nr - frame_set->first_frame;
14509
14510     if(is_particle_data == TNG_TRUE)
14511     {
14512         i_step = (*n_particles) * (*n_values_per_frame);
14513     }
14514     else
14515     {
14516         i_step = (*n_values_per_frame);
14517     }
14518     /* It's not very elegant to reuse so much of the code in the different case
14519      * statements, but it's unnecessarily slow to have the switch-case block
14520      * inside the for loops. */
14521     switch(*type)
14522     {
14523     case TNG_CHAR_DATA:
14524         for(i=0; i<n_frames; i++)
14525         {
14526             if(current_frame_pos == frame_set->n_frames)
14527             {
14528                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14529                 if(stat != TNG_SUCCESS)
14530                 {
14531                     return(stat);
14532                 }
14533                 current_frame_pos = 0;
14534             }
14535             if(is_particle_data == TNG_TRUE)
14536             {
14537                 for(j = 0; j < *n_particles; j++)
14538                 {
14539                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14540                     for(k = 0; k < *n_values_per_frame; k++)
14541                     {
14542                         len = strlen(data->strings[current_frame_pos][j][k]) + 1;
14543                         (*values)[i][mapping][k].c = (char *)malloc(len);
14544                         strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
14545                     }
14546                 }
14547             }
14548             else
14549             {
14550                 for(j = 0; j < *n_values_per_frame; j++)
14551                 {
14552                     len = strlen(data->strings[0][current_frame_pos][j]) + 1;
14553                     (*values)[0][i][j].c = (char *)malloc(len);
14554                     strncpy((*values)[0][i][j].c, data->strings[0][current_frame_pos][j], len);
14555                 }
14556             }
14557             current_frame_pos++;
14558         }
14559         break;
14560     case TNG_INT_DATA:
14561         size = sizeof(int);
14562         for(i=0; i<n_frames; i++)
14563         {
14564             if(current_frame_pos == frame_set->n_frames)
14565             {
14566                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14567                 if(stat != TNG_SUCCESS)
14568                 {
14569                     return(stat);
14570                 }
14571                 current_frame_pos = 0;
14572             }
14573             if(is_particle_data == TNG_TRUE)
14574             {
14575                 for(j = 0; j < *n_particles; j++)
14576                 {
14577                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14578                     for(k = 0; k < *n_values_per_frame; k++)
14579                     {
14580                         (*values)[i][mapping][k].i = *(int *)
14581                                                      ((char *)data->values + size *
14582                                                       (current_frame_pos *
14583                                                        i_step + j *
14584                                                        (*n_values_per_frame) + k));
14585                     }
14586                 }
14587                 current_frame_pos++;
14588             }
14589             else
14590             {
14591                 for(j = 0; j < *n_values_per_frame; j++)
14592                 {
14593                     (*values)[0][i][j].i = *(int *)((char *)data->values + size *
14594                                                 (current_frame_pos *
14595                                                  i_step + j));
14596                 }
14597             }
14598         }
14599         break;
14600     case TNG_FLOAT_DATA:
14601         size = sizeof(float);
14602         for(i=0; i<n_frames; i++)
14603         {
14604             if(current_frame_pos == frame_set->n_frames)
14605             {
14606                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14607                 if(stat != TNG_SUCCESS)
14608                 {
14609                     return(stat);
14610                 }
14611                 current_frame_pos = 0;
14612             }
14613             if(is_particle_data == TNG_TRUE)
14614             {
14615                 for(j=0; j<*n_particles; j++)
14616                 {
14617                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14618                     for(k=0; k<*n_values_per_frame; k++)
14619                     {
14620                         (*values)[i][mapping][k].f = *(float *)
14621                                                      ((char *)data->values + size *
14622                                                       (current_frame_pos *
14623                                                        i_step + j *
14624                                                        (*n_values_per_frame) + k));
14625                     }
14626                 }
14627             }
14628             else
14629             {
14630                 for(j = 0; j < *n_values_per_frame; j++)
14631                 {
14632                     (*values)[0][i][j].f = *(float *)((char *)data->values + size *
14633                                                    (current_frame_pos *
14634                                                     i_step + j));
14635                 }
14636             }
14637             current_frame_pos++;
14638         }
14639         break;
14640     case TNG_DOUBLE_DATA:
14641     default:
14642         size = sizeof(double);
14643         for(i=0; i<n_frames; i++)
14644         {
14645             if(current_frame_pos == frame_set->n_frames)
14646             {
14647                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14648                 if(stat != TNG_SUCCESS)
14649                 {
14650                     return(stat);
14651                 }
14652                 current_frame_pos = 0;
14653             }
14654             if(is_particle_data == TNG_TRUE)
14655             {
14656                 for(j=0; j<*n_particles; j++)
14657                 {
14658                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14659                     for(k=0; k<*n_values_per_frame; k++)
14660                     {
14661                         (*values)[i][mapping][k].d = *(double *)
14662                                                      ((char *)data->values + size *
14663                                                       (current_frame_pos *
14664                                                        i_step + j *
14665                                                        (*n_values_per_frame) + k));
14666                     }
14667                 }
14668             }
14669             else
14670             {
14671                 for(j = 0; j < *n_values_per_frame; j++)
14672                 {
14673                     (*values)[0][i][j].d = *(double *)((char *)data->values + size *
14674                                                     (current_frame_pos *
14675                                                      i_step + j));
14676                 }
14677             }
14678             current_frame_pos++;
14679         }
14680     }
14681
14682     data->last_retrieved_frame = end_frame_nr;
14683
14684     return(TNG_SUCCESS);
14685 }
14686
14687 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
14688                 (const tng_trajectory_t tng_data,
14689                  const int64_t block_id,
14690                  const int64_t start_frame_nr,
14691                  const int64_t end_frame_nr,
14692                  const char hash_mode,
14693                  union data_values ***values,
14694                  int64_t *n_values_per_frame,
14695                  char *type)
14696 {
14697     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14698     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
14699     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14700     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14701
14702     return(tng_gen_data_interval_get(tng_data, block_id, TNG_FALSE, start_frame_nr,
14703                                      end_frame_nr, hash_mode, &values, 0,
14704                                      n_values_per_frame, type));
14705 }
14706
14707 static tng_function_status tng_gen_data_vector_interval_get
14708                 (const tng_trajectory_t tng_data,
14709                  const int64_t block_id,
14710                  const tng_bool is_particle_data,
14711                  const int64_t start_frame_nr,
14712                  const int64_t end_frame_nr,
14713                  const char hash_mode,
14714                  void **values,
14715                  int64_t *n_particles,
14716                  int64_t *stride_length,
14717                  int64_t *n_values_per_frame,
14718                  char *type)
14719 {
14720     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
14721     int64_t file_pos, current_frame_pos, last_frame_pos, full_data_len, frame_size;
14722     int size;
14723     tng_trajectory_frame_set_t frame_set;
14724     tng_data_t data;
14725     tng_gen_block_t block;
14726     void *current_values = 0, *temp;
14727     tng_function_status stat;
14728
14729     frame_set = &tng_data->current_trajectory_frame_set;
14730     first_frame = frame_set->first_frame;
14731
14732     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14733     if(stat != TNG_SUCCESS)
14734     {
14735         return(stat);
14736     }
14737
14738     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
14739     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
14740     if(is_particle_data == TNG_TRUE)
14741     {
14742         stat = tng_particle_data_find(tng_data, block_id, &data);
14743     }
14744     else
14745     {
14746         stat = tng_data_find(tng_data, block_id, &data);
14747     }
14748
14749     if(first_frame != frame_set->first_frame ||
14750        stat != TNG_SUCCESS)
14751     {
14752         tng_block_init(&block);
14753         if(stat != TNG_SUCCESS)
14754         {
14755             fseeko(tng_data->input_file,
14756                   tng_data->current_trajectory_frame_set_input_file_pos,
14757                   SEEK_SET);
14758             stat = tng_block_header_read(tng_data, block);
14759             if(stat != TNG_SUCCESS)
14760             {
14761                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
14762                         __FILE__, __LINE__);
14763                 return(stat);
14764             }
14765
14766             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
14767         }
14768         file_pos = ftello(tng_data->input_file);
14769         /* Read until next frame set block */
14770         stat = tng_block_header_read(tng_data, block);
14771         while(file_pos < tng_data->input_file_len &&
14772             stat != TNG_CRITICAL &&
14773             block->id != TNG_TRAJECTORY_FRAME_SET &&
14774             block->id != -1)
14775         {
14776             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
14777             {
14778                 stat = tng_block_read_next(tng_data, block,
14779                                         hash_mode);
14780                 if(stat != TNG_CRITICAL)
14781                 {
14782                     file_pos = ftello(tng_data->input_file);
14783                     if(file_pos < tng_data->input_file_len)
14784                     {
14785                         stat = tng_block_header_read(tng_data, block);
14786                     }
14787                 }
14788             }
14789             else
14790             {
14791                 file_pos += block->block_contents_size + block->header_contents_size;
14792                 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
14793                 if(file_pos < tng_data->input_file_len)
14794                 {
14795                     stat = tng_block_header_read(tng_data, block);
14796                 }
14797             }
14798         }
14799         tng_block_destroy(&block);
14800         if(stat == TNG_CRITICAL)
14801         {
14802             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
14803                     file_pos, __FILE__, __LINE__);
14804             return(stat);
14805         }
14806     }
14807     if(is_particle_data == TNG_TRUE)
14808     {
14809         stat = tng_particle_data_find(tng_data, block_id, &data);
14810     }
14811     else
14812     {
14813         stat = tng_data_find(tng_data, block_id, &data);
14814     }
14815     if(stat != TNG_SUCCESS)
14816     {
14817         return(stat);
14818     }
14819
14820     stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data,
14821                                    &current_values, &n_frames, stride_length,
14822                                    n_particles, n_values_per_frame, type);
14823
14824     if(stat != TNG_SUCCESS || (is_particle_data && *n_particles == 0))
14825     {
14826         if(current_values)
14827         {
14828             free(current_values);
14829         }
14830         return(stat);
14831     }
14832
14833     if(n_frames == 1 && n_frames < frame_set->n_frames)
14834     {
14835         tot_n_frames = 1;
14836     }
14837     else
14838     {
14839         tot_n_frames = end_frame_nr - start_frame_nr + 1;
14840     }
14841
14842     switch(*type)
14843     {
14844     case TNG_CHAR_DATA:
14845         return(TNG_FAILURE);
14846     case TNG_INT_DATA:
14847         size = sizeof(int64_t);
14848         break;
14849     case TNG_FLOAT_DATA:
14850         size = sizeof(float);
14851         break;
14852     case TNG_DOUBLE_DATA:
14853     default:
14854         size = sizeof(double);
14855     }
14856
14857     n_frames_div = (tot_n_frames % *stride_length) ?
14858                  tot_n_frames / *stride_length + 1:
14859                  tot_n_frames / *stride_length;
14860
14861     full_data_len = n_frames_div * size * (*n_values_per_frame);
14862     if(is_particle_data)
14863     {
14864         full_data_len *= (*n_particles);
14865     }
14866
14867     temp = (char *)realloc(*values, full_data_len);
14868     if(!temp)
14869     {
14870         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
14871                 __FILE__, __LINE__);
14872         free(*values);
14873         *values = 0;
14874         return(TNG_CRITICAL);
14875     }
14876
14877     *values = temp;
14878
14879     if( n_frames == 1 && n_frames < frame_set->n_frames)
14880     {
14881         if(is_particle_data)
14882         {
14883             memcpy(*values, current_values, size * (*n_particles) *
14884                    (*n_values_per_frame));
14885         }
14886         else
14887         {
14888             memcpy(*values, current_values, size * (*n_values_per_frame));
14889         }
14890     }
14891     else
14892     {
14893         current_frame_pos = start_frame_nr - frame_set->first_frame;
14894
14895         frame_size = size * (*n_values_per_frame);
14896         if(is_particle_data)
14897         {
14898             frame_size *= (*n_particles);
14899         }
14900
14901         last_frame_pos = tng_min_i64(n_frames,
14902                                      end_frame_nr - start_frame_nr);
14903
14904         n_frames_div = current_frame_pos / *stride_length;
14905         n_frames_div_2 = (last_frame_pos % *stride_length) ?
14906                        last_frame_pos / *stride_length + 1:
14907                        last_frame_pos / *stride_length;
14908         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
14909
14910         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
14911                n_frames_div_2 * frame_size);
14912
14913         current_frame_pos += n_frames - current_frame_pos;
14914
14915         while(current_frame_pos <= end_frame_nr - start_frame_nr)
14916         {
14917             stat = tng_frame_set_read_next(tng_data, hash_mode);
14918             if(stat != TNG_SUCCESS)
14919             {
14920                 if(current_values)
14921                 {
14922                     free(current_values);
14923                 }
14924                 free(*values);
14925                 *values = 0;
14926                 return(stat);
14927             }
14928
14929             stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data,
14930                                            &current_values, &n_frames,
14931                                            stride_length, n_particles,
14932                                            n_values_per_frame, type);
14933
14934             if(stat != TNG_SUCCESS)
14935             {
14936                 if(current_values)
14937                 {
14938                     free(current_values);
14939                 }
14940                 free(*values);
14941                 *values = 0;
14942                 return(stat);
14943             }
14944
14945             last_frame_pos = tng_min_i64(n_frames,
14946                                          end_frame_nr - current_frame_pos);
14947
14948             n_frames_div = current_frame_pos / *stride_length;
14949             n_frames_div_2 = (last_frame_pos % *stride_length) ?
14950                            last_frame_pos / *stride_length + 1:
14951                            last_frame_pos / *stride_length;
14952             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
14953
14954             memcpy(((char *)*values) + n_frames_div * frame_size,
14955                    current_values,
14956                    n_frames_div_2 * frame_size);
14957
14958             current_frame_pos += n_frames;
14959         }
14960     }
14961
14962     if(current_values)
14963     {
14964         free(current_values);
14965     }
14966
14967     data->last_retrieved_frame = end_frame_nr;
14968
14969     return(TNG_SUCCESS);
14970 }
14971
14972
14973 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
14974                 (const tng_trajectory_t tng_data,
14975                  const int64_t block_id,
14976                  const int64_t start_frame_nr,
14977                  const int64_t end_frame_nr,
14978                  const char hash_mode,
14979                  void **values,
14980                  int64_t *stride_length,
14981                  int64_t *n_values_per_frame,
14982                  char *type)
14983 {
14984     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14985     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
14986     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14987     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14988     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14989
14990     return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_FALSE,
14991                                             start_frame_nr, end_frame_nr,
14992                                             hash_mode, values, 0, stride_length,
14993                                             n_values_per_frame, type));
14994 }
14995
14996 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
14997                 (const tng_trajectory_t tng_data,
14998                  const int64_t block_id,
14999                  union data_values ****values,
15000                  int64_t *n_frames,
15001                  int64_t *n_particles,
15002                  int64_t *n_values_per_frame,
15003                  char *type)
15004 {
15005     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15006     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15007     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15008     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15009     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15010
15011     return(tng_gen_data_get(tng_data, block_id, TNG_TRUE, values, n_frames, n_particles,
15012                             n_values_per_frame, type));
15013 }
15014
15015 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
15016                 (const tng_trajectory_t tng_data,
15017                  const int64_t block_id,
15018                  void **values,
15019                  int64_t *n_frames,
15020                  int64_t *stride_length,
15021                  int64_t *n_particles,
15022                  int64_t *n_values_per_frame,
15023                  char *type)
15024 {
15025     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15026     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15027     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15028     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15029     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15030
15031     return(tng_gen_data_vector_get(tng_data, block_id, TNG_TRUE, values,
15032                                    n_frames, stride_length, n_particles,
15033                                    n_values_per_frame, type));
15034 }
15035
15036 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
15037                 (const tng_trajectory_t tng_data,
15038                  const int64_t block_id,
15039                  const int64_t start_frame_nr,
15040                  const int64_t end_frame_nr,
15041                  const char hash_mode,
15042                  union data_values ****values,
15043                  int64_t *n_particles,
15044                  int64_t *n_values_per_frame,
15045                  char *type)
15046 {
15047     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15048     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15049     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15050     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15051     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15052
15053     return(tng_gen_data_interval_get(tng_data, block_id, TNG_TRUE, start_frame_nr,
15054                                      end_frame_nr, hash_mode, values, n_particles,
15055                                      n_values_per_frame, type));
15056 }
15057
15058 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
15059                 (const tng_trajectory_t tng_data,
15060                  const int64_t block_id,
15061                  const int64_t start_frame_nr,
15062                  const int64_t end_frame_nr,
15063                  const char hash_mode,
15064                  void **values,
15065                  int64_t *n_particles,
15066                  int64_t *stride_length,
15067                  int64_t *n_values_per_frame,
15068                  char *type)
15069 {
15070     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15071     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15072     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15073     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15074     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15075     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15076
15077     return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_TRUE,
15078                                             start_frame_nr, end_frame_nr,
15079                                             hash_mode, values, n_particles,
15080                                             stride_length, n_values_per_frame,
15081                                             type));
15082 }
15083
15084 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
15085                 (const tng_trajectory_t tng_data,
15086                  const int64_t block_id,
15087                  int64_t frame,
15088                  int64_t *stride_length)
15089 {
15090     tng_function_status stat;
15091     tng_data_t data;
15092     int64_t orig_file_pos, file_pos;
15093     int is_particle_data;
15094
15095     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
15096     {
15097         frame = 0;
15098     }
15099
15100     if(frame >= 0)
15101     {
15102         stat = tng_frame_set_of_frame_find(tng_data, frame);
15103         if(stat != TNG_SUCCESS)
15104         {
15105             return(stat);
15106         }
15107     }
15108     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
15109     stat = tng_data_find(tng_data, block_id, &data);
15110     if(stat != TNG_SUCCESS)
15111     {
15112         stat = tng_particle_data_find(tng_data, block_id, &data);
15113         if(stat != TNG_SUCCESS)
15114         {
15115             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15116             /* If no specific frame was required read until this data block is found */
15117             if(frame < 0)
15118             {
15119                 file_pos = ftello(tng_data->input_file);
15120                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15121                 {
15122                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15123                     file_pos = ftello(tng_data->input_file);
15124                 }
15125             }
15126             if(stat != TNG_SUCCESS)
15127             {
15128                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15129
15130                 return(stat);
15131             }
15132             stat = tng_data_find(tng_data, block_id, &data);
15133             if(stat != TNG_SUCCESS)
15134             {
15135                 stat = tng_particle_data_find(tng_data, block_id, &data);
15136                 if(stat != TNG_SUCCESS)
15137                 {
15138                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15139
15140                     return(stat);
15141                 }
15142                 else
15143                 {
15144                     is_particle_data = 1;
15145                 }
15146             }
15147             else
15148             {
15149                 is_particle_data = 0;
15150             }
15151         }
15152         else
15153         {
15154             is_particle_data = 1;
15155         }
15156     }
15157     else
15158     {
15159         is_particle_data = 0;
15160     }
15161     if(is_particle_data)
15162     {
15163         *stride_length = data->stride_length;
15164     }
15165     else
15166     {
15167         *stride_length = data->stride_length;
15168     }
15169     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15170
15171     return(TNG_SUCCESS);
15172 }
15173
15174 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
15175                 (const tng_trajectory_t tng_data,
15176                  char *time)
15177 {
15178     struct tm *time_data;
15179     time_t secs;
15180     int retval;
15181
15182     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15183     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
15184
15185     secs = tng_data->time;
15186
15187     time_data = localtime(&secs); /* Returns a statically allocated variable. */
15188     retval = TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
15189              "%4d-%02d-%02d %02d:%02d:%02d",
15190              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
15191              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
15192
15193     /* handle return value (also) to quiet a -Wformat-truncation warning */
15194     return( (retval < 0) ? TNG_SUCCESS : TNG_FAILURE );
15195 }
15196
15197
15198 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
15199                 (const char *filename,
15200                  const char mode,
15201                  tng_trajectory_t *tng_data_p)
15202 {
15203     tng_function_status stat;
15204
15205     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
15206
15207     if(mode != 'r' && mode != 'w' && mode != 'a')
15208     {
15209         return(TNG_FAILURE);
15210     }
15211
15212     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
15213     {
15214         tng_trajectory_destroy(tng_data_p);
15215         return(TNG_CRITICAL);
15216     }
15217
15218     if(mode == 'w')
15219     {
15220         stat = tng_output_file_set(*tng_data_p, filename);
15221         return(stat);
15222     }
15223     tng_input_file_set(*tng_data_p, filename);
15224
15225     /* Read the file headers */
15226     tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
15227
15228     stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
15229
15230     if(stat != TNG_SUCCESS)
15231     {
15232         return(stat);
15233     }
15234
15235     if(mode == 'a')
15236     {
15237         if((*tng_data_p)->output_file)
15238         {
15239             fclose((*tng_data_p)->output_file);
15240         }
15241         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
15242         fseeko((*tng_data_p)->input_file,
15243                 (*tng_data_p)->last_trajectory_frame_set_input_file_pos,
15244                 SEEK_SET);
15245
15246         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
15247         if(stat != TNG_SUCCESS)
15248         {
15249             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
15250                    __FILE__, __LINE__);
15251         }
15252         (*tng_data_p)->output_file = 0;
15253
15254         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
15255         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
15256         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
15257         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
15258         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
15259         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
15260         if((*tng_data_p)->input_file)
15261         {
15262             fclose((*tng_data_p)->input_file);
15263             (*tng_data_p)->input_file = 0;
15264         }
15265         if((*tng_data_p)->input_file_path)
15266         {
15267             free((*tng_data_p)->input_file_path);
15268             (*tng_data_p)->input_file_path = 0;
15269         }
15270         tng_output_append_file_set(*tng_data_p, filename);
15271
15272         fseeko((*tng_data_p)->output_file, 0, SEEK_END);
15273
15274         (*tng_data_p)->output_endianness_swap_func_32 = (*tng_data_p)->input_endianness_swap_func_32;
15275         (*tng_data_p)->output_endianness_swap_func_64 = (*tng_data_p)->input_endianness_swap_func_64;
15276     }
15277
15278     return(stat);
15279 }
15280
15281 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
15282                 (tng_trajectory_t *tng_data_p)
15283 {
15284     tng_trajectory_frame_set_t frame_set;
15285
15286     if(tng_data_p == 0)
15287     {
15288         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
15289                __FILE__, __LINE__);
15290         return(TNG_FAILURE);
15291     }
15292
15293     if(*tng_data_p == 0)
15294     {
15295         return(TNG_SUCCESS);
15296     }
15297
15298     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
15299
15300     if(frame_set->n_unwritten_frames > 0)
15301     {
15302         frame_set->n_frames = frame_set->n_unwritten_frames;
15303         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
15304     }
15305
15306     return(tng_trajectory_destroy(tng_data_p));
15307 }
15308
15309 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
15310                 (const tng_trajectory_t tng_data,
15311                  const int64_t frame_nr,
15312                  double *time)
15313 {
15314     int64_t first_frame;
15315     tng_trajectory_frame_set_t frame_set;
15316     tng_function_status stat;
15317
15318     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15319     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
15320
15321     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
15322     if(stat != TNG_SUCCESS)
15323     {
15324         fprintf(stderr, "TNG library: Cannot find frame nr %" PRId64 ". %s: %d\n",
15325                frame_nr, __FILE__, __LINE__);
15326         return(stat);
15327     }
15328
15329     frame_set = &tng_data->current_trajectory_frame_set;
15330     first_frame = frame_set->first_frame;
15331
15332     if(tng_data->time_per_frame <= 0)
15333     {
15334         return(TNG_FAILURE);
15335     }
15336
15337     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
15338
15339     return(TNG_SUCCESS);
15340 }
15341
15342 /*
15343 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
15344                 (const tng_trajectory_t tng_data,
15345                  int64_t *n_mols,
15346                  int64_t **molecule_cnt_list,
15347                  tng_molecule_t *mols)
15348 {
15349     tng_trajectory_frame_set_t frame_set;
15350
15351     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15352     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
15353
15354     *n_mols = tng_data->n_molecules;
15355
15356     frame_set = &tng_data->current_trajectory_frame_set;
15357     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
15358     {
15359         *molecule_cnt_list = frame_set->molecule_cnt_list;
15360     }
15361     else
15362     {
15363         *molecule_cnt_list = tng_data->molecule_cnt_list;
15364     }
15365
15366     *mols = tng_data->molecules;
15367
15368     return(TNG_SUCCESS);
15369 }
15370 */
15371 /*
15372 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
15373                 (const tng_trajectory_t tng_data,
15374                  const char *name,
15375                  const int64_t cnt,
15376                  tng_molecule_t *mol)
15377 {
15378     tng_function_status stat;
15379
15380     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
15381     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
15382
15383     stat = tng_molecule_add(tng_data, name, mol);
15384     if(stat != TNG_SUCCESS)
15385     {
15386         return(stat);
15387     }
15388     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
15389
15390     return(stat);
15391 }
15392 */
15393 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
15394                 (const tng_trajectory_t tng_data,
15395                  const tng_molecule_t mol,
15396                  int64_t *n_particles,
15397                  char ***names,
15398                  char ***types,
15399                  char ***res_names,
15400                  int64_t **res_ids,
15401                  char ***chain_names,
15402                  int64_t **chain_ids)
15403 {
15404     tng_atom_t atom;
15405     tng_residue_t res;
15406     tng_chain_t chain;
15407     int64_t i;
15408     (void)tng_data;
15409
15410     *n_particles = mol->n_atoms;
15411
15412     *names = (char **)malloc(sizeof(char *) * *n_particles);
15413     *types = (char **)malloc(sizeof(char *) * *n_particles);
15414     *res_names = (char **)malloc(sizeof(char *) * *n_particles);
15415     *chain_names = (char **)malloc(sizeof(char *) * *n_particles);
15416     *res_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
15417     *chain_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
15418
15419     for(i = 0; i < *n_particles; i++)
15420     {
15421         atom = &mol->atoms[i];
15422         res = atom->residue;
15423         chain = res->chain;
15424         (*names)[i] = (char *)malloc(strlen(atom->name));
15425         strcpy(*names[i], atom->name);
15426         (*types)[i] = (char *)malloc(strlen(atom->atom_type));
15427         strcpy(*types[i], atom->atom_type);
15428         (*res_names)[i] = (char *)malloc(strlen(res->name));
15429         strcpy(*res_names[i], res->name);
15430         (*chain_names)[i] = (char *)malloc(strlen(chain->name));
15431         strcpy(*chain_names[i], chain->name);
15432         (*res_ids)[i] = res->id;
15433         (*chain_ids)[i] = chain->id;
15434     }
15435
15436     return(TNG_SUCCESS);
15437 }
15438
15439 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
15440                 (const tng_trajectory_t tng_data,
15441                  const tng_molecule_t mol,
15442                  const int64_t n_particles,
15443                  const char **names,
15444                  const char **types,
15445                  const char **res_names,
15446                  const int64_t *res_ids,
15447                  const char **chain_names,
15448                  const int64_t *chain_ids)
15449 {
15450     int64_t i;
15451     tng_chain_t chain;
15452     tng_residue_t residue;
15453     tng_atom_t atom;
15454     tng_function_status stat;
15455
15456     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15457     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
15458     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
15459     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
15460     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
15461     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
15462     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
15463
15464     for(i = 0; i < n_particles; i++)
15465     {
15466         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
15467            &chain) == TNG_FAILURE)
15468         {
15469             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
15470                                           &chain);
15471             if(stat != TNG_SUCCESS)
15472             {
15473                 return(stat);
15474             }
15475         }
15476         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
15477            &residue) == TNG_FAILURE)
15478         {
15479             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
15480                                          &residue);
15481             if(stat != TNG_SUCCESS)
15482             {
15483                 return(stat);
15484             }
15485         }
15486         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
15487         if(stat != TNG_SUCCESS)
15488         {
15489             return(stat);
15490         }
15491     }
15492     return(TNG_SUCCESS);
15493 }
15494
15495 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
15496                 (const tng_trajectory_t tng_data,
15497                  float **positions, int64_t *stride_length)
15498 {
15499     int64_t n_frames, n_particles, n_values_per_frame;
15500     char type;
15501     tng_function_status stat;
15502
15503     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15504     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
15505     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15506
15507     stat = tng_num_frames_get(tng_data, &n_frames);
15508     if(stat != TNG_SUCCESS)
15509     {
15510         return(stat);
15511     }
15512
15513     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
15514                                                  0, n_frames - 1, TNG_USE_HASH,
15515                                                  (void **)positions,
15516                                                  &n_particles,
15517                                                  stride_length,
15518                                                  &n_values_per_frame,
15519                                                  &type);
15520
15521     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15522     {
15523         return(TNG_FAILURE);
15524     }
15525
15526     return(stat);
15527 }
15528
15529 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
15530                 (const tng_trajectory_t tng_data,
15531                  float **velocities, int64_t *stride_length)
15532 {
15533     int64_t n_frames, n_particles, n_values_per_frame;
15534     char type;
15535     tng_function_status stat;
15536
15537     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15538     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
15539     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15540
15541     stat = tng_num_frames_get(tng_data, &n_frames);
15542     if(stat != TNG_SUCCESS)
15543     {
15544         return(stat);
15545     }
15546
15547     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
15548                                                  0, n_frames - 1, TNG_USE_HASH,
15549                                                  (void **)velocities,
15550                                                  &n_particles,
15551                                                  stride_length,
15552                                                  &n_values_per_frame,
15553                                                  &type);
15554
15555     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15556     {
15557         return(TNG_FAILURE);
15558     }
15559
15560     return(stat);
15561 }
15562
15563 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
15564                 (const tng_trajectory_t tng_data,
15565                  float **forces, int64_t *stride_length)
15566 {
15567     int64_t n_frames, n_particles, n_values_per_frame;
15568     char type;
15569     tng_function_status stat;
15570
15571     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15572     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
15573     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15574
15575     stat = tng_num_frames_get(tng_data, &n_frames);
15576     if(stat != TNG_SUCCESS)
15577     {
15578         return(stat);
15579     }
15580
15581     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
15582                                                  0, n_frames - 1, TNG_USE_HASH,
15583                                                  (void **)forces,
15584                                                  &n_particles,
15585                                                  stride_length,
15586                                                  &n_values_per_frame,
15587                                                  &type);
15588
15589     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15590     {
15591         return(TNG_FAILURE);
15592     }
15593
15594     return(stat);
15595 }
15596
15597 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
15598                 (const tng_trajectory_t tng_data,
15599                  float **box_shape,
15600                  int64_t *stride_length)
15601 {
15602     int64_t n_frames, n_values_per_frame;
15603     char type;
15604     tng_function_status stat;
15605
15606     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15607     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
15608     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15609
15610     stat = tng_num_frames_get(tng_data, &n_frames);
15611     if(stat != TNG_SUCCESS)
15612     {
15613         return(stat);
15614     }
15615
15616     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
15617                                         0, n_frames - 1, TNG_USE_HASH,
15618                                         (void **)box_shape,
15619                                         stride_length,
15620                                         &n_values_per_frame,
15621                                         &type);
15622
15623     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15624     {
15625         return(TNG_FAILURE);
15626     }
15627
15628     return(stat);
15629 }
15630
15631 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
15632                 (const tng_trajectory_t tng_data,
15633                  const int64_t block_id,
15634                  void **values,
15635                  char *data_type,
15636                  int64_t *retrieved_frame_number,
15637                  double *retrieved_time)
15638 {
15639     tng_trajectory_frame_set_t frame_set;
15640     tng_data_t data = 0;
15641     tng_function_status stat;
15642     int size;
15643     int64_t i, full_data_len, n_particles;
15644     void *temp;
15645     int64_t file_pos;
15646
15647     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15648     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
15649     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
15650     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
15651     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
15652
15653     frame_set = &tng_data->current_trajectory_frame_set;
15654
15655     stat = tng_particle_data_find(tng_data, block_id, &data);
15656     if(stat != TNG_SUCCESS)
15657     {
15658         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15659         file_pos = ftello(tng_data->input_file);
15660         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15661         {
15662             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15663             file_pos = ftello(tng_data->input_file);
15664         }
15665         if(stat != TNG_SUCCESS)
15666         {
15667             return(stat);
15668         }
15669         stat = tng_particle_data_find(tng_data, block_id, &data);
15670         if(stat != TNG_SUCCESS)
15671         {
15672             return(stat);
15673         }
15674     }
15675     if(data->last_retrieved_frame < 0)
15676     {
15677         fseeko(tng_data->input_file,
15678               tng_data->first_trajectory_frame_set_input_file_pos,
15679               SEEK_SET);
15680         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
15681         if(stat != TNG_SUCCESS)
15682         {
15683             return(stat);
15684         }
15685         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15686         if(stat != TNG_SUCCESS)
15687         {
15688             return(stat);
15689         }
15690
15691         i = data->first_frame_with_data;
15692     }
15693     else
15694     {
15695         if(data->n_frames == 1 && frame_set->n_frames == 1)
15696         {
15697             i = data->last_retrieved_frame + 1;
15698         }
15699         else
15700         {
15701             i = data->last_retrieved_frame + data->stride_length;
15702         }
15703         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
15704         {
15705             stat = tng_frame_set_of_frame_find(tng_data, i);
15706             if(stat != TNG_SUCCESS)
15707             {
15708                 /* If the frame set search found the frame set after the starting
15709                  * frame set there is a gap in the frame sets. So, even if the frame
15710                  * was not found the next frame with data is still in the found
15711                  * frame set. */
15712                 if(stat == TNG_CRITICAL)
15713                 {
15714                     return(stat);
15715                 }
15716                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
15717                 {
15718                     return(TNG_FAILURE);
15719                 }
15720                 i = frame_set->first_frame;
15721             }
15722         }
15723         if(data->last_retrieved_frame < frame_set->first_frame)
15724         {
15725             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15726             if(stat != TNG_SUCCESS)
15727             {
15728                 return(stat);
15729             }
15730         }
15731     }
15732     data->last_retrieved_frame = i;
15733     *retrieved_frame_number = i;
15734     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
15735     {
15736         *retrieved_time = frame_set->first_frame_time +
15737                         (i - frame_set->first_frame) *
15738                         tng_data->time_per_frame;
15739     }
15740     else
15741     {
15742         *retrieved_time = 0;
15743     }
15744
15745     if(data->stride_length > 1)
15746     {
15747         i = (i - data->first_frame_with_data) / data->stride_length;
15748     }
15749     else
15750     {
15751         i = (i - frame_set->first_frame);
15752     }
15753
15754     tng_num_particles_get(tng_data, &n_particles);
15755
15756     *data_type = data->datatype;
15757
15758     switch(*data_type)
15759     {
15760     case TNG_CHAR_DATA:
15761         return(TNG_FAILURE);
15762     case TNG_INT_DATA:
15763         size = sizeof(int64_t);
15764         break;
15765     case TNG_FLOAT_DATA:
15766         size = sizeof(float);
15767         break;
15768     case TNG_DOUBLE_DATA:
15769     default:
15770         size = sizeof(double);
15771     }
15772
15773     full_data_len = size * n_particles * data->n_values_per_frame;
15774
15775 //     fprintf(stderr, "TNG library: TEMP: i = %" PRId64 ", full_data_len = %" PRId64 ", size = %d, n_particles = %" PRId64 ", n_values_per_frame = %" PRId64 "\n",
15776 //            i, full_data_len, size, n_particles, data->n_values_per_frame);
15777
15778     temp = (char *)realloc(*values, full_data_len);
15779     if(!temp)
15780     {
15781         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
15782                 __FILE__, __LINE__);
15783         free(*values);
15784         *values = 0;
15785         return(TNG_CRITICAL);
15786     }
15787
15788     *values = temp;
15789
15790     memcpy(*values, (char *)data->values + i * full_data_len, full_data_len);
15791
15792     return(TNG_SUCCESS);
15793 }
15794
15795 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
15796                 (const tng_trajectory_t tng_data,
15797                  const int64_t block_id,
15798                  void **values,
15799                  char *data_type,
15800                  int64_t *retrieved_frame_number,
15801                  double *retrieved_time)
15802 {
15803     tng_trajectory_frame_set_t frame_set;
15804     tng_data_t data = 0;
15805     tng_function_status stat;
15806     int size;
15807     int64_t i, full_data_len;
15808     void *temp;
15809     int64_t file_pos;
15810
15811     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15812     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
15813     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
15814     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
15815     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
15816
15817     frame_set = &tng_data->current_trajectory_frame_set;
15818
15819     stat = tng_data_find(tng_data, block_id, &data);
15820     if(stat != TNG_SUCCESS)
15821     {
15822         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15823         file_pos = ftello(tng_data->input_file);
15824         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15825         {
15826             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15827             file_pos = ftello(tng_data->input_file);
15828         }
15829         if(stat != TNG_SUCCESS)
15830         {
15831             return(stat);
15832         }
15833         stat = tng_data_find(tng_data, block_id, &data);
15834         if(stat != TNG_SUCCESS)
15835         {
15836             return(stat);
15837         }
15838     }
15839     if(data->last_retrieved_frame < 0)
15840     {
15841         fseeko(tng_data->input_file,
15842                 tng_data->first_trajectory_frame_set_input_file_pos,
15843                 SEEK_SET);
15844         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
15845         if(stat != TNG_SUCCESS)
15846         {
15847             return(stat);
15848         }
15849         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15850         if(stat != TNG_SUCCESS)
15851         {
15852             return(stat);
15853         }
15854
15855         i = data->first_frame_with_data;
15856     }
15857     else
15858     {
15859         if(data->n_frames == 1 && frame_set->n_frames == 1)
15860         {
15861             i = data->last_retrieved_frame + 1;
15862         }
15863         else
15864         {
15865             i = data->last_retrieved_frame + data->stride_length;
15866         }
15867         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
15868         {
15869             stat = tng_frame_set_of_frame_find(tng_data, i);
15870             if(stat != TNG_SUCCESS)
15871             {
15872                 /* If the frame set search found the frame set after the starting
15873                  * frame set there is a gap in the frame sets. So, even if the frame
15874                  * was not found the next frame with data is still in the found
15875                  * frame set. */
15876                 if(stat == TNG_CRITICAL)
15877                 {
15878                     return(stat);
15879                 }
15880                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
15881                 {
15882                     return(TNG_FAILURE);
15883                 }
15884                 i = frame_set->first_frame;
15885             }
15886         }
15887         if(data->last_retrieved_frame < frame_set->first_frame)
15888         {
15889             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15890             if(stat != TNG_SUCCESS)
15891             {
15892                 return(stat);
15893             }
15894         }
15895     }
15896     data->last_retrieved_frame = i;
15897     *retrieved_frame_number = i;
15898     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
15899     {
15900         *retrieved_time = frame_set->first_frame_time +
15901                         (i - frame_set->first_frame) *
15902                         tng_data->time_per_frame;
15903     }
15904     else
15905     {
15906         *retrieved_time = 0;
15907     }
15908
15909     if(data->stride_length > 1)
15910     {
15911         i = (i - data->first_frame_with_data) / data->stride_length;
15912     }
15913     else
15914     {
15915         i = (i - frame_set->first_frame);
15916     }
15917
15918     *data_type = data->datatype;
15919
15920     switch(*data_type)
15921     {
15922     case TNG_CHAR_DATA:
15923         return(TNG_FAILURE);
15924     case TNG_INT_DATA:
15925         size = sizeof(int64_t);
15926         break;
15927     case TNG_FLOAT_DATA:
15928         size = sizeof(float);
15929         break;
15930     case TNG_DOUBLE_DATA:
15931     default:
15932         size = sizeof(double);
15933     }
15934
15935     full_data_len = size * data->n_values_per_frame;
15936
15937     temp = (char *)realloc(*values, full_data_len);
15938     if(!temp)
15939     {
15940         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
15941                 __FILE__, __LINE__);
15942         free(*values);
15943         *values = 0;
15944         return(TNG_CRITICAL);
15945     }
15946
15947     *values = temp;
15948
15949     memcpy(*values, (char *)data->values + i * full_data_len, full_data_len);
15950
15951     return(TNG_SUCCESS);
15952 }
15953
15954 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
15955                 (const tng_trajectory_t tng_data,
15956                  const int64_t first_frame,
15957                  const int64_t last_frame,
15958                  float **positions,
15959                  int64_t *stride_length)
15960 {
15961     int64_t n_particles, n_values_per_frame;
15962     char type;
15963     tng_function_status stat;
15964
15965     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15966     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
15967     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
15968     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15969
15970     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
15971                                                  first_frame, last_frame,
15972                                                  TNG_USE_HASH,
15973                                                  (void **)positions,
15974                                                  &n_particles,
15975                                                  stride_length,
15976                                                  &n_values_per_frame,
15977                                                  &type);
15978
15979     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15980     {
15981         return(TNG_FAILURE);
15982     }
15983
15984     return(stat);
15985 }
15986
15987 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
15988                 (const tng_trajectory_t tng_data,
15989                  const int64_t first_frame,
15990                  const int64_t last_frame,
15991                  float **velocities,
15992                  int64_t *stride_length)
15993 {
15994     int64_t n_particles, n_values_per_frame;
15995     char type;
15996     tng_function_status stat;
15997
15998     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15999     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16000     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16001     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16002
16003     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
16004                                                  first_frame, last_frame,
16005                                                  TNG_USE_HASH,
16006                                                  (void **)velocities,
16007                                                  &n_particles,
16008                                                  stride_length,
16009                                                  &n_values_per_frame,
16010                                                  &type);
16011
16012     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16013     {
16014         return(TNG_FAILURE);
16015     }
16016
16017     return(stat);
16018 }
16019
16020 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
16021                 (const tng_trajectory_t tng_data,
16022                  const int64_t first_frame,
16023                  const int64_t last_frame,
16024                  float **forces,
16025                  int64_t *stride_length)
16026 {
16027     int64_t n_particles, n_values_per_frame;
16028     char type;
16029     tng_function_status stat;
16030
16031     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16032     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
16033     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16034     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16035
16036     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16037                                                  first_frame, last_frame,
16038                                                  TNG_USE_HASH,
16039                                                  (void **)forces,
16040                                                  &n_particles,
16041                                                  stride_length,
16042                                                  &n_values_per_frame,
16043                                                  &type);
16044
16045     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16046     {
16047         return(TNG_FAILURE);
16048     }
16049
16050     return(stat);
16051 }
16052
16053 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
16054                 (const tng_trajectory_t tng_data,
16055                  const int64_t first_frame,
16056                  const int64_t last_frame,
16057                  float **box_shape,
16058                  int64_t *stride_length)
16059 {
16060     int64_t n_values_per_frame;
16061     char type;
16062     tng_function_status stat;
16063
16064     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16065     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16066     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16067     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16068
16069     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16070                                         first_frame, last_frame,
16071                                         TNG_USE_HASH,
16072                                         (void **)box_shape,
16073                                         stride_length,
16074                                         &n_values_per_frame,
16075                                         &type);
16076
16077     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16078     {
16079         return(TNG_FAILURE);
16080     }
16081
16082     return(stat);
16083 }
16084
16085 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
16086                 (const tng_trajectory_t tng_data,
16087                  const int64_t i,
16088                  const int64_t n_values_per_frame,
16089                  const int64_t block_id,
16090                  const char *block_name,
16091                  const char particle_dependency,
16092                  const char compression)
16093 {
16094     tng_trajectory_frame_set_t frame_set;
16095     tng_data_t data;
16096     int64_t n_particles, n_frames;
16097     tng_function_status stat;
16098
16099     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16100     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16101
16102     if(i <= 0)
16103     {
16104         fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
16105                i, __FILE__, __LINE__);
16106         return(TNG_FAILURE);
16107     }
16108
16109     frame_set = &tng_data->current_trajectory_frame_set;
16110
16111     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16112     {
16113         n_frames = tng_data->frame_set_n_frames;
16114
16115         stat = tng_frame_set_new(tng_data, 0, n_frames);
16116         if(stat != TNG_SUCCESS)
16117         {
16118             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16119                 __LINE__);
16120             return(stat);
16121         }
16122     }
16123     else
16124     {
16125         n_frames = frame_set->n_frames;
16126     }
16127
16128     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16129     {
16130         tng_num_particles_get(tng_data, &n_particles);
16131         if(n_particles <= 0)
16132         {
16133             return(TNG_FAILURE);
16134         }
16135
16136         if(tng_particle_data_find(tng_data, block_id, &data)
16137         != TNG_SUCCESS)
16138         {
16139             stat = tng_particle_data_block_add(tng_data, block_id,
16140                                                block_name,
16141                                                TNG_FLOAT_DATA,
16142                                                TNG_TRAJECTORY_BLOCK,
16143                                                n_frames, n_values_per_frame, i,
16144                                                0, n_particles,
16145                                                compression, 0);
16146             if(stat != TNG_SUCCESS)
16147             {
16148                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16149                        __FILE__, __LINE__);
16150                 return(stat);
16151             }
16152             data = &frame_set->tr_particle_data[frame_set->
16153                                                   n_particle_data_blocks - 1];
16154             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16155                                                   i, n_particles,
16156                                                   n_values_per_frame);
16157             if(stat != TNG_SUCCESS)
16158             {
16159                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16160                        __FILE__, __LINE__);
16161                 return(stat);
16162             }
16163         }
16164         else
16165         {
16166             if(data->stride_length != i)
16167             {
16168                 data->stride_length = i;
16169                 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16170                                                       i, n_particles,
16171                                                       n_values_per_frame);
16172                 if(stat != TNG_SUCCESS)
16173                 {
16174                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16175                            __FILE__, __LINE__);
16176                     return(stat);
16177                 }
16178             }
16179         }
16180     }
16181     else
16182     {
16183         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16184         {
16185             stat = tng_data_block_add(tng_data, block_id, block_name,
16186                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
16187                                       n_frames, n_values_per_frame,
16188                                       i, compression, 0);
16189             if(stat != TNG_SUCCESS)
16190             {
16191                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16192                        __FILE__, __LINE__);
16193                 return(stat);
16194             }
16195             data = &frame_set->tr_data[frame_set->
16196                                           n_data_blocks - 1];
16197             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16198                                          i, n_values_per_frame);
16199             if(stat != TNG_SUCCESS)
16200             {
16201                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16202                        __FILE__, __LINE__);
16203                 return(stat);
16204             }
16205         }
16206         else
16207         {
16208             if(data->stride_length != i)
16209             {
16210                 data->stride_length = i;
16211                 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16212                                              i, n_values_per_frame);
16213                 if(stat != TNG_SUCCESS)
16214                 {
16215                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16216                            __FILE__, __LINE__);
16217                     return(stat);
16218                 }
16219             }
16220         }
16221     }
16222
16223     return(TNG_SUCCESS);
16224 }
16225
16226 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
16227                 (const tng_trajectory_t tng_data,
16228                  const int64_t i,
16229                  const int64_t n_values_per_frame,
16230                  const int64_t block_id,
16231                  const char *block_name,
16232                  const char particle_dependency,
16233                  const char compression)
16234 {
16235     tng_trajectory_frame_set_t frame_set;
16236     tng_data_t data;
16237     int64_t n_particles, n_frames;
16238     tng_function_status stat;
16239
16240     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16241     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16242
16243     if(i <= 0)
16244     {
16245         fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
16246                i, __FILE__, __LINE__);
16247         return(TNG_FAILURE);
16248     }
16249
16250     frame_set = &tng_data->current_trajectory_frame_set;
16251
16252     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16253     {
16254         n_frames = tng_data->frame_set_n_frames;
16255
16256         stat = tng_frame_set_new(tng_data, 0, n_frames);
16257         if(stat != TNG_SUCCESS)
16258         {
16259             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16260                 __LINE__);
16261             return(stat);
16262         }
16263     }
16264     else
16265     {
16266         n_frames = frame_set->n_frames;
16267     }
16268
16269     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16270     {
16271         tng_num_particles_get(tng_data, &n_particles);
16272
16273         if(n_particles <= 0)
16274         {
16275             return(TNG_FAILURE);
16276         }
16277
16278         if(tng_particle_data_find(tng_data, block_id, &data)
16279         != TNG_SUCCESS)
16280         {
16281             stat = tng_particle_data_block_add(tng_data, block_id,
16282                                             block_name,
16283                                             TNG_DOUBLE_DATA,
16284                                             TNG_TRAJECTORY_BLOCK,
16285                                             n_frames, n_values_per_frame, i,
16286                                             0, n_particles,
16287                                             compression, 0);
16288             if(stat != TNG_SUCCESS)
16289             {
16290                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16291                        __FILE__, __LINE__);
16292                 return(stat);
16293             }
16294             data = &frame_set->tr_particle_data[frame_set->
16295                                                   n_particle_data_blocks - 1];
16296             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16297                                                   i, n_particles,
16298                                                   n_values_per_frame);
16299             if(stat != TNG_SUCCESS)
16300             {
16301                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16302                        __FILE__, __LINE__);
16303                 return(stat);
16304             }
16305         }
16306         else
16307         {
16308             data->stride_length = i;
16309         }
16310     }
16311     else
16312     {
16313         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16314         {
16315             stat = tng_data_block_add(tng_data, block_id, block_name,
16316                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
16317                                       n_frames, n_values_per_frame,
16318                                       i, compression, 0);
16319             if(stat != TNG_SUCCESS)
16320             {
16321                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16322                        __FILE__, __LINE__);
16323                 return(stat);
16324             }
16325             data = &frame_set->tr_data[frame_set->
16326                                           n_data_blocks - 1];
16327             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16328                                          i, n_values_per_frame);
16329             if(stat != TNG_SUCCESS)
16330             {
16331                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16332                        __FILE__, __LINE__);
16333                 return(stat);
16334             }
16335         }
16336         else
16337         {
16338             data->stride_length = i;
16339         }
16340     }
16341
16342     return(TNG_SUCCESS);
16343 }
16344
16345 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
16346                 (const tng_trajectory_t tng_data,
16347                  const int64_t i,
16348                  const int64_t n_values_per_frame,
16349                  const int64_t block_id,
16350                  const char *block_name,
16351                  const char particle_dependency,
16352                  const char compression)
16353 {
16354     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
16355            "See documentation. %s: %d", __FILE__, __LINE__);
16356     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
16357                                                block_id, block_name,
16358                                                particle_dependency,
16359                                                compression));
16360 }
16361 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
16362                 (const tng_trajectory_t tng_data,
16363                  const int64_t i)
16364 {
16365     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16366     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16367
16368     return(tng_util_generic_write_interval_set(tng_data, i, 3,
16369                                                TNG_TRAJ_POSITIONS,
16370                                                "POSITIONS",
16371                                                TNG_PARTICLE_BLOCK_DATA,
16372                                                TNG_TNG_COMPRESSION));
16373 }
16374
16375 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
16376                 (const tng_trajectory_t tng_data,
16377                  const int64_t i)
16378 {
16379     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16380     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16381
16382     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16383                                                       TNG_TRAJ_POSITIONS,
16384                                                       "POSITIONS",
16385                                                       TNG_PARTICLE_BLOCK_DATA,
16386                                                       TNG_TNG_COMPRESSION));
16387 }
16388
16389 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
16390                 (const tng_trajectory_t tng_data,
16391                  const int64_t i)
16392 {
16393     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
16394            "See documentation. %s: %d", __FILE__, __LINE__);
16395     return(tng_util_pos_write_interval_set(tng_data, i));
16396 }
16397
16398 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
16399                 (const tng_trajectory_t tng_data,
16400                  const int64_t i)
16401 {
16402     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16403     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16404
16405     return(tng_util_generic_write_interval_set(tng_data, i, 3,
16406                                                TNG_TRAJ_VELOCITIES,
16407                                                "VELOCITIES",
16408                                                TNG_PARTICLE_BLOCK_DATA,
16409                                                TNG_TNG_COMPRESSION));
16410 }
16411
16412 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
16413                 (const tng_trajectory_t tng_data,
16414                  const int64_t i)
16415 {
16416     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16417     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16418
16419     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16420                                                       TNG_TRAJ_VELOCITIES,
16421                                                       "VELOCITIES",
16422                                                       TNG_PARTICLE_BLOCK_DATA,
16423                                                       TNG_TNG_COMPRESSION));
16424 }
16425
16426 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
16427                 (const tng_trajectory_t tng_data,
16428                  const int64_t i)
16429 {
16430     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
16431            "See documentation. %s: %d", __FILE__, __LINE__);
16432     return(tng_util_vel_write_interval_set(tng_data, i));
16433 }
16434
16435 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
16436                 (const tng_trajectory_t tng_data,
16437                  const int64_t i)
16438 {
16439     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16440     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16441
16442     return(tng_util_generic_write_interval_set(tng_data, i, 3,
16443                                                TNG_TRAJ_FORCES,
16444                                                "FORCES",
16445                                                TNG_PARTICLE_BLOCK_DATA,
16446                                                TNG_GZIP_COMPRESSION));
16447 }
16448
16449 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
16450                 (const tng_trajectory_t tng_data,
16451                  const int64_t i)
16452 {
16453     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16454     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16455
16456     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16457                                                       TNG_TRAJ_FORCES,
16458                                                       "FORCES",
16459                                                       TNG_PARTICLE_BLOCK_DATA,
16460                                                       TNG_GZIP_COMPRESSION));
16461 }
16462
16463 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
16464                 (const tng_trajectory_t tng_data,
16465                  const int64_t i)
16466 {
16467     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
16468            "See documentation. %s: %d", __FILE__, __LINE__);
16469     return(tng_util_force_write_interval_set(tng_data, i));
16470 }
16471
16472 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
16473                 (const tng_trajectory_t tng_data,
16474                  const int64_t i)
16475 {
16476     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16477     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16478
16479     return(tng_util_generic_write_interval_set(tng_data, i, 9,
16480                                                TNG_TRAJ_BOX_SHAPE,
16481                                                "BOX SHAPE",
16482                                                TNG_NON_PARTICLE_BLOCK_DATA,
16483                                                TNG_GZIP_COMPRESSION));
16484 }
16485
16486 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
16487                 (const tng_trajectory_t tng_data,
16488                  const int64_t i)
16489 {
16490     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16491     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16492
16493     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
16494                                                       TNG_TRAJ_BOX_SHAPE,
16495                                                       "BOX SHAPE",
16496                                                       TNG_NON_PARTICLE_BLOCK_DATA,
16497                                                       TNG_GZIP_COMPRESSION));
16498 }
16499
16500 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
16501                 (const tng_trajectory_t tng_data,
16502                  const int64_t i)
16503 {
16504     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
16505            "See documentation. %s: %d", __FILE__, __LINE__);
16506     return(tng_util_box_shape_write_interval_set(tng_data, i));
16507 }
16508
16509 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
16510                 (const tng_trajectory_t tng_data,
16511                  const int64_t frame_nr,
16512                  const float *values,
16513                  const int64_t n_values_per_frame,
16514                  const int64_t block_id,
16515                  const char *block_name,
16516                  const char particle_dependency,
16517                  const char compression)
16518 {
16519     tng_trajectory_frame_set_t frame_set;
16520     tng_data_t data;
16521     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
16522     int64_t last_frame;
16523     int is_first_frame_flag = 0;
16524     char block_type_flag;
16525     tng_function_status stat;
16526
16527     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16528     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
16529
16530     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16531     {
16532         tng_num_particles_get(tng_data, &n_particles);
16533         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
16534     }
16535
16536     if(values == 0)
16537     {
16538         return(TNG_FAILURE);
16539     }
16540
16541     frame_set = &tng_data->current_trajectory_frame_set;
16542
16543     if(frame_nr < 0)
16544     {
16545         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16546         n_frames = stride_length = 1;
16547     }
16548     else
16549     {
16550         block_type_flag = TNG_TRAJECTORY_BLOCK;
16551
16552         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16553         {
16554             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
16555             if(stat != TNG_SUCCESS)
16556             {
16557                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16558                     __LINE__);
16559                 return(stat);
16560             }
16561         }
16562         last_frame = frame_set->first_frame +
16563                      frame_set->n_frames - 1;
16564         if(frame_nr > last_frame)
16565         {
16566             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
16567             if(stat != TNG_SUCCESS)
16568             {
16569                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
16570                     __LINE__);
16571                 return(stat);
16572             }
16573             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
16574             {
16575                 last_frame = frame_nr - 1;
16576             }
16577             stat = tng_frame_set_new(tng_data, last_frame + 1,
16578                                      tng_data->frame_set_n_frames);
16579             if(stat != TNG_SUCCESS)
16580             {
16581                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16582                     __LINE__);
16583                 return(stat);
16584             }
16585         }
16586         if(frame_set->n_unwritten_frames == 0)
16587         {
16588             is_first_frame_flag = 1;
16589         }
16590         frame_set->n_unwritten_frames = frame_nr -
16591                                         frame_set->first_frame + 1;
16592
16593         n_frames = frame_set->n_frames;
16594     }
16595
16596     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16597     {
16598         if(tng_particle_data_find(tng_data, block_id, &data)
16599         != TNG_SUCCESS)
16600         {
16601             stat = tng_particle_data_block_add(tng_data, block_id,
16602                                                block_name,
16603                                                TNG_FLOAT_DATA,
16604                                                block_type_flag,
16605                                                n_frames, n_values_per_frame,
16606                                                stride_length,
16607                                                0, n_particles,
16608                                                compression, 0);
16609             if(stat != TNG_SUCCESS)
16610             {
16611                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16612                        __FILE__, __LINE__);
16613                 return(stat);
16614             }
16615             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16616             {
16617                 data = &frame_set->tr_particle_data[frame_set->
16618                                                     n_particle_data_blocks - 1];
16619             }
16620             else
16621             {
16622                 data = &tng_data->non_tr_particle_data[tng_data->
16623                                                        n_particle_data_blocks - 1];
16624             }
16625             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16626                                                   stride_length, n_particles,
16627                                                   n_values_per_frame);
16628             if(stat != TNG_SUCCESS)
16629             {
16630                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16631                        __FILE__, __LINE__);
16632                 return(stat);
16633             }
16634         }
16635         /* FIXME: Here we must be able to handle modified n_particles as well. */
16636         else if(n_frames > data->n_frames)
16637         {
16638             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16639                                                   data->stride_length, n_particles,
16640                                                   n_values_per_frame);
16641             if(stat != TNG_SUCCESS)
16642             {
16643                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16644                        __FILE__, __LINE__);
16645                 return(stat);
16646             }
16647         }
16648
16649         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16650         {
16651             stride_length = data->stride_length;
16652
16653             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16654             {
16655                 data->first_frame_with_data = frame_nr;
16656                 frame_pos = 0;
16657             }
16658             else
16659             {
16660                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16661             }
16662
16663             memcpy((char *)data->values + sizeof(float) * frame_pos * n_particles *
16664                    n_values_per_frame, values, sizeof(float) *
16665                    n_particles * n_values_per_frame);
16666         }
16667         else
16668         {
16669             memcpy(data->values, values, sizeof(float) * n_particles *
16670                    n_values_per_frame);
16671         }
16672     }
16673     else
16674     {
16675         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16676         {
16677             stat = tng_data_block_add(tng_data, block_id, block_name,
16678                                       TNG_FLOAT_DATA, block_type_flag,
16679                                       n_frames, n_values_per_frame,
16680                                       stride_length, compression, 0);
16681             if(stat != TNG_SUCCESS)
16682             {
16683                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16684                        __FILE__, __LINE__);
16685                 return(stat);
16686             }
16687             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16688             {
16689                 data = &frame_set->tr_data[frame_set->
16690                                               n_data_blocks - 1];
16691             }
16692             else
16693             {
16694                 data = &tng_data->non_tr_data[tng_data->
16695                                                  n_data_blocks - 1];
16696             }
16697             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16698                                          stride_length, n_values_per_frame);
16699             if(stat != TNG_SUCCESS)
16700             {
16701                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16702                        __FILE__, __LINE__);
16703                 return(stat);
16704             }
16705         }
16706         /* FIXME: Here we must be able to handle modified n_particles as well. */
16707         else if(n_frames > data->n_frames)
16708         {
16709             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16710                                          data->stride_length, n_values_per_frame);
16711             if(stat != TNG_SUCCESS)
16712             {
16713                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16714                        __FILE__, __LINE__);
16715                 return(stat);
16716             }
16717         }
16718
16719         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16720         {
16721             stride_length = data->stride_length;
16722
16723             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16724             {
16725                 data->first_frame_with_data = frame_nr;
16726                 frame_pos = 0;
16727             }
16728             else
16729             {
16730                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16731             }
16732
16733             memcpy((char *)data->values + sizeof(float) * frame_pos *
16734                    n_values_per_frame, values, sizeof(float) *
16735                    n_values_per_frame);
16736         }
16737         else
16738         {
16739             memcpy(data->values, values, sizeof(float) * n_values_per_frame);
16740         }
16741     }
16742
16743     return(TNG_SUCCESS);
16744 }
16745
16746 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
16747                 (const tng_trajectory_t tng_data,
16748                  const int64_t frame_nr,
16749                  const double *values,
16750                  const int64_t n_values_per_frame,
16751                  const int64_t block_id,
16752                  const char *block_name,
16753                  const char particle_dependency,
16754                  const char compression)
16755 {
16756     tng_trajectory_frame_set_t frame_set;
16757     tng_data_t data;
16758     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
16759     int64_t last_frame;
16760     int is_first_frame_flag = 0;
16761     char block_type_flag;
16762     tng_function_status stat;
16763
16764     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16765     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
16766
16767     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16768     {
16769         tng_num_particles_get(tng_data, &n_particles);
16770         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
16771     }
16772
16773     if(values == 0)
16774     {
16775         return(TNG_FAILURE);
16776     }
16777
16778     frame_set = &tng_data->current_trajectory_frame_set;
16779
16780     if(frame_nr < 0)
16781     {
16782         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16783         n_frames = stride_length = 1;
16784     }
16785     else
16786     {
16787         block_type_flag = TNG_TRAJECTORY_BLOCK;
16788
16789         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16790         {
16791             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
16792             if(stat != TNG_SUCCESS)
16793             {
16794                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16795                     __LINE__);
16796                 return(stat);
16797             }
16798         }
16799         last_frame = frame_set->first_frame +
16800                      frame_set->n_frames - 1;
16801         if(frame_nr > last_frame)
16802         {
16803             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
16804             if(stat != TNG_SUCCESS)
16805             {
16806                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
16807                     __LINE__);
16808                 return(stat);
16809             }
16810             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
16811             {
16812                 last_frame = frame_nr - 1;
16813             }
16814             stat = tng_frame_set_new(tng_data, last_frame + 1,
16815                                      tng_data->frame_set_n_frames);
16816             if(stat != TNG_SUCCESS)
16817             {
16818                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16819                     __LINE__);
16820                 return(stat);
16821             }
16822         }
16823         if(frame_set->n_unwritten_frames == 0)
16824         {
16825             is_first_frame_flag = 1;
16826         }
16827         frame_set->n_unwritten_frames = frame_nr -
16828                                         frame_set->first_frame + 1;
16829
16830         n_frames = frame_set->n_frames;
16831     }
16832
16833
16834     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16835     {
16836         if(tng_particle_data_find(tng_data, block_id, &data)
16837         != TNG_SUCCESS)
16838         {
16839             stat = tng_particle_data_block_add(tng_data, block_id,
16840                                             block_name,
16841                                             TNG_DOUBLE_DATA,
16842                                             block_type_flag,
16843                                             n_frames, n_values_per_frame,
16844                                             stride_length,
16845                                             0, n_particles,
16846                                             compression, 0);
16847             if(stat != TNG_SUCCESS)
16848             {
16849                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16850                        __FILE__, __LINE__);
16851                 return(stat);
16852             }
16853             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16854             {
16855                 data = &frame_set->tr_particle_data[frame_set->
16856                                                     n_particle_data_blocks - 1];
16857             }
16858             else
16859             {
16860                 data = &tng_data->non_tr_particle_data[tng_data->
16861                                                     n_particle_data_blocks - 1];
16862             }
16863             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16864                                                   stride_length, n_particles,
16865                                                   n_values_per_frame);
16866             if(stat != TNG_SUCCESS)
16867             {
16868                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16869                        __FILE__, __LINE__);
16870                 return(stat);
16871             }
16872         }
16873         /* FIXME: Here we must be able to handle modified n_particles as well. */
16874         else if(n_frames > data->n_frames)
16875         {
16876             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16877                                                   data->stride_length, n_particles,
16878                                                   n_values_per_frame);
16879             if(stat != TNG_SUCCESS)
16880             {
16881                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16882                        __FILE__, __LINE__);
16883                 return(stat);
16884             }
16885         }
16886
16887         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16888         {
16889             stride_length = data->stride_length;
16890
16891             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16892             {
16893                 data->first_frame_with_data = frame_nr;
16894                 frame_pos = 0;
16895             }
16896             else
16897             {
16898                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16899             }
16900
16901             memcpy((char *)data->values + sizeof(double) * frame_pos * n_particles *
16902                    n_values_per_frame, values, sizeof(double) *
16903                    n_particles * n_values_per_frame);
16904         }
16905         else
16906         {
16907             memcpy(data->values, values, sizeof(double) * n_particles *
16908                    n_values_per_frame);
16909         }
16910     }
16911     else
16912     {
16913         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16914         {
16915             stat = tng_data_block_add(tng_data, block_id, block_name,
16916                                       TNG_DOUBLE_DATA, block_type_flag,
16917                                       n_frames, n_values_per_frame,
16918                                       stride_length, compression, 0);
16919             if(stat != TNG_SUCCESS)
16920             {
16921                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16922                        __FILE__, __LINE__);
16923                 return(stat);
16924             }
16925             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16926             {
16927                 data = &frame_set->tr_data[frame_set->
16928                                               n_data_blocks - 1];
16929             }
16930             else
16931             {
16932                 data = &tng_data->non_tr_data[tng_data->
16933                                                  n_data_blocks - 1];
16934             }
16935             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16936                                          stride_length, n_values_per_frame);
16937             if(stat != TNG_SUCCESS)
16938             {
16939                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16940                        __FILE__, __LINE__);
16941                 return(stat);
16942             }
16943         }
16944         /* FIXME: Here we must be able to handle modified n_particles as well. */
16945         else if(n_frames > data->n_frames)
16946         {
16947             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16948                                          data->stride_length, n_values_per_frame);
16949             if(stat != TNG_SUCCESS)
16950             {
16951                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16952                        __FILE__, __LINE__);
16953                 return(stat);
16954             }
16955         }
16956
16957         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16958         {
16959             stride_length = data->stride_length;
16960
16961             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16962             {
16963                 data->first_frame_with_data = frame_nr;
16964                 frame_pos = 0;
16965             }
16966             else
16967             {
16968                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16969             }
16970
16971             memcpy((char *)data->values + sizeof(double) * frame_pos *
16972                    n_values_per_frame, values, sizeof(double) *
16973                    n_values_per_frame);
16974         }
16975         else
16976         {
16977             memcpy(data->values, values, sizeof(double) * n_values_per_frame);
16978         }
16979     }
16980
16981     return(TNG_SUCCESS);
16982 }
16983
16984 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
16985                 (const tng_trajectory_t tng_data,
16986                  const int64_t frame_nr,
16987                  const float *positions)
16988 {
16989     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16990     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16991
16992     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
16993                                   TNG_TRAJ_POSITIONS, "POSITIONS",
16994                                   TNG_PARTICLE_BLOCK_DATA,
16995                                   TNG_TNG_COMPRESSION));
16996 }
16997
16998 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
16999                 (const tng_trajectory_t tng_data,
17000                  const int64_t frame_nr,
17001                  const double *positions)
17002 {
17003     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17004     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17005
17006     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
17007                                          TNG_TRAJ_POSITIONS, "POSITIONS",
17008                                          TNG_PARTICLE_BLOCK_DATA,
17009                                          TNG_TNG_COMPRESSION));
17010 }
17011
17012 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
17013                 (const tng_trajectory_t tng_data,
17014                  const int64_t frame_nr,
17015                  const float *velocities)
17016 {
17017     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17018     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17019
17020     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
17021                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
17022                                   TNG_PARTICLE_BLOCK_DATA,
17023                                   TNG_TNG_COMPRESSION));
17024 }
17025
17026 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
17027                 (const tng_trajectory_t tng_data,
17028                  const int64_t frame_nr,
17029                  const double *velocities)
17030 {
17031     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17032     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17033
17034     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
17035                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
17036                                          TNG_PARTICLE_BLOCK_DATA,
17037                                          TNG_TNG_COMPRESSION));
17038 }
17039
17040 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
17041                 (const tng_trajectory_t tng_data,
17042                  const int64_t frame_nr,
17043                  const float *forces)
17044 {
17045     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17046     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17047
17048     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
17049                                   TNG_TRAJ_FORCES, "FORCES",
17050                                   TNG_PARTICLE_BLOCK_DATA,
17051                                   TNG_GZIP_COMPRESSION));
17052 }
17053
17054 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
17055                 (const tng_trajectory_t tng_data,
17056                  const int64_t frame_nr,
17057                  const double *forces)
17058 {
17059     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17060     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17061
17062     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
17063                                          TNG_TRAJ_FORCES, "FORCES",
17064                                          TNG_PARTICLE_BLOCK_DATA,
17065                                          TNG_GZIP_COMPRESSION));
17066 }
17067
17068 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
17069                 (const tng_trajectory_t tng_data,
17070                  const int64_t frame_nr,
17071                  const float *box_shape)
17072 {
17073     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17074     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17075
17076     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
17077                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17078                                   TNG_NON_PARTICLE_BLOCK_DATA,
17079                                   TNG_GZIP_COMPRESSION));
17080 }
17081
17082 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
17083                 (const tng_trajectory_t tng_data,
17084                  const int64_t frame_nr,
17085                  const double *box_shape)
17086 {
17087     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17088     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17089
17090     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
17091                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17092                                          TNG_NON_PARTICLE_BLOCK_DATA,
17093                                          TNG_GZIP_COMPRESSION));
17094 }
17095
17096 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
17097                 (const tng_trajectory_t tng_data,
17098                  const int64_t frame_nr,
17099                  const double time,
17100                  const float *values,
17101                  const int64_t n_values_per_frame,
17102                  const int64_t block_id,
17103                  const char *block_name,
17104                  const char particle_dependency,
17105                  const char compression)
17106 {
17107     tng_trajectory_frame_set_t frame_set;
17108     tng_function_status stat;
17109
17110     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17111     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17112     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17113     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17114
17115     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
17116                                   block_id, block_name,
17117                                   particle_dependency,
17118                                   compression);
17119
17120     if(stat != TNG_SUCCESS)
17121     {
17122         return(stat);
17123     }
17124
17125     frame_set = &tng_data->current_trajectory_frame_set;
17126
17127     /* first_frame_time is -1 when it is not yet set. */
17128     if(frame_set->first_frame_time < -0.1)
17129     {
17130         if(frame_nr > frame_set->first_frame)
17131         {
17132             stat = tng_frame_set_first_frame_time_set(tng_data,
17133                                                       time -
17134                                                       (frame_nr -
17135                                                        frame_set->first_frame) *
17136                                                       tng_data->time_per_frame);
17137         }
17138         else
17139         {
17140             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17141         }
17142     }
17143     return(stat);
17144 }
17145
17146 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
17147                 (const tng_trajectory_t tng_data,
17148                  const int64_t frame_nr,
17149                  const double time,
17150                  const double *values,
17151                  const int64_t n_values_per_frame,
17152                  const int64_t block_id,
17153                  const char *block_name,
17154                  const char particle_dependency,
17155                  const char compression)
17156 {
17157     tng_trajectory_frame_set_t frame_set;
17158     tng_function_status stat;
17159
17160     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17161     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17162     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17163     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17164
17165     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
17166                                          block_id, block_name,
17167                                          particle_dependency,
17168                                          compression);
17169
17170     if(stat != TNG_SUCCESS)
17171     {
17172         return(stat);
17173     }
17174
17175     frame_set = &tng_data->current_trajectory_frame_set;
17176
17177     /* first_frame_time is -1 when it is not yet set. */
17178     if(frame_set->first_frame_time < -0.1)
17179     {
17180         if(frame_nr > frame_set->first_frame)
17181         {
17182             stat = tng_frame_set_first_frame_time_set(tng_data,
17183                                                       time -
17184                                                       (frame_nr -
17185                                                        frame_set->first_frame) *
17186                                                       tng_data->time_per_frame);
17187         }
17188         else
17189         {
17190             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17191         }
17192     }
17193     return(stat);
17194 }
17195
17196 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
17197                 (const tng_trajectory_t tng_data,
17198                  const int64_t frame_nr,
17199                  const double time,
17200                  const float *positions)
17201 {
17202     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17203     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17204     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17205     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17206
17207     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
17208                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
17209                                             TNG_PARTICLE_BLOCK_DATA,
17210                                             TNG_TNG_COMPRESSION));
17211 }
17212
17213 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
17214                 (const tng_trajectory_t tng_data,
17215                  const int64_t frame_nr,
17216                  const double time,
17217                  const double *positions)
17218 {
17219     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17220     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17221     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17222     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17223
17224     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17225                                                    positions, 3,
17226                                                    TNG_TRAJ_POSITIONS,
17227                                                    "POSITIONS",
17228                                                    TNG_PARTICLE_BLOCK_DATA,
17229                                                    TNG_TNG_COMPRESSION));
17230 }
17231
17232 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
17233                 (const tng_trajectory_t tng_data,
17234                  const int64_t frame_nr,
17235                  const double time,
17236                  const float *velocities)
17237 {
17238     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17239     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17240     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17241     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17242
17243     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
17244                                             velocities, 3,
17245                                             TNG_TRAJ_VELOCITIES,
17246                                             "VELOCITIES",
17247                                             TNG_PARTICLE_BLOCK_DATA,
17248                                             TNG_TNG_COMPRESSION));
17249 }
17250
17251 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
17252                 (const tng_trajectory_t tng_data,
17253                  const int64_t frame_nr,
17254                  const double time,
17255                  const double *velocities)
17256 {
17257     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17258     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17259     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17260     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17261
17262     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17263                                                    velocities, 3,
17264                                                    TNG_TRAJ_VELOCITIES,
17265                                                    "VELOCITIES",
17266                                                    TNG_PARTICLE_BLOCK_DATA,
17267                                                    TNG_TNG_COMPRESSION));
17268 }
17269
17270 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
17271                 (const tng_trajectory_t tng_data,
17272                  const int64_t frame_nr,
17273                  const double time,
17274                  const float *forces)
17275 {
17276     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17277     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17278     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17279     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17280
17281     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
17282                                             3, TNG_TRAJ_FORCES, "FORCES",
17283                                             TNG_PARTICLE_BLOCK_DATA,
17284                                             TNG_GZIP_COMPRESSION));
17285 }
17286
17287 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
17288                 (const tng_trajectory_t tng_data,
17289                  const int64_t frame_nr,
17290                  const double time,
17291                  const double *forces)
17292 {
17293     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17294     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17295     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17296     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17297
17298     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17299                                                    forces, 3,
17300                                                    TNG_TRAJ_FORCES, "FORCES",
17301                                                    TNG_PARTICLE_BLOCK_DATA,
17302                                                    TNG_GZIP_COMPRESSION));
17303 }
17304
17305 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
17306                 (const tng_trajectory_t tng_data,
17307                  const int64_t frame_nr,
17308                  const double time,
17309                  const float *box_shape)
17310 {
17311     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17312     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17313     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17314     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17315
17316     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
17317                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17318                                             TNG_NON_PARTICLE_BLOCK_DATA,
17319                                             TNG_GZIP_COMPRESSION));
17320 }
17321
17322 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
17323                 (const tng_trajectory_t tng_data,
17324                  const int64_t frame_nr,
17325                  const double time,
17326                  const double *box_shape)
17327 {
17328     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17329     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17330     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17331     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17332
17333     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
17334                                                    time, box_shape, 9,
17335                                                    TNG_TRAJ_BOX_SHAPE,
17336                                                    "BOX SHAPE",
17337                                                    TNG_NON_PARTICLE_BLOCK_DATA,
17338                                                    TNG_GZIP_COMPRESSION));
17339 }
17340
17341 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
17342                 (const tng_trajectory_t tng_data,
17343                  const int64_t block_id,
17344                  int64_t *codec_id,
17345                  double *factor)
17346 {
17347     tng_trajectory_frame_set_t frame_set;
17348     tng_data_t data = 0;
17349     tng_function_status stat;
17350     int64_t i;
17351     int block_type = -1;
17352
17353     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17354     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
17355     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
17356
17357     frame_set = &tng_data->current_trajectory_frame_set;
17358
17359     stat = tng_particle_data_find(tng_data, block_id, &data);
17360     if(stat == TNG_SUCCESS)
17361     {
17362         block_type = TNG_PARTICLE_BLOCK_DATA;
17363     }
17364     else
17365     {
17366         stat = tng_data_find(tng_data, block_id, &data);
17367         if(stat == TNG_SUCCESS)
17368         {
17369             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
17370         }
17371         else
17372         {
17373             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17374             if(stat != TNG_SUCCESS)
17375             {
17376                 return(stat);
17377             }
17378             stat = tng_particle_data_find(tng_data, block_id, &data);
17379             if(stat == TNG_SUCCESS)
17380             {
17381                 block_type = TNG_PARTICLE_BLOCK_DATA;
17382             }
17383             else
17384             {
17385                 stat = tng_data_find(tng_data, block_id, &data);
17386                 if(stat == TNG_SUCCESS)
17387                 {
17388                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
17389                 }
17390                 else
17391                 {
17392                     return(stat);
17393                 }
17394             }
17395         }
17396     }
17397     if(block_type == TNG_PARTICLE_BLOCK_DATA)
17398     {
17399         if(data->last_retrieved_frame < 0)
17400         {
17401             i = data->first_frame_with_data;
17402         }
17403         else
17404         {
17405             i = data->last_retrieved_frame;
17406         }
17407     }
17408     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
17409     {
17410         if(data->last_retrieved_frame < 0)
17411         {
17412             i = data->first_frame_with_data;
17413         }
17414         else
17415         {
17416             i = data->last_retrieved_frame;
17417         }
17418     }
17419     else
17420     {
17421         return(TNG_FAILURE);
17422     }
17423     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17424     {
17425         stat = tng_frame_set_of_frame_find(tng_data, i);
17426         if(stat != TNG_SUCCESS)
17427         {
17428             return(stat);
17429         }
17430         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17431         if(stat != TNG_SUCCESS)
17432         {
17433             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17434                 __FILE__, __LINE__);
17435             return(stat);
17436         }
17437     }
17438     if(block_type == TNG_PARTICLE_BLOCK_DATA)
17439     {
17440         *codec_id = data->codec_id;
17441         *factor   = data->compression_multiplier;
17442     }
17443     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
17444     {
17445         *codec_id = data->codec_id;
17446         *factor   = data->compression_multiplier;
17447     }
17448     return(TNG_SUCCESS);
17449 }
17450
17451 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
17452                 (const tng_trajectory_t tng_data,
17453                  int64_t current_frame,
17454                  const int64_t n_requested_data_block_ids,
17455                  const int64_t *requested_data_block_ids,
17456                  int64_t *next_frame,
17457                  int64_t *n_data_blocks_in_next_frame,
17458                  int64_t **data_block_ids_in_next_frame)
17459 {
17460     tng_trajectory_frame_set_t frame_set;
17461     tng_function_status stat;
17462     tng_data_t data;
17463     tng_gen_block_t block;
17464     int64_t i, j, block_id, *temp;
17465     int64_t data_frame, frame_diff, min_diff;
17466     int64_t size, frame_set_file_pos;
17467     int found, read_all = 0;
17468     int64_t file_pos;
17469
17470     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17471     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
17472     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
17473     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
17474
17475     if(n_requested_data_block_ids)
17476     {
17477         TNG_ASSERT(requested_data_block_ids, "TNG library: If the number of requested data blocks is > 0 then the array of data block IDs must not be NULL.");
17478         size = sizeof(int64_t) * n_requested_data_block_ids;
17479         temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
17480         if(!temp)
17481         {
17482             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
17483                     __FILE__, __LINE__);
17484             free(*data_block_ids_in_next_frame);
17485             *data_block_ids_in_next_frame = 0;
17486             return(TNG_CRITICAL);
17487         }
17488         *data_block_ids_in_next_frame = temp;
17489     }
17490
17491     frame_set = &tng_data->current_trajectory_frame_set;
17492
17493     current_frame += 1;
17494
17495     if(current_frame < frame_set->first_frame ||
17496        current_frame >= frame_set->first_frame + frame_set->n_frames)
17497     {
17498         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
17499         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
17500         if(stat != TNG_SUCCESS)
17501         {
17502             /* If the frame set search found the frame set after the starting
17503              * frame set there is a gap in the frame sets. So, even if the frame
17504              * was not found the next frame with data is still in the found
17505              * frame set. */
17506             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
17507                frame_set_file_pos)
17508             {
17509                 return(stat);
17510             }
17511             current_frame = frame_set->first_frame;
17512         }
17513     }
17514
17515     /* Check for data blocks only if they have not already been found. */
17516     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
17517     {
17518         file_pos = ftello(tng_data->input_file);
17519         if(file_pos < tng_data->input_file_len)
17520         {
17521             tng_block_init(&block);
17522             stat = tng_block_header_read(tng_data, block);
17523             while(file_pos < tng_data->input_file_len &&
17524                 stat != TNG_CRITICAL &&
17525                 block->id != TNG_TRAJECTORY_FRAME_SET &&
17526                 block->id != -1)
17527             {
17528                 stat = tng_block_read_next(tng_data, block,
17529                                         TNG_USE_HASH);
17530                 if(stat != TNG_CRITICAL)
17531                 {
17532                     file_pos = ftello(tng_data->input_file);
17533                     if(file_pos < tng_data->input_file_len)
17534                     {
17535                         stat = tng_block_header_read(tng_data, block);
17536                     }
17537                 }
17538             }
17539             tng_block_destroy(&block);
17540             if(stat == TNG_CRITICAL)
17541             {
17542                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
17543                         file_pos, __FILE__, __LINE__);
17544                 return(stat);
17545             }
17546         }
17547         read_all = 1;
17548     }
17549
17550     min_diff = -1;
17551
17552     *n_data_blocks_in_next_frame = 0;
17553
17554     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
17555     {
17556         data = &frame_set->tr_particle_data[i];
17557         block_id = data->block_id;
17558
17559         if(n_requested_data_block_ids > 0)
17560         {
17561             found = 0;
17562             for(j = 0; j < n_requested_data_block_ids; j++)
17563             {
17564                 if(block_id == requested_data_block_ids[j])
17565                 {
17566                     found = 1;
17567                     break;
17568                 }
17569             }
17570             if(!found)
17571             {
17572                 continue;
17573             }
17574         }
17575
17576         if(!read_all && (data->last_retrieved_frame < frame_set->first_frame ||
17577            data->last_retrieved_frame >=
17578            frame_set->first_frame + frame_set->n_frames))
17579         {
17580             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
17581                                                                       TNG_USE_HASH, block_id);
17582             if(stat == TNG_CRITICAL)
17583             {
17584                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17585                     __FILE__, __LINE__);
17586                 return(stat);
17587             }
17588             if(stat == TNG_FAILURE)
17589             {
17590                 continue;
17591             }
17592         }
17593         if(frame_set->first_frame != current_frame &&
17594            data->last_retrieved_frame >= 0)
17595         {
17596             data_frame = data->last_retrieved_frame + data->stride_length;
17597         }
17598         else
17599         {
17600             data_frame = data->first_frame_with_data;
17601         }
17602         frame_diff = data_frame - current_frame;
17603         if(frame_diff < 0)
17604         {
17605             continue;
17606         }
17607         if(min_diff == -1 || frame_diff <= min_diff)
17608         {
17609             if(frame_diff < min_diff)
17610             {
17611                 *n_data_blocks_in_next_frame = 1;
17612             }
17613             else
17614             {
17615                 *n_data_blocks_in_next_frame += 1;
17616             }
17617             if(n_requested_data_block_ids <= 0)
17618             {
17619                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
17620                 temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
17621                 if(!temp)
17622                 {
17623                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
17624                             __FILE__, __LINE__);
17625                     free(*data_block_ids_in_next_frame);
17626                     *data_block_ids_in_next_frame = 0;
17627                     return(TNG_CRITICAL);
17628                 }
17629                 *data_block_ids_in_next_frame = temp;
17630             }
17631             else
17632             {
17633                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
17634             }
17635             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
17636
17637             min_diff = frame_diff;
17638         }
17639     }
17640     for(i = 0; i < frame_set->n_data_blocks; i++)
17641     {
17642         data = &frame_set->tr_data[i];
17643         block_id = data->block_id;
17644
17645         if(n_requested_data_block_ids > 0)
17646         {
17647             found = 0;
17648             for(j = 0; j < n_requested_data_block_ids; j++)
17649             {
17650                 if(block_id == requested_data_block_ids[j])
17651                 {
17652                     found = 1;
17653                     break;
17654                 }
17655             }
17656             if(!found)
17657             {
17658                 continue;
17659             }
17660         }
17661
17662         if(!read_all && (data->last_retrieved_frame < frame_set->first_frame ||
17663            data->last_retrieved_frame >=
17664            frame_set->first_frame + frame_set->n_frames))
17665         {
17666             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
17667                                                                       TNG_USE_HASH, block_id);
17668             if(stat == TNG_CRITICAL)
17669             {
17670                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17671                     __FILE__, __LINE__);
17672                 return(stat);
17673             }
17674             if(stat == TNG_FAILURE)
17675             {
17676                 continue;
17677             }
17678         }
17679         if(frame_set->first_frame != current_frame &&
17680            data->last_retrieved_frame >= 0)
17681         {
17682             data_frame = data->last_retrieved_frame + data->stride_length;
17683         }
17684         else
17685         {
17686             data_frame = data->first_frame_with_data;
17687         }
17688         frame_diff = data_frame - current_frame;
17689         if(frame_diff < 0)
17690         {
17691             continue;
17692         }
17693         if(min_diff == -1 || frame_diff <= min_diff)
17694         {
17695             if(frame_diff < min_diff)
17696             {
17697                 *n_data_blocks_in_next_frame = 1;
17698             }
17699             else
17700             {
17701                 *n_data_blocks_in_next_frame += 1;
17702             }
17703             if(n_requested_data_block_ids <= 0)
17704             {
17705                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
17706                 temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
17707                 if(!temp)
17708                 {
17709                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
17710                             __FILE__, __LINE__);
17711                     free(*data_block_ids_in_next_frame);
17712                     *data_block_ids_in_next_frame = 0;
17713                     return(TNG_CRITICAL);
17714                 }
17715                 *data_block_ids_in_next_frame = temp;
17716             }
17717             else
17718             {
17719                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
17720             }
17721             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
17722
17723             min_diff = frame_diff;
17724         }
17725     }
17726     if(min_diff < 0)
17727     {
17728         return(TNG_FAILURE);
17729     }
17730     *next_frame = current_frame + min_diff;
17731
17732     return(TNG_SUCCESS);
17733 }
17734
17735 /*
17736 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
17737                 (const tng_trajectory_t tng_data,
17738                  int64_t *n_data_blocks,
17739                  int64_t **data_block_ids,
17740                  char ***data_block_names,
17741                  int64_t **stride_lengths,
17742                  int64_t **n_values_per_frame,
17743                  char **block_types,
17744                  char **dependencies,
17745                  char **compressions)
17746 {
17747     tng_gen_block_t block;
17748     int64_t orig_file_pos, file_pos;
17749
17750     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17751     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
17752     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
17753     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
17754     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
17755
17756     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
17757     {
17758         return(TNG_CRITICAL);
17759     }
17760
17761     orig_file_pos = ftello(tng_data->input_file);
17762
17763     fseeko(tng_data->input_file, 0, SEEK_SET);
17764     file_pos = 0;
17765
17766     *n_data_blocks = 0;
17767
17768     tng_block_init(&block);
17769
17770     while(file_pos < tng_data->input_file_len &&
17771           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
17772     {
17773         if(block->id > TNG_TRAJECTORY_FRAME_SET)
17774         {
17775
17776         }
17777         file_pos += (block->block_contents_size + block->header_contents_size);
17778         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
17779     }
17780
17781     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
17782
17783     return(TNG_SUCCESS);
17784 }
17785 */
17786 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
17787                 (const tng_trajectory_t tng_data,
17788                  const int64_t prev_frame)
17789 {
17790     tng_function_status stat;
17791     FILE *temp = tng_data->input_file;
17792
17793     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17794     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
17795
17796     tng_data->input_file = tng_data->output_file;
17797
17798     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
17799     if(stat != TNG_SUCCESS)
17800     {
17801         return(stat);
17802     }
17803
17804     tng_data->current_trajectory_frame_set_output_file_pos =
17805     tng_data->current_trajectory_frame_set_input_file_pos;
17806
17807     tng_data->input_file = temp;
17808
17809     return(TNG_SUCCESS);
17810 }
17811
17812 tng_function_status DECLSPECDLLEXPORT tng_util_num_frames_with_data_of_block_id_get
17813                 (const tng_trajectory_t tng_data,
17814                  const int64_t block_id,
17815                  int64_t *n_frames)
17816 {
17817     int64_t curr_file_pos, first_frame_set_file_pos, curr_n_frames;
17818     tng_function_status stat;
17819
17820     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17821
17822     *n_frames = 0;
17823
17824     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
17825     {
17826         return(TNG_CRITICAL);
17827     }
17828
17829     first_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
17830     curr_file_pos = ftello(tng_data->input_file);
17831     fseeko(tng_data->input_file, first_frame_set_file_pos, SEEK_SET);
17832
17833     stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames);
17834
17835     while(stat == TNG_SUCCESS && tng_data->current_trajectory_frame_set.next_frame_set_file_pos != -1)
17836     {
17837         *n_frames += curr_n_frames;
17838         fseeko(tng_data->input_file,
17839                tng_data->current_trajectory_frame_set.next_frame_set_file_pos,
17840                SEEK_SET);
17841         stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames);
17842     }
17843     if(stat == TNG_SUCCESS)
17844     {
17845         *n_frames += curr_n_frames;
17846     }
17847     fseeko(tng_data->input_file, curr_file_pos, SEEK_SET);
17848     if(stat == TNG_CRITICAL)
17849     {
17850         return(TNG_CRITICAL);
17851     }
17852     return(TNG_SUCCESS);
17853 }