Updated TNG to version 1.8
[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 tng_function_status DECLSPECDLLEXPORT tng_version_major
6842                 (const tng_trajectory_t tng_data,
6843                  int *version)
6844 {
6845     (void)tng_data;
6846
6847     *version = TNG_VERSION_MAJOR;
6848
6849     return(TNG_SUCCESS);
6850 }
6851
6852 tng_function_status DECLSPECDLLEXPORT tng_version_minor
6853                 (const tng_trajectory_t tng_data,
6854                  int *version)
6855 {
6856     (void)tng_data;
6857
6858     *version = TNG_VERSION_MINOR;
6859
6860     return(TNG_SUCCESS);
6861 }
6862
6863 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
6864                 (const tng_trajectory_t tng_data,
6865                  int *patch_level)
6866 {
6867     (void)tng_data;
6868
6869     *patch_level = TNG_VERSION_PATCHLEVEL;
6870
6871     return(TNG_SUCCESS);
6872 }
6873
6874 tng_function_status DECLSPECDLLEXPORT tng_version
6875                 (const tng_trajectory_t tng_data,
6876                  char *version,
6877                  const int max_len)
6878 {
6879     (void)tng_data;
6880     TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
6881
6882     TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
6883
6884     return(TNG_SUCCESS);
6885 }
6886
6887 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
6888                 (const tng_trajectory_t tng_data,
6889                  const char *name,
6890                  tng_molecule_t *molecule)
6891 {
6892     int64_t id;
6893
6894     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6895     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
6896
6897     /* Set ID to the ID of the last molecule + 1 */
6898     if(tng_data->n_molecules)
6899     {
6900         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
6901     }
6902     else
6903     {
6904         id = 1;
6905     }
6906
6907     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
6908 }
6909
6910 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
6911                 (const tng_trajectory_t tng_data,
6912                  const char *name,
6913                  const int64_t id,
6914                  tng_molecule_t *molecule)
6915 {
6916     tng_molecule_t new_molecules;
6917     int64_t *new_molecule_cnt_list;
6918     tng_function_status stat = TNG_SUCCESS;
6919
6920     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6921     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
6922
6923     new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
6924                                             sizeof(struct tng_molecule) *
6925                                             (tng_data->n_molecules + 1));
6926
6927     if(!new_molecules)
6928     {
6929         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6930                 __FILE__, __LINE__);
6931         free(tng_data->molecules);
6932         tng_data->molecules = 0;
6933         return(TNG_CRITICAL);
6934     }
6935
6936     new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
6937                                                sizeof(int64_t) *
6938                                                (tng_data->n_molecules + 1));
6939
6940     if(!new_molecule_cnt_list)
6941     {
6942         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6943                 __FILE__, __LINE__);
6944         free(tng_data->molecule_cnt_list);
6945         tng_data->molecule_cnt_list = 0;
6946         free(new_molecules);
6947         return(TNG_CRITICAL);
6948     }
6949
6950     tng_data->molecules = new_molecules;
6951     tng_data->molecule_cnt_list = new_molecule_cnt_list;
6952
6953     *molecule = &new_molecules[tng_data->n_molecules];
6954
6955     tng_molecule_init(tng_data, *molecule);
6956     tng_molecule_name_set(tng_data, *molecule, name);
6957
6958     /* FIXME: Should this be a function argument instead? */
6959     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
6960
6961     (*molecule)->id = id;
6962
6963     tng_data->n_molecules++;
6964
6965     return(stat);
6966 }
6967
6968 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
6969                 (const tng_trajectory_t tng_data,
6970                  tng_molecule_t *molecule_p)
6971 {
6972     int64_t *new_molecule_cnt_list, id;
6973     tng_molecule_t new_molecules, molecule;
6974
6975     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6976
6977     /* Set ID to the ID of the last molecule + 1 */
6978     if(tng_data->n_molecules)
6979     {
6980         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
6981     }
6982     else
6983     {
6984         id = 1;
6985     }
6986
6987     new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
6988                                             sizeof(struct tng_molecule) *
6989                                             (tng_data->n_molecules + 1));
6990
6991     if(!new_molecules)
6992     {
6993         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6994                 __FILE__, __LINE__);
6995         free(tng_data->molecules);
6996         tng_data->molecules = 0;
6997         return(TNG_CRITICAL);
6998     }
6999
7000     new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
7001                                                sizeof(int64_t) *
7002                                                (tng_data->n_molecules + 1));
7003
7004     if(!new_molecule_cnt_list)
7005     {
7006         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7007                 __FILE__, __LINE__);
7008         free(tng_data->molecule_cnt_list);
7009         tng_data->molecule_cnt_list = 0;
7010         free(new_molecules);
7011         return(TNG_CRITICAL);
7012     }
7013
7014     molecule = *molecule_p;
7015
7016     tng_data->molecules = new_molecules;
7017     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7018
7019     new_molecules[tng_data->n_molecules] = *molecule;
7020
7021     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7022
7023     free(*molecule_p);
7024
7025     molecule = &new_molecules[tng_data->n_molecules];
7026
7027     *molecule_p = molecule;
7028
7029     molecule->id = id;
7030
7031     tng_data->n_molecules++;
7032
7033     return(TNG_SUCCESS);
7034 }
7035
7036 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
7037                                           const tng_molecule_t molecule,
7038                                           char *name,
7039                                           const int max_len)
7040 {
7041     (void) tng_data;
7042     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7043     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7044
7045     strncpy(name, molecule->name, max_len - 1);
7046     name[max_len - 1] = 0;
7047
7048     if(strlen(molecule->name) > (unsigned int)max_len - 1)
7049     {
7050         return(TNG_FAILURE);
7051     }
7052     return(TNG_SUCCESS);
7053 }
7054
7055 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
7056                 (const tng_trajectory_t tng_data,
7057                  const tng_molecule_t molecule,
7058                  const char *new_name)
7059 {
7060     unsigned int len;
7061     (void)tng_data;
7062
7063     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7064     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7065
7066     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7067
7068     /* If the currently stored string length is not enough to store the new
7069      * string it is freed and reallocated. */
7070     if(molecule->name && strlen(molecule->name) < len)
7071     {
7072         free(molecule->name);
7073         molecule->name = 0;
7074     }
7075     if(!molecule->name)
7076     {
7077         molecule->name = (char *)malloc(len);
7078         if(!molecule->name)
7079         {
7080             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7081                     __FILE__, __LINE__);
7082             return(TNG_CRITICAL);
7083         }
7084     }
7085
7086     strncpy(molecule->name, new_name, len);
7087
7088     return(TNG_SUCCESS);
7089 }
7090
7091 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
7092                 (const tng_trajectory_t tng_data,
7093                  const tng_molecule_t molecule,
7094                  int64_t *cnt)
7095 {
7096     int64_t i, index = -1;
7097
7098     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7099     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
7100
7101     for(i = 0; i < tng_data->n_molecules; i++)
7102     {
7103         if(&tng_data->molecules[i] == molecule)
7104         {
7105             index = i;
7106             break;
7107         }
7108     }
7109     if(index == -1)
7110     {
7111         return(TNG_FAILURE);
7112     }
7113     *cnt = tng_data->molecule_cnt_list[index];
7114
7115     return(TNG_SUCCESS);
7116 }
7117
7118 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
7119                 (const tng_trajectory_t tng_data,
7120                  const tng_molecule_t molecule,
7121                  const int64_t cnt)
7122 {
7123     int64_t i, old_cnt, index = -1;
7124
7125     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7126
7127     for(i = 0; i < tng_data->n_molecules; i++)
7128     {
7129         if(&tng_data->molecules[i] == molecule)
7130         {
7131             index = i;
7132             break;
7133         }
7134     }
7135     if(index == -1)
7136     {
7137         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
7138                __FILE__, __LINE__);
7139         return(TNG_FAILURE);
7140     }
7141     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
7142     {
7143         old_cnt = tng_data->molecule_cnt_list[index];
7144         tng_data->molecule_cnt_list[index] = cnt;
7145
7146         tng_data->n_particles += (cnt-old_cnt) *
7147                                  tng_data->molecules[index].n_atoms;
7148     }
7149     else
7150     {
7151         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
7152         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
7153
7154         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
7155                 tng_data->molecules[index].n_atoms;
7156     }
7157
7158     return(TNG_SUCCESS);
7159 }
7160
7161 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
7162                 (const tng_trajectory_t tng_data,
7163                  const char *name,
7164                  const int64_t nr,
7165                  tng_molecule_t *molecule)
7166 {
7167     int64_t i, n_molecules;
7168
7169     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7170     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7171     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7172
7173     n_molecules = tng_data->n_molecules;
7174
7175     for(i = n_molecules - 1; i >= 0; i--)
7176     {
7177         *molecule = &tng_data->molecules[i];
7178         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
7179         {
7180             if(nr == -1 || nr == (*molecule)->id)
7181             {
7182                 return(TNG_SUCCESS);
7183             }
7184         }
7185     }
7186
7187     *molecule = 0;
7188
7189     return(TNG_FAILURE);
7190 }
7191
7192 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
7193                 (const tng_trajectory_t tng_data,
7194                  const int64_t index,
7195                  tng_molecule_t *molecule)
7196 {
7197     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7198     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7199
7200     if(index >= tng_data->n_molecules)
7201     {
7202         *molecule = 0;
7203         return(TNG_FAILURE);
7204     }
7205     *molecule = &tng_data->molecules[index];
7206     return(TNG_SUCCESS);
7207 }
7208
7209 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(const tng_trajectory_t tng_data_src,
7210                                                                const tng_trajectory_t tng_data_dest)
7211 {
7212     tng_molecule_t molecule, molecule_temp;
7213     tng_chain_t chain, chain_temp;
7214     tng_residue_t residue, residue_temp;
7215     tng_atom_t atom, atom_temp;
7216     tng_bond_t bond_temp;
7217     tng_function_status stat;
7218     int64_t i, j, k, l, *list_temp;
7219
7220     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
7221     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
7222
7223     for(i = 0; i < tng_data_dest->n_molecules; i++)
7224     {
7225         molecule = &tng_data_dest->molecules[i];
7226         tng_molecule_destroy(tng_data_dest, molecule);
7227     }
7228
7229     tng_data_dest->n_molecules = 0;
7230     tng_data_dest->n_particles = 0;
7231
7232     molecule_temp = (tng_molecule_t)realloc(tng_data_dest->molecules,
7233                                             sizeof(struct tng_molecule) * tng_data_src->n_molecules);
7234     if(!molecule_temp)
7235     {
7236         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7237                 __FILE__, __LINE__);
7238         free(tng_data_dest->molecules);
7239         tng_data_dest->molecules = 0;
7240         return(TNG_CRITICAL);
7241     }
7242     list_temp = (int64_t *)realloc(tng_data_dest->molecule_cnt_list,
7243                                    sizeof(int64_t) * tng_data_src->n_molecules);
7244     if(!list_temp)
7245     {
7246         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7247                 __FILE__, __LINE__);
7248         free(tng_data_dest->molecule_cnt_list);
7249         tng_data_dest->molecule_cnt_list = 0;
7250         free(molecule_temp);
7251         return(TNG_CRITICAL);
7252     }
7253
7254     tng_data_dest->molecules = molecule_temp;
7255     tng_data_dest->molecule_cnt_list = list_temp;
7256
7257     for(i = 0; i < tng_data_src->n_molecules; i++)
7258     {
7259         molecule = &tng_data_src->molecules[i];
7260         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
7261                                      &molecule_temp);
7262         if(stat != TNG_SUCCESS)
7263         {
7264             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
7265                    __FILE__, __LINE__);
7266             return(stat);
7267         }
7268         molecule_temp->quaternary_str = molecule->quaternary_str;
7269         for(j = 0; j < molecule->n_chains; j++)
7270         {
7271             chain = &molecule->chains[j];
7272             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
7273                                                chain->name, chain->id,
7274                                                &chain_temp);
7275             if(stat != TNG_SUCCESS)
7276             {
7277                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
7278                        __FILE__, __LINE__);
7279                 return(stat);
7280             }
7281             for(k = 0; k < chain->n_residues; k++)
7282             {
7283                 residue = &chain->residues[k];
7284                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
7285                                                   residue->name, residue->id,
7286                                                   &residue_temp);
7287                 if(stat != TNG_SUCCESS)
7288                 {
7289                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
7290                            __FILE__, __LINE__);
7291                     return(stat);
7292                 }
7293                 for(l = 0; l < residue->n_atoms; l++)
7294                 {
7295                     atom = &molecule->atoms[residue->atoms_offset + l];
7296                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
7297                                                      atom->name, atom->atom_type,
7298                                                      atom->id, &atom_temp);
7299                     if(stat != TNG_SUCCESS)
7300                     {
7301                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
7302                            __FILE__, __LINE__);
7303                         return(stat);
7304                     }
7305                 }
7306             }
7307         }
7308         molecule_temp->n_bonds = molecule->n_bonds;
7309         if(molecule->n_bonds > 0)
7310         {
7311             bond_temp = (tng_bond_t)realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
7312                                             molecule->n_bonds);
7313             if(!bond_temp)
7314             {
7315                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7316                         __FILE__, __LINE__);
7317                 free(molecule_temp->bonds);
7318                 molecule_temp->n_bonds = 0;
7319                 return(TNG_CRITICAL);
7320             }
7321             molecule_temp->bonds = bond_temp;
7322             for(j = 0; j < molecule->n_bonds; j++)
7323             {
7324                 molecule_temp->bonds[j] = molecule->bonds[j];
7325             }
7326         }
7327         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
7328                                     tng_data_src->molecule_cnt_list[i]);
7329         if(stat != TNG_SUCCESS)
7330         {
7331             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
7332                    __FILE__, __LINE__);
7333             return(stat);
7334         }
7335     }
7336     return(TNG_SUCCESS);
7337 }
7338
7339 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
7340                 (const tng_trajectory_t tng_data,
7341                  const tng_molecule_t molecule,
7342                  int64_t *n)
7343 {
7344     (void) tng_data;
7345     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7346     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7347
7348     *n = molecule->n_chains;
7349
7350     return(TNG_SUCCESS);
7351 }
7352
7353 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
7354                 (const tng_trajectory_t tng_data,
7355                  const tng_molecule_t molecule,
7356                  const int64_t index,
7357                  tng_chain_t *chain)
7358 {
7359     (void) tng_data;
7360     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7361     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7362
7363     if(index >= molecule->n_chains)
7364     {
7365         *chain = 0;
7366         return(TNG_FAILURE);
7367     }
7368     *chain = &molecule->chains[index];
7369     return(TNG_SUCCESS);
7370 }
7371
7372 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
7373                 (const tng_trajectory_t tng_data,
7374                  const tng_molecule_t molecule,
7375                  int64_t *n)
7376 {
7377     (void) tng_data;
7378     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7379     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7380
7381     *n = molecule->n_residues;
7382
7383     return(TNG_SUCCESS);
7384 }
7385
7386 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
7387                 (const tng_trajectory_t tng_data,
7388                  const tng_molecule_t molecule,
7389                  const int64_t index,
7390                  tng_residue_t *residue)
7391 {
7392     (void) tng_data;
7393     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7394     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7395
7396     if(index >= molecule->n_residues)
7397     {
7398         *residue = 0;
7399         return(TNG_FAILURE);
7400     }
7401     *residue = &molecule->residues[index];
7402     return(TNG_SUCCESS);
7403 }
7404
7405 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
7406                 (const tng_trajectory_t tng_data,
7407                  const tng_molecule_t molecule,
7408                  int64_t *n)
7409 {
7410     (void) tng_data;
7411     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7412     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7413
7414     *n = molecule->n_atoms;
7415
7416     return(TNG_SUCCESS);
7417 }
7418
7419 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
7420                 (const tng_trajectory_t tng_data,
7421                  const tng_molecule_t molecule,
7422                  const int64_t index,
7423                  tng_atom_t *atom)
7424 {
7425     (void) tng_data;
7426     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7427     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7428
7429     if(index >= molecule->n_atoms)
7430     {
7431         *atom = 0;
7432         return(TNG_FAILURE);
7433     }
7434     *atom = &molecule->atoms[index];
7435     return(TNG_SUCCESS);
7436 }
7437
7438 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
7439                 (const tng_trajectory_t tng_data,
7440                  const tng_molecule_t molecule,
7441                  const char *name,
7442                  const int64_t nr,
7443                  tng_chain_t *chain)
7444 {
7445     int64_t i, n_chains;
7446     (void)tng_data;
7447
7448     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7449     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7450
7451     n_chains = molecule->n_chains;
7452
7453     for(i = n_chains - 1; i >= 0; i--)
7454     {
7455         *chain = &molecule->chains[i];
7456         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
7457         {
7458             if(nr == -1 || nr == (*chain)->id)
7459             {
7460                 return(TNG_SUCCESS);
7461             }
7462         }
7463     }
7464
7465     *chain = 0;
7466
7467     return(TNG_FAILURE);
7468 }
7469
7470 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
7471                 (const tng_trajectory_t tng_data,
7472                  const tng_molecule_t molecule,
7473                  const char *name,
7474                  tng_chain_t *chain)
7475 {
7476     int64_t id;
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     /* Set ID to the ID of the last chain + 1 */
7482     if(molecule->n_chains)
7483     {
7484         id = molecule->chains[molecule->n_chains-1].id + 1;
7485     }
7486     else
7487     {
7488         id = 1;
7489     }
7490
7491     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
7492                                        id, chain));
7493 }
7494
7495 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
7496                 (const tng_trajectory_t tng_data,
7497                  const tng_molecule_t molecule,
7498                  const char *name,
7499                  const int64_t id,
7500                  tng_chain_t *chain)
7501 {
7502     tng_chain_t new_chains;
7503     tng_function_status stat = TNG_SUCCESS;
7504
7505     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7506     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7507
7508     new_chains = (tng_chain_t)realloc(molecule->chains,
7509                                       sizeof(struct tng_chain) *
7510                                       (molecule->n_chains + 1));
7511
7512     if(!new_chains)
7513     {
7514         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7515                 __FILE__, __LINE__);
7516         free(molecule->chains);
7517         molecule->chains = 0;
7518         return(TNG_CRITICAL);
7519     }
7520
7521     molecule->chains = new_chains;
7522
7523     *chain = &new_chains[molecule->n_chains];
7524     (*chain)->name = 0;
7525
7526     tng_chain_name_set(tng_data, *chain, name);
7527
7528     (*chain)->molecule = molecule;
7529     (*chain)->n_residues = 0;
7530
7531     molecule->n_chains++;
7532
7533     (*chain)->id = id;
7534
7535     return(stat);
7536 }
7537
7538 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
7539                 (const tng_trajectory_t tng_data,
7540                  const tng_molecule_t molecule,
7541                  const int64_t from_atom_id,
7542                  const int64_t to_atom_id,
7543                  tng_bond_t *bond)
7544 {
7545     tng_bond_t new_bonds;
7546     (void)tng_data;
7547
7548     new_bonds = (tng_bond_t)realloc(molecule->bonds,
7549                                     sizeof(struct tng_bond) *
7550                                     (molecule->n_bonds + 1));
7551
7552     if(!new_bonds)
7553     {
7554         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7555                 __FILE__, __LINE__);
7556         *bond = 0;
7557         free(molecule->bonds);
7558         molecule->bonds = 0;
7559         return(TNG_CRITICAL);
7560     }
7561
7562     molecule->bonds = new_bonds;
7563
7564     *bond = &new_bonds[molecule->n_bonds];
7565
7566     (*bond)->from_atom_id = from_atom_id;
7567     (*bond)->to_atom_id = to_atom_id;
7568
7569     molecule->n_bonds++;
7570
7571     return(TNG_SUCCESS);
7572 }
7573
7574 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
7575                 (const tng_trajectory_t tng_data,
7576                  const tng_molecule_t molecule,
7577                  const char *name,
7578                  const int64_t id,
7579                  tng_atom_t *atom)
7580 {
7581     int64_t i, n_atoms;
7582     (void)tng_data;
7583
7584     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7585
7586     n_atoms = molecule->n_atoms;
7587
7588     for(i = n_atoms - 1; i >= 0; i--)
7589     {
7590         *atom = &molecule->atoms[i];
7591         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
7592         {
7593             if(id == -1 || id == (*atom)->id)
7594             {
7595                 return(TNG_SUCCESS);
7596             }
7597         }
7598     }
7599
7600     *atom = 0;
7601
7602     return(TNG_FAILURE);
7603 }
7604
7605 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
7606                                        const tng_chain_t chain,
7607                                        char *name,
7608                                        const int max_len)
7609 {
7610     (void) tng_data;
7611     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7612     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7613
7614     strncpy(name, chain->name, max_len - 1);
7615     name[max_len - 1] = 0;
7616
7617     if(strlen(chain->name) > (unsigned int)max_len - 1)
7618     {
7619         return(TNG_FAILURE);
7620     }
7621     return(TNG_SUCCESS);
7622 }
7623
7624 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
7625                 (const tng_trajectory_t tng_data,
7626                  const tng_chain_t chain,
7627                  const char *new_name)
7628 {
7629     unsigned int len;
7630     (void)tng_data;
7631
7632     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7633
7634     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7635
7636     /* If the currently stored string length is not enough to store the new
7637      * string it is freed and reallocated. */
7638     if(chain->name && strlen(chain->name) < len)
7639     {
7640         free(chain->name);
7641         chain->name = 0;
7642     }
7643     if(!chain->name)
7644     {
7645         chain->name = (char *)malloc(len);
7646         if(!chain->name)
7647         {
7648             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7649                     __FILE__, __LINE__);
7650             return(TNG_CRITICAL);
7651         }
7652     }
7653
7654     strncpy(chain->name, new_name, len);
7655
7656     return(TNG_SUCCESS);
7657 }
7658
7659 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
7660                 (const tng_trajectory_t tng_data,
7661                  const tng_chain_t chain,
7662                  int64_t *n)
7663 {
7664     (void) tng_data;
7665     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7666     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7667
7668     *n = chain->n_residues;
7669
7670     return(TNG_SUCCESS);
7671 }
7672
7673 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
7674                 (const tng_trajectory_t tng_data,
7675                  const tng_chain_t chain,
7676                  const int64_t index,
7677                  tng_residue_t *residue)
7678 {
7679     (void) tng_data;
7680     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7681     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7682
7683     if(index >= chain->n_residues)
7684     {
7685         *residue = 0;
7686         return(TNG_FAILURE);
7687     }
7688     *residue = &chain->residues[index];
7689     return(TNG_SUCCESS);
7690 }
7691
7692 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
7693                 (const tng_trajectory_t tng_data,
7694                  const tng_chain_t chain,
7695                  const char *name,
7696                  const int64_t id,
7697                  tng_residue_t *residue)
7698 {
7699     int64_t i, n_residues;
7700     (void)tng_data;
7701
7702     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7703
7704     n_residues = chain->n_residues;
7705
7706     for(i = n_residues - 1; i >= 0; i--)
7707     {
7708         *residue = &chain->residues[i];
7709         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
7710         {
7711             if(id == -1 || id == (*residue)->id)
7712             {
7713                 return(TNG_SUCCESS);
7714             }
7715         }
7716     }
7717
7718     *residue = 0;
7719
7720     return(TNG_FAILURE);
7721 }
7722
7723 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
7724                 (const tng_trajectory_t tng_data,
7725                  const tng_chain_t chain,
7726                  const char *name,
7727                  tng_residue_t *residue)
7728 {
7729     int64_t id;
7730
7731     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7732     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7733
7734     /* Set ID to the ID of the last residue + 1 */
7735     if(chain->n_residues)
7736     {
7737         id = chain->residues[chain->n_residues-1].id + 1;
7738     }
7739     else
7740     {
7741         id = 0;
7742     }
7743
7744     return(tng_chain_residue_w_id_add(tng_data, chain, name,
7745                                       id, residue));
7746 }
7747
7748 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
7749                 (const tng_trajectory_t tng_data,
7750                  const tng_chain_t chain,
7751                  const char *name,
7752                  const int64_t id,
7753                  tng_residue_t *residue)
7754 {
7755     int64_t curr_index;
7756     tng_residue_t new_residues, temp_residue, last_residue;
7757     tng_molecule_t molecule = chain->molecule;
7758     tng_function_status stat = TNG_SUCCESS;
7759
7760     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7761     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7762
7763     if(chain->n_residues)
7764     {
7765         curr_index = chain->residues - molecule->residues;
7766     }
7767     else
7768     {
7769         curr_index = -1;
7770     }
7771
7772     new_residues = (tng_residue_t)realloc(molecule->residues,
7773                                           sizeof(struct tng_residue) *
7774                                           (molecule->n_residues + 1));
7775
7776     if(!new_residues)
7777     {
7778         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7779                 __FILE__, __LINE__);
7780         free(molecule->residues);
7781         molecule->residues = 0;
7782         return(TNG_CRITICAL);
7783     }
7784
7785     molecule->residues = new_residues;
7786
7787     if(curr_index != -1)
7788     {
7789         chain->residues = new_residues + curr_index;
7790         if(molecule->n_residues)
7791         {
7792             last_residue = &new_residues[molecule->n_residues - 1];
7793
7794             temp_residue = chain->residues + (chain->n_residues - 1);
7795             /* Make space in list of residues to add the new residues together with the other
7796             * residues of this chain */
7797             if(temp_residue != last_residue)
7798             {
7799                 ++temp_residue;
7800                 memmove(temp_residue + 1, temp_residue,
7801                         last_residue - temp_residue);
7802             }
7803         }
7804     }
7805     else
7806     {
7807         curr_index = molecule->n_residues;
7808     }
7809
7810     *residue = &molecule->residues[curr_index + chain->n_residues];
7811
7812     tng_molecule_chains_residue_pointers_update(tng_data, molecule);
7813
7814     (*residue)->name = 0;
7815     tng_residue_name_set(tng_data, *residue, name);
7816
7817     (*residue)->chain = chain;
7818     (*residue)->n_atoms = 0;
7819     (*residue)->atoms_offset = 0;
7820
7821     chain->n_residues++;
7822     molecule->n_residues++;
7823
7824     (*residue)->id = id;
7825
7826     return(stat);
7827 }
7828
7829 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
7830                                          const tng_residue_t residue,
7831                                          char *name,
7832                                          const int max_len)
7833 {
7834     (void) tng_data;
7835     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
7836     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7837
7838     strncpy(name, residue->name, max_len - 1);
7839     name[max_len - 1] = 0;
7840
7841     if(strlen(residue->name) > (unsigned int)max_len - 1)
7842     {
7843         return(TNG_FAILURE);
7844     }
7845     return(TNG_SUCCESS);
7846 }
7847
7848 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(const tng_trajectory_t tng_data,
7849                                                            const tng_residue_t residue,
7850                                                            const char *new_name)
7851 {
7852     unsigned int len;
7853     (void)tng_data;
7854
7855     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7856     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
7857
7858     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7859
7860     /* If the currently stored string length is not enough to store the new
7861      * string it is freed and reallocated. */
7862     if(residue->name && strlen(residue->name) < len)
7863     {
7864         free(residue->name);
7865         residue->name = 0;
7866     }
7867     if(!residue->name)
7868     {
7869         residue->name = (char *)malloc(len);
7870         if(!residue->name)
7871         {
7872             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7873                     __FILE__, __LINE__);
7874             return(TNG_CRITICAL);
7875         }
7876     }
7877
7878     strncpy(residue->name, new_name, len);
7879
7880     return(TNG_SUCCESS);
7881 }
7882
7883 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
7884                 (const tng_trajectory_t tng_data,
7885                  const tng_residue_t residue,
7886                  int64_t *n)
7887 {
7888     (void) tng_data;
7889     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
7890     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7891
7892     *n = residue->n_atoms;
7893
7894     return(TNG_SUCCESS);
7895 }
7896
7897 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
7898                 (const tng_trajectory_t tng_data,
7899                  const tng_residue_t residue,
7900                  const int64_t index,
7901                  tng_atom_t *atom)
7902 {
7903     tng_chain_t chain;
7904     tng_molecule_t molecule;
7905
7906     (void) tng_data;
7907     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7908     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7909
7910     if(index >= residue->n_atoms)
7911     {
7912         *atom = 0;
7913         return(TNG_FAILURE);
7914     }
7915     chain = residue->chain;
7916     molecule = chain->molecule;
7917
7918     if(index + residue->atoms_offset >= molecule->n_atoms)
7919     {
7920         *atom = 0;
7921         return(TNG_FAILURE);
7922     }
7923
7924     *atom = &molecule->atoms[residue->atoms_offset + index];
7925     return(TNG_SUCCESS);
7926 }
7927
7928 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
7929                 (const tng_trajectory_t tng_data,
7930                  const tng_residue_t residue,
7931                  const char *atom_name,
7932                  const char *atom_type,
7933                  tng_atom_t *atom)
7934 {
7935     int64_t id;
7936
7937     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7938     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
7939     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
7940
7941     /* Set ID to the ID of the last atom + 1 */
7942     if(residue->chain->molecule->n_atoms)
7943     {
7944         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
7945     }
7946     else
7947     {
7948         id = 0;
7949     }
7950
7951     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
7952                                      id, atom));
7953 }
7954
7955 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
7956                 (const tng_trajectory_t tng_data,
7957                  const tng_residue_t residue,
7958                  const char *atom_name,
7959                  const char *atom_type,
7960                  const int64_t id,
7961                  tng_atom_t *atom)
7962 {
7963     tng_atom_t new_atoms;
7964     tng_molecule_t molecule = residue->chain->molecule;
7965     tng_function_status stat = TNG_SUCCESS;
7966
7967     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7968     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
7969     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
7970
7971     if(!residue->n_atoms)
7972     {
7973         residue->atoms_offset = molecule->n_atoms;
7974     }
7975
7976     new_atoms = (tng_atom_t)realloc(molecule->atoms,
7977                                     sizeof(struct tng_atom) *
7978                                     (molecule->n_atoms + 1));
7979
7980     if(!new_atoms)
7981     {
7982         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7983                 __FILE__, __LINE__);
7984         free(molecule->atoms);
7985         molecule->atoms = 0;
7986         return(TNG_CRITICAL);
7987     }
7988
7989     molecule->atoms = new_atoms;
7990
7991     *atom = &new_atoms[molecule->n_atoms];
7992
7993     tng_atom_init(*atom);
7994     tng_atom_name_set(tng_data, *atom, atom_name);
7995     tng_atom_type_set(tng_data, *atom, atom_type);
7996
7997     (*atom)->residue = residue;
7998
7999     residue->n_atoms++;
8000     molecule->n_atoms++;
8001
8002     (*atom)->id = id;
8003
8004     return(stat);
8005 }
8006
8007 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
8008                                                          tng_molecule_t *molecule_p)
8009 {
8010     *molecule_p = (tng_molecule_t)malloc(sizeof(struct tng_molecule));
8011     if(!*molecule_p)
8012     {
8013         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8014                 __FILE__, __LINE__);
8015         return(TNG_CRITICAL);
8016     }
8017
8018     tng_molecule_init(tng_data, *molecule_p);
8019
8020     return(TNG_SUCCESS);
8021 }
8022
8023 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
8024                                                         tng_molecule_t *molecule_p)
8025 {
8026     if(!*molecule_p)
8027     {
8028         return(TNG_SUCCESS);
8029     }
8030
8031     tng_molecule_destroy(tng_data, *molecule_p);
8032
8033     free(*molecule_p);
8034     *molecule_p = 0;
8035
8036     return(TNG_SUCCESS);
8037 }
8038
8039 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
8040                                                         const tng_molecule_t molecule)
8041 {
8042     (void)tng_data;
8043     molecule->quaternary_str = 1;
8044     molecule->name = 0;
8045     molecule->n_chains = 0;
8046     molecule->chains = 0;
8047     molecule->n_residues = 0;
8048     molecule->residues = 0;
8049     molecule->n_atoms = 0;
8050     molecule->atoms = 0;
8051     molecule->n_bonds = 0;
8052     molecule->bonds = 0;
8053
8054     return(TNG_SUCCESS);
8055 }
8056
8057 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
8058                                                            const tng_molecule_t molecule)
8059 {
8060     int64_t i;
8061     (void)tng_data;
8062
8063     if(molecule->name)
8064     {
8065         free(molecule->name);
8066         molecule->name = 0;
8067     }
8068
8069     if(molecule->chains)
8070     {
8071         for(i = 0; i < molecule->n_chains; i++)
8072         {
8073             if(molecule->chains[i].name)
8074             {
8075                 free(molecule->chains[i].name);
8076                 molecule->chains[i].name = 0;
8077             }
8078         }
8079         free(molecule->chains);
8080         molecule->chains = 0;
8081     }
8082     molecule->n_chains = 0;
8083
8084     if(molecule->residues)
8085     {
8086         for(i = 0; i < molecule->n_residues; i++)
8087         {
8088             if(molecule->residues[i].name)
8089             {
8090                 free(molecule->residues[i].name);
8091                 molecule->residues[i].name = 0;
8092             }
8093         }
8094         free(molecule->residues);
8095         molecule->residues = 0;
8096     }
8097     molecule->n_residues = 0;
8098
8099     if(molecule->atoms)
8100     {
8101         for(i = 0; i < molecule->n_atoms; i++)
8102         {
8103             tng_atom_destroy(&molecule->atoms[i]);
8104         }
8105         free(molecule->atoms);
8106         molecule->atoms = 0;
8107     }
8108     molecule->n_atoms = 0;
8109
8110     if(molecule->bonds)
8111     {
8112         free(molecule->bonds);
8113         molecule->bonds = 0;
8114     }
8115     molecule->n_bonds = 0;
8116
8117     return(TNG_SUCCESS);
8118 }
8119
8120 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
8121                 (const tng_trajectory_t tng_data,
8122                  const int64_t nr,
8123                  char *name,
8124                  const int max_len)
8125 {
8126     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8127     tng_molecule_t mol;
8128     tng_bool found = TNG_FALSE;
8129
8130     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8131     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8132
8133     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8134
8135     if(!molecule_cnt_list)
8136     {
8137         return(TNG_FAILURE);
8138     }
8139
8140     for(i = 0; i < tng_data->n_molecules; i++)
8141     {
8142         mol = &tng_data->molecules[i];
8143         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8144         {
8145             cnt += mol->n_atoms * molecule_cnt_list[i];
8146             continue;
8147         }
8148         found = TNG_TRUE;
8149         break;
8150     }
8151     if(!found)
8152     {
8153         return(TNG_FAILURE);
8154     }
8155
8156     strncpy(name, mol->name, max_len - 1);
8157     name[max_len - 1] = 0;
8158
8159     if(strlen(mol->name) > (unsigned int)max_len - 1)
8160     {
8161         return(TNG_FAILURE);
8162     }
8163     return(TNG_SUCCESS);
8164 }
8165
8166 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
8167                 (const tng_trajectory_t tng_data,
8168                  const int64_t nr,
8169                  int64_t *id)
8170 {
8171     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8172     tng_molecule_t mol;
8173     tng_bool found = TNG_FALSE;
8174
8175     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8176     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8177
8178     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8179
8180     if(!molecule_cnt_list)
8181     {
8182         return(TNG_FAILURE);
8183     }
8184
8185     for(i = 0; i < tng_data->n_molecules; i++)
8186     {
8187         mol = &tng_data->molecules[i];
8188         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8189         {
8190             cnt += mol->n_atoms * molecule_cnt_list[i];
8191             continue;
8192         }
8193         found = TNG_TRUE;
8194         break;
8195     }
8196     if(!found)
8197     {
8198         return(TNG_FAILURE);
8199     }
8200
8201     *id = mol->id;
8202
8203     return(TNG_SUCCESS);
8204 }
8205
8206 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
8207                 (const tng_trajectory_t tng_data,
8208                  int64_t *n_bonds,
8209                  int64_t **from_atoms,
8210                  int64_t **to_atoms)
8211 {
8212     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
8213     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
8214     tng_molecule_t mol;
8215     tng_bond_t bond;
8216
8217     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8218     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
8219     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
8220     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
8221
8222     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8223
8224     if(!molecule_cnt_list)
8225     {
8226         return(TNG_FAILURE);
8227     }
8228
8229     *n_bonds = 0;
8230     /* First count the total number of bonds to allocate memory */
8231     for(i = 0; i < tng_data->n_molecules; i++)
8232     {
8233         mol = &tng_data->molecules[i];
8234         mol_cnt = molecule_cnt_list[i];
8235         *n_bonds += mol_cnt * mol->n_bonds;
8236     }
8237     if(*n_bonds == 0)
8238     {
8239         return(TNG_SUCCESS);
8240     }
8241
8242     *from_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
8243     if(!*from_atoms)
8244     {
8245         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8246                 __FILE__, __LINE__);
8247         return(TNG_CRITICAL);
8248     }
8249     *to_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
8250     if(!*to_atoms)
8251     {
8252         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8253                 __FILE__, __LINE__);
8254         free(*from_atoms);
8255         *from_atoms = 0;
8256         return(TNG_CRITICAL);
8257     }
8258
8259     cnt = 0;
8260     for(i = 0; i < tng_data->n_molecules; i++)
8261     {
8262         mol = &tng_data->molecules[i];
8263         mol_cnt = molecule_cnt_list[i];
8264         for(j = 0; j < mol_cnt; j++)
8265         {
8266             for(k = 0; k < mol->n_bonds; k++)
8267             {
8268                 bond = &mol->bonds[k];
8269                 from_atom = atom_cnt + bond->from_atom_id;
8270                 to_atom = atom_cnt + bond->to_atom_id;
8271                 (*from_atoms)[cnt] = from_atom;
8272                 (*to_atoms)[cnt++] = to_atom;
8273             }
8274             atom_cnt += mol->n_atoms;
8275         }
8276     }
8277
8278     return(TNG_SUCCESS);
8279 }
8280
8281 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
8282                 (const tng_trajectory_t tng_data,
8283                  const int64_t nr,
8284                  char *name,
8285                  const int max_len)
8286 {
8287     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8288     tng_molecule_t mol;
8289     tng_atom_t atom;
8290     tng_bool found = TNG_FALSE;
8291
8292     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8293     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8294
8295     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8296
8297     if(!molecule_cnt_list)
8298     {
8299         return(TNG_FAILURE);
8300     }
8301
8302     for(i = 0; i < tng_data->n_molecules; i++)
8303     {
8304         mol = &tng_data->molecules[i];
8305         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8306         {
8307             cnt += mol->n_atoms * molecule_cnt_list[i];
8308             continue;
8309         }
8310         atom = &mol->atoms[nr % mol->n_atoms];
8311         found = TNG_TRUE;
8312         break;
8313     }
8314     if(!found)
8315     {
8316         return(TNG_FAILURE);
8317     }
8318     if(!atom->residue || !atom->residue->chain)
8319     {
8320         return(TNG_FAILURE);
8321     }
8322
8323     strncpy(name, atom->residue->chain->name, max_len - 1);
8324     name[max_len - 1] = 0;
8325
8326     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
8327     {
8328         return(TNG_FAILURE);
8329     }
8330     return(TNG_SUCCESS);
8331 }
8332
8333 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
8334                 (const tng_trajectory_t tng_data,
8335                  const int64_t nr,
8336                  char *name,
8337                  const int max_len)
8338 {
8339     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8340     tng_molecule_t mol;
8341     tng_atom_t atom;
8342     tng_bool found = TNG_FALSE;
8343
8344     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8345     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8346
8347     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8348
8349     if(!molecule_cnt_list)
8350     {
8351         return(TNG_FAILURE);
8352     }
8353
8354     for(i = 0; i < tng_data->n_molecules; i++)
8355     {
8356         mol = &tng_data->molecules[i];
8357         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8358         {
8359             cnt += mol->n_atoms * molecule_cnt_list[i];
8360             continue;
8361         }
8362         atom = &mol->atoms[nr % mol->n_atoms];
8363         found = TNG_TRUE;
8364         break;
8365     }
8366     if(!found)
8367     {
8368         return(TNG_FAILURE);
8369     }
8370     if(!atom->residue)
8371     {
8372         return(TNG_FAILURE);
8373     }
8374
8375     strncpy(name, atom->residue->name, max_len - 1);
8376     name[max_len - 1] = 0;
8377
8378     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
8379     {
8380         return(TNG_FAILURE);
8381     }
8382     return(TNG_SUCCESS);
8383 }
8384
8385 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
8386                 (const tng_trajectory_t tng_data,
8387                  const int64_t nr,
8388                  int64_t *id)
8389 {
8390     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8391     tng_molecule_t mol;
8392     tng_atom_t atom;
8393     tng_bool found = TNG_FALSE;
8394
8395     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8396     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8397
8398     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8399
8400     if(!molecule_cnt_list)
8401     {
8402         return(TNG_FAILURE);
8403     }
8404
8405     for(i = 0; i < tng_data->n_molecules; i++)
8406     {
8407         mol = &tng_data->molecules[i];
8408         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8409         {
8410             cnt += mol->n_atoms * molecule_cnt_list[i];
8411             continue;
8412         }
8413         atom = &mol->atoms[nr % mol->n_atoms];
8414         found = TNG_TRUE;
8415         break;
8416     }
8417     if(!found)
8418     {
8419         return(TNG_FAILURE);
8420     }
8421     if(!atom->residue)
8422     {
8423         return(TNG_FAILURE);
8424     }
8425
8426     *id = atom->residue->id;
8427
8428     return(TNG_SUCCESS);
8429 }
8430
8431 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
8432                 (const tng_trajectory_t tng_data,
8433                  const int64_t nr,
8434                  int64_t *id)
8435 {
8436     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
8437     tng_molecule_t mol;
8438     tng_atom_t atom;
8439     tng_bool found = TNG_FALSE;
8440
8441     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8442     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8443
8444     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8445
8446     if(!molecule_cnt_list)
8447     {
8448         return(TNG_FAILURE);
8449     }
8450
8451     for(i = 0; i < tng_data->n_molecules; i++)
8452     {
8453         mol = &tng_data->molecules[i];
8454         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8455         {
8456             cnt += mol->n_atoms * molecule_cnt_list[i];
8457             offset += mol->n_residues * molecule_cnt_list[i];
8458             continue;
8459         }
8460         atom = &mol->atoms[nr % mol->n_atoms];
8461         found = TNG_TRUE;
8462         break;
8463     }
8464     if(!found)
8465     {
8466         return(TNG_FAILURE);
8467     }
8468     if(!atom->residue)
8469     {
8470         return(TNG_FAILURE);
8471     }
8472
8473     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
8474
8475     *id = atom->residue->id + offset;
8476
8477     return(TNG_SUCCESS);
8478 }
8479
8480 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
8481                 (const tng_trajectory_t tng_data,
8482                  const int64_t nr,
8483                  char *name,
8484                  const int max_len)
8485 {
8486     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8487     tng_molecule_t mol;
8488     tng_atom_t atom;
8489     tng_bool found = TNG_FALSE;
8490
8491     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8492     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8493
8494     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8495
8496     if(!molecule_cnt_list)
8497     {
8498         return(TNG_FAILURE);
8499     }
8500
8501     for(i = 0; i < tng_data->n_molecules; i++)
8502     {
8503         mol = &tng_data->molecules[i];
8504         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8505         {
8506             cnt += mol->n_atoms * molecule_cnt_list[i];
8507             continue;
8508         }
8509         atom = &mol->atoms[nr % mol->n_atoms];
8510         found = TNG_TRUE;
8511         break;
8512     }
8513     if(!found)
8514     {
8515         return(TNG_FAILURE);
8516     }
8517
8518     strncpy(name, atom->name, max_len - 1);
8519     name[max_len - 1] = 0;
8520
8521     if(strlen(atom->name) > (unsigned int)max_len - 1)
8522     {
8523         return(TNG_FAILURE);
8524     }
8525     return(TNG_SUCCESS);
8526 }
8527
8528 tng_function_status tng_atom_type_of_particle_nr_get
8529                 (const tng_trajectory_t tng_data,
8530                  const int64_t nr,
8531                  char *type,
8532                  const int max_len)
8533 {
8534     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8535     tng_molecule_t mol;
8536     tng_atom_t atom;
8537     tng_bool found = TNG_FALSE;
8538
8539     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8540     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
8541
8542     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8543
8544     if(!molecule_cnt_list)
8545     {
8546         return(TNG_FAILURE);
8547     }
8548
8549     for(i = 0; i < tng_data->n_molecules; i++)
8550     {
8551         mol = &tng_data->molecules[i];
8552         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8553         {
8554             cnt += mol->n_atoms * molecule_cnt_list[i];
8555             continue;
8556         }
8557         atom = &mol->atoms[nr % mol->n_atoms];
8558         found = TNG_TRUE;
8559         break;
8560     }
8561     if(!found)
8562     {
8563         return(TNG_FAILURE);
8564     }
8565
8566     strncpy(type, atom->atom_type, max_len - 1);
8567     type[max_len - 1] = 0;
8568
8569     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
8570     {
8571         return(TNG_FAILURE);
8572     }
8573     return(TNG_SUCCESS);
8574 }
8575
8576 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
8577                 (const tng_trajectory_t tng_data,
8578                  const int64_t num_first_particle,
8579                  const int64_t n_particles,
8580                  const int64_t *mapping_table)
8581 {
8582     int64_t i;
8583     tng_particle_mapping_t mapping;
8584     tng_trajectory_frame_set_t frame_set;
8585
8586     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8587
8588     frame_set = &tng_data->current_trajectory_frame_set;
8589
8590     /* Sanity check of the particle ranges. Split into multiple if
8591      * statements for improved readability */
8592     for(i = 0; i < frame_set->n_mapping_blocks; i++)
8593     {
8594         mapping = &frame_set->mappings[i];
8595         if(num_first_particle >= mapping->num_first_particle &&
8596            num_first_particle < mapping->num_first_particle +
8597                                    mapping->n_particles)
8598         {
8599             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8600             return(TNG_FAILURE);
8601         }
8602         if(num_first_particle + n_particles >=
8603            mapping->num_first_particle &&
8604            num_first_particle + n_particles <
8605            mapping->num_first_particle + mapping->n_particles)
8606         {
8607             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8608             return(TNG_FAILURE);
8609         }
8610         if(mapping->num_first_particle >= num_first_particle &&
8611            mapping->num_first_particle < num_first_particle +
8612                                             n_particles)
8613         {
8614             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8615             return(TNG_FAILURE);
8616         }
8617         if(mapping->num_first_particle + mapping->n_particles >
8618            num_first_particle &&
8619            mapping->num_first_particle + mapping->n_particles <
8620            num_first_particle + n_particles)
8621         {
8622             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8623             return(TNG_FAILURE);
8624         }
8625     }
8626
8627     frame_set->n_mapping_blocks++;
8628
8629     mapping = (tng_particle_mapping_t)realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
8630                                               frame_set->n_mapping_blocks);
8631
8632     if(!mapping)
8633     {
8634         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8635                 __FILE__, __LINE__);
8636         free(frame_set->mappings);
8637         frame_set->mappings = 0;
8638         return(TNG_CRITICAL);
8639     }
8640     frame_set->mappings = mapping;
8641
8642     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
8643     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
8644
8645     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = (int64_t *)malloc(sizeof(int64_t) * n_particles);
8646     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
8647     {
8648         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8649                 __FILE__, __LINE__);
8650         return(TNG_CRITICAL);
8651     }
8652
8653     for(i=0; i<n_particles; i++)
8654     {
8655         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
8656     }
8657
8658     return(TNG_SUCCESS);
8659 }
8660
8661 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(const tng_trajectory_t tng_data)
8662 {
8663     tng_trajectory_frame_set_t frame_set;
8664     tng_particle_mapping_t mapping;
8665     int64_t i;
8666
8667     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8668
8669     frame_set = &tng_data->current_trajectory_frame_set;
8670
8671     if(frame_set->n_mapping_blocks && frame_set->mappings)
8672     {
8673         for(i = 0; i < frame_set->n_mapping_blocks; i++)
8674         {
8675             mapping = &frame_set->mappings[i];
8676             if(mapping->real_particle_numbers)
8677             {
8678                 free(mapping->real_particle_numbers);
8679                 mapping->real_particle_numbers = 0;
8680             }
8681         }
8682         free(frame_set->mappings);
8683         frame_set->mappings = 0;
8684         frame_set->n_mapping_blocks = 0;
8685     }
8686
8687     return(TNG_SUCCESS);
8688 }
8689
8690 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
8691 {
8692     time_t seconds;
8693     tng_trajectory_frame_set_t frame_set;
8694     tng_trajectory_t tng_data;
8695
8696     *tng_data_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
8697     if(!*tng_data_p)
8698     {
8699         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8700                 __FILE__, __LINE__);
8701         return(TNG_CRITICAL);
8702     }
8703
8704     tng_data = *tng_data_p;
8705
8706     frame_set = &tng_data->current_trajectory_frame_set;
8707
8708     tng_data->input_file_path = 0;
8709     tng_data->input_file = 0;
8710     tng_data->input_file_len = 0;
8711     tng_data->output_file_path = 0;
8712     tng_data->output_file = 0;
8713
8714     tng_data->first_program_name = 0;
8715     tng_data->first_user_name = 0;
8716     tng_data->first_computer_name = 0;
8717     tng_data->first_pgp_signature = 0;
8718     tng_data->last_program_name = 0;
8719     tng_data->last_user_name = 0;
8720     tng_data->last_computer_name = 0;
8721     tng_data->last_pgp_signature = 0;
8722     tng_data->forcefield_name = 0;
8723
8724     seconds = time(0);
8725     if ( seconds == -1)
8726     {
8727         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
8728     }
8729     else
8730     {
8731         tng_data->time = seconds;
8732     }
8733
8734     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
8735     tng_data->first_trajectory_frame_set_input_file_pos = -1;
8736     tng_data->last_trajectory_frame_set_input_file_pos = -1;
8737     tng_data->current_trajectory_frame_set_input_file_pos = -1;
8738     tng_data->first_trajectory_frame_set_output_file_pos = -1;
8739     tng_data->last_trajectory_frame_set_output_file_pos = -1;
8740     tng_data->current_trajectory_frame_set_output_file_pos = -1;
8741     tng_data->frame_set_n_frames = 100;
8742     tng_data->n_trajectory_frame_sets = 0;
8743     tng_data->medium_stride_length = 100;
8744     tng_data->long_stride_length = 10000;
8745
8746     tng_data->time_per_frame = -1;
8747
8748     tng_data->n_particle_data_blocks = 0;
8749     tng_data->n_data_blocks = 0;
8750
8751     tng_data->non_tr_particle_data = 0;
8752     tng_data->non_tr_data = 0;
8753
8754     tng_data->compress_algo_pos = 0;
8755     tng_data->compress_algo_vel = 0;
8756     tng_data->compression_precision = 1000;
8757     tng_data->distance_unit_exponential = -9;
8758
8759     frame_set->first_frame = -1;
8760     frame_set->n_mapping_blocks = 0;
8761     frame_set->mappings = 0;
8762     frame_set->molecule_cnt_list = 0;
8763
8764     frame_set->n_particle_data_blocks = 0;
8765     frame_set->n_data_blocks = 0;
8766
8767     frame_set->tr_particle_data = 0;
8768     frame_set->tr_data = 0;
8769
8770     frame_set->n_written_frames = 0;
8771     frame_set->n_unwritten_frames = 0;
8772
8773     frame_set->next_frame_set_file_pos = -1;
8774     frame_set->prev_frame_set_file_pos = -1;
8775     frame_set->medium_stride_next_frame_set_file_pos = -1;
8776     frame_set->medium_stride_prev_frame_set_file_pos = -1;
8777     frame_set->long_stride_next_frame_set_file_pos = -1;
8778     frame_set->long_stride_prev_frame_set_file_pos = -1;
8779
8780     frame_set->first_frame_time = -1;
8781
8782     tng_data->n_molecules = 0;
8783     tng_data->molecules = 0;
8784     tng_data->molecule_cnt_list = 0;
8785     tng_data->n_particles = 0;
8786
8787     {
8788       /* Check the endianness of the computer */
8789       static int32_t endianness_32 = 0x01234567;
8790       /* 0x01234567 */
8791       if ( *(const unsigned char*)&endianness_32 == 0x01 )
8792         {
8793           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
8794         }
8795
8796       /* 0x67452301 */
8797       else if( *(const unsigned char*)&endianness_32 == 0x67 )
8798         {
8799           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
8800
8801         }
8802
8803       /* 0x45670123 */
8804       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
8805         {
8806           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
8807         }
8808     }
8809     {
8810       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
8811       /* 0x0123456789ABCDEF */
8812       if ( *(const unsigned char*)&endianness_64 == 0x01 )
8813         {
8814           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
8815         }
8816
8817       /* 0xEFCDAB8967452301 */
8818       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
8819         {
8820           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
8821         }
8822
8823       /* 0x89ABCDEF01234567 */
8824       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
8825         {
8826           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
8827         }
8828
8829       /* 0x45670123CDEF89AB */
8830       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
8831         {
8832           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
8833         }
8834
8835       /* 0x23016745AB89EFCD */
8836       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
8837         {
8838           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
8839         }
8840     }
8841
8842     /* By default do not swap the byte order, i.e. keep the byte order of the
8843      * architecture. The input file endianness will be set when reading the
8844      * header. The output endianness can be changed - before the file is
8845      * written. */
8846     tng_data->input_endianness_swap_func_32 = 0;
8847     tng_data->input_endianness_swap_func_64 = 0;
8848     tng_data->output_endianness_swap_func_32 = 0;
8849     tng_data->output_endianness_swap_func_64 = 0;
8850
8851     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
8852     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
8853     tng_data->current_trajectory_frame_set.n_frames = 0;
8854
8855     return(TNG_SUCCESS);
8856 }
8857
8858 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
8859 {
8860     int64_t i, j, k, l;
8861     int64_t n_particles, n_values_per_frame;
8862     tng_trajectory_t tng_data = *tng_data_p;
8863     tng_trajectory_frame_set_t frame_set;
8864
8865     if(!*tng_data_p)
8866     {
8867         return(TNG_SUCCESS);
8868     }
8869
8870     frame_set = &tng_data->current_trajectory_frame_set;
8871
8872     if(tng_data->input_file)
8873     {
8874         if(tng_data->output_file == tng_data->input_file)
8875         {
8876             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
8877             tng_data->output_file = 0;
8878         }
8879         fclose(tng_data->input_file);
8880         tng_data->input_file = 0;
8881     }
8882
8883     if(tng_data->input_file_path)
8884     {
8885         free(tng_data->input_file_path);
8886         tng_data->input_file_path = 0;
8887     }
8888
8889     if(tng_data->output_file)
8890     {
8891         /* FIXME: Do not always write the hash */
8892         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
8893         fclose(tng_data->output_file);
8894         tng_data->output_file = 0;
8895     }
8896
8897     if(tng_data->output_file_path)
8898     {
8899         free(tng_data->output_file_path);
8900         tng_data->output_file_path = 0;
8901     }
8902
8903     if(tng_data->first_program_name)
8904     {
8905         free(tng_data->first_program_name);
8906         tng_data->first_program_name = 0;
8907     }
8908
8909     if(tng_data->last_program_name)
8910     {
8911         free(tng_data->last_program_name);
8912         tng_data->last_program_name = 0;
8913     }
8914
8915     if(tng_data->first_user_name)
8916     {
8917         free(tng_data->first_user_name);
8918         tng_data->first_user_name = 0;
8919     }
8920
8921     if(tng_data->last_user_name)
8922     {
8923         free(tng_data->last_user_name);
8924         tng_data->last_user_name = 0;
8925     }
8926
8927     if(tng_data->first_computer_name)
8928     {
8929         free(tng_data->first_computer_name);
8930         tng_data->first_computer_name = 0;
8931     }
8932
8933     if(tng_data->last_computer_name)
8934     {
8935         free(tng_data->last_computer_name);
8936         tng_data->last_computer_name = 0;
8937     }
8938
8939     if(tng_data->first_pgp_signature)
8940     {
8941         free(tng_data->first_pgp_signature);
8942         tng_data->first_pgp_signature = 0;
8943     }
8944
8945     if(tng_data->last_pgp_signature)
8946     {
8947         free(tng_data->last_pgp_signature);
8948         tng_data->last_pgp_signature = 0;
8949     }
8950
8951     if(tng_data->forcefield_name)
8952     {
8953         free(tng_data->forcefield_name);
8954         tng_data->forcefield_name = 0;
8955     }
8956
8957     tng_frame_set_particle_mapping_free(tng_data);
8958
8959     if(frame_set->molecule_cnt_list)
8960     {
8961         free(frame_set->molecule_cnt_list);
8962         frame_set->molecule_cnt_list = 0;
8963     }
8964
8965     if(tng_data->var_num_atoms_flag)
8966     {
8967         n_particles = frame_set->n_particles;
8968     }
8969     else
8970     {
8971         n_particles = tng_data->n_particles;
8972     }
8973
8974     if(tng_data->non_tr_particle_data)
8975     {
8976         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
8977         {
8978             if(tng_data->non_tr_particle_data[i].values)
8979             {
8980                 free(tng_data->non_tr_particle_data[i].values);
8981                 tng_data->non_tr_particle_data[i].values = 0;
8982             }
8983
8984             if(tng_data->non_tr_particle_data[i].strings)
8985             {
8986                 n_values_per_frame = tng_data->non_tr_particle_data[i].
8987                                      n_values_per_frame;
8988                 if(tng_data->non_tr_particle_data[i].strings[0])
8989                 {
8990                     for(j = 0; j < n_particles; j++)
8991                     {
8992                         if(tng_data->non_tr_particle_data[i].strings[0][j])
8993                         {
8994                             for(k = 0; k < n_values_per_frame; k++)
8995                             {
8996                                 if(tng_data->non_tr_particle_data[i].
8997                                    strings[0][j][k])
8998                                 {
8999                                     free(tng_data->non_tr_particle_data[i].
9000                                          strings[0][j][k]);
9001                                     tng_data->non_tr_particle_data[i].
9002                                     strings[0][j][k] = 0;
9003                                 }
9004                             }
9005                             free(tng_data->non_tr_particle_data[i].
9006                                  strings[0][j]);
9007                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
9008                         }
9009                     }
9010                     free(tng_data->non_tr_particle_data[i].strings[0]);
9011                     tng_data->non_tr_particle_data[i].strings[0] = 0;
9012                 }
9013                 free(tng_data->non_tr_particle_data[i].strings);
9014                 tng_data->non_tr_particle_data[i].strings = 0;
9015             }
9016
9017             if(tng_data->non_tr_particle_data[i].block_name)
9018             {
9019                 free(tng_data->non_tr_particle_data[i].block_name);
9020                 tng_data->non_tr_particle_data[i].block_name = 0;
9021             }
9022         }
9023         free(tng_data->non_tr_particle_data);
9024         tng_data->non_tr_particle_data = 0;
9025     }
9026
9027     if(tng_data->non_tr_data)
9028     {
9029         for(i = 0; i < tng_data->n_data_blocks; i++)
9030         {
9031             if(tng_data->non_tr_data[i].values)
9032             {
9033                 free(tng_data->non_tr_data[i].values);
9034                 tng_data->non_tr_data[i].values = 0;
9035             }
9036
9037             if(tng_data->non_tr_data[i].strings)
9038             {
9039                 n_values_per_frame = tng_data->non_tr_data[i].
9040                                      n_values_per_frame;
9041                 if(tng_data->non_tr_data[i].strings[0][0])
9042                 {
9043                     for(j = 0; j < n_values_per_frame; j++)
9044                     {
9045                         if(tng_data->non_tr_data[i].strings[0][0][j])
9046                         {
9047                             free(tng_data->non_tr_data[i].strings[0][0][j]);
9048                             tng_data->non_tr_data[i].strings[0][0][j] = 0;
9049                         }
9050                     }
9051                     free(tng_data->non_tr_data[i].strings[0][0]);
9052                     tng_data->non_tr_data[i].strings[0][0] = 0;
9053                 }
9054                 free(tng_data->non_tr_data[i].strings[0]);
9055                 tng_data->non_tr_data[i].strings[0] = 0;
9056                 free(tng_data->non_tr_data[i].strings);
9057                 tng_data->non_tr_data[i].strings = 0;
9058             }
9059
9060             if(tng_data->non_tr_data[i].block_name)
9061             {
9062                 free(tng_data->non_tr_data[i].block_name);
9063                 tng_data->non_tr_data[i].block_name = 0;
9064             }
9065         }
9066         free(tng_data->non_tr_data);
9067         tng_data->non_tr_data = 0;
9068     }
9069
9070     tng_data->n_particle_data_blocks = 0;
9071     tng_data->n_data_blocks = 0;
9072
9073     if(tng_data->compress_algo_pos)
9074     {
9075         free(tng_data->compress_algo_pos);
9076         tng_data->compress_algo_pos = 0;
9077     }
9078     if(tng_data->compress_algo_vel)
9079     {
9080         free(tng_data->compress_algo_vel);
9081         tng_data->compress_algo_vel = 0;
9082     }
9083
9084     if(frame_set->tr_particle_data)
9085     {
9086         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
9087         {
9088             if(frame_set->tr_particle_data[i].values)
9089             {
9090                 free(frame_set->tr_particle_data[i].values);
9091                 frame_set->tr_particle_data[i].values = 0;
9092             }
9093
9094             if(frame_set->tr_particle_data[i].strings)
9095             {
9096                 n_values_per_frame = frame_set->tr_particle_data[i].
9097                                      n_values_per_frame;
9098                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
9099                 {
9100                     if(frame_set->tr_particle_data[i].strings[j])
9101                     {
9102                         for(k = 0; k < n_particles; k++)
9103                         {
9104                             if(frame_set->tr_particle_data[i].
9105                                 strings[j][k])
9106                             {
9107                                 for(l = 0; l < n_values_per_frame; l++)
9108                                 {
9109                                     if(frame_set->tr_particle_data[i].
9110                                         strings[j][k][l])
9111                                     {
9112                                         free(frame_set->tr_particle_data[i].
9113                                                 strings[j][k][l]);
9114                                         frame_set->tr_particle_data[i].
9115                                         strings[j][k][l] = 0;
9116                                     }
9117                                 }
9118                                 free(frame_set->tr_particle_data[i].
9119                                         strings[j][k]);
9120                                 frame_set->tr_particle_data[i].
9121                                 strings[j][k] = 0;
9122                             }
9123                         }
9124                         free(frame_set->tr_particle_data[i].strings[j]);
9125                         frame_set->tr_particle_data[i].strings[j] = 0;
9126                     }
9127                 }
9128                 free(frame_set->tr_particle_data[i].strings);
9129                 frame_set->tr_particle_data[i].strings = 0;
9130             }
9131
9132             if(frame_set->tr_particle_data[i].block_name)
9133             {
9134                 free(frame_set->tr_particle_data[i].block_name);
9135                 frame_set->tr_particle_data[i].block_name = 0;
9136             }
9137         }
9138         free(frame_set->tr_particle_data);
9139         frame_set->tr_particle_data = 0;
9140     }
9141
9142     if(frame_set->tr_data)
9143     {
9144         for(i = 0; i < frame_set->n_data_blocks; i++)
9145         {
9146             if(frame_set->tr_data[i].values)
9147             {
9148                 free(frame_set->tr_data[i].values);
9149                 frame_set->tr_data[i].values = 0;
9150             }
9151
9152             if(frame_set->tr_data[i].strings)
9153             {
9154                 n_values_per_frame = frame_set->tr_data[i].
9155                                      n_values_per_frame;
9156                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
9157                 {
9158                     if(frame_set->tr_data[i].strings[j])
9159                     {
9160                         for(k = 0; k < n_values_per_frame; k++)
9161                         {
9162                             if(frame_set->tr_data[i].strings[j][k])
9163                             {
9164                                 free(frame_set->tr_data[i].strings[j][k]);
9165                                 frame_set->tr_data[i].strings[j][k] = 0;
9166                             }
9167                         }
9168                         free(frame_set->tr_data[i].strings[j]);
9169                         frame_set->tr_data[i].strings[j] = 0;
9170                     }
9171                 }
9172                 free(frame_set->tr_data[i].strings);
9173                 frame_set->tr_data[i].strings = 0;
9174             }
9175
9176             if(frame_set->tr_data[i].block_name)
9177             {
9178                 free(frame_set->tr_data[i].block_name);
9179                 frame_set->tr_data[i].block_name = 0;
9180             }
9181         }
9182         free(frame_set->tr_data);
9183         frame_set->tr_data = 0;
9184     }
9185
9186     frame_set->n_particle_data_blocks = 0;
9187     frame_set->n_data_blocks = 0;
9188
9189     if(tng_data->molecules)
9190     {
9191         for(i = 0; i < tng_data->n_molecules; i++)
9192         {
9193             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
9194         }
9195         free(tng_data->molecules);
9196         tng_data->molecules = 0;
9197         tng_data->n_molecules = 0;
9198     }
9199     if(tng_data->molecule_cnt_list)
9200     {
9201         free(tng_data->molecule_cnt_list);
9202         tng_data->molecule_cnt_list = 0;
9203     }
9204
9205     free(*tng_data_p);
9206     *tng_data_p = 0;
9207
9208     return(TNG_SUCCESS);
9209 }
9210
9211 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src
9212                 (const tng_trajectory_t src,
9213                  tng_trajectory_t *dest_p)
9214 {
9215     tng_trajectory_frame_set_t frame_set;
9216     tng_trajectory_t dest;
9217
9218     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
9219
9220     *dest_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
9221     if(!*dest_p)
9222     {
9223         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9224                 __FILE__, __LINE__);
9225         return(TNG_CRITICAL);
9226     }
9227
9228     dest = *dest_p;
9229
9230     frame_set = &dest->current_trajectory_frame_set;
9231
9232     if(src->input_file_path)
9233     {
9234         dest->input_file_path = (char *)malloc(strlen(src->input_file_path) + 1);
9235         if(!dest->input_file_path)
9236         {
9237             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9238                     __FILE__, __LINE__);
9239             return(TNG_CRITICAL);
9240         }
9241         strcpy(dest->input_file_path, src->input_file_path);
9242         dest->input_file_len = src->input_file_len;
9243     }
9244     else
9245     {
9246         dest->input_file_path = 0;
9247     }
9248     dest->input_file = 0;
9249     if(src->output_file_path)
9250     {
9251         dest->output_file_path = (char *)malloc(strlen(src->output_file_path) + 1);
9252         if(!dest->output_file_path)
9253         {
9254             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9255                     __FILE__, __LINE__);
9256             return(TNG_CRITICAL);
9257         }
9258         strcpy(dest->output_file_path, src->output_file_path);
9259     }
9260     else
9261     {
9262         dest->output_file_path = 0;
9263     }
9264     dest->output_file = 0;
9265
9266     dest->first_program_name = 0;
9267     dest->first_user_name = 0;
9268     dest->first_computer_name = 0;
9269     dest->first_pgp_signature = 0;
9270     dest->last_program_name = 0;
9271     dest->last_user_name = 0;
9272     dest->last_computer_name = 0;
9273     dest->last_pgp_signature = 0;
9274     dest->forcefield_name = 0;
9275
9276     dest->var_num_atoms_flag = src->var_num_atoms_flag;
9277     dest->first_trajectory_frame_set_input_file_pos =
9278     src->first_trajectory_frame_set_input_file_pos;
9279     dest->last_trajectory_frame_set_input_file_pos =
9280     src->last_trajectory_frame_set_input_file_pos;
9281     dest->current_trajectory_frame_set_input_file_pos =
9282     src->current_trajectory_frame_set_input_file_pos;
9283     dest->first_trajectory_frame_set_output_file_pos =
9284     src->first_trajectory_frame_set_output_file_pos;
9285     dest->last_trajectory_frame_set_output_file_pos =
9286     src->last_trajectory_frame_set_output_file_pos;
9287     dest->current_trajectory_frame_set_output_file_pos =
9288     src->current_trajectory_frame_set_output_file_pos;
9289     dest->frame_set_n_frames = src->frame_set_n_frames;
9290     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
9291     dest->medium_stride_length = src->medium_stride_length;
9292     dest->long_stride_length = src->long_stride_length;
9293
9294     dest->time_per_frame = src->time_per_frame;
9295
9296     /* Currently the non trajectory data blocks are not copied since it
9297      * can lead to problems when freeing memory in a parallel block. */
9298     dest->n_particle_data_blocks = 0;
9299     dest->n_data_blocks = 0;
9300     dest->non_tr_particle_data = 0;
9301     dest->non_tr_data = 0;
9302
9303     dest->compress_algo_pos = 0;
9304     dest->compress_algo_vel = 0;
9305     dest->distance_unit_exponential = -9;
9306     dest->compression_precision = 1000;
9307
9308     frame_set->n_mapping_blocks = 0;
9309     frame_set->mappings = 0;
9310     frame_set->molecule_cnt_list = 0;
9311
9312     frame_set->n_particle_data_blocks = 0;
9313     frame_set->n_data_blocks = 0;
9314
9315     frame_set->tr_particle_data = 0;
9316     frame_set->tr_data = 0;
9317
9318     frame_set->n_written_frames = 0;
9319     frame_set->n_unwritten_frames = 0;
9320
9321     frame_set->next_frame_set_file_pos = -1;
9322     frame_set->prev_frame_set_file_pos = -1;
9323     frame_set->medium_stride_next_frame_set_file_pos = -1;
9324     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9325     frame_set->long_stride_next_frame_set_file_pos = -1;
9326     frame_set->long_stride_prev_frame_set_file_pos = -1;
9327     frame_set->first_frame = -1;
9328
9329     dest->n_molecules = 0;
9330     dest->molecules = 0;
9331     dest->molecule_cnt_list = 0;
9332     dest->n_particles = src->n_particles;
9333
9334     dest->endianness_32 = src->endianness_32;
9335     dest->endianness_64 = src->endianness_64;
9336     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
9337     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
9338     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
9339     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
9340
9341     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9342     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9343     dest->current_trajectory_frame_set.n_frames = 0;
9344
9345     return(TNG_SUCCESS);
9346 }
9347
9348 tng_function_status DECLSPECDLLEXPORT tng_input_file_get
9349                 (const tng_trajectory_t tng_data,
9350                  char *file_name,
9351                  const int max_len)
9352 {
9353     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9354     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9355
9356     strncpy(file_name, tng_data->input_file_path, max_len - 1);
9357     file_name[max_len - 1] = 0;
9358
9359     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
9360     {
9361         return(TNG_FAILURE);
9362     }
9363     return(TNG_SUCCESS);
9364 }
9365
9366 tng_function_status DECLSPECDLLEXPORT tng_input_file_set
9367                 (const tng_trajectory_t tng_data,
9368                  const char *file_name)
9369 {
9370     unsigned int len;
9371     char *temp;
9372
9373     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9374     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9375
9376
9377     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
9378                                            file_name) == 0)
9379     {
9380         return(TNG_SUCCESS);
9381     }
9382
9383     if(tng_data->input_file)
9384     {
9385         fclose(tng_data->input_file);
9386     }
9387
9388     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9389     temp = (char *)realloc(tng_data->input_file_path, len);
9390     if(!temp)
9391     {
9392         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9393                 __FILE__, __LINE__);
9394         free(tng_data->input_file_path);
9395         tng_data->input_file_path = 0;
9396         return(TNG_CRITICAL);
9397     }
9398     tng_data->input_file_path = temp;
9399
9400     strncpy(tng_data->input_file_path, file_name, len);
9401
9402     return(tng_input_file_init(tng_data));
9403 }
9404
9405 tng_function_status tng_output_file_get
9406                 (const tng_trajectory_t tng_data,
9407                  char *file_name,
9408                  const int max_len)
9409 {
9410     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9411     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9412
9413     strncpy(file_name, tng_data->output_file_path, max_len - 1);
9414     file_name[max_len - 1] = 0;
9415
9416     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
9417     {
9418         return(TNG_FAILURE);
9419     }
9420     return(TNG_SUCCESS);
9421 }
9422
9423 tng_function_status DECLSPECDLLEXPORT tng_output_file_set
9424                 (const tng_trajectory_t tng_data,
9425                  const char *file_name)
9426 {
9427     int len;
9428     char *temp;
9429
9430     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9431     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9432
9433     if(tng_data->output_file_path &&
9434        strcmp(tng_data->output_file_path, file_name) == 0)
9435     {
9436         return(TNG_SUCCESS);
9437     }
9438
9439     if(tng_data->output_file)
9440     {
9441         fclose(tng_data->output_file);
9442     }
9443
9444     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9445     temp = (char *)realloc(tng_data->output_file_path, len);
9446     if(!temp)
9447     {
9448         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9449                 __FILE__, __LINE__);
9450         free(tng_data->output_file_path);
9451         tng_data->output_file_path = 0;
9452         return(TNG_CRITICAL);
9453     }
9454     tng_data->output_file_path = temp;
9455
9456     strncpy(tng_data->output_file_path, file_name, len);
9457
9458     return(tng_output_file_init(tng_data));
9459 }
9460
9461 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
9462                 (const tng_trajectory_t tng_data,
9463                  const char *file_name)
9464 {
9465     int len;
9466     char *temp;
9467
9468     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9469     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9470
9471     if(tng_data->output_file_path &&
9472        strcmp(tng_data->output_file_path, file_name) == 0)
9473     {
9474         return(TNG_SUCCESS);
9475     }
9476
9477     if(tng_data->output_file)
9478     {
9479         fclose(tng_data->output_file);
9480     }
9481
9482     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9483     temp = (char *)realloc(tng_data->output_file_path, len);
9484     if(!temp)
9485     {
9486         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9487                 __FILE__, __LINE__);
9488         free(tng_data->output_file_path);
9489         tng_data->output_file_path = 0;
9490         return(TNG_CRITICAL);
9491     }
9492     tng_data->output_file_path = temp;
9493
9494     strncpy(tng_data->output_file_path, file_name, len);
9495
9496     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
9497     if(!tng_data->output_file)
9498     {
9499         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
9500                 tng_data->output_file_path, __FILE__, __LINE__);
9501         return(TNG_CRITICAL);
9502     }
9503     tng_data->input_file = tng_data->output_file;
9504
9505     return(TNG_SUCCESS);
9506 }
9507
9508 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
9509                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
9510 {
9511     tng_endianness_32 end_32;
9512     tng_endianness_64 end_64;
9513
9514     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9515     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
9516
9517     if(tng_data->output_endianness_swap_func_32)
9518     {
9519         /* If other endianness variants are added they must be added here as well */
9520         if(tng_data->output_endianness_swap_func_32 ==
9521            &tng_swap_byte_order_big_endian_32)
9522         {
9523             end_32 = TNG_BIG_ENDIAN_32;
9524         }
9525         else if(tng_data->output_endianness_swap_func_32 ==
9526                 &tng_swap_byte_order_little_endian_32)
9527         {
9528             end_32 = TNG_LITTLE_ENDIAN_32;
9529         }
9530         else
9531         {
9532             return(TNG_FAILURE);
9533         }
9534     }
9535     else
9536     {
9537         end_32 = (tng_endianness_32)tng_data->endianness_32;
9538     }
9539
9540     if(tng_data->output_endianness_swap_func_64)
9541     {
9542         /* If other endianness variants are added they must be added here as well */
9543         if(tng_data->output_endianness_swap_func_64 ==
9544            &tng_swap_byte_order_big_endian_64)
9545         {
9546             end_64 = TNG_BIG_ENDIAN_64;
9547         }
9548         else if(tng_data->output_endianness_swap_func_64 ==
9549                 &tng_swap_byte_order_little_endian_64)
9550         {
9551             end_64 = TNG_LITTLE_ENDIAN_64;
9552         }
9553         else
9554         {
9555             return(TNG_FAILURE);
9556         }
9557     }
9558     else
9559     {
9560         end_64 = (tng_endianness_64)tng_data->endianness_64;
9561     }
9562
9563     if((int)end_32 != (int)end_64)
9564     {
9565         return(TNG_FAILURE);
9566     }
9567
9568     if(end_32 == TNG_LITTLE_ENDIAN_32)
9569     {
9570         *endianness = TNG_LITTLE_ENDIAN;
9571     }
9572
9573     else if(end_32 == TNG_BIG_ENDIAN_32)
9574     {
9575         *endianness = TNG_BIG_ENDIAN;
9576     }
9577     else
9578     {
9579         return(TNG_FAILURE);
9580     }
9581
9582     return(TNG_SUCCESS);
9583 }
9584
9585 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
9586                 (const tng_trajectory_t tng_data,
9587                  const tng_file_endianness endianness)
9588 {
9589     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9590
9591     /* Tne endianness cannot be changed if the data has already been written
9592      * to the output file. */
9593     if(ftello(tng_data->output_file) > 0)
9594     {
9595         return(TNG_FAILURE);
9596     }
9597
9598     if(endianness == TNG_BIG_ENDIAN)
9599     {
9600         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
9601         {
9602             tng_data->output_endianness_swap_func_32 = 0;
9603         }
9604         else
9605         {
9606             tng_data->output_endianness_swap_func_32 =
9607             &tng_swap_byte_order_big_endian_32;
9608         }
9609         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
9610         {
9611             tng_data->output_endianness_swap_func_64 = 0;
9612         }
9613         else
9614         {
9615             tng_data->output_endianness_swap_func_64 =
9616             &tng_swap_byte_order_big_endian_64;
9617         }
9618         return(TNG_SUCCESS);
9619     }
9620     else if(endianness == TNG_LITTLE_ENDIAN)
9621     {
9622         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
9623         {
9624             tng_data->output_endianness_swap_func_32 = 0;
9625         }
9626         else
9627         {
9628             tng_data->output_endianness_swap_func_32 =
9629             &tng_swap_byte_order_little_endian_32;
9630         }
9631         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
9632         {
9633             tng_data->output_endianness_swap_func_64 = 0;
9634         }
9635         else
9636         {
9637             tng_data->output_endianness_swap_func_64 =
9638             &tng_swap_byte_order_little_endian_64;
9639         }
9640         return(TNG_SUCCESS);
9641     }
9642
9643     /* If the specified endianness is neither big nor little endian return a
9644      * failure. */
9645     return(TNG_FAILURE);
9646 }
9647
9648 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
9649                     (const tng_trajectory_t tng_data,
9650                      char *name,
9651                      const int max_len)
9652 {
9653     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9654     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9655
9656     strncpy(name, tng_data->first_program_name, max_len - 1);
9657     name[max_len - 1] = 0;
9658
9659     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
9660     {
9661         return(TNG_FAILURE);
9662     }
9663     return(TNG_SUCCESS);
9664 }
9665
9666 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set
9667                 (const tng_trajectory_t tng_data,
9668                  const char *new_name)
9669 {
9670     unsigned int len;
9671
9672     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9673     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9674
9675     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9676
9677     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
9678     {
9679         free(tng_data->first_program_name);
9680         tng_data->first_program_name = 0;
9681     }
9682     if(!tng_data->first_program_name)
9683     {
9684         tng_data->first_program_name = (char *)malloc(len);
9685         if(!tng_data->first_program_name)
9686         {
9687             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9688                     __FILE__, __LINE__);
9689             return(TNG_CRITICAL);
9690         }
9691     }
9692
9693     strncpy(tng_data->first_program_name, new_name, len);
9694
9695     return(TNG_SUCCESS);
9696 }
9697
9698 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
9699                     (const tng_trajectory_t tng_data,
9700                      char *name, const int max_len)
9701 {
9702     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9703     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9704
9705     strncpy(name, tng_data->last_program_name, max_len - 1);
9706     name[max_len - 1] = 0;
9707
9708     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
9709     {
9710         return(TNG_FAILURE);
9711     }
9712     return(TNG_SUCCESS);
9713 }
9714
9715 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
9716                     (const tng_trajectory_t tng_data,
9717                      const char *new_name)
9718 {
9719     unsigned int len;
9720
9721     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9722     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9723
9724     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9725
9726     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
9727     {
9728         free(tng_data->last_program_name);
9729         tng_data->last_program_name = 0;
9730     }
9731     if(!tng_data->last_program_name)
9732     {
9733         tng_data->last_program_name = (char *)malloc(len);
9734         if(!tng_data->last_program_name)
9735         {
9736             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9737                     __FILE__, __LINE__);
9738             return(TNG_CRITICAL);
9739         }
9740     }
9741
9742     strncpy(tng_data->last_program_name, new_name, len);
9743
9744     return(TNG_SUCCESS);
9745 }
9746
9747 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
9748                     (const tng_trajectory_t tng_data,
9749                      char *name, const int max_len)
9750 {
9751     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9752     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9753
9754     strncpy(name, tng_data->first_user_name, max_len - 1);
9755     name[max_len - 1] = 0;
9756
9757     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
9758     {
9759         return(TNG_FAILURE);
9760     }
9761     return(TNG_SUCCESS);
9762 }
9763
9764 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
9765                     (const tng_trajectory_t tng_data,
9766                      const char *new_name)
9767 {
9768     unsigned int len;
9769
9770     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9771     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9772
9773     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9774
9775     /* If the currently stored string length is not enough to store the new
9776      * string it is freed and reallocated. */
9777     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
9778     {
9779         free(tng_data->first_user_name);
9780         tng_data->first_user_name = 0;
9781     }
9782     if(!tng_data->first_user_name)
9783     {
9784         tng_data->first_user_name = (char *)malloc(len);
9785         if(!tng_data->first_user_name)
9786         {
9787             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9788                     __FILE__, __LINE__);
9789             return(TNG_CRITICAL);
9790         }
9791     }
9792
9793     strncpy(tng_data->first_user_name, new_name, len);
9794
9795     return(TNG_SUCCESS);
9796 }
9797
9798 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
9799                     (const tng_trajectory_t tng_data,
9800                      char *name, const int max_len)
9801 {
9802     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9803     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9804
9805     strncpy(name, tng_data->last_user_name, max_len - 1);
9806     name[max_len - 1] = 0;
9807
9808     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
9809     {
9810         return(TNG_FAILURE);
9811     }
9812     return(TNG_SUCCESS);
9813 }
9814
9815 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
9816                     (const tng_trajectory_t tng_data,
9817                      const char *new_name)
9818 {
9819     unsigned int len;
9820
9821     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9822     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9823
9824     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9825
9826     /* If the currently stored string length is not enough to store the new
9827      * string it is freed and reallocated. */
9828     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
9829     {
9830         free(tng_data->last_user_name);
9831         tng_data->last_user_name = 0;
9832     }
9833     if(!tng_data->last_user_name)
9834     {
9835         tng_data->last_user_name = (char *)malloc(len);
9836         if(!tng_data->last_user_name)
9837         {
9838             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9839                     __FILE__, __LINE__);
9840             return(TNG_CRITICAL);
9841         }
9842     }
9843
9844     strncpy(tng_data->last_user_name, new_name, len);
9845
9846     return(TNG_SUCCESS);
9847 }
9848
9849 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
9850                     (const tng_trajectory_t tng_data,
9851                      char *name, const int max_len)
9852 {
9853     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9854     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9855
9856     strncpy(name, tng_data->first_computer_name, max_len - 1);
9857     name[max_len - 1] = 0;
9858
9859     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
9860     {
9861         return(TNG_FAILURE);
9862     }
9863     return(TNG_SUCCESS);
9864 }
9865
9866 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
9867                     (const tng_trajectory_t tng_data,
9868                      const char *new_name)
9869 {
9870     unsigned int len;
9871
9872     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9873     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9874
9875     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9876
9877     /* If the currently stored string length is not enough to store the new
9878      * string it is freed and reallocated. */
9879     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
9880     {
9881         free(tng_data->first_computer_name);
9882         tng_data->first_computer_name = 0;
9883     }
9884     if(!tng_data->first_computer_name)
9885     {
9886         tng_data->first_computer_name = (char *)malloc(len);
9887         if(!tng_data->first_computer_name)
9888         {
9889             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9890                     __FILE__, __LINE__);
9891             return(TNG_CRITICAL);
9892         }
9893     }
9894
9895     strncpy(tng_data->first_computer_name, new_name, len);
9896
9897     return(TNG_SUCCESS);
9898 }
9899
9900 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
9901                     (const tng_trajectory_t tng_data,
9902                      char *name, const int max_len)
9903 {
9904     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9905     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9906
9907     strncpy(name, tng_data->last_computer_name, max_len - 1);
9908     name[max_len - 1] = 0;
9909
9910     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
9911     {
9912         return(TNG_FAILURE);
9913     }
9914     return(TNG_SUCCESS);
9915 }
9916
9917 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
9918                     (const tng_trajectory_t tng_data,
9919                      const char *new_name)
9920 {
9921     unsigned int len;
9922
9923     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9924     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9925
9926     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9927
9928     /* If the currently stored string length is not enough to store the new
9929      * string it is freed and reallocated. */
9930     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
9931         len)
9932     {
9933         free(tng_data->last_computer_name);
9934         tng_data->last_computer_name = 0;
9935     }
9936     if(!tng_data->last_computer_name)
9937     {
9938         tng_data->last_computer_name = (char *)malloc(len);
9939         if(!tng_data->last_computer_name)
9940         {
9941             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9942                     __FILE__, __LINE__);
9943             return(TNG_CRITICAL);
9944         }
9945     }
9946
9947     strncpy(tng_data->last_computer_name, new_name, len);
9948
9949     return(TNG_SUCCESS);
9950 }
9951
9952 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
9953                     (const tng_trajectory_t tng_data,
9954                      char *signature, const int max_len)
9955 {
9956     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9957     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
9958
9959     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
9960     signature[max_len - 1] = 0;
9961
9962     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
9963     {
9964         return(TNG_FAILURE);
9965     }
9966     return(TNG_SUCCESS);
9967 }
9968
9969 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
9970                     (const tng_trajectory_t tng_data,
9971                      const char *signature)
9972 {
9973     unsigned int len;
9974
9975     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9976     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
9977
9978     len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN);
9979
9980     /* If the currently stored string length is not enough to store the new
9981      * string it is freed and reallocated. */
9982     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
9983         len)
9984     {
9985         free(tng_data->first_pgp_signature);
9986         tng_data->first_pgp_signature = 0;
9987     }
9988     if(!tng_data->first_pgp_signature)
9989     {
9990         tng_data->first_pgp_signature = (char *)malloc(len);
9991         if(!tng_data->first_pgp_signature)
9992         {
9993             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9994                     __FILE__, __LINE__);
9995             return(TNG_CRITICAL);
9996         }
9997     }
9998
9999     strncpy(tng_data->first_pgp_signature, signature, len);
10000
10001     return(TNG_SUCCESS);
10002 }
10003
10004 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
10005                     (const tng_trajectory_t tng_data,
10006                      char *signature, const int max_len)
10007 {
10008     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10009     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10010
10011     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
10012     signature[max_len - 1] = 0;
10013
10014     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
10015     {
10016         return(TNG_FAILURE);
10017     }
10018     return(TNG_SUCCESS);
10019 }
10020
10021 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
10022                     (const tng_trajectory_t tng_data,
10023                      const char *signature)
10024 {
10025     unsigned int len;
10026
10027     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10028     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10029
10030     len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN);
10031
10032     /* If the currently stored string length is not enough to store the new
10033      * string it is freed and reallocated. */
10034     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
10035         len)
10036     {
10037         free(tng_data->last_pgp_signature);
10038         tng_data->last_pgp_signature = 0;
10039     }
10040     if(!tng_data->last_pgp_signature)
10041     {
10042         tng_data->last_pgp_signature = (char *)malloc(len);
10043         if(!tng_data->last_pgp_signature)
10044         {
10045             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
10046                     __FILE__, __LINE__);
10047             return(TNG_CRITICAL);
10048         }
10049     }
10050
10051     strncpy(tng_data->last_pgp_signature, signature, len);
10052
10053     return(TNG_SUCCESS);
10054 }
10055
10056 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
10057                     (const tng_trajectory_t tng_data,
10058                      char *name, const int max_len)
10059 {
10060     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10061     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10062
10063     strncpy(name, tng_data->forcefield_name, max_len - 1);
10064     name[max_len - 1] = 0;
10065
10066     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
10067     {
10068         return(TNG_FAILURE);
10069     }
10070     return(TNG_SUCCESS);
10071 }
10072
10073 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
10074                     (const tng_trajectory_t tng_data,
10075                      const char *new_name)
10076 {
10077     unsigned int len;
10078
10079     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10080     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10081
10082     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
10083
10084     /* If the currently stored string length is not enough to store the new
10085      * string it is freed and reallocated. */
10086     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
10087     {
10088         free(tng_data->forcefield_name);
10089         tng_data->forcefield_name = 0;
10090     }
10091     if(!tng_data->forcefield_name)
10092     {
10093         tng_data->forcefield_name = (char *)malloc(len);
10094         if(!tng_data->forcefield_name)
10095         {
10096             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
10097                     __FILE__, __LINE__);
10098             return(TNG_CRITICAL);
10099         }
10100     }
10101
10102     strncpy(tng_data->forcefield_name, new_name, len);
10103
10104     return(TNG_SUCCESS);
10105 }
10106
10107 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
10108                     (const tng_trajectory_t tng_data,
10109                      int64_t *len)
10110 {
10111     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10112     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10113
10114     *len = tng_data->medium_stride_length;
10115
10116     return(TNG_SUCCESS);
10117 }
10118
10119 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
10120                     (const tng_trajectory_t tng_data,
10121                      const int64_t len)
10122 {
10123     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10124
10125     if(len >= tng_data->long_stride_length)
10126     {
10127         return(TNG_FAILURE);
10128     }
10129     tng_data->medium_stride_length = len;
10130
10131     return(TNG_SUCCESS);
10132 }
10133
10134 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
10135                 (const tng_trajectory_t tng_data,
10136                  int64_t *len)
10137 {
10138     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10139     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10140
10141     *len = tng_data->long_stride_length;
10142
10143     return(TNG_SUCCESS);
10144 }
10145
10146 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
10147                 (const tng_trajectory_t tng_data,
10148                  const int64_t len)
10149 {
10150     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10151
10152     if(len <= tng_data->medium_stride_length)
10153     {
10154         return(TNG_FAILURE);
10155     }
10156     tng_data->long_stride_length = len;
10157
10158     return(TNG_SUCCESS);
10159 }
10160
10161 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
10162                 (const tng_trajectory_t tng_data,
10163                  double *time)
10164 {
10165     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10166     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
10167
10168     *time = tng_data->time_per_frame;
10169
10170     return(TNG_SUCCESS);
10171 }
10172
10173 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
10174                 (const tng_trajectory_t tng_data,
10175                  const double time)
10176 {
10177     tng_trajectory_frame_set_t frame_set;
10178
10179     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10180     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
10181
10182     if(fabs(time - tng_data->time_per_frame) < 0.00001)
10183     {
10184         return(TNG_SUCCESS);
10185     }
10186
10187     frame_set = &tng_data->current_trajectory_frame_set;
10188
10189     /* If the current frame set is not finished write it to disk before
10190        changing time per frame. */
10191     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
10192     {
10193         frame_set->n_frames = frame_set->n_unwritten_frames;
10194         tng_frame_set_write(tng_data, TNG_USE_HASH);
10195     }
10196     tng_data->time_per_frame = time;
10197
10198     return(TNG_SUCCESS);
10199 }
10200
10201 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
10202                     (const tng_trajectory_t tng_data,
10203                      int64_t *len)
10204 {
10205     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10206     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10207
10208     *len = tng_data->input_file_len;
10209
10210     return(TNG_SUCCESS);
10211 }
10212
10213 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
10214                     (const tng_trajectory_t tng_data,
10215                      int64_t *n)
10216 {
10217     tng_gen_block_t block;
10218     tng_function_status stat;
10219     int64_t file_pos, last_file_pos, first_frame, n_frames;
10220
10221     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10222     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
10223     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10224
10225     file_pos = ftello(tng_data->input_file);
10226     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10227
10228     if(last_file_pos <= 0)
10229     {
10230         return(TNG_FAILURE);
10231     }
10232
10233     tng_block_init(&block);
10234     fseeko(tng_data->input_file,
10235            last_file_pos,
10236            SEEK_SET);
10237     /* Read block headers first to see that a frame set block is found. */
10238     stat = tng_block_header_read(tng_data, block);
10239     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10240     {
10241         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", last_file_pos,
10242                 __FILE__, __LINE__);
10243         tng_block_destroy(&block);
10244         return(TNG_FAILURE);
10245     }
10246     tng_block_destroy(&block);
10247
10248     if(tng_file_input_numerical(tng_data, &first_frame,
10249                                 sizeof(first_frame),
10250                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
10251     {
10252         return(TNG_CRITICAL);
10253     }
10254
10255     if(tng_file_input_numerical(tng_data, &n_frames,
10256                                 sizeof(n_frames),
10257                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
10258     {
10259         return(TNG_CRITICAL);
10260     }
10261
10262     fseeko(tng_data->input_file, file_pos, SEEK_SET);
10263
10264     *n = first_frame + n_frames;
10265
10266     return(TNG_SUCCESS);
10267 }
10268
10269 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
10270                 (const tng_trajectory_t tng_data,
10271                  double *precision)
10272 {
10273     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10274
10275     *precision = tng_data->compression_precision;
10276
10277     return(TNG_SUCCESS);
10278 }
10279
10280 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
10281                 (const tng_trajectory_t tng_data,
10282                  const double precision)
10283 {
10284     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10285
10286     tng_data->compression_precision = precision;
10287
10288     return(TNG_SUCCESS);
10289 }
10290
10291 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
10292                 (const tng_trajectory_t tng_data,
10293                  const int64_t n)
10294 {
10295     tng_molecule_t mol;
10296     tng_chain_t chain;
10297     tng_residue_t res;
10298     tng_atom_t atom;
10299     tng_function_status stat;
10300     int64_t diff, n_mod, n_impl;
10301
10302     TNG_ASSERT(n >= 0, "TNG library: The requested number of particles must be >= 0");
10303
10304     diff = n - tng_data->n_particles;
10305
10306     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
10307     if(stat == TNG_SUCCESS)
10308     {
10309         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
10310         {
10311             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
10312                     __FILE__, __LINE__);
10313             return(TNG_FAILURE);
10314         }
10315         diff -= n_impl * mol->n_atoms;
10316     }
10317
10318     if(diff == 0)
10319     {
10320         if(stat == TNG_SUCCESS)
10321         {
10322             stat = tng_molecule_cnt_set(tng_data, mol, 0);
10323             return(stat);
10324         }
10325         return(TNG_SUCCESS);
10326     }
10327     else if(diff < 0)
10328     {
10329         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
10330         fprintf(stderr, "particle count.\n");
10331         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10332                 __FILE__, __LINE__);
10333         /* FIXME: Should we set the count of all other molecules to 0 and add
10334          * implicit molecules? */
10335         return(TNG_FAILURE);
10336     }
10337     if(stat != TNG_SUCCESS)
10338     {
10339         stat = tng_molecule_add(tng_data,
10340                                 "TNG_IMPLICIT_MOL",
10341                                 &mol);
10342         if(stat != TNG_SUCCESS)
10343         {
10344             return(stat);
10345         }
10346         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
10347         if(stat != TNG_SUCCESS)
10348         {
10349             return(stat);
10350         }
10351         stat = tng_chain_residue_add(tng_data, chain, "", &res);
10352         if(stat != TNG_SUCCESS)
10353         {
10354             return(stat);
10355         }
10356         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
10357         if(stat != TNG_SUCCESS)
10358         {
10359             return(stat);
10360         }
10361     }
10362     else
10363     {
10364         if(mol->n_atoms > 1)
10365         {
10366             n_mod = diff % mol->n_atoms;
10367             if(n_mod != 0)
10368             {
10369                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
10370                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
10371                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10372                         __FILE__, __LINE__);
10373                 return(TNG_FAILURE);
10374             }
10375             diff /= mol->n_atoms;
10376         }
10377     }
10378     stat = tng_molecule_cnt_set(tng_data, mol, diff);
10379
10380     return(stat);
10381 }
10382
10383 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
10384                 (const tng_trajectory_t tng_data,
10385                  int64_t *n)
10386 {
10387     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10388     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10389
10390     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
10391     {
10392         *n = tng_data->n_particles;
10393     }
10394     else
10395     {
10396         *n = tng_data->current_trajectory_frame_set.n_particles;
10397     }
10398
10399     return(TNG_SUCCESS);
10400 }
10401
10402 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
10403                 (const tng_trajectory_t tng_data,
10404                  char *variable)
10405 {
10406     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10407     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
10408
10409     *variable = tng_data->var_num_atoms_flag;
10410
10411     return(TNG_SUCCESS);
10412 }
10413
10414 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_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     *n = tng_data->n_molecules;
10422
10423     return(TNG_SUCCESS);
10424 }
10425
10426 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
10427                     (const tng_trajectory_t tng_data,
10428                      int64_t *n)
10429 {
10430     int64_t *cnt_list = 0, cnt = 0, i;
10431
10432     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10433     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10434
10435     tng_molecule_cnt_list_get(tng_data, &cnt_list);
10436
10437     if(!cnt_list)
10438     {
10439         return(TNG_FAILURE);
10440     }
10441
10442     for(i = 0; i < tng_data->n_molecules; i++)
10443     {
10444         cnt += cnt_list[i];
10445     }
10446
10447     *n = cnt;
10448
10449     return(TNG_SUCCESS);
10450 }
10451
10452 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
10453                 (const tng_trajectory_t tng_data,
10454                  int64_t **mol_cnt_list)
10455 {
10456     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10457
10458     if(tng_data->var_num_atoms_flag)
10459     {
10460         *mol_cnt_list = tng_data->current_trajectory_frame_set.
10461                        molecule_cnt_list;
10462     }
10463     else
10464     {
10465         *mol_cnt_list = tng_data->molecule_cnt_list;
10466     }
10467     if(*mol_cnt_list == 0)
10468     {
10469         return(TNG_FAILURE);
10470     }
10471     return(TNG_SUCCESS);
10472 }
10473
10474 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
10475                 (const tng_trajectory_t tng_data,
10476                  int64_t *exp)
10477 {
10478     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10479     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
10480
10481     *exp = tng_data->distance_unit_exponential;
10482
10483     return(TNG_SUCCESS);
10484 }
10485
10486 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
10487                 (const tng_trajectory_t tng_data,
10488                  const int64_t exp)
10489 {
10490     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10491
10492     tng_data->distance_unit_exponential = exp;
10493
10494     return(TNG_SUCCESS);
10495 }
10496
10497 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
10498                 (const tng_trajectory_t tng_data,
10499                  int64_t *n)
10500 {
10501     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10502     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10503
10504     *n = tng_data->frame_set_n_frames;
10505
10506     return(TNG_SUCCESS);
10507 }
10508
10509 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
10510                 (const tng_trajectory_t tng_data,
10511                  const int64_t n)
10512 {
10513     tng_trajectory_frame_set_t frame_set;
10514     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10515
10516     tng_data->frame_set_n_frames = n;
10517     frame_set = &tng_data->current_trajectory_frame_set;
10518     if(frame_set)
10519     {
10520         frame_set->n_frames = n;
10521     }
10522
10523     return(TNG_SUCCESS);
10524 }
10525
10526 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
10527                 (const tng_trajectory_t tng_data,
10528                  int64_t *n)
10529 {
10530     int64_t long_stride_length, medium_stride_length;
10531     int64_t file_pos, orig_frame_set_file_pos;
10532     tng_trajectory_frame_set_t frame_set;
10533     struct tng_trajectory_frame_set orig_frame_set;
10534     tng_gen_block_t block;
10535     tng_function_status stat;
10536     int64_t cnt = 0;
10537
10538     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10539     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10540
10541     orig_frame_set = tng_data->current_trajectory_frame_set;
10542
10543     frame_set = &tng_data->current_trajectory_frame_set;
10544
10545     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10546     file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
10547
10548     if(file_pos < 0)
10549     {
10550         *n = tng_data->n_trajectory_frame_sets = cnt;
10551         return(TNG_SUCCESS);
10552     }
10553
10554     tng_block_init(&block);
10555     fseeko(tng_data->input_file,
10556            file_pos,
10557            SEEK_SET);
10558     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10559     /* Read block headers first to see what block is found. */
10560     stat = tng_block_header_read(tng_data, block);
10561     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10562     {
10563         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
10564                 __FILE__, __LINE__);
10565         tng_block_destroy(&block);
10566         return(TNG_CRITICAL);
10567     }
10568
10569     if(tng_block_read_next(tng_data, block,
10570                         TNG_SKIP_HASH) != TNG_SUCCESS)
10571     {
10572         tng_block_destroy(&block);
10573         return(TNG_CRITICAL);
10574     }
10575
10576     ++cnt;
10577
10578     long_stride_length = tng_data->long_stride_length;
10579     medium_stride_length = tng_data->medium_stride_length;
10580
10581     /* Take long steps forward until a long step forward would be too long or
10582      * the last frame set is found */
10583     file_pos = frame_set->long_stride_next_frame_set_file_pos;
10584     while(file_pos > 0)
10585     {
10586         if(file_pos > 0)
10587         {
10588             cnt += long_stride_length;
10589             fseeko(tng_data->input_file, file_pos, SEEK_SET);
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",
10595                        file_pos, __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         file_pos = frame_set->long_stride_next_frame_set_file_pos;
10608     }
10609
10610     /* Take medium steps forward until a medium step forward would be too long
10611      * or the last frame set is found */
10612     file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10613     while(file_pos > 0)
10614     {
10615         if(file_pos > 0)
10616         {
10617             cnt += medium_stride_length;
10618             fseeko(tng_data->input_file,
10619                    file_pos,
10620                    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->medium_stride_next_frame_set_file_pos;
10639     }
10640
10641     /* Take one step forward until the last frame set is found */
10642     file_pos = frame_set->next_frame_set_file_pos;
10643     while(file_pos > 0)
10644     {
10645         if(file_pos > 0)
10646         {
10647             ++cnt;
10648             fseeko(tng_data->input_file,
10649                    file_pos,
10650                    SEEK_SET);
10651             /* Read block headers first to see what block is found. */
10652             stat = tng_block_header_read(tng_data, block);
10653             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10654             {
10655                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10656                        file_pos, __FILE__, __LINE__);
10657                 tng_block_destroy(&block);
10658                 return(TNG_CRITICAL);
10659             }
10660
10661             if(tng_block_read_next(tng_data, block,
10662                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10663             {
10664                 tng_block_destroy(&block);
10665                 return(TNG_CRITICAL);
10666             }
10667         }
10668         file_pos = frame_set->next_frame_set_file_pos;
10669     }
10670
10671     tng_block_destroy(&block);
10672
10673     *n = tng_data->n_trajectory_frame_sets = cnt;
10674
10675     *frame_set = orig_frame_set;
10676     /* The mapping block in the original frame set has been freed when reading
10677      * other frame sets. */
10678     frame_set->mappings = 0;
10679     frame_set->n_mapping_blocks = 0;
10680
10681     fseeko(tng_data->input_file,
10682            tng_data->first_trajectory_frame_set_input_file_pos,
10683            SEEK_SET);
10684
10685     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
10686
10687     return(TNG_SUCCESS);
10688 }
10689
10690 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
10691                 (const tng_trajectory_t tng_data,
10692                  tng_trajectory_frame_set_t *frame_set_p)
10693 {
10694     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10695
10696     *frame_set_p = &tng_data->current_trajectory_frame_set;
10697
10698     return(TNG_SUCCESS);
10699 }
10700
10701 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
10702                 (const tng_trajectory_t tng_data,
10703                  const int64_t nr)
10704 {
10705     int64_t long_stride_length, medium_stride_length;
10706     int64_t file_pos, curr_nr = 0, n_frame_sets;
10707     tng_trajectory_frame_set_t frame_set;
10708     tng_gen_block_t block;
10709     tng_function_status stat;
10710
10711     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10712     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
10713
10714     frame_set = &tng_data->current_trajectory_frame_set;
10715
10716     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
10717
10718     if(stat != TNG_SUCCESS)
10719     {
10720         return(stat);
10721     }
10722
10723     if(nr >= n_frame_sets)
10724     {
10725         return(TNG_FAILURE);
10726     }
10727
10728     long_stride_length = tng_data->long_stride_length;
10729     medium_stride_length = tng_data->medium_stride_length;
10730
10731     /* FIXME: The frame set number of the current frame set is not stored */
10732
10733     if(nr < n_frame_sets - 1 - nr)
10734     {
10735         /* Start from the beginning */
10736         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
10737     }
10738     else
10739     {
10740         /* Start from the end */
10741         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10742         curr_nr = n_frame_sets - 1;
10743     }
10744     if(file_pos <= 0)
10745     {
10746         return(TNG_FAILURE);
10747     }
10748
10749     tng_block_init(&block);
10750     fseeko(tng_data->input_file,
10751            file_pos,
10752            SEEK_SET);
10753     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10754     /* Read block headers first to see what block is found. */
10755     stat = tng_block_header_read(tng_data, block);
10756     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10757     {
10758         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
10759                 __FILE__, __LINE__);
10760         tng_block_destroy(&block);
10761         return(TNG_CRITICAL);
10762     }
10763
10764     if(tng_block_read_next(tng_data, block,
10765                         TNG_SKIP_HASH) != TNG_SUCCESS)
10766     {
10767         tng_block_destroy(&block);
10768         return(TNG_CRITICAL);
10769     }
10770
10771     if(curr_nr == nr)
10772     {
10773         tng_block_destroy(&block);
10774         return(TNG_SUCCESS);
10775     }
10776
10777     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10778
10779     /* Take long steps forward until a long step forward would be too long or
10780      * the right frame set is found */
10781     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
10782     {
10783         file_pos = frame_set->long_stride_next_frame_set_file_pos;
10784         if(file_pos > 0)
10785         {
10786             curr_nr += long_stride_length;
10787             fseeko(tng_data->input_file, file_pos, SEEK_SET);
10788             /* Read block headers first to see what block is found. */
10789             stat = tng_block_header_read(tng_data, block);
10790             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10791             {
10792                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10793                        file_pos,  __FILE__, __LINE__);
10794                 tng_block_destroy(&block);
10795                 return(TNG_CRITICAL);
10796             }
10797
10798             if(tng_block_read_next(tng_data, block,
10799                                    TNG_SKIP_HASH) != TNG_SUCCESS)
10800             {
10801                 tng_block_destroy(&block);
10802                 return(TNG_CRITICAL);
10803             }
10804             if(curr_nr == nr)
10805             {
10806                 tng_block_destroy(&block);
10807                 return(TNG_SUCCESS);
10808             }
10809         }
10810     }
10811
10812     /* Take medium steps forward until a medium step forward would be too long
10813      * or the right frame set is found */
10814     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
10815     {
10816         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10817         if(file_pos > 0)
10818         {
10819             curr_nr += medium_stride_length;
10820             fseeko(tng_data->input_file,
10821                    file_pos,
10822                    SEEK_SET);
10823             /* Read block headers first to see what block is found. */
10824             stat = tng_block_header_read(tng_data, block);
10825             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10826             {
10827                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10828                        file_pos, __FILE__, __LINE__);
10829                 tng_block_destroy(&block);
10830                 return(TNG_CRITICAL);
10831             }
10832
10833             if(tng_block_read_next(tng_data, block,
10834                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10835             {
10836                 tng_block_destroy(&block);
10837                 return(TNG_CRITICAL);
10838             }
10839             if(curr_nr == nr)
10840             {
10841                 tng_block_destroy(&block);
10842                 return(TNG_SUCCESS);
10843             }
10844         }
10845     }
10846
10847     /* Take one step forward until the right frame set is found */
10848     while(file_pos > 0 && curr_nr < nr)
10849     {
10850         file_pos = frame_set->next_frame_set_file_pos;
10851
10852         if(file_pos > 0)
10853         {
10854             ++curr_nr;
10855             fseeko(tng_data->input_file,
10856                    file_pos,
10857                    SEEK_SET);
10858             /* Read block headers first to see what block is found. */
10859             stat = tng_block_header_read(tng_data, block);
10860             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10861             {
10862                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10863                        file_pos, __FILE__, __LINE__);
10864                 tng_block_destroy(&block);
10865                 return(TNG_CRITICAL);
10866             }
10867
10868             if(tng_block_read_next(tng_data, block,
10869                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10870             {
10871                 tng_block_destroy(&block);
10872                 return(TNG_CRITICAL);
10873             }
10874             if(curr_nr == nr)
10875             {
10876                 tng_block_destroy(&block);
10877                 return(TNG_SUCCESS);
10878             }
10879         }
10880     }
10881
10882     /* Take long steps backward until a long step backward would be too long
10883      * or the right frame set is found */
10884     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
10885     {
10886         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
10887         if(file_pos > 0)
10888         {
10889             curr_nr -= long_stride_length;
10890             fseeko(tng_data->input_file,
10891                    file_pos,
10892                    SEEK_SET);
10893             /* Read block headers first to see what block is found. */
10894             stat = tng_block_header_read(tng_data, block);
10895             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10896             {
10897                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10898                        file_pos, __FILE__, __LINE__);
10899                 tng_block_destroy(&block);
10900                 return(TNG_CRITICAL);
10901             }
10902
10903             if(tng_block_read_next(tng_data, block,
10904                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10905             {
10906                 tng_block_destroy(&block);
10907                 return(TNG_CRITICAL);
10908             }
10909             if(curr_nr == nr)
10910             {
10911                 tng_block_destroy(&block);
10912                 return(TNG_SUCCESS);
10913             }
10914         }
10915     }
10916
10917     /* Take medium steps backward until a medium step backward would be too long
10918      * or the right frame set is found */
10919     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
10920     {
10921         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
10922         if(file_pos > 0)
10923         {
10924             curr_nr -= medium_stride_length;
10925             fseeko(tng_data->input_file,
10926                    file_pos,
10927                    SEEK_SET);
10928             /* Read block headers first to see what block is found. */
10929             stat = tng_block_header_read(tng_data, block);
10930             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10931             {
10932                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10933                        file_pos, __FILE__, __LINE__);
10934                 tng_block_destroy(&block);
10935                 return(TNG_CRITICAL);
10936             }
10937
10938             if(tng_block_read_next(tng_data, block,
10939                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10940             {
10941                 tng_block_destroy(&block);
10942                 return(TNG_CRITICAL);
10943             }
10944             if(curr_nr == nr)
10945             {
10946                 tng_block_destroy(&block);
10947                 return(TNG_SUCCESS);
10948             }
10949         }
10950     }
10951
10952     /* Take one step backward until the right frame set is found */
10953     while(file_pos > 0 && curr_nr > nr)
10954     {
10955         file_pos = frame_set->prev_frame_set_file_pos;
10956         if(file_pos > 0)
10957         {
10958             --curr_nr;
10959             fseeko(tng_data->input_file,
10960                    file_pos,
10961                    SEEK_SET);
10962             /* Read block headers first to see what block is found. */
10963             stat = tng_block_header_read(tng_data, block);
10964             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10965             {
10966                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10967                        file_pos, __FILE__, __LINE__);
10968                 tng_block_destroy(&block);
10969                 return(TNG_CRITICAL);
10970             }
10971
10972             if(tng_block_read_next(tng_data, block,
10973                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10974             {
10975                 tng_block_destroy(&block);
10976                 return(TNG_CRITICAL);
10977             }
10978             if(curr_nr == nr)
10979             {
10980                 tng_block_destroy(&block);
10981                 return(TNG_SUCCESS);
10982             }
10983         }
10984     }
10985
10986     /* If for some reason the current frame set is not yet found,
10987      * take one step forward until the right frame set is found */
10988     while(file_pos > 0 && curr_nr < nr)
10989     {
10990         file_pos = frame_set->next_frame_set_file_pos;
10991         if(file_pos > 0)
10992         {
10993             ++curr_nr;
10994             fseeko(tng_data->input_file,
10995                    file_pos,
10996                    SEEK_SET);
10997             /* Read block headers first to see what block is found. */
10998             stat = tng_block_header_read(tng_data, block);
10999             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11000             {
11001                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11002                        file_pos, __FILE__, __LINE__);
11003                 tng_block_destroy(&block);
11004                 return(TNG_CRITICAL);
11005             }
11006
11007             if(tng_block_read_next(tng_data, block,
11008                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11009             {
11010                 tng_block_destroy(&block);
11011                 return(TNG_CRITICAL);
11012             }
11013             if(curr_nr == nr)
11014             {
11015                 tng_block_destroy(&block);
11016                 return(TNG_SUCCESS);
11017             }
11018         }
11019     }
11020
11021     tng_block_destroy(&block);
11022     return(TNG_FAILURE);
11023 }
11024
11025 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
11026                 (const tng_trajectory_t tng_data,
11027                  const int64_t frame)
11028 {
11029     int64_t first_frame, last_frame, n_frames_per_frame_set;
11030     int64_t long_stride_length, medium_stride_length;
11031     int64_t file_pos, temp_frame, n_frames;
11032     tng_trajectory_frame_set_t frame_set;
11033     tng_gen_block_t block;
11034     tng_function_status stat;
11035
11036     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11037     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
11038
11039     frame_set = &tng_data->current_trajectory_frame_set;
11040
11041     tng_block_init(&block);
11042
11043     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
11044     {
11045         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11046         fseeko(tng_data->input_file,
11047                file_pos,
11048                SEEK_SET);
11049         tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11050         /* Read block headers first to see what block is found. */
11051         stat = tng_block_header_read(tng_data, block);
11052         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11053         {
11054             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11055                     file_pos, __FILE__, __LINE__);
11056             tng_block_destroy(&block);
11057             return(TNG_CRITICAL);
11058         }
11059
11060         if(tng_block_read_next(tng_data, block,
11061                             TNG_SKIP_HASH) != TNG_SUCCESS)
11062         {
11063             tng_block_destroy(&block);
11064             return(TNG_CRITICAL);
11065         }
11066     }
11067
11068     first_frame = tng_max_i64(frame_set->first_frame, 0);
11069     last_frame = first_frame + frame_set->n_frames - 1;
11070     /* Is this the right frame set? */
11071     if(first_frame <= frame && frame <= last_frame)
11072     {
11073         tng_block_destroy(&block);
11074         return(TNG_SUCCESS);
11075     }
11076
11077     n_frames_per_frame_set = tng_data->frame_set_n_frames;
11078     long_stride_length = tng_data->long_stride_length;
11079     medium_stride_length = tng_data->medium_stride_length;
11080
11081     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
11082        TNG_SUCCESS)
11083     {
11084         if(temp_frame - first_frame > n_frames_per_frame_set)
11085         {
11086             n_frames_per_frame_set = temp_frame - first_frame;
11087         }
11088     }
11089
11090     tng_num_frames_get(tng_data, &n_frames);
11091
11092     if(frame >= n_frames)
11093     {
11094         tng_block_destroy(&block);
11095         return(TNG_FAILURE);
11096     }
11097
11098     if(first_frame - frame >= frame ||
11099        frame - last_frame >
11100        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
11101     {
11102         /* Start from the beginning */
11103         if(first_frame - frame >= frame)
11104         {
11105             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11106
11107             if(file_pos <= 0)
11108             {
11109                 tng_block_destroy(&block);
11110                 return(TNG_FAILURE);
11111             }
11112         }
11113         /* Start from the end */
11114         else if(frame - first_frame > (n_frames - 1) - frame)
11115         {
11116             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11117
11118             /* If the last frame set position is not set start from the current
11119              * frame set, since it will be closer than the first frame set. */
11120         }
11121         /* Start from current */
11122         else
11123         {
11124             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11125         }
11126
11127         if(file_pos > 0)
11128         {
11129             fseeko(tng_data->input_file,
11130                    file_pos,
11131                    SEEK_SET);
11132             tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11133             /* Read block headers first to see what block is found. */
11134             stat = tng_block_header_read(tng_data, block);
11135             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11136             {
11137                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11138                        file_pos, __FILE__, __LINE__);
11139                 tng_block_destroy(&block);
11140                 return(TNG_CRITICAL);
11141             }
11142
11143             if(tng_block_read_next(tng_data, block,
11144                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11145             {
11146                 tng_block_destroy(&block);
11147                 return(TNG_CRITICAL);
11148             }
11149         }
11150     }
11151
11152     first_frame = tng_max_i64(frame_set->first_frame, 0);
11153     last_frame = first_frame + frame_set->n_frames - 1;
11154
11155     if(frame >= first_frame && frame <= last_frame)
11156     {
11157         tng_block_destroy(&block);
11158         return(TNG_SUCCESS);
11159     }
11160
11161     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11162
11163     /* Take long steps forward until a long step forward would be too long or
11164      * the right frame set is found */
11165     while(file_pos > 0 && first_frame + long_stride_length *
11166           n_frames_per_frame_set <= frame)
11167     {
11168         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11169         if(file_pos > 0)
11170         {
11171             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11172             /* Read block headers first to see what block is found. */
11173             stat = tng_block_header_read(tng_data, block);
11174             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11175             {
11176                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11177                        file_pos, __FILE__, __LINE__);
11178                 tng_block_destroy(&block);
11179                 return(TNG_CRITICAL);
11180             }
11181
11182             if(tng_block_read_next(tng_data, block,
11183                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11184             {
11185                 tng_block_destroy(&block);
11186                 return(TNG_CRITICAL);
11187             }
11188         }
11189         first_frame = tng_max_i64(frame_set->first_frame, 0);
11190         last_frame = first_frame + frame_set->n_frames - 1;
11191         if(frame >= first_frame && frame <= last_frame)
11192         {
11193             tng_block_destroy(&block);
11194             return(TNG_SUCCESS);
11195         }
11196     }
11197
11198     /* Take medium steps forward until a medium step forward would be too long
11199      * or the right frame set is found */
11200     while(file_pos > 0 && first_frame + medium_stride_length *
11201           n_frames_per_frame_set <= frame)
11202     {
11203         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11204         if(file_pos > 0)
11205         {
11206             fseeko(tng_data->input_file,
11207                    file_pos,
11208                    SEEK_SET);
11209             /* Read block headers first to see what block is found. */
11210             stat = tng_block_header_read(tng_data, block);
11211             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11212             {
11213                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11214                        file_pos, __FILE__, __LINE__);
11215                 tng_block_destroy(&block);
11216                 return(TNG_CRITICAL);
11217             }
11218
11219             if(tng_block_read_next(tng_data, block,
11220                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11221             {
11222                 tng_block_destroy(&block);
11223                 return(TNG_CRITICAL);
11224             }
11225         }
11226         first_frame = tng_max_i64(frame_set->first_frame, 0);
11227         last_frame = first_frame + frame_set->n_frames - 1;
11228         if(frame >= first_frame && frame <= last_frame)
11229         {
11230             tng_block_destroy(&block);
11231             return(TNG_SUCCESS);
11232         }
11233     }
11234
11235     /* Take one step forward until the right frame set is found */
11236     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11237     {
11238         file_pos = frame_set->next_frame_set_file_pos;
11239         if(file_pos > 0)
11240         {
11241             fseeko(tng_data->input_file,
11242                    file_pos,
11243                    SEEK_SET);
11244             /* Read block headers first to see what block is found. */
11245             stat = tng_block_header_read(tng_data, block);
11246             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11247             {
11248                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11249                        file_pos, __FILE__, __LINE__);
11250                 tng_block_destroy(&block);
11251                 return(TNG_CRITICAL);
11252             }
11253
11254             if(tng_block_read_next(tng_data, block,
11255                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11256             {
11257                 tng_block_destroy(&block);
11258                 return(TNG_CRITICAL);
11259             }
11260         }
11261         first_frame = tng_max_i64(frame_set->first_frame, 0);
11262         last_frame = first_frame + frame_set->n_frames - 1;
11263         if(frame >= first_frame && frame <= last_frame)
11264         {
11265             tng_block_destroy(&block);
11266             return(TNG_SUCCESS);
11267         }
11268     }
11269
11270     /* Take long steps backward until a long step backward would be too long
11271      * or the right frame set is found */
11272     while(file_pos > 0 && first_frame - long_stride_length *
11273           n_frames_per_frame_set >= frame)
11274     {
11275         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11276         if(file_pos > 0)
11277         {
11278             fseeko(tng_data->input_file,
11279                    file_pos,
11280                    SEEK_SET);
11281             /* Read block headers first to see what block is found. */
11282             stat = tng_block_header_read(tng_data, block);
11283             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11284             {
11285                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11286                        file_pos, __FILE__, __LINE__);
11287                 tng_block_destroy(&block);
11288                 return(TNG_CRITICAL);
11289             }
11290
11291             if(tng_block_read_next(tng_data, block,
11292                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11293             {
11294                 tng_block_destroy(&block);
11295                 return(TNG_CRITICAL);
11296             }
11297         }
11298         first_frame = tng_max_i64(frame_set->first_frame, 0);
11299         last_frame = first_frame + frame_set->n_frames - 1;
11300         if(frame >= first_frame && frame <= last_frame)
11301         {
11302             tng_block_destroy(&block);
11303             return(TNG_SUCCESS);
11304         }
11305     }
11306
11307     /* Take medium steps backward until a medium step backward would be too long
11308      * or the right frame set is found */
11309     while(file_pos > 0 && first_frame - medium_stride_length *
11310           n_frames_per_frame_set >= frame)
11311     {
11312         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11313         if(file_pos > 0)
11314         {
11315             fseeko(tng_data->input_file,
11316                    file_pos,
11317                    SEEK_SET);
11318             /* Read block headers first to see what block is found. */
11319             stat = tng_block_header_read(tng_data, block);
11320             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11321             {
11322                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11323                        file_pos, __FILE__, __LINE__);
11324                 tng_block_destroy(&block);
11325                 return(TNG_CRITICAL);
11326             }
11327
11328             if(tng_block_read_next(tng_data, block,
11329                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11330             {
11331                 tng_block_destroy(&block);
11332                 return(TNG_CRITICAL);
11333             }
11334         }
11335         first_frame = tng_max_i64(frame_set->first_frame, 0);
11336         last_frame = first_frame + frame_set->n_frames - 1;
11337         if(frame >= first_frame && frame <= last_frame)
11338         {
11339             tng_block_destroy(&block);
11340             return(TNG_SUCCESS);
11341         }
11342     }
11343
11344     /* Take one step backward until the right frame set is found */
11345     while(file_pos > 0 && first_frame > frame && last_frame > frame)
11346     {
11347         file_pos = frame_set->prev_frame_set_file_pos;
11348         if(file_pos > 0)
11349         {
11350             fseeko(tng_data->input_file,
11351                    file_pos,
11352                    SEEK_SET);
11353             /* Read block headers first to see what block is found. */
11354             stat = tng_block_header_read(tng_data, block);
11355             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11356             {
11357                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11358                        file_pos, __FILE__, __LINE__);
11359                 tng_block_destroy(&block);
11360                 return(TNG_CRITICAL);
11361             }
11362
11363             if(tng_block_read_next(tng_data, block,
11364                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11365             {
11366                 tng_block_destroy(&block);
11367                 return(TNG_CRITICAL);
11368             }
11369         }
11370         first_frame = tng_max_i64(frame_set->first_frame, 0);
11371         last_frame = first_frame + frame_set->n_frames - 1;
11372         if(frame >= first_frame && frame <= last_frame)
11373         {
11374             tng_block_destroy(&block);
11375             return(TNG_SUCCESS);
11376         }
11377     }
11378
11379     /* If for some reason the current frame set is not yet found,
11380      * take one step forward until the right frame set is found */
11381     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11382     {
11383         file_pos = frame_set->next_frame_set_file_pos;
11384         if(file_pos > 0)
11385         {
11386             fseeko(tng_data->input_file,
11387                    file_pos,
11388                    SEEK_SET);
11389             /* Read block headers first to see what block is found. */
11390             stat = tng_block_header_read(tng_data, block);
11391             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11392             {
11393                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11394                        file_pos, __FILE__, __LINE__);
11395                 tng_block_destroy(&block);
11396                 return(TNG_CRITICAL);
11397             }
11398
11399             if(tng_block_read_next(tng_data, block,
11400                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11401             {
11402                 tng_block_destroy(&block);
11403                 return(TNG_CRITICAL);
11404             }
11405         }
11406         first_frame = tng_max_i64(frame_set->first_frame, 0);
11407         last_frame = first_frame + frame_set->n_frames - 1;
11408         if(frame >= first_frame && frame <= last_frame)
11409         {
11410             tng_block_destroy(&block);
11411             return(TNG_SUCCESS);
11412         }
11413     }
11414
11415     tng_block_destroy(&block);
11416     return(TNG_FAILURE);
11417 }
11418
11419 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
11420                 (const tng_trajectory_t tng_data,
11421                  const tng_trajectory_frame_set_t frame_set,
11422                  int64_t *pos)
11423 {
11424     (void)tng_data;
11425
11426     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11427     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11428
11429     *pos = frame_set->next_frame_set_file_pos;
11430
11431     return(TNG_SUCCESS);
11432 }
11433
11434 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
11435                 (const tng_trajectory_t tng_data,
11436                  const tng_trajectory_frame_set_t frame_set,
11437                  int64_t *pos)
11438 {
11439     (void)tng_data;
11440
11441     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11442     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11443
11444     *pos = frame_set->prev_frame_set_file_pos;
11445
11446     return(TNG_SUCCESS);
11447 }
11448
11449 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
11450                 (const tng_trajectory_t tng_data,
11451                  const tng_trajectory_frame_set_t frame_set,
11452                  int64_t *first_frame,
11453                  int64_t *last_frame)
11454 {
11455     (void)tng_data;
11456
11457     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
11458     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
11459     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
11460
11461     *first_frame = frame_set->first_frame;
11462     *last_frame = *first_frame + frame_set->n_frames - 1;
11463
11464     return(TNG_SUCCESS);
11465 }
11466
11467 /**
11468  * @brief Translate from the particle numbering used in a frame set to the real
11469  *  particle numbering - used in the molecule description.
11470  * @param frame_set is the frame_set containing the mappings to use.
11471  * @param local is the index number of the atom in this frame set
11472  * @param real is set to the index of the atom in the molecular system.
11473  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11474  * cannot be found.
11475  */
11476 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
11477                 (const tng_trajectory_frame_set_t frame_set,
11478                  const int64_t local,
11479                  int64_t *real)
11480 {
11481     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
11482     tng_particle_mapping_t mapping;
11483     if(n_blocks <= 0)
11484     {
11485         *real = local;
11486         return(TNG_SUCCESS);
11487     }
11488     for(i = 0; i < n_blocks; i++)
11489     {
11490         mapping = &frame_set->mappings[i];
11491         first = mapping->num_first_particle;
11492         if(local < first ||
11493            local >= first + mapping->n_particles)
11494         {
11495             continue;
11496         }
11497         *real = mapping->real_particle_numbers[local-first];
11498         return(TNG_SUCCESS);
11499     }
11500     *real = local;
11501     return(TNG_FAILURE);
11502 }
11503
11504 /**
11505  * @brief Translate from the real particle numbering to the particle numbering
11506  *  used in a frame set.
11507  * @param frame_set is the frame_set containing the mappings to use.
11508  * @param real is the index number of the atom in the molecular system.
11509  * @param local is set to the index of the atom in this frame set.
11510  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11511  * cannot be found.
11512  */
11513 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
11514                 (const tng_trajectory_frame_set_t frame_set,
11515                  const int64_t real,
11516                  int64_t *local)
11517 {
11518     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
11519     tng_particle_mapping_t mapping;
11520     if(n_blocks <= 0)
11521     {
11522         *local = real;
11523         return(TNG_SUCCESS);
11524     }
11525     for(i = 0; i < n_blocks; i++)
11526     {
11527         mapping = &frame_set->mappings[i];
11528         for(j = mapping->n_particles; j--;)
11529         {
11530             if(mapping->real_particle_numbers[j] == real)
11531             {
11532                 *local = j;
11533                 return(TNG_SUCCESS);
11534             }
11535         }
11536     }
11537     return(TNG_FAILURE);
11538 }
11539 */
11540
11541 static tng_function_status tng_file_headers_len_get
11542                 (const tng_trajectory_t tng_data,
11543                  int64_t *len)
11544 {
11545     int64_t orig_pos;
11546     tng_gen_block_t block;
11547
11548     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11549
11550     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11551     {
11552         return(TNG_CRITICAL);
11553     }
11554
11555     *len = 0;
11556
11557     orig_pos = ftello(tng_data->input_file);
11558
11559     fseeko(tng_data->input_file, 0, SEEK_SET);
11560
11561     tng_block_init(&block);
11562     /* Read through the headers of non-trajectory blocks (they come before the
11563      * trajectory blocks in the file) */
11564     while (*len < tng_data->input_file_len &&
11565            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11566            block->id != -1 &&
11567            block->id != TNG_TRAJECTORY_FRAME_SET)
11568     {
11569         *len += block->header_contents_size + block->block_contents_size;
11570         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11571     }
11572
11573     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
11574
11575     tng_block_destroy(&block);
11576
11577     return(TNG_SUCCESS);
11578 }
11579
11580 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
11581                 (const tng_trajectory_t tng_data,
11582                  const char hash_mode)
11583 {
11584     int64_t prev_pos = 0;
11585     tng_gen_block_t block;
11586
11587     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11588
11589     tng_data->n_trajectory_frame_sets = 0;
11590
11591     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11592     {
11593         return(TNG_CRITICAL);
11594     }
11595
11596     fseeko(tng_data->input_file, 0, SEEK_SET);
11597
11598     tng_block_init(&block);
11599     /* Non trajectory blocks (they come before the trajectory
11600      * blocks in the file) */
11601     while (prev_pos < tng_data->input_file_len &&
11602            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11603            block->id != -1 &&
11604            block->id != TNG_TRAJECTORY_FRAME_SET)
11605     {
11606         tng_block_read_next(tng_data, block, hash_mode);
11607         prev_pos = ftello(tng_data->input_file);
11608     }
11609
11610     /* Go back if a trajectory block was encountered */
11611     if(block->id == TNG_TRAJECTORY_FRAME_SET)
11612     {
11613         fseeko(tng_data->input_file, prev_pos, SEEK_SET);
11614     }
11615
11616     tng_block_destroy(&block);
11617
11618     return(TNG_SUCCESS);
11619 }
11620
11621 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
11622                 (const tng_trajectory_t tng_data,
11623                  const char hash_mode)
11624 {
11625     int i;
11626     int64_t len, orig_len, tot_len = 0, data_start_pos, temp_pos = -1;
11627     tng_function_status stat;
11628     tng_gen_block_t block;
11629
11630     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11631
11632     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
11633     {
11634         return(TNG_CRITICAL);
11635     }
11636
11637     if(tng_data->n_trajectory_frame_sets > 0)
11638     {
11639         stat = tng_file_headers_len_get(tng_data, &orig_len);
11640         if(stat != TNG_SUCCESS)
11641         {
11642             return(stat);
11643         }
11644
11645         tng_block_init(&block);
11646         block->name = (char *)malloc(TNG_MAX_STR_LEN);
11647         if(!block->name)
11648         {
11649             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
11650                     __FILE__, __LINE__);
11651             tng_block_destroy(&block);
11652             return(TNG_CRITICAL);
11653         }
11654         strcpy(block->name, "GENERAL INFO");
11655         tng_block_header_len_calculate(tng_data, block, &len);
11656         tot_len += len;
11657         tng_general_info_block_len_calculate(tng_data, &len);
11658         tot_len += len;
11659         strcpy(block->name, "MOLECULES");
11660         tng_block_header_len_calculate(tng_data, block, &len);
11661         tot_len += len;
11662         tng_molecules_block_len_calculate(tng_data, &len);
11663         tot_len += len;
11664
11665         for(i = 0; i < tng_data->n_data_blocks; i++)
11666         {
11667             strcpy(block->name, tng_data->non_tr_data[i].block_name);
11668             tng_block_header_len_calculate(tng_data, block, &len);
11669             tot_len += len;
11670             tng_data_block_len_calculate(tng_data,
11671                                         (tng_data_t)&tng_data->non_tr_data[i],
11672                                          TNG_FALSE, 1, 1, 1, 0, 1,
11673                                          &data_start_pos,
11674                                          &len);
11675             tot_len += len;
11676         }
11677         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11678         {
11679             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
11680             tng_block_header_len_calculate(tng_data, block, &len);
11681             tot_len += len;
11682             tng_data_block_len_calculate(tng_data,
11683                                          &tng_data->non_tr_particle_data[i],
11684                                          TNG_TRUE, 1, 1, 1, 0,
11685                                          tng_data->n_particles,
11686                                          &data_start_pos,
11687                                          &len);
11688             tot_len += len;
11689         }
11690         tng_block_destroy(&block);
11691
11692         if(tot_len > orig_len)
11693         {
11694             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len, hash_mode);
11695             tng_data->last_trajectory_frame_set_input_file_pos = tng_data->last_trajectory_frame_set_output_file_pos;
11696         }
11697
11698         stat = tng_reread_frame_set_at_file_pos(tng_data, tng_data->last_trajectory_frame_set_input_file_pos);
11699         if(stat == TNG_CRITICAL)
11700         {
11701             fprintf(stderr, "TNG library: Cannot read frame set. %s: %d\n",
11702                     __FILE__, __LINE__);
11703             return(TNG_CRITICAL);
11704         }
11705
11706         /* In order to write non-trajectory data the current_trajectory_frame_set_output_file_pos
11707          * must temporarily be reset */
11708         temp_pos = tng_data->current_trajectory_frame_set_output_file_pos;
11709         tng_data->current_trajectory_frame_set_output_file_pos = -1;
11710     }
11711
11712     if(tng_general_info_block_write(tng_data, hash_mode)
11713        != TNG_SUCCESS)
11714     {
11715         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
11716                 tng_data->input_file_path, __FILE__, __LINE__);
11717         return(TNG_CRITICAL);
11718     }
11719
11720     if(tng_molecules_block_write(tng_data, hash_mode)
11721         != TNG_SUCCESS)
11722     {
11723         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
11724                 tng_data->input_file_path, __FILE__, __LINE__);
11725         return(TNG_CRITICAL);
11726     }
11727
11728     /* FIXME: Currently writing non-trajectory data blocks here.
11729      * Should perhaps be moved. */
11730     tng_block_init(&block);
11731     for(i = 0; i < tng_data->n_data_blocks; i++)
11732     {
11733         block->id = tng_data->non_tr_data[i].block_id;
11734         tng_data_block_write(tng_data, block,
11735                              i, TNG_FALSE, 0, hash_mode);
11736     }
11737
11738     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11739     {
11740         block->id = tng_data->non_tr_particle_data[i].block_id;
11741         tng_data_block_write(tng_data, block,
11742                              i, TNG_TRUE, 0, hash_mode);
11743     }
11744
11745     tng_block_destroy(&block);
11746
11747     /* Continue writing at the end of the file. */
11748     fseeko(tng_data->output_file, 0, SEEK_END);
11749     if(temp_pos > 0)
11750     {
11751         tng_data->current_trajectory_frame_set_output_file_pos = temp_pos;
11752     }
11753
11754     return(TNG_SUCCESS);
11755 }
11756
11757 tng_function_status DECLSPECDLLEXPORT tng_block_read_next
11758                 (const tng_trajectory_t tng_data,
11759                  const tng_gen_block_t block,
11760                  const char hash_mode)
11761 {
11762     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11763     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
11764
11765     switch(block->id)
11766     {
11767     case TNG_TRAJECTORY_FRAME_SET:
11768         return(tng_frame_set_block_read(tng_data, block, hash_mode));
11769     case TNG_PARTICLE_MAPPING:
11770         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
11771     case TNG_GENERAL_INFO:
11772         return(tng_general_info_block_read(tng_data, block, hash_mode));
11773     case TNG_MOLECULES:
11774         return(tng_molecules_block_read(tng_data, block, hash_mode));
11775     default:
11776         if(block->id >= TNG_TRAJ_BOX_SHAPE)
11777         {
11778             return(tng_data_block_contents_read(tng_data, block, hash_mode));
11779         }
11780         else
11781         {
11782             /* Skip to the next block */
11783             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11784             return(TNG_FAILURE);
11785         }
11786     }
11787 }
11788
11789 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
11790                 (const tng_trajectory_t tng_data,
11791                  const char hash_mode)
11792 {
11793     int64_t file_pos;
11794     tng_gen_block_t block;
11795     tng_function_status stat;
11796
11797     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11798
11799     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11800     {
11801         return(TNG_CRITICAL);
11802     }
11803
11804     file_pos = ftello(tng_data->input_file);
11805
11806     tng_block_init(&block);
11807
11808     /* Read block headers first to see what block is found. */
11809     stat = tng_block_header_read(tng_data, block);
11810     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
11811        block->id == -1)
11812     {
11813         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11814                file_pos, __FILE__, __LINE__);
11815         tng_block_destroy(&block);
11816         return(TNG_CRITICAL);
11817     }
11818
11819     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11820
11821     if(tng_block_read_next(tng_data, block,
11822                            hash_mode) == TNG_SUCCESS)
11823     {
11824         tng_data->n_trajectory_frame_sets++;
11825         file_pos = ftello(tng_data->input_file);
11826         /* Read all blocks until next frame set block */
11827         stat = tng_block_header_read(tng_data, block);
11828         while(file_pos < tng_data->input_file_len &&
11829               stat != TNG_CRITICAL &&
11830               block->id != TNG_TRAJECTORY_FRAME_SET &&
11831               block->id != -1)
11832         {
11833             stat = tng_block_read_next(tng_data, block,
11834                                        hash_mode);
11835             if(stat != TNG_CRITICAL)
11836             {
11837                 file_pos = ftello(tng_data->input_file);
11838                 if(file_pos < tng_data->input_file_len)
11839                 {
11840                     stat = tng_block_header_read(tng_data, block);
11841                 }
11842             }
11843         }
11844         if(stat == TNG_CRITICAL)
11845         {
11846             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11847                    file_pos, __FILE__, __LINE__);
11848             tng_block_destroy(&block);
11849             return(stat);
11850         }
11851
11852         if(block->id == TNG_TRAJECTORY_FRAME_SET)
11853         {
11854             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11855         }
11856     }
11857
11858     tng_block_destroy(&block);
11859
11860     return(TNG_SUCCESS);
11861 }
11862
11863
11864 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
11865                 (const tng_trajectory_t tng_data,
11866                  const char hash_mode,
11867                  const int64_t block_id)
11868 {
11869     int64_t file_pos;
11870     tng_gen_block_t block;
11871     tng_function_status stat;
11872     int found_flag = 1;
11873
11874     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11875
11876     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11877     {
11878         return(TNG_CRITICAL);
11879     }
11880
11881     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11882
11883     if(file_pos < 0)
11884     {
11885         /* No current frame set. This means that the first frame set must be
11886          * read */
11887         found_flag = 0;
11888         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11889     }
11890
11891     if(file_pos > 0)
11892     {
11893         fseeko(tng_data->input_file,
11894               file_pos,
11895               SEEK_SET);
11896     }
11897     else
11898     {
11899         return(TNG_FAILURE);
11900     }
11901
11902     tng_block_init(&block);
11903
11904     /* Read block headers first to see what block is found. */
11905     stat = tng_block_header_read(tng_data, block);
11906     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11907     {
11908         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11909                file_pos, __FILE__, __LINE__);
11910         tng_block_destroy(&block);
11911         return(TNG_CRITICAL);
11912     }
11913     /* If the current frame set had already been read skip its block contents */
11914     if(found_flag)
11915     {
11916         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11917     }
11918     /* Otherwise read the frame set block */
11919     else
11920     {
11921         stat = tng_block_read_next(tng_data, block,
11922                                    hash_mode);
11923         if(stat != TNG_SUCCESS)
11924         {
11925             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
11926             tng_block_destroy(&block);
11927             return(stat);
11928         }
11929     }
11930     file_pos = ftello(tng_data->input_file);
11931
11932     found_flag = 0;
11933
11934     /* Read only blocks of the requested ID
11935         * until next frame set block */
11936     stat = tng_block_header_read(tng_data, block);
11937     while(file_pos < tng_data->input_file_len &&
11938           stat != TNG_CRITICAL &&
11939           block->id != TNG_TRAJECTORY_FRAME_SET &&
11940           block->id != -1)
11941     {
11942         if(block->id == block_id)
11943         {
11944             stat = tng_block_read_next(tng_data, block,
11945                                        hash_mode);
11946             if(stat != TNG_CRITICAL)
11947             {
11948                 file_pos = ftello(tng_data->input_file);
11949                 found_flag = 1;
11950                 if(file_pos < tng_data->input_file_len)
11951                 {
11952                     stat = tng_block_header_read(tng_data, block);
11953                 }
11954             }
11955         }
11956         else
11957         {
11958             file_pos += block->block_contents_size + block->header_contents_size;
11959             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11960             if(file_pos < tng_data->input_file_len)
11961             {
11962                 stat = tng_block_header_read(tng_data, block);
11963             }
11964         }
11965     }
11966     if(stat == TNG_CRITICAL)
11967     {
11968         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11969                 file_pos, __FILE__, __LINE__);
11970         tng_block_destroy(&block);
11971         return(stat);
11972     }
11973
11974     if(block->id == TNG_TRAJECTORY_FRAME_SET)
11975     {
11976         fseeko(tng_data->input_file, file_pos, SEEK_SET);
11977     }
11978
11979     tng_block_destroy(&block);
11980
11981     if(found_flag)
11982     {
11983         return(TNG_SUCCESS);
11984     }
11985     else
11986     {
11987         return(TNG_FAILURE);
11988     }
11989 }
11990
11991 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
11992                 (const tng_trajectory_t tng_data,
11993                  const char hash_mode)
11994 {
11995     int64_t file_pos;
11996
11997     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11998
11999     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12000     {
12001         return(TNG_CRITICAL);
12002     }
12003
12004     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12005
12006     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12007     {
12008         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12009     }
12010
12011     if(file_pos > 0)
12012     {
12013         fseeko(tng_data->input_file,
12014                file_pos,
12015                SEEK_SET);
12016     }
12017     else
12018     {
12019         return(TNG_FAILURE);
12020     }
12021
12022     return(tng_frame_set_read(tng_data, hash_mode));
12023 }
12024
12025 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
12026                 (const tng_trajectory_t tng_data,
12027                  const char hash_mode,
12028                  const int64_t block_id)
12029 {
12030     int64_t file_pos;
12031     tng_gen_block_t block;
12032     tng_function_status stat;
12033
12034     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12035
12036     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12037     {
12038         return(TNG_CRITICAL);
12039     }
12040
12041     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12042
12043     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12044     {
12045         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12046     }
12047
12048     if(file_pos > 0)
12049     {
12050         fseeko(tng_data->input_file,
12051                file_pos,
12052                SEEK_SET);
12053     }
12054     else
12055     {
12056         return(TNG_FAILURE);
12057     }
12058
12059     tng_block_init(&block);
12060
12061     /* Read block headers first to see what block is found. */
12062     stat = tng_block_header_read(tng_data, block);
12063     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12064     {
12065         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
12066                 file_pos, __FILE__, __LINE__);
12067         tng_block_destroy(&block);
12068         return(TNG_CRITICAL);
12069     }
12070
12071     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12072
12073     if(tng_block_read_next(tng_data, block,
12074                            hash_mode) == TNG_SUCCESS)
12075     {
12076         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
12077     }
12078
12079     tng_block_destroy(&block);
12080
12081     return(stat);
12082 }
12083
12084 tng_function_status tng_frame_set_write
12085                 (const tng_trajectory_t tng_data,
12086                  const char hash_mode)
12087 {
12088     int i, j;
12089     tng_gen_block_t block;
12090     tng_trajectory_frame_set_t frame_set;
12091     tng_function_status stat;
12092
12093     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12094
12095     frame_set = &tng_data->current_trajectory_frame_set;
12096
12097     if(frame_set->n_written_frames == frame_set->n_frames)
12098     {
12099         return(TNG_SUCCESS);
12100     }
12101
12102     tng_data->current_trajectory_frame_set_output_file_pos =
12103     ftello(tng_data->output_file);
12104     tng_data->last_trajectory_frame_set_output_file_pos =
12105     tng_data->current_trajectory_frame_set_output_file_pos;
12106
12107     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
12108     {
12109         return(TNG_FAILURE);
12110     }
12111
12112     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
12113     {
12114         tng_data->first_trajectory_frame_set_output_file_pos =
12115         tng_data->current_trajectory_frame_set_output_file_pos;
12116     }
12117
12118     tng_block_init(&block);
12119
12120     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
12121     {
12122         tng_block_destroy(&block);
12123         return(TNG_FAILURE);
12124     }
12125
12126     /* Write non-particle data blocks */
12127     for(i = 0; i<frame_set->n_data_blocks; i++)
12128     {
12129         block->id = frame_set->tr_data[i].block_id;
12130         tng_data_block_write(tng_data, block, i, TNG_FALSE, 0, hash_mode);
12131     }
12132     /* Write the mapping blocks and particle data blocks*/
12133     if(frame_set->n_mapping_blocks)
12134     {
12135         for(i = 0; i < frame_set->n_mapping_blocks; i++)
12136         {
12137             block->id = TNG_PARTICLE_MAPPING;
12138             if(frame_set->mappings[i].n_particles > 0)
12139             {
12140                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
12141                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
12142                 {
12143                     block->id = frame_set->tr_particle_data[j].block_id;
12144                     tng_data_block_write(tng_data, block,
12145                                          j, TNG_TRUE, &frame_set->mappings[i],
12146                                          hash_mode);
12147                 }
12148             }
12149         }
12150     }
12151     else
12152     {
12153         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
12154         {
12155             block->id = frame_set->tr_particle_data[i].block_id;
12156             tng_data_block_write(tng_data, block,
12157                                  i, TNG_TRUE, 0, hash_mode);
12158         }
12159     }
12160
12161
12162     /* Update pointers in the general info block */
12163     stat = tng_header_pointers_update(tng_data, hash_mode);
12164
12165     if(stat == TNG_SUCCESS)
12166     {
12167         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
12168     }
12169
12170     tng_block_destroy(&block);
12171
12172     frame_set->n_unwritten_frames = 0;
12173
12174     fflush(tng_data->output_file);
12175
12176     return(stat);
12177 }
12178
12179 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
12180                 (const tng_trajectory_t tng_data,
12181                  const char hash_mode)
12182 {
12183     tng_trajectory_frame_set_t frame_set;
12184
12185     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12186
12187     frame_set = &tng_data->current_trajectory_frame_set;
12188
12189     if(frame_set->n_unwritten_frames == 0)
12190     {
12191         return(TNG_SUCCESS);
12192     }
12193     frame_set->n_frames = frame_set->n_unwritten_frames;
12194
12195     return(tng_frame_set_write(tng_data, hash_mode));
12196 }
12197
12198 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
12199                 (const tng_trajectory_t tng_data,
12200                  const int64_t first_frame,
12201                  const int64_t n_frames)
12202 {
12203     tng_gen_block_t block;
12204     tng_trajectory_frame_set_t frame_set;
12205     FILE *temp = tng_data->input_file;
12206     int64_t curr_file_pos;
12207
12208     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12209     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12210     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12211
12212     frame_set = &tng_data->current_trajectory_frame_set;
12213
12214     curr_file_pos = ftello(tng_data->output_file);
12215
12216     if(curr_file_pos <= 10)
12217     {
12218         tng_file_headers_write(tng_data, TNG_USE_HASH);
12219     }
12220
12221     /* Set pointer to previous frame set to the one that was loaded
12222      * before.
12223      * FIXME: This is a bit risky. If they are not added in order
12224      * it will be wrong. */
12225     if(tng_data->n_trajectory_frame_sets)
12226     {
12227         frame_set->prev_frame_set_file_pos =
12228         tng_data->last_trajectory_frame_set_output_file_pos;
12229     }
12230
12231     frame_set->next_frame_set_file_pos = -1;
12232
12233     tng_data->current_trajectory_frame_set_output_file_pos =
12234     ftello(tng_data->output_file);
12235
12236     tng_data->n_trajectory_frame_sets++;
12237
12238     /* Set the medium range pointers */
12239     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
12240     {
12241         frame_set->medium_stride_prev_frame_set_file_pos =
12242         tng_data->first_trajectory_frame_set_output_file_pos;
12243     }
12244     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12245     {
12246         /* FIXME: Currently only working if the previous frame set has its
12247          * medium stride pointer already set. This might need some fixing. */
12248         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
12249            frame_set->medium_stride_prev_frame_set_file_pos != 0)
12250         {
12251             tng_block_init(&block);
12252             tng_data->input_file = tng_data->output_file;
12253
12254             curr_file_pos = ftello(tng_data->output_file);
12255             fseeko(tng_data->output_file,
12256                    frame_set->medium_stride_prev_frame_set_file_pos,
12257                    SEEK_SET);
12258
12259             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12260             {
12261                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12262                     __FILE__, __LINE__);
12263                 tng_data->input_file = temp;
12264                 tng_block_destroy(&block);
12265                 return(TNG_CRITICAL);
12266             }
12267
12268             /* Read the next frame set from the previous frame set and one
12269              * medium stride step back */
12270             fseeko(tng_data->output_file, block->block_contents_size - (6 *
12271             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
12272             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
12273                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
12274                1, tng_data->output_file) == 0)
12275             {
12276                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12277                 tng_data->input_file = temp;
12278                 tng_block_destroy(&block);
12279                 return(TNG_CRITICAL);
12280             }
12281
12282             if(tng_data->input_endianness_swap_func_64)
12283             {
12284                 if(tng_data->input_endianness_swap_func_64(tng_data,
12285                    (uint64_t *)&frame_set->medium_stride_prev_frame_set_file_pos)
12286                     != TNG_SUCCESS)
12287                 {
12288                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12289                             __FILE__, __LINE__);
12290                 }
12291             }
12292
12293             tng_block_destroy(&block);
12294
12295             /* Set the long range pointers */
12296             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
12297             {
12298                 frame_set->long_stride_prev_frame_set_file_pos =
12299                 tng_data->first_trajectory_frame_set_output_file_pos;
12300             }
12301             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12302             {
12303                 /* FIXME: Currently only working if the previous frame set has its
12304                 * long stride pointer already set. This might need some fixing. */
12305                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
12306                 frame_set->long_stride_prev_frame_set_file_pos != 0)
12307                 {
12308                     tng_block_init(&block);
12309                     tng_data->input_file = tng_data->output_file;
12310
12311                     fseeko(tng_data->output_file,
12312                            frame_set->long_stride_prev_frame_set_file_pos,
12313                            SEEK_SET);
12314
12315                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12316                     {
12317                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12318                             __FILE__, __LINE__);
12319                         tng_data->input_file = temp;
12320                         tng_block_destroy(&block);
12321                         return(TNG_CRITICAL);
12322                     }
12323
12324                     /* Read the next frame set from the previous frame set and one
12325                     * long stride step back */
12326                     fseeko(tng_data->output_file, block->block_contents_size - (6 *
12327                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
12328
12329                     tng_block_destroy(&block);
12330
12331                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
12332                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
12333                     1, tng_data->output_file) == 0)
12334                     {
12335                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12336                         tng_data->input_file = temp;
12337                         return(TNG_CRITICAL);
12338                     }
12339
12340                     if(tng_data->input_endianness_swap_func_64)
12341                     {
12342                         if(tng_data->input_endianness_swap_func_64(tng_data,
12343                            (uint64_t *)&frame_set->long_stride_prev_frame_set_file_pos)
12344                             != TNG_SUCCESS)
12345                         {
12346                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12347                                     __FILE__, __LINE__);
12348                         }
12349                     }
12350
12351                 }
12352             }
12353
12354             tng_data->input_file = temp;
12355             fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
12356         }
12357     }
12358
12359     frame_set->first_frame = first_frame;
12360     frame_set->n_frames = n_frames;
12361     frame_set->n_written_frames = 0;
12362     frame_set->n_unwritten_frames = 0;
12363     frame_set->first_frame_time = -1;
12364
12365     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
12366        tng_data->first_trajectory_frame_set_output_file_pos == 0)
12367     {
12368         tng_data->first_trajectory_frame_set_output_file_pos =
12369         tng_data->current_trajectory_frame_set_output_file_pos;
12370     }
12371     /* FIXME: Should check the frame number instead of the file_pos,
12372      * in case frame sets are not in order */
12373     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
12374        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
12375        tng_data->last_trajectory_frame_set_output_file_pos <
12376        tng_data->current_trajectory_frame_set_output_file_pos)
12377     {
12378         tng_data->last_trajectory_frame_set_output_file_pos =
12379         tng_data->current_trajectory_frame_set_output_file_pos;
12380     }
12381
12382     return(TNG_SUCCESS);
12383 }
12384
12385 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
12386                 (const tng_trajectory_t tng_data,
12387                  const int64_t first_frame,
12388                  const int64_t n_frames,
12389                  const double first_frame_time)
12390 {
12391     tng_function_status stat;
12392
12393     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12394     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12395     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12396     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12397
12398
12399     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
12400     if(stat != TNG_SUCCESS)
12401     {
12402         return(stat);
12403     }
12404     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
12405
12406     return(stat);
12407 }
12408
12409 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
12410                 (const tng_trajectory_t tng_data,
12411                  const double first_frame_time)
12412 {
12413     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12414     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12415
12416     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
12417
12418     return(TNG_SUCCESS);
12419 }
12420
12421 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
12422                 (const tng_trajectory_t tng_data,
12423                  int64_t *frame)
12424 {
12425     int64_t file_pos, next_frame_set_file_pos;
12426     tng_gen_block_t block;
12427     tng_function_status stat;
12428
12429     tng_trajectory_frame_set_t frame_set;
12430
12431     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12432     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
12433     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
12434
12435     file_pos = ftello(tng_data->input_file);
12436
12437     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12438     {
12439         next_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12440     }
12441     else
12442     {
12443         frame_set = &tng_data->current_trajectory_frame_set;
12444         next_frame_set_file_pos = frame_set->next_frame_set_file_pos;
12445     }
12446
12447     if(next_frame_set_file_pos <= 0)
12448     {
12449         return(TNG_FAILURE);
12450     }
12451
12452     fseeko(tng_data->input_file, next_frame_set_file_pos, SEEK_SET);
12453     /* Read block headers first to see that a frame set block is found. */
12454     tng_block_init(&block);
12455     stat = tng_block_header_read(tng_data, block);
12456     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12457     {
12458         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
12459                file_pos, __FILE__, __LINE__);
12460         return(TNG_CRITICAL);
12461     }
12462 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12463     {
12464         tng_block_read_next(tng_data, block, TNG_USE_HASH);
12465     }*/
12466     tng_block_destroy(&block);
12467
12468     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
12469     {
12470         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
12471                __FILE__, __LINE__);
12472         return(TNG_CRITICAL);
12473     }
12474     fseeko(tng_data->input_file, file_pos, SEEK_SET);
12475
12476     return(TNG_SUCCESS);
12477 }
12478
12479 static tng_function_status tng_gen_data_block_add
12480                 (const tng_trajectory_t tng_data,
12481                  const int64_t id,
12482                  const tng_bool is_particle_data,
12483                  const char *block_name,
12484                  const char datatype,
12485                  const char block_type_flag,
12486                  int64_t n_frames,
12487                  const int64_t n_values_per_frame,
12488                  int64_t stride_length,
12489                  const int64_t num_first_particle,
12490                  const int64_t n_particles,
12491                  const int64_t codec_id,
12492                  void *new_data)
12493 {
12494     int i, size, len;
12495     int64_t j, k;
12496     int64_t tot_n_particles, n_frames_div;
12497     char ***first_dim_values, **second_dim_values;
12498     tng_trajectory_frame_set_t frame_set;
12499     tng_data_t data;
12500     char *new_data_c = (char *)new_data;
12501     tng_function_status stat;
12502
12503     frame_set = &tng_data->current_trajectory_frame_set;
12504
12505     if(stride_length <= 0)
12506     {
12507         stride_length = 1;
12508     }
12509
12510     if(is_particle_data)
12511     {
12512         stat = tng_particle_data_find(tng_data, id, &data);
12513     }
12514     else
12515     {
12516         stat = tng_data_find(tng_data, id, &data);
12517     }
12518     /* If the block does not exist, create it */
12519     if(stat != TNG_SUCCESS)
12520     {
12521         if(is_particle_data)
12522         {
12523             stat = tng_particle_data_block_create(tng_data, block_type_flag);
12524         }
12525         else
12526         {
12527             stat = tng_data_block_create(tng_data, block_type_flag);
12528         }
12529
12530         if(stat != TNG_SUCCESS)
12531         {
12532             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
12533                    __FILE__, __LINE__);
12534             return(TNG_CRITICAL);
12535         }
12536         if(is_particle_data)
12537         {
12538             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12539             {
12540                 data = &frame_set->tr_particle_data[frame_set->
12541                                                     n_particle_data_blocks - 1];
12542             }
12543             else
12544             {
12545                 data = &tng_data->non_tr_particle_data[tng_data->
12546                                                     n_particle_data_blocks - 1];
12547             }
12548         }
12549         else
12550         {
12551             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12552             {
12553                 data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
12554             }
12555             else
12556             {
12557                 data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
12558             }
12559         }
12560         data->block_id = id;
12561
12562         data->block_name = (char *)malloc(strlen(block_name) + 1);
12563         if(!data->block_name)
12564         {
12565             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
12566                     __FILE__, __LINE__);
12567             return(TNG_CRITICAL);
12568         }
12569         strncpy(data->block_name, block_name, strlen(block_name) + 1);
12570
12571         data->values = 0;
12572         /* FIXME: Memory leak from strings. */
12573         data->strings = 0;
12574         data->last_retrieved_frame = -1;
12575     }
12576
12577     data->datatype = datatype;
12578     data->stride_length = tng_max_i64(stride_length, 1);
12579     data->n_values_per_frame = n_values_per_frame;
12580     data->n_frames = n_frames;
12581     if(is_particle_data)
12582     {
12583         data->dependency = TNG_PARTICLE_DEPENDENT;
12584     }
12585     else
12586     {
12587         data->dependency = 0;
12588     }
12589     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
12590                           (n_frames > 1 ||
12591                            frame_set->n_frames == n_frames ||
12592                            stride_length > 1))
12593     {
12594         data->dependency += TNG_FRAME_DEPENDENT;
12595     }
12596     data->codec_id = codec_id;
12597     data->compression_multiplier = 1.0;
12598     /* FIXME: This can cause problems. */
12599     data->first_frame_with_data = frame_set->first_frame;
12600
12601     if(is_particle_data)
12602     {
12603         if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
12604         {
12605             tot_n_particles = frame_set->n_particles;
12606         }
12607         else
12608         {
12609             tot_n_particles = tng_data->n_particles;
12610         }
12611     }
12612     /* This is just to keep the compiler happy - avoid it considering tot_n_particles
12613      * uninitialized. */
12614     else
12615     {
12616         tot_n_particles = 0;
12617     }
12618
12619     /* If data values are supplied add that data to the data block. */
12620     if(new_data_c)
12621     {
12622         /* Allocate memory */
12623         if(is_particle_data)
12624         {
12625             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
12626                                             stride_length, tot_n_particles,
12627                                             n_values_per_frame);
12628         }
12629         else
12630         {
12631             stat = tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
12632                                  n_values_per_frame);
12633         }
12634         if(stat != TNG_SUCCESS)
12635         {
12636             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
12637                 __FILE__, __LINE__);
12638             return(TNG_CRITICAL);
12639         }
12640
12641         if(n_frames > frame_set->n_unwritten_frames)
12642         {
12643             frame_set->n_unwritten_frames = n_frames;
12644         }
12645
12646         n_frames_div = (n_frames % stride_length) ?
12647                      n_frames / stride_length + 1:
12648                      n_frames / stride_length;
12649
12650         if(datatype == TNG_CHAR_DATA)
12651         {
12652             if(is_particle_data)
12653             {
12654                 for(i = 0; i < n_frames_div; i++)
12655                 {
12656                     first_dim_values = data->strings[i];
12657                     for(j = num_first_particle; j < num_first_particle + n_particles;
12658                         j++)
12659                     {
12660                         second_dim_values = first_dim_values[j];
12661                         for(k = 0; k < n_values_per_frame; k++)
12662                         {
12663                             len = tng_min_size(strlen(new_data_c) + 1,
12664                                     TNG_MAX_STR_LEN);
12665                             if(second_dim_values[k])
12666                             {
12667                                 free(second_dim_values[k]);
12668                             }
12669                             second_dim_values[k] = (char *)malloc(len);
12670                             if(!second_dim_values[k])
12671                             {
12672                                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
12673                                         __FILE__, __LINE__);
12674                                 return(TNG_CRITICAL);
12675                             }
12676                             strncpy(second_dim_values[k],
12677                                     new_data_c, len);
12678                             new_data_c += len;
12679                         }
12680                     }
12681                 }
12682             }
12683             else
12684             {
12685                 for(i = 0; i < n_frames_div; i++)
12686                 {
12687                     second_dim_values = data->strings[0][i];
12688                     for(j = 0; j < n_values_per_frame; j++)
12689                     {
12690                         len = tng_min_size(strlen(new_data_c) + 1,
12691                                     TNG_MAX_STR_LEN);
12692                         if(second_dim_values[j])
12693                         {
12694                             free(second_dim_values[j]);
12695                         }
12696                         second_dim_values[j] = (char *)malloc(len);
12697                         if(!second_dim_values[j])
12698                         {
12699                             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
12700                                     __FILE__, __LINE__);
12701                             return(TNG_CRITICAL);
12702                         }
12703                         strncpy(second_dim_values[j],
12704                                 new_data_c, len);
12705                         new_data_c += len;
12706                     }
12707                 }
12708             }
12709         }
12710         else
12711         {
12712             switch(datatype)
12713             {
12714             case TNG_INT_DATA:
12715                 size = sizeof(int64_t);
12716                 break;
12717             case TNG_FLOAT_DATA:
12718                 size = sizeof(float);
12719                 break;
12720             case TNG_DOUBLE_DATA:
12721             default:
12722                 size = sizeof(double);
12723             }
12724
12725             if(is_particle_data)
12726             {
12727                 memcpy(data->values, new_data, size * n_frames_div *
12728                     n_particles * n_values_per_frame);
12729             }
12730             else
12731             {
12732                 memcpy(data->values, new_data, size * n_frames_div *
12733                     n_values_per_frame);
12734             }
12735         }
12736     }
12737
12738     return(TNG_SUCCESS);
12739 }
12740
12741 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
12742                 (const tng_trajectory_t tng_data,
12743                  const int64_t id,
12744                  const char *block_name,
12745                  const char datatype,
12746                  const char block_type_flag,
12747                  int64_t n_frames,
12748                  const int64_t n_values_per_frame,
12749                  int64_t stride_length,
12750                  const int64_t codec_id,
12751                  void *new_data)
12752 {
12753     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12754     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
12755     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12756
12757     return(tng_gen_data_block_add(tng_data, id, TNG_FALSE, block_name, datatype,
12758                                   block_type_flag, n_frames, n_values_per_frame,
12759                                   stride_length, 0, 0, codec_id, new_data));
12760 }
12761
12762 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
12763                 (const tng_trajectory_t tng_data,
12764                  const int64_t id,
12765                  const char *block_name,
12766                  const char datatype,
12767                  const char block_type_flag,
12768                  int64_t n_frames,
12769                  const int64_t n_values_per_frame,
12770                  int64_t stride_length,
12771                  const int64_t num_first_particle,
12772                  const int64_t n_particles,
12773                  const int64_t codec_id,
12774                  void *new_data)
12775 {
12776     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12777     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
12778     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12779     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
12780     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
12781
12782     return(tng_gen_data_block_add(tng_data, id, TNG_TRUE, block_name, datatype,
12783                                   block_type_flag, n_frames, n_values_per_frame,
12784                                   stride_length, num_first_particle, n_particles,
12785                                   codec_id, new_data));
12786 }
12787
12788 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
12789                 (const tng_trajectory_t tng_data,
12790                  const int64_t block_id,
12791                  char *name,
12792                  const int max_len)
12793 {
12794     int64_t i;
12795     tng_trajectory_frame_set_t frame_set;
12796     tng_function_status stat;
12797     tng_data_t data;
12798     int block_type = -1;
12799
12800     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12801     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
12802
12803     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12804     {
12805         data = &tng_data->non_tr_particle_data[i];
12806         if(data->block_id == block_id)
12807         {
12808             strncpy(name, data->block_name, max_len);
12809             name[max_len - 1] = '\0';
12810             return(TNG_SUCCESS);
12811         }
12812     }
12813     for(i = 0; i < tng_data->n_data_blocks; i++)
12814     {
12815         data = &tng_data->non_tr_data[i];
12816         if(data->block_id == block_id)
12817         {
12818             strncpy(name, data->block_name, max_len);
12819             name[max_len - 1] = '\0';
12820             return(TNG_SUCCESS);
12821         }
12822     }
12823
12824     frame_set = &tng_data->current_trajectory_frame_set;
12825
12826     stat = tng_particle_data_find(tng_data, block_id, &data);
12827     if(stat == TNG_SUCCESS)
12828     {
12829         block_type = TNG_PARTICLE_BLOCK_DATA;
12830     }
12831     else
12832     {
12833         stat = tng_data_find(tng_data, block_id, &data);
12834         if(stat == TNG_SUCCESS)
12835         {
12836             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
12837         }
12838         else
12839         {
12840             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
12841             if(stat != TNG_SUCCESS)
12842             {
12843                 return(stat);
12844             }
12845             stat = tng_particle_data_find(tng_data, block_id, &data);
12846             if(stat == TNG_SUCCESS)
12847             {
12848                 block_type = TNG_PARTICLE_BLOCK_DATA;
12849             }
12850             else
12851             {
12852                 stat = tng_data_find(tng_data, block_id, &data);
12853                 if(stat == TNG_SUCCESS)
12854                 {
12855                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
12856                 }
12857             }
12858         }
12859     }
12860     if(block_type == TNG_PARTICLE_BLOCK_DATA)
12861     {
12862         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
12863         {
12864             data = &frame_set->tr_particle_data[i];
12865             if(data->block_id == block_id)
12866             {
12867                 strncpy(name, data->block_name, max_len);
12868                 name[max_len - 1] = '\0';
12869                 return(TNG_SUCCESS);
12870             }
12871         }
12872     }
12873     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
12874     {
12875         for(i = 0; i < frame_set->n_data_blocks; i++)
12876         {
12877             data = &frame_set->tr_data[i];
12878             if(data->block_id == block_id)
12879             {
12880                 strncpy(name, data->block_name, max_len);
12881                 name[max_len - 1] = '\0';
12882                 return(TNG_SUCCESS);
12883             }
12884         }
12885     }
12886
12887     return(TNG_FAILURE);
12888 }
12889
12890 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
12891                 (const tng_trajectory_t tng_data,
12892                  const int64_t block_id,
12893                  int *block_dependency)
12894 {
12895     int64_t i;
12896     tng_function_status stat;
12897     tng_data_t data;
12898
12899     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12900     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
12901
12902     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12903     {
12904         data = &tng_data->non_tr_particle_data[i];
12905         if(data->block_id == block_id)
12906         {
12907             *block_dependency = TNG_PARTICLE_DEPENDENT;
12908             return(TNG_SUCCESS);
12909         }
12910     }
12911     for(i = 0; i < tng_data->n_data_blocks; i++)
12912     {
12913         data = &tng_data->non_tr_data[i];
12914         if(data->block_id == block_id)
12915         {
12916             *block_dependency = 0;
12917             return(TNG_SUCCESS);
12918         }
12919     }
12920
12921     stat = tng_particle_data_find(tng_data, block_id, &data);
12922     if(stat == TNG_SUCCESS)
12923     {
12924         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
12925         return(TNG_SUCCESS);
12926     }
12927     else
12928     {
12929         stat = tng_data_find(tng_data, block_id, &data);
12930         if(stat == TNG_SUCCESS)
12931         {
12932             *block_dependency = TNG_FRAME_DEPENDENT;
12933             return(TNG_SUCCESS);
12934         }
12935         else
12936         {
12937             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
12938             if(stat != TNG_SUCCESS)
12939             {
12940                 return(stat);
12941             }
12942             stat = tng_particle_data_find(tng_data, block_id, &data);
12943             if(stat == TNG_SUCCESS)
12944             {
12945                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
12946                 return(TNG_SUCCESS);
12947             }
12948             else
12949             {
12950                 stat = tng_data_find(tng_data, block_id, &data);
12951                 if(stat == TNG_SUCCESS)
12952                 {
12953                     *block_dependency = TNG_FRAME_DEPENDENT;
12954                     return(TNG_SUCCESS);
12955                 }
12956             }
12957         }
12958     }
12959
12960     return(TNG_FAILURE);
12961 }
12962
12963 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
12964                 (const tng_trajectory_t tng_data,
12965                  const int64_t block_id,
12966                  int64_t *n_values_per_frame)
12967 {
12968     int64_t i;
12969     tng_function_status stat;
12970     tng_data_t data;
12971
12972     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12973     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
12974
12975     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12976     {
12977         data = &tng_data->non_tr_particle_data[i];
12978         if(data->block_id == block_id)
12979         {
12980             *n_values_per_frame = data->n_values_per_frame;
12981             return(TNG_SUCCESS);
12982         }
12983     }
12984     for(i = 0; i < tng_data->n_data_blocks; i++)
12985     {
12986         data = &tng_data->non_tr_data[i];
12987         if(data->block_id == block_id)
12988         {
12989             *n_values_per_frame = data->n_values_per_frame;
12990             return(TNG_SUCCESS);
12991         }
12992     }
12993
12994     stat = tng_particle_data_find(tng_data, block_id, &data);
12995     if(stat == TNG_SUCCESS)
12996     {
12997         *n_values_per_frame = data->n_values_per_frame;
12998         return(TNG_SUCCESS);
12999     }
13000     else
13001     {
13002         stat = tng_data_find(tng_data, block_id, &data);
13003         if(stat == TNG_SUCCESS)
13004         {
13005             *n_values_per_frame = data->n_values_per_frame;
13006             return(TNG_SUCCESS);
13007         }
13008         else
13009         {
13010             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13011             if(stat != TNG_SUCCESS)
13012             {
13013                 return(stat);
13014             }
13015             stat = tng_particle_data_find(tng_data, block_id, &data);
13016             if(stat == TNG_SUCCESS)
13017             {
13018                 *n_values_per_frame = data->n_values_per_frame;
13019                 return(TNG_SUCCESS);
13020             }
13021             else
13022             {
13023                 stat = tng_data_find(tng_data, block_id, &data);
13024                 if(stat == TNG_SUCCESS)
13025                 {
13026                     *n_values_per_frame = data->n_values_per_frame;
13027                     return(TNG_SUCCESS);
13028                 }
13029             }
13030         }
13031     }
13032
13033     return(TNG_FAILURE);
13034 }
13035
13036 tng_function_status DECLSPECDLLEXPORT tng_frame_set_n_frames_of_data_block_get
13037                 (const tng_trajectory_t tng_data,
13038                  const int64_t block_id,
13039                  int64_t *n_frames)
13040 {
13041     tng_gen_block_t block;
13042     tng_function_status stat;
13043     char datatype, dependency, sparse_data;
13044     int64_t n_values, codec_id, first_frame_with_data, stride_length, curr_n_frames;
13045     int64_t num_first_particle, block_n_particles;
13046     double multiplier;
13047     md5_state_t md5_state;
13048     int found = TNG_FALSE;
13049
13050     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13051
13052     tng_block_init(&block);
13053
13054     stat = tng_block_header_read(tng_data, block);
13055     /* If the block header could not be read the reading position might not have been
13056      * at the start of a block. Try again from the file position of the current frame
13057      * set. */
13058     if(stat != TNG_SUCCESS)
13059     {
13060         fseeko(tng_data->input_file, tng_data->current_trajectory_frame_set_input_file_pos, SEEK_SET);
13061         stat = tng_block_header_read(tng_data, block);
13062         if(stat != TNG_SUCCESS)
13063         {
13064             tng_block_destroy(&block);
13065             return(stat);
13066         }
13067     }
13068     if(block->id == TNG_TRAJECTORY_FRAME_SET)
13069     {
13070         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
13071         if(stat != TNG_SUCCESS)
13072         {
13073             tng_block_destroy(&block);
13074             return(stat);
13075         }
13076         stat = tng_block_header_read(tng_data, block);
13077     }
13078     while(stat == TNG_SUCCESS && block->id != TNG_TRAJECTORY_FRAME_SET && found == TNG_FALSE)
13079     {
13080         if(block->id == block_id)
13081         {
13082             stat = tng_data_block_meta_information_read(tng_data, &datatype,
13083                                                         &dependency, &sparse_data,
13084                                                         &n_values, &codec_id,
13085                                                         &first_frame_with_data,
13086                                                         &stride_length, &curr_n_frames,
13087                                                         &num_first_particle,
13088                                                         &block_n_particles,
13089                                                         &multiplier, TNG_SKIP_HASH,
13090                                                         &md5_state);
13091             if(stat == TNG_SUCCESS)
13092             {
13093                 found = TNG_TRUE;
13094             }
13095         }
13096         else
13097         {
13098             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
13099             stat = tng_block_header_read(tng_data, block);
13100         }
13101     }
13102     if(found == TNG_TRUE)
13103     {
13104         *n_frames = (tng_data->current_trajectory_frame_set.n_frames -
13105                      (tng_data->current_trajectory_frame_set.first_frame - first_frame_with_data)) / stride_length;
13106     }
13107     else if(stat == TNG_SUCCESS)
13108     {
13109         *n_frames = 0;
13110     }
13111
13112     tng_block_destroy(&block);
13113
13114     return(stat);
13115 }
13116
13117 static tng_function_status tng_frame_gen_data_write
13118                 (const tng_trajectory_t tng_data,
13119                  const int64_t frame_nr,
13120                  const int64_t block_id,
13121                  const tng_bool is_particle_data,
13122                  const int64_t val_first_particle,
13123                  const int64_t val_n_particles,
13124                  const void *values,
13125                  const char hash_mode)
13126 {
13127     int64_t header_pos, file_pos, tot_n_particles;
13128     int64_t output_file_len, n_values_per_frame, size, contents_size;
13129     int64_t header_size, temp_first, temp_last;
13130     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
13131     int64_t i, last_frame, temp_current, write_n_particles;
13132     tng_gen_block_t block;
13133     tng_trajectory_frame_set_t frame_set;
13134     FILE *temp = tng_data->input_file;
13135     struct tng_data data;
13136     tng_function_status stat;
13137     tng_particle_mapping_t mapping;
13138     char dependency, sparse_data, datatype;
13139     void *copy;
13140
13141     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13142     {
13143         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13144                __FILE__, __LINE__);
13145         return(TNG_CRITICAL);
13146     }
13147
13148     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13149     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13150     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13151     tng_data->first_trajectory_frame_set_input_file_pos =
13152     tng_data->first_trajectory_frame_set_output_file_pos;
13153     tng_data->last_trajectory_frame_set_input_file_pos =
13154     tng_data->last_trajectory_frame_set_output_file_pos;
13155     tng_data->current_trajectory_frame_set_input_file_pos =
13156     tng_data->current_trajectory_frame_set_output_file_pos;
13157
13158     tng_data->input_file = tng_data->output_file;
13159
13160     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13161
13162     frame_set = &tng_data->current_trajectory_frame_set;
13163
13164     if(stat != TNG_SUCCESS)
13165     {
13166         last_frame = frame_set->first_frame +
13167                      frame_set->n_frames - 1;
13168         /* If the wanted frame would be in the frame set after the last
13169             * frame set create a new frame set. */
13170         if(stat == TNG_FAILURE &&
13171             last_frame < frame_nr)
13172 /*           (last_frame < frame_nr &&
13173             tng_data->current_trajectory_frame_set.first_frame +
13174             tng_data->frame_set_n_frames >= frame_nr))*/
13175         {
13176             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13177             {
13178                 last_frame = frame_nr - 1;
13179             }
13180             tng_frame_set_new(tng_data,
13181                               last_frame+1,
13182                               tng_data->frame_set_n_frames);
13183             file_pos = ftello(tng_data->output_file);
13184             fseeko(tng_data->output_file, 0, SEEK_END);
13185             output_file_len = ftello(tng_data->output_file);
13186             fseeko(tng_data->output_file, file_pos, SEEK_SET);
13187
13188             /* Read mapping blocks from the last frame set */
13189             tng_block_init(&block);
13190
13191             stat = tng_block_header_read(tng_data, block);
13192             while(file_pos < output_file_len &&
13193                   stat != TNG_CRITICAL &&
13194                   block->id != TNG_TRAJECTORY_FRAME_SET &&
13195                   block->id != -1)
13196             {
13197                 if(block->id == TNG_PARTICLE_MAPPING)
13198                 {
13199                     tng_trajectory_mapping_block_read(tng_data, block,
13200                                                       hash_mode);
13201                 }
13202                 else
13203                 {
13204                     fseeko(tng_data->output_file, block->block_contents_size,
13205                         SEEK_CUR);
13206                 }
13207                 file_pos = ftello(tng_data->output_file);
13208                 if(file_pos < output_file_len)
13209                 {
13210                     stat = tng_block_header_read(tng_data, block);
13211                 }
13212             }
13213
13214             tng_block_destroy(&block);
13215             /* Write the frame set to disk */
13216             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13217             {
13218                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13219                 return(TNG_CRITICAL);
13220             }
13221         }
13222         else
13223         {
13224             tng_data->input_file = temp;
13225             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13226             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13227             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13228             return(stat);
13229         }
13230     }
13231
13232     tng_block_init(&block);
13233
13234     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13235
13236     fseeko(tng_data->output_file, 0, SEEK_END);
13237     output_file_len = ftello(tng_data->output_file);
13238     fseeko(tng_data->output_file, file_pos, SEEK_SET);
13239
13240     /* Read past the frame set block first */
13241     stat = tng_block_header_read(tng_data, block);
13242     if(stat == TNG_CRITICAL)
13243     {
13244         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13245                file_pos, __FILE__, __LINE__);
13246         tng_block_destroy(&block);
13247         tng_data->input_file = temp;
13248
13249         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13250         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13251         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13252         return(stat);
13253     }
13254     fseeko(tng_data->output_file, block->block_contents_size,
13255             SEEK_CUR);
13256
13257     if(is_particle_data == TNG_TRUE)
13258     {
13259         if(tng_data->var_num_atoms_flag)
13260         {
13261             tot_n_particles = frame_set->n_particles;
13262         }
13263         else
13264         {
13265             tot_n_particles = tng_data->n_particles;
13266         }
13267
13268         if(val_n_particles < tot_n_particles)
13269         {
13270             mapping_block_end_pos = -1;
13271             /* Read all mapping blocks to find the right place to put the data */
13272             stat = tng_block_header_read(tng_data, block);
13273             while(file_pos < output_file_len &&
13274                     stat != TNG_CRITICAL &&
13275                     block->id != TNG_TRAJECTORY_FRAME_SET &&
13276                     block->id != -1)
13277             {
13278                 if(block->id == TNG_PARTICLE_MAPPING)
13279                 {
13280                     tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
13281                 }
13282                 else
13283                 {
13284                     fseeko(tng_data->output_file, block->block_contents_size,
13285                            SEEK_CUR);
13286                 }
13287                 file_pos = ftello(tng_data->output_file);
13288                 if(block->id == TNG_PARTICLE_MAPPING)
13289                 {
13290                     mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
13291                     if(val_first_particle >= mapping->num_first_particle &&
13292                        val_first_particle < mapping->num_first_particle +
13293                        mapping->n_particles &&
13294                        val_first_particle + val_n_particles <=
13295                        mapping->num_first_particle + mapping->n_particles)
13296                     {
13297                         mapping_block_end_pos = file_pos;
13298                     }
13299                 }
13300                 if(file_pos < output_file_len)
13301                 {
13302                     stat = tng_block_header_read(tng_data, block);
13303                 }
13304             }
13305             if(stat == TNG_CRITICAL)
13306             {
13307                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13308                        file_pos, __FILE__, __LINE__);
13309                 tng_block_destroy(&block);
13310                 tng_data->input_file = temp;
13311
13312                 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13313                 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13314                 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13315                 return(stat);
13316             }
13317             if(mapping_block_end_pos < 0)
13318             {
13319                 tng_block_destroy(&block);
13320                 tng_data->input_file = temp;
13321
13322                 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13323                 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13324                 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13325                 return(TNG_FAILURE);
13326             }
13327             fseeko(tng_data->output_file, mapping_block_end_pos, SEEK_SET);
13328         }
13329     }
13330
13331     /* Read all block headers until next frame set block or
13332      * until the wanted block id is found */
13333     stat = tng_block_header_read(tng_data, block);
13334     while(file_pos < output_file_len &&
13335             stat != TNG_CRITICAL &&
13336             block->id != block_id &&
13337             (is_particle_data != TNG_TRUE || block->id != TNG_PARTICLE_MAPPING) &&
13338             block->id != TNG_TRAJECTORY_FRAME_SET &&
13339             block->id != -1)
13340     {
13341         fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
13342         file_pos = ftello(tng_data->output_file);
13343         if(file_pos < output_file_len)
13344         {
13345             stat = tng_block_header_read(tng_data, block);
13346         }
13347     }
13348     if(stat == TNG_CRITICAL)
13349     {
13350         fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13351                file_pos, __FILE__, __LINE__);
13352         tng_block_destroy(&block);
13353         tng_data->input_file = temp;
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(stat);
13358     }
13359
13360     contents_size = block->block_contents_size;
13361     header_size = block->header_contents_size;
13362
13363     header_pos = ftello(tng_data->output_file) - header_size;
13364     frame_set = &tng_data->current_trajectory_frame_set;
13365
13366     if(tng_file_input_numerical(tng_data, &datatype,
13367                                  sizeof(datatype),
13368                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13369     {
13370         tng_block_destroy(&block);
13371         return(TNG_CRITICAL);
13372     }
13373     if(tng_file_input_numerical(tng_data, &dependency,
13374                                  sizeof(dependency),
13375                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13376     {
13377         tng_block_destroy(&block);
13378         return(TNG_CRITICAL);
13379     }
13380     data.datatype = datatype;
13381
13382     if(!(dependency & TNG_FRAME_DEPENDENT) ||
13383        (is_particle_data == TNG_FALSE && dependency & TNG_PARTICLE_DEPENDENT) ||
13384        (is_particle_data == TNG_TRUE && !(dependency & TNG_PARTICLE_DEPENDENT)))
13385     {
13386         tng_block_destroy(&block);
13387         tng_data->input_file = temp;
13388
13389         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13390         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13391         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13392         return(TNG_FAILURE);
13393     }
13394
13395     if(tng_file_input_numerical(tng_data, &sparse_data,
13396                                  sizeof(sparse_data),
13397                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13398     {
13399         tng_block_destroy(&block);
13400         return(TNG_CRITICAL);
13401     }
13402
13403     if(tng_file_input_numerical(tng_data, &data.n_values_per_frame,
13404                                  sizeof(data.n_values_per_frame),
13405                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13406     {
13407         tng_block_destroy(&block);
13408         return(TNG_CRITICAL);
13409     }
13410
13411     if(tng_file_input_numerical(tng_data, &data.codec_id,
13412                                  sizeof(data.codec_id),
13413                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13414     {
13415         tng_block_destroy(&block);
13416         return(TNG_CRITICAL);
13417     }
13418
13419     if(data.codec_id != TNG_UNCOMPRESSED)
13420     {
13421         if(tng_file_input_numerical(tng_data, &data.compression_multiplier,
13422                                      sizeof(data.compression_multiplier),
13423                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13424         {
13425             tng_block_destroy(&block);
13426             return(TNG_CRITICAL);
13427         }
13428     }
13429     else
13430     {
13431         data.compression_multiplier = 1;
13432     }
13433
13434     if(sparse_data)
13435     {
13436         if(tng_file_input_numerical(tng_data, &data.first_frame_with_data,
13437                                      sizeof(data.first_frame_with_data),
13438                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13439         {
13440             tng_block_destroy(&block);
13441             return(TNG_CRITICAL);
13442         }
13443
13444         if(tng_file_input_numerical(tng_data, &data.stride_length,
13445                                      sizeof(data.stride_length),
13446                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13447         {
13448             tng_block_destroy(&block);
13449             return(TNG_CRITICAL);
13450         }
13451     }
13452     else
13453     {
13454         data.first_frame_with_data = 0;
13455         data.stride_length = 1;
13456     }
13457     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
13458
13459     if(is_particle_data == TNG_TRUE)
13460     {
13461         if(tng_file_input_numerical(tng_data, &num_first_particle,
13462                                      sizeof(num_first_particle),
13463                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13464         {
13465             tng_block_destroy(&block);
13466             return(TNG_CRITICAL);
13467         }
13468
13469         if(tng_file_input_numerical(tng_data, &block_n_particles,
13470                                      sizeof(block_n_particles),
13471                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13472         {
13473             tng_block_destroy(&block);
13474             return(TNG_CRITICAL);
13475         }
13476     }
13477
13478     tng_data->input_file = temp;
13479
13480     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13481     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13482     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13483
13484     switch(data.datatype)
13485     {
13486         case(TNG_INT_DATA):
13487             size = sizeof(int64_t);
13488             break;
13489         case(TNG_FLOAT_DATA):
13490             size = sizeof(float);
13491             break;
13492         case(TNG_DOUBLE_DATA):
13493             size = sizeof(double);
13494             break;
13495         default:
13496             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
13497                    __LINE__);
13498             tng_block_destroy(&block);
13499             return(TNG_FAILURE);
13500     }
13501
13502     n_values_per_frame = data.n_values_per_frame;
13503
13504     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
13505                                data.first_frame_with_data)) /
13506                 data.stride_length;
13507     if(is_particle_data == TNG_TRUE)
13508     {
13509         file_pos *= block_n_particles * size * n_values_per_frame;
13510     }
13511     else
13512     {
13513         file_pos *= size * n_values_per_frame;
13514     }
13515
13516     if(file_pos > contents_size)
13517     {
13518         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
13519                __LINE__);
13520         tng_block_destroy(&block);
13521         return(TNG_FAILURE);
13522     }
13523
13524     fseeko(tng_data->output_file, file_pos, SEEK_CUR);
13525
13526     if(is_particle_data == TNG_TRUE)
13527     {
13528         write_n_particles = val_n_particles;
13529     }
13530     else
13531     {
13532         write_n_particles = 1;
13533     }
13534
13535     /* If the endianness is not big endian the data needs to be swapped */
13536     if((data.datatype == TNG_INT_DATA ||
13537         data.datatype == TNG_DOUBLE_DATA) &&
13538        tng_data->output_endianness_swap_func_64)
13539     {
13540         copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
13541         memcpy(copy, values, write_n_particles * n_values_per_frame * size);
13542         for(i = 0; i < write_n_particles * n_values_per_frame; i++)
13543         {
13544             if(tng_data->output_endianness_swap_func_64(tng_data,
13545                 (uint64_t *) copy+i)
13546                 != TNG_SUCCESS)
13547             {
13548                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13549                         __FILE__, __LINE__);
13550             }
13551         }
13552         fwrite(copy, write_n_particles * n_values_per_frame, size,
13553                tng_data->output_file);
13554         free(copy);
13555     }
13556     else if(data.datatype == TNG_FLOAT_DATA &&
13557             tng_data->output_endianness_swap_func_32)
13558     {
13559         copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
13560         memcpy(copy, values, write_n_particles * n_values_per_frame * size);
13561         for(i = 0; i < write_n_particles * n_values_per_frame; i++)
13562         {
13563             if(tng_data->output_endianness_swap_func_32(tng_data,
13564                 (uint32_t *) copy+i)
13565                 != TNG_SUCCESS)
13566             {
13567                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13568                         __FILE__, __LINE__);
13569             }
13570         }
13571         fwrite(copy, write_n_particles * n_values_per_frame, size,
13572                tng_data->output_file);
13573         free(copy);
13574     }
13575
13576     else
13577     {
13578         fwrite(values, write_n_particles * n_values_per_frame, size, tng_data->output_file);
13579     }
13580
13581     fflush(tng_data->output_file);
13582
13583     /* Update the number of written frames in the frame set. */
13584     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
13585     {
13586         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
13587     }
13588
13589     /* If the last frame has been written update the hash */
13590     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
13591        data.first_frame_with_data) >=
13592        frame_set->n_frames)
13593     {
13594         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
13595                             header_size);
13596     }
13597
13598     tng_block_destroy(&block);
13599
13600     return(TNG_SUCCESS);
13601 }
13602
13603 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
13604                 (const tng_trajectory_t tng_data,
13605                  const int64_t frame_nr,
13606                  const int64_t block_id,
13607                  const void *values,
13608                  const char hash_mode)
13609 {
13610     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13611     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13612     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13613
13614     /* This is now just calling the generic data writing function. This
13615      * function must keep its signature to let the API be backwards
13616      * compatible. */
13617     return(tng_frame_gen_data_write(tng_data, frame_nr, block_id,
13618                                     TNG_FALSE, 0, 0, values, hash_mode));
13619 }
13620
13621 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
13622                 (const tng_trajectory_t tng_data,
13623                  const int64_t frame_nr,
13624                  const int64_t block_id,
13625                  const int64_t val_first_particle,
13626                  const int64_t val_n_particles,
13627                  const void *values,
13628                  const char hash_mode)
13629 {
13630     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13631     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13632     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13633     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
13634     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
13635
13636     /* This is now just calling the generic data writing function. This
13637      * function must keep its signature to let the API be backwards
13638      * compatible. */
13639     return(tng_frame_gen_data_write(tng_data, frame_nr, block_id,
13640                                     TNG_TRUE, val_first_particle, val_n_particles,
13641                                     values, hash_mode));
13642 }
13643
13644 static tng_function_status tng_data_values_alloc
13645                 (const tng_trajectory_t tng_data,
13646                  union data_values ***values,
13647                  const int64_t n_frames,
13648                  const int64_t n_values_per_frame,
13649                  const char type)
13650 {
13651     int64_t i;
13652     tng_function_status stat;
13653
13654     if(n_frames <= 0 || n_values_per_frame <= 0)
13655     {
13656         return(TNG_FAILURE);
13657     }
13658
13659     if(*values)
13660     {
13661         stat = tng_data_values_free(tng_data, *values, n_frames,
13662                                     n_values_per_frame,
13663                                     type);
13664         if(stat != TNG_SUCCESS)
13665         {
13666             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
13667                    __FILE__, __LINE__);
13668             return(stat);
13669         }
13670     }
13671     *values = (union data_values **)malloc(sizeof(union data_values *) * n_frames);
13672     if(!*values)
13673     {
13674         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13675                 __FILE__, __LINE__);
13676         return(TNG_CRITICAL);
13677
13678     }
13679
13680     for(i = 0; i < n_frames; i++)
13681     {
13682         (*values)[i] = (union data_values *)malloc(sizeof(union data_values) *
13683                            n_values_per_frame);
13684         if(!(*values)[i])
13685         {
13686             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13687                     __FILE__, __LINE__);
13688             free(values);
13689             values = 0;
13690             return(TNG_CRITICAL);
13691         }
13692     }
13693     return(TNG_SUCCESS);
13694 }
13695
13696 /* FIXME: This needs ***values */
13697 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
13698                 (const tng_trajectory_t tng_data,
13699                  union data_values **values,
13700                  const int64_t n_frames,
13701                  const int64_t n_values_per_frame,
13702                  const char type)
13703 {
13704     int64_t i, j;
13705     (void)tng_data;
13706
13707     if(values)
13708     {
13709         for(i = 0; i < n_frames; i++)
13710         {
13711             if(values[i])
13712             {
13713                 if(type == TNG_CHAR_DATA)
13714                 {
13715                     for(j = 0; j < n_values_per_frame; j++)
13716                     {
13717                         if(values[i][j].c)
13718                         {
13719                             free(values[i][j].c);
13720                             values[i][j].c = 0;
13721                         }
13722                     }
13723                 }
13724                 free(values[i]);
13725                 values[i] = 0;
13726             }
13727         }
13728         free(values);
13729         values = 0;
13730     }
13731
13732     return(TNG_SUCCESS);
13733 }
13734
13735 static tng_function_status tng_particle_data_values_alloc
13736                 (const tng_trajectory_t tng_data,
13737                  union data_values ****values,
13738                  const int64_t n_frames,
13739                  const int64_t n_particles,
13740                  const int64_t n_values_per_frame,
13741                  const char type)
13742 {
13743     int64_t i, j;
13744     tng_function_status stat;
13745
13746     if(n_particles == 0 || n_values_per_frame == 0)
13747     {
13748         return(TNG_FAILURE);
13749     }
13750
13751     if(*values)
13752     {
13753         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
13754                                              n_particles, n_values_per_frame,
13755                                              type);
13756         if(stat != TNG_SUCCESS)
13757         {
13758             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
13759                    __FILE__, __LINE__);
13760             return(stat);
13761         }
13762     }
13763     *values = (union data_values ***)malloc(sizeof(union data_values **) * n_frames);
13764     if(!*values)
13765     {
13766         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13767                 __FILE__, __LINE__);
13768         return(TNG_CRITICAL);
13769
13770     }
13771
13772     for(i = 0; i < n_frames; i++)
13773     {
13774         (*values)[i] = (union data_values **)malloc(sizeof(union data_values *) *
13775                            n_particles);
13776         if(!(*values)[i])
13777         {
13778             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13779                     __FILE__, __LINE__);
13780             free(*values);
13781             *values = 0;
13782             return(TNG_CRITICAL);
13783         }
13784         for(j = 0; j < n_particles; j++)
13785         {
13786             (*values)[i][j] = (union data_values *)malloc(sizeof(union data_values) *
13787                                   n_values_per_frame);
13788             if(!(*values)[i][j])
13789             {
13790                 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13791                         __FILE__, __LINE__);
13792                 tng_particle_data_values_free(tng_data, *values, n_frames,
13793                                               n_particles, n_values_per_frame,
13794                                               type);
13795                 *values = 0;
13796                 return(TNG_CRITICAL);
13797             }
13798         }
13799     }
13800     return(TNG_SUCCESS);
13801 }
13802
13803 /* FIXME: This needs ****values */
13804 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
13805                 (const tng_trajectory_t tng_data,
13806                  union data_values ***values,
13807                  const int64_t n_frames,
13808                  const int64_t n_particles,
13809                  const int64_t n_values_per_frame,
13810                  const char type)
13811 {
13812     int64_t i, j, k;
13813     (void)tng_data;
13814
13815     if(values)
13816     {
13817         for(i = 0; i < n_frames; i++)
13818         {
13819             if(values[i])
13820             {
13821                 for(j = 0; j < n_particles; j++)
13822                 {
13823                     if(type == TNG_CHAR_DATA)
13824                     {
13825                         for(k = 0; k < n_values_per_frame; k++)
13826                         {
13827                             if(values[i][j][k].c)
13828                             {
13829                                 free(values[i][j][k].c);
13830                                 values[i][j][k].c = 0;
13831                             }
13832                         }
13833                     }
13834                     free(values[i][j]);
13835                     values[i][j] = 0;
13836                 }
13837                 free(values[i]);
13838                 values[i] = 0;
13839             }
13840         }
13841         free(values);
13842         values = 0;
13843     }
13844
13845     return(TNG_SUCCESS);
13846 }
13847
13848 static tng_function_status tng_gen_data_get
13849                 (const tng_trajectory_t tng_data,
13850                  const int64_t block_id,
13851                  const tng_bool is_particle_data,
13852                  union data_values ****values,
13853                  int64_t *n_frames,
13854                  int64_t *n_particles,
13855                  int64_t *n_values_per_frame,
13856                  char *type)
13857 {
13858     int64_t i, j, k, mapping, file_pos, i_step, block_index;
13859     int size;
13860     size_t len;
13861     tng_data_t data;
13862     tng_trajectory_frame_set_t frame_set;
13863     tng_gen_block_t block;
13864     char block_type_flag;
13865     tng_function_status stat;
13866
13867     frame_set = &tng_data->current_trajectory_frame_set;
13868
13869     block_index = -1;
13870     data = 0;
13871
13872     if(is_particle_data == TNG_TRUE)
13873     {
13874         stat = tng_particle_data_find(tng_data, block_id, &data);
13875     }
13876     else
13877     {
13878         stat = tng_data_find(tng_data, block_id, &data);
13879     }
13880
13881     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
13882     {
13883         block_type_flag = TNG_TRAJECTORY_BLOCK;
13884     }
13885     else
13886     {
13887         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
13888     }
13889
13890     if(stat != TNG_SUCCESS)
13891     {
13892         tng_block_init(&block);
13893         file_pos = ftello(tng_data->input_file);
13894         /* Read all blocks until next frame set block */
13895         stat = tng_block_header_read(tng_data, block);
13896         while(file_pos < tng_data->input_file_len &&
13897                 stat != TNG_CRITICAL &&
13898                 block->id != TNG_TRAJECTORY_FRAME_SET &&
13899                 block->id != -1)
13900         {
13901             /* Use hash by default */
13902             stat = tng_block_read_next(tng_data, block,
13903                                     TNG_USE_HASH);
13904             if(stat != TNG_CRITICAL)
13905             {
13906                 file_pos = ftello(tng_data->input_file);
13907                 if(file_pos < tng_data->input_file_len)
13908                 {
13909                     stat = tng_block_header_read(tng_data, block);
13910                 }
13911             }
13912         }
13913         tng_block_destroy(&block);
13914         if(stat == TNG_CRITICAL)
13915         {
13916             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13917                     file_pos, __FILE__, __LINE__);
13918             return(stat);
13919         }
13920
13921         if(is_particle_data == TNG_TRUE)
13922         {
13923             for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13924             {
13925                 data = &frame_set->tr_particle_data[i];
13926                 if(data->block_id == block_id)
13927                 {
13928                     block_index = i;
13929                     block_type_flag = TNG_TRAJECTORY_BLOCK;
13930                     break;
13931                 }
13932             }
13933         }
13934         else
13935         {
13936             for(i = 0; i < frame_set->n_data_blocks; i++)
13937             {
13938                 data = &frame_set->tr_data[i];
13939                 if(data->block_id == block_id)
13940                 {
13941                     block_index = i;
13942                     break;
13943                 }
13944             }
13945         }
13946         if(block_index < 0)
13947         {
13948             return(TNG_FAILURE);
13949         }
13950     }
13951
13952     if(is_particle_data == TNG_TRUE)
13953     {
13954         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
13955            tng_data->var_num_atoms_flag)
13956         {
13957             *n_particles = frame_set->n_particles;
13958         }
13959         else
13960         {
13961             *n_particles = tng_data->n_particles;
13962         }
13963     }
13964
13965     *n_frames = tng_max_i64(1, data->n_frames);
13966     *n_values_per_frame = data->n_values_per_frame;
13967     *type = data->datatype;
13968
13969     if(is_particle_data == TNG_TRUE)
13970     {
13971         if(*values == 0)
13972         {
13973             if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
13974                                              *n_particles, *n_values_per_frame,
13975                                              *type) != TNG_SUCCESS)
13976             {
13977                 return(TNG_CRITICAL);
13978             }
13979         }
13980
13981         i_step = (*n_particles) * (*n_values_per_frame);
13982
13983         /* It's not very elegant to reuse so much of the code in the different case
13984          * statements, but it's unnecessarily slow to have the switch-case block
13985          * inside the for loops. */
13986         switch(*type)
13987         {
13988         case TNG_CHAR_DATA:
13989             for(i = 0; i < *n_frames; i++)
13990             {
13991                 for(j = 0; j < *n_particles; j++)
13992                 {
13993                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
13994                     for(k = 0; k < *n_values_per_frame; k++)
13995                     {
13996                         len = strlen(data->strings[i][j][k]) + 1;
13997                         (*values)[i][mapping][k].c = (char *)malloc(len);
13998                         strncpy((*values)[i][mapping][k].c,
13999                                 data->strings[i][j][k], len);
14000                     }
14001                 }
14002             }
14003             break;
14004         case TNG_INT_DATA:
14005             size = sizeof(int);
14006             for(i = 0; i < *n_frames; i++)
14007             {
14008                 for(j = 0; j < *n_particles; j++)
14009                 {
14010                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14011                     for(k = 0; k < *n_values_per_frame; k++)
14012                     {
14013                         (*values)[i][mapping][k].i = *(int *)
14014                                                      ((char *)data->values + size *
14015                                                      (i * i_step + j *
14016                                                       (*n_values_per_frame) + k));
14017                     }
14018                 }
14019             }
14020             break;
14021         case TNG_FLOAT_DATA:
14022             size = sizeof(float);
14023             for(i = 0; i < *n_frames; i++)
14024             {
14025                 for(j = 0; j < *n_particles; j++)
14026                 {
14027                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14028                     for(k = 0; k < *n_values_per_frame; k++)
14029                     {
14030                         (*values)[i][mapping][k].f = *(float *)
14031                                                      ((char *)data->values + size *
14032                                                      (i * i_step + j *
14033                                                       (*n_values_per_frame) + k));
14034                     }
14035                 }
14036             }
14037             break;
14038         case TNG_DOUBLE_DATA:
14039         default:
14040             size = sizeof(double);
14041             for(i = 0; i < *n_frames; i++)
14042             {
14043                 for(j = 0; j < *n_particles; j++)
14044                 {
14045                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14046                     for(k = 0; k < *n_values_per_frame; k++)
14047                     {
14048                         (*values)[i][mapping][k].d = *(double *)
14049                                                      ((char *)data->values + size *
14050                                                      (i * i_step + j *
14051                                                       (*n_values_per_frame) + k));
14052                     }
14053                 }
14054             }
14055         }
14056     }
14057     else
14058     {
14059         if(*(values[0]) == 0)
14060         {
14061             if(tng_data_values_alloc(tng_data, values[0], *n_frames,
14062                                      *n_values_per_frame,
14063                                      *type) != TNG_SUCCESS)
14064             {
14065                 return(TNG_CRITICAL);
14066             }
14067         }
14068         switch(*type)
14069         {
14070         case TNG_CHAR_DATA:
14071             for(i = 0; i < *n_frames; i++)
14072             {
14073                 for(j = 0; j < *n_values_per_frame; j++)
14074                 {
14075                     len = strlen(data->strings[0][i][j]) + 1;
14076                     (*values)[0][i][j].c = (char *)malloc(len);
14077                     strncpy((*values)[0][i][j].c, data->strings[0][i][j], len);
14078                 }
14079             }
14080             break;
14081         case TNG_INT_DATA:
14082             size = sizeof(int);
14083             for(i = 0; i < *n_frames; i++)
14084             {
14085                 for(j = 0; j < *n_values_per_frame; j++)
14086                 {
14087                     (*values)[0][i][j].i = *(int *)((char *)data->values + size *
14088                                                     (i*(*n_values_per_frame) + j));
14089                 }
14090             }
14091             break;
14092         case TNG_FLOAT_DATA:
14093             size = sizeof(float);
14094             for(i = 0; i < *n_frames; i++)
14095             {
14096                 for(j = 0; j < *n_values_per_frame; j++)
14097                 {
14098                     (*values)[0][i][j].f = *(float *)((char *)data->values + size *
14099                                                    (i*(*n_values_per_frame) + j));
14100                 }
14101             }
14102             break;
14103         case TNG_DOUBLE_DATA:
14104         default:
14105             size = sizeof(double);
14106             for(i = 0; i < *n_frames; i++)
14107             {
14108                 for(j = 0; j < *n_values_per_frame; j++)
14109                 {
14110                     (*values)[0][i][j].d = *(double *)((char *)data->values + size *
14111                                                        (i*(*n_values_per_frame) + j));
14112                 }
14113             }
14114         }
14115     }
14116
14117     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14118
14119     return(TNG_SUCCESS);
14120 }
14121
14122 tng_function_status DECLSPECDLLEXPORT tng_data_get
14123                 (const tng_trajectory_t tng_data,
14124                  const int64_t block_id,
14125                  union data_values ***values,
14126                  int64_t *n_frames,
14127                  int64_t *n_values_per_frame,
14128                  char *type)
14129 {
14130     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14131     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14132     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14133     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14134
14135     return(tng_gen_data_get(tng_data, block_id, TNG_FALSE, &values, n_frames, 0,
14136                             n_values_per_frame, type));
14137 }
14138
14139 static tng_function_status tng_gen_data_vector_get
14140                 (const tng_trajectory_t tng_data,
14141                  const int64_t block_id,
14142                  const tng_bool is_particle_data,
14143                  void **values,
14144                  int64_t *n_frames,
14145                  int64_t *stride_length,
14146                  int64_t *n_particles,
14147                  int64_t *n_values_per_frame,
14148                  char *type)
14149 {
14150     int64_t i, j, mapping, file_pos, i_step, full_data_len, n_frames_div;
14151     int64_t block_index;
14152     int size;
14153     tng_data_t data;
14154     tng_trajectory_frame_set_t frame_set;
14155     tng_gen_block_t block;
14156     void *temp;
14157     char block_type_flag;
14158     tng_function_status stat;
14159
14160     frame_set = &tng_data->current_trajectory_frame_set;
14161
14162     block_index = -1;
14163     data = 0;
14164
14165     if(is_particle_data == TNG_TRUE)
14166     {
14167         stat = tng_particle_data_find(tng_data, block_id, &data);
14168     }
14169     else
14170     {
14171         stat = tng_data_find(tng_data, block_id, &data);
14172     }
14173
14174     if(stat != TNG_SUCCESS)
14175     {
14176         tng_block_init(&block);
14177         file_pos = ftello(tng_data->input_file);
14178         /* Read all blocks until next frame set block */
14179         stat = tng_block_header_read(tng_data, block);
14180         while(file_pos < tng_data->input_file_len &&
14181                 stat != TNG_CRITICAL &&
14182                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14183                 block->id != -1)
14184         {
14185             /* Use hash by default */
14186             stat = tng_block_read_next(tng_data, block,
14187                                     TNG_USE_HASH);
14188             if(stat != TNG_CRITICAL)
14189             {
14190                 file_pos = ftello(tng_data->input_file);
14191                 if(file_pos < tng_data->input_file_len)
14192                 {
14193                     stat = tng_block_header_read(tng_data, block);
14194                 }
14195             }
14196         }
14197         tng_block_destroy(&block);
14198         if(stat == TNG_CRITICAL)
14199         {
14200             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
14201                     file_pos, __FILE__, __LINE__);
14202             return(stat);
14203         }
14204
14205         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
14206         {
14207             data = &frame_set->tr_particle_data[i];
14208             if(data->block_id == block_id)
14209             {
14210                 block_index = i;
14211                 break;
14212             }
14213         }
14214         if(block_index < 0)
14215         {
14216             return(TNG_FAILURE);
14217         }
14218     }
14219
14220     if(is_particle_data == TNG_TRUE)
14221     {
14222         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
14223         {
14224             block_type_flag = TNG_TRAJECTORY_BLOCK;
14225         }
14226         else
14227         {
14228             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
14229         }
14230
14231        if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
14232           tng_data->var_num_atoms_flag)
14233         {
14234             *n_particles = frame_set->n_particles;
14235         }
14236         else
14237         {
14238             *n_particles = tng_data->n_particles;
14239         }
14240     }
14241
14242     *type = data->datatype;
14243
14244     switch(*type)
14245     {
14246     case TNG_CHAR_DATA:
14247         return(TNG_FAILURE);
14248     case TNG_INT_DATA:
14249         size = sizeof(int64_t);
14250         break;
14251     case TNG_FLOAT_DATA:
14252         size = sizeof(float);
14253         break;
14254     case TNG_DOUBLE_DATA:
14255     default:
14256         size = sizeof(double);
14257     }
14258
14259     *n_frames = tng_max_i64(1, data->n_frames);
14260     *n_values_per_frame = data->n_values_per_frame;
14261     *stride_length = data->stride_length;
14262
14263     n_frames_div = (*n_frames % *stride_length) ?
14264                    *n_frames / *stride_length + 1:
14265                    *n_frames / *stride_length;
14266
14267     full_data_len = n_frames_div * size *
14268                 (*n_values_per_frame);
14269     if(is_particle_data == TNG_TRUE)
14270     {
14271         full_data_len *= (*n_particles);
14272     }
14273
14274     temp = (char *)realloc(*values, full_data_len);
14275     if(!temp)
14276     {
14277         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
14278                 __FILE__, __LINE__);
14279         free(*values);
14280         *values = 0;
14281         return(TNG_CRITICAL);
14282     }
14283
14284     *values = temp;
14285
14286     if(is_particle_data != TNG_TRUE || frame_set->n_mapping_blocks <= 0)
14287     {
14288         memcpy(*values, data->values, full_data_len);
14289     }
14290     else
14291     {
14292         i_step = (*n_particles) * (*n_values_per_frame);
14293         for(i = 0; i < *n_frames; i++)
14294         {
14295             for(j = 0; j < *n_particles; j++)
14296             {
14297                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14298                 memcpy(((char *)*values) + size * (i * i_step + mapping *
14299                        (*n_values_per_frame)),
14300                        (char *)data->values + size *
14301                        (i * i_step + j * (*n_values_per_frame)),
14302                        size * (*n_values_per_frame));
14303             }
14304         }
14305     }
14306
14307     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14308
14309     return(TNG_SUCCESS);
14310 }
14311
14312 tng_function_status DECLSPECDLLEXPORT tng_data_vector_get
14313                 (const tng_trajectory_t tng_data,
14314                  const int64_t block_id,
14315                  void **values,
14316                  int64_t *n_frames,
14317                  int64_t *stride_length,
14318                  int64_t *n_values_per_frame,
14319                  char *type)
14320 {
14321     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14322     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14323     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14324     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14325     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14326
14327     return(tng_gen_data_vector_get(tng_data, block_id, TNG_FALSE, values,
14328                                    n_frames, stride_length, 0, n_values_per_frame,
14329                                    type));
14330 }
14331
14332 static tng_function_status tng_gen_data_interval_get
14333                 (const tng_trajectory_t tng_data,
14334                  const int64_t block_id,
14335                  const tng_bool is_particle_data,
14336                  const int64_t start_frame_nr,
14337                  const int64_t end_frame_nr,
14338                  const char hash_mode,
14339                  union data_values ****values,
14340                  int64_t *n_particles,
14341                  int64_t *n_values_per_frame,
14342                  char *type)
14343 {
14344     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
14345     int64_t first_frame, block_index;
14346     int size;
14347     size_t len;
14348     tng_data_t data;
14349     tng_trajectory_frame_set_t frame_set;
14350     tng_gen_block_t block;
14351     char block_type_flag;
14352     tng_function_status stat;
14353
14354     block_index = -1;
14355
14356     frame_set = &tng_data->current_trajectory_frame_set;
14357     first_frame = frame_set->first_frame;
14358
14359     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14360     if(stat != TNG_SUCCESS)
14361     {
14362         return(stat);
14363     }
14364
14365     /* Do not re-read the frame set. */
14366     if((is_particle_data == TNG_TRUE &&
14367        (first_frame != frame_set->first_frame ||
14368         frame_set->n_particle_data_blocks <= 0)) ||
14369        (is_particle_data == TNG_FALSE &&
14370        (first_frame != frame_set->first_frame ||
14371         frame_set->n_data_blocks <= 0)))
14372     {
14373         tng_block_init(&block);
14374         file_pos = ftello(tng_data->input_file);
14375         /* Read all blocks until next frame set block */
14376         stat = tng_block_header_read(tng_data, block);
14377         while(file_pos < tng_data->input_file_len &&
14378                 stat != TNG_CRITICAL &&
14379                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14380                 block->id != -1)
14381         {
14382             stat = tng_block_read_next(tng_data, block,
14383                                     hash_mode);
14384             if(stat != TNG_CRITICAL)
14385             {
14386                 file_pos = ftello(tng_data->input_file);
14387                 if(file_pos < tng_data->input_file_len)
14388                 {
14389                     stat = tng_block_header_read(tng_data, block);
14390                 }
14391             }
14392         }
14393         tng_block_destroy(&block);
14394         if(stat == TNG_CRITICAL)
14395         {
14396             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
14397                     file_pos, __FILE__, __LINE__);
14398             return(stat);
14399         }
14400     }
14401
14402     /* See if there is already a data block of this ID.
14403      * Start checking the last read frame set */
14404     if(is_particle_data == TNG_TRUE)
14405     {
14406         for(i = frame_set->n_particle_data_blocks; i-- ;)
14407         {
14408             data = &frame_set->tr_particle_data[i];
14409             if(data->block_id == block_id)
14410             {
14411                 block_index = i;
14412                 block_type_flag = TNG_TRAJECTORY_BLOCK;
14413                 break;
14414             }
14415         }
14416     }
14417     else
14418     {
14419         for(i = 0; i < frame_set->n_data_blocks; i++)
14420         {
14421             data = &frame_set->tr_data[i];
14422             if(data->block_id == block_id)
14423             {
14424                 block_index = i;
14425                 break;
14426             }
14427         }
14428     }
14429
14430     if(block_index < 0)
14431     {
14432         fprintf(stderr, "TNG library: Could not find particle data block with id %" PRId64 ". %s: %d\n",
14433                 block_id, __FILE__, __LINE__);
14434         return(TNG_FAILURE);
14435     }
14436
14437     if(is_particle_data ==  TNG_TRUE)
14438     {
14439         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
14440            tng_data->var_num_atoms_flag)
14441         {
14442             *n_particles = frame_set->n_particles;
14443         }
14444         else
14445         {
14446             *n_particles = tng_data->n_particles;
14447         }
14448     }
14449
14450     n_frames = end_frame_nr - start_frame_nr + 1;
14451     *n_values_per_frame = data->n_values_per_frame;
14452     *type = data->datatype;
14453
14454     if(*values == 0)
14455     {
14456         if(is_particle_data == TNG_TRUE)
14457         {
14458             if(tng_particle_data_values_alloc(tng_data, values, n_frames,
14459                                              *n_particles, *n_values_per_frame,
14460                                              *type) != TNG_SUCCESS)
14461             {
14462                 return(TNG_CRITICAL);
14463             }
14464         }
14465         else
14466         {
14467             if(tng_data_values_alloc(tng_data, *values, n_frames,
14468                                      *n_values_per_frame,
14469                                      *type) != TNG_SUCCESS)
14470             {
14471                 return(TNG_CRITICAL);
14472             }
14473         }
14474     }
14475
14476     current_frame_pos = start_frame_nr - frame_set->first_frame;
14477
14478     if(is_particle_data == TNG_TRUE)
14479     {
14480         i_step = (*n_particles) * (*n_values_per_frame);
14481     }
14482     else
14483     {
14484         i_step = (*n_values_per_frame);
14485     }
14486     /* It's not very elegant to reuse so much of the code in the different case
14487      * statements, but it's unnecessarily slow to have the switch-case block
14488      * inside the for loops. */
14489     switch(*type)
14490     {
14491     case TNG_CHAR_DATA:
14492         for(i=0; i<n_frames; i++)
14493         {
14494             if(current_frame_pos == frame_set->n_frames)
14495             {
14496                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14497                 if(stat != TNG_SUCCESS)
14498                 {
14499                     return(stat);
14500                 }
14501                 current_frame_pos = 0;
14502             }
14503             if(is_particle_data == TNG_TRUE)
14504             {
14505                 for(j = 0; j < *n_particles; j++)
14506                 {
14507                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14508                     for(k = 0; k < *n_values_per_frame; k++)
14509                     {
14510                         len = strlen(data->strings[current_frame_pos][j][k]) + 1;
14511                         (*values)[i][mapping][k].c = (char *)malloc(len);
14512                         strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
14513                     }
14514                 }
14515             }
14516             else
14517             {
14518                 for(j = 0; j < *n_values_per_frame; j++)
14519                 {
14520                     len = strlen(data->strings[0][current_frame_pos][j]) + 1;
14521                     (*values)[0][i][j].c = (char *)malloc(len);
14522                     strncpy((*values)[0][i][j].c, data->strings[0][current_frame_pos][j], len);
14523                 }
14524             }
14525             current_frame_pos++;
14526         }
14527         break;
14528     case TNG_INT_DATA:
14529         size = sizeof(int);
14530         for(i=0; i<n_frames; i++)
14531         {
14532             if(current_frame_pos == frame_set->n_frames)
14533             {
14534                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14535                 if(stat != TNG_SUCCESS)
14536                 {
14537                     return(stat);
14538                 }
14539                 current_frame_pos = 0;
14540             }
14541             if(is_particle_data == TNG_TRUE)
14542             {
14543                 for(j = 0; j < *n_particles; j++)
14544                 {
14545                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14546                     for(k = 0; k < *n_values_per_frame; k++)
14547                     {
14548                         (*values)[i][mapping][k].i = *(int *)
14549                                                      ((char *)data->values + size *
14550                                                       (current_frame_pos *
14551                                                        i_step + j *
14552                                                        (*n_values_per_frame) + k));
14553                     }
14554                 }
14555                 current_frame_pos++;
14556             }
14557             else
14558             {
14559                 for(j = 0; j < *n_values_per_frame; j++)
14560                 {
14561                     (*values)[0][i][j].i = *(int *)((char *)data->values + size *
14562                                                 (current_frame_pos *
14563                                                  i_step + j));
14564                 }
14565             }
14566         }
14567         break;
14568     case TNG_FLOAT_DATA:
14569         size = sizeof(float);
14570         for(i=0; i<n_frames; i++)
14571         {
14572             if(current_frame_pos == frame_set->n_frames)
14573             {
14574                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14575                 if(stat != TNG_SUCCESS)
14576                 {
14577                     return(stat);
14578                 }
14579                 current_frame_pos = 0;
14580             }
14581             if(is_particle_data == TNG_TRUE)
14582             {
14583                 for(j=0; j<*n_particles; j++)
14584                 {
14585                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14586                     for(k=0; k<*n_values_per_frame; k++)
14587                     {
14588                         (*values)[i][mapping][k].f = *(float *)
14589                                                      ((char *)data->values + size *
14590                                                       (current_frame_pos *
14591                                                        i_step + j *
14592                                                        (*n_values_per_frame) + k));
14593                     }
14594                 }
14595             }
14596             else
14597             {
14598                 for(j = 0; j < *n_values_per_frame; j++)
14599                 {
14600                     (*values)[0][i][j].f = *(float *)((char *)data->values + size *
14601                                                    (current_frame_pos *
14602                                                     i_step + j));
14603                 }
14604             }
14605             current_frame_pos++;
14606         }
14607         break;
14608     case TNG_DOUBLE_DATA:
14609     default:
14610         size = sizeof(double);
14611         for(i=0; i<n_frames; i++)
14612         {
14613             if(current_frame_pos == frame_set->n_frames)
14614             {
14615                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14616                 if(stat != TNG_SUCCESS)
14617                 {
14618                     return(stat);
14619                 }
14620                 current_frame_pos = 0;
14621             }
14622             if(is_particle_data == TNG_TRUE)
14623             {
14624                 for(j=0; j<*n_particles; j++)
14625                 {
14626                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14627                     for(k=0; k<*n_values_per_frame; k++)
14628                     {
14629                         (*values)[i][mapping][k].d = *(double *)
14630                                                      ((char *)data->values + size *
14631                                                       (current_frame_pos *
14632                                                        i_step + j *
14633                                                        (*n_values_per_frame) + k));
14634                     }
14635                 }
14636             }
14637             else
14638             {
14639                 for(j = 0; j < *n_values_per_frame; j++)
14640                 {
14641                     (*values)[0][i][j].d = *(double *)((char *)data->values + size *
14642                                                     (current_frame_pos *
14643                                                      i_step + j));
14644                 }
14645             }
14646             current_frame_pos++;
14647         }
14648     }
14649
14650     data->last_retrieved_frame = end_frame_nr;
14651
14652     return(TNG_SUCCESS);
14653 }
14654
14655 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
14656                 (const tng_trajectory_t tng_data,
14657                  const int64_t block_id,
14658                  const int64_t start_frame_nr,
14659                  const int64_t end_frame_nr,
14660                  const char hash_mode,
14661                  union data_values ***values,
14662                  int64_t *n_values_per_frame,
14663                  char *type)
14664 {
14665     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14666     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
14667     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14668     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14669
14670     return(tng_gen_data_interval_get(tng_data, block_id, TNG_FALSE, start_frame_nr,
14671                                      end_frame_nr, hash_mode, &values, 0,
14672                                      n_values_per_frame, type));
14673 }
14674
14675 static tng_function_status tng_gen_data_vector_interval_get
14676                 (const tng_trajectory_t tng_data,
14677                  const int64_t block_id,
14678                  const tng_bool is_particle_data,
14679                  const int64_t start_frame_nr,
14680                  const int64_t end_frame_nr,
14681                  const char hash_mode,
14682                  void **values,
14683                  int64_t *n_particles,
14684                  int64_t *stride_length,
14685                  int64_t *n_values_per_frame,
14686                  char *type)
14687 {
14688     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
14689     int64_t file_pos, current_frame_pos, last_frame_pos, full_data_len, frame_size;
14690     int size;
14691     tng_trajectory_frame_set_t frame_set;
14692     tng_data_t data;
14693     tng_gen_block_t block;
14694     void *current_values = 0, *temp;
14695     tng_function_status stat;
14696
14697     frame_set = &tng_data->current_trajectory_frame_set;
14698     first_frame = frame_set->first_frame;
14699
14700     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14701     if(stat != TNG_SUCCESS)
14702     {
14703         return(stat);
14704     }
14705
14706     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
14707     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
14708     if(is_particle_data == TNG_TRUE)
14709     {
14710         stat = tng_particle_data_find(tng_data, block_id, &data);
14711     }
14712     else
14713     {
14714         stat = tng_data_find(tng_data, block_id, &data);
14715     }
14716
14717     if(first_frame != frame_set->first_frame ||
14718        stat != TNG_SUCCESS)
14719     {
14720         tng_block_init(&block);
14721         if(stat != TNG_SUCCESS)
14722         {
14723             fseeko(tng_data->input_file,
14724                   tng_data->current_trajectory_frame_set_input_file_pos,
14725                   SEEK_SET);
14726             stat = tng_block_header_read(tng_data, block);
14727             if(stat != TNG_SUCCESS)
14728             {
14729                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
14730                         __FILE__, __LINE__);
14731                 return(stat);
14732             }
14733
14734             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
14735         }
14736         file_pos = ftello(tng_data->input_file);
14737         /* Read until next frame set block */
14738         stat = tng_block_header_read(tng_data, block);
14739         while(file_pos < tng_data->input_file_len &&
14740             stat != TNG_CRITICAL &&
14741             block->id != TNG_TRAJECTORY_FRAME_SET &&
14742             block->id != -1)
14743         {
14744             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
14745             {
14746                 stat = tng_block_read_next(tng_data, block,
14747                                         hash_mode);
14748                 if(stat != TNG_CRITICAL)
14749                 {
14750                     file_pos = ftello(tng_data->input_file);
14751                     if(file_pos < tng_data->input_file_len)
14752                     {
14753                         stat = tng_block_header_read(tng_data, block);
14754                     }
14755                 }
14756             }
14757             else
14758             {
14759                 file_pos += block->block_contents_size + block->header_contents_size;
14760                 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
14761                 if(file_pos < tng_data->input_file_len)
14762                 {
14763                     stat = tng_block_header_read(tng_data, block);
14764                 }
14765             }
14766         }
14767         tng_block_destroy(&block);
14768         if(stat == TNG_CRITICAL)
14769         {
14770             fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
14771                     file_pos, __FILE__, __LINE__);
14772             return(stat);
14773         }
14774     }
14775     if(is_particle_data == TNG_TRUE)
14776     {
14777         stat = tng_particle_data_find(tng_data, block_id, &data);
14778     }
14779     else
14780     {
14781         stat = tng_data_find(tng_data, block_id, &data);
14782     }
14783     if(stat != TNG_SUCCESS)
14784     {
14785         return(stat);
14786     }
14787
14788     stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data,
14789                                    &current_values, &n_frames, stride_length,
14790                                    n_particles, n_values_per_frame, type);
14791
14792     if(stat != TNG_SUCCESS || (is_particle_data && *n_particles == 0))
14793     {
14794         if(current_values)
14795         {
14796             free(current_values);
14797         }
14798         return(stat);
14799     }
14800
14801     if(n_frames == 1 && n_frames < frame_set->n_frames)
14802     {
14803         tot_n_frames = 1;
14804     }
14805     else
14806     {
14807         tot_n_frames = end_frame_nr - start_frame_nr + 1;
14808     }
14809
14810     switch(*type)
14811     {
14812     case TNG_CHAR_DATA:
14813         return(TNG_FAILURE);
14814     case TNG_INT_DATA:
14815         size = sizeof(int64_t);
14816         break;
14817     case TNG_FLOAT_DATA:
14818         size = sizeof(float);
14819         break;
14820     case TNG_DOUBLE_DATA:
14821     default:
14822         size = sizeof(double);
14823     }
14824
14825     n_frames_div = (tot_n_frames % *stride_length) ?
14826                  tot_n_frames / *stride_length + 1:
14827                  tot_n_frames / *stride_length;
14828
14829     full_data_len = n_frames_div * size * (*n_values_per_frame);
14830     if(is_particle_data)
14831     {
14832         full_data_len *= (*n_particles);
14833     }
14834
14835     temp = (char *)realloc(*values, full_data_len);
14836     if(!temp)
14837     {
14838         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
14839                 __FILE__, __LINE__);
14840         free(*values);
14841         *values = 0;
14842         return(TNG_CRITICAL);
14843     }
14844
14845     *values = temp;
14846
14847     if( n_frames == 1 && n_frames < frame_set->n_frames)
14848     {
14849         if(is_particle_data)
14850         {
14851             memcpy(*values, current_values, size * (*n_particles) *
14852                    (*n_values_per_frame));
14853         }
14854         else
14855         {
14856             memcpy(*values, current_values, size * (*n_values_per_frame));
14857         }
14858     }
14859     else
14860     {
14861         current_frame_pos = start_frame_nr - frame_set->first_frame;
14862
14863         frame_size = size * (*n_values_per_frame);
14864         if(is_particle_data)
14865         {
14866             frame_size *= (*n_particles);
14867         }
14868
14869         last_frame_pos = tng_min_i64(n_frames,
14870                                      end_frame_nr - start_frame_nr);
14871
14872         n_frames_div = current_frame_pos / *stride_length;
14873         n_frames_div_2 = (last_frame_pos % *stride_length) ?
14874                        last_frame_pos / *stride_length + 1:
14875                        last_frame_pos / *stride_length;
14876         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
14877
14878         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
14879                n_frames_div_2 * frame_size);
14880
14881         current_frame_pos += n_frames - current_frame_pos;
14882
14883         while(current_frame_pos <= end_frame_nr - start_frame_nr)
14884         {
14885             stat = tng_frame_set_read_next(tng_data, hash_mode);
14886             if(stat != TNG_SUCCESS)
14887             {
14888                 if(current_values)
14889                 {
14890                     free(current_values);
14891                 }
14892                 free(*values);
14893                 *values = 0;
14894                 return(stat);
14895             }
14896
14897             stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data,
14898                                            &current_values, &n_frames,
14899                                            stride_length, n_particles,
14900                                            n_values_per_frame, type);
14901
14902             if(stat != TNG_SUCCESS)
14903             {
14904                 if(current_values)
14905                 {
14906                     free(current_values);
14907                 }
14908                 free(*values);
14909                 *values = 0;
14910                 return(stat);
14911             }
14912
14913             last_frame_pos = tng_min_i64(n_frames,
14914                                          end_frame_nr - current_frame_pos);
14915
14916             n_frames_div = current_frame_pos / *stride_length;
14917             n_frames_div_2 = (last_frame_pos % *stride_length) ?
14918                            last_frame_pos / *stride_length + 1:
14919                            last_frame_pos / *stride_length;
14920             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
14921
14922             memcpy(((char *)*values) + n_frames_div * frame_size,
14923                    current_values,
14924                    n_frames_div_2 * frame_size);
14925
14926             current_frame_pos += n_frames;
14927         }
14928     }
14929
14930     if(current_values)
14931     {
14932         free(current_values);
14933     }
14934
14935     data->last_retrieved_frame = end_frame_nr;
14936
14937     return(TNG_SUCCESS);
14938 }
14939
14940
14941 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
14942                 (const tng_trajectory_t tng_data,
14943                  const int64_t block_id,
14944                  const int64_t start_frame_nr,
14945                  const int64_t end_frame_nr,
14946                  const char hash_mode,
14947                  void **values,
14948                  int64_t *stride_length,
14949                  int64_t *n_values_per_frame,
14950                  char *type)
14951 {
14952     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14953     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
14954     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14955     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14956     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14957
14958     return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_FALSE,
14959                                             start_frame_nr, end_frame_nr,
14960                                             hash_mode, values, 0, stride_length,
14961                                             n_values_per_frame, type));
14962 }
14963
14964 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
14965                 (const tng_trajectory_t tng_data,
14966                  const int64_t block_id,
14967                  union data_values ****values,
14968                  int64_t *n_frames,
14969                  int64_t *n_particles,
14970                  int64_t *n_values_per_frame,
14971                  char *type)
14972 {
14973     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14974     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14975     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
14976     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14977     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14978
14979     return(tng_gen_data_get(tng_data, block_id, TNG_TRUE, values, n_frames, n_particles,
14980                             n_values_per_frame, type));
14981 }
14982
14983 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
14984                 (const tng_trajectory_t tng_data,
14985                  const int64_t block_id,
14986                  void **values,
14987                  int64_t *n_frames,
14988                  int64_t *stride_length,
14989                  int64_t *n_particles,
14990                  int64_t *n_values_per_frame,
14991                  char *type)
14992 {
14993     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14994     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
14995     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14996     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14997     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14998
14999     return(tng_gen_data_vector_get(tng_data, block_id, TNG_TRUE, values,
15000                                    n_frames, stride_length, n_particles,
15001                                    n_values_per_frame, type));
15002 }
15003
15004 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
15005                 (const tng_trajectory_t tng_data,
15006                  const int64_t block_id,
15007                  const int64_t start_frame_nr,
15008                  const int64_t end_frame_nr,
15009                  const char hash_mode,
15010                  union data_values ****values,
15011                  int64_t *n_particles,
15012                  int64_t *n_values_per_frame,
15013                  char *type)
15014 {
15015     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15016     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15017     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15018     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15019     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15020
15021     return(tng_gen_data_interval_get(tng_data, block_id, TNG_TRUE, start_frame_nr,
15022                                      end_frame_nr, hash_mode, values, n_particles,
15023                                      n_values_per_frame, type));
15024 }
15025
15026 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
15027                 (const tng_trajectory_t tng_data,
15028                  const int64_t block_id,
15029                  const int64_t start_frame_nr,
15030                  const int64_t end_frame_nr,
15031                  const char hash_mode,
15032                  void **values,
15033                  int64_t *n_particles,
15034                  int64_t *stride_length,
15035                  int64_t *n_values_per_frame,
15036                  char *type)
15037 {
15038     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15039     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15040     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15041     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15042     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15043     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15044
15045     return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_TRUE,
15046                                             start_frame_nr, end_frame_nr,
15047                                             hash_mode, values, n_particles,
15048                                             stride_length, n_values_per_frame,
15049                                             type));
15050 }
15051
15052 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
15053                 (const tng_trajectory_t tng_data,
15054                  const int64_t block_id,
15055                  int64_t frame,
15056                  int64_t *stride_length)
15057 {
15058     tng_function_status stat;
15059     tng_data_t data;
15060     int64_t orig_file_pos, file_pos;
15061     int is_particle_data;
15062
15063     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
15064     {
15065         frame = 0;
15066     }
15067
15068     if(frame >= 0)
15069     {
15070         stat = tng_frame_set_of_frame_find(tng_data, frame);
15071         if(stat != TNG_SUCCESS)
15072         {
15073             return(stat);
15074         }
15075     }
15076     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
15077     stat = tng_data_find(tng_data, block_id, &data);
15078     if(stat != TNG_SUCCESS)
15079     {
15080         stat = tng_particle_data_find(tng_data, block_id, &data);
15081         if(stat != TNG_SUCCESS)
15082         {
15083             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15084             /* If no specific frame was required read until this data block is found */
15085             if(frame < 0)
15086             {
15087                 file_pos = ftello(tng_data->input_file);
15088                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15089                 {
15090                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15091                     file_pos = ftello(tng_data->input_file);
15092                 }
15093             }
15094             if(stat != TNG_SUCCESS)
15095             {
15096                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15097
15098                 return(stat);
15099             }
15100             stat = tng_data_find(tng_data, block_id, &data);
15101             if(stat != TNG_SUCCESS)
15102             {
15103                 stat = tng_particle_data_find(tng_data, block_id, &data);
15104                 if(stat != TNG_SUCCESS)
15105                 {
15106                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15107
15108                     return(stat);
15109                 }
15110                 else
15111                 {
15112                     is_particle_data = 1;
15113                 }
15114             }
15115             else
15116             {
15117                 is_particle_data = 0;
15118             }
15119         }
15120         else
15121         {
15122             is_particle_data = 1;
15123         }
15124     }
15125     else
15126     {
15127         is_particle_data = 0;
15128     }
15129     if(is_particle_data)
15130     {
15131         *stride_length = data->stride_length;
15132     }
15133     else
15134     {
15135         *stride_length = data->stride_length;
15136     }
15137     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15138
15139     return(TNG_SUCCESS);
15140 }
15141
15142 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
15143                 (const tng_trajectory_t tng_data,
15144                  char *time)
15145 {
15146     struct tm *time_data;
15147     time_t secs;
15148
15149     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15150     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
15151
15152     secs = tng_data->time;
15153
15154     time_data = localtime(&secs); /* Returns a statically allocated variable. */
15155     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
15156              "%4d-%02d-%02d %02d:%02d:%02d",
15157              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
15158              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
15159
15160     return(TNG_SUCCESS);
15161 }
15162
15163
15164 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
15165                 (const char *filename,
15166                  const char mode,
15167                  tng_trajectory_t *tng_data_p)
15168 {
15169     tng_function_status stat;
15170
15171     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
15172
15173     if(mode != 'r' && mode != 'w' && mode != 'a')
15174     {
15175         return(TNG_FAILURE);
15176     }
15177
15178     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
15179     {
15180         tng_trajectory_destroy(tng_data_p);
15181         return(TNG_CRITICAL);
15182     }
15183
15184     if(mode == 'w')
15185     {
15186         stat = tng_output_file_set(*tng_data_p, filename);
15187         return(stat);
15188     }
15189     tng_input_file_set(*tng_data_p, filename);
15190
15191     /* Read the file headers */
15192     tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
15193
15194     stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
15195
15196     if(stat != TNG_SUCCESS)
15197     {
15198         return(stat);
15199     }
15200
15201     if(mode == 'a')
15202     {
15203         if((*tng_data_p)->output_file)
15204         {
15205             fclose((*tng_data_p)->output_file);
15206         }
15207         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
15208         fseeko((*tng_data_p)->input_file,
15209                 (*tng_data_p)->last_trajectory_frame_set_input_file_pos,
15210                 SEEK_SET);
15211
15212         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
15213         if(stat != TNG_SUCCESS)
15214         {
15215             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
15216                    __FILE__, __LINE__);
15217         }
15218         (*tng_data_p)->output_file = 0;
15219
15220         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
15221         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
15222         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
15223         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
15224         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
15225         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
15226         if((*tng_data_p)->input_file)
15227         {
15228             fclose((*tng_data_p)->input_file);
15229             (*tng_data_p)->input_file = 0;
15230         }
15231         if((*tng_data_p)->input_file_path)
15232         {
15233             free((*tng_data_p)->input_file_path);
15234             (*tng_data_p)->input_file_path = 0;
15235         }
15236         tng_output_append_file_set(*tng_data_p, filename);
15237
15238         fseeko((*tng_data_p)->output_file, 0, SEEK_END);
15239
15240         (*tng_data_p)->output_endianness_swap_func_32 = (*tng_data_p)->input_endianness_swap_func_32;
15241         (*tng_data_p)->output_endianness_swap_func_64 = (*tng_data_p)->input_endianness_swap_func_64;
15242     }
15243
15244     return(stat);
15245 }
15246
15247 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
15248                 (tng_trajectory_t *tng_data_p)
15249 {
15250     tng_trajectory_frame_set_t frame_set;
15251
15252     if(tng_data_p == 0)
15253     {
15254         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
15255                __FILE__, __LINE__);
15256         return(TNG_FAILURE);
15257     }
15258
15259     if(*tng_data_p == 0)
15260     {
15261         return(TNG_SUCCESS);
15262     }
15263
15264     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
15265
15266     if(frame_set->n_unwritten_frames > 0)
15267     {
15268         frame_set->n_frames = frame_set->n_unwritten_frames;
15269         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
15270     }
15271
15272     return(tng_trajectory_destroy(tng_data_p));
15273 }
15274
15275 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
15276                 (const tng_trajectory_t tng_data,
15277                  const int64_t frame_nr,
15278                  double *time)
15279 {
15280     int64_t first_frame;
15281     tng_trajectory_frame_set_t frame_set;
15282     tng_function_status stat;
15283
15284     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15285     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
15286
15287     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
15288     if(stat != TNG_SUCCESS)
15289     {
15290         fprintf(stderr, "TNG library: Cannot find frame nr %" PRId64 ". %s: %d\n",
15291                frame_nr, __FILE__, __LINE__);
15292         return(stat);
15293     }
15294
15295     frame_set = &tng_data->current_trajectory_frame_set;
15296     first_frame = frame_set->first_frame;
15297
15298     if(tng_data->time_per_frame <= 0)
15299     {
15300         return(TNG_FAILURE);
15301     }
15302
15303     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
15304
15305     return(TNG_SUCCESS);
15306 }
15307
15308 /*
15309 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
15310                 (const tng_trajectory_t tng_data,
15311                  int64_t *n_mols,
15312                  int64_t **molecule_cnt_list,
15313                  tng_molecule_t *mols)
15314 {
15315     tng_trajectory_frame_set_t frame_set;
15316
15317     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15318     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
15319
15320     *n_mols = tng_data->n_molecules;
15321
15322     frame_set = &tng_data->current_trajectory_frame_set;
15323     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
15324     {
15325         *molecule_cnt_list = frame_set->molecule_cnt_list;
15326     }
15327     else
15328     {
15329         *molecule_cnt_list = tng_data->molecule_cnt_list;
15330     }
15331
15332     *mols = tng_data->molecules;
15333
15334     return(TNG_SUCCESS);
15335 }
15336 */
15337 /*
15338 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
15339                 (const tng_trajectory_t tng_data,
15340                  const char *name,
15341                  const int64_t cnt,
15342                  tng_molecule_t *mol)
15343 {
15344     tng_function_status stat;
15345
15346     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
15347     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
15348
15349     stat = tng_molecule_add(tng_data, name, mol);
15350     if(stat != TNG_SUCCESS)
15351     {
15352         return(stat);
15353     }
15354     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
15355
15356     return(stat);
15357 }
15358 */
15359 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
15360                 (const tng_trajectory_t tng_data,
15361                  const tng_molecule_t mol,
15362                  int64_t *n_particles,
15363                  char ***names,
15364                  char ***types,
15365                  char ***res_names,
15366                  int64_t **res_ids,
15367                  char ***chain_names,
15368                  int64_t **chain_ids)
15369 {
15370     tng_atom_t atom;
15371     tng_residue_t res;
15372     tng_chain_t chain;
15373     int64_t i;
15374     (void)tng_data;
15375
15376     *n_particles = mol->n_atoms;
15377
15378     *names = (char **)malloc(sizeof(char *) * *n_particles);
15379     *types = (char **)malloc(sizeof(char *) * *n_particles);
15380     *res_names = (char **)malloc(sizeof(char *) * *n_particles);
15381     *chain_names = (char **)malloc(sizeof(char *) * *n_particles);
15382     *res_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
15383     *chain_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
15384
15385     for(i = 0; i < *n_particles; i++)
15386     {
15387         atom = &mol->atoms[i];
15388         res = atom->residue;
15389         chain = res->chain;
15390         (*names)[i] = (char *)malloc(strlen(atom->name));
15391         strcpy(*names[i], atom->name);
15392         (*types)[i] = (char *)malloc(strlen(atom->atom_type));
15393         strcpy(*types[i], atom->atom_type);
15394         (*res_names)[i] = (char *)malloc(strlen(res->name));
15395         strcpy(*res_names[i], res->name);
15396         (*chain_names)[i] = (char *)malloc(strlen(chain->name));
15397         strcpy(*chain_names[i], chain->name);
15398         (*res_ids)[i] = res->id;
15399         (*chain_ids)[i] = chain->id;
15400     }
15401
15402     return(TNG_SUCCESS);
15403 }
15404
15405 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
15406                 (const tng_trajectory_t tng_data,
15407                  const tng_molecule_t mol,
15408                  const int64_t n_particles,
15409                  const char **names,
15410                  const char **types,
15411                  const char **res_names,
15412                  const int64_t *res_ids,
15413                  const char **chain_names,
15414                  const int64_t *chain_ids)
15415 {
15416     int64_t i;
15417     tng_chain_t chain;
15418     tng_residue_t residue;
15419     tng_atom_t atom;
15420     tng_function_status stat;
15421
15422     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15423     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
15424     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
15425     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
15426     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
15427     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
15428     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
15429
15430     for(i = 0; i < n_particles; i++)
15431     {
15432         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
15433            &chain) == TNG_FAILURE)
15434         {
15435             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
15436                                           &chain);
15437             if(stat != TNG_SUCCESS)
15438             {
15439                 return(stat);
15440             }
15441         }
15442         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
15443            &residue) == TNG_FAILURE)
15444         {
15445             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
15446                                          &residue);
15447             if(stat != TNG_SUCCESS)
15448             {
15449                 return(stat);
15450             }
15451         }
15452         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
15453         if(stat != TNG_SUCCESS)
15454         {
15455             return(stat);
15456         }
15457     }
15458     return(TNG_SUCCESS);
15459 }
15460
15461 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
15462                 (const tng_trajectory_t tng_data,
15463                  float **positions, int64_t *stride_length)
15464 {
15465     int64_t n_frames, n_particles, n_values_per_frame;
15466     char type;
15467     tng_function_status stat;
15468
15469     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15470     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
15471     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15472
15473     stat = tng_num_frames_get(tng_data, &n_frames);
15474     if(stat != TNG_SUCCESS)
15475     {
15476         return(stat);
15477     }
15478
15479     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
15480                                                  0, n_frames - 1, TNG_USE_HASH,
15481                                                  (void **)positions,
15482                                                  &n_particles,
15483                                                  stride_length,
15484                                                  &n_values_per_frame,
15485                                                  &type);
15486
15487     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15488     {
15489         return(TNG_FAILURE);
15490     }
15491
15492     return(stat);
15493 }
15494
15495 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
15496                 (const tng_trajectory_t tng_data,
15497                  float **velocities, 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(velocities, "TNG library: velocities 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_VELOCITIES,
15514                                                  0, n_frames - 1, TNG_USE_HASH,
15515                                                  (void **)velocities,
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_force_read
15530                 (const tng_trajectory_t tng_data,
15531                  float **forces, 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(forces, "TNG library: forces 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_FORCES,
15548                                                  0, n_frames - 1, TNG_USE_HASH,
15549                                                  (void **)forces,
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_box_shape_read
15564                 (const tng_trajectory_t tng_data,
15565                  float **box_shape,
15566                  int64_t *stride_length)
15567 {
15568     int64_t n_frames, n_values_per_frame;
15569     char type;
15570     tng_function_status stat;
15571
15572     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15573     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
15574     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15575
15576     stat = tng_num_frames_get(tng_data, &n_frames);
15577     if(stat != TNG_SUCCESS)
15578     {
15579         return(stat);
15580     }
15581
15582     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
15583                                         0, n_frames - 1, TNG_USE_HASH,
15584                                         (void **)box_shape,
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_particle_data_next_frame_read
15598                 (const tng_trajectory_t tng_data,
15599                  const int64_t block_id,
15600                  void **values,
15601                  char *data_type,
15602                  int64_t *retrieved_frame_number,
15603                  double *retrieved_time)
15604 {
15605     tng_trajectory_frame_set_t frame_set;
15606     tng_data_t data = 0;
15607     tng_function_status stat;
15608     int size;
15609     int64_t i, full_data_len, n_particles;
15610     void *temp;
15611     int64_t file_pos;
15612
15613     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15614     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
15615     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
15616     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
15617     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
15618
15619     frame_set = &tng_data->current_trajectory_frame_set;
15620
15621     stat = tng_particle_data_find(tng_data, block_id, &data);
15622     if(stat != TNG_SUCCESS)
15623     {
15624         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15625         file_pos = ftello(tng_data->input_file);
15626         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15627         {
15628             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15629             file_pos = ftello(tng_data->input_file);
15630         }
15631         if(stat != TNG_SUCCESS)
15632         {
15633             return(stat);
15634         }
15635         stat = tng_particle_data_find(tng_data, block_id, &data);
15636         if(stat != TNG_SUCCESS)
15637         {
15638             return(stat);
15639         }
15640     }
15641     if(data->last_retrieved_frame < 0)
15642     {
15643         fseeko(tng_data->input_file,
15644               tng_data->first_trajectory_frame_set_input_file_pos,
15645               SEEK_SET);
15646         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
15647         if(stat != TNG_SUCCESS)
15648         {
15649             return(stat);
15650         }
15651         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15652         if(stat != TNG_SUCCESS)
15653         {
15654             return(stat);
15655         }
15656
15657         i = data->first_frame_with_data;
15658     }
15659     else
15660     {
15661         if(data->n_frames == 1 && frame_set->n_frames == 1)
15662         {
15663             i = data->last_retrieved_frame + 1;
15664         }
15665         else
15666         {
15667             i = data->last_retrieved_frame + data->stride_length;
15668         }
15669         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
15670         {
15671             stat = tng_frame_set_of_frame_find(tng_data, i);
15672             if(stat != TNG_SUCCESS)
15673             {
15674                 /* If the frame set search found the frame set after the starting
15675                  * frame set there is a gap in the frame sets. So, even if the frame
15676                  * was not found the next frame with data is still in the found
15677                  * frame set. */
15678                 if(stat == TNG_CRITICAL)
15679                 {
15680                     return(stat);
15681                 }
15682                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
15683                 {
15684                     return(TNG_FAILURE);
15685                 }
15686                 i = frame_set->first_frame;
15687             }
15688         }
15689         if(data->last_retrieved_frame < frame_set->first_frame)
15690         {
15691             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15692             if(stat != TNG_SUCCESS)
15693             {
15694                 return(stat);
15695             }
15696         }
15697     }
15698     data->last_retrieved_frame = i;
15699     *retrieved_frame_number = i;
15700     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
15701     {
15702         *retrieved_time = frame_set->first_frame_time +
15703                         (i - frame_set->first_frame) *
15704                         tng_data->time_per_frame;
15705     }
15706     else
15707     {
15708         *retrieved_time = 0;
15709     }
15710
15711     if(data->stride_length > 1)
15712     {
15713         i = (i - data->first_frame_with_data) / data->stride_length;
15714     }
15715     else
15716     {
15717         i = (i - frame_set->first_frame);
15718     }
15719
15720     tng_num_particles_get(tng_data, &n_particles);
15721
15722     *data_type = data->datatype;
15723
15724     switch(*data_type)
15725     {
15726     case TNG_CHAR_DATA:
15727         return(TNG_FAILURE);
15728     case TNG_INT_DATA:
15729         size = sizeof(int64_t);
15730         break;
15731     case TNG_FLOAT_DATA:
15732         size = sizeof(float);
15733         break;
15734     case TNG_DOUBLE_DATA:
15735     default:
15736         size = sizeof(double);
15737     }
15738
15739     full_data_len = size * n_particles * data->n_values_per_frame;
15740
15741 //     fprintf(stderr, "TNG library: TEMP: i = %" PRId64 ", full_data_len = %" PRId64 ", size = %d, n_particles = %" PRId64 ", n_values_per_frame = %" PRId64 "\n",
15742 //            i, full_data_len, size, n_particles, data->n_values_per_frame);
15743
15744     temp = (char *)realloc(*values, full_data_len);
15745     if(!temp)
15746     {
15747         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
15748                 __FILE__, __LINE__);
15749         free(*values);
15750         *values = 0;
15751         return(TNG_CRITICAL);
15752     }
15753
15754     *values = temp;
15755
15756     memcpy(*values, (char *)data->values + i * full_data_len, full_data_len);
15757
15758     return(TNG_SUCCESS);
15759 }
15760
15761 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
15762                 (const tng_trajectory_t tng_data,
15763                  const int64_t block_id,
15764                  void **values,
15765                  char *data_type,
15766                  int64_t *retrieved_frame_number,
15767                  double *retrieved_time)
15768 {
15769     tng_trajectory_frame_set_t frame_set;
15770     tng_data_t data = 0;
15771     tng_function_status stat;
15772     int size;
15773     int64_t i, full_data_len;
15774     void *temp;
15775     int64_t file_pos;
15776
15777     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15778     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
15779     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
15780     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
15781     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
15782
15783     frame_set = &tng_data->current_trajectory_frame_set;
15784
15785     stat = tng_data_find(tng_data, block_id, &data);
15786     if(stat != TNG_SUCCESS)
15787     {
15788         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15789         file_pos = ftello(tng_data->input_file);
15790         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15791         {
15792             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15793             file_pos = ftello(tng_data->input_file);
15794         }
15795         if(stat != TNG_SUCCESS)
15796         {
15797             return(stat);
15798         }
15799         stat = tng_data_find(tng_data, block_id, &data);
15800         if(stat != TNG_SUCCESS)
15801         {
15802             return(stat);
15803         }
15804     }
15805     if(data->last_retrieved_frame < 0)
15806     {
15807         fseeko(tng_data->input_file,
15808                 tng_data->first_trajectory_frame_set_input_file_pos,
15809                 SEEK_SET);
15810         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
15811         if(stat != TNG_SUCCESS)
15812         {
15813             return(stat);
15814         }
15815         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15816         if(stat != TNG_SUCCESS)
15817         {
15818             return(stat);
15819         }
15820
15821         i = data->first_frame_with_data;
15822     }
15823     else
15824     {
15825         if(data->n_frames == 1 && frame_set->n_frames == 1)
15826         {
15827             i = data->last_retrieved_frame + 1;
15828         }
15829         else
15830         {
15831             i = data->last_retrieved_frame + data->stride_length;
15832         }
15833         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
15834         {
15835             stat = tng_frame_set_of_frame_find(tng_data, i);
15836             if(stat != TNG_SUCCESS)
15837             {
15838                 /* If the frame set search found the frame set after the starting
15839                  * frame set there is a gap in the frame sets. So, even if the frame
15840                  * was not found the next frame with data is still in the found
15841                  * frame set. */
15842                 if(stat == TNG_CRITICAL)
15843                 {
15844                     return(stat);
15845                 }
15846                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
15847                 {
15848                     return(TNG_FAILURE);
15849                 }
15850                 i = frame_set->first_frame;
15851             }
15852         }
15853         if(data->last_retrieved_frame < frame_set->first_frame)
15854         {
15855             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15856             if(stat != TNG_SUCCESS)
15857             {
15858                 return(stat);
15859             }
15860         }
15861     }
15862     data->last_retrieved_frame = i;
15863     *retrieved_frame_number = i;
15864     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
15865     {
15866         *retrieved_time = frame_set->first_frame_time +
15867                         (i - frame_set->first_frame) *
15868                         tng_data->time_per_frame;
15869     }
15870     else
15871     {
15872         *retrieved_time = 0;
15873     }
15874
15875     if(data->stride_length > 1)
15876     {
15877         i = (i - data->first_frame_with_data) / data->stride_length;
15878     }
15879     else
15880     {
15881         i = (i - frame_set->first_frame);
15882     }
15883
15884     *data_type = data->datatype;
15885
15886     switch(*data_type)
15887     {
15888     case TNG_CHAR_DATA:
15889         return(TNG_FAILURE);
15890     case TNG_INT_DATA:
15891         size = sizeof(int64_t);
15892         break;
15893     case TNG_FLOAT_DATA:
15894         size = sizeof(float);
15895         break;
15896     case TNG_DOUBLE_DATA:
15897     default:
15898         size = sizeof(double);
15899     }
15900
15901     full_data_len = size * data->n_values_per_frame;
15902
15903     temp = (char *)realloc(*values, full_data_len);
15904     if(!temp)
15905     {
15906         fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
15907                 __FILE__, __LINE__);
15908         free(*values);
15909         *values = 0;
15910         return(TNG_CRITICAL);
15911     }
15912
15913     *values = temp;
15914
15915     memcpy(*values, (char *)data->values + i * full_data_len, full_data_len);
15916
15917     return(TNG_SUCCESS);
15918 }
15919
15920 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
15921                 (const tng_trajectory_t tng_data,
15922                  const int64_t first_frame,
15923                  const int64_t last_frame,
15924                  float **positions,
15925                  int64_t *stride_length)
15926 {
15927     int64_t n_particles, n_values_per_frame;
15928     char type;
15929     tng_function_status stat;
15930
15931     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15932     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
15933     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
15934     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15935
15936     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
15937                                                  first_frame, last_frame,
15938                                                  TNG_USE_HASH,
15939                                                  (void **)positions,
15940                                                  &n_particles,
15941                                                  stride_length,
15942                                                  &n_values_per_frame,
15943                                                  &type);
15944
15945     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15946     {
15947         return(TNG_FAILURE);
15948     }
15949
15950     return(stat);
15951 }
15952
15953 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
15954                 (const tng_trajectory_t tng_data,
15955                  const int64_t first_frame,
15956                  const int64_t last_frame,
15957                  float **velocities,
15958                  int64_t *stride_length)
15959 {
15960     int64_t n_particles, n_values_per_frame;
15961     char type;
15962     tng_function_status stat;
15963
15964     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15965     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
15966     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
15967     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15968
15969     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
15970                                                  first_frame, last_frame,
15971                                                  TNG_USE_HASH,
15972                                                  (void **)velocities,
15973                                                  &n_particles,
15974                                                  stride_length,
15975                                                  &n_values_per_frame,
15976                                                  &type);
15977
15978     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15979     {
15980         return(TNG_FAILURE);
15981     }
15982
15983     return(stat);
15984 }
15985
15986 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
15987                 (const tng_trajectory_t tng_data,
15988                  const int64_t first_frame,
15989                  const int64_t last_frame,
15990                  float **forces,
15991                  int64_t *stride_length)
15992 {
15993     int64_t n_particles, n_values_per_frame;
15994     char type;
15995     tng_function_status stat;
15996
15997     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15998     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
15999     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16000     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16001
16002     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16003                                                  first_frame, last_frame,
16004                                                  TNG_USE_HASH,
16005                                                  (void **)forces,
16006                                                  &n_particles,
16007                                                  stride_length,
16008                                                  &n_values_per_frame,
16009                                                  &type);
16010
16011     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16012     {
16013         return(TNG_FAILURE);
16014     }
16015
16016     return(stat);
16017 }
16018
16019 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
16020                 (const tng_trajectory_t tng_data,
16021                  const int64_t first_frame,
16022                  const int64_t last_frame,
16023                  float **box_shape,
16024                  int64_t *stride_length)
16025 {
16026     int64_t n_values_per_frame;
16027     char type;
16028     tng_function_status stat;
16029
16030     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16031     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16032     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16033     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16034
16035     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16036                                         first_frame, last_frame,
16037                                         TNG_USE_HASH,
16038                                         (void **)box_shape,
16039                                         stride_length,
16040                                         &n_values_per_frame,
16041                                         &type);
16042
16043     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16044     {
16045         return(TNG_FAILURE);
16046     }
16047
16048     return(stat);
16049 }
16050
16051 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
16052                 (const tng_trajectory_t tng_data,
16053                  const int64_t i,
16054                  const int64_t n_values_per_frame,
16055                  const int64_t block_id,
16056                  const char *block_name,
16057                  const char particle_dependency,
16058                  const char compression)
16059 {
16060     tng_trajectory_frame_set_t frame_set;
16061     tng_data_t data;
16062     int64_t n_particles, n_frames;
16063     tng_function_status stat;
16064
16065     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16066     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16067
16068     if(i <= 0)
16069     {
16070         fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
16071                i, __FILE__, __LINE__);
16072         return(TNG_FAILURE);
16073     }
16074
16075     frame_set = &tng_data->current_trajectory_frame_set;
16076
16077     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16078     {
16079         n_frames = tng_data->frame_set_n_frames;
16080
16081         stat = tng_frame_set_new(tng_data, 0, n_frames);
16082         if(stat != TNG_SUCCESS)
16083         {
16084             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16085                 __LINE__);
16086             return(stat);
16087         }
16088     }
16089     else
16090     {
16091         n_frames = frame_set->n_frames;
16092     }
16093
16094     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16095     {
16096         tng_num_particles_get(tng_data, &n_particles);
16097         if(n_particles <= 0)
16098         {
16099             return(TNG_FAILURE);
16100         }
16101
16102         if(tng_particle_data_find(tng_data, block_id, &data)
16103         != TNG_SUCCESS)
16104         {
16105             stat = tng_particle_data_block_add(tng_data, block_id,
16106                                                block_name,
16107                                                TNG_FLOAT_DATA,
16108                                                TNG_TRAJECTORY_BLOCK,
16109                                                n_frames, n_values_per_frame, i,
16110                                                0, n_particles,
16111                                                compression, 0);
16112             if(stat != TNG_SUCCESS)
16113             {
16114                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16115                        __FILE__, __LINE__);
16116                 return(stat);
16117             }
16118             data = &frame_set->tr_particle_data[frame_set->
16119                                                   n_particle_data_blocks - 1];
16120             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16121                                                   i, n_particles,
16122                                                   n_values_per_frame);
16123             if(stat != TNG_SUCCESS)
16124             {
16125                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16126                        __FILE__, __LINE__);
16127                 return(stat);
16128             }
16129         }
16130         else
16131         {
16132             if(data->stride_length != i)
16133             {
16134                 data->stride_length = i;
16135                 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16136                                                       i, n_particles,
16137                                                       n_values_per_frame);
16138                 if(stat != TNG_SUCCESS)
16139                 {
16140                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16141                            __FILE__, __LINE__);
16142                     return(stat);
16143                 }
16144             }
16145         }
16146     }
16147     else
16148     {
16149         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16150         {
16151             stat = tng_data_block_add(tng_data, block_id, block_name,
16152                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
16153                                       n_frames, n_values_per_frame,
16154                                       i, compression, 0);
16155             if(stat != TNG_SUCCESS)
16156             {
16157                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16158                        __FILE__, __LINE__);
16159                 return(stat);
16160             }
16161             data = &frame_set->tr_data[frame_set->
16162                                           n_data_blocks - 1];
16163             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16164                                          i, n_values_per_frame);
16165             if(stat != TNG_SUCCESS)
16166             {
16167                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16168                        __FILE__, __LINE__);
16169                 return(stat);
16170             }
16171         }
16172         else
16173         {
16174             if(data->stride_length != i)
16175             {
16176                 data->stride_length = i;
16177                 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16178                                              i, n_values_per_frame);
16179                 if(stat != TNG_SUCCESS)
16180                 {
16181                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16182                            __FILE__, __LINE__);
16183                     return(stat);
16184                 }
16185             }
16186         }
16187     }
16188
16189     return(TNG_SUCCESS);
16190 }
16191
16192 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
16193                 (const tng_trajectory_t tng_data,
16194                  const int64_t i,
16195                  const int64_t n_values_per_frame,
16196                  const int64_t block_id,
16197                  const char *block_name,
16198                  const char particle_dependency,
16199                  const char compression)
16200 {
16201     tng_trajectory_frame_set_t frame_set;
16202     tng_data_t data;
16203     int64_t n_particles, n_frames;
16204     tng_function_status stat;
16205
16206     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16207     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16208
16209     if(i <= 0)
16210     {
16211         fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
16212                i, __FILE__, __LINE__);
16213         return(TNG_FAILURE);
16214     }
16215
16216     frame_set = &tng_data->current_trajectory_frame_set;
16217
16218     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16219     {
16220         n_frames = tng_data->frame_set_n_frames;
16221
16222         stat = tng_frame_set_new(tng_data, 0, n_frames);
16223         if(stat != TNG_SUCCESS)
16224         {
16225             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16226                 __LINE__);
16227             return(stat);
16228         }
16229     }
16230     else
16231     {
16232         n_frames = frame_set->n_frames;
16233     }
16234
16235     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16236     {
16237         tng_num_particles_get(tng_data, &n_particles);
16238
16239         if(n_particles <= 0)
16240         {
16241             return(TNG_FAILURE);
16242         }
16243
16244         if(tng_particle_data_find(tng_data, block_id, &data)
16245         != TNG_SUCCESS)
16246         {
16247             stat = tng_particle_data_block_add(tng_data, block_id,
16248                                             block_name,
16249                                             TNG_DOUBLE_DATA,
16250                                             TNG_TRAJECTORY_BLOCK,
16251                                             n_frames, n_values_per_frame, i,
16252                                             0, n_particles,
16253                                             compression, 0);
16254             if(stat != TNG_SUCCESS)
16255             {
16256                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16257                        __FILE__, __LINE__);
16258                 return(stat);
16259             }
16260             data = &frame_set->tr_particle_data[frame_set->
16261                                                   n_particle_data_blocks - 1];
16262             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16263                                                   i, n_particles,
16264                                                   n_values_per_frame);
16265             if(stat != TNG_SUCCESS)
16266             {
16267                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16268                        __FILE__, __LINE__);
16269                 return(stat);
16270             }
16271         }
16272         else
16273         {
16274             data->stride_length = i;
16275         }
16276     }
16277     else
16278     {
16279         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16280         {
16281             stat = tng_data_block_add(tng_data, block_id, block_name,
16282                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
16283                                       n_frames, n_values_per_frame,
16284                                       i, compression, 0);
16285             if(stat != TNG_SUCCESS)
16286             {
16287                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16288                        __FILE__, __LINE__);
16289                 return(stat);
16290             }
16291             data = &frame_set->tr_data[frame_set->
16292                                           n_data_blocks - 1];
16293             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16294                                          i, n_values_per_frame);
16295             if(stat != TNG_SUCCESS)
16296             {
16297                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16298                        __FILE__, __LINE__);
16299                 return(stat);
16300             }
16301         }
16302         else
16303         {
16304             data->stride_length = i;
16305         }
16306     }
16307
16308     return(TNG_SUCCESS);
16309 }
16310
16311 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
16312                 (const tng_trajectory_t tng_data,
16313                  const int64_t i,
16314                  const int64_t n_values_per_frame,
16315                  const int64_t block_id,
16316                  const char *block_name,
16317                  const char particle_dependency,
16318                  const char compression)
16319 {
16320     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
16321            "See documentation. %s: %d", __FILE__, __LINE__);
16322     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
16323                                                block_id, block_name,
16324                                                particle_dependency,
16325                                                compression));
16326 }
16327 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
16328                 (const tng_trajectory_t tng_data,
16329                  const int64_t i)
16330 {
16331     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16332     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16333
16334     return(tng_util_generic_write_interval_set(tng_data, i, 3,
16335                                                TNG_TRAJ_POSITIONS,
16336                                                "POSITIONS",
16337                                                TNG_PARTICLE_BLOCK_DATA,
16338                                                TNG_TNG_COMPRESSION));
16339 }
16340
16341 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
16342                 (const tng_trajectory_t tng_data,
16343                  const int64_t i)
16344 {
16345     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16346     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16347
16348     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16349                                                       TNG_TRAJ_POSITIONS,
16350                                                       "POSITIONS",
16351                                                       TNG_PARTICLE_BLOCK_DATA,
16352                                                       TNG_TNG_COMPRESSION));
16353 }
16354
16355 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
16356                 (const tng_trajectory_t tng_data,
16357                  const int64_t i)
16358 {
16359     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
16360            "See documentation. %s: %d", __FILE__, __LINE__);
16361     return(tng_util_pos_write_interval_set(tng_data, i));
16362 }
16363
16364 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
16365                 (const tng_trajectory_t tng_data,
16366                  const int64_t i)
16367 {
16368     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16369     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16370
16371     return(tng_util_generic_write_interval_set(tng_data, i, 3,
16372                                                TNG_TRAJ_VELOCITIES,
16373                                                "VELOCITIES",
16374                                                TNG_PARTICLE_BLOCK_DATA,
16375                                                TNG_TNG_COMPRESSION));
16376 }
16377
16378 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
16379                 (const tng_trajectory_t tng_data,
16380                  const int64_t i)
16381 {
16382     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16383     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16384
16385     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16386                                                       TNG_TRAJ_VELOCITIES,
16387                                                       "VELOCITIES",
16388                                                       TNG_PARTICLE_BLOCK_DATA,
16389                                                       TNG_TNG_COMPRESSION));
16390 }
16391
16392 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
16393                 (const tng_trajectory_t tng_data,
16394                  const int64_t i)
16395 {
16396     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
16397            "See documentation. %s: %d", __FILE__, __LINE__);
16398     return(tng_util_vel_write_interval_set(tng_data, i));
16399 }
16400
16401 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
16402                 (const tng_trajectory_t tng_data,
16403                  const int64_t i)
16404 {
16405     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16406     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16407
16408     return(tng_util_generic_write_interval_set(tng_data, i, 3,
16409                                                TNG_TRAJ_FORCES,
16410                                                "FORCES",
16411                                                TNG_PARTICLE_BLOCK_DATA,
16412                                                TNG_GZIP_COMPRESSION));
16413 }
16414
16415 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
16416                 (const tng_trajectory_t tng_data,
16417                  const int64_t i)
16418 {
16419     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16420     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16421
16422     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16423                                                       TNG_TRAJ_FORCES,
16424                                                       "FORCES",
16425                                                       TNG_PARTICLE_BLOCK_DATA,
16426                                                       TNG_GZIP_COMPRESSION));
16427 }
16428
16429 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
16430                 (const tng_trajectory_t tng_data,
16431                  const int64_t i)
16432 {
16433     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
16434            "See documentation. %s: %d", __FILE__, __LINE__);
16435     return(tng_util_force_write_interval_set(tng_data, i));
16436 }
16437
16438 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
16439                 (const tng_trajectory_t tng_data,
16440                  const int64_t i)
16441 {
16442     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16443     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16444
16445     return(tng_util_generic_write_interval_set(tng_data, i, 9,
16446                                                TNG_TRAJ_BOX_SHAPE,
16447                                                "BOX SHAPE",
16448                                                TNG_NON_PARTICLE_BLOCK_DATA,
16449                                                TNG_GZIP_COMPRESSION));
16450 }
16451
16452 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
16453                 (const tng_trajectory_t tng_data,
16454                  const int64_t i)
16455 {
16456     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16457     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16458
16459     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
16460                                                       TNG_TRAJ_BOX_SHAPE,
16461                                                       "BOX SHAPE",
16462                                                       TNG_NON_PARTICLE_BLOCK_DATA,
16463                                                       TNG_GZIP_COMPRESSION));
16464 }
16465
16466 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
16467                 (const tng_trajectory_t tng_data,
16468                  const int64_t i)
16469 {
16470     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
16471            "See documentation. %s: %d", __FILE__, __LINE__);
16472     return(tng_util_box_shape_write_interval_set(tng_data, i));
16473 }
16474
16475 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
16476                 (const tng_trajectory_t tng_data,
16477                  const int64_t frame_nr,
16478                  const float *values,
16479                  const int64_t n_values_per_frame,
16480                  const int64_t block_id,
16481                  const char *block_name,
16482                  const char particle_dependency,
16483                  const char compression)
16484 {
16485     tng_trajectory_frame_set_t frame_set;
16486     tng_data_t data;
16487     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
16488     int64_t last_frame;
16489     int is_first_frame_flag = 0;
16490     char block_type_flag;
16491     tng_function_status stat;
16492
16493     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16494     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
16495
16496     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16497     {
16498         tng_num_particles_get(tng_data, &n_particles);
16499         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
16500     }
16501
16502     if(values == 0)
16503     {
16504         return(TNG_FAILURE);
16505     }
16506
16507     frame_set = &tng_data->current_trajectory_frame_set;
16508
16509     if(frame_nr < 0)
16510     {
16511         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16512         n_frames = stride_length = 1;
16513     }
16514     else
16515     {
16516         block_type_flag = TNG_TRAJECTORY_BLOCK;
16517
16518         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16519         {
16520             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
16521             if(stat != TNG_SUCCESS)
16522             {
16523                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16524                     __LINE__);
16525                 return(stat);
16526             }
16527         }
16528         last_frame = frame_set->first_frame +
16529                      frame_set->n_frames - 1;
16530         if(frame_nr > last_frame)
16531         {
16532             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
16533             if(stat != TNG_SUCCESS)
16534             {
16535                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
16536                     __LINE__);
16537                 return(stat);
16538             }
16539             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
16540             {
16541                 last_frame = frame_nr - 1;
16542             }
16543             stat = tng_frame_set_new(tng_data, last_frame + 1,
16544                                      tng_data->frame_set_n_frames);
16545             if(stat != TNG_SUCCESS)
16546             {
16547                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16548                     __LINE__);
16549                 return(stat);
16550             }
16551         }
16552         if(frame_set->n_unwritten_frames == 0)
16553         {
16554             is_first_frame_flag = 1;
16555         }
16556         frame_set->n_unwritten_frames = frame_nr -
16557                                         frame_set->first_frame + 1;
16558
16559         n_frames = frame_set->n_frames;
16560     }
16561
16562     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16563     {
16564         if(tng_particle_data_find(tng_data, block_id, &data)
16565         != TNG_SUCCESS)
16566         {
16567             stat = tng_particle_data_block_add(tng_data, block_id,
16568                                                block_name,
16569                                                TNG_FLOAT_DATA,
16570                                                block_type_flag,
16571                                                n_frames, n_values_per_frame,
16572                                                stride_length,
16573                                                0, n_particles,
16574                                                compression, 0);
16575             if(stat != TNG_SUCCESS)
16576             {
16577                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16578                        __FILE__, __LINE__);
16579                 return(stat);
16580             }
16581             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16582             {
16583                 data = &frame_set->tr_particle_data[frame_set->
16584                                                     n_particle_data_blocks - 1];
16585             }
16586             else
16587             {
16588                 data = &tng_data->non_tr_particle_data[tng_data->
16589                                                        n_particle_data_blocks - 1];
16590             }
16591             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16592                                                   stride_length, n_particles,
16593                                                   n_values_per_frame);
16594             if(stat != TNG_SUCCESS)
16595             {
16596                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16597                        __FILE__, __LINE__);
16598                 return(stat);
16599             }
16600         }
16601         /* FIXME: Here we must be able to handle modified n_particles as well. */
16602         else if(n_frames > data->n_frames)
16603         {
16604             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16605                                                   data->stride_length, n_particles,
16606                                                   n_values_per_frame);
16607             if(stat != TNG_SUCCESS)
16608             {
16609                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16610                        __FILE__, __LINE__);
16611                 return(stat);
16612             }
16613         }
16614
16615         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16616         {
16617             stride_length = data->stride_length;
16618
16619             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16620             {
16621                 data->first_frame_with_data = frame_nr;
16622                 frame_pos = 0;
16623             }
16624             else
16625             {
16626                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16627             }
16628
16629             memcpy((char *)data->values + sizeof(float) * frame_pos * n_particles *
16630                    n_values_per_frame, values, sizeof(float) *
16631                    n_particles * n_values_per_frame);
16632         }
16633         else
16634         {
16635             memcpy(data->values, values, sizeof(float) * n_particles *
16636                    n_values_per_frame);
16637         }
16638     }
16639     else
16640     {
16641         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16642         {
16643             stat = tng_data_block_add(tng_data, block_id, block_name,
16644                                       TNG_FLOAT_DATA, block_type_flag,
16645                                       n_frames, n_values_per_frame,
16646                                       stride_length, compression, 0);
16647             if(stat != TNG_SUCCESS)
16648             {
16649                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16650                        __FILE__, __LINE__);
16651                 return(stat);
16652             }
16653             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16654             {
16655                 data = &frame_set->tr_data[frame_set->
16656                                               n_data_blocks - 1];
16657             }
16658             else
16659             {
16660                 data = &tng_data->non_tr_data[tng_data->
16661                                                  n_data_blocks - 1];
16662             }
16663             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16664                                          stride_length, n_values_per_frame);
16665             if(stat != TNG_SUCCESS)
16666             {
16667                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16668                        __FILE__, __LINE__);
16669                 return(stat);
16670             }
16671         }
16672         /* FIXME: Here we must be able to handle modified n_particles as well. */
16673         else if(n_frames > data->n_frames)
16674         {
16675             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16676                                          data->stride_length, n_values_per_frame);
16677             if(stat != TNG_SUCCESS)
16678             {
16679                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16680                        __FILE__, __LINE__);
16681                 return(stat);
16682             }
16683         }
16684
16685         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16686         {
16687             stride_length = data->stride_length;
16688
16689             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16690             {
16691                 data->first_frame_with_data = frame_nr;
16692                 frame_pos = 0;
16693             }
16694             else
16695             {
16696                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16697             }
16698
16699             memcpy((char *)data->values + sizeof(float) * frame_pos *
16700                    n_values_per_frame, values, sizeof(float) *
16701                    n_values_per_frame);
16702         }
16703         else
16704         {
16705             memcpy(data->values, values, sizeof(float) * n_values_per_frame);
16706         }
16707     }
16708
16709     return(TNG_SUCCESS);
16710 }
16711
16712 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
16713                 (const tng_trajectory_t tng_data,
16714                  const int64_t frame_nr,
16715                  const double *values,
16716                  const int64_t n_values_per_frame,
16717                  const int64_t block_id,
16718                  const char *block_name,
16719                  const char particle_dependency,
16720                  const char compression)
16721 {
16722     tng_trajectory_frame_set_t frame_set;
16723     tng_data_t data;
16724     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
16725     int64_t last_frame;
16726     int is_first_frame_flag = 0;
16727     char block_type_flag;
16728     tng_function_status stat;
16729
16730     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16731     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
16732
16733     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16734     {
16735         tng_num_particles_get(tng_data, &n_particles);
16736         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
16737     }
16738
16739     if(values == 0)
16740     {
16741         return(TNG_FAILURE);
16742     }
16743
16744     frame_set = &tng_data->current_trajectory_frame_set;
16745
16746     if(frame_nr < 0)
16747     {
16748         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16749         n_frames = stride_length = 1;
16750     }
16751     else
16752     {
16753         block_type_flag = TNG_TRAJECTORY_BLOCK;
16754
16755         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16756         {
16757             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
16758             if(stat != TNG_SUCCESS)
16759             {
16760                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16761                     __LINE__);
16762                 return(stat);
16763             }
16764         }
16765         last_frame = frame_set->first_frame +
16766                      frame_set->n_frames - 1;
16767         if(frame_nr > last_frame)
16768         {
16769             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
16770             if(stat != TNG_SUCCESS)
16771             {
16772                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
16773                     __LINE__);
16774                 return(stat);
16775             }
16776             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
16777             {
16778                 last_frame = frame_nr - 1;
16779             }
16780             stat = tng_frame_set_new(tng_data, last_frame + 1,
16781                                      tng_data->frame_set_n_frames);
16782             if(stat != TNG_SUCCESS)
16783             {
16784                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16785                     __LINE__);
16786                 return(stat);
16787             }
16788         }
16789         if(frame_set->n_unwritten_frames == 0)
16790         {
16791             is_first_frame_flag = 1;
16792         }
16793         frame_set->n_unwritten_frames = frame_nr -
16794                                         frame_set->first_frame + 1;
16795
16796         n_frames = frame_set->n_frames;
16797     }
16798
16799
16800     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16801     {
16802         if(tng_particle_data_find(tng_data, block_id, &data)
16803         != TNG_SUCCESS)
16804         {
16805             stat = tng_particle_data_block_add(tng_data, block_id,
16806                                             block_name,
16807                                             TNG_DOUBLE_DATA,
16808                                             block_type_flag,
16809                                             n_frames, n_values_per_frame,
16810                                             stride_length,
16811                                             0, n_particles,
16812                                             compression, 0);
16813             if(stat != TNG_SUCCESS)
16814             {
16815                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16816                        __FILE__, __LINE__);
16817                 return(stat);
16818             }
16819             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16820             {
16821                 data = &frame_set->tr_particle_data[frame_set->
16822                                                     n_particle_data_blocks - 1];
16823             }
16824             else
16825             {
16826                 data = &tng_data->non_tr_particle_data[tng_data->
16827                                                     n_particle_data_blocks - 1];
16828             }
16829             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16830                                                   stride_length, n_particles,
16831                                                   n_values_per_frame);
16832             if(stat != TNG_SUCCESS)
16833             {
16834                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16835                        __FILE__, __LINE__);
16836                 return(stat);
16837             }
16838         }
16839         /* FIXME: Here we must be able to handle modified n_particles as well. */
16840         else if(n_frames > data->n_frames)
16841         {
16842             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16843                                                   data->stride_length, n_particles,
16844                                                   n_values_per_frame);
16845             if(stat != TNG_SUCCESS)
16846             {
16847                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16848                        __FILE__, __LINE__);
16849                 return(stat);
16850             }
16851         }
16852
16853         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16854         {
16855             stride_length = data->stride_length;
16856
16857             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16858             {
16859                 data->first_frame_with_data = frame_nr;
16860                 frame_pos = 0;
16861             }
16862             else
16863             {
16864                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16865             }
16866
16867             memcpy((char *)data->values + sizeof(double) * frame_pos * n_particles *
16868                    n_values_per_frame, values, sizeof(double) *
16869                    n_particles * n_values_per_frame);
16870         }
16871         else
16872         {
16873             memcpy(data->values, values, sizeof(double) * n_particles *
16874                    n_values_per_frame);
16875         }
16876     }
16877     else
16878     {
16879         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16880         {
16881             stat = tng_data_block_add(tng_data, block_id, block_name,
16882                                       TNG_DOUBLE_DATA, block_type_flag,
16883                                       n_frames, n_values_per_frame,
16884                                       stride_length, compression, 0);
16885             if(stat != TNG_SUCCESS)
16886             {
16887                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16888                        __FILE__, __LINE__);
16889                 return(stat);
16890             }
16891             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16892             {
16893                 data = &frame_set->tr_data[frame_set->
16894                                               n_data_blocks - 1];
16895             }
16896             else
16897             {
16898                 data = &tng_data->non_tr_data[tng_data->
16899                                                  n_data_blocks - 1];
16900             }
16901             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16902                                          stride_length, n_values_per_frame);
16903             if(stat != TNG_SUCCESS)
16904             {
16905                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16906                        __FILE__, __LINE__);
16907                 return(stat);
16908             }
16909         }
16910         /* FIXME: Here we must be able to handle modified n_particles as well. */
16911         else if(n_frames > data->n_frames)
16912         {
16913             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16914                                          data->stride_length, n_values_per_frame);
16915             if(stat != TNG_SUCCESS)
16916             {
16917                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16918                        __FILE__, __LINE__);
16919                 return(stat);
16920             }
16921         }
16922
16923         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16924         {
16925             stride_length = data->stride_length;
16926
16927             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16928             {
16929                 data->first_frame_with_data = frame_nr;
16930                 frame_pos = 0;
16931             }
16932             else
16933             {
16934                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16935             }
16936
16937             memcpy((char *)data->values + sizeof(double) * frame_pos *
16938                    n_values_per_frame, values, sizeof(double) *
16939                    n_values_per_frame);
16940         }
16941         else
16942         {
16943             memcpy(data->values, values, sizeof(double) * n_values_per_frame);
16944         }
16945     }
16946
16947     return(TNG_SUCCESS);
16948 }
16949
16950 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
16951                 (const tng_trajectory_t tng_data,
16952                  const int64_t frame_nr,
16953                  const float *positions)
16954 {
16955     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16956     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16957
16958     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
16959                                   TNG_TRAJ_POSITIONS, "POSITIONS",
16960                                   TNG_PARTICLE_BLOCK_DATA,
16961                                   TNG_TNG_COMPRESSION));
16962 }
16963
16964 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
16965                 (const tng_trajectory_t tng_data,
16966                  const int64_t frame_nr,
16967                  const double *positions)
16968 {
16969     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16970     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16971
16972     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
16973                                          TNG_TRAJ_POSITIONS, "POSITIONS",
16974                                          TNG_PARTICLE_BLOCK_DATA,
16975                                          TNG_TNG_COMPRESSION));
16976 }
16977
16978 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
16979                 (const tng_trajectory_t tng_data,
16980                  const int64_t frame_nr,
16981                  const float *velocities)
16982 {
16983     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16984     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16985
16986     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
16987                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
16988                                   TNG_PARTICLE_BLOCK_DATA,
16989                                   TNG_TNG_COMPRESSION));
16990 }
16991
16992 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
16993                 (const tng_trajectory_t tng_data,
16994                  const int64_t frame_nr,
16995                  const double *velocities)
16996 {
16997     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16998     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16999
17000     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
17001                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
17002                                          TNG_PARTICLE_BLOCK_DATA,
17003                                          TNG_TNG_COMPRESSION));
17004 }
17005
17006 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
17007                 (const tng_trajectory_t tng_data,
17008                  const int64_t frame_nr,
17009                  const float *forces)
17010 {
17011     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17012     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17013
17014     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
17015                                   TNG_TRAJ_FORCES, "FORCES",
17016                                   TNG_PARTICLE_BLOCK_DATA,
17017                                   TNG_GZIP_COMPRESSION));
17018 }
17019
17020 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
17021                 (const tng_trajectory_t tng_data,
17022                  const int64_t frame_nr,
17023                  const double *forces)
17024 {
17025     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17026     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17027
17028     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
17029                                          TNG_TRAJ_FORCES, "FORCES",
17030                                          TNG_PARTICLE_BLOCK_DATA,
17031                                          TNG_GZIP_COMPRESSION));
17032 }
17033
17034 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
17035                 (const tng_trajectory_t tng_data,
17036                  const int64_t frame_nr,
17037                  const float *box_shape)
17038 {
17039     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17040     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17041
17042     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
17043                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17044                                   TNG_NON_PARTICLE_BLOCK_DATA,
17045                                   TNG_GZIP_COMPRESSION));
17046 }
17047
17048 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
17049                 (const tng_trajectory_t tng_data,
17050                  const int64_t frame_nr,
17051                  const double *box_shape)
17052 {
17053     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17054     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17055
17056     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
17057                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17058                                          TNG_NON_PARTICLE_BLOCK_DATA,
17059                                          TNG_GZIP_COMPRESSION));
17060 }
17061
17062 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
17063                 (const tng_trajectory_t tng_data,
17064                  const int64_t frame_nr,
17065                  const double time,
17066                  const float *values,
17067                  const int64_t n_values_per_frame,
17068                  const int64_t block_id,
17069                  const char *block_name,
17070                  const char particle_dependency,
17071                  const char compression)
17072 {
17073     tng_trajectory_frame_set_t frame_set;
17074     tng_function_status stat;
17075
17076     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17077     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17078     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17079     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17080
17081     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
17082                                   block_id, block_name,
17083                                   particle_dependency,
17084                                   compression);
17085
17086     if(stat != TNG_SUCCESS)
17087     {
17088         return(stat);
17089     }
17090
17091     frame_set = &tng_data->current_trajectory_frame_set;
17092
17093     /* first_frame_time is -1 when it is not yet set. */
17094     if(frame_set->first_frame_time < -0.1)
17095     {
17096         if(frame_nr > frame_set->first_frame)
17097         {
17098             stat = tng_frame_set_first_frame_time_set(tng_data,
17099                                                       time -
17100                                                       (frame_nr -
17101                                                        frame_set->first_frame) *
17102                                                       tng_data->time_per_frame);
17103         }
17104         else
17105         {
17106             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17107         }
17108     }
17109     return(stat);
17110 }
17111
17112 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
17113                 (const tng_trajectory_t tng_data,
17114                  const int64_t frame_nr,
17115                  const double time,
17116                  const double *values,
17117                  const int64_t n_values_per_frame,
17118                  const int64_t block_id,
17119                  const char *block_name,
17120                  const char particle_dependency,
17121                  const char compression)
17122 {
17123     tng_trajectory_frame_set_t frame_set;
17124     tng_function_status stat;
17125
17126     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17127     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17128     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17129     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17130
17131     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
17132                                          block_id, block_name,
17133                                          particle_dependency,
17134                                          compression);
17135
17136     if(stat != TNG_SUCCESS)
17137     {
17138         return(stat);
17139     }
17140
17141     frame_set = &tng_data->current_trajectory_frame_set;
17142
17143     /* first_frame_time is -1 when it is not yet set. */
17144     if(frame_set->first_frame_time < -0.1)
17145     {
17146         if(frame_nr > frame_set->first_frame)
17147         {
17148             stat = tng_frame_set_first_frame_time_set(tng_data,
17149                                                       time -
17150                                                       (frame_nr -
17151                                                        frame_set->first_frame) *
17152                                                       tng_data->time_per_frame);
17153         }
17154         else
17155         {
17156             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17157         }
17158     }
17159     return(stat);
17160 }
17161
17162 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
17163                 (const tng_trajectory_t tng_data,
17164                  const int64_t frame_nr,
17165                  const double time,
17166                  const float *positions)
17167 {
17168     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17169     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17170     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17171     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17172
17173     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
17174                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
17175                                             TNG_PARTICLE_BLOCK_DATA,
17176                                             TNG_TNG_COMPRESSION));
17177 }
17178
17179 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
17180                 (const tng_trajectory_t tng_data,
17181                  const int64_t frame_nr,
17182                  const double time,
17183                  const double *positions)
17184 {
17185     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17186     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17187     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17188     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17189
17190     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17191                                                    positions, 3,
17192                                                    TNG_TRAJ_POSITIONS,
17193                                                    "POSITIONS",
17194                                                    TNG_PARTICLE_BLOCK_DATA,
17195                                                    TNG_TNG_COMPRESSION));
17196 }
17197
17198 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
17199                 (const tng_trajectory_t tng_data,
17200                  const int64_t frame_nr,
17201                  const double time,
17202                  const float *velocities)
17203 {
17204     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17205     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17206     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17207     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17208
17209     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
17210                                             velocities, 3,
17211                                             TNG_TRAJ_VELOCITIES,
17212                                             "VELOCITIES",
17213                                             TNG_PARTICLE_BLOCK_DATA,
17214                                             TNG_TNG_COMPRESSION));
17215 }
17216
17217 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
17218                 (const tng_trajectory_t tng_data,
17219                  const int64_t frame_nr,
17220                  const double time,
17221                  const double *velocities)
17222 {
17223     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17224     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17225     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17226     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17227
17228     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17229                                                    velocities, 3,
17230                                                    TNG_TRAJ_VELOCITIES,
17231                                                    "VELOCITIES",
17232                                                    TNG_PARTICLE_BLOCK_DATA,
17233                                                    TNG_TNG_COMPRESSION));
17234 }
17235
17236 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
17237                 (const tng_trajectory_t tng_data,
17238                  const int64_t frame_nr,
17239                  const double time,
17240                  const float *forces)
17241 {
17242     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17243     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17244     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17245     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17246
17247     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
17248                                             3, TNG_TRAJ_FORCES, "FORCES",
17249                                             TNG_PARTICLE_BLOCK_DATA,
17250                                             TNG_GZIP_COMPRESSION));
17251 }
17252
17253 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
17254                 (const tng_trajectory_t tng_data,
17255                  const int64_t frame_nr,
17256                  const double time,
17257                  const double *forces)
17258 {
17259     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17260     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17261     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17262     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17263
17264     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17265                                                    forces, 3,
17266                                                    TNG_TRAJ_FORCES, "FORCES",
17267                                                    TNG_PARTICLE_BLOCK_DATA,
17268                                                    TNG_GZIP_COMPRESSION));
17269 }
17270
17271 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
17272                 (const tng_trajectory_t tng_data,
17273                  const int64_t frame_nr,
17274                  const double time,
17275                  const float *box_shape)
17276 {
17277     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17278     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17279     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17280     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17281
17282     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
17283                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17284                                             TNG_NON_PARTICLE_BLOCK_DATA,
17285                                             TNG_GZIP_COMPRESSION));
17286 }
17287
17288 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
17289                 (const tng_trajectory_t tng_data,
17290                  const int64_t frame_nr,
17291                  const double time,
17292                  const double *box_shape)
17293 {
17294     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17295     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17296     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17297     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17298
17299     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
17300                                                    time, box_shape, 9,
17301                                                    TNG_TRAJ_BOX_SHAPE,
17302                                                    "BOX SHAPE",
17303                                                    TNG_NON_PARTICLE_BLOCK_DATA,
17304                                                    TNG_GZIP_COMPRESSION));
17305 }
17306
17307 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
17308                 (const tng_trajectory_t tng_data,
17309                  const int64_t block_id,
17310                  int64_t *codec_id,
17311                  double *factor)
17312 {
17313     tng_trajectory_frame_set_t frame_set;
17314     tng_data_t data = 0;
17315     tng_function_status stat;
17316     int64_t i;
17317     int block_type = -1;
17318
17319     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17320     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
17321     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
17322
17323     frame_set = &tng_data->current_trajectory_frame_set;
17324
17325     stat = tng_particle_data_find(tng_data, block_id, &data);
17326     if(stat == TNG_SUCCESS)
17327     {
17328         block_type = TNG_PARTICLE_BLOCK_DATA;
17329     }
17330     else
17331     {
17332         stat = tng_data_find(tng_data, block_id, &data);
17333         if(stat == TNG_SUCCESS)
17334         {
17335             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
17336         }
17337         else
17338         {
17339             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17340             if(stat != TNG_SUCCESS)
17341             {
17342                 return(stat);
17343             }
17344             stat = tng_particle_data_find(tng_data, block_id, &data);
17345             if(stat == TNG_SUCCESS)
17346             {
17347                 block_type = TNG_PARTICLE_BLOCK_DATA;
17348             }
17349             else
17350             {
17351                 stat = tng_data_find(tng_data, block_id, &data);
17352                 if(stat == TNG_SUCCESS)
17353                 {
17354                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
17355                 }
17356                 else
17357                 {
17358                     return(stat);
17359                 }
17360             }
17361         }
17362     }
17363     if(block_type == TNG_PARTICLE_BLOCK_DATA)
17364     {
17365         if(data->last_retrieved_frame < 0)
17366         {
17367             i = data->first_frame_with_data;
17368         }
17369         else
17370         {
17371             i = data->last_retrieved_frame;
17372         }
17373     }
17374     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
17375     {
17376         if(data->last_retrieved_frame < 0)
17377         {
17378             i = data->first_frame_with_data;
17379         }
17380         else
17381         {
17382             i = data->last_retrieved_frame;
17383         }
17384     }
17385     else
17386     {
17387         return(TNG_FAILURE);
17388     }
17389     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17390     {
17391         stat = tng_frame_set_of_frame_find(tng_data, i);
17392         if(stat != TNG_SUCCESS)
17393         {
17394             return(stat);
17395         }
17396         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17397         if(stat != TNG_SUCCESS)
17398         {
17399             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17400                 __FILE__, __LINE__);
17401             return(stat);
17402         }
17403     }
17404     if(block_type == TNG_PARTICLE_BLOCK_DATA)
17405     {
17406         *codec_id = data->codec_id;
17407         *factor   = data->compression_multiplier;
17408     }
17409     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
17410     {
17411         *codec_id = data->codec_id;
17412         *factor   = data->compression_multiplier;
17413     }
17414     return(TNG_SUCCESS);
17415 }
17416
17417 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
17418                 (const tng_trajectory_t tng_data,
17419                  int64_t current_frame,
17420                  const int64_t n_requested_data_block_ids,
17421                  const int64_t *requested_data_block_ids,
17422                  int64_t *next_frame,
17423                  int64_t *n_data_blocks_in_next_frame,
17424                  int64_t **data_block_ids_in_next_frame)
17425 {
17426     tng_trajectory_frame_set_t frame_set;
17427     tng_function_status stat;
17428     tng_data_t data;
17429     tng_gen_block_t block;
17430     int64_t i, j, block_id, *temp;
17431     int64_t data_frame, frame_diff, min_diff;
17432     int64_t size, frame_set_file_pos;
17433     int found, read_all = 0;
17434     int64_t file_pos;
17435
17436     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17437     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
17438     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
17439     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
17440
17441     if(n_requested_data_block_ids)
17442     {
17443         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.");
17444         size = sizeof(int64_t) * n_requested_data_block_ids;
17445         temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
17446         if(!temp)
17447         {
17448             fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
17449                     __FILE__, __LINE__);
17450             free(*data_block_ids_in_next_frame);
17451             *data_block_ids_in_next_frame = 0;
17452             return(TNG_CRITICAL);
17453         }
17454         *data_block_ids_in_next_frame = temp;
17455     }
17456
17457     frame_set = &tng_data->current_trajectory_frame_set;
17458
17459     current_frame += 1;
17460
17461     if(current_frame < frame_set->first_frame ||
17462        current_frame >= frame_set->first_frame + frame_set->n_frames)
17463     {
17464         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
17465         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
17466         if(stat != TNG_SUCCESS)
17467         {
17468             /* If the frame set search found the frame set after the starting
17469              * frame set there is a gap in the frame sets. So, even if the frame
17470              * was not found the next frame with data is still in the found
17471              * frame set. */
17472             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
17473                frame_set_file_pos)
17474             {
17475                 return(stat);
17476             }
17477             current_frame = frame_set->first_frame;
17478         }
17479     }
17480
17481     /* Check for data blocks only if they have not already been found. */
17482     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
17483     {
17484         file_pos = ftello(tng_data->input_file);
17485         if(file_pos < tng_data->input_file_len)
17486         {
17487             tng_block_init(&block);
17488             stat = tng_block_header_read(tng_data, block);
17489             while(file_pos < tng_data->input_file_len &&
17490                 stat != TNG_CRITICAL &&
17491                 block->id != TNG_TRAJECTORY_FRAME_SET &&
17492                 block->id != -1)
17493             {
17494                 stat = tng_block_read_next(tng_data, block,
17495                                         TNG_USE_HASH);
17496                 if(stat != TNG_CRITICAL)
17497                 {
17498                     file_pos = ftello(tng_data->input_file);
17499                     if(file_pos < tng_data->input_file_len)
17500                     {
17501                         stat = tng_block_header_read(tng_data, block);
17502                     }
17503                 }
17504             }
17505             tng_block_destroy(&block);
17506             if(stat == TNG_CRITICAL)
17507             {
17508                 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
17509                         file_pos, __FILE__, __LINE__);
17510                 return(stat);
17511             }
17512         }
17513         read_all = 1;
17514     }
17515
17516     min_diff = -1;
17517
17518     *n_data_blocks_in_next_frame = 0;
17519
17520     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
17521     {
17522         data = &frame_set->tr_particle_data[i];
17523         block_id = data->block_id;
17524
17525         if(n_requested_data_block_ids > 0)
17526         {
17527             found = 0;
17528             for(j = 0; j < n_requested_data_block_ids; j++)
17529             {
17530                 if(block_id == requested_data_block_ids[j])
17531                 {
17532                     found = 1;
17533                     break;
17534                 }
17535             }
17536             if(!found)
17537             {
17538                 continue;
17539             }
17540         }
17541
17542         if(!read_all && (data->last_retrieved_frame < frame_set->first_frame ||
17543            data->last_retrieved_frame >=
17544            frame_set->first_frame + frame_set->n_frames))
17545         {
17546             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
17547                                                                       TNG_USE_HASH, block_id);
17548             if(stat == TNG_CRITICAL)
17549             {
17550                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17551                     __FILE__, __LINE__);
17552                 return(stat);
17553             }
17554             if(stat == TNG_FAILURE)
17555             {
17556                 continue;
17557             }
17558         }
17559         if(frame_set->first_frame != current_frame &&
17560            data->last_retrieved_frame >= 0)
17561         {
17562             data_frame = data->last_retrieved_frame + data->stride_length;
17563         }
17564         else
17565         {
17566             data_frame = data->first_frame_with_data;
17567         }
17568         frame_diff = data_frame - current_frame;
17569         if(frame_diff < 0)
17570         {
17571             continue;
17572         }
17573         if(min_diff == -1 || frame_diff <= min_diff)
17574         {
17575             if(frame_diff < min_diff)
17576             {
17577                 *n_data_blocks_in_next_frame = 1;
17578             }
17579             else
17580             {
17581                 *n_data_blocks_in_next_frame += 1;
17582             }
17583             if(n_requested_data_block_ids <= 0)
17584             {
17585                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
17586                 temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
17587                 if(!temp)
17588                 {
17589                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
17590                             __FILE__, __LINE__);
17591                     free(*data_block_ids_in_next_frame);
17592                     *data_block_ids_in_next_frame = 0;
17593                     return(TNG_CRITICAL);
17594                 }
17595                 *data_block_ids_in_next_frame = temp;
17596             }
17597             else
17598             {
17599                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
17600             }
17601             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
17602
17603             min_diff = frame_diff;
17604         }
17605     }
17606     for(i = 0; i < frame_set->n_data_blocks; i++)
17607     {
17608         data = &frame_set->tr_data[i];
17609         block_id = data->block_id;
17610
17611         if(n_requested_data_block_ids > 0)
17612         {
17613             found = 0;
17614             for(j = 0; j < n_requested_data_block_ids; j++)
17615             {
17616                 if(block_id == requested_data_block_ids[j])
17617                 {
17618                     found = 1;
17619                     break;
17620                 }
17621             }
17622             if(!found)
17623             {
17624                 continue;
17625             }
17626         }
17627
17628         if(!read_all && (data->last_retrieved_frame < frame_set->first_frame ||
17629            data->last_retrieved_frame >=
17630            frame_set->first_frame + frame_set->n_frames))
17631         {
17632             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
17633                                                                       TNG_USE_HASH, block_id);
17634             if(stat == TNG_CRITICAL)
17635             {
17636                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17637                     __FILE__, __LINE__);
17638                 return(stat);
17639             }
17640             if(stat == TNG_FAILURE)
17641             {
17642                 continue;
17643             }
17644         }
17645         if(frame_set->first_frame != current_frame &&
17646            data->last_retrieved_frame >= 0)
17647         {
17648             data_frame = data->last_retrieved_frame + data->stride_length;
17649         }
17650         else
17651         {
17652             data_frame = data->first_frame_with_data;
17653         }
17654         frame_diff = data_frame - current_frame;
17655         if(frame_diff < 0)
17656         {
17657             continue;
17658         }
17659         if(min_diff == -1 || frame_diff <= min_diff)
17660         {
17661             if(frame_diff < min_diff)
17662             {
17663                 *n_data_blocks_in_next_frame = 1;
17664             }
17665             else
17666             {
17667                 *n_data_blocks_in_next_frame += 1;
17668             }
17669             if(n_requested_data_block_ids <= 0)
17670             {
17671                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
17672                 temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
17673                 if(!temp)
17674                 {
17675                     fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
17676                             __FILE__, __LINE__);
17677                     free(*data_block_ids_in_next_frame);
17678                     *data_block_ids_in_next_frame = 0;
17679                     return(TNG_CRITICAL);
17680                 }
17681                 *data_block_ids_in_next_frame = temp;
17682             }
17683             else
17684             {
17685                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
17686             }
17687             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
17688
17689             min_diff = frame_diff;
17690         }
17691     }
17692     if(min_diff < 0)
17693     {
17694         return(TNG_FAILURE);
17695     }
17696     *next_frame = current_frame + min_diff;
17697
17698     return(TNG_SUCCESS);
17699 }
17700
17701 /*
17702 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
17703                 (const tng_trajectory_t tng_data,
17704                  int64_t *n_data_blocks,
17705                  int64_t **data_block_ids,
17706                  char ***data_block_names,
17707                  int64_t **stride_lengths,
17708                  int64_t **n_values_per_frame,
17709                  char **block_types,
17710                  char **dependencies,
17711                  char **compressions)
17712 {
17713     tng_gen_block_t block;
17714     int64_t orig_file_pos, file_pos;
17715
17716     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17717     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
17718     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
17719     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
17720     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
17721
17722     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
17723     {
17724         return(TNG_CRITICAL);
17725     }
17726
17727     orig_file_pos = ftello(tng_data->input_file);
17728
17729     fseeko(tng_data->input_file, 0, SEEK_SET);
17730     file_pos = 0;
17731
17732     *n_data_blocks = 0;
17733
17734     tng_block_init(&block);
17735
17736     while(file_pos < tng_data->input_file_len &&
17737           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
17738     {
17739         if(block->id > TNG_TRAJECTORY_FRAME_SET)
17740         {
17741
17742         }
17743         file_pos += (block->block_contents_size + block->header_contents_size);
17744         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
17745     }
17746
17747     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
17748
17749     return(TNG_SUCCESS);
17750 }
17751 */
17752 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
17753                 (const tng_trajectory_t tng_data,
17754                  const int64_t prev_frame)
17755 {
17756     tng_function_status stat;
17757     FILE *temp = tng_data->input_file;
17758
17759     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17760     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
17761
17762     tng_data->input_file = tng_data->output_file;
17763
17764     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
17765     if(stat != TNG_SUCCESS)
17766     {
17767         return(stat);
17768     }
17769
17770     tng_data->current_trajectory_frame_set_output_file_pos =
17771     tng_data->current_trajectory_frame_set_input_file_pos;
17772
17773     tng_data->input_file = temp;
17774
17775     return(TNG_SUCCESS);
17776 }
17777
17778 tng_function_status DECLSPECDLLEXPORT tng_util_num_frames_with_data_of_block_id_get
17779                 (const tng_trajectory_t tng_data,
17780                  const int64_t block_id,
17781                  int64_t *n_frames)
17782 {
17783     int64_t curr_file_pos, first_frame_set_file_pos, curr_n_frames;
17784     tng_function_status stat;
17785
17786     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17787
17788     *n_frames = 0;
17789
17790     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
17791     {
17792         return(TNG_CRITICAL);
17793     }
17794
17795     first_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
17796     curr_file_pos = ftello(tng_data->input_file);
17797     fseeko(tng_data->input_file, first_frame_set_file_pos, SEEK_SET);
17798
17799     stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames);
17800
17801     while(stat == TNG_SUCCESS && tng_data->current_trajectory_frame_set.next_frame_set_file_pos != -1)
17802     {
17803         *n_frames += curr_n_frames;
17804         fseeko(tng_data->input_file,
17805                tng_data->current_trajectory_frame_set.next_frame_set_file_pos,
17806                SEEK_SET);
17807         stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames);
17808     }
17809     if(stat == TNG_SUCCESS)
17810     {
17811         *n_frames += curr_n_frames;
17812     }
17813     fseeko(tng_data->input_file, curr_file_pos, SEEK_SET);
17814     if(stat == TNG_CRITICAL)
17815     {
17816         return(TNG_CRITICAL);
17817     }
17818     return(TNG_SUCCESS);
17819 }