TNG version 1.7.6
[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-2015, 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 #ifdef USE_ZLIB
32 #include <zlib.h>
33 #endif
34
35 #include "tng/md5.h"
36 #include "compression/tng_compress.h"
37 #include "tng/version.h"
38
39 #if defined( _WIN32 ) || defined( _WIN64 )
40     #ifndef fseeko
41         #define fseeko _fseeki64
42     #endif
43     #ifndef ftello
44         #ifdef __MINGW32__
45             #define ftello ftello64
46         #else
47             #define ftello _ftelli64
48         #endif
49     #endif
50 #endif
51
52 struct tng_bond {
53     /** One of the atoms of the bond */
54     int64_t from_atom_id;
55     /** The other atom of the bond */
56     int64_t to_atom_id;
57 };
58
59 struct tng_atom {
60     /** The residue containing this atom */
61     tng_residue_t residue;
62     /** A unique (per molecule) ID number of the atom */
63     int64_t id;
64     /** The atom_type (depending on the forcefield) */
65     char *atom_type;
66     /** The name of the atom */
67     char *name;
68 };
69
70 struct tng_residue {
71     /** The chain containing this residue */
72     tng_chain_t chain;
73     /** A unique (per chain) ID number of the residue */
74     int64_t id;
75     /** The name of the residue */
76     char *name;
77     /** The number of atoms in the residue */
78     int64_t n_atoms;
79     /** A list of atoms in the residue */
80     int64_t atoms_offset;
81 };
82
83 struct tng_chain {
84     /** The molecule containing this chain */
85     tng_molecule_t molecule;
86     /** A unique (per molecule) ID number of the chain */
87     int64_t id;
88     /** The name of the chain */
89     char *name;
90     /** The number of residues in the chain */
91     int64_t n_residues;
92     /** A list of residues in the chain */
93     tng_residue_t residues;
94 };
95
96 struct tng_molecule {
97     /** A unique ID number of the molecule */
98     int64_t id;
99     /** Quaternary structure of the molecule.
100      *  1 => monomeric
101      *  2 => dimeric
102      *  3 => trimeric
103      *  etc */
104     int64_t quaternary_str;
105     /** The number of chains in the molecule */
106     int64_t n_chains;
107     /** The number of residues in the molecule */
108     int64_t n_residues;
109     /** The number of atoms in the molecule */
110     int64_t n_atoms;
111     /** The number of bonds in the molecule. If the bonds are not specified this
112      * value can be 0. */
113     int64_t n_bonds;
114     /** The name of the molecule */
115     char *name;
116     /** A list of chains in the molecule */
117     tng_chain_t chains;
118     /** A list of residues in the molecule */
119     tng_residue_t residues;
120     /** A list of the atoms in the molecule */
121     tng_atom_t atoms;
122     /** A list of the bonds in the molecule */
123     tng_bond_t bonds;
124 };
125
126 struct tng_gen_block {
127     /** The size of the block header in bytes */
128     int64_t header_contents_size;
129     /** The size of the block contents in bytes */
130     int64_t block_contents_size;
131     /** The ID of the block to determine its type */
132     int64_t id;
133     /** The MD5 hash of the block to verify integrity */
134     char md5_hash[TNG_MD5_HASH_LEN];
135     /** The name of the block */
136     char *name;
137     /** The library version used to write the block */
138     int64_t block_version;
139     int64_t alt_hash_type;
140     int64_t alt_hash_len;
141     char *alt_hash;
142     int64_t signature_type;
143     int64_t signature_len;
144     char *signature;
145     /** The full block header contents */
146     char *header_contents;
147     /** The full block contents */
148     char *block_contents;
149 };
150
151 struct tng_particle_mapping {
152     /** The index number of the first particle in this mapping block */
153     int64_t num_first_particle;
154     /** The number of particles list in this mapping block */
155     int64_t n_particles;
156     /** the mapping of index numbers to the real particle numbers in the
157      * trajectory. real_particle_numbers[0] is the real particle number
158      * (as it is numbered in the molecular system) of the first particle
159      * in the data blocks covered by this particle mapping block */
160     int64_t *real_particle_numbers;
161 };
162
163 struct tng_trajectory_frame_set {
164     /** The number of different particle mapping blocks present. */
165     int64_t n_mapping_blocks;
166     /** The atom mappings of this frame set */
167     struct tng_particle_mapping *mappings;
168     /** The first frame of this frame set */
169     int64_t first_frame;
170     /** The number of frames in this frame set */
171     int64_t n_frames;
172     /** The number of written frames in this frame set (used when writing one
173      * frame at a time). */
174     int64_t n_written_frames;
175     /** The number of frames not yet written to file in this frame set
176      * (used from the utility functions to finish the writing properly. */
177     int64_t n_unwritten_frames;
178
179
180     /** A list of the number of each molecule type - only used when using
181      * variable number of atoms */
182     int64_t *molecule_cnt_list;
183     /** The number of particles/atoms - only used when using variable number
184      * of atoms */
185     int64_t n_particles;
186     /** The file position of the next frame set */
187     int64_t next_frame_set_file_pos;
188     /** The file position of the previous frame set */
189     int64_t prev_frame_set_file_pos;
190     /** The file position of the frame set one long stride step ahead */
191     int64_t medium_stride_next_frame_set_file_pos;
192     /** The file position of the frame set one long stride step behind */
193     int64_t medium_stride_prev_frame_set_file_pos;
194     /** The file position of the frame set one long stride step ahead */
195     int64_t long_stride_next_frame_set_file_pos;
196     /** The file position of the frame set one long stride step behind */
197     int64_t long_stride_prev_frame_set_file_pos;
198     /** Time stamp (in seconds) of first frame in frame set */
199     double first_frame_time;
200
201     /* The data blocks in a frame set are trajectory data blocks */
202     /** The number of trajectory data blocks of particle dependent data */
203     int n_particle_data_blocks;
204     /** A list of data blocks containing particle dependent data */
205     struct tng_data *tr_particle_data;
206     /** The number of trajectory data blocks independent of particles */
207     int n_data_blocks;
208     /** A list of data blocks containing particle indepdendent data */
209     struct tng_data *tr_data;
210 };
211
212 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
213 struct tng_data {
214     /** The block ID of the data block containing this particle data.
215      *  This is used to determine the kind of data that is stored */
216     int64_t block_id;
217     /** The name of the data block. This is used to determine the kind of
218      *  data that is stored */
219     char *block_name;
220     /** The type of data stored. */
221     char datatype;
222     /** A flag to indicate if this data block contains frame and/or particle dependent
223      * data */
224     char dependency;
225     /** The frame number of the first data value */
226     int64_t first_frame_with_data;
227     /** The number of frames in this frame set */
228     int64_t n_frames;
229     /** The number of values stored per frame */
230     int64_t n_values_per_frame;
231     /** The number of frames between each data point - e.g. when
232      *  storing sparse data. */
233     int64_t stride_length;
234     /** ID of the CODEC used for compression 0 == no compression. */
235     int64_t codec_id;
236     /** If reading one frame at a time this is the last read frame */
237     int64_t last_retrieved_frame;
238     /** The multiplier used for getting integer values for compression */
239     double compression_multiplier;
240     /** A 1-dimensional array of values of length
241      *  [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
242     void *values;
243     /** If storing character data store it in a 3-dimensional array */
244     char ****strings;
245 };
246
247
248 struct tng_trajectory {
249     /** The path of the input trajectory file */
250     char *input_file_path;
251     /** A handle to the input file */
252     FILE *input_file;
253     /** The length of the input file */
254     int64_t input_file_len;
255     /** The path of the output trajectory file */
256     char *output_file_path;
257     /** A handle to the output file */
258     FILE *output_file;
259     /** Function to swap 32 bit values to and from the endianness of the
260      * input file */
261     tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
262     /** Function to swap 64 bit values to and from the endianness of the
263      * input file */
264     tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
265     /** Function to swap 32 bit values to and from the endianness of the
266      * input file */
267     tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
268     /** Function to swap 64 bit values to and from the endianness of the
269      * input file */
270     tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
271     /** The endianness of 32 bit values of the current computer */
272     char endianness_32;
273     /** The endianness of 64 bit values of the current computer */
274     char endianness_64;
275
276     /** The name of the program producing this trajectory */
277     char *first_program_name;
278     /** The forcefield used in the simulations */
279     char *forcefield_name;
280     /** The name of the user running the simulations */
281     char *first_user_name;
282     /** The name of the computer on which the simulations were performed */
283     char *first_computer_name;
284     /** The PGP signature of the user creating the file. */
285     char *first_pgp_signature;
286     /** The name of the program used when making last modifications to the
287      *  file */
288     char *last_program_name;
289     /** The name of the user making the last modifications to the file */
290     char *last_user_name;
291     /** The name of the computer on which the last modifications were made */
292     char *last_computer_name;
293     /** The PGP signature of the user making the last modifications to the
294      *  file. */
295     char *last_pgp_signature;
296     /** The time (n seconds since 1970) when the file was created */
297     int64_t time;
298     /** The exponential of the value of the distance unit used. The default
299      * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
300      * the measurements are in Ã… the distance_unit_exponential = -10. */
301     int64_t distance_unit_exponential;
302
303     /** A flag indicating if the number of atoms can vary throughout the
304      *  simulation, e.g. using a grand canonical ensemble */
305     char var_num_atoms_flag;
306     /** The number of frames in a frame set. It is allowed to have frame sets
307      *  with fewer frames, but this will help searching for specific frames */
308     int64_t frame_set_n_frames;
309     /** The number of frame sets in a medium stride step */
310     int64_t medium_stride_length;
311     /** The number of frame sets in a long stride step */
312     int64_t long_stride_length;
313     /** The current (can change from one frame set to another) time length
314      *  (in seconds) of one frame */
315     double time_per_frame;
316
317     /** The number of different kinds of molecules in the trajectory */
318     int64_t n_molecules;
319     /** A list of molecules in the trajectory */
320     tng_molecule_t molecules;
321     /** A list of the count of each molecule - if using variable number of
322      *  particles this will be specified in each frame set */
323     int64_t *molecule_cnt_list;
324     /** The total number of particles/atoms. If using variable number of
325      *  particles this will be specified in each frame set */
326     int64_t n_particles;
327
328      /** The pos in the src file of the first frame set */
329     int64_t first_trajectory_frame_set_input_file_pos;
330     /** The pos in the dest file of the first frame set */
331     int64_t first_trajectory_frame_set_output_file_pos;
332     /** The pos in the src file of the last frame set */
333     int64_t last_trajectory_frame_set_input_file_pos;
334     /** The pos in the dest file of the last frame set */
335     int64_t last_trajectory_frame_set_output_file_pos;
336     /** The currently active frame set */
337     struct tng_trajectory_frame_set current_trajectory_frame_set;
338     /** The pos in the src file of the current frame set */
339     int64_t current_trajectory_frame_set_input_file_pos;
340     /** The pos in the dest file of the current frame set */
341     int64_t current_trajectory_frame_set_output_file_pos;
342     /** The number of frame sets in the trajectory N.B. Not saved in file and
343      *  cannot be trusted to be up-to-date */
344     int64_t n_trajectory_frame_sets;
345
346     /* These data blocks are non-trajectory data blocks */
347     /** The number of non-frame dependent particle dependent data blocks */
348     int n_particle_data_blocks;
349     /** A list of data blocks containing particle dependent data */
350     struct tng_data *non_tr_particle_data;
351
352     /** The number of frame and particle independent data blocks */
353     int n_data_blocks;
354     /** A list of frame and particle indepdendent data blocks */
355     struct tng_data *non_tr_data;
356
357     /** TNG compression algorithm for compressing positions */
358     int *compress_algo_pos;
359     /** TNG compression algorithm for compressing velocities */
360     int *compress_algo_vel;
361     /** The precision used for lossy compression */
362     double compression_precision;
363 };
364
365 #ifndef USE_WINDOWS
366 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
367 #define USE_WINDOWS
368 #endif /* win32... */
369 #endif /* not defined USE_WINDOWS */
370
371 #ifdef USE_WINDOWS
372 #define TNG_INLINE __inline
373 #define TNG_SNPRINTF _snprintf
374 #else
375 #define TNG_INLINE inline
376 #define TNG_SNPRINTF snprintf
377 #endif
378
379 static TNG_INLINE size_t tng_min_size(const size_t a, const size_t b)
380 {
381     return (a < b ? a : b);
382 }
383
384 static TNG_INLINE int64_t tng_min_i64(const int64_t a, const int64_t b)
385 {
386     return (a < b ? a : b);
387 }
388
389 static TNG_INLINE int64_t tng_max_i64(const int64_t a, const int64_t b)
390 {
391     return (a > b ? a : b);
392 }
393
394 /**
395  * @brief This function swaps the byte order of a 32 bit numerical variable
396  * to big endian.
397  * @param tng_data is a trajectory data container.
398  * @param v is a pointer to a 32 bit numerical value (float or integer).
399  * @details The function does not only work with integer, but e.g. floats need casting.
400  * If the byte order is already big endian no change is needed.
401  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
402  * byte order is not recognised.
403  */
404 static tng_function_status tng_swap_byte_order_big_endian_32
405                 (const tng_trajectory_t tng_data, int32_t *v)
406 {
407     switch(tng_data->endianness_32)
408     {
409     case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
410         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
411              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
412              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
413              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
414
415         return(TNG_SUCCESS);
416
417     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
418         *v = ((*v & 0xFFFF0000) >> 16) |
419              ((*v & 0x0000FFFF) << 16);
420
421         return(TNG_SUCCESS);
422
423     case TNG_BIG_ENDIAN_32: /* Already correct */
424         return(TNG_SUCCESS);
425
426     default:
427         return(TNG_FAILURE);
428     }
429 }
430
431 /**
432  * @brief This function swaps the byte order of a 64 bit numerical variable
433  * to big endian.
434  * @param tng_data is a trajectory data container.
435  * @param v is a pointer to a 64 bit numerical value (double or integer).
436  * @details The function does not only work with integer, but e.g. floats need casting.
437  * The byte order swapping routine can convert four different byte
438  * orders to big endian.
439  * If the byte order is already big endian no change is needed.
440  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
441  * byte order is not recognised.
442  */
443 static tng_function_status tng_swap_byte_order_big_endian_64
444                 (const tng_trajectory_t tng_data, int64_t *v)
445 {
446     switch(tng_data->endianness_64)
447     {
448     case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
449         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
450              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
451              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
452              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
453              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
454              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
455              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
456              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
457
458         return(TNG_SUCCESS);
459
460     case TNG_QUAD_SWAP_64: /* Byte quad swap */
461         *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
462              ((*v & 0x00000000FFFFFFFFLL) << 32);
463
464         return(TNG_SUCCESS);
465
466     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
467         *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
468              ((*v & 0x0000FFFF0000FFFFLL) << 16);
469
470         return(TNG_SUCCESS);
471
472     case TNG_BYTE_SWAP_64: /* Byte swap */
473         *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
474              ((*v & 0x00FF00FF00FF00FFLL) << 8);
475
476         return(TNG_SUCCESS);
477
478     case TNG_BIG_ENDIAN_64: /* Already correct */
479         return(TNG_SUCCESS);
480
481     default:
482         return(TNG_FAILURE);
483     }
484 }
485
486 /**
487  * @brief This function swaps the byte order of a 32 bit numerical variable
488  * to little endian.
489  * @param tng_data is a trajectory data container.
490  * @param v is a pointer to a 32 bit numerical value (float or integer).
491  * @details The function does not only work with integer, but e.g. floats need casting.
492  * If the byte order is already little endian no change is needed.
493  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
494  * byte order is not recognised.
495  */
496 static tng_function_status tng_swap_byte_order_little_endian_32
497                 (const tng_trajectory_t tng_data, int32_t *v)
498 {
499     switch(tng_data->endianness_32)
500     {
501     case TNG_LITTLE_ENDIAN_32: /* Already correct */
502         return(TNG_SUCCESS);
503
504     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
505         *v = ((*v & 0xFF00FF00) >> 8) |
506              ((*v & 0x00FF00FF) << 8);
507
508         return(TNG_SUCCESS);
509
510     case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
511         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
512              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
513              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
514              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
515
516         return(TNG_SUCCESS);
517
518     default:
519         return(TNG_FAILURE);
520     }
521 }
522
523 /**
524  * @brief This function swaps the byte order of a 64 bit numerical variable
525  * to little endian.
526  * @param tng_data is a trajectory data container.
527  * @param v is a pointer to a 64 bit numerical value (double or integer).
528  * @details The function does not only work with integer, but e.g. floats need casting.
529  * The byte order swapping routine can convert four different byte
530  * orders to little endian.
531  * If the byte order is already little endian no change is needed.
532  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
533  * byte order is not recognised.
534  */
535 static tng_function_status tng_swap_byte_order_little_endian_64
536                 (const tng_trajectory_t tng_data, int64_t *v)
537 {
538     switch(tng_data->endianness_64)
539     {
540     case TNG_LITTLE_ENDIAN_64: /* Already correct */
541         return(TNG_SUCCESS);
542
543     case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
544         *v = ((*v & 0xFF000000FF000000LL) >> 24) |
545              ((*v & 0x00FF000000FF0000LL) >> 8) |
546              ((*v & 0x0000FF000000FF00LL) << 8) |
547              ((*v & 0x000000FF000000FFLL) << 24);
548
549         return(TNG_SUCCESS);
550
551     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
552         *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
553              ((*v & 0x00FF00FF00000000LL) >> 24) |
554              ((*v & 0x00000000FF00FF00LL) << 24) |
555              ((*v & 0x0000000000FF00FFLL) << 40);
556
557         return(TNG_SUCCESS);
558
559     case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
560         *v = ((*v & 0xFFFF000000000000LL) >> 48) |
561              ((*v & 0x0000FFFF00000000LL) >> 16) |
562              ((*v & 0x00000000FFFF0000LL) << 16) |
563              ((*v & 0x000000000000FFFFLL) << 48);
564
565         return(TNG_SUCCESS);
566
567     case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
568         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
569              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
570              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
571              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
572              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
573              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
574              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
575              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
576
577         return(TNG_SUCCESS);
578
579     default:
580         return(TNG_FAILURE);
581     }
582 }
583
584 /**
585  * @brief Read a NULL terminated string from a file.
586  * @param tng_data is a trajectory data container
587  * @param str is a pointer to the character string that will
588  * contain the read string. *str is reallocated in the function
589  * and must be NULL or pointing at already allocated memory.
590  * @param hash_mode is an option to decide whether to use the md5 hash or not.
591  * @param md5_state is a pointer to the current md5 storage, which will be
592  * appended with str if hash_mode == TNG_USE_HASH.
593  * @param line_nr is the line number where this function was called, to be
594  * able to give more useful error messages.
595  */
596 static tng_function_status tng_freadstr(const tng_trajectory_t tng_data,
597                                         char **str,
598                                         const char hash_mode,
599                                         md5_state_t *md5_state,
600                                         const int line_nr)
601 {
602     char temp[TNG_MAX_STR_LEN], *temp_alloc;
603     int c, count = 0;
604
605     do
606     {
607         c = fgetc(tng_data->input_file);
608
609         if (c == EOF)
610         {
611             /* Clear file error flag and return -1 if EOF is read.*/
612             clearerr(tng_data->input_file);
613             return TNG_FAILURE;
614         }
615         else
616         {
617             /* Cast c to char */
618             temp[count++] = (char) c;
619         }
620     } while ((temp[count-1] != '\0') && (count < TNG_MAX_STR_LEN));
621
622     temp_alloc = realloc(*str, count);
623     if(!temp_alloc)
624     {
625         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", count,
626                __FILE__, line_nr);
627         free(*str);
628         *str = 0;
629         return TNG_FAILURE;
630     }
631     *str = temp_alloc;
632
633     strncpy(*str, temp, count);
634
635     if(hash_mode == TNG_USE_HASH)
636     {
637         md5_append(md5_state, (md5_byte_t *)*str, count);
638     }
639
640     return TNG_SUCCESS;
641 }
642
643 /**
644  * @brief Write a NULL terminated string to a file.
645  * @param tng_data is a trajectory data container
646  * @param str is a pointer to the character string should be written.
647  * @param hash_mode is an option to decide whether to use the md5 hash or not.
648  * @param md5_state is a pointer to the current md5 storage, which will be
649  * appended with str if hash_mode == TNG_USE_HASH.
650  * @param line_nr is the line number where this function was called, to be
651  * able to give more useful error messages.
652  */
653 static TNG_INLINE tng_function_status tng_fwritestr(tng_trajectory_t tng_data,
654                                                 const char *str,
655                                                 const char hash_mode,
656                                                 md5_state_t *md5_state,
657                                                 const int line_nr)
658 {
659     size_t len;
660
661     len = tng_min_size(strlen(str) + 1, TNG_MAX_STR_LEN);
662
663     if(fwrite(str, len, 1, tng_data->output_file) != 1)
664     {
665         fprintf(stderr, "TNG library: Could not write block data. %s: %d\n", __FILE__, line_nr);
666         return(TNG_CRITICAL);
667     }
668
669     if(hash_mode == TNG_USE_HASH)
670     {
671         md5_append(md5_state, (md5_byte_t *)str, len);
672     }
673
674     return(TNG_SUCCESS);
675 }
676
677 /**
678  * @brief Read a numerical value from file.
679  * The byte order will be swapped if need be.
680  * @param tng_data is a trajectory data container
681  * @param dest is a pointer to where to store the read data.
682  * @param len is the length (in bytes) of the numerical data type. Should
683  * be 8 for 64 bit, 4 for 32 bit or 1 for a single byte flag.
684  * @param hash_mode is an option to decide whether to use the md5 hash or not.
685  * @param md5_state is a pointer to the current md5 storage, which will be
686  * appended with str if hash_mode == TNG_USE_HASH.
687  * @param line_nr is the line number where this function was called, to be
688  * able to give more useful error messages.
689  */
690 static TNG_INLINE tng_function_status tng_file_input_numerical
691                 (const tng_trajectory_t tng_data,
692                  void *dest,
693                  const size_t len,
694                  const char hash_mode,
695                  md5_state_t *md5_state,
696                  const int line_nr)
697 {
698     if(fread(dest, len, 1, tng_data->input_file) == 0)
699     {
700         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, line_nr);
701         return(TNG_CRITICAL);
702     }
703     if(hash_mode == TNG_USE_HASH)
704     {
705         md5_append(md5_state, (md5_byte_t *)dest, len);
706     }
707     switch(len)
708     {
709     case 8:
710         if(tng_data->input_endianness_swap_func_64 &&
711            tng_data->input_endianness_swap_func_64(tng_data, dest) != TNG_SUCCESS)
712         {
713             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
714                     __FILE__, line_nr);
715         }
716         break;
717     case 4:
718         if(tng_data->input_endianness_swap_func_32 &&
719            tng_data->input_endianness_swap_func_32(tng_data, dest) != TNG_SUCCESS)
720         {
721             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
722                     __FILE__, line_nr);
723         }
724         break;
725     default:
726         break;
727     }
728
729     return(TNG_SUCCESS);
730 }
731
732 /**
733  * @brief Write a numerical value to file.
734  * The byte order will be swapped if need be.
735  * @param tng_data is a trajectory data container
736  * @param src is a pointer to the data to write.
737  * @param len is the length (in bytes) of the numerical data type. Should
738  * be 8 for 64 bit, 4 for 32 bit or 1 for a single byte flag.
739  * @param hash_mode is an option to decide whether to use the md5 hash or not.
740  * @param md5_state is a pointer to the current md5 storage, which will be
741  * appended with str if hash_mode == TNG_USE_HASH.
742  * @param line_nr is the line number where this function was called, to be
743  * able to give more useful error messages.
744  */
745 static TNG_INLINE tng_function_status tng_file_output_numerical
746                 (const tng_trajectory_t tng_data,
747                  const void *src,
748                  const size_t len,
749                  const char hash_mode,
750                  md5_state_t *md5_state,
751                  const int line_nr)
752 {
753     int32_t temp_i32;
754     int64_t temp_i64;
755
756     switch(len)
757     {
758         case 8:
759             temp_i64 = *((int64_t *)src);
760             if(tng_data->output_endianness_swap_func_64 &&
761             tng_data->output_endianness_swap_func_64(tng_data, &temp_i64) != TNG_SUCCESS)
762             {
763                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
764                         __FILE__, line_nr);
765             }
766             if(fwrite(&temp_i64, len, 1, tng_data->output_file) != 1)
767             {
768                 fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr);
769                 return(TNG_CRITICAL);
770             }
771             if(hash_mode == TNG_USE_HASH)
772             {
773                 md5_append(md5_state, (md5_byte_t *)&temp_i64, len);
774             }
775             break;
776         case 4:
777             temp_i32 = *((int32_t *)src);
778             if(tng_data->output_endianness_swap_func_32 &&
779             tng_data->output_endianness_swap_func_32(tng_data, &temp_i32) != TNG_SUCCESS)
780             {
781                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
782                         __FILE__, line_nr);
783             }
784             if(fwrite(&temp_i32, len, 1, tng_data->output_file) != 1)
785             {
786                 fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr);
787                 return(TNG_CRITICAL);
788             }
789             if(hash_mode == TNG_USE_HASH)
790             {
791                 md5_append(md5_state, (md5_byte_t *)&temp_i32, len);
792             }
793             break;
794         default:
795             if(fwrite(src, len, 1, tng_data->output_file) != 1)
796             {
797                 fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr);
798                 return(TNG_CRITICAL);
799             }
800             if(hash_mode == TNG_USE_HASH)
801             {
802                 md5_append(md5_state, (md5_byte_t *)src, len);
803             }
804             break;
805     }
806
807     return(TNG_SUCCESS);
808 }
809
810 /**
811  * @brief Generate the md5 hash of a block.
812  * The hash is created based on the actual block contents.
813  * @param block is a general block container.
814  * @return TNG_SUCCESS (0) if successful.
815  */
816 static tng_function_status tng_block_md5_hash_generate(const tng_gen_block_t block)
817 {
818     md5_state_t md5_state;
819
820     md5_init(&md5_state);
821     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
822                (int)block->block_contents_size);
823     md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
824
825     return(TNG_SUCCESS);
826 }
827
828 /**
829  * @brief If there is data left in the block read that to append that to the MD5 hash.
830  * @param tng_data is a trajectory data container.
831  * @param block is the data block that is being read.
832  * @param start_pos is the file position where the block started.
833  * @param md5_state is the md5 to which the md5 of the remaining block
834  * will be appended.
835  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
836  * error has occured.
837  */
838 static tng_function_status tng_md5_remaining_append(const tng_trajectory_t tng_data,
839                                                     const tng_gen_block_t block,
840                                                     const int64_t start_pos,
841                                                     md5_state_t *md5_state)
842 {
843     int64_t curr_file_pos;
844     char *temp_data;
845
846     curr_file_pos = ftello(tng_data->input_file);
847     if(curr_file_pos < start_pos + block->block_contents_size)
848     {
849         temp_data = malloc(start_pos + block->block_contents_size - curr_file_pos);
850         if(!temp_data)
851         {
852             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
853                     start_pos + block->block_contents_size - curr_file_pos, __FILE__, __LINE__);
854             return(TNG_CRITICAL);
855         }
856         if(fread(temp_data, start_pos + block->block_contents_size - curr_file_pos,
857                     1, tng_data->input_file) == 0)
858         {
859             fprintf(stderr, "TNG library: Cannot read remaining part of block to generate MD5 sum. %s: %d\n", __FILE__, __LINE__);
860             free(temp_data);
861             return(TNG_CRITICAL);
862         }
863         md5_append(md5_state, (md5_byte_t *)temp_data,
864                    start_pos + block->block_contents_size - curr_file_pos);
865         free(temp_data);
866     }
867
868     return(TNG_SUCCESS);
869 }
870
871 /**
872  * @brief Open the input file if it is not already opened.
873  * @param tng_data is a trajectory data container.
874  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
875  * error has occured.
876  */
877 static tng_function_status tng_input_file_init(const tng_trajectory_t tng_data)
878 {
879     int64_t file_pos;
880
881     if(!tng_data->input_file)
882     {
883         if(!tng_data->input_file_path)
884         {
885             fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
886                    __FILE__, __LINE__);
887             return(TNG_CRITICAL);
888         }
889         tng_data->input_file = fopen(tng_data->input_file_path, "rb");
890         if(!tng_data->input_file)
891         {
892             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
893                    tng_data->input_file_path, __FILE__, __LINE__);
894             return(TNG_CRITICAL);
895         }
896     }
897
898     if(!tng_data->input_file_len)
899     {
900         file_pos = ftello(tng_data->input_file);
901         fseeko(tng_data->input_file, 0, SEEK_END);
902         tng_data->input_file_len = ftello(tng_data->input_file);
903         fseeko(tng_data->input_file, file_pos, SEEK_SET);
904     }
905
906     return(TNG_SUCCESS);
907 }
908
909 /**
910  * @brief Open the output file if it is not already opened
911  * @param tng_data is a trajectory data container.
912  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
913  * error has occured.
914  */
915 static tng_function_status tng_output_file_init(const tng_trajectory_t tng_data)
916 {
917     if(!tng_data->output_file)
918     {
919         if(!tng_data->output_file_path)
920         {
921             fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
922                    __FILE__, __LINE__);
923             return(TNG_CRITICAL);
924         }
925
926         tng_data->output_file = fopen(tng_data->output_file_path, "wb+");
927
928         if(!tng_data->output_file)
929         {
930             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
931                    tng_data->output_file_path, __FILE__, __LINE__);
932             return(TNG_CRITICAL);
933         }
934     }
935     return(TNG_SUCCESS);
936 }
937
938 /**
939  * @brief Setup a file block container.
940  * @param block_p a pointer to memory to initialise as a file block container.
941  * @details Memory is allocated during initialisation.
942  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
943  * error has occured.
944  */
945 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
946 {
947     tng_gen_block_t block;
948
949     *block_p = malloc(sizeof(struct tng_gen_block));
950     if(!*block_p)
951     {
952         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
953                sizeof(struct tng_gen_block), __FILE__, __LINE__);
954         return(TNG_CRITICAL);
955     }
956
957     block = *block_p;
958
959     block->id = -1;
960     /* Reset the md5_hash */
961     memset(block->md5_hash, '\0', TNG_MD5_HASH_LEN);
962     block->name = 0;
963     block->block_version = TNG_API_VERSION;
964     block->header_contents = 0;
965     block->header_contents_size = 0;
966     block->block_contents = 0;
967     block->block_contents_size = 0;
968
969     return(TNG_SUCCESS);
970 }
971
972 /**
973  * @brief Clean up a file block container.
974  * @param block_p a pointer to the file block container to destroy.
975  * @details All allocated memory in the data structure is freed, as well as
976  * block_p itself.
977  * @return TNG_SUCCESS (0) if successful.
978  */
979 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
980 {
981     tng_gen_block_t block = *block_p;
982
983     if(!*block_p)
984     {
985         return(TNG_SUCCESS);
986     }
987
988 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
989     if(block->name)
990     {
991         free(block->name);
992         block->name = 0;
993     }
994     if(block->header_contents)
995     {
996         free(block->header_contents);
997         block->header_contents = 0;
998     }
999     if(block->block_contents)
1000     {
1001         free(block->block_contents);
1002         block->block_contents = 0;
1003     }
1004
1005     free(*block_p);
1006     *block_p = 0;
1007
1008     return(TNG_SUCCESS);
1009 }
1010
1011 /**
1012  * @brief Read the header of a data block, regardless of its type
1013  * @param tng_data is a trajectory data container.
1014  * @param block is a general block container.
1015  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor
1016  * error has occured (not able to read the header size, thus skipping
1017  * the block) or TNG_CRITICAL (2) if a major error has occured.
1018  */
1019 static tng_function_status tng_block_header_read
1020                 (const tng_trajectory_t tng_data, const tng_gen_block_t block)
1021 {
1022     int64_t start_pos;
1023
1024     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
1025
1026     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1027     {
1028         return(TNG_CRITICAL);
1029     }
1030
1031     start_pos = ftello(tng_data->input_file);
1032
1033     /* First read the header size to be able to read the whole header. */
1034     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
1035         1, tng_data->input_file) == 0)
1036     {
1037         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
1038                __FILE__, __LINE__);
1039         return(TNG_CRITICAL);
1040     }
1041
1042     if(block->header_contents_size == 0)
1043     {
1044         block->id = -1;
1045         return(TNG_FAILURE);
1046     }
1047
1048     /* If this was the size of the general info block check the endianness */
1049     if(ftello(tng_data->input_file) < 9)
1050     {
1051         /* File is little endian */
1052         if ( *((const char*)&block->header_contents_size) != 0x00 &&
1053              *((const char*)(&block->header_contents_size) + 7) == 0x00)
1054         {
1055             /* If the architecture endianness is little endian no byte swap
1056              * will be needed. Otherwise use the functions to swap to little
1057              * endian */
1058             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
1059             {
1060                 tng_data->input_endianness_swap_func_32 = 0;
1061             }
1062             else
1063             {
1064                 tng_data->input_endianness_swap_func_32 =
1065                 &tng_swap_byte_order_little_endian_32;
1066             }
1067             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
1068             {
1069                 tng_data->input_endianness_swap_func_64 = 0;
1070             }
1071             else
1072             {
1073                 tng_data->input_endianness_swap_func_64 =
1074                 &tng_swap_byte_order_little_endian_64;
1075             }
1076         }
1077         /* File is big endian */
1078         else
1079         {
1080             /* If the architecture endianness is big endian no byte swap
1081              * will be needed. Otherwise use the functions to swap to big
1082              * endian */
1083             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
1084             {
1085                 tng_data->input_endianness_swap_func_32 = 0;
1086             }
1087             else
1088             {
1089                 tng_data->input_endianness_swap_func_32 =
1090                 &tng_swap_byte_order_big_endian_32;
1091             }
1092             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
1093             {
1094                 tng_data->input_endianness_swap_func_64 = 0;
1095             }
1096             else
1097             {
1098                 tng_data->input_endianness_swap_func_64 =
1099                 &tng_swap_byte_order_big_endian_64;
1100             }
1101         }
1102     }
1103
1104     if(tng_data->input_endianness_swap_func_64 &&
1105        tng_data->input_endianness_swap_func_64(tng_data, &block->header_contents_size) != TNG_SUCCESS)
1106     {
1107         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1108                 __FILE__, __LINE__);
1109     }
1110
1111     if(tng_file_input_numerical(tng_data, &block->block_contents_size,
1112                                 sizeof(block->block_contents_size),
1113                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
1114     {
1115         return(TNG_CRITICAL);
1116     }
1117
1118     if(tng_file_input_numerical(tng_data, &block->id,
1119                                 sizeof(block->id),
1120                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
1121     {
1122         return(TNG_CRITICAL);
1123     }
1124
1125     if(fread(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->input_file) == 0)
1126     {
1127         fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n", __FILE__, __LINE__);
1128         return(TNG_CRITICAL);
1129     }
1130
1131     tng_freadstr(tng_data, &block->name, TNG_SKIP_HASH, 0, __LINE__);
1132
1133     if(tng_file_input_numerical(tng_data, &block->block_version,
1134                                 sizeof(block->block_version),
1135                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
1136     {
1137         return(TNG_CRITICAL);
1138     }
1139
1140     fseeko(tng_data->input_file, start_pos + block->header_contents_size, SEEK_SET);
1141
1142     return(TNG_SUCCESS);
1143 }
1144
1145 /**
1146  * @brief Write a whole block, both header and contents, regardless of it type
1147  * @param tng_data is a trajectory data container.
1148  * @param block is a general block container.
1149  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
1150  * has occurred or TNG_CRITICAL (2) if a major error has occured.
1151  */
1152 /* Disabled until it is used.*/
1153 /*
1154 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1155 //                                                     tng_gen_block_t block)
1156 // {
1157 //     if(!block->header_contents)
1158 //     {
1159 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1160 //         return(TNG_FAILURE);
1161 //     }
1162 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1163 //                 tng_data->output_file) != 1)
1164 //     {
1165 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1166 //                 __FILE__, __LINE__);
1167 //         return(TNG_CRITICAL);
1168 //     }
1169 //
1170 //     if(!block->block_contents)
1171 //     {
1172 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1173 //                 __FILE__, __LINE__);
1174 //         return(TNG_FAILURE);
1175 //     }
1176 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1177 //                 tng_data->output_file) != 1)
1178 //     {
1179 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1180 //                 __FILE__, __LINE__);
1181 //         return(TNG_CRITICAL);
1182 //     }
1183 //     return(TNG_SUCCESS);
1184 // }
1185 */
1186
1187 /**
1188  * @brief Update the md5 hash of a block already written to the file
1189  * @param tng_data is a trajectory data container.
1190  * @param block is the block, of which to update the md5 hash.
1191  * @param header_start_pos is the file position where the block header starts.
1192  * @param contents_start_pos is the file position where the block contents
1193  * start.
1194  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1195  * error has occured.
1196  */
1197 static tng_function_status tng_md5_hash_update(const tng_trajectory_t tng_data,
1198                                                const tng_gen_block_t block,
1199                                                const int64_t header_start_pos,
1200                                                const int64_t contents_start_pos)
1201 {
1202     if(block->block_contents)
1203     {
1204         free(block->block_contents);
1205     }
1206
1207     block->block_contents = malloc(block->block_contents_size);
1208     if(!block->block_contents)
1209     {
1210         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1211                block->block_contents_size, __FILE__, __LINE__);
1212         return(TNG_CRITICAL);
1213     }
1214
1215     fseeko(tng_data->output_file, contents_start_pos, SEEK_SET);
1216     if(fread(block->block_contents, block->block_contents_size, 1,
1217             tng_data->output_file) == 0)
1218     {
1219         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1220         return(TNG_CRITICAL);
1221     }
1222
1223     tng_block_md5_hash_generate(block);
1224
1225     fseeko(tng_data->output_file, header_start_pos + 3 * sizeof(int64_t),
1226           SEEK_SET);
1227     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
1228
1229     return(TNG_SUCCESS);
1230 }
1231
1232 /**
1233  * @brief Update the frame set pointers in the file header (general info block),
1234  * already written to disk
1235  * @param tng_data is a trajectory data container.
1236  * @param hash_mode specifies whether to update the block md5 hash when
1237  * updating the pointers.
1238  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1239  * error has occured.
1240  */
1241 static tng_function_status tng_header_pointers_update
1242                 (const tng_trajectory_t tng_data, const char hash_mode)
1243 {
1244     tng_gen_block_t block;
1245     FILE *temp = tng_data->input_file;
1246     int64_t output_file_pos, pos, contents_start_pos;
1247
1248     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1249     {
1250         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1251                __FILE__, __LINE__);
1252         return(TNG_CRITICAL);
1253     }
1254
1255     tng_data->input_file = tng_data->output_file;
1256
1257     tng_block_init(&block);
1258
1259     output_file_pos = ftello(tng_data->output_file);
1260     fseeko(tng_data->output_file, 0, SEEK_SET);
1261
1262     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1263     {
1264         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
1265                __FILE__, __LINE__);
1266         tng_data->input_file = temp;
1267         tng_block_destroy(&block);
1268         return(TNG_CRITICAL);
1269     }
1270
1271     contents_start_pos = ftello(tng_data->output_file);
1272
1273     fseeko(tng_data->output_file, block->block_contents_size - 5 *
1274            sizeof(int64_t), SEEK_CUR);
1275
1276     tng_data->input_file = temp;
1277
1278     pos = tng_data->first_trajectory_frame_set_output_file_pos;
1279
1280     if(tng_data->input_endianness_swap_func_64)
1281     {
1282         if(tng_data->input_endianness_swap_func_64(tng_data,
1283                                                     &pos)
1284             != TNG_SUCCESS)
1285         {
1286             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1287                     __FILE__, __LINE__);
1288         }
1289     }
1290
1291     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1292     {
1293         tng_block_destroy(&block);
1294         return(TNG_CRITICAL);
1295     }
1296
1297     pos = tng_data->last_trajectory_frame_set_output_file_pos;
1298
1299     if(tng_data->input_endianness_swap_func_64)
1300     {
1301         if(tng_data->input_endianness_swap_func_64(tng_data,
1302                                                     &pos)
1303             != TNG_SUCCESS)
1304         {
1305             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1306                     __FILE__, __LINE__);
1307         }
1308     }
1309
1310     if(fwrite(&pos,
1311         sizeof(int64_t), 1, tng_data->output_file) != 1)
1312     {
1313         tng_block_destroy(&block);
1314         return(TNG_CRITICAL);
1315     }
1316
1317     if(hash_mode == TNG_USE_HASH)
1318     {
1319         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
1320     }
1321
1322     tng_block_destroy(&block);
1323
1324     fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1325
1326     return(TNG_SUCCESS);
1327 }
1328
1329 /**
1330  * @brief Update the frame set pointers in the current frame set block, already
1331  * written to disk. It also updates the pointers of the blocks pointing to
1332  * the current frame set block.
1333  * @param tng_data is a trajectory data container.
1334  * @param hash_mode specifies whether to update the block md5 hash when
1335  * updating the pointers.
1336  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1337  * error has occured.
1338  */
1339 static tng_function_status tng_frame_set_pointers_update
1340                 (const tng_trajectory_t tng_data, const char hash_mode)
1341 {
1342     tng_gen_block_t block;
1343     tng_trajectory_frame_set_t frame_set;
1344     FILE *temp = tng_data->input_file;
1345     int64_t pos, output_file_pos, contents_start_pos;
1346
1347     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1348     {
1349         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1350                __FILE__, __LINE__);
1351         return(TNG_CRITICAL);
1352     }
1353
1354     tng_block_init(&block);
1355     output_file_pos = ftello(tng_data->output_file);
1356
1357     tng_data->input_file = tng_data->output_file;
1358
1359     frame_set = &tng_data->current_trajectory_frame_set;
1360
1361     pos = tng_data->current_trajectory_frame_set_output_file_pos;
1362
1363     /* Update next frame set */
1364     if(frame_set->next_frame_set_file_pos > 0)
1365     {
1366         fseeko(tng_data->output_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1367
1368         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1369         {
1370             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1371                 __FILE__, __LINE__);
1372             tng_data->input_file = temp;
1373             tng_block_destroy(&block);
1374             return(TNG_CRITICAL);
1375         }
1376
1377         contents_start_pos = ftello(tng_data->output_file);
1378
1379         fseeko(tng_data->output_file, block->block_contents_size - (5 *
1380                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1381
1382         if(tng_data->input_endianness_swap_func_64)
1383         {
1384             if(tng_data->input_endianness_swap_func_64(tng_data,
1385                                                         &pos)
1386                 != TNG_SUCCESS)
1387             {
1388                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1389                         __FILE__, __LINE__);
1390             }
1391         }
1392
1393         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1394         {
1395             tng_data->input_file = temp;
1396             tng_block_destroy(&block);
1397             return(TNG_CRITICAL);
1398         }
1399
1400         if(hash_mode == TNG_USE_HASH)
1401         {
1402             tng_md5_hash_update(tng_data, block, frame_set->next_frame_set_file_pos,
1403                                 contents_start_pos);
1404         }
1405     }
1406     /* Update previous frame set */
1407     if(frame_set->prev_frame_set_file_pos > 0)
1408     {
1409         fseeko(tng_data->output_file, frame_set->prev_frame_set_file_pos,
1410               SEEK_SET);
1411
1412         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1413         {
1414             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1415                 __FILE__, __LINE__);
1416             tng_data->input_file = temp;
1417             tng_block_destroy(&block);
1418             return(TNG_CRITICAL);
1419         }
1420
1421         contents_start_pos = ftello(tng_data->output_file);
1422
1423         fseeko(tng_data->output_file, block->block_contents_size - (6 *
1424                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1425
1426         if(tng_data->input_endianness_swap_func_64)
1427         {
1428             if(tng_data->input_endianness_swap_func_64(tng_data,
1429                                                         &pos)
1430                 != TNG_SUCCESS)
1431             {
1432                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1433                         __FILE__, __LINE__);
1434             }
1435         }
1436
1437         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1438         {
1439             tng_data->input_file = temp;
1440             tng_block_destroy(&block);
1441             return(TNG_CRITICAL);
1442         }
1443
1444         if(hash_mode == TNG_USE_HASH)
1445         {
1446             tng_md5_hash_update(tng_data, block, frame_set->prev_frame_set_file_pos,
1447                                 contents_start_pos);
1448         }
1449     }
1450
1451     /* Update the frame set one medium stride step after */
1452     if(frame_set->medium_stride_next_frame_set_file_pos > 0)
1453     {
1454         fseeko(tng_data->output_file,
1455               frame_set->medium_stride_next_frame_set_file_pos,
1456               SEEK_SET);
1457
1458         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1459         {
1460             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1461                 __FILE__, __LINE__);
1462             tng_data->input_file = temp;
1463             tng_block_destroy(&block);
1464             return(TNG_CRITICAL);
1465         }
1466
1467         contents_start_pos = ftello(tng_data->output_file);
1468
1469         fseeko(tng_data->output_file, block->block_contents_size - (3 *
1470                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1471
1472         if(tng_data->input_endianness_swap_func_64)
1473         {
1474             if(tng_data->input_endianness_swap_func_64(tng_data,
1475                                                         &pos)
1476                 != TNG_SUCCESS)
1477             {
1478                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1479                         __FILE__, __LINE__);
1480             }
1481         }
1482
1483         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1484         {
1485             tng_data->input_file = temp;
1486             tng_block_destroy(&block);
1487             return(TNG_CRITICAL);
1488         }
1489
1490         if(hash_mode == TNG_USE_HASH)
1491         {
1492             tng_md5_hash_update(tng_data, block,
1493                                 frame_set->medium_stride_next_frame_set_file_pos,
1494                                 contents_start_pos);
1495         }
1496     }
1497     /* Update the frame set one medium stride step before */
1498     if(frame_set->medium_stride_prev_frame_set_file_pos > 0)
1499     {
1500         fseeko(tng_data->output_file,
1501                frame_set->medium_stride_prev_frame_set_file_pos,
1502                SEEK_SET);
1503
1504         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1505         {
1506             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1507                 __FILE__, __LINE__);
1508             tng_data->input_file = temp;
1509             tng_block_destroy(&block);
1510             return(TNG_CRITICAL);
1511         }
1512
1513         contents_start_pos = ftello(tng_data->output_file);
1514
1515         fseeko(tng_data->output_file, block->block_contents_size - (4 *
1516                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1517
1518         if(tng_data->input_endianness_swap_func_64)
1519         {
1520             if(tng_data->input_endianness_swap_func_64(tng_data,
1521                                                         &pos)
1522                 != TNG_SUCCESS)
1523             {
1524                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1525                         __FILE__, __LINE__);
1526             }
1527         }
1528
1529         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1530         {
1531             tng_data->input_file = temp;
1532             tng_block_destroy(&block);
1533             return(TNG_CRITICAL);
1534         }
1535
1536         if(hash_mode == TNG_USE_HASH)
1537         {
1538             tng_md5_hash_update(tng_data, block,
1539                                 frame_set->medium_stride_prev_frame_set_file_pos,
1540                                 contents_start_pos);
1541         }
1542     }
1543
1544     /* Update the frame set one long stride step after */
1545     if(frame_set->long_stride_next_frame_set_file_pos > 0)
1546     {
1547         fseeko(tng_data->output_file,
1548                frame_set->long_stride_next_frame_set_file_pos,
1549                SEEK_SET);
1550
1551         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1552         {
1553             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1554                 __FILE__, __LINE__);
1555             tng_data->input_file = temp;
1556             tng_block_destroy(&block);
1557             return(TNG_CRITICAL);
1558         }
1559
1560         contents_start_pos = ftello(tng_data->output_file);
1561
1562         fseeko(tng_data->output_file, block->block_contents_size - (1 *
1563                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1564
1565         if(tng_data->input_endianness_swap_func_64)
1566         {
1567             if(tng_data->input_endianness_swap_func_64(tng_data,
1568                                                         &pos)
1569                 != TNG_SUCCESS)
1570             {
1571                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1572                         __FILE__, __LINE__);
1573             }
1574         }
1575
1576         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1577         {
1578             tng_data->input_file = temp;
1579             tng_block_destroy(&block);
1580             return(TNG_CRITICAL);
1581         }
1582
1583         if(hash_mode == TNG_USE_HASH)
1584         {
1585             tng_md5_hash_update(tng_data, block,
1586                                 frame_set->long_stride_next_frame_set_file_pos,
1587                                 contents_start_pos);
1588         }
1589     }
1590     /* Update the frame set one long stride step before */
1591     if(frame_set->long_stride_prev_frame_set_file_pos > 0)
1592     {
1593         fseeko(tng_data->output_file,
1594                frame_set->long_stride_prev_frame_set_file_pos,
1595                SEEK_SET);
1596
1597         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1598         {
1599             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1600                 __FILE__, __LINE__);
1601             tng_data->input_file = temp;
1602             tng_block_destroy(&block);
1603             return(TNG_CRITICAL);
1604         }
1605
1606         contents_start_pos = ftello(tng_data->output_file);
1607
1608         fseeko(tng_data->output_file, block->block_contents_size - (2 *
1609                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1610
1611         if(tng_data->input_endianness_swap_func_64)
1612         {
1613             if(tng_data->input_endianness_swap_func_64(tng_data,
1614                                                         &pos)
1615                 != TNG_SUCCESS)
1616             {
1617                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1618                         __FILE__, __LINE__);
1619             }
1620         }
1621
1622         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1623         {
1624             tng_data->input_file = temp;
1625             tng_block_destroy(&block);
1626             return(TNG_CRITICAL);
1627         }
1628
1629         if(hash_mode == TNG_USE_HASH)
1630         {
1631             tng_md5_hash_update(tng_data, block,
1632                                 frame_set->long_stride_prev_frame_set_file_pos,
1633                                 contents_start_pos);
1634         }
1635     }
1636
1637     fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1638
1639     tng_data->input_file = temp;
1640
1641     tng_block_destroy(&block);
1642
1643     return(TNG_SUCCESS);
1644 }
1645
1646 static tng_function_status tng_reread_frame_set_at_file_pos
1647                 (const tng_trajectory_t tng_data,
1648                  const int64_t pos)
1649 {
1650     tng_gen_block_t block;
1651     tng_function_status stat;
1652
1653     tng_block_init(&block);
1654
1655     fseeko(tng_data->input_file, pos, SEEK_SET);
1656     if(pos > 0)
1657     {
1658         stat = tng_block_header_read(tng_data, block);
1659         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1660         {
1661             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
1662                     __FILE__, __LINE__);
1663             tng_block_destroy(&block);
1664             return(TNG_FAILURE);
1665         }
1666
1667         if(tng_block_read_next(tng_data, block,
1668                                TNG_SKIP_HASH) != TNG_SUCCESS)
1669         {
1670             tng_block_destroy(&block);
1671             return(TNG_CRITICAL);
1672         }
1673     }
1674
1675     tng_block_destroy(&block);
1676
1677     return(TNG_SUCCESS);
1678 }
1679
1680 static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
1681                 (const tng_trajectory_t tng_data,
1682                  int64_t *pos)
1683 {
1684     int64_t orig_pos, curr_frame_set_pos;
1685     tng_gen_block_t block;
1686     tng_function_status stat;
1687     tng_trajectory_frame_set_t frame_set =
1688     &tng_data->current_trajectory_frame_set;
1689
1690     orig_pos = ftello(tng_data->input_file);
1691     curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos;
1692
1693     *pos = tng_data->first_trajectory_frame_set_input_file_pos;
1694
1695     if(*pos <= 0)
1696     {
1697         return(TNG_SUCCESS);
1698     }
1699
1700     fseeko(tng_data->input_file, *pos, SEEK_SET);
1701
1702     tng_block_init(&block);
1703     /* Read block headers first to see that a frame set block is found. */
1704     stat = tng_block_header_read(tng_data, block);
1705     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1706     {
1707         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1708                 __FILE__, __LINE__);
1709         tng_block_destroy(&block);
1710         return(TNG_FAILURE);
1711     }
1712
1713     if(tng_block_read_next(tng_data, block,
1714                            TNG_SKIP_HASH) != TNG_SUCCESS)
1715     {
1716         tng_block_destroy(&block);
1717         return(TNG_CRITICAL);
1718     }
1719
1720     /* Read all frame set blocks (not the blocks between them) */
1721     while(frame_set->next_frame_set_file_pos > 0)
1722     {
1723         fseeko(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1724         stat = tng_block_header_read(tng_data, block);
1725         if(stat == TNG_CRITICAL)
1726         {
1727             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1728                     __FILE__, __LINE__);
1729             tng_block_destroy(&block);
1730             return(TNG_CRITICAL);
1731         }
1732         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1733         {
1734             return(TNG_FAILURE);
1735         }
1736
1737         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
1738         if(stat != TNG_SUCCESS)
1739         {
1740             tng_block_destroy(&block);
1741             return(stat);
1742         }
1743         /* Update *pos if this is the earliest frame set so far (after orig_pos) */
1744         if(tng_data->current_trajectory_frame_set_input_file_pos < *pos &&
1745            tng_data->current_trajectory_frame_set_input_file_pos > orig_pos)
1746         {
1747             *pos = tng_data->current_trajectory_frame_set_input_file_pos;
1748         }
1749     }
1750
1751     /* Re-read the frame set that used to be the current one */
1752     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1753
1754     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1755
1756     tng_block_destroy(&block);
1757
1758     return(TNG_SUCCESS);
1759 }
1760
1761 /**
1762  * @brief Migrate a whole frame set from one position in the file to another.
1763  * @param tng_data is a trajectory data container.
1764  * @param block_start_pos is the starting position in the file of the frame set.
1765  * @param block_len is the length of the whole frame set (including all data blocks etc).
1766  * @param new_pos is the new position in the file of the frame set.
1767  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
1768  */
1769 static tng_function_status tng_frame_set_complete_migrate
1770                 (const tng_trajectory_t tng_data,
1771                  const int64_t block_start_pos,
1772                  const int64_t block_len,
1773                  const int64_t new_pos,
1774                  const char hash_mode)
1775 {
1776     tng_bool updated = TNG_FALSE;
1777
1778     char *contents;
1779
1780     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1781     {
1782         return(TNG_CRITICAL);
1783     }
1784
1785     fseeko(tng_data->input_file, block_start_pos, SEEK_SET);
1786
1787     contents = malloc(block_len);
1788     if(!contents)
1789     {
1790         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1791                 block_len, __FILE__, __LINE__);
1792         return(TNG_CRITICAL);
1793     }
1794
1795     if(fread(contents, block_len, 1, tng_data->input_file) == 0)
1796     {
1797         fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n",
1798                __FILE__, __LINE__);
1799         free(contents);
1800         return(TNG_CRITICAL);
1801     }
1802     fseeko(tng_data->output_file, new_pos, SEEK_SET);
1803
1804     if(fwrite(contents, block_len, 1, tng_data->output_file) != 1)
1805     {
1806         fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n",
1807                 __FILE__, __LINE__);
1808         free(contents);
1809         return(TNG_CRITICAL);
1810     }
1811
1812     tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
1813
1814     tng_frame_set_pointers_update(tng_data, hash_mode);
1815
1816     /* Update the general info block if needed */
1817     if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos)
1818     {
1819         tng_data->first_trajectory_frame_set_output_file_pos = new_pos;
1820         updated = TNG_TRUE;
1821     }
1822     if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos)
1823     {
1824         tng_data->last_trajectory_frame_set_output_file_pos = new_pos;
1825         updated = TNG_TRUE;
1826     }
1827     if(updated)
1828     {
1829         tng_header_pointers_update(tng_data, hash_mode);
1830     }
1831
1832     /* Fill the block with NULL to avoid confusion. */
1833     memset(contents, '\0', block_len);
1834     fseeko(tng_data->output_file, block_start_pos, SEEK_SET);
1835
1836     /* FIXME: casting block_len to size_t is dangerous */
1837     fwrite(contents, 1, block_len, tng_data->output_file);
1838
1839     free(contents);
1840
1841     return(TNG_SUCCESS);
1842 }
1843
1844 static tng_function_status tng_length_of_current_frame_set_contents_get
1845                 (const tng_trajectory_t tng_data,
1846                  int64_t *len)
1847 {
1848     int64_t orig_pos, pos, curr_frame_set_pos;
1849     tng_gen_block_t block;
1850     tng_function_status stat;
1851
1852     orig_pos = ftello(tng_data->input_file);
1853     curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos;
1854
1855     *len = 0;
1856
1857     fseeko(tng_data->input_file, curr_frame_set_pos, SEEK_SET);
1858
1859     tng_block_init(&block);
1860     /* Read block headers first to see that a frame set block is found. */
1861     stat = tng_block_header_read(tng_data, block);
1862     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1863     {
1864         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
1865                 curr_frame_set_pos, __FILE__, __LINE__);
1866         tng_block_destroy(&block);
1867         return(TNG_FAILURE);
1868     }
1869
1870     /* Read the headers of all blocks in the frame set (not the actual contents of them) */
1871     while(stat == TNG_SUCCESS)
1872     {
1873         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
1874         *len += block->header_contents_size + block->block_contents_size;
1875         pos += block->header_contents_size + block->block_contents_size;
1876         if(pos >= tng_data->input_file_len)
1877         {
1878             break;
1879         }
1880         stat = tng_block_header_read(tng_data, block);
1881         if(block->id == TNG_TRAJECTORY_FRAME_SET)
1882         {
1883             break;
1884         }
1885     }
1886
1887     /* Re-read the frame set that used to be the current one */
1888     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1889
1890     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1891
1892     tng_block_destroy(&block);
1893
1894     return(TNG_SUCCESS);
1895 }
1896
1897 /**
1898  * @brief Migrate blocks in the file to make room for new data in a block. This
1899  * is required e.g. when adding data to a block or extending strings in a
1900  * block.
1901  * @param tng_data is a trajectory data container.
1902  * @param start_pos is the position from which to start moving data, usually
1903  * the byte after the end of the block to which data was added.
1904  * @param offset is the number of bytes that were inserted.
1905  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
1906  * @details Trajectory blocks (frame sets and their related blocks) are moved
1907  * to the end of the file (if needed) in order to make room for non-trajectory
1908  * data.
1909  */
1910 static tng_function_status tng_migrate_data_in_file
1911                 (const tng_trajectory_t tng_data,
1912                  const int64_t start_pos,
1913                  const int64_t offset,
1914                  const char hash_mode)
1915 {
1916     int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length;
1917     tng_gen_block_t block;
1918     tng_function_status stat;
1919
1920     if(offset <= 0)
1921     {
1922         return(TNG_SUCCESS);
1923     }
1924
1925     stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos);
1926     if(stat != TNG_SUCCESS)
1927     {
1928         return(stat);
1929     }
1930
1931     tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos;
1932
1933     empty_space = traj_start_pos - (start_pos - 1);
1934
1935     if(empty_space >= offset)
1936     {
1937         return(TNG_SUCCESS);
1938     }
1939
1940     orig_file_pos = ftello(tng_data->input_file);
1941     tng_block_init(&block);
1942
1943     while(empty_space < offset)
1944     {
1945         fseeko(tng_data->input_file, traj_start_pos, SEEK_SET);
1946         stat = tng_block_header_read(tng_data, block);
1947         if(stat == TNG_CRITICAL)
1948         {
1949             fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
1950                     __FILE__, __LINE__);
1951             tng_block_destroy(&block);
1952             return(TNG_CRITICAL);
1953         }
1954         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1955         {
1956             tng_block_destroy(&block);
1957             return(TNG_FAILURE);
1958         }
1959         stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length);
1960         if(stat != TNG_SUCCESS)
1961         {
1962             tng_block_destroy(&block);
1963             return(stat);
1964         }
1965         stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos,
1966                                               frame_set_length, tng_data->input_file_len,
1967                                               hash_mode);
1968         if(stat != TNG_SUCCESS)
1969         {
1970             tng_block_destroy(&block);
1971             return(stat);
1972         }
1973
1974         empty_space += frame_set_length;
1975     }
1976     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
1977     tng_block_destroy(&block);
1978
1979     return(TNG_SUCCESS);
1980 }
1981
1982 static tng_function_status tng_block_header_len_calculate
1983                 (const tng_trajectory_t tng_data,
1984                  const tng_gen_block_t block,
1985                  int64_t *len)
1986 {
1987     int name_len;
1988     (void)tng_data;
1989
1990     /* If the string is unallocated allocate memory for just string
1991      * termination */
1992     if(!block->name)
1993     {
1994         block->name = malloc(1);
1995         if(!block->name)
1996         {
1997             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1998                    __FILE__, __LINE__);
1999             return(TNG_CRITICAL);
2000         }
2001         block->name[0] = 0;
2002     }
2003
2004     name_len = tng_min_size(strlen(block->name) + 1, TNG_MAX_STR_LEN);
2005
2006     /* Calculate the size of the header to write */
2007     *len = sizeof(block->header_contents_size) +
2008                   sizeof(block->block_contents_size) +
2009                   sizeof(block->id) +
2010                   sizeof(block->block_version) +
2011                   TNG_MD5_HASH_LEN +
2012                   name_len;
2013
2014     return (TNG_SUCCESS);
2015 }
2016
2017 /**
2018  * @brief Write the header of a data block, regardless of its type
2019  * @param tng_data is a trajectory data container.
2020  * @param block is a general block container.
2021  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2022  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2023  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2024  * error has occured.
2025  */
2026 static tng_function_status tng_block_header_write
2027                 (const tng_trajectory_t tng_data,
2028                  const tng_gen_block_t block)
2029 {
2030     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
2031
2032     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2033     {
2034         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
2035                __FILE__, __LINE__);
2036         return(TNG_CRITICAL);
2037     }
2038
2039     if(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) !=
2040         TNG_SUCCESS)
2041     {
2042         fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n",
2043                 __FILE__, __LINE__);
2044         return(TNG_CRITICAL);
2045     }
2046
2047     if(tng_file_output_numerical(tng_data, &block->header_contents_size,
2048                                  sizeof(block->header_contents_size),
2049                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2050     {
2051         return(TNG_CRITICAL);
2052     }
2053
2054     if(tng_file_output_numerical(tng_data, &block->block_contents_size,
2055                                  sizeof(block->block_contents_size),
2056                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2057     {
2058         return(TNG_CRITICAL);
2059     }
2060
2061     if(tng_file_output_numerical(tng_data, &block->id,
2062                                  sizeof(block->id),
2063                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2064     {
2065         return(TNG_CRITICAL);
2066     }
2067
2068     if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
2069     {
2070         fprintf(stderr, "TNG library: Could not write header data. %s: %d\n", __FILE__, __LINE__);
2071         return(TNG_CRITICAL);
2072     }
2073
2074     if(tng_fwritestr(tng_data, block->name, TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2075     {
2076         return(TNG_CRITICAL);
2077     }
2078
2079     if(tng_file_output_numerical(tng_data, &block->block_version,
2080                                  sizeof(block->block_version),
2081                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2082     {
2083         return(TNG_CRITICAL);
2084     }
2085
2086     return(TNG_SUCCESS);
2087 }
2088
2089 static tng_function_status tng_general_info_block_len_calculate
2090                 (const tng_trajectory_t tng_data,
2091                  int64_t *len)
2092 {
2093     size_t first_program_name_len, first_user_name_len;
2094     size_t first_computer_name_len, first_pgp_signature_len;
2095     size_t last_program_name_len, last_user_name_len;
2096     size_t last_computer_name_len, last_pgp_signature_len;
2097     size_t forcefield_name_len;
2098
2099     /* If the strings are unallocated allocate memory for just string
2100      * termination */
2101     if(!tng_data->first_program_name)
2102     {
2103         tng_data->first_program_name = malloc(1);
2104         if(!tng_data->first_program_name)
2105         {
2106             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2107                    __FILE__, __LINE__);
2108             return(TNG_CRITICAL);
2109         }
2110         tng_data->first_program_name[0] = 0;
2111     }
2112     if(!tng_data->last_program_name)
2113     {
2114         tng_data->last_program_name = malloc(1);
2115         if(!tng_data->last_program_name)
2116         {
2117             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2118                    __FILE__, __LINE__);
2119             return(TNG_CRITICAL);
2120         }
2121         tng_data->last_program_name[0] = 0;
2122     }
2123     if(!tng_data->first_user_name)
2124     {
2125         tng_data->first_user_name = malloc(1);
2126         if(!tng_data->first_user_name)
2127         {
2128             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2129                    __FILE__, __LINE__);
2130             return(TNG_CRITICAL);
2131         }
2132         tng_data->first_user_name[0] = 0;
2133     }
2134     if(!tng_data->last_user_name)
2135     {
2136         tng_data->last_user_name = malloc(1);
2137         if(!tng_data->last_user_name)
2138         {
2139             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2140                    __FILE__, __LINE__);
2141             return(TNG_CRITICAL);
2142         }
2143         tng_data->last_user_name[0] = 0;
2144     }
2145     if(!tng_data->first_computer_name)
2146     {
2147         tng_data->first_computer_name = malloc(1);
2148         if(!tng_data->first_computer_name)
2149         {
2150             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2151                    __FILE__, __LINE__);
2152             return(TNG_CRITICAL);
2153         }
2154         tng_data->first_computer_name[0] = 0;
2155     }
2156     if(!tng_data->last_computer_name)
2157     {
2158         tng_data->last_computer_name = malloc(1);
2159         if(!tng_data->last_computer_name)
2160         {
2161             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2162                    __FILE__, __LINE__);
2163             return(TNG_CRITICAL);
2164         }
2165         tng_data->last_computer_name[0] = 0;
2166     }
2167     if(!tng_data->first_pgp_signature)
2168     {
2169         tng_data->first_pgp_signature = malloc(1);
2170         if(!tng_data->first_pgp_signature)
2171         {
2172             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2173                    __FILE__, __LINE__);
2174             return(TNG_CRITICAL);
2175         }
2176         tng_data->first_pgp_signature[0] = 0;
2177     }
2178     if(!tng_data->last_pgp_signature)
2179     {
2180         tng_data->last_pgp_signature = malloc(1);
2181         if(!tng_data->last_pgp_signature)
2182         {
2183             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2184                    __FILE__, __LINE__);
2185             return(TNG_CRITICAL);
2186         }
2187         tng_data->last_pgp_signature[0] = 0;
2188     }
2189     if(!tng_data->forcefield_name)
2190     {
2191         tng_data->forcefield_name = malloc(1);
2192         if(!tng_data->forcefield_name)
2193         {
2194             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2195                    __FILE__, __LINE__);
2196             return(TNG_CRITICAL);
2197         }
2198         tng_data->forcefield_name[0] = 0;
2199     }
2200
2201     first_program_name_len = tng_min_size(strlen(tng_data->first_program_name) + 1,
2202                            TNG_MAX_STR_LEN);
2203     last_program_name_len = tng_min_size(strlen(tng_data->last_program_name) + 1,
2204                            TNG_MAX_STR_LEN);
2205     first_user_name_len = tng_min_size(strlen(tng_data->first_user_name) + 1,
2206                         TNG_MAX_STR_LEN);
2207     last_user_name_len = tng_min_size(strlen(tng_data->last_user_name) + 1,
2208                         TNG_MAX_STR_LEN);
2209     first_computer_name_len = tng_min_size(strlen(tng_data->first_computer_name) + 1,
2210                             TNG_MAX_STR_LEN);
2211     last_computer_name_len = tng_min_size(strlen(tng_data->last_computer_name) + 1,
2212                             TNG_MAX_STR_LEN);
2213     first_pgp_signature_len = tng_min_size(strlen(tng_data->first_pgp_signature) + 1,
2214                             TNG_MAX_STR_LEN);
2215     last_pgp_signature_len = tng_min_size(strlen(tng_data->last_pgp_signature) + 1,
2216                             TNG_MAX_STR_LEN);
2217     forcefield_name_len = tng_min_size(strlen(tng_data->forcefield_name) + 1,
2218                               TNG_MAX_STR_LEN);
2219
2220     *len = sizeof(tng_data->time) +
2221                   sizeof(tng_data->var_num_atoms_flag) +
2222                   sizeof(tng_data->frame_set_n_frames) +
2223                   sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
2224                   sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
2225                   sizeof(tng_data->medium_stride_length) +
2226                   sizeof(tng_data->long_stride_length) +
2227                   sizeof(tng_data->distance_unit_exponential) +
2228                   first_program_name_len +
2229                   last_program_name_len +
2230                   first_user_name_len +
2231                   last_user_name_len +
2232                   first_computer_name_len +
2233                   last_computer_name_len +
2234                   first_pgp_signature_len +
2235                   last_pgp_signature_len +
2236                   forcefield_name_len;
2237
2238     return(TNG_SUCCESS);
2239 }
2240
2241 /**
2242  * @brief Read a general info block. This is the first block of a TNG file.
2243  * Populate the fields in tng_data.
2244  * @param tng_data is a trajectory data container.
2245  * @param block is a general block container.
2246  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2247  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2248  * compared to the md5 hash of the read contents to ensure valid data.
2249  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2250  * error has occured.
2251  */
2252 static tng_function_status tng_general_info_block_read
2253                 (const tng_trajectory_t tng_data,
2254                  const tng_gen_block_t block,
2255                  const char hash_mode)
2256 {
2257     int64_t start_pos;
2258     char hash[TNG_MD5_HASH_LEN];
2259     md5_state_t md5_state;
2260
2261     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
2262
2263     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2264     {
2265         return(TNG_CRITICAL);
2266     }
2267
2268     start_pos = ftello(tng_data->input_file);
2269
2270     if(hash_mode == TNG_USE_HASH)
2271     {
2272         md5_init(&md5_state);
2273     }
2274
2275     tng_freadstr(tng_data, &tng_data->first_program_name, hash_mode, &md5_state, __LINE__);
2276
2277     tng_freadstr(tng_data, &tng_data->last_program_name, hash_mode, &md5_state, __LINE__);
2278
2279     tng_freadstr(tng_data, &tng_data->first_user_name, hash_mode, &md5_state, __LINE__);
2280
2281     tng_freadstr(tng_data, &tng_data->last_user_name, hash_mode, &md5_state, __LINE__);
2282
2283     tng_freadstr(tng_data, &tng_data->first_computer_name, hash_mode, &md5_state, __LINE__);
2284
2285     tng_freadstr(tng_data, &tng_data->last_computer_name, hash_mode, &md5_state, __LINE__);
2286
2287     tng_freadstr(tng_data, &tng_data->first_pgp_signature, hash_mode, &md5_state, __LINE__);
2288
2289     tng_freadstr(tng_data, &tng_data->last_pgp_signature, hash_mode, &md5_state, __LINE__);
2290
2291     tng_freadstr(tng_data, &tng_data->forcefield_name, hash_mode, &md5_state, __LINE__);
2292
2293     if(tng_file_input_numerical(tng_data, &tng_data->time, sizeof(tng_data->time),
2294                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2295     {
2296         return(TNG_CRITICAL);
2297     }
2298
2299
2300     if(tng_file_input_numerical(tng_data, &tng_data->var_num_atoms_flag,
2301                                 sizeof(tng_data->var_num_atoms_flag),
2302                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2303     {
2304         return(TNG_CRITICAL);
2305     }
2306
2307     if(tng_file_input_numerical(tng_data, &tng_data->frame_set_n_frames,
2308                                 sizeof(tng_data->frame_set_n_frames),
2309                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2310     {
2311         return(TNG_CRITICAL);
2312     }
2313
2314     if(tng_file_input_numerical(tng_data,
2315                                 &tng_data->first_trajectory_frame_set_input_file_pos,
2316                                 sizeof(tng_data->first_trajectory_frame_set_input_file_pos),
2317                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2318     {
2319         return(TNG_CRITICAL);
2320     }
2321
2322     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
2323     tng_data->first_trajectory_frame_set_input_file_pos;
2324
2325     if(tng_file_input_numerical(tng_data,
2326                                 &tng_data->last_trajectory_frame_set_input_file_pos,
2327                                 sizeof(tng_data->last_trajectory_frame_set_input_file_pos),
2328                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2329     {
2330         return(TNG_CRITICAL);
2331     }
2332
2333     if(tng_file_input_numerical(tng_data,
2334                                 &tng_data->medium_stride_length,
2335                                 sizeof(tng_data->medium_stride_length),
2336                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2337     {
2338         return(TNG_CRITICAL);
2339     }
2340
2341     if(tng_file_input_numerical(tng_data,
2342                                 &tng_data->long_stride_length,
2343                                 sizeof(tng_data->long_stride_length),
2344                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2345     {
2346         return(TNG_CRITICAL);
2347     }
2348
2349     if(block->block_version >= 3)
2350     {
2351         if(tng_file_input_numerical(tng_data,
2352                                     &tng_data->distance_unit_exponential,
2353                                     sizeof(tng_data->distance_unit_exponential),
2354                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2355         {
2356             return(TNG_CRITICAL);
2357         }
2358     }
2359
2360     if(hash_mode == TNG_USE_HASH)
2361     {
2362         /* If there is data left in the block that the current version of the library
2363          * cannot interpret still read that to generate the MD5 hash. */
2364         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
2365
2366         md5_finish(&md5_state, (md5_byte_t *)hash);
2367         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)
2368         {
2369             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
2370             {
2371                 fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
2372                         "%s: %d\n", __FILE__, __LINE__);
2373             }
2374         }
2375     }
2376     else
2377     {
2378         /* Seek to the end of the block */
2379         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
2380     }
2381
2382     return(TNG_SUCCESS);
2383 }
2384
2385 /**
2386  * @brief Write a general info block. This is the first block of a TNG file.
2387  * @param tng_data is a trajectory data container.
2388  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2389  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2390  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2391  * error has occured.
2392  */
2393 static tng_function_status tng_general_info_block_write
2394                 (const tng_trajectory_t tng_data,
2395                  const char hash_mode)
2396 {
2397     int64_t header_file_pos, curr_file_pos;
2398     size_t name_len;
2399     tng_gen_block_t block;
2400     md5_state_t md5_state;
2401
2402     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2403     {
2404         return(TNG_CRITICAL);
2405     }
2406
2407     fseeko(tng_data->output_file, 0, SEEK_SET);
2408
2409     tng_block_init(&block);
2410
2411     name_len = strlen("GENERAL INFO");
2412
2413     block->name = malloc(name_len + 1);
2414     if(!block->name)
2415     {
2416         fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
2417                 (unsigned int)(name_len+1), __FILE__, __LINE__);
2418         tng_block_destroy(&block);
2419         return(TNG_CRITICAL);
2420     }
2421
2422     strcpy(block->name, "GENERAL INFO");
2423     block->id = TNG_GENERAL_INFO;
2424
2425     if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) !=
2426         TNG_SUCCESS)
2427     {
2428         fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n",
2429                 __FILE__, __LINE__);
2430         tng_block_destroy(&block);
2431         return(TNG_CRITICAL);
2432     }
2433
2434     header_file_pos = 0;
2435
2436     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
2437     {
2438         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2439                tng_data->output_file_path, __FILE__, __LINE__);
2440         tng_block_destroy(&block);
2441         return(TNG_CRITICAL);
2442     }
2443
2444     if(hash_mode == TNG_USE_HASH)
2445     {
2446         md5_init(&md5_state);
2447     }
2448
2449     if(tng_fwritestr(tng_data, tng_data->first_program_name,
2450                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2451     {
2452         return(TNG_CRITICAL);
2453     }
2454
2455     if(tng_fwritestr(tng_data, tng_data->last_program_name,
2456                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2457     {
2458         return(TNG_CRITICAL);
2459     }
2460
2461     if(tng_fwritestr(tng_data, tng_data->first_user_name,
2462                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2463     {
2464         return(TNG_CRITICAL);
2465     }
2466
2467     if(tng_fwritestr(tng_data, tng_data->last_user_name,
2468                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2469     {
2470         return(TNG_CRITICAL);
2471     }
2472
2473     if(tng_fwritestr(tng_data, tng_data->first_computer_name,
2474                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2475     {
2476         return(TNG_CRITICAL);
2477     }
2478
2479     if(tng_fwritestr(tng_data, tng_data->last_computer_name,
2480                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2481     {
2482         return(TNG_CRITICAL);
2483     }
2484
2485     if(tng_fwritestr(tng_data, tng_data->first_pgp_signature,
2486                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2487     {
2488         return(TNG_CRITICAL);
2489     }
2490
2491     if(tng_fwritestr(tng_data, tng_data->last_pgp_signature,
2492                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2493     {
2494         return(TNG_CRITICAL);
2495     }
2496
2497     if(tng_fwritestr(tng_data, tng_data->forcefield_name,
2498                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2499     {
2500         return(TNG_CRITICAL);
2501     }
2502
2503
2504     if(tng_file_output_numerical(tng_data, &tng_data->time, sizeof(tng_data->time),
2505                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2506     {
2507         return(TNG_CRITICAL);
2508     }
2509
2510     if(tng_file_output_numerical(tng_data, &tng_data->var_num_atoms_flag,
2511                                  sizeof(tng_data->var_num_atoms_flag),
2512                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2513     {
2514         return(TNG_CRITICAL);
2515     }
2516
2517     if(tng_file_output_numerical(tng_data, &tng_data->frame_set_n_frames,
2518                                  sizeof(tng_data->frame_set_n_frames),
2519                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2520     {
2521         return(TNG_CRITICAL);
2522     }
2523
2524     if(tng_file_output_numerical(tng_data, &tng_data->first_trajectory_frame_set_output_file_pos,
2525                                  sizeof(tng_data->first_trajectory_frame_set_output_file_pos),
2526                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2527     {
2528         return(TNG_CRITICAL);
2529     }
2530
2531     if(tng_file_output_numerical(tng_data, &tng_data->last_trajectory_frame_set_output_file_pos,
2532                                  sizeof(tng_data->last_trajectory_frame_set_output_file_pos),
2533                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2534     {
2535         return(TNG_CRITICAL);
2536     }
2537
2538     if(tng_file_output_numerical(tng_data, &tng_data->medium_stride_length,
2539                                  sizeof(tng_data->medium_stride_length),
2540                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2541     {
2542         return(TNG_CRITICAL);
2543     }
2544
2545     if(tng_file_output_numerical(tng_data, &tng_data->long_stride_length,
2546                                  sizeof(tng_data->long_stride_length),
2547                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2548     {
2549         return(TNG_CRITICAL);
2550     }
2551
2552     if(tng_file_output_numerical(tng_data, &tng_data->distance_unit_exponential,
2553                                  sizeof(tng_data->distance_unit_exponential),
2554                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2555     {
2556         return(TNG_CRITICAL);
2557     }
2558     if(hash_mode == TNG_USE_HASH)
2559     {
2560         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
2561         curr_file_pos = ftello(tng_data->output_file);
2562         fseeko(tng_data->output_file, header_file_pos +
2563                3 * sizeof(int64_t), SEEK_SET);
2564         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
2565         {
2566             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
2567                     __LINE__);
2568             return(TNG_CRITICAL);
2569         }
2570         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
2571     }
2572
2573     tng_block_destroy(&block);
2574
2575     return(TNG_SUCCESS);
2576 }
2577
2578 /**
2579  * @brief Read the chain data of a molecules block.
2580  * @param tng_data is a trajectory data container.
2581  * @param chain is the chain data container.
2582  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2583  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2584  * if hash_mode == TNG_USE_HASH.
2585  * @return TNG_SUCCESS(0) is successful.
2586  */
2587 static tng_function_status tng_chain_data_read(const tng_trajectory_t tng_data,
2588                                                const tng_chain_t chain,
2589                                                const char hash_mode,
2590                                                md5_state_t *md5_state)
2591 {
2592     if(tng_file_input_numerical(tng_data, &chain->id,
2593                                 sizeof(chain->id),
2594                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2595     {
2596         return(TNG_CRITICAL);
2597     }
2598
2599     tng_freadstr(tng_data, &chain->name, hash_mode, md5_state, __LINE__);
2600
2601     if(tng_file_input_numerical(tng_data, &chain->n_residues,
2602                                 sizeof(chain->n_residues),
2603                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2604     {
2605         return(TNG_CRITICAL);
2606     }
2607
2608     return(TNG_SUCCESS);
2609 }
2610
2611 /**
2612  * @brief Write the chain data of a molecules block.
2613  * @param tng_data is a trajectory data container.
2614  * @param chain is the chain data container.
2615  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2616  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2617  * if hash_mode == TNG_USE_HASH.
2618  * @return TNG_SUCCESS(0) is successful.
2619  */
2620 static tng_function_status tng_chain_data_write(const tng_trajectory_t tng_data,
2621                                                 const tng_chain_t chain,
2622                                                 const char hash_mode,
2623                                                 md5_state_t *md5_state)
2624 {
2625     if(tng_file_output_numerical(tng_data, &chain->id,
2626                                  sizeof(chain->id),
2627                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2628     {
2629         return(TNG_CRITICAL);
2630     }
2631
2632     if(tng_fwritestr(tng_data, chain->name, hash_mode,
2633                      md5_state, __LINE__) == TNG_CRITICAL)
2634     {
2635         return(TNG_CRITICAL);
2636     }
2637
2638     if(tng_file_output_numerical(tng_data, &chain->n_residues,
2639                                  sizeof(chain->n_residues),
2640                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2641     {
2642         return(TNG_CRITICAL);
2643     }
2644
2645     return(TNG_SUCCESS);
2646 }
2647
2648 /**
2649  * @brief Read the residue data of a molecules block.
2650  * @param tng_data is a trajectory data container.
2651  * @param residue is the residue data container.
2652  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2653  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2654  * if hash_mode == TNG_USE_HASH.
2655  * @return TNG_SUCCESS(0) is successful.
2656  */
2657 static tng_function_status tng_residue_data_read(const tng_trajectory_t tng_data,
2658                                                  const tng_residue_t residue,
2659                                                  const char hash_mode,
2660                                                  md5_state_t *md5_state)
2661 {
2662     if(tng_file_input_numerical(tng_data, &residue->id,
2663                                 sizeof(residue->id),
2664                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2665     {
2666         return(TNG_CRITICAL);
2667     }
2668
2669     tng_freadstr(tng_data, &residue->name, hash_mode, md5_state, __LINE__);
2670
2671     if(tng_file_input_numerical(tng_data, &residue->n_atoms,
2672                                 sizeof(residue->n_atoms),
2673                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2674     {
2675         return(TNG_CRITICAL);
2676     }
2677
2678     return(TNG_SUCCESS);
2679 }
2680
2681 /**
2682  * @brief Write the residue data of a molecules block.
2683  * @param tng_data is a trajectory data container.
2684  * @param residue is the residue data container.
2685  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2686  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2687  * if hash_mode == TNG_USE_HASH.
2688  * @return TNG_SUCCESS(0) is successful.
2689  */
2690 static tng_function_status tng_residue_data_write(const tng_trajectory_t tng_data,
2691                                                   const tng_residue_t residue,
2692                                                   const char hash_mode,
2693                                                   md5_state_t *md5_state)
2694 {
2695     if(tng_file_output_numerical(tng_data, &residue->id,
2696                                  sizeof(residue->id),
2697                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2698     {
2699         return(TNG_CRITICAL);
2700     }
2701
2702     if(tng_fwritestr(tng_data, residue->name, hash_mode,
2703                      md5_state, __LINE__) == TNG_CRITICAL)
2704     {
2705         return(TNG_CRITICAL);
2706     }
2707
2708     if(tng_file_output_numerical(tng_data, &residue->n_atoms,
2709                                  sizeof(residue->n_atoms),
2710                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2711     {
2712         return(TNG_CRITICAL);
2713     }
2714
2715     return(TNG_SUCCESS);
2716 }
2717
2718 /**
2719  * @brief Read the atom data of a molecules block.
2720  * @param tng_data is a trajectory data container.
2721  * @param atom is the atom data container.
2722  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2723  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2724  * if hash_mode == TNG_USE_HASH.
2725  * @return TNG_SUCCESS(0) is successful.
2726  */
2727 static tng_function_status tng_atom_data_read(const tng_trajectory_t tng_data,
2728                                               const tng_atom_t atom,
2729                                               const char hash_mode,
2730                                               md5_state_t *md5_state)
2731 {
2732     if(tng_file_input_numerical(tng_data, &atom->id,
2733                                 sizeof(atom->id),
2734                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2735     {
2736         return(TNG_CRITICAL);
2737     }
2738
2739     tng_freadstr(tng_data, &atom->name, hash_mode, md5_state, __LINE__);
2740
2741     tng_freadstr(tng_data, &atom->atom_type, hash_mode, md5_state, __LINE__);
2742
2743     return(TNG_SUCCESS);
2744 }
2745
2746 /**
2747  * @brief Write the atom data of a molecules block.
2748  * @param tng_data is a trajectory data container.
2749  * @param atom is the atom data container.
2750  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2751  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2752  * if hash_mode == TNG_USE_HASH.
2753  * @return TNG_SUCCESS(0) is successful.
2754  */
2755 static tng_function_status tng_atom_data_write(const tng_trajectory_t tng_data,
2756                                                const tng_atom_t atom,
2757                                                const char hash_mode,
2758                                                md5_state_t *md5_state)
2759 {
2760     if(tng_file_output_numerical(tng_data, &atom->id,
2761                                  sizeof(atom->id),
2762                                  hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2763     {
2764         return(TNG_CRITICAL);
2765     }
2766
2767     if(tng_fwritestr(tng_data, atom->name, hash_mode,
2768                      md5_state, __LINE__) == TNG_CRITICAL)
2769     {
2770         return(TNG_CRITICAL);
2771     }
2772
2773     if(tng_fwritestr(tng_data, atom->atom_type, hash_mode,
2774                      md5_state, __LINE__) == TNG_CRITICAL)
2775     {
2776         return(TNG_CRITICAL);
2777     }
2778
2779     return(TNG_SUCCESS);
2780 }
2781
2782 static tng_function_status tng_molecules_block_len_calculate
2783                 (const tng_trajectory_t tng_data,
2784                  int64_t *len)
2785 {
2786     int64_t i, j;
2787     tng_molecule_t molecule;
2788     tng_chain_t chain;
2789     tng_residue_t residue;
2790     tng_atom_t atom;
2791     tng_bond_t bond;
2792
2793     *len = 0;
2794
2795     for(i = 0; i < tng_data->n_molecules; i++)
2796     {
2797         molecule = &tng_data->molecules[i];
2798         if(!molecule->name)
2799         {
2800             molecule->name = malloc(1);
2801             if(!molecule->name)
2802             {
2803                 fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2804                        __FILE__, __LINE__);
2805                 return(TNG_CRITICAL);
2806             }
2807             molecule->name[0] = 0;
2808         }
2809         *len += tng_min_size(strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
2810
2811         chain = molecule->chains;
2812         for(j = 0; j < molecule->n_chains; j++)
2813         {
2814             *len += sizeof(chain->id);
2815
2816             if(!chain->name)
2817             {
2818                 chain->name = malloc(1);
2819                 if(!chain->name)
2820                 {
2821                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2822                            __FILE__, __LINE__);
2823                     return(TNG_CRITICAL);
2824                 }
2825                 chain->name[0] = 0;
2826             }
2827             *len += tng_min_size(strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2828
2829             *len += sizeof(chain->n_residues);
2830
2831             chain++;
2832         }
2833
2834         residue = molecule->residues;
2835         for(j = 0; j < molecule->n_residues; j++)
2836         {
2837             *len += sizeof(residue->id);
2838
2839             if(!residue->name)
2840             {
2841                 residue->name = malloc(1);
2842                 if(!residue->name)
2843                 {
2844                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2845                            __FILE__, __LINE__);
2846                     return(TNG_CRITICAL);
2847                 }
2848                 residue->name[0] = 0;
2849             }
2850             *len += tng_min_size(strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2851
2852             *len += sizeof(residue->n_atoms);
2853
2854             residue++;
2855         }
2856
2857         atom = molecule->atoms;
2858         for(j = 0; j < molecule->n_atoms; j++)
2859         {
2860             *len += sizeof(atom->id);
2861             if(!atom->name)
2862             {
2863                 atom->name = malloc(1);
2864                 if(!atom->name)
2865                 {
2866                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2867                            __FILE__, __LINE__);
2868                     return(TNG_CRITICAL);
2869                 }
2870                 atom->name[0] = 0;
2871             }
2872             *len += tng_min_size(strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2873
2874             if(!atom->atom_type)
2875             {
2876                 atom->atom_type = malloc(1);
2877                 if(!atom->atom_type)
2878                 {
2879                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2880                            __FILE__, __LINE__);
2881                     return(TNG_CRITICAL);
2882                 }
2883                 atom->atom_type[0] = 0;
2884             }
2885             *len += tng_min_size(strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2886
2887             atom++;
2888         }
2889
2890         for(j = 0; j < molecule->n_bonds; j++)
2891         {
2892             *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
2893         }
2894     }
2895     *len += sizeof(tng_data->n_molecules) +
2896             (sizeof(molecule->id) +
2897             sizeof(molecule->quaternary_str) +
2898             sizeof(molecule->n_chains) +
2899             sizeof(molecule->n_residues) +
2900             sizeof(molecule->n_atoms) +
2901             sizeof(molecule->n_bonds)) *
2902             tng_data->n_molecules;
2903
2904     if(!tng_data->var_num_atoms_flag)
2905     {
2906         *len += tng_data->n_molecules * sizeof(int64_t);
2907     }
2908
2909     return(TNG_SUCCESS);
2910 }
2911
2912 /**
2913  * @brief Read a molecules block. Contains chain, residue and atom data
2914  * @param tng_data is a trajectory data container.
2915  * @param block is a general block container.
2916  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2917  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2918  * compared to the md5 hash of the read contents to ensure valid data.
2919  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2920  * error has occured.
2921  */
2922 static tng_function_status tng_molecules_block_read
2923                 (const tng_trajectory_t tng_data,
2924                  const tng_gen_block_t block,
2925                  const char hash_mode)
2926 {
2927     int64_t start_pos, i, j, k, l;
2928     tng_molecule_t molecule;
2929     tng_chain_t chain;
2930     tng_residue_t residue;
2931     tng_atom_t atom;
2932     tng_bond_t bond;
2933     char hash[TNG_MD5_HASH_LEN];
2934     md5_state_t md5_state;
2935
2936     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2937     {
2938         return(TNG_CRITICAL);
2939     }
2940
2941     start_pos = ftello(tng_data->input_file);
2942
2943     /* FIXME: Does not check if the size of the contents matches the expected
2944      * size or if the contents can be read. */
2945
2946     if(tng_data->molecules)
2947     {
2948         for(i=0; i<tng_data->n_molecules; i++)
2949         {
2950             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
2951         }
2952         free(tng_data->molecules);
2953         tng_data->molecules = 0;
2954         tng_data->n_molecules = 0;
2955     }
2956
2957     if(hash_mode == TNG_USE_HASH)
2958     {
2959         md5_init(&md5_state);
2960     }
2961
2962     if(tng_file_input_numerical(tng_data, &tng_data->n_molecules,
2963                                 sizeof(tng_data->n_molecules),
2964                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2965     {
2966         return(TNG_CRITICAL);
2967     }
2968
2969     if(tng_data->molecules)
2970     {
2971         free(tng_data->molecules);
2972     }
2973
2974     tng_data->n_particles = 0;
2975
2976     tng_data->molecules = malloc(tng_data->n_molecules *
2977                           sizeof(struct tng_molecule));
2978     if(!tng_data->molecules)
2979     {
2980         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
2981                tng_data->n_molecules * sizeof(struct tng_molecule),
2982                __FILE__, __LINE__);
2983         return(TNG_CRITICAL);
2984     }
2985
2986     if(!tng_data->var_num_atoms_flag)
2987     {
2988         if(tng_data->molecule_cnt_list)
2989         {
2990             free(tng_data->molecule_cnt_list);
2991         }
2992         tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
2993                                       tng_data->n_molecules);
2994         if(!tng_data->molecule_cnt_list)
2995         {
2996             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
2997                    tng_data->n_molecules * sizeof(struct tng_molecule),
2998                    __FILE__, __LINE__);
2999             return(TNG_CRITICAL);
3000         }
3001     }
3002
3003     /* Read each molecule from file */
3004     for(i=0; i < tng_data->n_molecules; i++)
3005     {
3006         molecule = &tng_data->molecules[i];
3007
3008         molecule->name = 0;
3009
3010         if(tng_file_input_numerical(tng_data, &molecule->id,
3011                                     sizeof(molecule->id),
3012                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3013         {
3014             return(TNG_CRITICAL);
3015         }
3016
3017 /*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
3018         tng_freadstr(tng_data, &molecule->name, hash_mode, &md5_state, __LINE__);
3019
3020         if(tng_file_input_numerical(tng_data, &molecule->quaternary_str,
3021                                     sizeof(molecule->quaternary_str),
3022                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3023         {
3024             return(TNG_CRITICAL);
3025         }
3026
3027         if(!tng_data->var_num_atoms_flag)
3028         {
3029             if(tng_file_input_numerical(tng_data, &tng_data->molecule_cnt_list[i],
3030                                         sizeof(int64_t),
3031                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3032             {
3033                 return(TNG_CRITICAL);
3034             }
3035         }
3036
3037         if(tng_file_input_numerical(tng_data, &molecule->n_chains,
3038                                     sizeof(molecule->n_chains),
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_residues,
3045                                     sizeof(molecule->n_residues),
3046                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3047         {
3048             return(TNG_CRITICAL);
3049         }
3050
3051         if(tng_file_input_numerical(tng_data, &molecule->n_atoms,
3052                                     sizeof(molecule->n_atoms),
3053                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3054         {
3055             return(TNG_CRITICAL);
3056         }
3057
3058         tng_data->n_particles += molecule->n_atoms *
3059                                  tng_data->molecule_cnt_list[i];
3060
3061         if(molecule->n_chains > 0)
3062         {
3063             molecule->chains = malloc(molecule->n_chains *
3064                                     sizeof(struct tng_chain));
3065             if(!molecule->chains)
3066             {
3067                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3068                     molecule->n_chains * sizeof(struct tng_chain),
3069                     __FILE__, __LINE__);
3070                 return(TNG_CRITICAL);
3071             }
3072
3073             chain = molecule->chains;
3074         }
3075         else
3076         {
3077             chain = 0;
3078         }
3079
3080         if(molecule->n_residues > 0)
3081         {
3082             molecule->residues = malloc(molecule->n_residues *
3083                                         sizeof(struct tng_residue));
3084             if(!molecule->residues)
3085             {
3086                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3087                     molecule->n_residues * sizeof(struct tng_residue),
3088                     __FILE__, __LINE__);
3089                 if(molecule->chains)
3090                 {
3091                     free(molecule->chains);
3092                     molecule->chains = 0;
3093                 }
3094                 return(TNG_CRITICAL);
3095             }
3096
3097             residue = molecule->residues;
3098         }
3099         else
3100         {
3101             residue = 0;
3102         }
3103
3104         molecule->atoms = malloc(molecule->n_atoms *
3105                                  sizeof(struct tng_atom));
3106         if(!molecule->atoms)
3107         {
3108             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3109                    molecule->n_atoms * sizeof(struct tng_atom),
3110                    __FILE__, __LINE__);
3111             if(molecule->chains)
3112             {
3113                 free(molecule->chains);
3114                 molecule->chains = 0;
3115             }
3116             if(molecule->residues)
3117             {
3118                 free(molecule->residues);
3119                 molecule->residues = 0;
3120             }
3121             return(TNG_CRITICAL);
3122         }
3123
3124         atom = molecule->atoms;
3125
3126         if(molecule->n_chains > 0)
3127         {
3128             /* Read the chains of the molecule */
3129             for(j=0; j<molecule->n_chains; j++)
3130             {
3131                 chain->molecule = molecule;
3132
3133                 chain->name = 0;
3134
3135                 tng_chain_data_read(tng_data, chain, hash_mode, &md5_state);
3136
3137                 if(j==0)
3138                 {
3139                     chain->residues = molecule->residues;
3140                     residue = chain->residues;
3141                 }
3142                 else
3143                 {
3144                     chain->residues = residue;
3145                 }
3146
3147                 /* Read the residues of the chain */
3148                 for(k=0; k<chain->n_residues; k++)
3149                 {
3150                     residue->chain = chain;
3151
3152                     residue->name = 0;
3153
3154                     tng_residue_data_read(tng_data, residue, hash_mode, &md5_state);
3155
3156                     residue->atoms_offset = atom - molecule->atoms;
3157                     /* Read the atoms of the residue */
3158                     for(l=0; l<residue->n_atoms; l++)
3159                     {
3160                         atom->residue = residue;
3161
3162                         atom->name = 0;
3163                         atom->atom_type = 0;
3164
3165                         tng_atom_data_read(tng_data,atom, hash_mode, &md5_state);
3166
3167                         atom++;
3168                     }
3169                     residue++;
3170                 }
3171                 chain++;
3172             }
3173         }
3174         else
3175         {
3176             if(molecule->n_residues > 0)
3177             {
3178                 for(k=0; k<molecule->n_residues; k++)
3179                 {
3180                     residue->chain = 0;
3181
3182                     residue->name = 0;
3183
3184                     tng_residue_data_read(tng_data, residue, hash_mode, &md5_state);
3185
3186                     residue->atoms_offset = atom - molecule->atoms;
3187                     /* Read the atoms of the residue */
3188                     for(l=0; l<residue->n_atoms; l++)
3189                     {
3190                         atom->residue = residue;
3191
3192                         tng_atom_data_read(tng_data, atom, hash_mode, &md5_state);
3193
3194                         atom++;
3195                     }
3196                     residue++;
3197                 }
3198             }
3199             else
3200             {
3201                 for(l=0; l<molecule->n_atoms; l++)
3202                 {
3203                     atom->residue = 0;
3204
3205                     atom->name = 0;
3206                     atom->atom_type = 0;
3207
3208                     tng_atom_data_read(tng_data, atom, hash_mode, &md5_state);
3209
3210                     atom++;
3211                 }
3212             }
3213         }
3214
3215         if(tng_file_input_numerical(tng_data, &molecule->n_bonds,
3216                                     sizeof(molecule->n_bonds),
3217                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3218         {
3219             return(TNG_CRITICAL);
3220         }
3221
3222         if(molecule->n_bonds > 0)
3223         {
3224             tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
3225                                            sizeof(struct tng_bond));
3226             if(!molecule->bonds)
3227             {
3228                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3229                        molecule->n_bonds * sizeof(struct tng_bond),
3230                        __FILE__, __LINE__);
3231                 if(molecule->chains)
3232                 {
3233                     free(molecule->chains);
3234                     molecule->chains = 0;
3235                 }
3236                 if(molecule->residues)
3237                 {
3238                     free(molecule->residues);
3239                     molecule->residues = 0;
3240                 }
3241                 if(molecule->atoms)
3242                 {
3243                     free(molecule->atoms);
3244                     molecule->atoms = 0;
3245                 }
3246                 return(TNG_CRITICAL);
3247             }
3248
3249             bond = molecule->bonds;
3250
3251             for(j=0; j<molecule->n_bonds; j++)
3252             {
3253                 if(tng_file_input_numerical(tng_data, &bond->from_atom_id,
3254                                             sizeof(bond->from_atom_id),
3255                                             hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3256                 {
3257                     return(TNG_CRITICAL);
3258                 }
3259
3260                 if(tng_file_input_numerical(tng_data, &bond->to_atom_id,
3261                                             sizeof(bond->to_atom_id),
3262                                             hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3263                 {
3264                     return(TNG_CRITICAL);
3265                 }
3266
3267                 bond++;
3268             }
3269         }
3270         else
3271         {
3272             molecule->bonds = 0;
3273         }
3274     }
3275
3276     if(hash_mode == TNG_USE_HASH)
3277     {
3278         /* If there is data left in the block that the current version of the library
3279          * cannot interpret still read that to generate the MD5 hash. */
3280         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
3281
3282         md5_finish(&md5_state, (md5_byte_t *)hash);
3283         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)
3284         {
3285             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
3286             {
3287                 fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
3288                         "%s: %d\n", __FILE__, __LINE__);
3289             }
3290         }
3291     }
3292
3293     else
3294     {
3295         /* Seek to the end of the block */
3296         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
3297     }
3298
3299     return(TNG_SUCCESS);
3300 }
3301
3302 /**
3303  * @brief Write a molecules block.
3304  * @param tng_data is a trajectory data container.
3305  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3306  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3307  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3308  * error has occured.
3309  */
3310 static tng_function_status tng_molecules_block_write
3311                 (const tng_trajectory_t tng_data,
3312                  const char hash_mode)
3313 {
3314     int name_len;
3315     int64_t i, j, k, l, header_file_pos, curr_file_pos;
3316     tng_molecule_t molecule;
3317     tng_chain_t chain;
3318     tng_residue_t residue;
3319     tng_atom_t atom;
3320     tng_bond_t bond;
3321     tng_gen_block_t block;
3322     md5_state_t md5_state;
3323
3324     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3325     {
3326         return(TNG_CRITICAL);
3327     }
3328
3329     tng_block_init(&block);
3330
3331     name_len = (unsigned int)strlen("MOLECULES");
3332
3333     block->name = malloc(name_len + 1);
3334     if(!block->name)
3335     {
3336         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3337                 name_len+1, __FILE__, __LINE__);
3338         tng_block_destroy(&block);
3339         return(TNG_CRITICAL);
3340     }
3341
3342     strcpy(block->name, "MOLECULES");
3343     block->id = TNG_MOLECULES;
3344
3345     if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) !=
3346         TNG_SUCCESS)
3347     {
3348         fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n",
3349                 __FILE__, __LINE__);
3350         tng_block_destroy(&block);
3351         return(TNG_CRITICAL);
3352     }
3353
3354     header_file_pos = ftello(tng_data->output_file);
3355
3356     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
3357     {
3358         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3359                tng_data->output_file_path, __FILE__, __LINE__);
3360         tng_block_destroy(&block);
3361         return(TNG_CRITICAL);
3362     }
3363
3364     if(hash_mode == TNG_USE_HASH)
3365     {
3366         md5_init(&md5_state);
3367     }
3368
3369     if(tng_file_output_numerical(tng_data, &tng_data->n_molecules,
3370                                  sizeof(tng_data->n_molecules),
3371                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3372     {
3373         return(TNG_CRITICAL);
3374     }
3375
3376     for(i = 0; i < tng_data->n_molecules; i++)
3377     {
3378         molecule = &tng_data->molecules[i];
3379
3380         if(tng_file_output_numerical(tng_data, &molecule->id,
3381                                     sizeof(molecule->id),
3382                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3383         {
3384             return(TNG_CRITICAL);
3385         }
3386
3387         if(tng_fwritestr(tng_data, molecule->name, hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3388         {
3389             return(TNG_CRITICAL);
3390         }
3391
3392         if(tng_file_output_numerical(tng_data, &molecule->quaternary_str,
3393                                     sizeof(molecule->quaternary_str),
3394                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3395         {
3396             return(TNG_CRITICAL);
3397         }
3398
3399         if(!tng_data->var_num_atoms_flag)
3400         {
3401             if(tng_file_output_numerical(tng_data, &tng_data->molecule_cnt_list[i],
3402                                         sizeof(int64_t),
3403                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3404             {
3405                 return(TNG_CRITICAL);
3406             }
3407         }
3408
3409         if(tng_file_output_numerical(tng_data, &molecule->n_chains,
3410                                     sizeof(molecule->n_chains),
3411                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3412         {
3413             return(TNG_CRITICAL);
3414         }
3415
3416         if(tng_file_output_numerical(tng_data, &molecule->n_residues,
3417                                     sizeof(molecule->n_residues),
3418                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3419         {
3420             return(TNG_CRITICAL);
3421         }
3422
3423         if(tng_file_output_numerical(tng_data, &molecule->n_atoms,
3424                                     sizeof(molecule->n_atoms),
3425                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3426         {
3427             return(TNG_CRITICAL);
3428         }
3429
3430         if(molecule->n_chains > 0)
3431         {
3432             chain = molecule->chains;
3433             for(j = 0; j < molecule->n_chains; j++)
3434             {
3435                 tng_chain_data_write(tng_data, chain, hash_mode, &md5_state);
3436
3437                 residue = chain->residues;
3438                 for(k = 0; k < chain->n_residues; k++)
3439                 {
3440                     tng_residue_data_write(tng_data, residue, hash_mode, &md5_state);
3441
3442                     atom = molecule->atoms + residue->atoms_offset;
3443                     for(l = 0; l < residue->n_atoms; l++)
3444                     {
3445                         tng_atom_data_write(tng_data, atom, hash_mode, &md5_state);
3446
3447                         atom++;
3448                     }
3449                     residue++;
3450                 }
3451                 chain++;
3452             }
3453         }
3454         else
3455         {
3456             if(molecule->n_residues > 0)
3457             {
3458                 residue = molecule->residues;
3459                 for(k = 0; k < molecule->n_residues; k++)
3460                 {
3461                     tng_residue_data_write(tng_data, residue, hash_mode, &md5_state);
3462
3463                     atom = molecule->atoms + residue->atoms_offset;
3464                     for(l = 0; l < residue->n_atoms; l++)
3465                     {
3466                         tng_atom_data_write(tng_data, atom, hash_mode, &md5_state);
3467
3468                         atom++;
3469                     }
3470                     residue++;
3471                 }
3472             }
3473             else
3474             {
3475                 atom = molecule->atoms;
3476                 for(l = 0; l < molecule->n_atoms; l++)
3477                 {
3478                     tng_atom_data_write(tng_data, atom, hash_mode, &md5_state);
3479
3480                     atom++;
3481                 }
3482             }
3483         }
3484
3485         if(tng_file_output_numerical(tng_data, &molecule->n_bonds,
3486                                     sizeof(molecule->n_bonds),
3487                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3488         {
3489             return(TNG_CRITICAL);
3490         }
3491
3492         bond = molecule->bonds;
3493         for(j = 0; j < molecule->n_bonds; j++)
3494         {
3495             if(tng_file_output_numerical(tng_data, &bond->from_atom_id,
3496                                         sizeof(bond->from_atom_id),
3497                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3498             {
3499                 return(TNG_CRITICAL);
3500             }
3501
3502             if(tng_file_output_numerical(tng_data, &bond->to_atom_id,
3503                                         sizeof(bond->to_atom_id),
3504                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3505             {
3506                 return(TNG_CRITICAL);
3507             }
3508
3509             bond++;
3510         }
3511     }
3512     if(hash_mode == TNG_USE_HASH)
3513     {
3514         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
3515         curr_file_pos = ftello(tng_data->output_file);
3516         fseeko(tng_data->output_file, header_file_pos +
3517                3 * sizeof(int64_t), SEEK_SET);
3518         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
3519         {
3520             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
3521                     __LINE__);
3522             return(TNG_CRITICAL);
3523         }
3524         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
3525     }
3526
3527     tng_block_destroy(&block);
3528
3529     return(TNG_SUCCESS);
3530 }
3531
3532 static tng_function_status tng_frame_set_block_len_calculate
3533                 (const tng_trajectory_t tng_data,
3534                  int64_t *len)
3535 {
3536     *len = sizeof(int64_t) * 8;
3537     *len += sizeof(double) * 2;
3538
3539     if(tng_data->var_num_atoms_flag)
3540     {
3541         *len += sizeof(int64_t) * tng_data->n_molecules;
3542     }
3543     return(TNG_SUCCESS);
3544 }
3545
3546 /**
3547  * @brief Read a frame set block. Update tng_data->current_trajectory_frame_set
3548  * @param tng_data is a trajectory data container.
3549  * @param block is a general block container.
3550  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3551  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3552  * compared to the md5 hash of the read contents to ensure valid data.
3553  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3554  * error has occured.
3555  */
3556 static tng_function_status tng_frame_set_block_read
3557                 (tng_trajectory_t tng_data,
3558                  tng_gen_block_t block,
3559                  const char hash_mode)
3560 {
3561     int64_t file_pos, start_pos, i, prev_n_particles;
3562     tng_trajectory_frame_set_t frame_set =
3563     &tng_data->current_trajectory_frame_set;
3564     char hash[TNG_MD5_HASH_LEN];
3565     md5_state_t md5_state;
3566
3567     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3568     {
3569         return(TNG_CRITICAL);
3570     }
3571
3572     start_pos = ftello(tng_data->input_file);
3573
3574     /* FIXME: Does not check if the size of the contents matches the expected
3575      * size or if the contents can be read. */
3576
3577     file_pos = start_pos - block->header_contents_size;
3578
3579     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3580
3581     tng_frame_set_particle_mapping_free(tng_data);
3582
3583     if(hash_mode == TNG_USE_HASH)
3584     {
3585         md5_init(&md5_state);
3586     }
3587     if(tng_file_input_numerical(tng_data, &frame_set->first_frame,
3588                                 sizeof(frame_set->first_frame),
3589                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3590     {
3591         return(TNG_CRITICAL);
3592     }
3593
3594     if(tng_file_input_numerical(tng_data, &frame_set->n_frames,
3595                                 sizeof(frame_set->n_frames),
3596                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3597     {
3598         return(TNG_CRITICAL);
3599     }
3600
3601     if(tng_data->var_num_atoms_flag)
3602     {
3603         prev_n_particles = frame_set->n_particles;
3604         frame_set->n_particles = 0;
3605         /* If the list of molecule counts has already been created assume that
3606          * it is of correct size. */
3607         if(!frame_set->molecule_cnt_list)
3608         {
3609                 frame_set->molecule_cnt_list =
3610                 malloc(sizeof(int64_t) * tng_data->n_molecules);
3611
3612                 if(!frame_set->molecule_cnt_list)
3613                 {
3614                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3615                            sizeof(int64_t) * tng_data->n_molecules,
3616                            __FILE__, __LINE__);
3617                     return(TNG_CRITICAL);
3618                 }
3619         }
3620         for(i = 0; i < tng_data->n_molecules; i++)
3621         {
3622             if(tng_file_input_numerical(tng_data, &frame_set->molecule_cnt_list[i],
3623                                         sizeof(int64_t),
3624                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3625             {
3626                 return(TNG_CRITICAL);
3627             }
3628
3629             frame_set->n_particles += tng_data->molecules[i].n_atoms *
3630                                       frame_set->molecule_cnt_list[i];
3631         }
3632         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
3633         {
3634             /* FIXME: Particle dependent data memory management */
3635         }
3636     }
3637
3638     if(tng_file_input_numerical(tng_data, &frame_set->next_frame_set_file_pos,
3639                                 sizeof(frame_set->next_frame_set_file_pos),
3640                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3641     {
3642         return(TNG_CRITICAL);
3643     }
3644
3645     if(tng_file_input_numerical(tng_data, &frame_set->prev_frame_set_file_pos,
3646                                 sizeof(frame_set->prev_frame_set_file_pos),
3647                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3648     {
3649         return(TNG_CRITICAL);
3650     }
3651
3652     if(tng_file_input_numerical(tng_data, &frame_set->medium_stride_next_frame_set_file_pos,
3653                                 sizeof(frame_set->medium_stride_next_frame_set_file_pos),
3654                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3655     {
3656         return(TNG_CRITICAL);
3657     }
3658
3659     if(tng_file_input_numerical(tng_data, &frame_set->medium_stride_prev_frame_set_file_pos,
3660                                 sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
3661                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3662     {
3663         return(TNG_CRITICAL);
3664     }
3665
3666     if(tng_file_input_numerical(tng_data, &frame_set->long_stride_next_frame_set_file_pos,
3667                                 sizeof(frame_set->long_stride_next_frame_set_file_pos),
3668                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3669     {
3670         return(TNG_CRITICAL);
3671     }
3672
3673     if(tng_file_input_numerical(tng_data, &frame_set->long_stride_prev_frame_set_file_pos,
3674                                 sizeof(frame_set->long_stride_prev_frame_set_file_pos),
3675                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3676     {
3677         return(TNG_CRITICAL);
3678     }
3679
3680     if(block->block_version >= 3)
3681     {
3682         if(tng_file_input_numerical(tng_data, &frame_set->first_frame_time,
3683                                     sizeof(frame_set->first_frame_time),
3684                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3685         {
3686             return(TNG_CRITICAL);
3687         }
3688
3689         if(tng_file_input_numerical(tng_data, &tng_data->time_per_frame,
3690                                     sizeof(tng_data->time_per_frame),
3691                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3692         {
3693             return(TNG_CRITICAL);
3694         }
3695     }
3696     else
3697     {
3698         frame_set->first_frame_time = -1;
3699         tng_data->time_per_frame = -1;
3700     }
3701
3702     if(hash_mode == TNG_USE_HASH)
3703     {
3704         /* If there is data left in the block that the current version of the library
3705          * cannot interpret still read that to generate the MD5 hash. */
3706         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
3707
3708         md5_finish(&md5_state, (md5_byte_t *)hash);
3709         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)
3710         {
3711             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
3712             {
3713                 fprintf(stderr, "TNG library: Frame set block contents corrupt (first frame %"PRId64"). Hashes do not match. "
3714                         "%s: %d\n", frame_set->first_frame, __FILE__, __LINE__);
3715             }
3716         }
3717     }
3718     else
3719     {
3720         /* Seek to the end of the block */
3721         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
3722     }
3723
3724     /* If the output file and the input files are the same the number of
3725      * frames in the file are the same number as has just been read.
3726      * This is updated here to later on see if there have been new frames
3727      * added and thereby the frame set needs to be rewritten. */
3728     if(tng_data->output_file == tng_data->input_file)
3729     {
3730         frame_set->n_written_frames = frame_set->n_frames;
3731     }
3732
3733     return(TNG_SUCCESS);
3734 }
3735
3736 /**
3737  * @brief Write tng_data->current_trajectory_frame_set to file
3738  * @param tng_data is a trajectory data container.
3739  * @param block is a general block container.
3740  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3741  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3742  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3743  * error has occured.
3744  */
3745 static tng_function_status tng_frame_set_block_write
3746                 (const tng_trajectory_t tng_data,
3747                  const tng_gen_block_t block,
3748                  const char hash_mode)
3749 {
3750     char *temp_name;
3751     int64_t i, header_file_pos, curr_file_pos;
3752     unsigned int name_len;
3753     tng_trajectory_frame_set_t frame_set =
3754     &tng_data->current_trajectory_frame_set;
3755     md5_state_t md5_state;
3756
3757     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3758     {
3759         return(TNG_CRITICAL);
3760     }
3761
3762     name_len = (unsigned int)strlen("TRAJECTORY FRAME SET");
3763
3764     if(!block->name || strlen(block->name) < name_len)
3765     {
3766         temp_name = realloc(block->name, name_len + 1);
3767         if(!temp_name)
3768         {
3769             fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
3770                    name_len+1, __FILE__, __LINE__);
3771             free(block->name);
3772             block->name = 0;
3773             return(TNG_CRITICAL);
3774         }
3775         block->name = temp_name;
3776     }
3777     strcpy(block->name, "TRAJECTORY FRAME SET");
3778     block->id = TNG_TRAJECTORY_FRAME_SET;
3779
3780     if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) !=
3781         TNG_SUCCESS)
3782     {
3783         fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n",
3784                 __FILE__, __LINE__);
3785         return(TNG_CRITICAL);
3786     }
3787
3788     header_file_pos = ftello(tng_data->output_file);
3789
3790     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
3791     {
3792         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3793                tng_data->output_file_path, __FILE__, __LINE__);
3794         return(TNG_CRITICAL);
3795     }
3796
3797     if(hash_mode == TNG_USE_HASH)
3798     {
3799         md5_init(&md5_state);
3800     }
3801     if(tng_file_output_numerical(tng_data, &frame_set->first_frame,
3802                                  sizeof(frame_set->first_frame),
3803                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3804     {
3805         return(TNG_CRITICAL);
3806     }
3807
3808     if(tng_file_output_numerical(tng_data, &frame_set->n_frames,
3809                                  sizeof(frame_set->n_frames),
3810                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3811     {
3812         return(TNG_CRITICAL);
3813     }
3814
3815     if(tng_data->var_num_atoms_flag)
3816     {
3817         for(i = 0; i < tng_data->n_molecules; i++)
3818         {
3819             if(tng_file_output_numerical(tng_data, &frame_set->molecule_cnt_list[i],
3820                                         sizeof(int64_t),
3821                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3822             {
3823                 return(TNG_CRITICAL);
3824             }
3825         }
3826     }
3827
3828     if(tng_file_output_numerical(tng_data, &frame_set->next_frame_set_file_pos,
3829                                  sizeof(frame_set->next_frame_set_file_pos),
3830                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3831     {
3832         return(TNG_CRITICAL);
3833     }
3834
3835     if(tng_file_output_numerical(tng_data, &frame_set->prev_frame_set_file_pos,
3836                                  sizeof(frame_set->prev_frame_set_file_pos),
3837                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3838     {
3839         return(TNG_CRITICAL);
3840     }
3841
3842     if(tng_file_output_numerical(tng_data, &frame_set->medium_stride_next_frame_set_file_pos,
3843                                  sizeof(frame_set->medium_stride_next_frame_set_file_pos),
3844                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3845     {
3846         return(TNG_CRITICAL);
3847     }
3848
3849     if(tng_file_output_numerical(tng_data, &frame_set->medium_stride_prev_frame_set_file_pos,
3850                                  sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
3851                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3852     {
3853         return(TNG_CRITICAL);
3854     }
3855
3856     if(tng_file_output_numerical(tng_data, &frame_set->long_stride_next_frame_set_file_pos,
3857                                  sizeof(frame_set->long_stride_next_frame_set_file_pos),
3858                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3859     {
3860         return(TNG_CRITICAL);
3861     }
3862
3863     if(tng_file_output_numerical(tng_data, &frame_set->long_stride_prev_frame_set_file_pos,
3864                                  sizeof(frame_set->long_stride_prev_frame_set_file_pos),
3865                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3866     {
3867         return(TNG_CRITICAL);
3868     }
3869
3870     if(tng_file_output_numerical(tng_data, &frame_set->first_frame_time,
3871                                  sizeof(frame_set->first_frame_time),
3872                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3873     {
3874         return(TNG_CRITICAL);
3875     }
3876
3877     if(tng_file_output_numerical(tng_data, &tng_data->time_per_frame,
3878                                  sizeof(tng_data->time_per_frame),
3879                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3880     {
3881         return(TNG_CRITICAL);
3882     }
3883     if(hash_mode == TNG_USE_HASH)
3884     {
3885         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
3886         curr_file_pos = ftello(tng_data->output_file);
3887         fseeko(tng_data->output_file, header_file_pos +
3888                3 * sizeof(int64_t), SEEK_SET);
3889         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
3890         {
3891             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
3892                     __LINE__);
3893             return(TNG_CRITICAL);
3894         }
3895         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
3896     }
3897
3898     return(TNG_SUCCESS);
3899 }
3900
3901 static tng_function_status tng_trajectory_mapping_block_len_calculate
3902                 (const tng_trajectory_t tng_data,
3903                  const int64_t n_particles,
3904                  int64_t *len)
3905 {
3906     (void)tng_data;
3907     *len = sizeof(int64_t) * (2 + n_particles);
3908
3909     return(TNG_SUCCESS);
3910 }
3911
3912 /**
3913  * @brief Read an atom mappings block (translating between real atom indexes and how
3914  *  the atom info is written in this frame set).
3915  * @param tng_data is a trajectory data container.
3916  * @param block is a general block container.
3917  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3918  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3919  * compared to the md5 hash of the read contents to ensure valid data.
3920  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3921  * error has occured.
3922  */
3923 static tng_function_status tng_trajectory_mapping_block_read
3924                 (const tng_trajectory_t tng_data,
3925                  const tng_gen_block_t block,
3926                  const char hash_mode)
3927 {
3928     int64_t start_pos, i;
3929     tng_trajectory_frame_set_t frame_set =
3930     &tng_data->current_trajectory_frame_set;
3931     tng_particle_mapping_t mapping, mappings;
3932     char hash[TNG_MD5_HASH_LEN];
3933     md5_state_t md5_state;
3934
3935     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3936     {
3937         return(TNG_CRITICAL);
3938     }
3939
3940     start_pos = ftello(tng_data->input_file);
3941
3942     /* FIXME: Does not check if the size of the contents matches the expected
3943      * size or if the contents can be read. */
3944
3945     frame_set->n_mapping_blocks++;
3946     mappings = realloc(frame_set->mappings,
3947                        sizeof(struct tng_particle_mapping) *
3948                        frame_set->n_mapping_blocks);
3949     if(!mappings)
3950     {
3951         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3952                block->block_contents_size, __FILE__, __LINE__);
3953         free(frame_set->mappings);
3954         frame_set->mappings = 0;
3955         return(TNG_CRITICAL);
3956     }
3957     frame_set->mappings = mappings;
3958     mapping = &mappings[frame_set->n_mapping_blocks - 1];
3959
3960
3961     if(hash_mode == TNG_USE_HASH)
3962     {
3963         md5_init(&md5_state);
3964     }
3965
3966     if(tng_file_input_numerical(tng_data, &mapping->num_first_particle,
3967                                 sizeof(mapping->num_first_particle),
3968                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3969     {
3970         return(TNG_CRITICAL);
3971     }
3972
3973     if(tng_file_input_numerical(tng_data, &mapping->n_particles,
3974                                 sizeof(mapping->n_particles),
3975                                 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3976     {
3977         return(TNG_CRITICAL);
3978     }
3979
3980     mapping->real_particle_numbers = malloc(mapping->n_particles *
3981                                             sizeof(int64_t));
3982     if(!mapping->real_particle_numbers)
3983     {
3984         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3985                 mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
3986         return(TNG_CRITICAL);
3987     }
3988
3989     /* If the byte order needs to be swapped the data must be read one value at
3990      * a time and swapped */
3991     if(tng_data->input_endianness_swap_func_64)
3992     {
3993         for(i = 0; i < mapping->n_particles; i++)
3994         {
3995             if(tng_file_input_numerical(tng_data, &mapping->real_particle_numbers[i],
3996                                         sizeof(int64_t),
3997                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3998             {
3999                 return(TNG_CRITICAL);
4000             }
4001         }
4002     }
4003     /* Otherwise the data can be read all at once */
4004     else
4005     {
4006         if(fread(mapping->real_particle_numbers, mapping->n_particles * sizeof(int64_t),
4007                 1, tng_data->input_file) == 0)
4008         {
4009             fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
4010             return(TNG_CRITICAL);
4011         }
4012         if(hash_mode == TNG_USE_HASH)
4013         {
4014             md5_append(&md5_state, (md5_byte_t *)mapping->real_particle_numbers, mapping->n_particles * sizeof(int64_t));
4015         }
4016     }
4017
4018     if(hash_mode == TNG_USE_HASH)
4019     {
4020         /* If there is data left in the block that the current version of the library
4021          * cannot interpret still read that to generate the MD5 hash. */
4022         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
4023
4024         md5_finish(&md5_state, (md5_byte_t *)hash);
4025         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)
4026         {
4027             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
4028             {
4029                 fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
4030                         "%s: %d\n", __FILE__, __LINE__);
4031             }
4032         }
4033     }
4034     else
4035     {
4036         /* Seek to the end of the block */
4037         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
4038     }
4039
4040     return(TNG_SUCCESS);
4041 }
4042
4043 /**
4044  * @brief Write the atom mappings of the current trajectory frame set
4045  * @param tng_data is a trajectory data container.
4046  * @param block is a general block container.
4047  * @param mapping_block_nr is the index of the mapping block to write.
4048  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4049  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4050  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
4051  * has occurred or TNG_CRITICAL (2) if a major error has occured.
4052  */
4053 static tng_function_status tng_trajectory_mapping_block_write
4054                 (const tng_trajectory_t tng_data,
4055                  const tng_gen_block_t block,
4056                  const int mapping_block_nr,
4057                  const char hash_mode)
4058 {
4059     int64_t header_file_pos, curr_file_pos;
4060     char *temp_name;
4061     int i;
4062     unsigned int name_len;
4063     md5_state_t md5_state;
4064     tng_particle_mapping_t mapping =
4065     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
4066
4067     if(mapping_block_nr >=
4068        tng_data->current_trajectory_frame_set.n_mapping_blocks)
4069     {
4070         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
4071                __FILE__, __LINE__);
4072         return(TNG_FAILURE);
4073     }
4074
4075     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4076     {
4077         return(TNG_CRITICAL);
4078     }
4079
4080     name_len = (unsigned int)strlen("PARTICLE MAPPING");
4081
4082     if(!block->name || strlen(block->name) < name_len)
4083     {
4084         temp_name = realloc(block->name, name_len + 1);
4085         if(!temp_name)
4086         {
4087             fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
4088                    name_len+1, __FILE__, __LINE__);
4089             free(block->name);
4090             block->name = 0;
4091             return(TNG_CRITICAL);
4092         }
4093         block->name = temp_name;
4094     }
4095     strcpy(block->name, "PARTICLE MAPPING");
4096     block->id = TNG_PARTICLE_MAPPING;
4097
4098     if(tng_trajectory_mapping_block_len_calculate(tng_data,
4099                                                   mapping->n_particles,
4100                                                   &block->block_contents_size) !=
4101         TNG_SUCCESS)
4102     {
4103         fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n",
4104                 __FILE__, __LINE__);
4105         return(TNG_CRITICAL);
4106     }
4107
4108     header_file_pos = ftello(tng_data->output_file);
4109
4110     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
4111     {
4112         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4113                tng_data->output_file_path, __FILE__, __LINE__);
4114         return(TNG_CRITICAL);
4115     }
4116
4117     if(hash_mode == TNG_USE_HASH)
4118     {
4119         md5_init(&md5_state);
4120     }
4121     if(tng_file_output_numerical(tng_data, &mapping->num_first_particle,
4122                                  sizeof(mapping->num_first_particle),
4123                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
4124     {
4125         return(TNG_CRITICAL);
4126     }
4127
4128     if(tng_file_output_numerical(tng_data, &mapping->n_particles,
4129                                  sizeof(mapping->n_particles),
4130                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
4131     {
4132         return(TNG_CRITICAL);
4133     }
4134
4135     if(tng_data->output_endianness_swap_func_64)
4136     {
4137         for(i = 0; i < mapping->n_particles; i++)
4138         {
4139             if(tng_file_output_numerical(tng_data, &mapping->real_particle_numbers[i],
4140                                         sizeof(int64_t),
4141                                         hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
4142             {
4143                 return(TNG_CRITICAL);
4144             }
4145         }
4146     }
4147     else
4148     {
4149         if(fwrite(mapping->real_particle_numbers,
4150                   mapping->n_particles * sizeof(int64_t),
4151                   1, tng_data->output_file) != 1)
4152         {
4153             fprintf(stderr, "TNG library: Could not write block data. %s: %d\n", __FILE__, __LINE__);
4154             return(TNG_CRITICAL);
4155         }
4156         if(hash_mode == TNG_USE_HASH)
4157         {
4158             md5_append(&md5_state, (md5_byte_t *)mapping->real_particle_numbers,
4159                        mapping->n_particles * sizeof(int64_t));
4160         }
4161     }
4162
4163     if(hash_mode == TNG_USE_HASH)
4164     {
4165         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
4166         curr_file_pos = ftello(tng_data->output_file);
4167         fseeko(tng_data->output_file, header_file_pos +
4168                3 * sizeof(int64_t), SEEK_SET);
4169         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
4170         {
4171             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
4172                     __LINE__);
4173             return(TNG_CRITICAL);
4174         }
4175         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
4176     }
4177
4178     return(TNG_SUCCESS);
4179 }
4180
4181 /**
4182  * @brief Prepare a block for storing particle data
4183  * @param tng_data is a trajectory data container.
4184  * @param block_type_flag specifies if this is a trajectory block or a
4185  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
4186  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4187  * error has occured.
4188  */
4189 static tng_function_status tng_particle_data_block_create
4190                 (const tng_trajectory_t tng_data,
4191                  const char block_type_flag)
4192 {
4193     tng_trajectory_frame_set_t frame_set =
4194     &tng_data->current_trajectory_frame_set;
4195
4196     tng_data_t data;
4197
4198     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4199     {
4200         frame_set->n_particle_data_blocks++;
4201         data = realloc(frame_set->tr_particle_data,
4202                     sizeof(struct tng_data) *
4203                     frame_set->n_particle_data_blocks);
4204         if(!data)
4205         {
4206             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
4207                 sizeof(struct tng_data) *
4208                 frame_set->n_particle_data_blocks,
4209                 __FILE__, __LINE__);
4210             free(frame_set->tr_particle_data);
4211             frame_set->tr_particle_data = 0;
4212             return(TNG_CRITICAL);
4213         }
4214         frame_set->tr_particle_data = data;
4215     }
4216     else
4217     {
4218         tng_data->n_particle_data_blocks++;
4219         data = realloc(tng_data->non_tr_particle_data,
4220                         sizeof(struct tng_data) *
4221                         tng_data->n_particle_data_blocks);
4222         if(!data)
4223         {
4224             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
4225                     sizeof(struct tng_data) *
4226                     tng_data->n_particle_data_blocks,
4227                     __FILE__, __LINE__);
4228             free(tng_data->non_tr_particle_data);
4229             tng_data->non_tr_particle_data = 0;
4230             return(TNG_CRITICAL);
4231         }
4232         tng_data->non_tr_particle_data = data;
4233     }
4234
4235     return(TNG_SUCCESS);
4236 }
4237
4238 static tng_function_status tng_compress(const tng_trajectory_t tng_data,
4239                                         const tng_gen_block_t block,
4240                                         const int64_t n_frames,
4241                                         const int64_t n_particles,
4242                                         const char type,
4243                                         char **data,
4244                                         int64_t *new_len)
4245 {
4246     int nalgo;
4247     int compressed_len;
4248     int *alt_algo = 0;
4249     char *dest;
4250     int64_t algo_find_n_frames = -1;
4251     float f_precision;
4252     double d_precision;
4253
4254     if(block->id != TNG_TRAJ_POSITIONS &&
4255        block->id != TNG_TRAJ_VELOCITIES)
4256     {
4257         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
4258                "TNG method. %s: %d\n", __FILE__, __LINE__);
4259         return(TNG_FAILURE);
4260     }
4261     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4262     {
4263         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
4264         return(TNG_FAILURE);
4265     }
4266
4267     if(n_frames <= 0 || n_particles <= 0)
4268     {
4269         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
4270                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
4271         return(TNG_FAILURE);
4272     }
4273
4274     f_precision = 1/(float)tng_data->compression_precision;
4275     d_precision = 1/tng_data->compression_precision;
4276
4277     if(block->id == TNG_TRAJ_POSITIONS)
4278     {
4279         /* If there is only one frame in this frame set and there might be more
4280          * do not store the algorithm as the compression algorithm, but find
4281          * the best one without storing it */
4282         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4283         {
4284             nalgo = tng_compress_nalgo();
4285             alt_algo = malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4286
4287             /* If we have already determined the initial coding and
4288              * initial coding parameter do not determine them again. */
4289             if(tng_data->compress_algo_pos)
4290             {
4291                 alt_algo[0] = tng_data->compress_algo_pos[0];
4292                 alt_algo[1] = tng_data->compress_algo_pos[1];
4293                 alt_algo[2] = tng_data->compress_algo_pos[2];
4294                 alt_algo[3] = tng_data->compress_algo_pos[3];
4295             }
4296             else
4297             {
4298                 alt_algo[0] = -1;
4299                 alt_algo[1] = -1;
4300                 alt_algo[2] = -1;
4301                 alt_algo[3] = -1;
4302             }
4303
4304             /* If the initial coding and initial coding parameter are -1
4305              * they will be determined in tng_compress_pos/_float/. */
4306             if(type == TNG_FLOAT_DATA)
4307             {
4308                 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4309                                               (int)n_frames,
4310                                               f_precision,
4311                                               0, alt_algo,
4312                                               &compressed_len);
4313
4314             }
4315             else
4316             {
4317                 dest = tng_compress_pos((double *)*data, (int)n_particles,
4318                                         (int)n_frames,
4319                                         d_precision,
4320                                         0, alt_algo,
4321                                         &compressed_len);
4322             }
4323             /* If there had been no algorithm determined before keep the initial coding
4324              * and initial coding parameter so that they won't have to be determined again. */
4325             if(!tng_data->compress_algo_pos)
4326             {
4327                 nalgo = tng_compress_nalgo();
4328                 tng_data->compress_algo_pos=malloc(nalgo *
4329                                                    sizeof *tng_data->compress_algo_pos);
4330                 tng_data->compress_algo_pos[0] = alt_algo[0];
4331                 tng_data->compress_algo_pos[1] = alt_algo[1];
4332                 tng_data->compress_algo_pos[2] = -1;
4333                 tng_data->compress_algo_pos[3] = -1;
4334             }
4335         }
4336         else if(!tng_data->compress_algo_pos || tng_data->compress_algo_pos[2] == -1 ||
4337                 tng_data->compress_algo_pos[2] == -1)
4338         {
4339             if(n_frames > 6)
4340             {
4341                 algo_find_n_frames = 5;
4342             }
4343             else
4344             {
4345                 algo_find_n_frames = n_frames;
4346             }
4347
4348             /* If the algorithm parameters are -1 they will be determined during the
4349              * compression. */
4350             if(!tng_data->compress_algo_pos)
4351             {
4352                 nalgo = tng_compress_nalgo();
4353                 tng_data->compress_algo_pos=malloc(nalgo *
4354                                                    sizeof *tng_data->compress_algo_pos);
4355                 tng_data->compress_algo_pos[0] = -1;
4356                 tng_data->compress_algo_pos[1] = -1;
4357                 tng_data->compress_algo_pos[2] = -1;
4358                 tng_data->compress_algo_pos[3] = -1;
4359             }
4360             if(type == TNG_FLOAT_DATA)
4361             {
4362                 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4363                                               (int)algo_find_n_frames,
4364                                               f_precision,
4365                                               0, tng_data->
4366                                               compress_algo_pos,
4367                                               &compressed_len);
4368
4369                 if(algo_find_n_frames < n_frames)
4370                 {
4371                     free(dest);
4372                     dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4373                                                   (int)n_frames,
4374                                                   f_precision,
4375                                                   0, tng_data->compress_algo_pos,
4376                                                   &compressed_len);
4377                 }
4378             }
4379             else
4380             {
4381                 dest = tng_compress_pos((double *)*data, (int)n_particles,
4382                                         (int)algo_find_n_frames,
4383                                         d_precision,
4384                                         0, tng_data->
4385                                         compress_algo_pos,
4386                                         &compressed_len);
4387
4388                 if(algo_find_n_frames < n_frames)
4389                 {
4390                     free(dest);
4391                     dest = tng_compress_pos((double *)*data, (int)n_particles,
4392                                             (int)n_frames,
4393                                             d_precision, 0,
4394                                             tng_data->compress_algo_pos,
4395                                             &compressed_len);
4396                 }
4397             }
4398         }
4399         else
4400         {
4401             if(type == TNG_FLOAT_DATA)
4402             {
4403                 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4404                                               (int)n_frames,
4405                                               f_precision, 0,
4406                                               tng_data->compress_algo_pos, &compressed_len);
4407             }
4408             else
4409             {
4410                 dest = tng_compress_pos((double *)*data, (int)n_particles,
4411                                         (int)n_frames,
4412                                         d_precision, 0,
4413                                         tng_data->compress_algo_pos,
4414                                         &compressed_len);
4415             }
4416         }
4417     }
4418     else if(block->id == TNG_TRAJ_VELOCITIES)
4419     {
4420         /* If there is only one frame in this frame set and there might be more
4421          * do not store the algorithm as the compression algorithm, but find
4422          * the best one without storing it */
4423         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4424         {
4425             nalgo = tng_compress_nalgo();
4426             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_vel);
4427
4428             /* If we have already determined the initial coding and
4429              * initial coding parameter do not determine them again. */
4430             if(tng_data->compress_algo_vel)
4431             {
4432                 alt_algo[0] = tng_data->compress_algo_vel[0];
4433                 alt_algo[1] = tng_data->compress_algo_vel[1];
4434                 alt_algo[2] = tng_data->compress_algo_vel[2];
4435                 alt_algo[3] = tng_data->compress_algo_vel[3];
4436             }
4437             else
4438             {
4439                 alt_algo[0] = -1;
4440                 alt_algo[1] = -1;
4441                 alt_algo[2] = -1;
4442                 alt_algo[3] = -1;
4443             }
4444
4445             /* If the initial coding and initial coding parameter are -1
4446              * they will be determined in tng_compress_pos/_float/. */
4447             if(type == TNG_FLOAT_DATA)
4448             {
4449                 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4450                                               (int)n_frames,
4451                                               f_precision,
4452                                               0, alt_algo,
4453                                               &compressed_len);
4454
4455             }
4456             else
4457             {
4458                 dest = tng_compress_vel((double *)*data, (int)n_particles,
4459                                         (int)n_frames,
4460                                         d_precision,
4461                                         0, alt_algo,
4462                                         &compressed_len);
4463             }
4464             /* If there had been no algorithm determined before keep the initial coding
4465              * and initial coding parameter so that they won't have to be determined again. */
4466             if(!tng_data->compress_algo_vel)
4467             {
4468                 nalgo = tng_compress_nalgo();
4469                 tng_data->compress_algo_vel=malloc(nalgo *
4470                                                    sizeof *tng_data->compress_algo_vel);
4471                 tng_data->compress_algo_vel[0] = alt_algo[0];
4472                 tng_data->compress_algo_vel[1] = alt_algo[1];
4473                 tng_data->compress_algo_vel[2] = -1;
4474                 tng_data->compress_algo_vel[3] = -1;
4475             }
4476         }
4477         else if(!tng_data->compress_algo_vel || tng_data->compress_algo_vel[2] == -1 ||
4478                 tng_data->compress_algo_vel[2] == -1)
4479         {
4480             if(n_frames > 6)
4481             {
4482                 algo_find_n_frames = 5;
4483             }
4484             else
4485             {
4486                 algo_find_n_frames = n_frames;
4487             }
4488
4489             /* If the algorithm parameters are -1 they will be determined during the
4490              * compression. */
4491             if(!tng_data->compress_algo_vel)
4492             {
4493                 nalgo = tng_compress_nalgo();
4494                 tng_data->compress_algo_vel=malloc(nalgo *
4495                                                    sizeof *tng_data->compress_algo_vel);
4496                 tng_data->compress_algo_vel[0] = -1;
4497                 tng_data->compress_algo_vel[1] = -1;
4498                 tng_data->compress_algo_vel[2] = -1;
4499                 tng_data->compress_algo_vel[3] = -1;
4500             }
4501             if(type == TNG_FLOAT_DATA)
4502             {
4503                 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4504                                               (int)algo_find_n_frames,
4505                                               f_precision,
4506                                               0, tng_data->
4507                                               compress_algo_vel,
4508                                               &compressed_len);
4509                 if(algo_find_n_frames < n_frames)
4510                 {
4511                     free(dest);
4512                     dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4513                                                   (int)n_frames,
4514                                                   f_precision,
4515                                                   0, tng_data->compress_algo_vel,
4516                                                   &compressed_len);
4517                 }
4518             }
4519             else
4520             {
4521                 dest = tng_compress_vel((double *)*data, (int)n_particles,
4522                                         (int)algo_find_n_frames,
4523                                         d_precision,
4524                                         0, tng_data->
4525                                         compress_algo_vel,
4526                                         &compressed_len);
4527                 if(algo_find_n_frames < n_frames)
4528                 {
4529                     free(dest);
4530                     dest = tng_compress_vel((double *)*data, (int)n_particles,
4531                                             (int)n_frames,
4532                                             d_precision,
4533                                             0, tng_data->compress_algo_vel,
4534                                             &compressed_len);
4535                 }
4536             }
4537         }
4538         else
4539         {
4540             if(type == TNG_FLOAT_DATA)
4541             {
4542                 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4543                                               (int)n_frames,
4544                                               f_precision,
4545                                               0, tng_data->
4546                                               compress_algo_vel,
4547                                               &compressed_len);
4548             }
4549             else
4550             {
4551                 dest = tng_compress_vel((double *)*data, (int)n_particles,
4552                                         (int)n_frames,
4553                                         d_precision,
4554                                         0, tng_data->
4555                                         compress_algo_vel,
4556                                         &compressed_len);
4557             }
4558         }
4559     }
4560     else
4561     {
4562         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
4563         return(TNG_FAILURE);
4564     }
4565
4566     if(alt_algo)
4567     {
4568         free(alt_algo);
4569     }
4570
4571     free(*data);
4572
4573     *data = (char *)dest;
4574
4575     *new_len = compressed_len;
4576
4577     return(TNG_SUCCESS);
4578 }
4579
4580 static tng_function_status tng_uncompress(const tng_trajectory_t tng_data,
4581                                           const tng_gen_block_t block,
4582                                           const char type,
4583                                           char **data,
4584                                           const int64_t uncompressed_len)
4585 {
4586     double *d_dest = 0;
4587     float *f_dest = 0;
4588     int result;
4589     (void)tng_data;
4590
4591     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
4592
4593     if(block->id != TNG_TRAJ_POSITIONS &&
4594        block->id != TNG_TRAJ_VELOCITIES)
4595     {
4596         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
4597                "TNG method.\n");
4598         return(TNG_FAILURE);
4599     }
4600     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4601     {
4602         fprintf(stderr, "TNG library: Data type not supported.\n");
4603         return(TNG_FAILURE);
4604     }
4605
4606     if(type == TNG_FLOAT_DATA)
4607     {
4608         f_dest = malloc(uncompressed_len);
4609         if(!f_dest)
4610         {
4611             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4612                 uncompressed_len, __FILE__, __LINE__);
4613             return(TNG_CRITICAL);
4614         }
4615         result = tng_compress_uncompress_float(*data, f_dest);
4616
4617         free(*data);
4618
4619         *data = (char *)f_dest;
4620     }
4621     else
4622     {
4623         d_dest = malloc(uncompressed_len);
4624         if(!d_dest)
4625         {
4626             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4627                 uncompressed_len, __FILE__, __LINE__);
4628             return(TNG_CRITICAL);
4629         }
4630         result = tng_compress_uncompress(*data, d_dest);
4631
4632         free(*data);
4633
4634         *data = (char *)d_dest;
4635     }
4636
4637     if(result == 1)
4638     {
4639         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
4640         return(TNG_FAILURE);
4641     }
4642
4643     return(TNG_SUCCESS);
4644 }
4645
4646 #ifdef USE_ZLIB
4647 static tng_function_status tng_gzip_compress(const tng_trajectory_t tng_data,
4648                                              char **data, const int64_t len,
4649                                              int64_t *new_len)
4650 {
4651     Bytef *dest;
4652     uLongf stat, max_len;
4653     (void)tng_data;
4654
4655     max_len = compressBound(len);
4656     dest = malloc(max_len);
4657     if(!dest)
4658     {
4659         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4660                max_len, __FILE__, __LINE__);
4661         return(TNG_CRITICAL);
4662     }
4663
4664     stat = compress(dest, &max_len, (Bytef *)*data, len);
4665     if(stat != (unsigned long)Z_OK)
4666     {
4667         free(dest);
4668         if(stat == (unsigned long)Z_MEM_ERROR)
4669         {
4670             fprintf(stderr, "TNG library: Not enough memory. ");
4671         }
4672         else if(stat == (unsigned long)Z_BUF_ERROR)
4673         {
4674             fprintf(stderr, "TNG library: Destination buffer too small. ");
4675         }
4676         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
4677         return(TNG_FAILURE);
4678     }
4679
4680     *new_len = max_len;
4681
4682     free(*data);
4683
4684     *data = (char *)dest;
4685
4686     return(TNG_SUCCESS);
4687 }
4688
4689 static tng_function_status tng_gzip_uncompress(const tng_trajectory_t tng_data,
4690                                                char **data,
4691                                                const int64_t compressed_len,
4692                                                const int64_t uncompressed_len)
4693 {
4694     Bytef *dest;
4695     unsigned long stat;
4696     (void)tng_data;
4697     uLongf new_len = uncompressed_len;
4698
4699     dest = malloc(uncompressed_len);
4700     if(!dest)
4701     {
4702         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4703                uncompressed_len, __FILE__, __LINE__);
4704         return(TNG_CRITICAL);
4705     }
4706
4707     stat = uncompress(dest, &new_len, (Bytef *) *data,
4708                       compressed_len);
4709
4710     if(stat != Z_OK)
4711     {
4712         free(dest);
4713         if(stat == (unsigned long)Z_MEM_ERROR)
4714         {
4715             fprintf(stderr, "TNG library: Not enough memory. ");
4716         }
4717         else if(stat == (unsigned long)Z_BUF_ERROR)
4718         {
4719             fprintf(stderr, "TNG library: Destination buffer too small. ");
4720         }
4721         else if(stat == (unsigned long)Z_DATA_ERROR)
4722         {
4723             fprintf(stderr, "TNG library: Data corrupt. ");
4724         }
4725         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
4726                __LINE__);
4727         return(TNG_FAILURE);
4728     }
4729
4730     free(*data);
4731
4732     *data = (char *)dest;
4733
4734     return(TNG_SUCCESS);
4735 }
4736 #endif
4737
4738 /**
4739  * @brief Allocate memory for storing particle data.
4740  * The allocated block will be refered to by data->values.
4741  * @param tng_data is a trajectory data container.
4742  * @param data is the data struct, which will contain the allocated memory in
4743  * data->values.
4744  * @param n_frames is the number of frames of data to store.
4745  * @param n_particles is the number of particles with data.
4746  * @param n_values_per_frame is the number of data values per particle and
4747  * frame.
4748  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4749  * error has occured.
4750  */
4751 static tng_function_status tng_allocate_particle_data_mem
4752                 (const tng_trajectory_t tng_data,
4753                  const tng_data_t data,
4754                  int64_t n_frames,
4755                  const int64_t stride_length,
4756                  const int64_t n_particles,
4757                  const int64_t n_values_per_frame)
4758 {
4759     void ***values;
4760     int64_t i, j, k, size, frame_alloc;
4761     (void)tng_data;
4762
4763     if(n_particles == 0 || n_values_per_frame == 0)
4764     {
4765         return(TNG_FAILURE);
4766     }
4767
4768     if(data->strings && data->datatype == TNG_CHAR_DATA)
4769     {
4770         for(i = 0; i < data->n_frames; i++)
4771         {
4772             for(j = 0; j < n_particles; j++)
4773             {
4774                 for(k = 0; k < data->n_values_per_frame; k++)
4775                 {
4776                     if(data->strings[i][j][k])
4777                     {
4778                         free(data->strings[i][j][k]);
4779                     }
4780                 }
4781                 free(data->strings[i][j]);
4782             }
4783             free(data->strings[i]);
4784         }
4785         free(data->strings);
4786     }
4787     data->n_frames = n_frames;
4788     n_frames = tng_max_i64(1, n_frames);
4789     data->stride_length = tng_max_i64(1, stride_length);
4790     data->n_values_per_frame = n_values_per_frame;
4791     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
4792
4793     if(data->datatype == TNG_CHAR_DATA)
4794     {
4795         data->strings = malloc(sizeof(char ***) * frame_alloc);
4796         for(i = 0; i < frame_alloc; i++)
4797         {
4798             data->strings[i] = malloc(sizeof(char **) *
4799                                     n_particles);
4800             if(!data->strings[i])
4801             {
4802                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
4803                     sizeof(union data_values *) * n_particles,
4804                     __FILE__, __LINE__);
4805                 return(TNG_CRITICAL);
4806             }
4807             for(j = 0; j < n_particles; j++)
4808             {
4809                 data->strings[i][j] = malloc(sizeof(char *) *
4810                                             n_values_per_frame);
4811                 if(!data->strings[i][j])
4812                 {
4813                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
4814                         sizeof(union data_values) * n_values_per_frame,
4815                         __FILE__, __LINE__);
4816                     return(TNG_CRITICAL);
4817                 }
4818                 for(k = 0; k < n_values_per_frame; k++)
4819                 {
4820                     data->strings[i][j][k] = 0;
4821                 }
4822             }
4823         }
4824     }
4825     else
4826     {
4827         switch(data->datatype)
4828         {
4829         case TNG_INT_DATA:
4830             size = sizeof(int64_t);
4831             break;
4832         case TNG_FLOAT_DATA:
4833             size = sizeof(float);
4834             break;
4835         case TNG_DOUBLE_DATA:
4836         default:
4837             size = sizeof(double);
4838         }
4839
4840         values = realloc(data->values,
4841                          size * frame_alloc *
4842                          n_particles * n_values_per_frame);
4843         if(!values)
4844         {
4845             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4846                    size * frame_alloc *
4847                    n_particles * n_values_per_frame,
4848                    __FILE__, __LINE__);
4849             free(data->values);
4850             data->values = 0;
4851             return(TNG_CRITICAL);
4852         }
4853         data->values = values;
4854     }
4855     return(TNG_SUCCESS);
4856 }
4857
4858 static tng_function_status tng_particle_data_find
4859                 (const tng_trajectory_t tng_data,
4860                  const int64_t id,
4861                  tng_data_t *data)
4862 {
4863     int64_t block_index, i;
4864     tng_trajectory_frame_set_t frame_set = &tng_data->
4865                                            current_trajectory_frame_set;
4866     char block_type_flag;
4867
4868     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4869        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4870     {
4871         block_type_flag = TNG_TRAJECTORY_BLOCK;
4872     }
4873     else
4874     {
4875         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4876     }
4877
4878     block_index = -1;
4879     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4880     {
4881         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
4882         {
4883             *data = &frame_set->tr_particle_data[i];
4884             if((*data)->block_id == id)
4885             {
4886                 block_index = i;
4887                 break;
4888             }
4889         }
4890     }
4891     else
4892     {
4893         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
4894         {
4895             *data = &tng_data->non_tr_particle_data[i];
4896             if((*data)->block_id == id)
4897             {
4898                 block_index = i;
4899                 break;
4900             }
4901         }
4902     }
4903     if(block_index == -1)
4904     {
4905         return(TNG_FAILURE);
4906     }
4907     return(TNG_SUCCESS);
4908 }
4909
4910 static tng_function_status tng_data_find
4911                 (const tng_trajectory_t tng_data,
4912                  const int64_t id,
4913                  tng_data_t *data)
4914 {
4915     int64_t block_index, i;
4916     tng_trajectory_frame_set_t frame_set = &tng_data->
4917                                            current_trajectory_frame_set;
4918     char block_type_flag;
4919
4920     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4921        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4922     {
4923         block_type_flag = TNG_TRAJECTORY_BLOCK;
4924     }
4925     else
4926     {
4927         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4928     }
4929
4930     block_index = -1;
4931     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4932     {
4933         for(i = 0; i < frame_set->n_data_blocks; i++)
4934         {
4935             *data = &frame_set->tr_data[i];
4936             if((*data)->block_id == id)
4937             {
4938                 block_index = i;
4939                 break;
4940             }
4941         }
4942         if(block_index == -1)
4943         {
4944             for(i = 0; i < tng_data->n_data_blocks; i++)
4945             {
4946                 *data = &tng_data->non_tr_data[i];
4947                 if((*data)->block_id == id)
4948                 {
4949                     block_index = i;
4950                     break;
4951                 }
4952             }
4953         }
4954     }
4955     else
4956     {
4957         for(i = 0; i < tng_data->n_data_blocks; i++)
4958         {
4959             *data = &tng_data->non_tr_data[i];
4960             if((*data)->block_id == id)
4961             {
4962                 block_index = i;
4963                 break;
4964             }
4965         }
4966     }
4967     if(block_index == -1)
4968     {
4969         return(TNG_FAILURE);
4970     }
4971     return(TNG_SUCCESS);
4972 }
4973
4974 static tng_function_status tng_data_block_len_calculate
4975                 (const tng_trajectory_t tng_data,
4976                  const tng_data_t data,
4977                  const tng_bool is_particle_data,
4978                  const int64_t n_frames,
4979                  const int64_t frame_step,
4980                  const int64_t stride_length,
4981                  const int64_t num_first_particle,
4982                  const int64_t n_particles,
4983                  int64_t *data_start_pos,
4984                  int64_t *len)
4985 {
4986     int size;
4987     int64_t i, j, k;
4988     char ***first_dim_values, **second_dim_values;
4989     (void)tng_data;
4990
4991     if(data == 0)
4992     {
4993         return(TNG_SUCCESS);
4994     }
4995
4996     switch(data->datatype)
4997     {
4998     case TNG_CHAR_DATA:
4999         size = 1;
5000         break;
5001     case TNG_INT_DATA:
5002         size = sizeof(int64_t);
5003         break;
5004     case TNG_FLOAT_DATA:
5005         size = sizeof(float);
5006         break;
5007     case TNG_DOUBLE_DATA:
5008     default:
5009         size = sizeof(double);
5010     }
5011
5012     *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
5013            sizeof(data->codec_id);
5014     if(is_particle_data)
5015     {
5016         *len += sizeof(num_first_particle) + sizeof(n_particles);
5017     }
5018
5019     if(stride_length > 1)
5020     {
5021         *len += sizeof(data->first_frame_with_data) +
5022                 sizeof(data->stride_length);
5023     }
5024
5025     if(data->codec_id != TNG_UNCOMPRESSED)
5026     {
5027         *len += sizeof(data->compression_multiplier);
5028     }
5029
5030     if(data->dependency & TNG_FRAME_DEPENDENT)
5031     {
5032         *len += sizeof(char);
5033     }
5034
5035     *data_start_pos = *len;
5036
5037     if(data->datatype == TNG_CHAR_DATA)
5038     {
5039         if(is_particle_data)
5040         {
5041             for(i = 0; i < n_frames; i++)
5042             {
5043                 first_dim_values = data->strings[i];
5044                 for(j = num_first_particle; j < num_first_particle + n_particles;
5045                     j++)
5046                 {
5047                     second_dim_values = first_dim_values[j];
5048                     for(k = 0; k < data->n_values_per_frame; k++)
5049                     {
5050                         *len += strlen(second_dim_values[k]) + 1;
5051                     }
5052                 }
5053             }
5054         }
5055         else
5056         {
5057             for(i = 0; i < n_frames; i++)
5058             {
5059                 second_dim_values = data->strings[0][i];
5060                 for(j = 0; j < data->n_values_per_frame; j++)
5061                 {
5062                     *len += strlen(second_dim_values[j]) + 1;
5063                 }
5064             }
5065         }
5066     }
5067     else
5068     {
5069         *len += size * frame_step * n_particles * data->n_values_per_frame;
5070     }
5071
5072     return(TNG_SUCCESS);
5073 }
5074
5075 /* TEST: */
5076 /**
5077  * @brief Create a non-particle data block
5078  * @param tng_data is a trajectory data container.
5079  * @param block_type_flag specifies if this is a trajectory block or a
5080  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
5081  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5082  * error has occured.
5083  */
5084 static tng_function_status tng_data_block_create
5085                 (const tng_trajectory_t tng_data,
5086                  const char block_type_flag)
5087 {
5088     tng_trajectory_frame_set_t frame_set =
5089     &tng_data->current_trajectory_frame_set;
5090
5091     tng_data_t data;
5092
5093     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5094     {
5095         frame_set->n_data_blocks++;
5096         data = realloc(frame_set->tr_data, sizeof(struct tng_data) *
5097                        frame_set->n_data_blocks);
5098         if(!data)
5099         {
5100             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
5101                 sizeof(struct tng_data) * frame_set->n_data_blocks,
5102                 __FILE__, __LINE__);
5103             free(frame_set->tr_data);
5104             frame_set->tr_data = 0;
5105             return(TNG_CRITICAL);
5106         }
5107         frame_set->tr_data = data;
5108     }
5109     else
5110     {
5111         tng_data->n_data_blocks++;
5112         data = realloc(tng_data->non_tr_data, sizeof(struct tng_data) *
5113                         tng_data->n_data_blocks);
5114         if(!data)
5115         {
5116             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
5117                 sizeof(struct tng_data) * tng_data->n_data_blocks,
5118                 __FILE__, __LINE__);
5119             free(tng_data->non_tr_data);
5120             tng_data->non_tr_data = 0;
5121             return(TNG_CRITICAL);
5122         }
5123         tng_data->non_tr_data = data;
5124     }
5125
5126     return(TNG_SUCCESS);
5127 }
5128
5129 /* TEST: */
5130 /**
5131  * @brief Allocate memory for storing non-particle data.
5132  * The allocated block will be refered to by data->values.
5133  * @param tng_data is a trajectory data container.
5134  * @param data is the data struct, which will contain the allocated memory in
5135  * data->values.
5136  * @param n_frames is the number of frames of data to store.
5137  * @param n_values_per_frame is the number of data values per frame.
5138  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5139  * error has occured.
5140  */
5141 static tng_function_status tng_allocate_data_mem
5142                 (const tng_trajectory_t tng_data,
5143                  const tng_data_t data,
5144                  int64_t n_frames,
5145                  const int64_t stride_length,
5146                  const int64_t n_values_per_frame)
5147 {
5148     void **values;
5149     int64_t i, j, size, frame_alloc;
5150     (void)tng_data;
5151
5152     if(n_values_per_frame == 0)
5153     {
5154         return(TNG_FAILURE);
5155     }
5156
5157     if(data->strings && data->datatype == TNG_CHAR_DATA)
5158     {
5159         for(i = 0; i < data->n_frames; i++)
5160         {
5161             for(j = 0; j < data->n_values_per_frame; j++)
5162             {
5163                 if(data->strings[0][i][j])
5164                 {
5165                     free(data->strings[0][i][j]);
5166                     data->strings[0][i][j] = 0;
5167                 }
5168             }
5169             free(data->strings[0][i]);
5170             data->strings[0][i] = 0;
5171         }
5172         free(data->strings[0]);
5173         data->strings[0] = 0;
5174         free(data->strings);
5175     }
5176     data->n_frames = n_frames;
5177     data->stride_length = tng_max_i64(1, stride_length);
5178     n_frames = tng_max_i64(1, n_frames);
5179     data->n_values_per_frame = n_values_per_frame;
5180     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5181
5182     if(data->datatype == TNG_CHAR_DATA)
5183     {
5184         data->strings = malloc(sizeof(char ***));
5185         data->strings[0] = malloc(sizeof(char **) * frame_alloc);
5186         for(i = 0; i < frame_alloc; i++)
5187         {
5188             data->strings[0][i] = malloc(sizeof(char *) * n_values_per_frame);
5189             if(!data->strings[0][i])
5190             {
5191                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5192                        n_values_per_frame,
5193                        __FILE__, __LINE__);
5194                 return(TNG_CRITICAL);
5195             }
5196             for(j = 0; j < n_values_per_frame; j++)
5197             {
5198                 data->strings[0][i][j] = 0;
5199             }
5200         }
5201     }
5202     else
5203     {
5204         switch(data->datatype)
5205         {
5206         case TNG_INT_DATA:
5207             size = sizeof(int64_t);
5208             break;
5209         case TNG_FLOAT_DATA:
5210             size = sizeof(float);
5211             break;
5212         case TNG_DOUBLE_DATA:
5213         default:
5214             size = sizeof(double);
5215         }
5216
5217         values = realloc(data->values,
5218                          size * frame_alloc *
5219                          n_values_per_frame);
5220         if(!values)
5221         {
5222             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5223                    size * frame_alloc *
5224                    n_values_per_frame,
5225                    __FILE__, __LINE__);
5226             free(data->values);
5227             data->values = 0;
5228             return(TNG_CRITICAL);
5229         }
5230         data->values = values;
5231     }
5232
5233     return(TNG_SUCCESS);
5234 }
5235
5236 /**
5237  * @brief Read the values of a data block
5238  * @param tng_data is a trajectory data container.
5239  * @param block is the block to store the data (should already contain
5240  * the block headers and the block contents).
5241  * @param block_data_len is the length of the data contents of the block.
5242  * @param datatype is the type of data of the data block (char, int, float or
5243  * double).
5244  * @param num_first_particle is the number of the first particle in the data
5245  * block. This should be the same as in the corresponding particle mapping
5246  * block. Only used if reading particle dependent data.
5247  * @param n_particles is the number of particles in the data block. This should
5248  * be the same as in the corresponding particle mapping block. Only used if
5249  * reading particle dependent data.
5250  * @param first_frame_with_data is the frame number of the first frame with data
5251  * in this data block.
5252  * @param stride_length is the number of frames between each data entry.
5253  * @param n_frames is the number of frames in this data block.
5254  * @param n_values is the number of values per frame stored in this data block.
5255  * @param codec_id is the ID of the codec to compress the data.
5256  * @param multiplier is the multiplication factor applied to each data value
5257  * before compression. This factor is applied since some compression algorithms
5258  * work only on integers.
5259  * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
5260  * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
5261  * if hash_mode == TNG_USE_HASH.
5262  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5263  * error has occured.
5264  */
5265 static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
5266                                          const tng_gen_block_t block,
5267                                          const int64_t block_data_len,
5268                                          const char datatype,
5269                                          const int64_t num_first_particle,
5270                                          const int64_t n_particles,
5271                                          const int64_t first_frame_with_data,
5272                                          const int64_t stride_length,
5273                                          int64_t n_frames,
5274                                          const int64_t n_values,
5275                                          const int64_t codec_id,
5276                                          const double multiplier,
5277                                          const char hash_mode,
5278                                          md5_state_t *md5_state)
5279 {
5280     int64_t i, j, k, tot_n_particles, n_frames_div, offset;
5281     int64_t full_data_len;
5282     int size, len;
5283     char ***first_dim_values, **second_dim_values;
5284     tng_data_t data;
5285     tng_trajectory_frame_set_t frame_set =
5286     &tng_data->current_trajectory_frame_set;
5287     char block_type_flag, *contents;
5288     tng_bool is_particle_data;
5289     tng_function_status stat;
5290
5291 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
5292
5293     /* This must be caught early to avoid creating a data block if not necessary. */
5294 #ifndef USE_ZLIB
5295     if(codec_id == TNG_GZIP_COMPRESSION)
5296     {
5297         fprintf(stderr, "TNG library: Cannot uncompress data block. %s: %d\n", __FILE__,
5298                 __LINE__);
5299         return(TNG_FAILURE);
5300     }
5301 #endif
5302
5303     switch(datatype)
5304     {
5305     case TNG_CHAR_DATA:
5306         size = 1;
5307         break;
5308     case TNG_INT_DATA:
5309         size = sizeof(int64_t);
5310         break;
5311     case TNG_FLOAT_DATA:
5312         size = sizeof(float);
5313         break;
5314     case TNG_DOUBLE_DATA:
5315     default:
5316         size = sizeof(double);
5317     }
5318
5319     if(n_particles > 0)
5320     {
5321         is_particle_data = TNG_TRUE;
5322     }
5323     else
5324     {
5325         if(codec_id == TNG_XTC_COMPRESSION || codec_id == TNG_TNG_COMPRESSION)
5326         {
5327             fprintf(stderr, "TNG library: Cannot uncompress data block. %s: %d\n", __FILE__,
5328                     __LINE__);
5329             return(TNG_FAILURE);
5330         }
5331         is_particle_data = TNG_FALSE;
5332     }
5333
5334     if(is_particle_data == TNG_TRUE)
5335     {
5336         stat = tng_particle_data_find(tng_data, block->id, &data);
5337     }
5338     else
5339     {
5340         stat = tng_data_find(tng_data, block->id, &data);
5341     }
5342
5343     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5344     {
5345         block_type_flag = TNG_TRAJECTORY_BLOCK;
5346     }
5347     else
5348     {
5349         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5350     }
5351
5352     /* If the block does not exist, create it */
5353     if(stat != TNG_SUCCESS)
5354     {
5355         if(is_particle_data == TNG_TRUE)
5356         {
5357             stat = tng_particle_data_block_create(tng_data, block_type_flag);
5358         }
5359         else
5360         {
5361             stat = tng_data_block_create(tng_data, block_type_flag);
5362         }
5363
5364         if(stat != TNG_SUCCESS)
5365         {
5366             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
5367                    __FILE__, __LINE__);
5368             return(TNG_CRITICAL);
5369         }
5370
5371         if(is_particle_data == TNG_TRUE)
5372         {
5373             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5374             {
5375                 data = &frame_set->tr_particle_data[frame_set->
5376                                                     n_particle_data_blocks - 1];
5377             }
5378             else
5379             {
5380                 data = &tng_data->non_tr_particle_data[tng_data->
5381                                                        n_particle_data_blocks - 1];
5382             }
5383         }
5384         else
5385         {
5386             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5387             {
5388                 data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
5389             }
5390             else
5391             {
5392                 data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
5393             }
5394         }
5395
5396         data->block_id = block->id;
5397
5398         data->block_name = malloc(strlen(block->name) + 1);
5399         if(!data->block_name)
5400         {
5401             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
5402                    (unsigned int)strlen(block->name)+1, __FILE__, __LINE__);
5403             return(TNG_CRITICAL);
5404         }
5405         strcpy(data->block_name, block->name);
5406
5407         data->datatype = datatype;
5408
5409         data->values = 0;
5410         /* FIXME: Memory leak from strings. */
5411         data->strings = 0;
5412         data->n_frames = 0;
5413         data->dependency = 0;
5414         if(is_particle_data == TNG_TRUE)
5415         {
5416             data->dependency += TNG_PARTICLE_DEPENDENT;
5417         }
5418         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
5419                               (n_frames > 1 ||
5420                                frame_set->n_frames == n_frames ||
5421                                stride_length > 1))
5422         {
5423             data->dependency += TNG_FRAME_DEPENDENT;
5424         }
5425         data->codec_id = codec_id;
5426         data->compression_multiplier = multiplier;
5427         data->last_retrieved_frame = -1;
5428     }
5429
5430     if(is_particle_data == TNG_TRUE)
5431     {
5432         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
5433            tng_data->var_num_atoms_flag)
5434         {
5435             tot_n_particles = frame_set->n_particles;
5436         }
5437         else
5438         {
5439             tot_n_particles = tng_data->n_particles;
5440         }
5441     }
5442     /* If there are no particles in this data block, still set tot_n_particles = 1
5443      * to calculate block lengths etc properly. */
5444     else
5445     {
5446         tot_n_particles = 1;
5447     }
5448
5449     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5450
5451     contents = malloc(block_data_len);
5452     if(!contents)
5453     {
5454         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5455                 block_data_len, __FILE__, __LINE__);
5456         return(TNG_CRITICAL);
5457     }
5458
5459     if(fread(contents, block_data_len, 1, tng_data->input_file) == 0)
5460     {
5461         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
5462         return(TNG_CRITICAL);
5463     }
5464
5465     if(hash_mode == TNG_USE_HASH)
5466     {
5467         md5_append(md5_state, (md5_byte_t *)contents, block_data_len);
5468     }
5469
5470     if(codec_id != TNG_UNCOMPRESSED)
5471     {
5472         full_data_len = n_frames_div * size * n_values;
5473         if(is_particle_data == TNG_TRUE)
5474         {
5475             full_data_len *= n_particles;
5476         }
5477         switch(codec_id)
5478         {
5479         case TNG_XTC_COMPRESSION:
5480             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5481             break;
5482         case TNG_TNG_COMPRESSION:
5483 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5484             if(tng_uncompress(tng_data, block, datatype,
5485                               &contents, full_data_len) != TNG_SUCCESS)
5486             {
5487                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5488                        __FILE__, __LINE__);
5489                 free(contents);
5490                 return(TNG_CRITICAL);
5491             }
5492 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5493             break;
5494 #ifdef USE_ZLIB
5495         case TNG_GZIP_COMPRESSION:
5496     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
5497             if(tng_gzip_uncompress(tng_data, &contents,
5498                                    block_data_len, full_data_len) != TNG_SUCCESS)
5499             {
5500                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5501                     __LINE__);
5502                 free(contents);
5503                 return(TNG_CRITICAL);
5504             }
5505     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
5506             break;
5507 #endif
5508         }
5509     }
5510     else
5511     {
5512         full_data_len = block_data_len;
5513     }
5514
5515     /* Allocate memory */
5516     if(!data->values || data->n_frames != n_frames ||
5517        data->n_values_per_frame != n_values)
5518     {
5519         if(is_particle_data == TNG_TRUE)
5520         {
5521             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
5522                                                   stride_length,
5523                                                   tot_n_particles, n_values);
5524         }
5525         else
5526         {
5527             stat = tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
5528                                          n_values);
5529         }
5530         if(stat != TNG_SUCCESS)
5531         {
5532             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
5533                    __FILE__, __LINE__);
5534             free(contents);
5535             return(TNG_CRITICAL);
5536         }
5537     }
5538
5539     data->first_frame_with_data = first_frame_with_data;
5540
5541     if(datatype == TNG_CHAR_DATA)
5542     {
5543         offset = 0;
5544         /* Strings are stores slightly differently if the data block contains particle
5545          * data (frames * particles * n_values) or not (frames * n_values). */
5546         if(is_particle_data == TNG_TRUE)
5547         {
5548             for(i = 0; i < n_frames_div; i++)
5549             {
5550                 first_dim_values = data->strings[i];
5551                 for(j = num_first_particle; j < num_first_particle + n_particles;
5552                     j++)
5553                 {
5554                     second_dim_values = first_dim_values[j];
5555                     for(k = 0; k < n_values; k++)
5556                     {
5557                         len = tng_min_size(strlen(contents+offset) + 1,
5558                                   TNG_MAX_STR_LEN);
5559                         if(second_dim_values[k])
5560                         {
5561                             free(second_dim_values[k]);
5562                         }
5563                         second_dim_values[k] = malloc(len);
5564                         if(!second_dim_values[k])
5565                         {
5566                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5567                                 len, __FILE__, __LINE__);
5568                             free(contents);
5569                             return(TNG_CRITICAL);
5570                         }
5571                         strncpy(second_dim_values[k], contents+offset, len);
5572                         offset += len;
5573                     }
5574                 }
5575             }
5576         }
5577         else
5578         {
5579             for(i = 0; i < n_frames_div; i++)
5580             {
5581                 for(j = 0; j < n_values; j++)
5582                 {
5583                     len = tng_min_size(strlen(contents+offset) + 1,
5584                                      TNG_MAX_STR_LEN);
5585                     if(data->strings[0][i][j])
5586                     {
5587                         free(data->strings[0][i][j]);
5588                     }
5589                     data->strings[0][i][j] = malloc(len);
5590                     if(!data->strings[0][i][j])
5591                     {
5592                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5593                                len, __FILE__, __LINE__);
5594                         free(contents);
5595                         return(TNG_CRITICAL);
5596                     }
5597                     strncpy(data->strings[0][i][j], contents+offset, len);
5598                     offset += len;
5599                 }
5600             }
5601         }
5602     }
5603     else
5604     {
5605         if(is_particle_data)
5606         {
5607             memcpy((char *)data->values + n_frames_div * size * n_values *
5608                    num_first_particle, contents, full_data_len);
5609         }
5610         else
5611         {
5612             memcpy(data->values, contents, full_data_len);
5613         }
5614         /* Endianness is handled by the TNG compression library. TNG compressed blocks are always written
5615          * as little endian by the compression library. */
5616         if(codec_id != TNG_TNG_COMPRESSION)
5617         {
5618             switch(datatype)
5619             {
5620             case TNG_FLOAT_DATA:
5621                 if(tng_data->input_endianness_swap_func_32)
5622                 {
5623                     for(i = 0; i < full_data_len; i+=size)
5624                     {
5625                         if(tng_data->input_endianness_swap_func_32(tng_data,
5626                             (int32_t *)((char *)data->values + i))
5627                             != TNG_SUCCESS)
5628                         {
5629                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5630                                     __FILE__, __LINE__);
5631                         }
5632                     }
5633                 }
5634                 break;
5635             case TNG_INT_DATA:
5636             case TNG_DOUBLE_DATA:
5637                 if(tng_data->input_endianness_swap_func_64)
5638                 {
5639                     for(i = 0; i < full_data_len; i+=size)
5640                     {
5641                         if(tng_data->input_endianness_swap_func_64(tng_data,
5642                             (int64_t *)((char *)data->values + i))
5643                             != TNG_SUCCESS)
5644                         {
5645                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5646                                     __FILE__, __LINE__);
5647                         }
5648                     }
5649                 }
5650                 break;
5651             case TNG_CHAR_DATA:
5652                 break;
5653             }
5654         }
5655     }
5656
5657     free(contents);
5658
5659     return(TNG_SUCCESS);
5660 }
5661
5662 /**
5663  * @brief Write a data block (particle or non-particle data)
5664  * @param tng_data is a trajectory data container.
5665  * @param block is the block to store the data (should already contain
5666  * the block headers and the block contents).
5667  * @param block_index is the index number of the data block in the frame set.
5668  * @param is_particle_data is a flag to specify if the data to write is
5669  * particle dependent or not.
5670  * @param mapping is the particle mapping that is relevant for the data block.
5671  * Only relevant if writing particle dependent data.
5672  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5673  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5674  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5675  * error has occured.
5676  */
5677 static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
5678                                                 const tng_gen_block_t block,
5679                                                 const int64_t block_index,
5680                                                 const tng_bool is_particle_data,
5681                                                 const tng_particle_mapping_t mapping,
5682                                                 const char hash_mode)
5683 {
5684     int64_t n_particles, num_first_particle, n_frames, stride_length;
5685     int64_t full_data_len, block_data_len, frame_step, data_start_pos;
5686     int64_t i, j, k, curr_file_pos, header_file_pos;
5687     int size;
5688     size_t len;
5689     tng_function_status stat;
5690     char temp, *temp_name, ***first_dim_values, **second_dim_values, *contents;
5691     double multiplier;
5692     tng_trajectory_frame_set_t frame_set =
5693     &tng_data->current_trajectory_frame_set;
5694     tng_data_t data;
5695     char block_type_flag;
5696     md5_state_t md5_state;
5697
5698     /* If we have already started writing frame sets it is too late to write
5699      * non-trajectory data blocks */
5700     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5701     {
5702         block_type_flag = TNG_TRAJECTORY_BLOCK;
5703     }
5704     else
5705     {
5706         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5707     }
5708
5709     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5710     {
5711         return(TNG_CRITICAL);
5712     }
5713
5714     if(is_particle_data == TNG_TRUE)
5715     {
5716         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5717         {
5718             data = &frame_set->tr_particle_data[block_index];
5719
5720             /* If this data block has not had any data added in this frame set
5721              * do not write it. */
5722             if(data->first_frame_with_data < frame_set->first_frame)
5723             {
5724                 return(TNG_SUCCESS);
5725             }
5726
5727             stride_length = tng_max_i64(1, data->stride_length);
5728         }
5729         else
5730         {
5731             data = &tng_data->non_tr_particle_data[block_index];
5732             stride_length = 1;
5733         }
5734     }
5735     else
5736     {
5737         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5738         {
5739             data = &frame_set->tr_data[block_index];
5740
5741             /* If this data block has not had any data added in this frame set
5742              * do not write it. */
5743             if(data->first_frame_with_data < frame_set->first_frame)
5744             {
5745                 return(TNG_SUCCESS);
5746             }
5747
5748             stride_length = tng_max_i64(1, data->stride_length);
5749         }
5750         else
5751         {
5752             data = &tng_data->non_tr_data[block_index];
5753             stride_length = 1;
5754         }
5755     }
5756
5757     switch(data->datatype)
5758     {
5759     case TNG_CHAR_DATA:
5760         size = 1;
5761         break;
5762     case TNG_INT_DATA:
5763         size = sizeof(int64_t);
5764         break;
5765     case TNG_FLOAT_DATA:
5766         size = sizeof(float);
5767         break;
5768     case TNG_DOUBLE_DATA:
5769     default:
5770         size = sizeof(double);
5771     }
5772
5773     len = strlen(data->block_name) + 1;
5774
5775     if(!block->name || strlen(block->name) < len)
5776     {
5777         temp_name = realloc(block->name, len);
5778         if(!temp_name)
5779         {
5780             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n", len+1,
5781                    __FILE__, __LINE__);
5782             free(block->name);
5783             block->name = 0;
5784             return(TNG_CRITICAL);
5785         }
5786         block->name = temp_name;
5787     }
5788     strncpy(block->name, data->block_name, len);
5789     block->id = data->block_id;
5790
5791     /* If writing frame independent data data->n_frames is 0, but n_frames
5792        is used for the loop writing the data (and reserving memory) and needs
5793        to be at least 1 */
5794     n_frames = tng_max_i64(1, data->n_frames);
5795
5796     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5797     {
5798         /* If the frame set is finished before writing the full number of frames
5799            make sure the data block is not longer than the frame set. */
5800         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5801
5802         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5803     }
5804
5805     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
5806                  n_frames / stride_length;
5807
5808     /* TNG compression will use compression precision to get integers from
5809      * floating point data. The compression multiplier stores that information
5810      * to be able to return the precision of the compressed data. */
5811     if(data->codec_id == TNG_TNG_COMPRESSION)
5812     {
5813         data->compression_multiplier = tng_data->compression_precision;
5814     }
5815     /* Uncompressed data blocks do not use compression multipliers at all.
5816      * GZip compression does not need it either. */
5817     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
5818     {
5819         data->compression_multiplier = 1.0;
5820     }
5821
5822     if(data->dependency & TNG_PARTICLE_DEPENDENT)
5823     {
5824         if(mapping && mapping->n_particles != 0)
5825         {
5826             n_particles = mapping->n_particles;
5827             num_first_particle = mapping->num_first_particle;
5828         }
5829         else
5830         {
5831             num_first_particle = 0;
5832             if(tng_data->var_num_atoms_flag)
5833             {
5834                 n_particles = frame_set->n_particles;
5835             }
5836             else
5837             {
5838                 n_particles = tng_data->n_particles;
5839             }
5840         }
5841     }
5842
5843     if(data->dependency & TNG_PARTICLE_DEPENDENT)
5844     {
5845         if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
5846                                         frame_step, stride_length, num_first_particle,
5847                                         n_particles, &data_start_pos,
5848                                         &block->block_contents_size) != TNG_SUCCESS)
5849         {
5850             fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
5851                     __FILE__, __LINE__);
5852             return(TNG_CRITICAL);
5853         }
5854     }
5855     else
5856     {
5857         if(tng_data_block_len_calculate(tng_data, data, TNG_FALSE, n_frames,
5858                                         frame_step, stride_length, 0,
5859                                         1, &data_start_pos,
5860                                         &block->block_contents_size) != TNG_SUCCESS)
5861         {
5862             fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
5863                     __FILE__, __LINE__);
5864             return(TNG_CRITICAL);
5865         }
5866     }
5867
5868     header_file_pos = ftello(tng_data->output_file);
5869
5870     if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
5871     {
5872         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
5873                tng_data->output_file_path, __FILE__, __LINE__);
5874         return(TNG_CRITICAL);
5875     }
5876
5877     if(hash_mode == TNG_USE_HASH)
5878     {
5879         md5_init(&md5_state);
5880     }
5881
5882     if(tng_file_output_numerical(tng_data, &data->datatype,
5883                                  sizeof(data->datatype),
5884                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5885     {
5886         return(TNG_CRITICAL);
5887     }
5888
5889     if(tng_file_output_numerical(tng_data, &data->dependency,
5890                                  sizeof(data->dependency),
5891                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5892     {
5893         return(TNG_CRITICAL);
5894     }
5895
5896     if(data->dependency & TNG_FRAME_DEPENDENT)
5897     {
5898         if(stride_length > 1)
5899         {
5900             temp = 1;
5901         }
5902         else
5903         {
5904             temp = 0;
5905         }
5906         if(tng_file_output_numerical(tng_data, &temp,
5907                                     sizeof(temp),
5908                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5909         {
5910             return(TNG_CRITICAL);
5911         }
5912     }
5913
5914     if(tng_file_output_numerical(tng_data, &data->n_values_per_frame,
5915                                  sizeof(data->n_values_per_frame),
5916                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5917     {
5918         return(TNG_CRITICAL);
5919     }
5920
5921     if(tng_file_output_numerical(tng_data, &data->codec_id,
5922                                  sizeof(data->codec_id),
5923                                  hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5924     {
5925         return(TNG_CRITICAL);
5926     }
5927
5928     if(data->codec_id != TNG_UNCOMPRESSED)
5929     {
5930         if(tng_file_output_numerical(tng_data, &data->compression_multiplier,
5931                                     sizeof(data->compression_multiplier),
5932                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5933         {
5934             return(TNG_CRITICAL);
5935         }
5936     }
5937
5938     if(data->n_frames > 0 && stride_length > 1)
5939     {
5940         /* FIXME: first_frame_with_data is not reliably set */
5941         if(data->first_frame_with_data == 0)
5942         {
5943             data->first_frame_with_data = frame_set->first_frame;
5944         }
5945         if(tng_file_output_numerical(tng_data, &data->first_frame_with_data,
5946                                     sizeof(data->first_frame_with_data),
5947                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5948         {
5949             return(TNG_CRITICAL);
5950         }
5951
5952         if(tng_file_output_numerical(tng_data, &stride_length,
5953                                     sizeof(stride_length),
5954                                     hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5955         {
5956             return(TNG_CRITICAL);
5957         }
5958     }
5959
5960     if(data->dependency & TNG_PARTICLE_DEPENDENT)
5961     {
5962         if(tng_file_output_numerical(tng_data, &num_first_particle,
5963                                      sizeof(num_first_particle),
5964                                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5965         {
5966             return(TNG_CRITICAL);
5967         }
5968
5969         if(tng_file_output_numerical(tng_data, &n_particles,
5970                                      sizeof(n_particles),
5971                                      hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5972         {
5973             return(TNG_CRITICAL);
5974         }
5975     }
5976
5977     if(data->datatype == TNG_CHAR_DATA)
5978     {
5979         if(data->strings)
5980         {
5981             if(data->dependency & TNG_PARTICLE_DEPENDENT)
5982             {
5983                 for(i = 0; i < frame_step; i++)
5984                 {
5985                     first_dim_values = data->strings[i];
5986                     for(j = num_first_particle; j < num_first_particle + n_particles;
5987                         j++)
5988                     {
5989                         second_dim_values = first_dim_values[j];
5990                         for(k = 0; k < data->n_values_per_frame; k++)
5991                         {
5992                             if(tng_fwritestr(tng_data, second_dim_values[k],
5993                                             hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5994                             {
5995                                 return(TNG_CRITICAL);
5996                             }
5997                         }
5998                     }
5999                 }
6000             }
6001             else
6002             {
6003                 for(i = 0; i < frame_step; i++)
6004                 {
6005                     for(j = 0; j < data->n_values_per_frame; j++)
6006                     {
6007                         if(tng_fwritestr(tng_data, data->strings[0][i][j],
6008                                          hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
6009                         {
6010                             return(TNG_CRITICAL);
6011                         }
6012                     }
6013                 }
6014             }
6015         }
6016     }
6017     else
6018     {
6019         if(data->dependency & TNG_PARTICLE_DEPENDENT)
6020         {
6021             full_data_len = size * frame_step * n_particles * data->n_values_per_frame;
6022         }
6023         else
6024         {
6025             full_data_len = size * frame_step * data->n_values_per_frame;
6026         }
6027         contents = malloc(full_data_len);
6028         if(!contents)
6029         {
6030             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6031                     full_data_len, __FILE__, __LINE__);
6032             return(TNG_CRITICAL);
6033         }
6034
6035         if(data->values)
6036         {
6037             memcpy(contents, data->values, full_data_len);
6038             /* If writing TNG compressed data the endianness is taken into account by the compression
6039              * routines. TNG compressed data is always written as little endian. */
6040             if(data->codec_id != TNG_TNG_COMPRESSION)
6041             {
6042                 switch(data->datatype)
6043                 {
6044                 case TNG_FLOAT_DATA:
6045                     if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6046                     {
6047                         if(tng_data->output_endianness_swap_func_32)
6048                         {
6049                             for(i = 0; i < full_data_len; i+=size)
6050                             {
6051                                 if(tng_data->output_endianness_swap_func_32(tng_data,
6052                                 (int32_t *)(contents + i))
6053                                 != TNG_SUCCESS)
6054                                 {
6055                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6056                                             __FILE__, __LINE__);
6057                                 }
6058                             }
6059                         }
6060                     }
6061                     else
6062                     {
6063                         multiplier = data->compression_multiplier;
6064                         if(fabs(multiplier - 1.0) > 0.00001 ||
6065                         tng_data->output_endianness_swap_func_32)
6066                         {
6067                             for(i = 0; full_data_len; i+=size)
6068                             {
6069                                 *(float *)(contents + i) *= (float)multiplier;
6070                                 if(tng_data->output_endianness_swap_func_32 &&
6071                                 tng_data->output_endianness_swap_func_32(tng_data,
6072                                 (int32_t *)(contents + i))
6073                                 != TNG_SUCCESS)
6074                                 {
6075                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6076                                             __FILE__, __LINE__);
6077                                 }
6078                             }
6079                         }
6080                     }
6081                     break;
6082                 case TNG_INT_DATA:
6083                     if(tng_data->output_endianness_swap_func_64)
6084                     {
6085                         for(i = 0; i < full_data_len; i+=size)
6086                         {
6087                             if(tng_data->output_endianness_swap_func_64(tng_data,
6088                             (int64_t *)(contents + i))
6089                             != TNG_SUCCESS)
6090                             {
6091                                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6092                                         __FILE__, __LINE__);
6093                             }
6094                         }
6095                     }
6096                     break;
6097                 case TNG_DOUBLE_DATA:
6098                     if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION)
6099                     {
6100                         if(tng_data->output_endianness_swap_func_64)
6101                         {
6102                             for(i = 0; i < full_data_len; i+=size)
6103                             {
6104                                 if(tng_data->output_endianness_swap_func_64(tng_data,
6105                                 (int64_t *)(contents + i))
6106                                 != TNG_SUCCESS)
6107                                 {
6108                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6109                                             __FILE__, __LINE__);
6110                                 }
6111                             }
6112                         }
6113                     }
6114                     else
6115                     {
6116                         multiplier = data->compression_multiplier;
6117                         if(fabs(multiplier - 1.0) > 0.00001 ||
6118                         tng_data->output_endianness_swap_func_64)
6119                         {
6120                             for(i = 0; i < full_data_len; i+=size)
6121                             {
6122                                 *(double *)(contents + i) *= multiplier;
6123                                 if(tng_data->output_endianness_swap_func_64 &&
6124                                 tng_data->output_endianness_swap_func_64(tng_data,
6125                                 (int64_t *)(contents + i))
6126                                 != TNG_SUCCESS)
6127                                 {
6128                                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6129                                             __FILE__, __LINE__);
6130                                 }
6131                             }
6132                         }
6133                     }
6134                     break;
6135                 case TNG_CHAR_DATA:
6136                     break;
6137                 }
6138             }
6139         }
6140         else
6141         {
6142             memset(contents, 0, full_data_len);
6143         }
6144
6145         block_data_len = full_data_len;
6146
6147         switch(data->codec_id)
6148         {
6149         case TNG_XTC_COMPRESSION:
6150             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6151             data->codec_id = TNG_UNCOMPRESSED;
6152             break;
6153         case TNG_TNG_COMPRESSION:
6154             stat = tng_compress(tng_data, block, frame_step,
6155                                 n_particles, data->datatype,
6156                                 &contents, &block_data_len);
6157             if(stat != TNG_SUCCESS)
6158             {
6159                 fprintf(stderr, "TNG library: Could not write TNG compressed block data. %s: %d\n",
6160                     __FILE__, __LINE__);
6161                 if(stat == TNG_CRITICAL)
6162                 {
6163                     return(TNG_CRITICAL);
6164                 }
6165                 /* Set the data again, but with no compression (to write only
6166                  * the relevant data) */
6167                 data->codec_id = TNG_UNCOMPRESSED;
6168                 stat = tng_data_block_write(tng_data, block,
6169                                             block_index, is_particle_data, mapping,
6170                                             hash_mode);
6171                 free(contents);
6172                 return(stat);
6173             }
6174             break;
6175 #ifdef USE_ZLIB
6176         case TNG_GZIP_COMPRESSION:
6177     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6178             stat = tng_gzip_compress(tng_data,
6179                                      &contents,
6180                                      full_data_len,
6181                                      &block_data_len);
6182             if(stat != TNG_SUCCESS)
6183             {
6184                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6185                     __LINE__);
6186                 if(stat == TNG_CRITICAL)
6187                 {
6188                     return(TNG_CRITICAL);
6189                 }
6190                 data->codec_id = TNG_UNCOMPRESSED;
6191             }
6192     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6193             break;
6194 #endif
6195         }
6196         if(block_data_len != full_data_len)
6197         {
6198             block->block_contents_size -= full_data_len - block_data_len;
6199
6200             curr_file_pos = ftello(tng_data->output_file);
6201             fseeko(tng_data->output_file, header_file_pos + sizeof(block->header_contents_size), SEEK_SET);
6202
6203             if(tng_file_output_numerical(tng_data, &block->block_contents_size,
6204                                          sizeof(block->block_contents_size),
6205                                          TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
6206             {
6207                 return(TNG_CRITICAL);
6208             }
6209             fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
6210         }
6211         if(fwrite(contents, block_data_len, 1, tng_data->output_file) != 1)
6212         {
6213             fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6214                     __LINE__);
6215             return(TNG_CRITICAL);
6216         }
6217         if(hash_mode == TNG_USE_HASH)
6218         {
6219             md5_append(&md5_state, (md5_byte_t *)contents, block_data_len);
6220         }
6221
6222         free(contents);
6223     }
6224
6225     if(hash_mode == TNG_USE_HASH)
6226     {
6227         md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
6228         curr_file_pos = ftello(tng_data->output_file);
6229         fseeko(tng_data->output_file, header_file_pos +
6230                 3 * sizeof(int64_t), SEEK_SET);
6231         if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
6232         {
6233             fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
6234                     __LINE__);
6235             return(TNG_CRITICAL);
6236         }
6237         fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
6238     }
6239
6240     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6241     frame_set->n_unwritten_frames = 0;
6242
6243     return(TNG_SUCCESS);
6244 }
6245
6246 /**
6247  * @brief Read the meta information of a data block (particle or non-particle data).
6248  * @param tng_data is a trajectory data container.
6249  * @param datatype is set to the datatype of the data block.
6250  * @param dependency is set to the dependency (particle and/or frame dependent)
6251  * @param sparse_data is set to TRUE if data is not written every frame.
6252  * @param n_values is set to the number of values per frame of the data.
6253  * @param codec_id is set to the ID of the codec used to compress the data.
6254  * @param first_frame_with_data is set to the first frame with data (only relevant if
6255  * sparse_data == TRUE).
6256  * @param stride_length is set to the writing interval of the data (1 if sparse_data
6257  * == FALSE).
6258  * @param num_first_particle is set to the number of the first particle with data written
6259  * in this block.
6260  * @param block_n_particles is set to the number of particles in this data block.
6261  * @param multiplier is set to the compression multiplier.
6262  * @param hash_mode specifies whether to check if the hash matches the contents or not.
6263  * @param md5_state is the md5 hash of the block (only used if hash_mode == TNG_USE_HASH).
6264  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6265  * error has occured.
6266  */
6267 static tng_function_status tng_data_block_meta_information_read
6268                 (const tng_trajectory_t tng_data,
6269                  char *datatype,
6270                  char *dependency,
6271                  char *sparse_data,
6272                  int64_t *n_values,
6273                  int64_t *codec_id,
6274                  int64_t *first_frame_with_data,
6275                  int64_t *stride_length,
6276                  int64_t *n_frames,
6277                  int64_t *num_first_particle,
6278                  int64_t *block_n_particles,
6279                  double *multiplier,
6280                  const char hash_mode,
6281                  md5_state_t *md5_state)
6282 {
6283     if(tng_file_input_numerical(tng_data, datatype,
6284                                 sizeof(*datatype),
6285                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6286     {
6287         return(TNG_CRITICAL);
6288     }
6289
6290     if(tng_file_input_numerical(tng_data, dependency,
6291                                 sizeof(*dependency),
6292                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6293     {
6294         return(TNG_CRITICAL);
6295     }
6296
6297     if(*dependency & TNG_FRAME_DEPENDENT)
6298     {
6299         if(tng_file_input_numerical(tng_data, sparse_data,
6300                                     sizeof(*sparse_data),
6301                                     hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6302         {
6303             return(TNG_CRITICAL);
6304         }
6305     }
6306
6307     if(tng_file_input_numerical(tng_data, n_values,
6308                                 sizeof(*n_values),
6309                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6310     {
6311         return(TNG_CRITICAL);
6312     }
6313
6314     if(tng_file_input_numerical(tng_data, codec_id,
6315                                 sizeof(*codec_id),
6316                                 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6317     {
6318         return(TNG_CRITICAL);
6319     }
6320
6321     if(*codec_id != TNG_UNCOMPRESSED)
6322     {
6323         if(tng_file_input_numerical(tng_data, multiplier,
6324                                     sizeof(*multiplier),
6325                                     hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6326         {
6327             return(TNG_CRITICAL);
6328         }
6329     }
6330     else
6331     {
6332         *multiplier = 1;
6333     }
6334
6335     if(*dependency & TNG_FRAME_DEPENDENT)
6336     {
6337         if(*sparse_data)
6338         {
6339             if(tng_file_input_numerical(tng_data, first_frame_with_data,
6340                                         sizeof(*first_frame_with_data),
6341                                         hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6342             {
6343                 return(TNG_CRITICAL);
6344             }
6345
6346             if(tng_file_input_numerical(tng_data, stride_length,
6347                                         sizeof(*stride_length),
6348                                         hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6349             {
6350                 return(TNG_CRITICAL);
6351             }
6352
6353             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
6354                         (*first_frame_with_data -
6355                         tng_data->current_trajectory_frame_set.first_frame);
6356         }
6357         else
6358         {
6359             *first_frame_with_data = tng_data->current_trajectory_frame_set.first_frame;
6360             *stride_length = 1;
6361             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
6362         }
6363     }
6364     else
6365     {
6366         *first_frame_with_data = 0;
6367         *stride_length = 1;
6368         *n_frames = 1;
6369     }
6370
6371     if (*dependency & TNG_PARTICLE_DEPENDENT)
6372     {
6373         if(tng_file_input_numerical(tng_data, num_first_particle,
6374                                     sizeof(*num_first_particle),
6375                                     hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6376         {
6377             return(TNG_CRITICAL);
6378         }
6379
6380         if(tng_file_input_numerical(tng_data, block_n_particles,
6381                                     sizeof(*block_n_particles),
6382                                     hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6383         {
6384             return(TNG_CRITICAL);
6385         }
6386     }
6387     else
6388     {
6389         *num_first_particle = -1;
6390         *block_n_particles = 0;
6391     }
6392
6393     return(TNG_SUCCESS);
6394 }
6395
6396 /**
6397  * @brief Read the contents of a data block (particle or non-particle data).
6398  * @param tng_data is a trajectory data container.
6399  * @param block is the block to store the data (should already contain
6400  * the block headers).
6401  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6402  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
6403  * compared to the md5 hash of the read contents to ensure valid data.
6404  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6405  * error has occured.
6406  */
6407 static tng_function_status tng_data_block_contents_read
6408                 (const tng_trajectory_t tng_data,
6409                  const tng_gen_block_t block,
6410                  const char hash_mode)
6411 {
6412     int64_t start_pos, n_values, codec_id, n_frames, first_frame_with_data;
6413     int64_t remaining_len, stride_length, block_n_particles, num_first_particle;
6414     double multiplier;
6415     char datatype, dependency, sparse_data;
6416     tng_function_status stat = TNG_SUCCESS;
6417     char hash[TNG_MD5_HASH_LEN];
6418     md5_state_t md5_state;
6419
6420     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
6421     {
6422         return(TNG_CRITICAL);
6423     }
6424
6425     start_pos = ftello(tng_data->input_file);
6426
6427     if(hash_mode == TNG_USE_HASH)
6428     {
6429         md5_init(&md5_state);
6430     }
6431
6432     /* FIXME: Does not check if the size of the contents matches the expected
6433      * size or if the contents can be read. */
6434
6435     if(tng_data_block_meta_information_read(tng_data,
6436                                             &datatype,
6437                                             &dependency, &sparse_data,
6438                                             &n_values, &codec_id,
6439                                             &first_frame_with_data,
6440                                             &stride_length, &n_frames,
6441                                             &num_first_particle,
6442                                             &block_n_particles,
6443                                             &multiplier,
6444                                             hash_mode,
6445                                             &md5_state) == TNG_CRITICAL)
6446     {
6447         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
6448             block->name, __FILE__, __LINE__);
6449         return(TNG_CRITICAL);
6450     }
6451
6452     remaining_len = block->block_contents_size - (ftello(tng_data->input_file) - start_pos);
6453
6454     stat = tng_data_read(tng_data, block,
6455                          remaining_len,
6456                          datatype,
6457                          num_first_particle,
6458                          block_n_particles,
6459                          first_frame_with_data,
6460                          stride_length,
6461                          n_frames, n_values,
6462                          codec_id, multiplier,
6463                          hash_mode,
6464                          &md5_state);
6465
6466     if(hash_mode == TNG_USE_HASH)
6467     {
6468         /* If there is data left in the block that the current version of the library
6469          * cannot interpret still read that to generate the MD5 hash. */
6470         tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
6471
6472         md5_finish(&md5_state, (md5_byte_t *)hash);
6473         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)
6474         {
6475             if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
6476             {
6477                 fprintf(stderr, "TNG library: Data block contents corrupt (%s). Hashes do not match. "
6478                         "%s: %d\n", block->name, __FILE__, __LINE__);
6479             }
6480         }
6481     }
6482     else
6483     {
6484         /* Seek to the end of the block */
6485         fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
6486     }
6487
6488     return(stat);
6489 }
6490
6491 /*
6492 // ** Move the blocks in a frame set so that there is no unused space between
6493 //  * them. This can only be done on the last frame set in the file and should
6494 //  * be done e.g. if the last frame set in the file has fewer frames than
6495 //  * default or after compressing data blocks in a frame set.
6496 //  * @param tng_data is a trajectory data container.
6497 //  * @details the current_trajectory_frame_set is the one that will be modified.
6498 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
6499 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
6500 //  * FIXME: This function is not finished!!!
6501 //  *
6502 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
6503 // {
6504 //     tng_gen_block_t block;
6505 //     tng_trajectory_frame_set_t frame_set;
6506 //     FILE *temp = tng_data->input_file;
6507 //     int64_t pos, contents_start_pos, output_file_len;
6508 //
6509 //     frame_set = &tng_data->current_trajectory_frame_set;
6510 //
6511 //     if(frame_set->n_written_frames == frame_set->n_frames)
6512 //     {
6513 //         return(TNG_SUCCESS);
6514 //     }
6515 //
6516 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
6517 //        tng_data->last_trajectory_frame_set_output_file_pos)
6518 //     {
6519 //     }
6520 //
6521 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6522 //     {
6523 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6524 //                __FILE__, __LINE__);
6525 //         return(TNG_CRITICAL);
6526 //     }
6527 //
6528 //     tng_block_init(&block);
6529 // //     output_file_pos = ftello(tng_data->output_file);
6530 //
6531 //     tng_data->input_file = tng_data->output_file;
6532 //
6533 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
6534 //
6535 //     fseeko(tng_data->output_file, pos, SEEK_SET);
6536 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6537 //     {
6538 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6539 //             __FILE__, __LINE__);
6540 //         tng_data->input_file = temp;
6541 //         tng_block_destroy(&block);
6542 //         return(TNG_CRITICAL);
6543 //     }
6544 //
6545 //     contents_start_pos = ftello(tng_data->output_file);
6546 //
6547 //     fseeko(tng_data->output_file, 0, SEEK_END);
6548 //     output_file_len = ftello(tng_data->output_file);
6549 //     pos = contents_start_pos + block->block_contents_size;
6550 //     fseeko(tng_data->output_file, pos,
6551 //           SEEK_SET);
6552 //
6553 //     while(pos < output_file_len)
6554 //     {
6555 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6556 //         {
6557 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
6558 //                    __FILE__, __LINE__);
6559 //             tng_data->input_file = temp;
6560 //             tng_block_destroy(&block);
6561 //             return(TNG_CRITICAL);
6562 //         }
6563 //         pos += block->header_contents_size + block->block_contents_size;
6564 //         fseeko(tng_data->output_file, pos, SEEK_SET);
6565 //     }
6566 //
6567 //     return(TNG_SUCCESS);
6568 // }
6569 */
6570 /**
6571  * @brief Finish writing the current frame set. Update the number of frames
6572  * and the hashes of the frame set and all its data blocks (if hash_mode
6573  * == TNG_USE_HASH).
6574  * @param tng_data is a trajectory data container.
6575  * @param hash_mode specifies whether to update the block md5 hash when
6576  * updating the pointers.
6577  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6578  * error has occured.
6579  */
6580 static tng_function_status tng_frame_set_finalize
6581                 (const tng_trajectory_t tng_data,
6582                  const char hash_mode)
6583 {
6584     tng_gen_block_t block;
6585     tng_trajectory_frame_set_t frame_set;
6586     FILE *temp = tng_data->input_file;
6587     int64_t pos, curr_file_pos;
6588
6589     frame_set = &tng_data->current_trajectory_frame_set;
6590
6591     if(frame_set->n_written_frames == frame_set->n_frames)
6592     {
6593         return(TNG_SUCCESS);
6594     }
6595
6596     frame_set->n_written_frames = frame_set->n_frames;
6597
6598     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6599     {
6600         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6601                __FILE__, __LINE__);
6602         return(TNG_CRITICAL);
6603     }
6604
6605     tng_block_init(&block);
6606 /*     output_file_pos = ftello(tng_data->output_file); */
6607
6608     tng_data->input_file = tng_data->output_file;
6609
6610     curr_file_pos = ftello(tng_data->output_file);
6611
6612     pos = tng_data->current_trajectory_frame_set_output_file_pos;
6613
6614     fseeko(tng_data->output_file, pos, SEEK_SET);
6615
6616     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6617     {
6618         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6619             __FILE__, __LINE__);
6620         tng_data->input_file = temp;
6621         tng_block_destroy(&block);
6622         return(TNG_CRITICAL);
6623     }
6624
6625 //     contents_start_pos = ftello(tng_data->output_file);
6626
6627     fseeko(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
6628     if(fwrite(&frame_set->n_frames, sizeof(frame_set->n_frames),
6629               1, tng_data->output_file) != 1)
6630     {
6631         tng_data->input_file = temp;
6632         tng_block_destroy(&block);
6633         return(TNG_CRITICAL);
6634     }
6635
6636     if(hash_mode == TNG_USE_HASH)
6637     {
6638         tng_md5_hash_update(tng_data, block, pos,
6639                             pos + block->header_contents_size);
6640     }
6641
6642     fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
6643
6644     tng_data->input_file = temp;
6645     tng_block_destroy(&block);
6646     return(TNG_SUCCESS);
6647 }
6648
6649 /*
6650 // ** Sets the name of a file contents block
6651 //  * @param tng_data is a trajectory data container.
6652 //  * @param block is the block, of which to change names.
6653 //  * @param new_name is the new name of the block.
6654 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6655 //  * error has occured.
6656 //
6657 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
6658 //                                               tng_gen_block_t block,
6659 //                                               const char *new_name)
6660 // {
6661 //     int len;
6662 //
6663 //     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
6664 //
6665 //      * If the currently stored string length is not enough to store the new
6666 //      * string it is freed and reallocated. *
6667 //     if(block->name && strlen(block->name) < len)
6668 //     {
6669 //         free(block->name);
6670 //         block->name = 0;
6671 //     }
6672 //     if(!block->name)
6673 //     {
6674 //         block->name = malloc(len);
6675 //         if(!block->name)
6676 //         {
6677 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
6678 //                    __FILE__, __LINE__);
6679 //             return(TNG_CRITICAL);
6680 //         }
6681 //     }
6682 //
6683 //     strncpy(block->name, new_name, len);
6684 //
6685 //     return(TNG_SUCCESS);
6686 // }
6687 */
6688
6689 tng_function_status DECLSPECDLLEXPORT tng_atom_residue_get
6690                 (const tng_trajectory_t tng_data,
6691                  const tng_atom_t atom,
6692                  tng_residue_t *residue)
6693 {
6694     (void) tng_data;
6695
6696     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
6697
6698     *residue = atom->residue;
6699
6700     return(TNG_SUCCESS);
6701 }
6702
6703 tng_function_status DECLSPECDLLEXPORT tng_atom_name_get
6704                 (const tng_trajectory_t tng_data,
6705                  const tng_atom_t atom,
6706                  char *name,
6707                  const int max_len)
6708 {
6709     (void) tng_data;
6710     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
6711     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
6712
6713     strncpy(name, atom->name, max_len - 1);
6714     name[max_len - 1] = 0;
6715
6716     if(strlen(atom->name) > (unsigned int)max_len - 1)
6717     {
6718         return(TNG_FAILURE);
6719     }
6720     return(TNG_SUCCESS);
6721 }
6722
6723 tng_function_status DECLSPECDLLEXPORT tng_atom_name_set
6724                 (const tng_trajectory_t tng_data,
6725                  const tng_atom_t atom,
6726                  const char *new_name)
6727 {
6728     unsigned int len;
6729     (void)tng_data;
6730
6731     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6732     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
6733
6734     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
6735
6736     /* If the currently stored string length is not enough to store the new
6737      * string it is freed and reallocated. */
6738     if(atom->name && strlen(atom->name) < len)
6739     {
6740         free(atom->name);
6741         atom->name = 0;
6742     }
6743     if(!atom->name)
6744     {
6745         atom->name = malloc(len);
6746         if(!atom->name)
6747         {
6748             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
6749                    __FILE__, __LINE__);
6750             return(TNG_CRITICAL);
6751         }
6752     }
6753
6754     strncpy(atom->name, new_name, len);
6755
6756     return(TNG_SUCCESS);
6757 }
6758
6759 tng_function_status DECLSPECDLLEXPORT tng_atom_type_get
6760                 (const tng_trajectory_t tng_data,
6761                  const tng_atom_t atom,
6762                  char *type,
6763                  const int max_len)
6764 {
6765     (void) tng_data;
6766     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
6767     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
6768
6769     strncpy(type, atom->atom_type, max_len - 1);
6770     type[max_len - 1] = 0;
6771
6772     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
6773     {
6774         return(TNG_FAILURE);
6775     }
6776     return(TNG_SUCCESS);
6777 }
6778
6779 tng_function_status DECLSPECDLLEXPORT tng_atom_type_set
6780                 (const tng_trajectory_t tng_data,
6781                  const tng_atom_t atom,
6782                  const char *new_type)
6783 {
6784     unsigned int len;
6785     (void)tng_data;
6786
6787     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6788     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
6789
6790     len = tng_min_size(strlen(new_type) + 1, TNG_MAX_STR_LEN);
6791
6792     /* If the currently stored string length is not enough to store the new
6793      * string it is freed and reallocated. */
6794     if(atom->atom_type && strlen(atom->atom_type) < len)
6795     {
6796         free(atom->atom_type);
6797         atom->atom_type = 0;
6798     }
6799     if(!atom->atom_type)
6800     {
6801         atom->atom_type = malloc(len);
6802         if(!atom->atom_type)
6803         {
6804             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
6805                    __FILE__, __LINE__);
6806             return(TNG_CRITICAL);
6807         }
6808     }
6809
6810     strncpy(atom->atom_type, new_type, len);
6811
6812     return(TNG_SUCCESS);
6813 }
6814
6815 /**
6816  * @brief Initialise an atom struct
6817  * @param atom is the atom to initialise.
6818  * @return TNG_SUCCESS (0) if successful.
6819  */
6820 static tng_function_status tng_atom_init(const tng_atom_t atom)
6821 {
6822     atom->name = 0;
6823     atom->atom_type = 0;
6824
6825     return(TNG_SUCCESS);
6826 }
6827
6828 /**
6829  * @brief Free the memory in an atom struct
6830  * @param atom is the atom to destroy.
6831  * @return TNG_SUCCESS (0) if successful.
6832  */
6833 static tng_function_status tng_atom_destroy(const tng_atom_t atom)
6834 {
6835     if(atom->name)
6836     {
6837         free(atom->name);
6838         atom->name = 0;
6839     }
6840     if(atom->atom_type)
6841     {
6842         free(atom->atom_type);
6843         atom->atom_type = 0;
6844     }
6845
6846     return(TNG_SUCCESS);
6847 }
6848
6849 /**
6850  * @brief Update chain->residue pointers (after new memory for
6851  * molecule->residues has been allocated).
6852  * @param tng_data The trajectory container containing the molecule.
6853  * @param mol The molecule that contains the chains that need to be
6854  * updated.
6855  * @returns TNG_SUCCESS (0) if successful.
6856  */
6857 static tng_function_status tng_molecule_chains_residue_pointers_update
6858                 (const tng_trajectory_t tng_data,
6859                  const tng_molecule_t mol)
6860 {
6861     tng_chain_t chain;
6862     int64_t i, res_cnt = 0;
6863     (void)tng_data;
6864
6865     for(i = 0; i < mol->n_chains; i++)
6866     {
6867         chain = &mol->chains[i];
6868         chain->residues = mol->residues + res_cnt;
6869         res_cnt += chain->n_residues;
6870     }
6871     return(TNG_SUCCESS);
6872 }
6873
6874 tng_function_status DECLSPECDLLEXPORT tng_version_major
6875                 (const tng_trajectory_t tng_data,
6876                  int *version)
6877 {
6878     (void)tng_data;
6879
6880     *version = TNG_VERSION_MAJOR;
6881
6882     return(TNG_SUCCESS);
6883 }
6884
6885 tng_function_status DECLSPECDLLEXPORT tng_version_minor
6886                 (const tng_trajectory_t tng_data,
6887                  int *version)
6888 {
6889     (void)tng_data;
6890
6891     *version = TNG_VERSION_MINOR;
6892
6893     return(TNG_SUCCESS);
6894 }
6895
6896 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
6897                 (const tng_trajectory_t tng_data,
6898                  int *patch_level)
6899 {
6900     (void)tng_data;
6901
6902     *patch_level = TNG_VERSION_PATCHLEVEL;
6903
6904     return(TNG_SUCCESS);
6905 }
6906
6907 tng_function_status DECLSPECDLLEXPORT tng_version
6908                 (const tng_trajectory_t tng_data,
6909                  char *version,
6910                  const int max_len)
6911 {
6912     (void)tng_data;
6913     TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
6914
6915     TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
6916
6917     return(TNG_SUCCESS);
6918 }
6919
6920 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
6921                 (const tng_trajectory_t tng_data,
6922                  const char *name,
6923                  tng_molecule_t *molecule)
6924 {
6925     int64_t id;
6926
6927     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6928     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
6929
6930     /* Set ID to the ID of the last molecule + 1 */
6931     if(tng_data->n_molecules)
6932     {
6933         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
6934     }
6935     else
6936     {
6937         id = 1;
6938     }
6939
6940     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
6941 }
6942
6943 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
6944                 (const tng_trajectory_t tng_data,
6945                  const char *name,
6946                  const int64_t id,
6947                  tng_molecule_t *molecule)
6948 {
6949     tng_molecule_t new_molecules;
6950     int64_t *new_molecule_cnt_list;
6951     tng_function_status stat = TNG_SUCCESS;
6952
6953     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6954     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
6955
6956     new_molecules = realloc(tng_data->molecules,
6957                             sizeof(struct tng_molecule) *
6958                             (tng_data->n_molecules + 1));
6959
6960     if(!new_molecules)
6961     {
6962         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
6963                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
6964                __FILE__, __LINE__);
6965         free(tng_data->molecules);
6966         tng_data->molecules = 0;
6967         return(TNG_CRITICAL);
6968     }
6969
6970     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
6971                                     sizeof(int64_t) *
6972                                     (tng_data->n_molecules + 1));
6973
6974     if(!new_molecule_cnt_list)
6975     {
6976         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
6977                sizeof(int64_t) * (tng_data->n_molecules + 1),
6978                __FILE__, __LINE__);
6979         free(tng_data->molecule_cnt_list);
6980         tng_data->molecule_cnt_list = 0;
6981         free(new_molecules);
6982         return(TNG_CRITICAL);
6983     }
6984
6985     tng_data->molecules = new_molecules;
6986     tng_data->molecule_cnt_list = new_molecule_cnt_list;
6987
6988     *molecule = &new_molecules[tng_data->n_molecules];
6989
6990     tng_molecule_init(tng_data, *molecule);
6991     tng_molecule_name_set(tng_data, *molecule, name);
6992
6993     /* FIXME: Should this be a function argument instead? */
6994     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
6995
6996     (*molecule)->id = id;
6997
6998     tng_data->n_molecules++;
6999
7000     return(stat);
7001 }
7002
7003 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
7004                 (const tng_trajectory_t tng_data,
7005                  tng_molecule_t *molecule_p)
7006 {
7007     int64_t *new_molecule_cnt_list, id;
7008     tng_molecule_t new_molecules, molecule;
7009
7010     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7011
7012     /* Set ID to the ID of the last molecule + 1 */
7013     if(tng_data->n_molecules)
7014     {
7015         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7016     }
7017     else
7018     {
7019         id = 1;
7020     }
7021
7022     new_molecules = realloc(tng_data->molecules,
7023                             sizeof(struct tng_molecule) *
7024                             (tng_data->n_molecules + 1));
7025
7026     if(!new_molecules)
7027     {
7028         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
7029                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7030                __FILE__, __LINE__);
7031         free(tng_data->molecules);
7032         tng_data->molecules = 0;
7033         return(TNG_CRITICAL);
7034     }
7035
7036     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7037                                     sizeof(int64_t) *
7038                                     (tng_data->n_molecules + 1));
7039
7040     if(!new_molecule_cnt_list)
7041     {
7042         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
7043                sizeof(int64_t) * (tng_data->n_molecules + 1),
7044                __FILE__, __LINE__);
7045         free(tng_data->molecule_cnt_list);
7046         tng_data->molecule_cnt_list = 0;
7047         free(new_molecules);
7048         return(TNG_CRITICAL);
7049     }
7050
7051     molecule = *molecule_p;
7052
7053     tng_data->molecules = new_molecules;
7054     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7055
7056     new_molecules[tng_data->n_molecules] = *molecule;
7057
7058     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7059
7060     free(*molecule_p);
7061
7062     molecule = &new_molecules[tng_data->n_molecules];
7063
7064     *molecule_p = molecule;
7065
7066     molecule->id = id;
7067
7068     tng_data->n_molecules++;
7069
7070     return(TNG_SUCCESS);
7071 }
7072
7073 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
7074                                           const tng_molecule_t molecule,
7075                                           char *name,
7076                                           const int max_len)
7077 {
7078     (void) tng_data;
7079     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7080     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7081
7082     strncpy(name, molecule->name, max_len - 1);
7083     name[max_len - 1] = 0;
7084
7085     if(strlen(molecule->name) > (unsigned int)max_len - 1)
7086     {
7087         return(TNG_FAILURE);
7088     }
7089     return(TNG_SUCCESS);
7090 }
7091
7092 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
7093                 (const tng_trajectory_t tng_data,
7094                  const tng_molecule_t molecule,
7095                  const char *new_name)
7096 {
7097     unsigned int len;
7098     (void)tng_data;
7099
7100     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7101     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7102
7103     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7104
7105     /* If the currently stored string length is not enough to store the new
7106      * string it is freed and reallocated. */
7107     if(molecule->name && strlen(molecule->name) < len)
7108     {
7109         free(molecule->name);
7110         molecule->name = 0;
7111     }
7112     if(!molecule->name)
7113     {
7114         molecule->name = malloc(len);
7115         if(!molecule->name)
7116         {
7117             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7118                    __FILE__, __LINE__);
7119             return(TNG_CRITICAL);
7120         }
7121     }
7122
7123     strncpy(molecule->name, new_name, len);
7124
7125     return(TNG_SUCCESS);
7126 }
7127
7128 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
7129                 (const tng_trajectory_t tng_data,
7130                  const tng_molecule_t molecule,
7131                  int64_t *cnt)
7132 {
7133     int64_t i, index = -1;
7134
7135     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7136     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
7137
7138     for(i = 0; i < tng_data->n_molecules; i++)
7139     {
7140         if(&tng_data->molecules[i] == molecule)
7141         {
7142             index = i;
7143             break;
7144         }
7145     }
7146     if(index == -1)
7147     {
7148         return(TNG_FAILURE);
7149     }
7150     *cnt = tng_data->molecule_cnt_list[index];
7151
7152     return(TNG_SUCCESS);
7153 }
7154
7155 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
7156                 (const tng_trajectory_t tng_data,
7157                  const tng_molecule_t molecule,
7158                  const int64_t cnt)
7159 {
7160     int64_t i, old_cnt, index = -1;
7161
7162     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7163
7164     for(i = 0; i < tng_data->n_molecules; i++)
7165     {
7166         if(&tng_data->molecules[i] == molecule)
7167         {
7168             index = i;
7169             break;
7170         }
7171     }
7172     if(index == -1)
7173     {
7174         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
7175                __FILE__, __LINE__);
7176         return(TNG_FAILURE);
7177     }
7178     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
7179     {
7180         old_cnt = tng_data->molecule_cnt_list[index];
7181         tng_data->molecule_cnt_list[index] = cnt;
7182
7183         tng_data->n_particles += (cnt-old_cnt) *
7184                                  tng_data->molecules[index].n_atoms;
7185     }
7186     else
7187     {
7188         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
7189         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
7190
7191         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
7192                 tng_data->molecules[index].n_atoms;
7193     }
7194
7195     return(TNG_SUCCESS);
7196 }
7197
7198 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
7199                 (const tng_trajectory_t tng_data,
7200                  const char *name,
7201                  const int64_t nr,
7202                  tng_molecule_t *molecule)
7203 {
7204     int64_t i, n_molecules;
7205
7206     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7207     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7208     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7209
7210     n_molecules = tng_data->n_molecules;
7211
7212     for(i = n_molecules - 1; i >= 0; i--)
7213     {
7214         *molecule = &tng_data->molecules[i];
7215         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
7216         {
7217             if(nr == -1 || nr == (*molecule)->id)
7218             {
7219                 return(TNG_SUCCESS);
7220             }
7221         }
7222     }
7223
7224     *molecule = 0;
7225
7226     return(TNG_FAILURE);
7227 }
7228
7229 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
7230                 (const tng_trajectory_t tng_data,
7231                  const int64_t index,
7232                  tng_molecule_t *molecule)
7233 {
7234     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7235     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7236
7237     if(index >= tng_data->n_molecules)
7238     {
7239         *molecule = 0;
7240         return(TNG_FAILURE);
7241     }
7242     *molecule = &tng_data->molecules[index];
7243     return(TNG_SUCCESS);
7244 }
7245
7246 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(const tng_trajectory_t tng_data_src,
7247                                                                const tng_trajectory_t tng_data_dest)
7248 {
7249     tng_molecule_t molecule, molecule_temp;
7250     tng_chain_t chain, chain_temp;
7251     tng_residue_t residue, residue_temp;
7252     tng_atom_t atom, atom_temp;
7253     tng_bond_t bond_temp;
7254     tng_function_status stat;
7255     int64_t i, j, k, l, *list_temp;
7256
7257     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
7258     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
7259
7260     for(i = 0; i < tng_data_dest->n_molecules; i++)
7261     {
7262         molecule = &tng_data_dest->molecules[i];
7263         tng_molecule_destroy(tng_data_dest, molecule);
7264     }
7265
7266     tng_data_dest->n_molecules = 0;
7267     tng_data_dest->n_particles = 0;
7268
7269     molecule_temp = realloc(tng_data_dest->molecules,
7270                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
7271     if(!molecule_temp)
7272     {
7273         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
7274                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
7275                __FILE__, __LINE__);
7276         free(tng_data_dest->molecules);
7277         tng_data_dest->molecules = 0;
7278         return(TNG_CRITICAL);
7279     }
7280     list_temp = realloc(tng_data_dest->molecule_cnt_list,
7281                                      sizeof(int64_t) * tng_data_src->n_molecules);
7282     if(!list_temp)
7283     {
7284         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
7285                sizeof(int64_t) * tng_data_src->n_molecules,
7286                __FILE__, __LINE__);
7287         free(tng_data_dest->molecule_cnt_list);
7288         tng_data_dest->molecule_cnt_list = 0;
7289         free(molecule_temp);
7290         return(TNG_CRITICAL);
7291     }
7292
7293     tng_data_dest->molecules = molecule_temp;
7294     tng_data_dest->molecule_cnt_list = list_temp;
7295
7296     for(i = 0; i < tng_data_src->n_molecules; i++)
7297     {
7298         molecule = &tng_data_src->molecules[i];
7299         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
7300                                      &molecule_temp);
7301         if(stat != TNG_SUCCESS)
7302         {
7303             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
7304                    __FILE__, __LINE__);
7305             return(stat);
7306         }
7307         molecule_temp->quaternary_str = molecule->quaternary_str;
7308         for(j = 0; j < molecule->n_chains; j++)
7309         {
7310             chain = &molecule->chains[j];
7311             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
7312                                                chain->name, chain->id,
7313                                                &chain_temp);
7314             if(stat != TNG_SUCCESS)
7315             {
7316                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
7317                        __FILE__, __LINE__);
7318                 return(stat);
7319             }
7320             for(k = 0; k < chain->n_residues; k++)
7321             {
7322                 residue = &chain->residues[k];
7323                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
7324                                                   residue->name, residue->id,
7325                                                   &residue_temp);
7326                 if(stat != TNG_SUCCESS)
7327                 {
7328                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
7329                            __FILE__, __LINE__);
7330                     return(stat);
7331                 }
7332                 for(l = 0; l < residue->n_atoms; l++)
7333                 {
7334                     atom = &molecule->atoms[residue->atoms_offset + l];
7335                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
7336                                                      atom->name, atom->atom_type,
7337                                                      atom->id, &atom_temp);
7338                     if(stat != TNG_SUCCESS)
7339                     {
7340                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
7341                            __FILE__, __LINE__);
7342                         return(stat);
7343                     }
7344                 }
7345             }
7346         }
7347         molecule_temp->n_bonds = molecule->n_bonds;
7348         if(molecule->n_bonds > 0)
7349         {
7350             bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
7351                                 molecule->n_bonds);
7352             if(!bond_temp)
7353             {
7354                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
7355                        sizeof(struct tng_bond) * molecule->n_bonds,
7356                        __FILE__, __LINE__);
7357                 free(molecule_temp->bonds);
7358                 molecule_temp->n_bonds = 0;
7359                 return(TNG_CRITICAL);
7360             }
7361             molecule_temp->bonds = bond_temp;
7362             for(j = 0; j < molecule->n_bonds; j++)
7363             {
7364                 molecule_temp->bonds[j] = molecule->bonds[j];
7365             }
7366         }
7367         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
7368                                     tng_data_src->molecule_cnt_list[i]);
7369         if(stat != TNG_SUCCESS)
7370         {
7371             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
7372                    __FILE__, __LINE__);
7373             return(stat);
7374         }
7375     }
7376     return(TNG_SUCCESS);
7377 }
7378
7379 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
7380                 (const tng_trajectory_t tng_data,
7381                  const tng_molecule_t molecule,
7382                  int64_t *n)
7383 {
7384     (void) tng_data;
7385     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7386     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7387
7388     *n = molecule->n_chains;
7389
7390     return(TNG_SUCCESS);
7391 }
7392
7393 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
7394                 (const tng_trajectory_t tng_data,
7395                  const tng_molecule_t molecule,
7396                  const int64_t index,
7397                  tng_chain_t *chain)
7398 {
7399     (void) tng_data;
7400     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7401     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7402
7403     if(index >= molecule->n_chains)
7404     {
7405         *chain = 0;
7406         return(TNG_FAILURE);
7407     }
7408     *chain = &molecule->chains[index];
7409     return(TNG_SUCCESS);
7410 }
7411
7412 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
7413                 (const tng_trajectory_t tng_data,
7414                  const tng_molecule_t molecule,
7415                  int64_t *n)
7416 {
7417     (void) tng_data;
7418     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7419     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7420
7421     *n = molecule->n_residues;
7422
7423     return(TNG_SUCCESS);
7424 }
7425
7426 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
7427                 (const tng_trajectory_t tng_data,
7428                  const tng_molecule_t molecule,
7429                  const int64_t index,
7430                  tng_residue_t *residue)
7431 {
7432     (void) tng_data;
7433     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7434     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7435
7436     if(index >= molecule->n_residues)
7437     {
7438         *residue = 0;
7439         return(TNG_FAILURE);
7440     }
7441     *residue = &molecule->residues[index];
7442     return(TNG_SUCCESS);
7443 }
7444
7445 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
7446                 (const tng_trajectory_t tng_data,
7447                  const tng_molecule_t molecule,
7448                  int64_t *n)
7449 {
7450     (void) tng_data;
7451     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7452     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7453
7454     *n = molecule->n_atoms;
7455
7456     return(TNG_SUCCESS);
7457 }
7458
7459 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
7460                 (const tng_trajectory_t tng_data,
7461                  const tng_molecule_t molecule,
7462                  const int64_t index,
7463                  tng_atom_t *atom)
7464 {
7465     (void) tng_data;
7466     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7467     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7468
7469     if(index >= molecule->n_atoms)
7470     {
7471         *atom = 0;
7472         return(TNG_FAILURE);
7473     }
7474     *atom = &molecule->atoms[index];
7475     return(TNG_SUCCESS);
7476 }
7477
7478 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
7479                 (const tng_trajectory_t tng_data,
7480                  const tng_molecule_t molecule,
7481                  const char *name,
7482                  const int64_t nr,
7483                  tng_chain_t *chain)
7484 {
7485     int64_t i, n_chains;
7486     (void)tng_data;
7487
7488     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7489     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7490
7491     n_chains = molecule->n_chains;
7492
7493     for(i = n_chains - 1; i >= 0; i--)
7494     {
7495         *chain = &molecule->chains[i];
7496         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
7497         {
7498             if(nr == -1 || nr == (*chain)->id)
7499             {
7500                 return(TNG_SUCCESS);
7501             }
7502         }
7503     }
7504
7505     *chain = 0;
7506
7507     return(TNG_FAILURE);
7508 }
7509
7510 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
7511                 (const tng_trajectory_t tng_data,
7512                  const tng_molecule_t molecule,
7513                  const char *name,
7514                  tng_chain_t *chain)
7515 {
7516     int64_t id;
7517
7518     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7519     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7520
7521     /* Set ID to the ID of the last chain + 1 */
7522     if(molecule->n_chains)
7523     {
7524         id = molecule->chains[molecule->n_chains-1].id + 1;
7525     }
7526     else
7527     {
7528         id = 1;
7529     }
7530
7531     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
7532                                        id, chain));
7533 }
7534
7535 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
7536                 (const tng_trajectory_t tng_data,
7537                  const tng_molecule_t molecule,
7538                  const char *name,
7539                  const int64_t id,
7540                  tng_chain_t *chain)
7541 {
7542     tng_chain_t new_chains;
7543     tng_function_status stat = TNG_SUCCESS;
7544
7545     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7546     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7547
7548     new_chains = realloc(molecule->chains,
7549                          sizeof(struct tng_chain) *
7550                          (molecule->n_chains + 1));
7551
7552     if(!new_chains)
7553     {
7554         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
7555                sizeof(struct tng_chain) * (molecule->n_chains + 1),
7556                __FILE__, __LINE__);
7557         free(molecule->chains);
7558         molecule->chains = 0;
7559         return(TNG_CRITICAL);
7560     }
7561
7562     molecule->chains = new_chains;
7563
7564     *chain = &new_chains[molecule->n_chains];
7565     (*chain)->name = 0;
7566
7567     tng_chain_name_set(tng_data, *chain, name);
7568
7569     (*chain)->molecule = molecule;
7570     (*chain)->n_residues = 0;
7571
7572     molecule->n_chains++;
7573
7574     (*chain)->id = id;
7575
7576     return(stat);
7577 }
7578
7579 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
7580                 (const tng_trajectory_t tng_data,
7581                  const tng_molecule_t molecule,
7582                  const int64_t from_atom_id,
7583                  const int64_t to_atom_id,
7584                  tng_bond_t *bond)
7585 {
7586     tng_bond_t new_bonds;
7587     (void)tng_data;
7588
7589     new_bonds = realloc(molecule->bonds,
7590                         sizeof(struct tng_bond) *
7591                         (molecule->n_bonds + 1));
7592
7593     if(!new_bonds)
7594     {
7595         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
7596                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
7597                __FILE__, __LINE__);
7598         *bond = 0;
7599         free(molecule->bonds);
7600         molecule->bonds = 0;
7601         return(TNG_CRITICAL);
7602     }
7603
7604     molecule->bonds = new_bonds;
7605
7606     *bond = &new_bonds[molecule->n_bonds];
7607
7608     (*bond)->from_atom_id = from_atom_id;
7609     (*bond)->to_atom_id = to_atom_id;
7610
7611     molecule->n_bonds++;
7612
7613     return(TNG_SUCCESS);
7614 }
7615
7616 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
7617                 (const tng_trajectory_t tng_data,
7618                  const tng_molecule_t molecule,
7619                  const char *name,
7620                  const int64_t id,
7621                  tng_atom_t *atom)
7622 {
7623     int64_t i, n_atoms;
7624     (void)tng_data;
7625
7626     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7627
7628     n_atoms = molecule->n_atoms;
7629
7630     for(i = n_atoms - 1; i >= 0; i--)
7631     {
7632         *atom = &molecule->atoms[i];
7633         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
7634         {
7635             if(id == -1 || id == (*atom)->id)
7636             {
7637                 return(TNG_SUCCESS);
7638             }
7639         }
7640     }
7641
7642     *atom = 0;
7643
7644     return(TNG_FAILURE);
7645 }
7646
7647 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
7648                                        const tng_chain_t chain,
7649                                        char *name,
7650                                        const int max_len)
7651 {
7652     (void) tng_data;
7653     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7654     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7655
7656     strncpy(name, chain->name, max_len - 1);
7657     name[max_len - 1] = 0;
7658
7659     if(strlen(chain->name) > (unsigned int)max_len - 1)
7660     {
7661         return(TNG_FAILURE);
7662     }
7663     return(TNG_SUCCESS);
7664 }
7665
7666 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
7667                 (const tng_trajectory_t tng_data,
7668                  const tng_chain_t chain,
7669                  const char *new_name)
7670 {
7671     unsigned int len;
7672     (void)tng_data;
7673
7674     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7675
7676     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7677
7678     /* If the currently stored string length is not enough to store the new
7679      * string it is freed and reallocated. */
7680     if(chain->name && strlen(chain->name) < len)
7681     {
7682         free(chain->name);
7683         chain->name = 0;
7684     }
7685     if(!chain->name)
7686     {
7687         chain->name = malloc(len);
7688         if(!chain->name)
7689         {
7690             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7691                    __FILE__, __LINE__);
7692             return(TNG_CRITICAL);
7693         }
7694     }
7695
7696     strncpy(chain->name, new_name, len);
7697
7698     return(TNG_SUCCESS);
7699 }
7700
7701 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
7702                 (const tng_trajectory_t tng_data,
7703                  const tng_chain_t chain,
7704                  int64_t *n)
7705 {
7706     (void) tng_data;
7707     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7708     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7709
7710     *n = chain->n_residues;
7711
7712     return(TNG_SUCCESS);
7713 }
7714
7715 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
7716                 (const tng_trajectory_t tng_data,
7717                  const tng_chain_t chain,
7718                  const int64_t index,
7719                  tng_residue_t *residue)
7720 {
7721     (void) tng_data;
7722     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7723     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7724
7725     if(index >= chain->n_residues)
7726     {
7727         *residue = 0;
7728         return(TNG_FAILURE);
7729     }
7730     *residue = &chain->residues[index];
7731     return(TNG_SUCCESS);
7732 }
7733
7734 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
7735                 (const tng_trajectory_t tng_data,
7736                  const tng_chain_t chain,
7737                  const char *name,
7738                  const int64_t id,
7739                  tng_residue_t *residue)
7740 {
7741     int64_t i, n_residues;
7742     (void)tng_data;
7743
7744     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7745
7746     n_residues = chain->n_residues;
7747
7748     for(i = n_residues - 1; i >= 0; i--)
7749     {
7750         *residue = &chain->residues[i];
7751         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
7752         {
7753             if(id == -1 || id == (*residue)->id)
7754             {
7755                 return(TNG_SUCCESS);
7756             }
7757         }
7758     }
7759
7760     *residue = 0;
7761
7762     return(TNG_FAILURE);
7763 }
7764
7765 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
7766                 (const tng_trajectory_t tng_data,
7767                  const tng_chain_t chain,
7768                  const char *name,
7769                  tng_residue_t *residue)
7770 {
7771     int64_t id;
7772
7773     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7774     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7775
7776     /* Set ID to the ID of the last residue + 1 */
7777     if(chain->n_residues)
7778     {
7779         id = chain->residues[chain->n_residues-1].id + 1;
7780     }
7781     else
7782     {
7783         id = 0;
7784     }
7785
7786     return(tng_chain_residue_w_id_add(tng_data, chain, name,
7787                                       id, residue));
7788 }
7789
7790 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
7791                 (const tng_trajectory_t tng_data,
7792                  const tng_chain_t chain,
7793                  const char *name,
7794                  const int64_t id,
7795                  tng_residue_t *residue)
7796 {
7797     int64_t curr_index;
7798     tng_residue_t new_residues, temp_residue, last_residue;
7799     tng_molecule_t molecule = chain->molecule;
7800     tng_function_status stat = TNG_SUCCESS;
7801
7802     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7803     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7804
7805     if(chain->n_residues)
7806     {
7807         curr_index = chain->residues - molecule->residues;
7808     }
7809     else
7810     {
7811         curr_index = -1;
7812     }
7813
7814     new_residues = realloc(molecule->residues,
7815                            sizeof(struct tng_residue) *
7816                            (molecule->n_residues + 1));
7817
7818     if(!new_residues)
7819     {
7820         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
7821                sizeof(struct tng_residue) * (molecule->n_residues + 1),
7822                __FILE__, __LINE__);
7823         free(molecule->residues);
7824         molecule->residues = 0;
7825         return(TNG_CRITICAL);
7826     }
7827
7828     molecule->residues = new_residues;
7829
7830     if(curr_index != -1)
7831     {
7832         chain->residues = new_residues + curr_index;
7833         if(molecule->n_residues)
7834         {
7835             last_residue = &new_residues[molecule->n_residues - 1];
7836
7837             temp_residue = chain->residues + (chain->n_residues - 1);
7838             /* Make space in list of residues to add the new residues together with the other
7839             * residues of this chain */
7840             if(temp_residue != last_residue)
7841             {
7842                 ++temp_residue;
7843                 memmove(temp_residue + 1, temp_residue,
7844                         last_residue - temp_residue);
7845             }
7846         }
7847     }
7848     else
7849     {
7850         curr_index = molecule->n_residues;
7851     }
7852
7853     *residue = &molecule->residues[curr_index + chain->n_residues];
7854
7855     tng_molecule_chains_residue_pointers_update(tng_data, molecule);
7856
7857     (*residue)->name = 0;
7858     tng_residue_name_set(tng_data, *residue, name);
7859
7860     (*residue)->chain = chain;
7861     (*residue)->n_atoms = 0;
7862     (*residue)->atoms_offset = 0;
7863
7864     chain->n_residues++;
7865     molecule->n_residues++;
7866
7867     (*residue)->id = id;
7868
7869     return(stat);
7870 }
7871
7872 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
7873                                          const tng_residue_t residue,
7874                                          char *name,
7875                                          const int max_len)
7876 {
7877     (void) tng_data;
7878     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
7879     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7880
7881     strncpy(name, residue->name, max_len - 1);
7882     name[max_len - 1] = 0;
7883
7884     if(strlen(residue->name) > (unsigned int)max_len - 1)
7885     {
7886         return(TNG_FAILURE);
7887     }
7888     return(TNG_SUCCESS);
7889 }
7890
7891 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(const tng_trajectory_t tng_data,
7892                                                            const tng_residue_t residue,
7893                                                            const char *new_name)
7894 {
7895     unsigned int len;
7896     (void)tng_data;
7897
7898     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7899     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
7900
7901     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7902
7903     /* If the currently stored string length is not enough to store the new
7904      * string it is freed and reallocated. */
7905     if(residue->name && strlen(residue->name) < len)
7906     {
7907         free(residue->name);
7908         residue->name = 0;
7909     }
7910     if(!residue->name)
7911     {
7912         residue->name = malloc(len);
7913         if(!residue->name)
7914         {
7915             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7916                    __FILE__, __LINE__);
7917             return(TNG_CRITICAL);
7918         }
7919     }
7920
7921     strncpy(residue->name, new_name, len);
7922
7923     return(TNG_SUCCESS);
7924 }
7925
7926 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
7927                 (const tng_trajectory_t tng_data,
7928                  const tng_residue_t residue,
7929                  int64_t *n)
7930 {
7931     (void) tng_data;
7932     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
7933     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7934
7935     *n = residue->n_atoms;
7936
7937     return(TNG_SUCCESS);
7938 }
7939
7940 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
7941                 (const tng_trajectory_t tng_data,
7942                  const tng_residue_t residue,
7943                  const int64_t index,
7944                  tng_atom_t *atom)
7945 {
7946     tng_chain_t chain;
7947     tng_molecule_t molecule;
7948
7949     (void) tng_data;
7950     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7951     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7952
7953     if(index >= residue->n_atoms)
7954     {
7955         *atom = 0;
7956         return(TNG_FAILURE);
7957     }
7958     chain = residue->chain;
7959     molecule = chain->molecule;
7960
7961     if(index + residue->atoms_offset >= molecule->n_atoms)
7962     {
7963         *atom = 0;
7964         return(TNG_FAILURE);
7965     }
7966
7967     *atom = &molecule->atoms[residue->atoms_offset + index];
7968     return(TNG_SUCCESS);
7969 }
7970
7971 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
7972                 (const tng_trajectory_t tng_data,
7973                  const tng_residue_t residue,
7974                  const char *atom_name,
7975                  const char *atom_type,
7976                  tng_atom_t *atom)
7977 {
7978     int64_t id;
7979
7980     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7981     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
7982     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
7983
7984     /* Set ID to the ID of the last atom + 1 */
7985     if(residue->chain->molecule->n_atoms)
7986     {
7987         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
7988     }
7989     else
7990     {
7991         id = 0;
7992     }
7993
7994     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
7995                                      id, atom));
7996 }
7997
7998 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
7999                 (const tng_trajectory_t tng_data,
8000                  const tng_residue_t residue,
8001                  const char *atom_name,
8002                  const char *atom_type,
8003                  const int64_t id,
8004                  tng_atom_t *atom)
8005 {
8006     tng_atom_t new_atoms;
8007     tng_molecule_t molecule = residue->chain->molecule;
8008     tng_function_status stat = TNG_SUCCESS;
8009
8010     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8011     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8012     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8013
8014     if(!residue->n_atoms)
8015     {
8016         residue->atoms_offset = molecule->n_atoms;
8017     }
8018
8019     new_atoms = realloc(molecule->atoms,
8020                         sizeof(struct tng_atom) *
8021                         (molecule->n_atoms + 1));
8022
8023     if(!new_atoms)
8024     {
8025         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8026                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
8027                __FILE__, __LINE__);
8028         free(molecule->atoms);
8029         molecule->atoms = 0;
8030         return(TNG_CRITICAL);
8031     }
8032
8033     molecule->atoms = new_atoms;
8034
8035     *atom = &new_atoms[molecule->n_atoms];
8036
8037     tng_atom_init(*atom);
8038     tng_atom_name_set(tng_data, *atom, atom_name);
8039     tng_atom_type_set(tng_data, *atom, atom_type);
8040
8041     (*atom)->residue = residue;
8042
8043     residue->n_atoms++;
8044     molecule->n_atoms++;
8045
8046     (*atom)->id = id;
8047
8048     return(stat);
8049 }
8050
8051 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
8052                                                          tng_molecule_t *molecule_p)
8053 {
8054     *molecule_p = malloc(sizeof(struct tng_molecule));
8055     if(!*molecule_p)
8056     {
8057         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
8058                sizeof(struct tng_molecule), __FILE__, __LINE__);
8059         return(TNG_CRITICAL);
8060     }
8061
8062     tng_molecule_init(tng_data, *molecule_p);
8063
8064     return(TNG_SUCCESS);
8065 }
8066
8067 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
8068                                                         tng_molecule_t *molecule_p)
8069 {
8070     if(!*molecule_p)
8071     {
8072         return(TNG_SUCCESS);
8073     }
8074
8075     tng_molecule_destroy(tng_data, *molecule_p);
8076
8077     free(*molecule_p);
8078     *molecule_p = 0;
8079
8080     return(TNG_SUCCESS);
8081 }
8082
8083 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
8084                                                         const tng_molecule_t molecule)
8085 {
8086     (void)tng_data;
8087     molecule->quaternary_str = 1;
8088     molecule->name = 0;
8089     molecule->n_chains = 0;
8090     molecule->chains = 0;
8091     molecule->n_residues = 0;
8092     molecule->residues = 0;
8093     molecule->n_atoms = 0;
8094     molecule->atoms = 0;
8095     molecule->n_bonds = 0;
8096     molecule->bonds = 0;
8097
8098     return(TNG_SUCCESS);
8099 }
8100
8101 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
8102                                                            const tng_molecule_t molecule)
8103 {
8104     int64_t i;
8105     (void)tng_data;
8106
8107     if(molecule->name)
8108     {
8109         free(molecule->name);
8110         molecule->name = 0;
8111     }
8112
8113     if(molecule->chains)
8114     {
8115         for(i = 0; i < molecule->n_chains; i++)
8116         {
8117             if(molecule->chains[i].name)
8118             {
8119                 free(molecule->chains[i].name);
8120                 molecule->chains[i].name = 0;
8121             }
8122         }
8123         free(molecule->chains);
8124         molecule->chains = 0;
8125     }
8126     molecule->n_chains = 0;
8127
8128     if(molecule->residues)
8129     {
8130         for(i = 0; i < molecule->n_residues; i++)
8131         {
8132             if(molecule->residues[i].name)
8133             {
8134                 free(molecule->residues[i].name);
8135                 molecule->residues[i].name = 0;
8136             }
8137         }
8138         free(molecule->residues);
8139         molecule->residues = 0;
8140     }
8141     molecule->n_residues = 0;
8142
8143     if(molecule->atoms)
8144     {
8145         for(i = 0; i < molecule->n_atoms; i++)
8146         {
8147             tng_atom_destroy(&molecule->atoms[i]);
8148         }
8149         free(molecule->atoms);
8150         molecule->atoms = 0;
8151     }
8152     molecule->n_atoms = 0;
8153
8154     if(molecule->bonds)
8155     {
8156         free(molecule->bonds);
8157         molecule->bonds = 0;
8158     }
8159     molecule->n_bonds = 0;
8160
8161     return(TNG_SUCCESS);
8162 }
8163
8164 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
8165                 (const tng_trajectory_t tng_data,
8166                  const int64_t nr,
8167                  char *name,
8168                  const int max_len)
8169 {
8170     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8171     tng_molecule_t mol;
8172     tng_bool found = TNG_FALSE;
8173
8174     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8175     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8176
8177     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8178
8179     if(!molecule_cnt_list)
8180     {
8181         return(TNG_FAILURE);
8182     }
8183
8184     for(i = 0; i < tng_data->n_molecules; i++)
8185     {
8186         mol = &tng_data->molecules[i];
8187         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8188         {
8189             cnt += mol->n_atoms * molecule_cnt_list[i];
8190             continue;
8191         }
8192         found = TNG_TRUE;
8193         break;
8194     }
8195     if(!found)
8196     {
8197         return(TNG_FAILURE);
8198     }
8199
8200     strncpy(name, mol->name, max_len - 1);
8201     name[max_len - 1] = 0;
8202
8203     if(strlen(mol->name) > (unsigned int)max_len - 1)
8204     {
8205         return(TNG_FAILURE);
8206     }
8207     return(TNG_SUCCESS);
8208 }
8209
8210 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
8211                 (const tng_trajectory_t tng_data,
8212                  const int64_t nr,
8213                  int64_t *id)
8214 {
8215     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8216     tng_molecule_t mol;
8217     tng_bool found = TNG_FALSE;
8218
8219     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8220     TNG_ASSERT(id, "TNG library: id 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     for(i = 0; i < tng_data->n_molecules; i++)
8230     {
8231         mol = &tng_data->molecules[i];
8232         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8233         {
8234             cnt += mol->n_atoms * molecule_cnt_list[i];
8235             continue;
8236         }
8237         found = TNG_TRUE;
8238         break;
8239     }
8240     if(!found)
8241     {
8242         return(TNG_FAILURE);
8243     }
8244
8245     *id = mol->id;
8246
8247     return(TNG_SUCCESS);
8248 }
8249
8250 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
8251                 (const tng_trajectory_t tng_data,
8252                  int64_t *n_bonds,
8253                  int64_t **from_atoms,
8254                  int64_t **to_atoms)
8255 {
8256     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
8257     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
8258     tng_molecule_t mol;
8259     tng_bond_t bond;
8260
8261     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8262     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
8263     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
8264     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
8265
8266     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8267
8268     if(!molecule_cnt_list)
8269     {
8270         return(TNG_FAILURE);
8271     }
8272
8273     *n_bonds = 0;
8274     /* First count the total number of bonds to allocate memory */
8275     for(i = 0; i < tng_data->n_molecules; i++)
8276     {
8277         mol = &tng_data->molecules[i];
8278         mol_cnt = molecule_cnt_list[i];
8279         *n_bonds += mol_cnt * mol->n_bonds;
8280     }
8281     if(*n_bonds == 0)
8282     {
8283         return(TNG_SUCCESS);
8284     }
8285
8286     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
8287     if(!*from_atoms)
8288     {
8289         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8290                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
8291         return(TNG_CRITICAL);
8292     }
8293     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
8294     if(!*to_atoms)
8295     {
8296         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8297                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
8298         free(*from_atoms);
8299         *from_atoms = 0;
8300         return(TNG_CRITICAL);
8301     }
8302
8303     cnt = 0;
8304     for(i = 0; i < tng_data->n_molecules; i++)
8305     {
8306         mol = &tng_data->molecules[i];
8307         mol_cnt = molecule_cnt_list[i];
8308         for(j = 0; j < mol_cnt; j++)
8309         {
8310             for(k = 0; k < mol->n_bonds; k++)
8311             {
8312                 bond = &mol->bonds[k];
8313                 from_atom = atom_cnt + bond->from_atom_id;
8314                 to_atom = atom_cnt + bond->to_atom_id;
8315                 (*from_atoms)[cnt] = from_atom;
8316                 (*to_atoms)[cnt++] = to_atom;
8317             }
8318             atom_cnt += mol->n_atoms;
8319         }
8320     }
8321
8322     return(TNG_SUCCESS);
8323 }
8324
8325 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
8326                 (const tng_trajectory_t tng_data,
8327                  const int64_t nr,
8328                  char *name,
8329                  const int max_len)
8330 {
8331     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8332     tng_molecule_t mol;
8333     tng_atom_t atom;
8334     tng_bool found = TNG_FALSE;
8335
8336     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8337     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8338
8339     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8340
8341     if(!molecule_cnt_list)
8342     {
8343         return(TNG_FAILURE);
8344     }
8345
8346     for(i = 0; i < tng_data->n_molecules; i++)
8347     {
8348         mol = &tng_data->molecules[i];
8349         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8350         {
8351             cnt += mol->n_atoms * molecule_cnt_list[i];
8352             continue;
8353         }
8354         atom = &mol->atoms[nr % mol->n_atoms];
8355         found = TNG_TRUE;
8356         break;
8357     }
8358     if(!found)
8359     {
8360         return(TNG_FAILURE);
8361     }
8362     if(!atom->residue || !atom->residue->chain)
8363     {
8364         return(TNG_FAILURE);
8365     }
8366
8367     strncpy(name, atom->residue->chain->name, max_len - 1);
8368     name[max_len - 1] = 0;
8369
8370     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
8371     {
8372         return(TNG_FAILURE);
8373     }
8374     return(TNG_SUCCESS);
8375 }
8376
8377 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
8378                 (const tng_trajectory_t tng_data,
8379                  const int64_t nr,
8380                  char *name,
8381                  const int max_len)
8382 {
8383     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8384     tng_molecule_t mol;
8385     tng_atom_t atom;
8386     tng_bool found = TNG_FALSE;
8387
8388     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8389     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8390
8391     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8392
8393     if(!molecule_cnt_list)
8394     {
8395         return(TNG_FAILURE);
8396     }
8397
8398     for(i = 0; i < tng_data->n_molecules; i++)
8399     {
8400         mol = &tng_data->molecules[i];
8401         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8402         {
8403             cnt += mol->n_atoms * molecule_cnt_list[i];
8404             continue;
8405         }
8406         atom = &mol->atoms[nr % mol->n_atoms];
8407         found = TNG_TRUE;
8408         break;
8409     }
8410     if(!found)
8411     {
8412         return(TNG_FAILURE);
8413     }
8414     if(!atom->residue)
8415     {
8416         return(TNG_FAILURE);
8417     }
8418
8419     strncpy(name, atom->residue->name, max_len - 1);
8420     name[max_len - 1] = 0;
8421
8422     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
8423     {
8424         return(TNG_FAILURE);
8425     }
8426     return(TNG_SUCCESS);
8427 }
8428
8429 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
8430                 (const tng_trajectory_t tng_data,
8431                  const int64_t nr,
8432                  int64_t *id)
8433 {
8434     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8435     tng_molecule_t mol;
8436     tng_atom_t atom;
8437     tng_bool found = TNG_FALSE;
8438
8439     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8440     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8441
8442     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8443
8444     if(!molecule_cnt_list)
8445     {
8446         return(TNG_FAILURE);
8447     }
8448
8449     for(i = 0; i < tng_data->n_molecules; i++)
8450     {
8451         mol = &tng_data->molecules[i];
8452         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8453         {
8454             cnt += mol->n_atoms * molecule_cnt_list[i];
8455             continue;
8456         }
8457         atom = &mol->atoms[nr % mol->n_atoms];
8458         found = TNG_TRUE;
8459         break;
8460     }
8461     if(!found)
8462     {
8463         return(TNG_FAILURE);
8464     }
8465     if(!atom->residue)
8466     {
8467         return(TNG_FAILURE);
8468     }
8469
8470     *id = atom->residue->id;
8471
8472     return(TNG_SUCCESS);
8473 }
8474
8475 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
8476                 (const tng_trajectory_t tng_data,
8477                  const int64_t nr,
8478                  int64_t *id)
8479 {
8480     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
8481     tng_molecule_t mol;
8482     tng_atom_t atom;
8483     tng_bool found = TNG_FALSE;
8484
8485     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8486     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8487
8488     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8489
8490     if(!molecule_cnt_list)
8491     {
8492         return(TNG_FAILURE);
8493     }
8494
8495     for(i = 0; i < tng_data->n_molecules; i++)
8496     {
8497         mol = &tng_data->molecules[i];
8498         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8499         {
8500             cnt += mol->n_atoms * molecule_cnt_list[i];
8501             offset += mol->n_residues * molecule_cnt_list[i];
8502             continue;
8503         }
8504         atom = &mol->atoms[nr % mol->n_atoms];
8505         found = TNG_TRUE;
8506         break;
8507     }
8508     if(!found)
8509     {
8510         return(TNG_FAILURE);
8511     }
8512     if(!atom->residue)
8513     {
8514         return(TNG_FAILURE);
8515     }
8516
8517     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
8518
8519     *id = atom->residue->id + offset;
8520
8521     return(TNG_SUCCESS);
8522 }
8523
8524 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
8525                 (const tng_trajectory_t tng_data,
8526                  const int64_t nr,
8527                  char *name,
8528                  const int max_len)
8529 {
8530     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8531     tng_molecule_t mol;
8532     tng_atom_t atom;
8533     tng_bool found = TNG_FALSE;
8534
8535     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8536     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8537
8538     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8539
8540     if(!molecule_cnt_list)
8541     {
8542         return(TNG_FAILURE);
8543     }
8544
8545     for(i = 0; i < tng_data->n_molecules; i++)
8546     {
8547         mol = &tng_data->molecules[i];
8548         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8549         {
8550             cnt += mol->n_atoms * molecule_cnt_list[i];
8551             continue;
8552         }
8553         atom = &mol->atoms[nr % mol->n_atoms];
8554         found = TNG_TRUE;
8555         break;
8556     }
8557     if(!found)
8558     {
8559         return(TNG_FAILURE);
8560     }
8561
8562     strncpy(name, atom->name, max_len - 1);
8563     name[max_len - 1] = 0;
8564
8565     if(strlen(atom->name) > (unsigned int)max_len - 1)
8566     {
8567         return(TNG_FAILURE);
8568     }
8569     return(TNG_SUCCESS);
8570 }
8571
8572 tng_function_status tng_atom_type_of_particle_nr_get
8573                 (const tng_trajectory_t tng_data,
8574                  const int64_t nr,
8575                  char *type,
8576                  const int max_len)
8577 {
8578     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8579     tng_molecule_t mol;
8580     tng_atom_t atom;
8581     tng_bool found = TNG_FALSE;
8582
8583     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8584     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
8585
8586     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8587
8588     if(!molecule_cnt_list)
8589     {
8590         return(TNG_FAILURE);
8591     }
8592
8593     for(i = 0; i < tng_data->n_molecules; i++)
8594     {
8595         mol = &tng_data->molecules[i];
8596         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8597         {
8598             cnt += mol->n_atoms * molecule_cnt_list[i];
8599             continue;
8600         }
8601         atom = &mol->atoms[nr % mol->n_atoms];
8602         found = TNG_TRUE;
8603         break;
8604     }
8605     if(!found)
8606     {
8607         return(TNG_FAILURE);
8608     }
8609
8610     strncpy(type, atom->atom_type, max_len - 1);
8611     type[max_len - 1] = 0;
8612
8613     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
8614     {
8615         return(TNG_FAILURE);
8616     }
8617     return(TNG_SUCCESS);
8618 }
8619
8620 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
8621                 (const tng_trajectory_t tng_data,
8622                  const int64_t num_first_particle,
8623                  const int64_t n_particles,
8624                  const int64_t *mapping_table)
8625 {
8626     int64_t i;
8627     tng_particle_mapping_t mapping;
8628     tng_trajectory_frame_set_t frame_set;
8629
8630     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8631
8632     frame_set = &tng_data->current_trajectory_frame_set;
8633
8634     /* Sanity check of the particle ranges. Split into multiple if
8635      * statements for improved readability */
8636     for(i = 0; i < frame_set->n_mapping_blocks; i++)
8637     {
8638         mapping = &frame_set->mappings[i];
8639         if(num_first_particle >= mapping->num_first_particle &&
8640            num_first_particle < mapping->num_first_particle +
8641                                    mapping->n_particles)
8642         {
8643             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8644             return(TNG_FAILURE);
8645         }
8646         if(num_first_particle + n_particles >=
8647            mapping->num_first_particle &&
8648            num_first_particle + n_particles <
8649            mapping->num_first_particle + mapping->n_particles)
8650         {
8651             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8652             return(TNG_FAILURE);
8653         }
8654         if(mapping->num_first_particle >= num_first_particle &&
8655            mapping->num_first_particle < num_first_particle +
8656                                             n_particles)
8657         {
8658             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8659             return(TNG_FAILURE);
8660         }
8661         if(mapping->num_first_particle + mapping->n_particles >
8662            num_first_particle &&
8663            mapping->num_first_particle + mapping->n_particles <
8664            num_first_particle + n_particles)
8665         {
8666             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8667             return(TNG_FAILURE);
8668         }
8669     }
8670
8671     frame_set->n_mapping_blocks++;
8672
8673     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
8674                       frame_set->n_mapping_blocks);
8675
8676     if(!mapping)
8677     {
8678         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8679                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
8680                __FILE__, __LINE__);
8681         free(frame_set->mappings);
8682         frame_set->mappings = 0;
8683         return(TNG_CRITICAL);
8684     }
8685     frame_set->mappings = mapping;
8686
8687     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
8688     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
8689
8690     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
8691     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
8692     {
8693         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8694                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
8695         return(TNG_CRITICAL);
8696     }
8697
8698     for(i=0; i<n_particles; i++)
8699     {
8700         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
8701     }
8702
8703     return(TNG_SUCCESS);
8704 }
8705
8706 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(const tng_trajectory_t tng_data)
8707 {
8708     tng_trajectory_frame_set_t frame_set;
8709     tng_particle_mapping_t mapping;
8710     int64_t i;
8711
8712     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8713
8714     frame_set = &tng_data->current_trajectory_frame_set;
8715
8716     if(frame_set->n_mapping_blocks && frame_set->mappings)
8717     {
8718         for(i = 0; i < frame_set->n_mapping_blocks; i++)
8719         {
8720             mapping = &frame_set->mappings[i];
8721             if(mapping->real_particle_numbers)
8722             {
8723                 free(mapping->real_particle_numbers);
8724                 mapping->real_particle_numbers = 0;
8725             }
8726         }
8727         free(frame_set->mappings);
8728         frame_set->mappings = 0;
8729         frame_set->n_mapping_blocks = 0;
8730     }
8731
8732     return(TNG_SUCCESS);
8733 }
8734
8735 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
8736 {
8737     time_t seconds;
8738     tng_trajectory_frame_set_t frame_set;
8739     tng_trajectory_t tng_data;
8740
8741     *tng_data_p = malloc(sizeof(struct tng_trajectory));
8742     if(!*tng_data_p)
8743     {
8744         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
8745                sizeof(struct tng_trajectory), __FILE__, __LINE__);
8746         return(TNG_CRITICAL);
8747     }
8748
8749     tng_data = *tng_data_p;
8750
8751     frame_set = &tng_data->current_trajectory_frame_set;
8752
8753     tng_data->input_file_path = 0;
8754     tng_data->input_file = 0;
8755     tng_data->input_file_len = 0;
8756     tng_data->output_file_path = 0;
8757     tng_data->output_file = 0;
8758
8759     tng_data->first_program_name = 0;
8760     tng_data->first_user_name = 0;
8761     tng_data->first_computer_name = 0;
8762     tng_data->first_pgp_signature = 0;
8763     tng_data->last_program_name = 0;
8764     tng_data->last_user_name = 0;
8765     tng_data->last_computer_name = 0;
8766     tng_data->last_pgp_signature = 0;
8767     tng_data->forcefield_name = 0;
8768
8769     seconds = time(0);
8770     if ( seconds == -1)
8771     {
8772         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
8773     }
8774     else
8775     {
8776         tng_data->time = seconds;
8777     }
8778
8779     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
8780     tng_data->first_trajectory_frame_set_input_file_pos = -1;
8781     tng_data->last_trajectory_frame_set_input_file_pos = -1;
8782     tng_data->current_trajectory_frame_set_input_file_pos = -1;
8783     tng_data->first_trajectory_frame_set_output_file_pos = -1;
8784     tng_data->last_trajectory_frame_set_output_file_pos = -1;
8785     tng_data->current_trajectory_frame_set_output_file_pos = -1;
8786     tng_data->frame_set_n_frames = 100;
8787     tng_data->n_trajectory_frame_sets = 0;
8788     tng_data->medium_stride_length = 100;
8789     tng_data->long_stride_length = 10000;
8790
8791     tng_data->time_per_frame = -1;
8792
8793     tng_data->n_particle_data_blocks = 0;
8794     tng_data->n_data_blocks = 0;
8795
8796     tng_data->non_tr_particle_data = 0;
8797     tng_data->non_tr_data = 0;
8798
8799     tng_data->compress_algo_pos = 0;
8800     tng_data->compress_algo_vel = 0;
8801     tng_data->compression_precision = 1000;
8802     tng_data->distance_unit_exponential = -9;
8803
8804     frame_set->first_frame = -1;
8805     frame_set->n_mapping_blocks = 0;
8806     frame_set->mappings = 0;
8807     frame_set->molecule_cnt_list = 0;
8808
8809     frame_set->n_particle_data_blocks = 0;
8810     frame_set->n_data_blocks = 0;
8811
8812     frame_set->tr_particle_data = 0;
8813     frame_set->tr_data = 0;
8814
8815     frame_set->n_written_frames = 0;
8816     frame_set->n_unwritten_frames = 0;
8817
8818     frame_set->next_frame_set_file_pos = -1;
8819     frame_set->prev_frame_set_file_pos = -1;
8820     frame_set->medium_stride_next_frame_set_file_pos = -1;
8821     frame_set->medium_stride_prev_frame_set_file_pos = -1;
8822     frame_set->long_stride_next_frame_set_file_pos = -1;
8823     frame_set->long_stride_prev_frame_set_file_pos = -1;
8824
8825     frame_set->first_frame_time = -1;
8826
8827     tng_data->n_molecules = 0;
8828     tng_data->molecules = 0;
8829     tng_data->molecule_cnt_list = 0;
8830     tng_data->n_particles = 0;
8831
8832     {
8833       /* Check the endianness of the computer */
8834       static int32_t endianness_32 = 0x01234567;
8835       /* 0x01234567 */
8836       if ( *(const unsigned char*)&endianness_32 == 0x01 )
8837         {
8838           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
8839         }
8840
8841       /* 0x67452301 */
8842       else if( *(const unsigned char*)&endianness_32 == 0x67 )
8843         {
8844           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
8845
8846         }
8847
8848       /* 0x45670123 */
8849       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
8850         {
8851           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
8852         }
8853     }
8854     {
8855       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
8856       /* 0x0123456789ABCDEF */
8857       if ( *(const unsigned char*)&endianness_64 == 0x01 )
8858         {
8859           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
8860         }
8861
8862       /* 0xEFCDAB8967452301 */
8863       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
8864         {
8865           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
8866         }
8867
8868       /* 0x89ABCDEF01234567 */
8869       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
8870         {
8871           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
8872         }
8873
8874       /* 0x45670123CDEF89AB */
8875       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
8876         {
8877           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
8878         }
8879
8880       /* 0x23016745AB89EFCD */
8881       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
8882         {
8883           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
8884         }
8885     }
8886
8887     /* By default do not swap the byte order, i.e. keep the byte order of the
8888      * architecture. The input file endianness will be set when reading the
8889      * header. The output endianness can be changed - before the file is
8890      * written. */
8891     tng_data->input_endianness_swap_func_32 = 0;
8892     tng_data->input_endianness_swap_func_64 = 0;
8893     tng_data->output_endianness_swap_func_32 = 0;
8894     tng_data->output_endianness_swap_func_64 = 0;
8895
8896     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
8897     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
8898     tng_data->current_trajectory_frame_set.n_frames = 0;
8899
8900     return(TNG_SUCCESS);
8901 }
8902
8903 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
8904 {
8905     int64_t i, j, k, l;
8906     int64_t n_particles, n_values_per_frame;
8907     tng_trajectory_t tng_data = *tng_data_p;
8908     tng_trajectory_frame_set_t frame_set;
8909
8910     if(!*tng_data_p)
8911     {
8912         return(TNG_SUCCESS);
8913     }
8914
8915     frame_set = &tng_data->current_trajectory_frame_set;
8916
8917     if(tng_data->input_file)
8918     {
8919         if(tng_data->output_file == tng_data->input_file)
8920         {
8921             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
8922             tng_data->output_file = 0;
8923         }
8924         fclose(tng_data->input_file);
8925         tng_data->input_file = 0;
8926     }
8927
8928     if(tng_data->input_file_path)
8929     {
8930         free(tng_data->input_file_path);
8931         tng_data->input_file_path = 0;
8932     }
8933
8934     if(tng_data->output_file)
8935     {
8936         /* FIXME: Do not always write the hash */
8937         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
8938         fclose(tng_data->output_file);
8939         tng_data->output_file = 0;
8940     }
8941
8942     if(tng_data->output_file_path)
8943     {
8944         free(tng_data->output_file_path);
8945         tng_data->output_file_path = 0;
8946     }
8947
8948     if(tng_data->first_program_name)
8949     {
8950         free(tng_data->first_program_name);
8951         tng_data->first_program_name = 0;
8952     }
8953
8954     if(tng_data->last_program_name)
8955     {
8956         free(tng_data->last_program_name);
8957         tng_data->last_program_name = 0;
8958     }
8959
8960     if(tng_data->first_user_name)
8961     {
8962         free(tng_data->first_user_name);
8963         tng_data->first_user_name = 0;
8964     }
8965
8966     if(tng_data->last_user_name)
8967     {
8968         free(tng_data->last_user_name);
8969         tng_data->last_user_name = 0;
8970     }
8971
8972     if(tng_data->first_computer_name)
8973     {
8974         free(tng_data->first_computer_name);
8975         tng_data->first_computer_name = 0;
8976     }
8977
8978     if(tng_data->last_computer_name)
8979     {
8980         free(tng_data->last_computer_name);
8981         tng_data->last_computer_name = 0;
8982     }
8983
8984     if(tng_data->first_pgp_signature)
8985     {
8986         free(tng_data->first_pgp_signature);
8987         tng_data->first_pgp_signature = 0;
8988     }
8989
8990     if(tng_data->last_pgp_signature)
8991     {
8992         free(tng_data->last_pgp_signature);
8993         tng_data->last_pgp_signature = 0;
8994     }
8995
8996     if(tng_data->forcefield_name)
8997     {
8998         free(tng_data->forcefield_name);
8999         tng_data->forcefield_name = 0;
9000     }
9001
9002     tng_frame_set_particle_mapping_free(tng_data);
9003
9004     if(frame_set->molecule_cnt_list)
9005     {
9006         free(frame_set->molecule_cnt_list);
9007         frame_set->molecule_cnt_list = 0;
9008     }
9009
9010     if(tng_data->var_num_atoms_flag)
9011     {
9012         n_particles = frame_set->n_particles;
9013     }
9014     else
9015     {
9016         n_particles = tng_data->n_particles;
9017     }
9018
9019     if(tng_data->non_tr_particle_data)
9020     {
9021         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
9022         {
9023             if(tng_data->non_tr_particle_data[i].values)
9024             {
9025                 free(tng_data->non_tr_particle_data[i].values);
9026                 tng_data->non_tr_particle_data[i].values = 0;
9027             }
9028
9029             if(tng_data->non_tr_particle_data[i].strings)
9030             {
9031                 n_values_per_frame = tng_data->non_tr_particle_data[i].
9032                                      n_values_per_frame;
9033                 if(tng_data->non_tr_particle_data[i].strings[0])
9034                 {
9035                     for(j = 0; j < n_particles; j++)
9036                     {
9037                         if(tng_data->non_tr_particle_data[i].strings[0][j])
9038                         {
9039                             for(k = 0; k < n_values_per_frame; k++)
9040                             {
9041                                 if(tng_data->non_tr_particle_data[i].
9042                                    strings[0][j][k])
9043                                 {
9044                                     free(tng_data->non_tr_particle_data[i].
9045                                          strings[0][j][k]);
9046                                     tng_data->non_tr_particle_data[i].
9047                                     strings[0][j][k] = 0;
9048                                 }
9049                             }
9050                             free(tng_data->non_tr_particle_data[i].
9051                                  strings[0][j]);
9052                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
9053                         }
9054                     }
9055                     free(tng_data->non_tr_particle_data[i].strings[0]);
9056                     tng_data->non_tr_particle_data[i].strings[0] = 0;
9057                 }
9058                 free(tng_data->non_tr_particle_data[i].strings);
9059                 tng_data->non_tr_particle_data[i].strings = 0;
9060             }
9061
9062             if(tng_data->non_tr_particle_data[i].block_name)
9063             {
9064                 free(tng_data->non_tr_particle_data[i].block_name);
9065                 tng_data->non_tr_particle_data[i].block_name = 0;
9066             }
9067         }
9068         free(tng_data->non_tr_particle_data);
9069         tng_data->non_tr_particle_data = 0;
9070     }
9071
9072     if(tng_data->non_tr_data)
9073     {
9074         for(i = 0; i < tng_data->n_data_blocks; i++)
9075         {
9076             if(tng_data->non_tr_data[i].values)
9077             {
9078                 free(tng_data->non_tr_data[i].values);
9079                 tng_data->non_tr_data[i].values = 0;
9080             }
9081
9082             if(tng_data->non_tr_data[i].strings)
9083             {
9084                 n_values_per_frame = tng_data->non_tr_data[i].
9085                                      n_values_per_frame;
9086                 if(tng_data->non_tr_data[i].strings[0][0])
9087                 {
9088                     for(j = 0; j < n_values_per_frame; j++)
9089                     {
9090                         if(tng_data->non_tr_data[i].strings[0][0][j])
9091                         {
9092                             free(tng_data->non_tr_data[i].strings[0][0][j]);
9093                             tng_data->non_tr_data[i].strings[0][0][j] = 0;
9094                         }
9095                     }
9096                     free(tng_data->non_tr_data[i].strings[0][0]);
9097                     tng_data->non_tr_data[i].strings[0][0] = 0;
9098                 }
9099                 free(tng_data->non_tr_data[i].strings[0]);
9100                 tng_data->non_tr_data[i].strings[0] = 0;
9101                 free(tng_data->non_tr_data[i].strings);
9102                 tng_data->non_tr_data[i].strings = 0;
9103             }
9104
9105             if(tng_data->non_tr_data[i].block_name)
9106             {
9107                 free(tng_data->non_tr_data[i].block_name);
9108                 tng_data->non_tr_data[i].block_name = 0;
9109             }
9110         }
9111         free(tng_data->non_tr_data);
9112         tng_data->non_tr_data = 0;
9113     }
9114
9115     tng_data->n_particle_data_blocks = 0;
9116     tng_data->n_data_blocks = 0;
9117
9118     if(tng_data->compress_algo_pos)
9119     {
9120         free(tng_data->compress_algo_pos);
9121         tng_data->compress_algo_pos = 0;
9122     }
9123     if(tng_data->compress_algo_vel)
9124     {
9125         free(tng_data->compress_algo_vel);
9126         tng_data->compress_algo_vel = 0;
9127     }
9128
9129     if(frame_set->tr_particle_data)
9130     {
9131         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
9132         {
9133             if(frame_set->tr_particle_data[i].values)
9134             {
9135                 free(frame_set->tr_particle_data[i].values);
9136                 frame_set->tr_particle_data[i].values = 0;
9137             }
9138
9139             if(frame_set->tr_particle_data[i].strings)
9140             {
9141                 n_values_per_frame = frame_set->tr_particle_data[i].
9142                                      n_values_per_frame;
9143                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
9144                 {
9145                     if(frame_set->tr_particle_data[i].strings[j])
9146                     {
9147                         for(k = 0; k < n_particles; k++)
9148                         {
9149                             if(frame_set->tr_particle_data[i].
9150                                 strings[j][k])
9151                             {
9152                                 for(l = 0; l < n_values_per_frame; l++)
9153                                 {
9154                                     if(frame_set->tr_particle_data[i].
9155                                         strings[j][k][l])
9156                                     {
9157                                         free(frame_set->tr_particle_data[i].
9158                                                 strings[j][k][l]);
9159                                         frame_set->tr_particle_data[i].
9160                                         strings[j][k][l] = 0;
9161                                     }
9162                                 }
9163                                 free(frame_set->tr_particle_data[i].
9164                                         strings[j][k]);
9165                                 frame_set->tr_particle_data[i].
9166                                 strings[j][k] = 0;
9167                             }
9168                         }
9169                         free(frame_set->tr_particle_data[i].strings[j]);
9170                         frame_set->tr_particle_data[i].strings[j] = 0;
9171                     }
9172                 }
9173                 free(frame_set->tr_particle_data[i].strings);
9174                 frame_set->tr_particle_data[i].strings = 0;
9175             }
9176
9177             if(frame_set->tr_particle_data[i].block_name)
9178             {
9179                 free(frame_set->tr_particle_data[i].block_name);
9180                 frame_set->tr_particle_data[i].block_name = 0;
9181             }
9182         }
9183         free(frame_set->tr_particle_data);
9184         frame_set->tr_particle_data = 0;
9185     }
9186
9187     if(frame_set->tr_data)
9188     {
9189         for(i = 0; i < frame_set->n_data_blocks; i++)
9190         {
9191             if(frame_set->tr_data[i].values)
9192             {
9193                 free(frame_set->tr_data[i].values);
9194                 frame_set->tr_data[i].values = 0;
9195             }
9196
9197             if(frame_set->tr_data[i].strings)
9198             {
9199                 n_values_per_frame = frame_set->tr_data[i].
9200                                      n_values_per_frame;
9201                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
9202                 {
9203                     if(frame_set->tr_data[i].strings[j])
9204                     {
9205                         for(k = 0; k < n_values_per_frame; k++)
9206                         {
9207                             if(frame_set->tr_data[i].strings[j][k])
9208                             {
9209                                 free(frame_set->tr_data[i].strings[j][k]);
9210                                 frame_set->tr_data[i].strings[j][k] = 0;
9211                             }
9212                         }
9213                         free(frame_set->tr_data[i].strings[j]);
9214                         frame_set->tr_data[i].strings[j] = 0;
9215                     }
9216                 }
9217                 free(frame_set->tr_data[i].strings);
9218                 frame_set->tr_data[i].strings = 0;
9219             }
9220
9221             if(frame_set->tr_data[i].block_name)
9222             {
9223                 free(frame_set->tr_data[i].block_name);
9224                 frame_set->tr_data[i].block_name = 0;
9225             }
9226         }
9227         free(frame_set->tr_data);
9228         frame_set->tr_data = 0;
9229     }
9230
9231     frame_set->n_particle_data_blocks = 0;
9232     frame_set->n_data_blocks = 0;
9233
9234     if(tng_data->molecules)
9235     {
9236         for(i = 0; i < tng_data->n_molecules; i++)
9237         {
9238             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
9239         }
9240         free(tng_data->molecules);
9241         tng_data->molecules = 0;
9242         tng_data->n_molecules = 0;
9243     }
9244     if(tng_data->molecule_cnt_list)
9245     {
9246         free(tng_data->molecule_cnt_list);
9247         tng_data->molecule_cnt_list = 0;
9248     }
9249
9250     free(*tng_data_p);
9251     *tng_data_p = 0;
9252
9253     return(TNG_SUCCESS);
9254 }
9255
9256 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src
9257                 (const tng_trajectory_t src,
9258                  tng_trajectory_t *dest_p)
9259 {
9260     tng_trajectory_frame_set_t frame_set;
9261     tng_trajectory_t dest;
9262
9263     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
9264
9265     *dest_p = malloc(sizeof(struct tng_trajectory));
9266     if(!*dest_p)
9267     {
9268         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
9269                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9270         return(TNG_CRITICAL);
9271     }
9272
9273     dest = *dest_p;
9274
9275     frame_set = &dest->current_trajectory_frame_set;
9276
9277     if(src->input_file_path)
9278     {
9279         dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
9280         if(!dest->input_file_path)
9281         {
9282             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
9283                    (unsigned int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
9284             return(TNG_CRITICAL);
9285         }
9286         strcpy(dest->input_file_path, src->input_file_path);
9287         dest->input_file_len = src->input_file_len;
9288     }
9289     else
9290     {
9291         dest->input_file_path = 0;
9292     }
9293     dest->input_file = 0;
9294     if(src->output_file_path)
9295     {
9296         dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
9297         if(!dest->output_file_path)
9298         {
9299             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
9300                    (unsigned int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
9301             return(TNG_CRITICAL);
9302         }
9303         strcpy(dest->output_file_path, src->output_file_path);
9304     }
9305     else
9306     {
9307         dest->output_file_path = 0;
9308     }
9309     dest->output_file = 0;
9310
9311     dest->first_program_name = 0;
9312     dest->first_user_name = 0;
9313     dest->first_computer_name = 0;
9314     dest->first_pgp_signature = 0;
9315     dest->last_program_name = 0;
9316     dest->last_user_name = 0;
9317     dest->last_computer_name = 0;
9318     dest->last_pgp_signature = 0;
9319     dest->forcefield_name = 0;
9320
9321     dest->var_num_atoms_flag = src->var_num_atoms_flag;
9322     dest->first_trajectory_frame_set_input_file_pos =
9323     src->first_trajectory_frame_set_input_file_pos;
9324     dest->last_trajectory_frame_set_input_file_pos =
9325     src->last_trajectory_frame_set_input_file_pos;
9326     dest->current_trajectory_frame_set_input_file_pos =
9327     src->current_trajectory_frame_set_input_file_pos;
9328     dest->first_trajectory_frame_set_output_file_pos =
9329     src->first_trajectory_frame_set_output_file_pos;
9330     dest->last_trajectory_frame_set_output_file_pos =
9331     src->last_trajectory_frame_set_output_file_pos;
9332     dest->current_trajectory_frame_set_output_file_pos =
9333     src->current_trajectory_frame_set_output_file_pos;
9334     dest->frame_set_n_frames = src->frame_set_n_frames;
9335     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
9336     dest->medium_stride_length = src->medium_stride_length;
9337     dest->long_stride_length = src->long_stride_length;
9338
9339     dest->time_per_frame = src->time_per_frame;
9340
9341     /* Currently the non trajectory data blocks are not copied since it
9342      * can lead to problems when freeing memory in a parallel block. */
9343     dest->n_particle_data_blocks = 0;
9344     dest->n_data_blocks = 0;
9345     dest->non_tr_particle_data = 0;
9346     dest->non_tr_data = 0;
9347
9348     dest->compress_algo_pos = 0;
9349     dest->compress_algo_vel = 0;
9350     dest->distance_unit_exponential = -9;
9351     dest->compression_precision = 1000;
9352
9353     frame_set->n_mapping_blocks = 0;
9354     frame_set->mappings = 0;
9355     frame_set->molecule_cnt_list = 0;
9356
9357     frame_set->n_particle_data_blocks = 0;
9358     frame_set->n_data_blocks = 0;
9359
9360     frame_set->tr_particle_data = 0;
9361     frame_set->tr_data = 0;
9362
9363     frame_set->n_written_frames = 0;
9364     frame_set->n_unwritten_frames = 0;
9365
9366     frame_set->next_frame_set_file_pos = -1;
9367     frame_set->prev_frame_set_file_pos = -1;
9368     frame_set->medium_stride_next_frame_set_file_pos = -1;
9369     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9370     frame_set->long_stride_next_frame_set_file_pos = -1;
9371     frame_set->long_stride_prev_frame_set_file_pos = -1;
9372     frame_set->first_frame = -1;
9373
9374     dest->n_molecules = 0;
9375     dest->molecules = 0;
9376     dest->molecule_cnt_list = 0;
9377     dest->n_particles = src->n_particles;
9378
9379     dest->endianness_32 = src->endianness_32;
9380     dest->endianness_64 = src->endianness_64;
9381     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
9382     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
9383     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
9384     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
9385
9386     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9387     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9388     dest->current_trajectory_frame_set.n_frames = 0;
9389
9390     return(TNG_SUCCESS);
9391 }
9392
9393 tng_function_status DECLSPECDLLEXPORT tng_input_file_get
9394                 (const tng_trajectory_t tng_data,
9395                  char *file_name,
9396                  const int max_len)
9397 {
9398     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9399     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9400
9401     strncpy(file_name, tng_data->input_file_path, max_len - 1);
9402     file_name[max_len - 1] = 0;
9403
9404     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
9405     {
9406         return(TNG_FAILURE);
9407     }
9408     return(TNG_SUCCESS);
9409 }
9410
9411 tng_function_status DECLSPECDLLEXPORT tng_input_file_set
9412                 (const tng_trajectory_t tng_data,
9413                  const char *file_name)
9414 {
9415     unsigned int len;
9416     char *temp;
9417
9418     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9419     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9420
9421
9422     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
9423                                            file_name) == 0)
9424     {
9425         return(TNG_SUCCESS);
9426     }
9427
9428     if(tng_data->input_file)
9429     {
9430         fclose(tng_data->input_file);
9431     }
9432
9433     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9434     temp = realloc(tng_data->input_file_path, len);
9435     if(!temp)
9436     {
9437         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9438                __FILE__, __LINE__);
9439         free(tng_data->input_file_path);
9440         tng_data->input_file_path = 0;
9441         return(TNG_CRITICAL);
9442     }
9443     tng_data->input_file_path = temp;
9444
9445     strncpy(tng_data->input_file_path, file_name, len);
9446
9447     return(tng_input_file_init(tng_data));
9448 }
9449
9450 tng_function_status tng_output_file_get
9451                 (const tng_trajectory_t tng_data,
9452                  char *file_name,
9453                  const int max_len)
9454 {
9455     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9456     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9457
9458     strncpy(file_name, tng_data->output_file_path, max_len - 1);
9459     file_name[max_len - 1] = 0;
9460
9461     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
9462     {
9463         return(TNG_FAILURE);
9464     }
9465     return(TNG_SUCCESS);
9466 }
9467
9468 tng_function_status DECLSPECDLLEXPORT tng_output_file_set
9469                 (const tng_trajectory_t tng_data,
9470                  const char *file_name)
9471 {
9472     int len;
9473     char *temp;
9474
9475     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9476     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9477
9478     if(tng_data->output_file_path &&
9479        strcmp(tng_data->output_file_path, file_name) == 0)
9480     {
9481         return(TNG_SUCCESS);
9482     }
9483
9484     if(tng_data->output_file)
9485     {
9486         fclose(tng_data->output_file);
9487     }
9488
9489     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9490     temp = realloc(tng_data->output_file_path, len);
9491     if(!temp)
9492     {
9493         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
9494                __FILE__, __LINE__);
9495         free(tng_data->output_file_path);
9496         tng_data->output_file_path = 0;
9497         return(TNG_CRITICAL);
9498     }
9499     tng_data->output_file_path = temp;
9500
9501     strncpy(tng_data->output_file_path, file_name, len);
9502
9503     return(tng_output_file_init(tng_data));
9504 }
9505
9506 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
9507                 (const tng_trajectory_t tng_data,
9508                  const char *file_name)
9509 {
9510     int len;
9511     char *temp;
9512
9513     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9514     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9515
9516     if(tng_data->output_file_path &&
9517        strcmp(tng_data->output_file_path, file_name) == 0)
9518     {
9519         return(TNG_SUCCESS);
9520     }
9521
9522     if(tng_data->output_file)
9523     {
9524         fclose(tng_data->output_file);
9525     }
9526
9527     len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9528     temp = realloc(tng_data->output_file_path, len);
9529     if(!temp)
9530     {
9531         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
9532                __FILE__, __LINE__);
9533         free(tng_data->output_file_path);
9534         tng_data->output_file_path = 0;
9535         return(TNG_CRITICAL);
9536     }
9537     tng_data->output_file_path = temp;
9538
9539     strncpy(tng_data->output_file_path, file_name, len);
9540
9541     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
9542     if(!tng_data->output_file)
9543     {
9544         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
9545                 tng_data->output_file_path, __FILE__, __LINE__);
9546         return(TNG_CRITICAL);
9547     }
9548     tng_data->input_file = tng_data->output_file;
9549
9550     return(TNG_SUCCESS);
9551 }
9552
9553 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
9554                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
9555 {
9556     tng_endianness_32 end_32;
9557     tng_endianness_64 end_64;
9558
9559     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9560     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
9561
9562     if(tng_data->output_endianness_swap_func_32)
9563     {
9564         /* If other endianness variants are added they must be added here as well */
9565         if(tng_data->output_endianness_swap_func_32 ==
9566            &tng_swap_byte_order_big_endian_32)
9567         {
9568             end_32 = TNG_BIG_ENDIAN_32;
9569         }
9570         else if(tng_data->output_endianness_swap_func_32 ==
9571                 &tng_swap_byte_order_little_endian_32)
9572         {
9573             end_32 = TNG_LITTLE_ENDIAN_32;
9574         }
9575         else
9576         {
9577             return(TNG_FAILURE);
9578         }
9579     }
9580     else
9581     {
9582         end_32 = (tng_endianness_32)tng_data->endianness_32;
9583     }
9584
9585     if(tng_data->output_endianness_swap_func_64)
9586     {
9587         /* If other endianness variants are added they must be added here as well */
9588         if(tng_data->output_endianness_swap_func_64 ==
9589            &tng_swap_byte_order_big_endian_64)
9590         {
9591             end_64 = TNG_BIG_ENDIAN_64;
9592         }
9593         else if(tng_data->output_endianness_swap_func_64 ==
9594                 &tng_swap_byte_order_little_endian_64)
9595         {
9596             end_64 = TNG_LITTLE_ENDIAN_64;
9597         }
9598         else
9599         {
9600             return(TNG_FAILURE);
9601         }
9602     }
9603     else
9604     {
9605         end_64 = (tng_endianness_64)tng_data->endianness_64;
9606     }
9607
9608     if((int)end_32 != (int)end_64)
9609     {
9610         return(TNG_FAILURE);
9611     }
9612
9613     if(end_32 == TNG_LITTLE_ENDIAN_32)
9614     {
9615         *endianness = TNG_LITTLE_ENDIAN;
9616     }
9617
9618     else if(end_32 == TNG_BIG_ENDIAN_32)
9619     {
9620         *endianness = TNG_BIG_ENDIAN;
9621     }
9622     else
9623     {
9624         return(TNG_FAILURE);
9625     }
9626
9627     return(TNG_SUCCESS);
9628 }
9629
9630 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
9631                 (const tng_trajectory_t tng_data,
9632                  const tng_file_endianness endianness)
9633 {
9634     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9635
9636     /* Tne endianness cannot be changed if the data has already been written
9637      * to the output file. */
9638     if(ftello(tng_data->output_file) > 0)
9639     {
9640         return(TNG_FAILURE);
9641     }
9642
9643     if(endianness == TNG_BIG_ENDIAN)
9644     {
9645         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
9646         {
9647             tng_data->output_endianness_swap_func_32 = 0;
9648         }
9649         else
9650         {
9651             tng_data->output_endianness_swap_func_32 =
9652             &tng_swap_byte_order_big_endian_32;
9653         }
9654         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
9655         {
9656             tng_data->output_endianness_swap_func_64 = 0;
9657         }
9658         else
9659         {
9660             tng_data->output_endianness_swap_func_64 =
9661             &tng_swap_byte_order_big_endian_64;
9662         }
9663         return(TNG_SUCCESS);
9664     }
9665     else if(endianness == TNG_LITTLE_ENDIAN)
9666     {
9667         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
9668         {
9669             tng_data->output_endianness_swap_func_32 = 0;
9670         }
9671         else
9672         {
9673             tng_data->output_endianness_swap_func_32 =
9674             &tng_swap_byte_order_little_endian_32;
9675         }
9676         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
9677         {
9678             tng_data->output_endianness_swap_func_64 = 0;
9679         }
9680         else
9681         {
9682             tng_data->output_endianness_swap_func_64 =
9683             &tng_swap_byte_order_little_endian_64;
9684         }
9685         return(TNG_SUCCESS);
9686     }
9687
9688     /* If the specified endianness is neither big nor little endian return a
9689      * failure. */
9690     return(TNG_FAILURE);
9691 }
9692
9693 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
9694                     (const tng_trajectory_t tng_data,
9695                      char *name,
9696                      const int max_len)
9697 {
9698     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9699     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9700
9701     strncpy(name, tng_data->first_program_name, max_len - 1);
9702     name[max_len - 1] = 0;
9703
9704     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
9705     {
9706         return(TNG_FAILURE);
9707     }
9708     return(TNG_SUCCESS);
9709 }
9710
9711 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set
9712                 (const tng_trajectory_t tng_data,
9713                  const char *new_name)
9714 {
9715     unsigned int len;
9716
9717     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9718     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9719
9720     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9721
9722     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
9723     {
9724         free(tng_data->first_program_name);
9725         tng_data->first_program_name = 0;
9726     }
9727     if(!tng_data->first_program_name)
9728     {
9729         tng_data->first_program_name = malloc(len);
9730         if(!tng_data->first_program_name)
9731         {
9732             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9733                    __FILE__, __LINE__);
9734             return(TNG_CRITICAL);
9735         }
9736     }
9737
9738     strncpy(tng_data->first_program_name, new_name, len);
9739
9740     return(TNG_SUCCESS);
9741 }
9742
9743 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
9744                     (const tng_trajectory_t tng_data,
9745                      char *name, const int max_len)
9746 {
9747     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9748     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9749
9750     strncpy(name, tng_data->last_program_name, max_len - 1);
9751     name[max_len - 1] = 0;
9752
9753     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
9754     {
9755         return(TNG_FAILURE);
9756     }
9757     return(TNG_SUCCESS);
9758 }
9759
9760 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
9761                     (const tng_trajectory_t tng_data,
9762                      const char *new_name)
9763 {
9764     unsigned int len;
9765
9766     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9767     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9768
9769     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9770
9771     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
9772     {
9773         free(tng_data->last_program_name);
9774         tng_data->last_program_name = 0;
9775     }
9776     if(!tng_data->last_program_name)
9777     {
9778         tng_data->last_program_name = malloc(len);
9779         if(!tng_data->last_program_name)
9780         {
9781             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9782                    __FILE__, __LINE__);
9783             return(TNG_CRITICAL);
9784         }
9785     }
9786
9787     strncpy(tng_data->last_program_name, new_name, len);
9788
9789     return(TNG_SUCCESS);
9790 }
9791
9792 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
9793                     (const tng_trajectory_t tng_data,
9794                      char *name, const int max_len)
9795 {
9796     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9797     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9798
9799     strncpy(name, tng_data->first_user_name, max_len - 1);
9800     name[max_len - 1] = 0;
9801
9802     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
9803     {
9804         return(TNG_FAILURE);
9805     }
9806     return(TNG_SUCCESS);
9807 }
9808
9809 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
9810                     (const tng_trajectory_t tng_data,
9811                      const char *new_name)
9812 {
9813     unsigned int len;
9814
9815     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9816     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9817
9818     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9819
9820     /* If the currently stored string length is not enough to store the new
9821      * string it is freed and reallocated. */
9822     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
9823     {
9824         free(tng_data->first_user_name);
9825         tng_data->first_user_name = 0;
9826     }
9827     if(!tng_data->first_user_name)
9828     {
9829         tng_data->first_user_name = malloc(len);
9830         if(!tng_data->first_user_name)
9831         {
9832             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9833                    __FILE__, __LINE__);
9834             return(TNG_CRITICAL);
9835         }
9836     }
9837
9838     strncpy(tng_data->first_user_name, new_name, len);
9839
9840     return(TNG_SUCCESS);
9841 }
9842
9843 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
9844                     (const tng_trajectory_t tng_data,
9845                      char *name, const int max_len)
9846 {
9847     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9848     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9849
9850     strncpy(name, tng_data->last_user_name, max_len - 1);
9851     name[max_len - 1] = 0;
9852
9853     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
9854     {
9855         return(TNG_FAILURE);
9856     }
9857     return(TNG_SUCCESS);
9858 }
9859
9860 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
9861                     (const tng_trajectory_t tng_data,
9862                      const char *new_name)
9863 {
9864     unsigned int len;
9865
9866     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9867     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9868
9869     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9870
9871     /* If the currently stored string length is not enough to store the new
9872      * string it is freed and reallocated. */
9873     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
9874     {
9875         free(tng_data->last_user_name);
9876         tng_data->last_user_name = 0;
9877     }
9878     if(!tng_data->last_user_name)
9879     {
9880         tng_data->last_user_name = malloc(len);
9881         if(!tng_data->last_user_name)
9882         {
9883             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9884                    __FILE__, __LINE__);
9885             return(TNG_CRITICAL);
9886         }
9887     }
9888
9889     strncpy(tng_data->last_user_name, new_name, len);
9890
9891     return(TNG_SUCCESS);
9892 }
9893
9894 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
9895                     (const tng_trajectory_t tng_data,
9896                      char *name, const int max_len)
9897 {
9898     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9899     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9900
9901     strncpy(name, tng_data->first_computer_name, max_len - 1);
9902     name[max_len - 1] = 0;
9903
9904     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
9905     {
9906         return(TNG_FAILURE);
9907     }
9908     return(TNG_SUCCESS);
9909 }
9910
9911 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
9912                     (const tng_trajectory_t tng_data,
9913                      const char *new_name)
9914 {
9915     unsigned int len;
9916
9917     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9918     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9919
9920     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9921
9922     /* If the currently stored string length is not enough to store the new
9923      * string it is freed and reallocated. */
9924     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
9925     {
9926         free(tng_data->first_computer_name);
9927         tng_data->first_computer_name = 0;
9928     }
9929     if(!tng_data->first_computer_name)
9930     {
9931         tng_data->first_computer_name = malloc(len);
9932         if(!tng_data->first_computer_name)
9933         {
9934             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9935                    __FILE__, __LINE__);
9936             return(TNG_CRITICAL);
9937         }
9938     }
9939
9940     strncpy(tng_data->first_computer_name, new_name, len);
9941
9942     return(TNG_SUCCESS);
9943 }
9944
9945 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
9946                     (const tng_trajectory_t tng_data,
9947                      char *name, const int max_len)
9948 {
9949     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9950     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9951
9952     strncpy(name, tng_data->last_computer_name, max_len - 1);
9953     name[max_len - 1] = 0;
9954
9955     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
9956     {
9957         return(TNG_FAILURE);
9958     }
9959     return(TNG_SUCCESS);
9960 }
9961
9962 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
9963                     (const tng_trajectory_t tng_data,
9964                      const char *new_name)
9965 {
9966     unsigned int len;
9967
9968     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9969     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9970
9971     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9972
9973     /* If the currently stored string length is not enough to store the new
9974      * string it is freed and reallocated. */
9975     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
9976         len)
9977     {
9978         free(tng_data->last_computer_name);
9979         tng_data->last_computer_name = 0;
9980     }
9981     if(!tng_data->last_computer_name)
9982     {
9983         tng_data->last_computer_name = malloc(len);
9984         if(!tng_data->last_computer_name)
9985         {
9986             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9987                    __FILE__, __LINE__);
9988             return(TNG_CRITICAL);
9989         }
9990     }
9991
9992     strncpy(tng_data->last_computer_name, new_name, len);
9993
9994     return(TNG_SUCCESS);
9995 }
9996
9997 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
9998                     (const tng_trajectory_t tng_data,
9999                      char *signature, const int max_len)
10000 {
10001     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10002     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10003
10004     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
10005     signature[max_len - 1] = 0;
10006
10007     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
10008     {
10009         return(TNG_FAILURE);
10010     }
10011     return(TNG_SUCCESS);
10012 }
10013
10014 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
10015                     (const tng_trajectory_t tng_data,
10016                      const char *signature)
10017 {
10018     unsigned int len;
10019
10020     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10021     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10022
10023     len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN);
10024
10025     /* If the currently stored string length is not enough to store the new
10026      * string it is freed and reallocated. */
10027     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
10028         len)
10029     {
10030         free(tng_data->first_pgp_signature);
10031         tng_data->first_pgp_signature = 0;
10032     }
10033     if(!tng_data->first_pgp_signature)
10034     {
10035         tng_data->first_pgp_signature = malloc(len);
10036         if(!tng_data->first_pgp_signature)
10037         {
10038             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10039                    __FILE__, __LINE__);
10040             return(TNG_CRITICAL);
10041         }
10042     }
10043
10044     strncpy(tng_data->first_pgp_signature, signature, len);
10045
10046     return(TNG_SUCCESS);
10047 }
10048
10049 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
10050                     (const tng_trajectory_t tng_data,
10051                      char *signature, const int max_len)
10052 {
10053     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10054     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10055
10056     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
10057     signature[max_len - 1] = 0;
10058
10059     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
10060     {
10061         return(TNG_FAILURE);
10062     }
10063     return(TNG_SUCCESS);
10064 }
10065
10066 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
10067                     (const tng_trajectory_t tng_data,
10068                      const char *signature)
10069 {
10070     unsigned int len;
10071
10072     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10073     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10074
10075     len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN);
10076
10077     /* If the currently stored string length is not enough to store the new
10078      * string it is freed and reallocated. */
10079     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
10080         len)
10081     {
10082         free(tng_data->last_pgp_signature);
10083         tng_data->last_pgp_signature = 0;
10084     }
10085     if(!tng_data->last_pgp_signature)
10086     {
10087         tng_data->last_pgp_signature = malloc(len);
10088         if(!tng_data->last_pgp_signature)
10089         {
10090             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10091                    __FILE__, __LINE__);
10092             return(TNG_CRITICAL);
10093         }
10094     }
10095
10096     strncpy(tng_data->last_pgp_signature, signature, len);
10097
10098     return(TNG_SUCCESS);
10099 }
10100
10101 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
10102                     (const tng_trajectory_t tng_data,
10103                      char *name, const int max_len)
10104 {
10105     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10106     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10107
10108     strncpy(name, tng_data->forcefield_name, max_len - 1);
10109     name[max_len - 1] = 0;
10110
10111     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
10112     {
10113         return(TNG_FAILURE);
10114     }
10115     return(TNG_SUCCESS);
10116 }
10117
10118 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
10119                     (const tng_trajectory_t tng_data,
10120                      const char *new_name)
10121 {
10122     unsigned int len;
10123
10124     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10125     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10126
10127     len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
10128
10129     /* If the currently stored string length is not enough to store the new
10130      * string it is freed and reallocated. */
10131     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
10132     {
10133         free(tng_data->forcefield_name);
10134         tng_data->forcefield_name = 0;
10135     }
10136     if(!tng_data->forcefield_name)
10137     {
10138         tng_data->forcefield_name = malloc(len);
10139         if(!tng_data->forcefield_name)
10140         {
10141             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10142                    __FILE__, __LINE__);
10143             return(TNG_CRITICAL);
10144         }
10145     }
10146
10147     strncpy(tng_data->forcefield_name, new_name, len);
10148
10149     return(TNG_SUCCESS);
10150 }
10151
10152 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
10153                     (const tng_trajectory_t tng_data,
10154                      int64_t *len)
10155 {
10156     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10157     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10158
10159     *len = tng_data->medium_stride_length;
10160
10161     return(TNG_SUCCESS);
10162 }
10163
10164 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
10165                     (const tng_trajectory_t tng_data,
10166                      const int64_t len)
10167 {
10168     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10169
10170     if(len >= tng_data->long_stride_length)
10171     {
10172         return(TNG_FAILURE);
10173     }
10174     tng_data->medium_stride_length = len;
10175
10176     return(TNG_SUCCESS);
10177 }
10178
10179 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
10180                 (const tng_trajectory_t tng_data,
10181                  int64_t *len)
10182 {
10183     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10184     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10185
10186     *len = tng_data->long_stride_length;
10187
10188     return(TNG_SUCCESS);
10189 }
10190
10191 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
10192                 (const tng_trajectory_t tng_data,
10193                  const int64_t len)
10194 {
10195     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10196
10197     if(len <= tng_data->medium_stride_length)
10198     {
10199         return(TNG_FAILURE);
10200     }
10201     tng_data->long_stride_length = len;
10202
10203     return(TNG_SUCCESS);
10204 }
10205
10206 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
10207                 (const tng_trajectory_t tng_data,
10208                  double *time)
10209 {
10210     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10211     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
10212
10213     *time = tng_data->time_per_frame;
10214
10215     return(TNG_SUCCESS);
10216 }
10217
10218 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
10219                 (const tng_trajectory_t tng_data,
10220                  const double time)
10221 {
10222     tng_trajectory_frame_set_t frame_set;
10223
10224     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10225     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
10226
10227     if(fabs(time - tng_data->time_per_frame) < 0.00001)
10228     {
10229         return(TNG_SUCCESS);
10230     }
10231
10232     frame_set = &tng_data->current_trajectory_frame_set;
10233
10234     /* If the current frame set is not finished write it to disk before
10235        changing time per frame. */
10236     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
10237     {
10238         frame_set->n_frames = frame_set->n_unwritten_frames;
10239         tng_frame_set_write(tng_data, TNG_USE_HASH);
10240     }
10241     tng_data->time_per_frame = time;
10242
10243     return(TNG_SUCCESS);
10244 }
10245
10246 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
10247                     (const tng_trajectory_t tng_data,
10248                      int64_t *len)
10249 {
10250     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10251     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10252
10253     *len = tng_data->input_file_len;
10254
10255     return(TNG_SUCCESS);
10256 }
10257
10258 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
10259                     (const tng_trajectory_t tng_data,
10260                      int64_t *n)
10261 {
10262     tng_gen_block_t block;
10263     tng_function_status stat;
10264     int64_t file_pos, last_file_pos, first_frame, n_frames;
10265
10266     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10267     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
10268     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10269
10270     file_pos = ftello(tng_data->input_file);
10271     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10272
10273     if(last_file_pos <= 0)
10274     {
10275         return(TNG_FAILURE);
10276     }
10277
10278     tng_block_init(&block);
10279     fseeko(tng_data->input_file,
10280            last_file_pos,
10281            SEEK_SET);
10282     /* Read block headers first to see that a frame set block is found. */
10283     stat = tng_block_header_read(tng_data, block);
10284     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10285     {
10286         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
10287                 __FILE__, __LINE__);
10288         tng_block_destroy(&block);
10289         return(TNG_FAILURE);
10290     }
10291     tng_block_destroy(&block);
10292
10293     if(tng_file_input_numerical(tng_data, &first_frame,
10294                                 sizeof(first_frame),
10295                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
10296     {
10297         return(TNG_CRITICAL);
10298     }
10299
10300     if(tng_file_input_numerical(tng_data, &n_frames,
10301                                 sizeof(n_frames),
10302                                 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
10303     {
10304         return(TNG_CRITICAL);
10305     }
10306
10307     fseeko(tng_data->input_file, file_pos, SEEK_SET);
10308
10309     *n = first_frame + n_frames;
10310
10311     return(TNG_SUCCESS);
10312 }
10313
10314 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
10315                 (const tng_trajectory_t tng_data,
10316                  double *precision)
10317 {
10318     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10319
10320     *precision = tng_data->compression_precision;
10321
10322     return(TNG_SUCCESS);
10323 }
10324
10325 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
10326                 (const tng_trajectory_t tng_data,
10327                  const double precision)
10328 {
10329     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10330
10331     tng_data->compression_precision = precision;
10332
10333     return(TNG_SUCCESS);
10334 }
10335
10336 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
10337                 (const tng_trajectory_t tng_data,
10338                  const int64_t n)
10339 {
10340     tng_molecule_t mol;
10341     tng_chain_t chain;
10342     tng_residue_t res;
10343     tng_atom_t atom;
10344     tng_function_status stat;
10345     int64_t diff, n_mod, n_impl;
10346
10347     TNG_ASSERT(n >= 0, "TNG library: The requested number of particles must be >= 0");
10348
10349     diff = n - tng_data->n_particles;
10350
10351     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
10352     if(stat == TNG_SUCCESS)
10353     {
10354         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
10355         {
10356             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
10357                     __FILE__, __LINE__);
10358             return(TNG_FAILURE);
10359         }
10360         diff -= n_impl * mol->n_atoms;
10361     }
10362
10363     if(diff == 0)
10364     {
10365         if(stat == TNG_SUCCESS)
10366         {
10367             stat = tng_molecule_cnt_set(tng_data, mol, 0);
10368             return(stat);
10369         }
10370         return(TNG_SUCCESS);
10371     }
10372     else if(diff < 0)
10373     {
10374         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
10375         fprintf(stderr, "particle count.\n");
10376         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10377                 __FILE__, __LINE__);
10378         /* FIXME: Should we set the count of all other molecules to 0 and add
10379          * implicit molecules? */
10380         return(TNG_FAILURE);
10381     }
10382     if(stat != TNG_SUCCESS)
10383     {
10384         stat = tng_molecule_add(tng_data,
10385                                 "TNG_IMPLICIT_MOL",
10386                                 &mol);
10387         if(stat != TNG_SUCCESS)
10388         {
10389             return(stat);
10390         }
10391         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
10392         if(stat != TNG_SUCCESS)
10393         {
10394             return(stat);
10395         }
10396         stat = tng_chain_residue_add(tng_data, chain, "", &res);
10397         if(stat != TNG_SUCCESS)
10398         {
10399             return(stat);
10400         }
10401         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
10402         if(stat != TNG_SUCCESS)
10403         {
10404             return(stat);
10405         }
10406     }
10407     else
10408     {
10409         if(mol->n_atoms > 1)
10410         {
10411             n_mod = diff % mol->n_atoms;
10412             if(n_mod != 0)
10413             {
10414                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
10415                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
10416                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10417                         __FILE__, __LINE__);
10418                 return(TNG_FAILURE);
10419             }
10420             diff /= mol->n_atoms;
10421         }
10422     }
10423     stat = tng_molecule_cnt_set(tng_data, mol, diff);
10424
10425     return(stat);
10426 }
10427
10428 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
10429                 (const tng_trajectory_t tng_data,
10430                  int64_t *n)
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     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
10436     {
10437         *n = tng_data->n_particles;
10438     }
10439     else
10440     {
10441         *n = tng_data->current_trajectory_frame_set.n_particles;
10442     }
10443
10444     return(TNG_SUCCESS);
10445 }
10446
10447 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
10448                 (const tng_trajectory_t tng_data,
10449                  char *variable)
10450 {
10451     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10452     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
10453
10454     *variable = tng_data->var_num_atoms_flag;
10455
10456     return(TNG_SUCCESS);
10457 }
10458
10459 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
10460                     (const tng_trajectory_t tng_data,
10461                      int64_t *n)
10462 {
10463     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10464     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10465
10466     *n = tng_data->n_molecules;
10467
10468     return(TNG_SUCCESS);
10469 }
10470
10471 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
10472                     (const tng_trajectory_t tng_data,
10473                      int64_t *n)
10474 {
10475     int64_t *cnt_list = 0, cnt = 0, i;
10476
10477     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10478     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10479
10480     tng_molecule_cnt_list_get(tng_data, &cnt_list);
10481
10482     if(!cnt_list)
10483     {
10484         return(TNG_FAILURE);
10485     }
10486
10487     for(i = 0; i < tng_data->n_molecules; i++)
10488     {
10489         cnt += cnt_list[i];
10490     }
10491
10492     *n = cnt;
10493
10494     return(TNG_SUCCESS);
10495 }
10496
10497 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
10498                 (const tng_trajectory_t tng_data,
10499                  int64_t **mol_cnt_list)
10500 {
10501     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10502
10503     if(tng_data->var_num_atoms_flag)
10504     {
10505         *mol_cnt_list = tng_data->current_trajectory_frame_set.
10506                        molecule_cnt_list;
10507     }
10508     else
10509     {
10510         *mol_cnt_list = tng_data->molecule_cnt_list;
10511     }
10512     if(*mol_cnt_list == 0)
10513     {
10514         return(TNG_FAILURE);
10515     }
10516     return(TNG_SUCCESS);
10517 }
10518
10519 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
10520                 (const tng_trajectory_t tng_data,
10521                  int64_t *exp)
10522 {
10523     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10524     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
10525
10526     *exp = tng_data->distance_unit_exponential;
10527
10528     return(TNG_SUCCESS);
10529 }
10530
10531 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
10532                 (const tng_trajectory_t tng_data,
10533                  const int64_t exp)
10534 {
10535     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10536
10537     tng_data->distance_unit_exponential = exp;
10538
10539     return(TNG_SUCCESS);
10540 }
10541
10542 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
10543                 (const tng_trajectory_t tng_data,
10544                  int64_t *n)
10545 {
10546     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10547     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10548
10549     *n = tng_data->frame_set_n_frames;
10550
10551     return(TNG_SUCCESS);
10552 }
10553
10554 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
10555                 (const tng_trajectory_t tng_data,
10556                  const int64_t n)
10557 {
10558     tng_trajectory_frame_set_t frame_set;
10559     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10560
10561     tng_data->frame_set_n_frames = n;
10562     frame_set = &tng_data->current_trajectory_frame_set;
10563     if(frame_set)
10564     {
10565         frame_set->n_frames = n;
10566     }
10567
10568     return(TNG_SUCCESS);
10569 }
10570
10571 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
10572                 (const tng_trajectory_t tng_data,
10573                  int64_t *n)
10574 {
10575     int64_t long_stride_length, medium_stride_length;
10576     int64_t file_pos, orig_frame_set_file_pos;
10577     tng_trajectory_frame_set_t frame_set;
10578     struct tng_trajectory_frame_set orig_frame_set;
10579     tng_gen_block_t block;
10580     tng_function_status stat;
10581     int64_t cnt = 0;
10582
10583     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10584     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10585
10586     orig_frame_set = tng_data->current_trajectory_frame_set;
10587
10588     frame_set = &tng_data->current_trajectory_frame_set;
10589
10590     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10591     file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
10592
10593     if(file_pos < 0)
10594     {
10595         *n = tng_data->n_trajectory_frame_sets = cnt;
10596         return(TNG_SUCCESS);
10597     }
10598
10599     tng_block_init(&block);
10600     fseeko(tng_data->input_file,
10601            file_pos,
10602            SEEK_SET);
10603     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10604     /* Read block headers first to see what block is found. */
10605     stat = tng_block_header_read(tng_data, block);
10606     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10607     {
10608         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
10609                 __FILE__, __LINE__);
10610         tng_block_destroy(&block);
10611         return(TNG_CRITICAL);
10612     }
10613
10614     if(tng_block_read_next(tng_data, block,
10615                         TNG_SKIP_HASH) != TNG_SUCCESS)
10616     {
10617         tng_block_destroy(&block);
10618         return(TNG_CRITICAL);
10619     }
10620
10621     ++cnt;
10622
10623     long_stride_length = tng_data->long_stride_length;
10624     medium_stride_length = tng_data->medium_stride_length;
10625
10626     /* Take long steps forward until a long step forward would be too long or
10627      * the last frame set is found */
10628     file_pos = frame_set->long_stride_next_frame_set_file_pos;
10629     while(file_pos > 0)
10630     {
10631         if(file_pos > 0)
10632         {
10633             cnt += long_stride_length;
10634             fseeko(tng_data->input_file, file_pos, SEEK_SET);
10635             /* Read block headers first to see what block is found. */
10636             stat = tng_block_header_read(tng_data, block);
10637             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10638             {
10639                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10640                        file_pos, __FILE__, __LINE__);
10641                 tng_block_destroy(&block);
10642                 return(TNG_CRITICAL);
10643             }
10644
10645             if(tng_block_read_next(tng_data, block,
10646                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10647             {
10648                 tng_block_destroy(&block);
10649                 return(TNG_CRITICAL);
10650             }
10651         }
10652         file_pos = frame_set->long_stride_next_frame_set_file_pos;
10653     }
10654
10655     /* Take medium steps forward until a medium step forward would be too long
10656      * or the last frame set is found */
10657     file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10658     while(file_pos > 0)
10659     {
10660         if(file_pos > 0)
10661         {
10662             cnt += medium_stride_length;
10663             fseeko(tng_data->input_file,
10664                    file_pos,
10665                    SEEK_SET);
10666             /* Read block headers first to see what block is found. */
10667             stat = tng_block_header_read(tng_data, block);
10668             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10669             {
10670                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10671                        file_pos, __FILE__, __LINE__);
10672                 tng_block_destroy(&block);
10673                 return(TNG_CRITICAL);
10674             }
10675
10676             if(tng_block_read_next(tng_data, block,
10677                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10678             {
10679                 tng_block_destroy(&block);
10680                 return(TNG_CRITICAL);
10681             }
10682         }
10683         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10684     }
10685
10686     /* Take one step forward until the last frame set is found */
10687     file_pos = frame_set->next_frame_set_file_pos;
10688     while(file_pos > 0)
10689     {
10690         if(file_pos > 0)
10691         {
10692             ++cnt;
10693             fseeko(tng_data->input_file,
10694                    file_pos,
10695                    SEEK_SET);
10696             /* Read block headers first to see what block is found. */
10697             stat = tng_block_header_read(tng_data, block);
10698             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10699             {
10700                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10701                        file_pos, __FILE__, __LINE__);
10702                 tng_block_destroy(&block);
10703                 return(TNG_CRITICAL);
10704             }
10705
10706             if(tng_block_read_next(tng_data, block,
10707                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10708             {
10709                 tng_block_destroy(&block);
10710                 return(TNG_CRITICAL);
10711             }
10712         }
10713         file_pos = frame_set->next_frame_set_file_pos;
10714     }
10715
10716     tng_block_destroy(&block);
10717
10718     *n = tng_data->n_trajectory_frame_sets = cnt;
10719
10720     *frame_set = orig_frame_set;
10721     /* The mapping block in the original frame set has been freed when reading
10722      * other frame sets. */
10723     frame_set->mappings = 0;
10724     frame_set->n_mapping_blocks = 0;
10725
10726     fseeko(tng_data->input_file,
10727            tng_data->first_trajectory_frame_set_input_file_pos,
10728            SEEK_SET);
10729
10730     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
10731
10732     return(TNG_SUCCESS);
10733 }
10734
10735 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
10736                 (const tng_trajectory_t tng_data,
10737                  tng_trajectory_frame_set_t *frame_set_p)
10738 {
10739     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10740
10741     *frame_set_p = &tng_data->current_trajectory_frame_set;
10742
10743     return(TNG_SUCCESS);
10744 }
10745
10746 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
10747                 (const tng_trajectory_t tng_data,
10748                  const int64_t nr)
10749 {
10750     int64_t long_stride_length, medium_stride_length;
10751     int64_t file_pos, curr_nr = 0, n_frame_sets;
10752     tng_trajectory_frame_set_t frame_set;
10753     tng_gen_block_t block;
10754     tng_function_status stat;
10755
10756     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10757     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
10758
10759     frame_set = &tng_data->current_trajectory_frame_set;
10760
10761     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
10762
10763     if(stat != TNG_SUCCESS)
10764     {
10765         return(stat);
10766     }
10767
10768     if(nr >= n_frame_sets)
10769     {
10770         return(TNG_FAILURE);
10771     }
10772
10773     long_stride_length = tng_data->long_stride_length;
10774     medium_stride_length = tng_data->medium_stride_length;
10775
10776     /* FIXME: The frame set number of the current frame set is not stored */
10777
10778     if(nr < n_frame_sets - 1 - nr)
10779     {
10780         /* Start from the beginning */
10781         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
10782     }
10783     else
10784     {
10785         /* Start from the end */
10786         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10787         curr_nr = n_frame_sets - 1;
10788     }
10789     if(file_pos <= 0)
10790     {
10791         return(TNG_FAILURE);
10792     }
10793
10794     tng_block_init(&block);
10795     fseeko(tng_data->input_file,
10796            file_pos,
10797            SEEK_SET);
10798     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10799     /* Read block headers first to see what block is found. */
10800     stat = tng_block_header_read(tng_data, block);
10801     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10802     {
10803         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
10804                 __FILE__, __LINE__);
10805         tng_block_destroy(&block);
10806         return(TNG_CRITICAL);
10807     }
10808
10809     if(tng_block_read_next(tng_data, block,
10810                         TNG_SKIP_HASH) != TNG_SUCCESS)
10811     {
10812         tng_block_destroy(&block);
10813         return(TNG_CRITICAL);
10814     }
10815
10816     if(curr_nr == nr)
10817     {
10818         tng_block_destroy(&block);
10819         return(TNG_SUCCESS);
10820     }
10821
10822     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10823
10824     /* Take long steps forward until a long step forward would be too long or
10825      * the right frame set is found */
10826     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
10827     {
10828         file_pos = frame_set->long_stride_next_frame_set_file_pos;
10829         if(file_pos > 0)
10830         {
10831             curr_nr += long_stride_length;
10832             fseeko(tng_data->input_file, file_pos, SEEK_SET);
10833             /* Read block headers first to see what block is found. */
10834             stat = tng_block_header_read(tng_data, block);
10835             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10836             {
10837                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10838                        file_pos,  __FILE__, __LINE__);
10839                 tng_block_destroy(&block);
10840                 return(TNG_CRITICAL);
10841             }
10842
10843             if(tng_block_read_next(tng_data, block,
10844                                    TNG_SKIP_HASH) != TNG_SUCCESS)
10845             {
10846                 tng_block_destroy(&block);
10847                 return(TNG_CRITICAL);
10848             }
10849             if(curr_nr == nr)
10850             {
10851                 tng_block_destroy(&block);
10852                 return(TNG_SUCCESS);
10853             }
10854         }
10855     }
10856
10857     /* Take medium steps forward until a medium step forward would be too long
10858      * or the right frame set is found */
10859     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
10860     {
10861         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10862         if(file_pos > 0)
10863         {
10864             curr_nr += medium_stride_length;
10865             fseeko(tng_data->input_file,
10866                    file_pos,
10867                    SEEK_SET);
10868             /* Read block headers first to see what block is found. */
10869             stat = tng_block_header_read(tng_data, block);
10870             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10871             {
10872                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10873                        file_pos, __FILE__, __LINE__);
10874                 tng_block_destroy(&block);
10875                 return(TNG_CRITICAL);
10876             }
10877
10878             if(tng_block_read_next(tng_data, block,
10879                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10880             {
10881                 tng_block_destroy(&block);
10882                 return(TNG_CRITICAL);
10883             }
10884             if(curr_nr == nr)
10885             {
10886                 tng_block_destroy(&block);
10887                 return(TNG_SUCCESS);
10888             }
10889         }
10890     }
10891
10892     /* Take one step forward until the right frame set is found */
10893     while(file_pos > 0 && curr_nr < nr)
10894     {
10895         file_pos = frame_set->next_frame_set_file_pos;
10896
10897         if(file_pos > 0)
10898         {
10899             ++curr_nr;
10900             fseeko(tng_data->input_file,
10901                    file_pos,
10902                    SEEK_SET);
10903             /* Read block headers first to see what block is found. */
10904             stat = tng_block_header_read(tng_data, block);
10905             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10906             {
10907                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10908                        file_pos, __FILE__, __LINE__);
10909                 tng_block_destroy(&block);
10910                 return(TNG_CRITICAL);
10911             }
10912
10913             if(tng_block_read_next(tng_data, block,
10914                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10915             {
10916                 tng_block_destroy(&block);
10917                 return(TNG_CRITICAL);
10918             }
10919             if(curr_nr == nr)
10920             {
10921                 tng_block_destroy(&block);
10922                 return(TNG_SUCCESS);
10923             }
10924         }
10925     }
10926
10927     /* Take long steps backward until a long step backward would be too long
10928      * or the right frame set is found */
10929     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
10930     {
10931         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
10932         if(file_pos > 0)
10933         {
10934             curr_nr -= long_stride_length;
10935             fseeko(tng_data->input_file,
10936                    file_pos,
10937                    SEEK_SET);
10938             /* Read block headers first to see what block is found. */
10939             stat = tng_block_header_read(tng_data, block);
10940             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10941             {
10942                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10943                        file_pos, __FILE__, __LINE__);
10944                 tng_block_destroy(&block);
10945                 return(TNG_CRITICAL);
10946             }
10947
10948             if(tng_block_read_next(tng_data, block,
10949                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10950             {
10951                 tng_block_destroy(&block);
10952                 return(TNG_CRITICAL);
10953             }
10954             if(curr_nr == nr)
10955             {
10956                 tng_block_destroy(&block);
10957                 return(TNG_SUCCESS);
10958             }
10959         }
10960     }
10961
10962     /* Take medium steps backward until a medium step backward would be too long
10963      * or the right frame set is found */
10964     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
10965     {
10966         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
10967         if(file_pos > 0)
10968         {
10969             curr_nr -= medium_stride_length;
10970             fseeko(tng_data->input_file,
10971                    file_pos,
10972                    SEEK_SET);
10973             /* Read block headers first to see what block is found. */
10974             stat = tng_block_header_read(tng_data, block);
10975             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10976             {
10977                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10978                        file_pos, __FILE__, __LINE__);
10979                 tng_block_destroy(&block);
10980                 return(TNG_CRITICAL);
10981             }
10982
10983             if(tng_block_read_next(tng_data, block,
10984                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10985             {
10986                 tng_block_destroy(&block);
10987                 return(TNG_CRITICAL);
10988             }
10989             if(curr_nr == nr)
10990             {
10991                 tng_block_destroy(&block);
10992                 return(TNG_SUCCESS);
10993             }
10994         }
10995     }
10996
10997     /* Take one step backward until the right frame set is found */
10998     while(file_pos > 0 && curr_nr > nr)
10999     {
11000         file_pos = frame_set->prev_frame_set_file_pos;
11001         if(file_pos > 0)
11002         {
11003             --curr_nr;
11004             fseeko(tng_data->input_file,
11005                    file_pos,
11006                    SEEK_SET);
11007             /* Read block headers first to see what block is found. */
11008             stat = tng_block_header_read(tng_data, block);
11009             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11010             {
11011                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11012                        file_pos, __FILE__, __LINE__);
11013                 tng_block_destroy(&block);
11014                 return(TNG_CRITICAL);
11015             }
11016
11017             if(tng_block_read_next(tng_data, block,
11018                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11019             {
11020                 tng_block_destroy(&block);
11021                 return(TNG_CRITICAL);
11022             }
11023             if(curr_nr == nr)
11024             {
11025                 tng_block_destroy(&block);
11026                 return(TNG_SUCCESS);
11027             }
11028         }
11029     }
11030
11031     /* If for some reason the current frame set is not yet found,
11032      * take one step forward until the right frame set is found */
11033     while(file_pos > 0 && curr_nr < nr)
11034     {
11035         file_pos = frame_set->next_frame_set_file_pos;
11036         if(file_pos > 0)
11037         {
11038             ++curr_nr;
11039             fseeko(tng_data->input_file,
11040                    file_pos,
11041                    SEEK_SET);
11042             /* Read block headers first to see what block is found. */
11043             stat = tng_block_header_read(tng_data, block);
11044             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11045             {
11046                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11047                        file_pos, __FILE__, __LINE__);
11048                 tng_block_destroy(&block);
11049                 return(TNG_CRITICAL);
11050             }
11051
11052             if(tng_block_read_next(tng_data, block,
11053                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11054             {
11055                 tng_block_destroy(&block);
11056                 return(TNG_CRITICAL);
11057             }
11058             if(curr_nr == nr)
11059             {
11060                 tng_block_destroy(&block);
11061                 return(TNG_SUCCESS);
11062             }
11063         }
11064     }
11065
11066     tng_block_destroy(&block);
11067     return(TNG_FAILURE);
11068 }
11069
11070 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
11071                 (const tng_trajectory_t tng_data,
11072                  const int64_t frame)
11073 {
11074     int64_t first_frame, last_frame, n_frames_per_frame_set;
11075     int64_t long_stride_length, medium_stride_length;
11076     int64_t file_pos, temp_frame, n_frames;
11077     tng_trajectory_frame_set_t frame_set;
11078     tng_gen_block_t block;
11079     tng_function_status stat;
11080
11081     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11082     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
11083
11084     frame_set = &tng_data->current_trajectory_frame_set;
11085
11086     tng_block_init(&block);
11087
11088     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
11089     {
11090         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11091         fseeko(tng_data->input_file,
11092                file_pos,
11093                SEEK_SET);
11094         tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11095         /* Read block headers first to see what block is found. */
11096         stat = tng_block_header_read(tng_data, block);
11097         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11098         {
11099             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11100                     file_pos, __FILE__, __LINE__);
11101             tng_block_destroy(&block);
11102             return(TNG_CRITICAL);
11103         }
11104
11105         if(tng_block_read_next(tng_data, block,
11106                             TNG_SKIP_HASH) != TNG_SUCCESS)
11107         {
11108             tng_block_destroy(&block);
11109             return(TNG_CRITICAL);
11110         }
11111     }
11112
11113     first_frame = tng_max_i64(frame_set->first_frame, 0);
11114     last_frame = first_frame + frame_set->n_frames - 1;
11115     /* Is this the right frame set? */
11116     if(first_frame <= frame && frame <= last_frame)
11117     {
11118         tng_block_destroy(&block);
11119         return(TNG_SUCCESS);
11120     }
11121
11122     n_frames_per_frame_set = tng_data->frame_set_n_frames;
11123     long_stride_length = tng_data->long_stride_length;
11124     medium_stride_length = tng_data->medium_stride_length;
11125
11126     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
11127        TNG_SUCCESS)
11128     {
11129         if(temp_frame - first_frame > n_frames_per_frame_set)
11130         {
11131             n_frames_per_frame_set = temp_frame - first_frame;
11132         }
11133     }
11134
11135     tng_num_frames_get(tng_data, &n_frames);
11136
11137     if(frame >= n_frames)
11138     {
11139         tng_block_destroy(&block);
11140         return(TNG_FAILURE);
11141     }
11142
11143     if(first_frame - frame >= frame ||
11144        frame - last_frame >
11145        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
11146     {
11147         /* Start from the beginning */
11148         if(first_frame - frame >= frame)
11149         {
11150             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11151
11152             if(file_pos <= 0)
11153             {
11154                 tng_block_destroy(&block);
11155                 return(TNG_FAILURE);
11156             }
11157         }
11158         /* Start from the end */
11159         else if(frame - first_frame > (n_frames - 1) - frame)
11160         {
11161             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11162
11163             /* If the last frame set position is not set start from the current
11164              * frame set, since it will be closer than the first frame set. */
11165         }
11166         /* Start from current */
11167         else
11168         {
11169             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11170         }
11171
11172         if(file_pos > 0)
11173         {
11174             fseeko(tng_data->input_file,
11175                    file_pos,
11176                    SEEK_SET);
11177             tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11178             /* Read block headers first to see what block is found. */
11179             stat = tng_block_header_read(tng_data, block);
11180             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11181             {
11182                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11183                        file_pos, __FILE__, __LINE__);
11184                 tng_block_destroy(&block);
11185                 return(TNG_CRITICAL);
11186             }
11187
11188             if(tng_block_read_next(tng_data, block,
11189                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11190             {
11191                 tng_block_destroy(&block);
11192                 return(TNG_CRITICAL);
11193             }
11194         }
11195     }
11196
11197     first_frame = tng_max_i64(frame_set->first_frame, 0);
11198     last_frame = first_frame + frame_set->n_frames - 1;
11199
11200     if(frame >= first_frame && frame <= last_frame)
11201     {
11202         tng_block_destroy(&block);
11203         return(TNG_SUCCESS);
11204     }
11205
11206     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11207
11208     /* Take long steps forward until a long step forward would be too long or
11209      * the right frame set is found */
11210     while(file_pos > 0 && first_frame + long_stride_length *
11211           n_frames_per_frame_set <= frame)
11212     {
11213         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11214         if(file_pos > 0)
11215         {
11216             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11217             /* Read block headers first to see what block is found. */
11218             stat = tng_block_header_read(tng_data, block);
11219             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11220             {
11221                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11222                        file_pos, __FILE__, __LINE__);
11223                 tng_block_destroy(&block);
11224                 return(TNG_CRITICAL);
11225             }
11226
11227             if(tng_block_read_next(tng_data, block,
11228                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11229             {
11230                 tng_block_destroy(&block);
11231                 return(TNG_CRITICAL);
11232             }
11233         }
11234         first_frame = tng_max_i64(frame_set->first_frame, 0);
11235         last_frame = first_frame + frame_set->n_frames - 1;
11236         if(frame >= first_frame && frame <= last_frame)
11237         {
11238             tng_block_destroy(&block);
11239             return(TNG_SUCCESS);
11240         }
11241     }
11242
11243     /* Take medium steps forward until a medium step forward would be too long
11244      * or the right frame set is found */
11245     while(file_pos > 0 && first_frame + medium_stride_length *
11246           n_frames_per_frame_set <= frame)
11247     {
11248         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11249         if(file_pos > 0)
11250         {
11251             fseeko(tng_data->input_file,
11252                    file_pos,
11253                    SEEK_SET);
11254             /* Read block headers first to see what block is found. */
11255             stat = tng_block_header_read(tng_data, block);
11256             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11257             {
11258                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11259                        file_pos, __FILE__, __LINE__);
11260                 tng_block_destroy(&block);
11261                 return(TNG_CRITICAL);
11262             }
11263
11264             if(tng_block_read_next(tng_data, block,
11265                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11266             {
11267                 tng_block_destroy(&block);
11268                 return(TNG_CRITICAL);
11269             }
11270         }
11271         first_frame = tng_max_i64(frame_set->first_frame, 0);
11272         last_frame = first_frame + frame_set->n_frames - 1;
11273         if(frame >= first_frame && frame <= last_frame)
11274         {
11275             tng_block_destroy(&block);
11276             return(TNG_SUCCESS);
11277         }
11278     }
11279
11280     /* Take one step forward until the right frame set is found */
11281     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11282     {
11283         file_pos = frame_set->next_frame_set_file_pos;
11284         if(file_pos > 0)
11285         {
11286             fseeko(tng_data->input_file,
11287                    file_pos,
11288                    SEEK_SET);
11289             /* Read block headers first to see what block is found. */
11290             stat = tng_block_header_read(tng_data, block);
11291             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11292             {
11293                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11294                        file_pos, __FILE__, __LINE__);
11295                 tng_block_destroy(&block);
11296                 return(TNG_CRITICAL);
11297             }
11298
11299             if(tng_block_read_next(tng_data, block,
11300                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11301             {
11302                 tng_block_destroy(&block);
11303                 return(TNG_CRITICAL);
11304             }
11305         }
11306         first_frame = tng_max_i64(frame_set->first_frame, 0);
11307         last_frame = first_frame + frame_set->n_frames - 1;
11308         if(frame >= first_frame && frame <= last_frame)
11309         {
11310             tng_block_destroy(&block);
11311             return(TNG_SUCCESS);
11312         }
11313     }
11314
11315     /* Take long steps backward until a long step backward would be too long
11316      * or the right frame set is found */
11317     while(file_pos > 0 && first_frame - long_stride_length *
11318           n_frames_per_frame_set >= frame)
11319     {
11320         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11321         if(file_pos > 0)
11322         {
11323             fseeko(tng_data->input_file,
11324                    file_pos,
11325                    SEEK_SET);
11326             /* Read block headers first to see what block is found. */
11327             stat = tng_block_header_read(tng_data, block);
11328             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11329             {
11330                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11331                        file_pos, __FILE__, __LINE__);
11332                 tng_block_destroy(&block);
11333                 return(TNG_CRITICAL);
11334             }
11335
11336             if(tng_block_read_next(tng_data, block,
11337                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11338             {
11339                 tng_block_destroy(&block);
11340                 return(TNG_CRITICAL);
11341             }
11342         }
11343         first_frame = tng_max_i64(frame_set->first_frame, 0);
11344         last_frame = first_frame + frame_set->n_frames - 1;
11345         if(frame >= first_frame && frame <= last_frame)
11346         {
11347             tng_block_destroy(&block);
11348             return(TNG_SUCCESS);
11349         }
11350     }
11351
11352     /* Take medium steps backward until a medium step backward would be too long
11353      * or the right frame set is found */
11354     while(file_pos > 0 && first_frame - medium_stride_length *
11355           n_frames_per_frame_set >= frame)
11356     {
11357         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11358         if(file_pos > 0)
11359         {
11360             fseeko(tng_data->input_file,
11361                    file_pos,
11362                    SEEK_SET);
11363             /* Read block headers first to see what block is found. */
11364             stat = tng_block_header_read(tng_data, block);
11365             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11366             {
11367                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11368                        file_pos, __FILE__, __LINE__);
11369                 tng_block_destroy(&block);
11370                 return(TNG_CRITICAL);
11371             }
11372
11373             if(tng_block_read_next(tng_data, block,
11374                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11375             {
11376                 tng_block_destroy(&block);
11377                 return(TNG_CRITICAL);
11378             }
11379         }
11380         first_frame = tng_max_i64(frame_set->first_frame, 0);
11381         last_frame = first_frame + frame_set->n_frames - 1;
11382         if(frame >= first_frame && frame <= last_frame)
11383         {
11384             tng_block_destroy(&block);
11385             return(TNG_SUCCESS);
11386         }
11387     }
11388
11389     /* Take one step backward until the right frame set is found */
11390     while(file_pos > 0 && first_frame > frame && last_frame > frame)
11391     {
11392         file_pos = frame_set->prev_frame_set_file_pos;
11393         if(file_pos > 0)
11394         {
11395             fseeko(tng_data->input_file,
11396                    file_pos,
11397                    SEEK_SET);
11398             /* Read block headers first to see what block is found. */
11399             stat = tng_block_header_read(tng_data, block);
11400             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11401             {
11402                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11403                        file_pos, __FILE__, __LINE__);
11404                 tng_block_destroy(&block);
11405                 return(TNG_CRITICAL);
11406             }
11407
11408             if(tng_block_read_next(tng_data, block,
11409                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11410             {
11411                 tng_block_destroy(&block);
11412                 return(TNG_CRITICAL);
11413             }
11414         }
11415         first_frame = tng_max_i64(frame_set->first_frame, 0);
11416         last_frame = first_frame + frame_set->n_frames - 1;
11417         if(frame >= first_frame && frame <= last_frame)
11418         {
11419             tng_block_destroy(&block);
11420             return(TNG_SUCCESS);
11421         }
11422     }
11423
11424     /* If for some reason the current frame set is not yet found,
11425      * take one step forward until the right frame set is found */
11426     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11427     {
11428         file_pos = frame_set->next_frame_set_file_pos;
11429         if(file_pos > 0)
11430         {
11431             fseeko(tng_data->input_file,
11432                    file_pos,
11433                    SEEK_SET);
11434             /* Read block headers first to see what block is found. */
11435             stat = tng_block_header_read(tng_data, block);
11436             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11437             {
11438                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11439                        file_pos, __FILE__, __LINE__);
11440                 tng_block_destroy(&block);
11441                 return(TNG_CRITICAL);
11442             }
11443
11444             if(tng_block_read_next(tng_data, block,
11445                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11446             {
11447                 tng_block_destroy(&block);
11448                 return(TNG_CRITICAL);
11449             }
11450         }
11451         first_frame = tng_max_i64(frame_set->first_frame, 0);
11452         last_frame = first_frame + frame_set->n_frames - 1;
11453         if(frame >= first_frame && frame <= last_frame)
11454         {
11455             tng_block_destroy(&block);
11456             return(TNG_SUCCESS);
11457         }
11458     }
11459
11460     tng_block_destroy(&block);
11461     return(TNG_FAILURE);
11462 }
11463
11464 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
11465                 (const tng_trajectory_t tng_data,
11466                  const tng_trajectory_frame_set_t frame_set,
11467                  int64_t *pos)
11468 {
11469     (void)tng_data;
11470
11471     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11472     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11473
11474     *pos = frame_set->next_frame_set_file_pos;
11475
11476     return(TNG_SUCCESS);
11477 }
11478
11479 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
11480                 (const tng_trajectory_t tng_data,
11481                  const tng_trajectory_frame_set_t frame_set,
11482                  int64_t *pos)
11483 {
11484     (void)tng_data;
11485
11486     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11487     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11488
11489     *pos = frame_set->prev_frame_set_file_pos;
11490
11491     return(TNG_SUCCESS);
11492 }
11493
11494 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
11495                 (const tng_trajectory_t tng_data,
11496                  const tng_trajectory_frame_set_t frame_set,
11497                  int64_t *first_frame,
11498                  int64_t *last_frame)
11499 {
11500     (void)tng_data;
11501
11502     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
11503     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
11504     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
11505
11506     *first_frame = frame_set->first_frame;
11507     *last_frame = *first_frame + frame_set->n_frames - 1;
11508
11509     return(TNG_SUCCESS);
11510 }
11511
11512 /**
11513  * @brief Translate from the particle numbering used in a frame set to the real
11514  *  particle numbering - used in the molecule description.
11515  * @param frame_set is the frame_set containing the mappings to use.
11516  * @param local is the index number of the atom in this frame set
11517  * @param real is set to the index of the atom in the molecular system.
11518  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11519  * cannot be found.
11520  */
11521 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
11522                 (const tng_trajectory_frame_set_t frame_set,
11523                  const int64_t local,
11524                  int64_t *real)
11525 {
11526     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
11527     tng_particle_mapping_t mapping;
11528     if(n_blocks <= 0)
11529     {
11530         *real = local;
11531         return(TNG_SUCCESS);
11532     }
11533     for(i = 0; i < n_blocks; i++)
11534     {
11535         mapping = &frame_set->mappings[i];
11536         first = mapping->num_first_particle;
11537         if(local < first ||
11538            local >= first + mapping->n_particles)
11539         {
11540             continue;
11541         }
11542         *real = mapping->real_particle_numbers[local-first];
11543         return(TNG_SUCCESS);
11544     }
11545     *real = local;
11546     return(TNG_FAILURE);
11547 }
11548
11549 /**
11550  * @brief Translate from the real particle numbering to the particle numbering
11551  *  used in a frame set.
11552  * @param frame_set is the frame_set containing the mappings to use.
11553  * @param real is the index number of the atom in the molecular system.
11554  * @param local is set to the index of the atom in this frame set.
11555  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11556  * cannot be found.
11557  */
11558 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
11559                 (const tng_trajectory_frame_set_t frame_set,
11560                  const int64_t real,
11561                  int64_t *local)
11562 {
11563     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
11564     tng_particle_mapping_t mapping;
11565     if(n_blocks <= 0)
11566     {
11567         *local = real;
11568         return(TNG_SUCCESS);
11569     }
11570     for(i = 0; i < n_blocks; i++)
11571     {
11572         mapping = &frame_set->mappings[i];
11573         for(j = mapping->n_particles; j--;)
11574         {
11575             if(mapping->real_particle_numbers[j] == real)
11576             {
11577                 *local = j;
11578                 return(TNG_SUCCESS);
11579             }
11580         }
11581     }
11582     return(TNG_FAILURE);
11583 }
11584 */
11585
11586 static tng_function_status tng_file_headers_len_get
11587                 (const tng_trajectory_t tng_data,
11588                  int64_t *len)
11589 {
11590     int64_t orig_pos;
11591     tng_gen_block_t block;
11592
11593     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11594
11595     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11596     {
11597         return(TNG_CRITICAL);
11598     }
11599
11600     *len = 0;
11601
11602     orig_pos = ftello(tng_data->input_file);
11603
11604     fseeko(tng_data->input_file, 0, SEEK_SET);
11605
11606     tng_block_init(&block);
11607     /* Read through the headers of non-trajectory blocks (they come before the
11608      * trajectory blocks in the file) */
11609     while (*len < tng_data->input_file_len &&
11610            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11611            block->id != -1 &&
11612            block->id != TNG_TRAJECTORY_FRAME_SET)
11613     {
11614         *len += block->header_contents_size + block->block_contents_size;
11615         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11616     }
11617
11618     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
11619
11620     tng_block_destroy(&block);
11621
11622     return(TNG_SUCCESS);
11623 }
11624
11625 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
11626                 (const tng_trajectory_t tng_data,
11627                  const char hash_mode)
11628 {
11629     int64_t prev_pos = 0;
11630     tng_gen_block_t block;
11631
11632     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11633
11634     tng_data->n_trajectory_frame_sets = 0;
11635
11636     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11637     {
11638         return(TNG_CRITICAL);
11639     }
11640
11641     fseeko(tng_data->input_file, 0, SEEK_SET);
11642
11643     tng_block_init(&block);
11644     /* Non trajectory blocks (they come before the trajectory
11645      * blocks in the file) */
11646     while (prev_pos < tng_data->input_file_len &&
11647            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11648            block->id != -1 &&
11649            block->id != TNG_TRAJECTORY_FRAME_SET)
11650     {
11651         tng_block_read_next(tng_data, block, hash_mode);
11652         prev_pos = ftello(tng_data->input_file);
11653     }
11654
11655     /* Go back if a trajectory block was encountered */
11656     if(block->id == TNG_TRAJECTORY_FRAME_SET)
11657     {
11658         fseeko(tng_data->input_file, prev_pos, SEEK_SET);
11659     }
11660
11661     tng_block_destroy(&block);
11662
11663     return(TNG_SUCCESS);
11664 }
11665
11666 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
11667                 (const tng_trajectory_t tng_data,
11668                  const char hash_mode)
11669 {
11670     int i;
11671     int64_t len, orig_len, tot_len = 0, data_start_pos, temp_pos = -1;
11672     tng_function_status stat;
11673     tng_gen_block_t block;
11674
11675     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11676
11677     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
11678     {
11679         return(TNG_CRITICAL);
11680     }
11681
11682     if(tng_data->n_trajectory_frame_sets > 0)
11683     {
11684         stat = tng_file_headers_len_get(tng_data, &orig_len);
11685         if(stat != TNG_SUCCESS)
11686         {
11687             return(stat);
11688         }
11689
11690         tng_block_init(&block);
11691         block->name = malloc(TNG_MAX_STR_LEN);
11692         if(!block->name)
11693         {
11694             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
11695                     TNG_MAX_STR_LEN, __FILE__, __LINE__);
11696             tng_block_destroy(&block);
11697             return(TNG_CRITICAL);
11698         }
11699         strcpy(block->name, "GENERAL INFO");
11700         tng_block_header_len_calculate(tng_data, block, &len);
11701         tot_len += len;
11702         tng_general_info_block_len_calculate(tng_data, &len);
11703         tot_len += len;
11704         strcpy(block->name, "MOLECULES");
11705         tng_block_header_len_calculate(tng_data, block, &len);
11706         tot_len += len;
11707         tng_molecules_block_len_calculate(tng_data, &len);
11708         tot_len += len;
11709
11710         for(i = 0; i < tng_data->n_data_blocks; i++)
11711         {
11712             strcpy(block->name, tng_data->non_tr_data[i].block_name);
11713             tng_block_header_len_calculate(tng_data, block, &len);
11714             tot_len += len;
11715             tng_data_block_len_calculate(tng_data,
11716                                         (tng_data_t)&tng_data->non_tr_data[i],
11717                                          TNG_FALSE, 1, 1, 1, 0, 1,
11718                                          &data_start_pos,
11719                                          &len);
11720             tot_len += len;
11721         }
11722         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11723         {
11724             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
11725             tng_block_header_len_calculate(tng_data, block, &len);
11726             tot_len += len;
11727             tng_data_block_len_calculate(tng_data,
11728                                          &tng_data->non_tr_particle_data[i],
11729                                          TNG_TRUE, 1, 1, 1, 0,
11730                                          tng_data->n_particles,
11731                                          &data_start_pos,
11732                                          &len);
11733             tot_len += len;
11734         }
11735         tng_block_destroy(&block);
11736
11737         if(tot_len > orig_len)
11738         {
11739             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len, hash_mode);
11740         }
11741
11742         stat = tng_reread_frame_set_at_file_pos(tng_data, tng_data->last_trajectory_frame_set_input_file_pos);
11743         if(stat == TNG_CRITICAL)
11744         {
11745             fprintf(stderr, "TNG library: Cannot read frame set. %s: %d\n",
11746                     __FILE__, __LINE__);
11747             return(TNG_CRITICAL);
11748         }
11749
11750         /* In order to write non-trajectory data the current_trajectory_frame_set_output_file_pos
11751          * must temporarily be reset */
11752         temp_pos = tng_data->current_trajectory_frame_set_output_file_pos;
11753         tng_data->current_trajectory_frame_set_output_file_pos = -1;
11754     }
11755
11756     if(tng_general_info_block_write(tng_data, hash_mode)
11757        != TNG_SUCCESS)
11758     {
11759         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
11760                 tng_data->input_file_path, __FILE__, __LINE__);
11761         return(TNG_CRITICAL);
11762     }
11763
11764     if(tng_molecules_block_write(tng_data, hash_mode)
11765         != TNG_SUCCESS)
11766     {
11767         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
11768                 tng_data->input_file_path, __FILE__, __LINE__);
11769         return(TNG_CRITICAL);
11770     }
11771
11772     /* FIXME: Currently writing non-trajectory data blocks here.
11773      * Should perhaps be moved. */
11774     tng_block_init(&block);
11775     for(i = 0; i < tng_data->n_data_blocks; i++)
11776     {
11777         block->id = tng_data->non_tr_data[i].block_id;
11778         tng_data_block_write(tng_data, block,
11779                              i, TNG_FALSE, 0, hash_mode);
11780     }
11781
11782     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11783     {
11784         block->id = tng_data->non_tr_particle_data[i].block_id;
11785         tng_data_block_write(tng_data, block,
11786                              i, TNG_TRUE, 0, hash_mode);
11787     }
11788
11789     tng_block_destroy(&block);
11790
11791     /* Continue writing at the end of the file. */
11792     fseeko(tng_data->output_file, 0, SEEK_END);
11793     if(temp_pos > 0)
11794     {
11795         tng_data->current_trajectory_frame_set_output_file_pos = temp_pos;
11796     }
11797
11798     return(TNG_SUCCESS);
11799 }
11800
11801 tng_function_status DECLSPECDLLEXPORT tng_block_read_next
11802                 (const tng_trajectory_t tng_data,
11803                  const tng_gen_block_t block,
11804                  const char hash_mode)
11805 {
11806     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11807     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
11808
11809     switch(block->id)
11810     {
11811     case TNG_TRAJECTORY_FRAME_SET:
11812         return(tng_frame_set_block_read(tng_data, block, hash_mode));
11813     case TNG_PARTICLE_MAPPING:
11814         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
11815     case TNG_GENERAL_INFO:
11816         return(tng_general_info_block_read(tng_data, block, hash_mode));
11817     case TNG_MOLECULES:
11818         return(tng_molecules_block_read(tng_data, block, hash_mode));
11819     default:
11820         if(block->id >= TNG_TRAJ_BOX_SHAPE)
11821         {
11822             return(tng_data_block_contents_read(tng_data, block, hash_mode));
11823         }
11824         else
11825         {
11826             /* Skip to the next block */
11827             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11828             return(TNG_FAILURE);
11829         }
11830     }
11831 }
11832
11833 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
11834                 (const tng_trajectory_t tng_data,
11835                  const char hash_mode)
11836 {
11837     int64_t file_pos;
11838     tng_gen_block_t block;
11839     tng_function_status stat;
11840
11841     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11842
11843     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11844     {
11845         return(TNG_CRITICAL);
11846     }
11847
11848     file_pos = ftello(tng_data->input_file);
11849
11850     tng_block_init(&block);
11851
11852     /* Read block headers first to see what block is found. */
11853     stat = tng_block_header_read(tng_data, block);
11854     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
11855        block->id == -1)
11856     {
11857         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11858                file_pos, __FILE__, __LINE__);
11859         tng_block_destroy(&block);
11860         return(TNG_CRITICAL);
11861     }
11862
11863     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11864
11865     if(tng_block_read_next(tng_data, block,
11866                            hash_mode) == TNG_SUCCESS)
11867     {
11868         tng_data->n_trajectory_frame_sets++;
11869         file_pos = ftello(tng_data->input_file);
11870         /* Read all blocks until next frame set block */
11871         stat = tng_block_header_read(tng_data, block);
11872         while(file_pos < tng_data->input_file_len &&
11873               stat != TNG_CRITICAL &&
11874               block->id != TNG_TRAJECTORY_FRAME_SET &&
11875               block->id != -1)
11876         {
11877             stat = tng_block_read_next(tng_data, block,
11878                                        hash_mode);
11879             if(stat != TNG_CRITICAL)
11880             {
11881                 file_pos = ftello(tng_data->input_file);
11882                 if(file_pos < tng_data->input_file_len)
11883                 {
11884                     stat = tng_block_header_read(tng_data, block);
11885                 }
11886             }
11887         }
11888         if(stat == TNG_CRITICAL)
11889         {
11890             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11891                    file_pos, __FILE__, __LINE__);
11892             tng_block_destroy(&block);
11893             return(stat);
11894         }
11895
11896         if(block->id == TNG_TRAJECTORY_FRAME_SET)
11897         {
11898             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11899         }
11900     }
11901
11902     tng_block_destroy(&block);
11903
11904     return(TNG_SUCCESS);
11905 }
11906
11907
11908 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
11909                 (const tng_trajectory_t tng_data,
11910                  const char hash_mode,
11911                  const int64_t block_id)
11912 {
11913     int64_t file_pos;
11914     tng_gen_block_t block;
11915     tng_function_status stat;
11916     int found_flag = 1;
11917
11918     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11919
11920     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11921     {
11922         return(TNG_CRITICAL);
11923     }
11924
11925     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11926
11927     if(file_pos < 0)
11928     {
11929         /* No current frame set. This means that the first frame set must be
11930          * read */
11931         found_flag = 0;
11932         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11933     }
11934
11935     if(file_pos > 0)
11936     {
11937         fseeko(tng_data->input_file,
11938               file_pos,
11939               SEEK_SET);
11940     }
11941     else
11942     {
11943         return(TNG_FAILURE);
11944     }
11945
11946     tng_block_init(&block);
11947
11948     /* Read block headers first to see what block is found. */
11949     stat = tng_block_header_read(tng_data, block);
11950     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11951     {
11952         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11953                file_pos, __FILE__, __LINE__);
11954         tng_block_destroy(&block);
11955         return(TNG_CRITICAL);
11956     }
11957     /* If the current frame set had already been read skip its block contents */
11958     if(found_flag)
11959     {
11960         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11961     }
11962     /* Otherwise read the frame set block */
11963     else
11964     {
11965         stat = tng_block_read_next(tng_data, block,
11966                                    hash_mode);
11967         if(stat != TNG_SUCCESS)
11968         {
11969             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
11970             tng_block_destroy(&block);
11971             return(stat);
11972         }
11973     }
11974     file_pos = ftello(tng_data->input_file);
11975
11976     found_flag = 0;
11977
11978     /* Read only blocks of the requested ID
11979         * until next frame set block */
11980     stat = tng_block_header_read(tng_data, block);
11981     while(file_pos < tng_data->input_file_len &&
11982           stat != TNG_CRITICAL &&
11983           block->id != TNG_TRAJECTORY_FRAME_SET &&
11984           block->id != -1)
11985     {
11986         if(block->id == block_id)
11987         {
11988             stat = tng_block_read_next(tng_data, block,
11989                                        hash_mode);
11990             if(stat != TNG_CRITICAL)
11991             {
11992                 file_pos = ftello(tng_data->input_file);
11993                 found_flag = 1;
11994                 if(file_pos < tng_data->input_file_len)
11995                 {
11996                     stat = tng_block_header_read(tng_data, block);
11997                 }
11998             }
11999         }
12000         else
12001         {
12002             file_pos += block->block_contents_size + block->header_contents_size;
12003             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12004             if(file_pos < tng_data->input_file_len)
12005             {
12006                 stat = tng_block_header_read(tng_data, block);
12007             }
12008         }
12009     }
12010     if(stat == TNG_CRITICAL)
12011     {
12012         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12013                 file_pos, __FILE__, __LINE__);
12014         tng_block_destroy(&block);
12015         return(stat);
12016     }
12017
12018     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12019     {
12020         fseeko(tng_data->input_file, file_pos, SEEK_SET);
12021     }
12022
12023     tng_block_destroy(&block);
12024
12025     if(found_flag)
12026     {
12027         return(TNG_SUCCESS);
12028     }
12029     else
12030     {
12031         return(TNG_FAILURE);
12032     }
12033 }
12034
12035 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
12036                 (const tng_trajectory_t tng_data,
12037                  const char hash_mode)
12038 {
12039     int64_t file_pos;
12040
12041     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12042
12043     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12044     {
12045         return(TNG_CRITICAL);
12046     }
12047
12048     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12049
12050     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12051     {
12052         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12053     }
12054
12055     if(file_pos > 0)
12056     {
12057         fseeko(tng_data->input_file,
12058                file_pos,
12059                SEEK_SET);
12060     }
12061     else
12062     {
12063         return(TNG_FAILURE);
12064     }
12065
12066     return(tng_frame_set_read(tng_data, hash_mode));
12067 }
12068
12069 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
12070                 (const tng_trajectory_t tng_data,
12071                  const char hash_mode,
12072                  const int64_t block_id)
12073 {
12074     int64_t file_pos;
12075     tng_gen_block_t block;
12076     tng_function_status stat;
12077
12078     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12079
12080     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12081     {
12082         return(TNG_CRITICAL);
12083     }
12084
12085     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12086
12087     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12088     {
12089         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12090     }
12091
12092     if(file_pos > 0)
12093     {
12094         fseeko(tng_data->input_file,
12095                file_pos,
12096                SEEK_SET);
12097     }
12098     else
12099     {
12100         return(TNG_FAILURE);
12101     }
12102
12103     tng_block_init(&block);
12104
12105     /* Read block headers first to see what block is found. */
12106     stat = tng_block_header_read(tng_data, block);
12107     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12108     {
12109         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12110                 file_pos, __FILE__, __LINE__);
12111         tng_block_destroy(&block);
12112         return(TNG_CRITICAL);
12113     }
12114
12115     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12116
12117     if(tng_block_read_next(tng_data, block,
12118                            hash_mode) == TNG_SUCCESS)
12119     {
12120         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
12121     }
12122
12123     tng_block_destroy(&block);
12124
12125     return(stat);
12126 }
12127
12128 tng_function_status tng_frame_set_write
12129                 (const tng_trajectory_t tng_data,
12130                  const char hash_mode)
12131 {
12132     int i, j;
12133     tng_gen_block_t block;
12134     tng_trajectory_frame_set_t frame_set;
12135     tng_function_status stat;
12136
12137     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12138
12139     frame_set = &tng_data->current_trajectory_frame_set;
12140
12141     if(frame_set->n_written_frames == frame_set->n_frames)
12142     {
12143         return(TNG_SUCCESS);
12144     }
12145
12146     tng_data->current_trajectory_frame_set_output_file_pos =
12147     ftello(tng_data->output_file);
12148     tng_data->last_trajectory_frame_set_output_file_pos =
12149     tng_data->current_trajectory_frame_set_output_file_pos;
12150
12151     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
12152     {
12153         return(TNG_FAILURE);
12154     }
12155
12156     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
12157     {
12158         tng_data->first_trajectory_frame_set_output_file_pos =
12159         tng_data->current_trajectory_frame_set_output_file_pos;
12160     }
12161
12162     tng_block_init(&block);
12163
12164     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
12165     {
12166         tng_block_destroy(&block);
12167         return(TNG_FAILURE);
12168     }
12169
12170     /* Write non-particle data blocks */
12171     for(i = 0; i<frame_set->n_data_blocks; i++)
12172     {
12173         block->id = frame_set->tr_data[i].block_id;
12174         tng_data_block_write(tng_data, block, i, TNG_FALSE, 0, hash_mode);
12175     }
12176     /* Write the mapping blocks and particle data blocks*/
12177     if(frame_set->n_mapping_blocks)
12178     {
12179         for(i = 0; i < frame_set->n_mapping_blocks; i++)
12180         {
12181             block->id = TNG_PARTICLE_MAPPING;
12182             if(frame_set->mappings[i].n_particles > 0)
12183             {
12184                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
12185                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
12186                 {
12187                     block->id = frame_set->tr_particle_data[j].block_id;
12188                     tng_data_block_write(tng_data, block,
12189                                          j, TNG_TRUE, &frame_set->mappings[i],
12190                                          hash_mode);
12191                 }
12192             }
12193         }
12194     }
12195     else
12196     {
12197         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
12198         {
12199             block->id = frame_set->tr_particle_data[i].block_id;
12200             tng_data_block_write(tng_data, block,
12201                                  i, TNG_TRUE, 0, hash_mode);
12202         }
12203     }
12204
12205
12206     /* Update pointers in the general info block */
12207     stat = tng_header_pointers_update(tng_data, hash_mode);
12208
12209     if(stat == TNG_SUCCESS)
12210     {
12211         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
12212     }
12213
12214     tng_block_destroy(&block);
12215
12216     frame_set->n_unwritten_frames = 0;
12217
12218     fflush(tng_data->output_file);
12219
12220     return(stat);
12221 }
12222
12223 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
12224                 (const tng_trajectory_t tng_data,
12225                  const char hash_mode)
12226 {
12227     tng_trajectory_frame_set_t frame_set;
12228
12229     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12230
12231     frame_set = &tng_data->current_trajectory_frame_set;
12232
12233     if(frame_set->n_unwritten_frames == 0)
12234     {
12235         return(TNG_SUCCESS);
12236     }
12237     frame_set->n_frames = frame_set->n_unwritten_frames;
12238
12239     return(tng_frame_set_write(tng_data, hash_mode));
12240 }
12241
12242 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
12243                 (const tng_trajectory_t tng_data,
12244                  const int64_t first_frame,
12245                  const int64_t n_frames)
12246 {
12247     tng_gen_block_t block;
12248     tng_trajectory_frame_set_t frame_set;
12249     FILE *temp = tng_data->input_file;
12250     int64_t curr_file_pos;
12251
12252     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12253     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12254     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12255
12256     frame_set = &tng_data->current_trajectory_frame_set;
12257
12258     curr_file_pos = ftello(tng_data->output_file);
12259
12260     if(curr_file_pos <= 10)
12261     {
12262         tng_file_headers_write(tng_data, TNG_USE_HASH);
12263     }
12264
12265     /* Set pointer to previous frame set to the one that was loaded
12266      * before.
12267      * FIXME: This is a bit risky. If they are not added in order
12268      * it will be wrong. */
12269     if(tng_data->n_trajectory_frame_sets)
12270     {
12271         frame_set->prev_frame_set_file_pos =
12272         tng_data->last_trajectory_frame_set_output_file_pos;
12273     }
12274
12275     frame_set->next_frame_set_file_pos = -1;
12276
12277     tng_data->current_trajectory_frame_set_output_file_pos =
12278     ftello(tng_data->output_file);
12279
12280     tng_data->n_trajectory_frame_sets++;
12281
12282     /* Set the medium range pointers */
12283     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
12284     {
12285         frame_set->medium_stride_prev_frame_set_file_pos =
12286         tng_data->first_trajectory_frame_set_output_file_pos;
12287     }
12288     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12289     {
12290         /* FIXME: Currently only working if the previous frame set has its
12291          * medium stride pointer already set. This might need some fixing. */
12292         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
12293            frame_set->medium_stride_prev_frame_set_file_pos != 0)
12294         {
12295             tng_block_init(&block);
12296             tng_data->input_file = tng_data->output_file;
12297
12298             curr_file_pos = ftello(tng_data->output_file);
12299             fseeko(tng_data->output_file,
12300                    frame_set->medium_stride_prev_frame_set_file_pos,
12301                    SEEK_SET);
12302
12303             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12304             {
12305                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12306                     __FILE__, __LINE__);
12307                 tng_data->input_file = temp;
12308                 tng_block_destroy(&block);
12309                 return(TNG_CRITICAL);
12310             }
12311
12312             /* Read the next frame set from the previous frame set and one
12313              * medium stride step back */
12314             fseeko(tng_data->output_file, block->block_contents_size - (6 *
12315             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
12316             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
12317                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
12318                1, tng_data->output_file) == 0)
12319             {
12320                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12321                 tng_data->input_file = temp;
12322                 tng_block_destroy(&block);
12323                 return(TNG_CRITICAL);
12324             }
12325
12326             if(tng_data->input_endianness_swap_func_64)
12327             {
12328                 if(tng_data->input_endianness_swap_func_64(tng_data,
12329                    &frame_set->medium_stride_prev_frame_set_file_pos)
12330                     != TNG_SUCCESS)
12331                 {
12332                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12333                             __FILE__, __LINE__);
12334                 }
12335             }
12336
12337             tng_block_destroy(&block);
12338
12339             /* Set the long range pointers */
12340             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
12341             {
12342                 frame_set->long_stride_prev_frame_set_file_pos =
12343                 tng_data->first_trajectory_frame_set_output_file_pos;
12344             }
12345             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12346             {
12347                 /* FIXME: Currently only working if the previous frame set has its
12348                 * long stride pointer already set. This might need some fixing. */
12349                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
12350                 frame_set->long_stride_prev_frame_set_file_pos != 0)
12351                 {
12352                     tng_block_init(&block);
12353                     tng_data->input_file = tng_data->output_file;
12354
12355                     fseeko(tng_data->output_file,
12356                            frame_set->long_stride_prev_frame_set_file_pos,
12357                            SEEK_SET);
12358
12359                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12360                     {
12361                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12362                             __FILE__, __LINE__);
12363                         tng_data->input_file = temp;
12364                         tng_block_destroy(&block);
12365                         return(TNG_CRITICAL);
12366                     }
12367
12368                     /* Read the next frame set from the previous frame set and one
12369                     * long stride step back */
12370                     fseeko(tng_data->output_file, block->block_contents_size - (6 *
12371                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
12372
12373                     tng_block_destroy(&block);
12374
12375                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
12376                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
12377                     1, tng_data->output_file) == 0)
12378                     {
12379                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12380                         tng_data->input_file = temp;
12381                         return(TNG_CRITICAL);
12382                     }
12383
12384                     if(tng_data->input_endianness_swap_func_64)
12385                     {
12386                         if(tng_data->input_endianness_swap_func_64(tng_data,
12387                            &frame_set->long_stride_prev_frame_set_file_pos)
12388                             != TNG_SUCCESS)
12389                         {
12390                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12391                                     __FILE__, __LINE__);
12392                         }
12393                     }
12394
12395                 }
12396             }
12397
12398             tng_data->input_file = temp;
12399             fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
12400         }
12401     }
12402
12403     frame_set->first_frame = first_frame;
12404     frame_set->n_frames = n_frames;
12405     frame_set->n_written_frames = 0;
12406     frame_set->n_unwritten_frames = 0;
12407     frame_set->first_frame_time = -1;
12408
12409     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
12410        tng_data->first_trajectory_frame_set_output_file_pos == 0)
12411     {
12412         tng_data->first_trajectory_frame_set_output_file_pos =
12413         tng_data->current_trajectory_frame_set_output_file_pos;
12414     }
12415     /* FIXME: Should check the frame number instead of the file_pos,
12416      * in case frame sets are not in order */
12417     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
12418        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
12419        tng_data->last_trajectory_frame_set_output_file_pos <
12420        tng_data->current_trajectory_frame_set_output_file_pos)
12421     {
12422         tng_data->last_trajectory_frame_set_output_file_pos =
12423         tng_data->current_trajectory_frame_set_output_file_pos;
12424     }
12425
12426     return(TNG_SUCCESS);
12427 }
12428
12429 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
12430                 (const tng_trajectory_t tng_data,
12431                  const int64_t first_frame,
12432                  const int64_t n_frames,
12433                  const double first_frame_time)
12434 {
12435     tng_function_status stat;
12436
12437     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12438     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12439     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12440     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12441
12442
12443     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
12444     if(stat != TNG_SUCCESS)
12445     {
12446         return(stat);
12447     }
12448     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
12449
12450     return(stat);
12451 }
12452
12453 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
12454                 (const tng_trajectory_t tng_data,
12455                  const double first_frame_time)
12456 {
12457     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12458     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12459
12460     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
12461
12462     return(TNG_SUCCESS);
12463 }
12464
12465 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
12466                 (const tng_trajectory_t tng_data,
12467                  int64_t *frame)
12468 {
12469     int64_t file_pos, next_frame_set_file_pos;
12470     tng_gen_block_t block;
12471     tng_function_status stat;
12472
12473     tng_trajectory_frame_set_t frame_set;
12474
12475     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12476     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
12477     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
12478
12479     file_pos = ftello(tng_data->input_file);
12480
12481     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12482     {
12483         next_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12484     }
12485     else
12486     {
12487         frame_set = &tng_data->current_trajectory_frame_set;
12488         next_frame_set_file_pos = frame_set->next_frame_set_file_pos;
12489     }
12490
12491     if(next_frame_set_file_pos <= 0)
12492     {
12493         return(TNG_FAILURE);
12494     }
12495
12496     fseeko(tng_data->input_file, next_frame_set_file_pos, SEEK_SET);
12497     /* Read block headers first to see that a frame set block is found. */
12498     tng_block_init(&block);
12499     stat = tng_block_header_read(tng_data, block);
12500     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12501     {
12502         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12503                file_pos, __FILE__, __LINE__);
12504         return(TNG_CRITICAL);
12505     }
12506 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12507     {
12508         tng_block_read_next(tng_data, block, TNG_USE_HASH);
12509     }*/
12510     tng_block_destroy(&block);
12511
12512     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
12513     {
12514         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
12515                __FILE__, __LINE__);
12516         return(TNG_CRITICAL);
12517     }
12518     fseeko(tng_data->input_file, file_pos, SEEK_SET);
12519
12520     return(TNG_SUCCESS);
12521 }
12522
12523 static tng_function_status tng_gen_data_block_add
12524                 (const tng_trajectory_t tng_data,
12525                  const int64_t id,
12526                  const tng_bool is_particle_data,
12527                  const char *block_name,
12528                  const char datatype,
12529                  const char block_type_flag,
12530                  int64_t n_frames,
12531                  const int64_t n_values_per_frame,
12532                  int64_t stride_length,
12533                  const int64_t num_first_particle,
12534                  const int64_t n_particles,
12535                  const int64_t codec_id,
12536                  void *new_data)
12537 {
12538     int i, size, len;
12539     int64_t j, k;
12540     int64_t tot_n_particles, n_frames_div;
12541     char ***first_dim_values, **second_dim_values;
12542     tng_trajectory_frame_set_t frame_set;
12543     tng_data_t data;
12544     char *new_data_c=new_data;
12545     tng_function_status stat;
12546
12547     frame_set = &tng_data->current_trajectory_frame_set;
12548
12549     if(stride_length <= 0)
12550     {
12551         stride_length = 1;
12552     }
12553
12554     if(is_particle_data)
12555     {
12556         stat = tng_particle_data_find(tng_data, id, &data);
12557     }
12558     else
12559     {
12560         stat = tng_data_find(tng_data, id, &data);
12561     }
12562     /* If the block does not exist, create it */
12563     if(stat != TNG_SUCCESS)
12564     {
12565         if(is_particle_data)
12566         {
12567             stat = tng_particle_data_block_create(tng_data, block_type_flag);
12568         }
12569         else
12570         {
12571             stat = tng_data_block_create(tng_data, block_type_flag);
12572         }
12573
12574         if(stat != TNG_SUCCESS)
12575         {
12576             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
12577                    __FILE__, __LINE__);
12578             return(TNG_CRITICAL);
12579         }
12580         if(is_particle_data)
12581         {
12582             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12583             {
12584                 data = &frame_set->tr_particle_data[frame_set->
12585                                                     n_particle_data_blocks - 1];
12586             }
12587             else
12588             {
12589                 data = &tng_data->non_tr_particle_data[tng_data->
12590                                                     n_particle_data_blocks - 1];
12591             }
12592         }
12593         else
12594         {
12595             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12596             {
12597                 data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
12598             }
12599             else
12600             {
12601                 data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
12602             }
12603         }
12604         data->block_id = id;
12605
12606         data->block_name = malloc(strlen(block_name) + 1);
12607         if(!data->block_name)
12608         {
12609             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
12610                    (unsigned int)strlen(block_name)+1, __FILE__, __LINE__);
12611             return(TNG_CRITICAL);
12612         }
12613         strncpy(data->block_name, block_name, strlen(block_name) + 1);
12614
12615         data->values = 0;
12616         /* FIXME: Memory leak from strings. */
12617         data->strings = 0;
12618         data->last_retrieved_frame = -1;
12619     }
12620
12621     data->datatype = datatype;
12622     data->stride_length = tng_max_i64(stride_length, 1);
12623     data->n_values_per_frame = n_values_per_frame;
12624     data->n_frames = n_frames;
12625     if(is_particle_data)
12626     {
12627         data->dependency = TNG_PARTICLE_DEPENDENT;
12628     }
12629     else
12630     {
12631         data->dependency = 0;
12632     }
12633     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
12634                           (n_frames > 1 ||
12635                            frame_set->n_frames == n_frames ||
12636                            stride_length > 1))
12637     {
12638         data->dependency += TNG_FRAME_DEPENDENT;
12639     }
12640     data->codec_id = codec_id;
12641     data->compression_multiplier = 1.0;
12642     /* FIXME: This can cause problems. */
12643     data->first_frame_with_data = frame_set->first_frame;
12644
12645     if(is_particle_data)
12646     {
12647         if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
12648         {
12649             tot_n_particles = frame_set->n_particles;
12650         }
12651         else
12652         {
12653             tot_n_particles = tng_data->n_particles;
12654         }
12655     }
12656     /* This is just to keep the compiler happy - avoid it considering tot_n_particles
12657      * uninitialized. */
12658     else
12659     {
12660         tot_n_particles = 0;
12661     }
12662
12663     /* If data values are supplied add that data to the data block. */
12664     if(new_data_c)
12665     {
12666         /* Allocate memory */
12667         if(is_particle_data)
12668         {
12669             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
12670                                             stride_length, tot_n_particles,
12671                                             n_values_per_frame);
12672         }
12673         else
12674         {
12675             stat = tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
12676                                  n_values_per_frame);
12677         }
12678         if(stat != TNG_SUCCESS)
12679         {
12680             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
12681                 __FILE__, __LINE__);
12682             return(TNG_CRITICAL);
12683         }
12684
12685         if(n_frames > frame_set->n_unwritten_frames)
12686         {
12687             frame_set->n_unwritten_frames = n_frames;
12688         }
12689
12690         n_frames_div = (n_frames % stride_length) ?
12691                      n_frames / stride_length + 1:
12692                      n_frames / stride_length;
12693
12694         if(datatype == TNG_CHAR_DATA)
12695         {
12696             if(is_particle_data)
12697             {
12698                 for(i = 0; i < n_frames_div; i++)
12699                 {
12700                     first_dim_values = data->strings[i];
12701                     for(j = num_first_particle; j < num_first_particle + n_particles;
12702                         j++)
12703                     {
12704                         second_dim_values = first_dim_values[j];
12705                         for(k = 0; k < n_values_per_frame; k++)
12706                         {
12707                             len = tng_min_size(strlen(new_data_c) + 1,
12708                                     TNG_MAX_STR_LEN);
12709                             if(second_dim_values[k])
12710                             {
12711                                 free(second_dim_values[k]);
12712                             }
12713                             second_dim_values[k] = malloc(len);
12714                             if(!second_dim_values[k])
12715                             {
12716                                 fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12717                                     len, __FILE__, __LINE__);
12718                                 return(TNG_CRITICAL);
12719                             }
12720                             strncpy(second_dim_values[k],
12721                                     new_data_c, len);
12722                             new_data_c += len;
12723                         }
12724                     }
12725                 }
12726             }
12727             else
12728             {
12729                 for(i = 0; i < n_frames_div; i++)
12730                 {
12731                     second_dim_values = data->strings[0][i];
12732                     for(j = 0; j < n_values_per_frame; j++)
12733                     {
12734                         len = tng_min_size(strlen(new_data_c) + 1,
12735                                     TNG_MAX_STR_LEN);
12736                         if(second_dim_values[j])
12737                         {
12738                             free(second_dim_values[j]);
12739                         }
12740                         second_dim_values[j] = malloc(len);
12741                         if(!second_dim_values[j])
12742                         {
12743                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12744                                 len, __FILE__, __LINE__);
12745                             return(TNG_CRITICAL);
12746                         }
12747                         strncpy(second_dim_values[j],
12748                                 new_data_c, len);
12749                         new_data_c += len;
12750                     }
12751                 }
12752             }
12753         }
12754         else
12755         {
12756             switch(datatype)
12757             {
12758             case TNG_INT_DATA:
12759                 size = sizeof(int64_t);
12760                 break;
12761             case TNG_FLOAT_DATA:
12762                 size = sizeof(float);
12763                 break;
12764             case TNG_DOUBLE_DATA:
12765             default:
12766                 size = sizeof(double);
12767             }
12768
12769             if(is_particle_data)
12770             {
12771                 memcpy(data->values, new_data, size * n_frames_div *
12772                     n_particles * n_values_per_frame);
12773             }
12774             else
12775             {
12776                 memcpy(data->values, new_data, size * n_frames_div *
12777                     n_values_per_frame);
12778             }
12779         }
12780     }
12781
12782     return(TNG_SUCCESS);
12783 }
12784
12785 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
12786                 (const tng_trajectory_t tng_data,
12787                  const int64_t id,
12788                  const char *block_name,
12789                  const char datatype,
12790                  const char block_type_flag,
12791                  int64_t n_frames,
12792                  const int64_t n_values_per_frame,
12793                  int64_t stride_length,
12794                  const int64_t codec_id,
12795                  void *new_data)
12796 {
12797     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12798     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
12799     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12800
12801     return(tng_gen_data_block_add(tng_data, id, TNG_FALSE, block_name, datatype,
12802                                   block_type_flag, n_frames, n_values_per_frame,
12803                                   stride_length, 0, 0, codec_id, new_data));
12804 }
12805
12806 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
12807                 (const tng_trajectory_t tng_data,
12808                  const int64_t id,
12809                  const char *block_name,
12810                  const char datatype,
12811                  const char block_type_flag,
12812                  int64_t n_frames,
12813                  const int64_t n_values_per_frame,
12814                  int64_t stride_length,
12815                  const int64_t num_first_particle,
12816                  const int64_t n_particles,
12817                  const int64_t codec_id,
12818                  void *new_data)
12819 {
12820     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12821     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
12822     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12823     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
12824     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
12825
12826     return(tng_gen_data_block_add(tng_data, id, TNG_TRUE, block_name, datatype,
12827                                   block_type_flag, n_frames, n_values_per_frame,
12828                                   stride_length, num_first_particle, n_particles,
12829                                   codec_id, new_data));
12830 }
12831
12832 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
12833                 (const tng_trajectory_t tng_data,
12834                  const int64_t block_id,
12835                  char *name,
12836                  const int max_len)
12837 {
12838     int64_t i;
12839     tng_trajectory_frame_set_t frame_set;
12840     tng_function_status stat;
12841     tng_data_t data;
12842     int block_type = -1;
12843
12844     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12845     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
12846
12847     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12848     {
12849         data = &tng_data->non_tr_particle_data[i];
12850         if(data->block_id == block_id)
12851         {
12852             strncpy(name, data->block_name, max_len);
12853             name[max_len - 1] = '\0';
12854             return(TNG_SUCCESS);
12855         }
12856     }
12857     for(i = 0; i < tng_data->n_data_blocks; i++)
12858     {
12859         data = &tng_data->non_tr_data[i];
12860         if(data->block_id == block_id)
12861         {
12862             strncpy(name, data->block_name, max_len);
12863             name[max_len - 1] = '\0';
12864             return(TNG_SUCCESS);
12865         }
12866     }
12867
12868     frame_set = &tng_data->current_trajectory_frame_set;
12869
12870     stat = tng_particle_data_find(tng_data, block_id, &data);
12871     if(stat == TNG_SUCCESS)
12872     {
12873         block_type = TNG_PARTICLE_BLOCK_DATA;
12874     }
12875     else
12876     {
12877         stat = tng_data_find(tng_data, block_id, &data);
12878         if(stat == TNG_SUCCESS)
12879         {
12880             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
12881         }
12882         else
12883         {
12884             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
12885             if(stat != TNG_SUCCESS)
12886             {
12887                 return(stat);
12888             }
12889             stat = tng_particle_data_find(tng_data, block_id, &data);
12890             if(stat == TNG_SUCCESS)
12891             {
12892                 block_type = TNG_PARTICLE_BLOCK_DATA;
12893             }
12894             else
12895             {
12896                 stat = tng_data_find(tng_data, block_id, &data);
12897                 if(stat == TNG_SUCCESS)
12898                 {
12899                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
12900                 }
12901             }
12902         }
12903     }
12904     if(block_type == TNG_PARTICLE_BLOCK_DATA)
12905     {
12906         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
12907         {
12908             data = &frame_set->tr_particle_data[i];
12909             if(data->block_id == block_id)
12910             {
12911                 strncpy(name, data->block_name, max_len);
12912                 name[max_len - 1] = '\0';
12913                 return(TNG_SUCCESS);
12914             }
12915         }
12916     }
12917     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
12918     {
12919         for(i = 0; i < frame_set->n_data_blocks; i++)
12920         {
12921             data = &frame_set->tr_data[i];
12922             if(data->block_id == block_id)
12923             {
12924                 strncpy(name, data->block_name, max_len);
12925                 name[max_len - 1] = '\0';
12926                 return(TNG_SUCCESS);
12927             }
12928         }
12929     }
12930
12931     return(TNG_FAILURE);
12932 }
12933
12934 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
12935                 (const tng_trajectory_t tng_data,
12936                  const int64_t block_id,
12937                  int *block_dependency)
12938 {
12939     int64_t i;
12940     tng_function_status stat;
12941     tng_data_t data;
12942
12943     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12944     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
12945
12946     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12947     {
12948         data = &tng_data->non_tr_particle_data[i];
12949         if(data->block_id == block_id)
12950         {
12951             *block_dependency = TNG_PARTICLE_DEPENDENT;
12952             return(TNG_SUCCESS);
12953         }
12954     }
12955     for(i = 0; i < tng_data->n_data_blocks; i++)
12956     {
12957         data = &tng_data->non_tr_data[i];
12958         if(data->block_id == block_id)
12959         {
12960             *block_dependency = 0;
12961             return(TNG_SUCCESS);
12962         }
12963     }
12964
12965     stat = tng_particle_data_find(tng_data, block_id, &data);
12966     if(stat == TNG_SUCCESS)
12967     {
12968         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
12969         return(TNG_SUCCESS);
12970     }
12971     else
12972     {
12973         stat = tng_data_find(tng_data, block_id, &data);
12974         if(stat == TNG_SUCCESS)
12975         {
12976             *block_dependency = TNG_FRAME_DEPENDENT;
12977             return(TNG_SUCCESS);
12978         }
12979         else
12980         {
12981             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
12982             if(stat != TNG_SUCCESS)
12983             {
12984                 return(stat);
12985             }
12986             stat = tng_particle_data_find(tng_data, block_id, &data);
12987             if(stat == TNG_SUCCESS)
12988             {
12989                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
12990                 return(TNG_SUCCESS);
12991             }
12992             else
12993             {
12994                 stat = tng_data_find(tng_data, block_id, &data);
12995                 if(stat == TNG_SUCCESS)
12996                 {
12997                     *block_dependency = TNG_FRAME_DEPENDENT;
12998                     return(TNG_SUCCESS);
12999                 }
13000             }
13001         }
13002     }
13003
13004     return(TNG_FAILURE);
13005 }
13006
13007 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
13008                 (const tng_trajectory_t tng_data,
13009                  const int64_t block_id,
13010                  int64_t *n_values_per_frame)
13011 {
13012     int64_t i;
13013     tng_function_status stat;
13014     tng_data_t data;
13015
13016     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13017     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
13018
13019     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13020     {
13021         data = &tng_data->non_tr_particle_data[i];
13022         if(data->block_id == block_id)
13023         {
13024             *n_values_per_frame = data->n_values_per_frame;
13025             return(TNG_SUCCESS);
13026         }
13027     }
13028     for(i = 0; i < tng_data->n_data_blocks; i++)
13029     {
13030         data = &tng_data->non_tr_data[i];
13031         if(data->block_id == block_id)
13032         {
13033             *n_values_per_frame = data->n_values_per_frame;
13034             return(TNG_SUCCESS);
13035         }
13036     }
13037
13038     stat = tng_particle_data_find(tng_data, block_id, &data);
13039     if(stat == TNG_SUCCESS)
13040     {
13041         *n_values_per_frame = data->n_values_per_frame;
13042         return(TNG_SUCCESS);
13043     }
13044     else
13045     {
13046         stat = tng_data_find(tng_data, block_id, &data);
13047         if(stat == TNG_SUCCESS)
13048         {
13049             *n_values_per_frame = data->n_values_per_frame;
13050             return(TNG_SUCCESS);
13051         }
13052         else
13053         {
13054             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13055             if(stat != TNG_SUCCESS)
13056             {
13057                 return(stat);
13058             }
13059             stat = tng_particle_data_find(tng_data, block_id, &data);
13060             if(stat == TNG_SUCCESS)
13061             {
13062                 *n_values_per_frame = data->n_values_per_frame;
13063                 return(TNG_SUCCESS);
13064             }
13065             else
13066             {
13067                 stat = tng_data_find(tng_data, block_id, &data);
13068                 if(stat == TNG_SUCCESS)
13069                 {
13070                     *n_values_per_frame = data->n_values_per_frame;
13071                     return(TNG_SUCCESS);
13072                 }
13073             }
13074         }
13075     }
13076
13077     return(TNG_FAILURE);
13078 }
13079
13080 tng_function_status DECLSPECDLLEXPORT tng_frame_set_n_frames_of_data_block_get
13081                 (const tng_trajectory_t tng_data,
13082                  const int64_t block_id,
13083                  int64_t *n_frames)
13084 {
13085     tng_gen_block_t block;
13086     tng_function_status stat;
13087     char datatype, dependency, sparse_data;
13088     int64_t n_values, codec_id, first_frame_with_data, stride_length, curr_n_frames;
13089     int64_t num_first_particle, block_n_particles;
13090     double multiplier;
13091     md5_state_t md5_state;
13092     int found = TNG_FALSE;
13093
13094     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13095
13096     tng_block_init(&block);
13097
13098     stat = tng_block_header_read(tng_data, block);
13099     /* If the block header could not be read the reading position might not have been
13100      * at the start of a block. Try again from the file position of the current frame
13101      * set. */
13102     if(stat != TNG_SUCCESS)
13103     {
13104         fseeko(tng_data->input_file, tng_data->current_trajectory_frame_set_input_file_pos, SEEK_SET);
13105         stat = tng_block_header_read(tng_data, block);
13106         if(stat != TNG_SUCCESS)
13107         {
13108             tng_block_destroy(&block);
13109             return(stat);
13110         }
13111     }
13112     if(block->id == TNG_TRAJECTORY_FRAME_SET)
13113     {
13114         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
13115         if(stat != TNG_SUCCESS)
13116         {
13117             tng_block_destroy(&block);
13118             return(stat);
13119         }
13120         stat = tng_block_header_read(tng_data, block);
13121     }
13122     while(stat == TNG_SUCCESS && block->id != TNG_TRAJECTORY_FRAME_SET && found == TNG_FALSE)
13123     {
13124         if(block->id == block_id)
13125         {
13126             stat = tng_data_block_meta_information_read(tng_data, &datatype,
13127                                                         &dependency, &sparse_data,
13128                                                         &n_values, &codec_id,
13129                                                         &first_frame_with_data,
13130                                                         &stride_length, &curr_n_frames,
13131                                                         &num_first_particle,
13132                                                         &block_n_particles,
13133                                                         &multiplier, TNG_SKIP_HASH,
13134                                                         &md5_state);
13135             if(stat == TNG_SUCCESS)
13136             {
13137                 found = TNG_TRUE;
13138             }
13139         }
13140         else
13141         {
13142             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
13143             stat = tng_block_header_read(tng_data, block);
13144         }
13145     }
13146     if(found == TNG_TRUE)
13147     {
13148         *n_frames = (tng_data->current_trajectory_frame_set.n_frames -
13149                      (tng_data->current_trajectory_frame_set.first_frame - first_frame_with_data)) / stride_length;
13150     }
13151     else if(stat == TNG_SUCCESS)
13152     {
13153         *n_frames = 0;
13154     }
13155
13156     tng_block_destroy(&block);
13157
13158     return(stat);
13159 }
13160
13161 static tng_function_status tng_frame_gen_data_write
13162                 (const tng_trajectory_t tng_data,
13163                  const int64_t frame_nr,
13164                  const int64_t block_id,
13165                  const tng_bool is_particle_data,
13166                  const int64_t val_first_particle,
13167                  const int64_t val_n_particles,
13168                  const void *values,
13169                  const char hash_mode)
13170 {
13171     int64_t header_pos, file_pos, tot_n_particles;
13172     int64_t output_file_len, n_values_per_frame, size, contents_size;
13173     int64_t header_size, temp_first, temp_last;
13174     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
13175     int64_t i, last_frame, temp_current, write_n_particles;
13176     tng_gen_block_t block;
13177     tng_trajectory_frame_set_t frame_set;
13178     FILE *temp = tng_data->input_file;
13179     struct tng_data data;
13180     tng_function_status stat;
13181     tng_particle_mapping_t mapping;
13182     char dependency, sparse_data, datatype;
13183     void *copy;
13184
13185     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13186     {
13187         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13188                __FILE__, __LINE__);
13189         return(TNG_CRITICAL);
13190     }
13191
13192     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13193     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13194     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13195     tng_data->first_trajectory_frame_set_input_file_pos =
13196     tng_data->first_trajectory_frame_set_output_file_pos;
13197     tng_data->last_trajectory_frame_set_input_file_pos =
13198     tng_data->last_trajectory_frame_set_output_file_pos;
13199     tng_data->current_trajectory_frame_set_input_file_pos =
13200     tng_data->current_trajectory_frame_set_output_file_pos;
13201
13202     tng_data->input_file = tng_data->output_file;
13203
13204     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13205
13206     frame_set = &tng_data->current_trajectory_frame_set;
13207
13208     if(stat != TNG_SUCCESS)
13209     {
13210         last_frame = frame_set->first_frame +
13211                      frame_set->n_frames - 1;
13212         /* If the wanted frame would be in the frame set after the last
13213             * frame set create a new frame set. */
13214         if(stat == TNG_FAILURE &&
13215             last_frame < frame_nr)
13216 /*           (last_frame < frame_nr &&
13217             tng_data->current_trajectory_frame_set.first_frame +
13218             tng_data->frame_set_n_frames >= frame_nr))*/
13219         {
13220             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13221             {
13222                 last_frame = frame_nr - 1;
13223             }
13224             tng_frame_set_new(tng_data,
13225                               last_frame+1,
13226                               tng_data->frame_set_n_frames);
13227             file_pos = ftello(tng_data->output_file);
13228             fseeko(tng_data->output_file, 0, SEEK_END);
13229             output_file_len = ftello(tng_data->output_file);
13230             fseeko(tng_data->output_file, file_pos, SEEK_SET);
13231
13232             /* Read mapping blocks from the last frame set */
13233             tng_block_init(&block);
13234
13235             stat = tng_block_header_read(tng_data, block);
13236             while(file_pos < output_file_len &&
13237                   stat != TNG_CRITICAL &&
13238                   block->id != TNG_TRAJECTORY_FRAME_SET &&
13239                   block->id != -1)
13240             {
13241                 if(block->id == TNG_PARTICLE_MAPPING)
13242                 {
13243                     tng_trajectory_mapping_block_read(tng_data, block,
13244                                                       hash_mode);
13245                 }
13246                 else
13247                 {
13248                     fseeko(tng_data->output_file, block->block_contents_size,
13249                         SEEK_CUR);
13250                 }
13251                 file_pos = ftello(tng_data->output_file);
13252                 if(file_pos < output_file_len)
13253                 {
13254                     stat = tng_block_header_read(tng_data, block);
13255                 }
13256             }
13257
13258             tng_block_destroy(&block);
13259             /* Write the frame set to disk */
13260             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13261             {
13262                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13263                 return(TNG_CRITICAL);
13264             }
13265         }
13266         else
13267         {
13268             tng_data->input_file = temp;
13269             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13270             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13271             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13272             return(stat);
13273         }
13274     }
13275
13276     tng_block_init(&block);
13277
13278     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13279
13280     fseeko(tng_data->output_file, 0, SEEK_END);
13281     output_file_len = ftello(tng_data->output_file);
13282     fseeko(tng_data->output_file, file_pos, SEEK_SET);
13283
13284     /* Read past the frame set block first */
13285     stat = tng_block_header_read(tng_data, block);
13286     if(stat == TNG_CRITICAL)
13287     {
13288         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13289                file_pos, __FILE__, __LINE__);
13290         tng_block_destroy(&block);
13291         tng_data->input_file = temp;
13292
13293         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13294         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13295         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13296         return(stat);
13297     }
13298     fseeko(tng_data->output_file, block->block_contents_size,
13299             SEEK_CUR);
13300
13301     if(is_particle_data == TNG_TRUE)
13302     {
13303         if(tng_data->var_num_atoms_flag)
13304         {
13305             tot_n_particles = frame_set->n_particles;
13306         }
13307         else
13308         {
13309             tot_n_particles = tng_data->n_particles;
13310         }
13311
13312         if(val_n_particles < tot_n_particles)
13313         {
13314             mapping_block_end_pos = -1;
13315             /* Read all mapping blocks to find the right place to put the data */
13316             stat = tng_block_header_read(tng_data, block);
13317             while(file_pos < output_file_len &&
13318                     stat != TNG_CRITICAL &&
13319                     block->id != TNG_TRAJECTORY_FRAME_SET &&
13320                     block->id != -1)
13321             {
13322                 if(block->id == TNG_PARTICLE_MAPPING)
13323                 {
13324                     tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
13325                 }
13326                 else
13327                 {
13328                     fseeko(tng_data->output_file, block->block_contents_size,
13329                            SEEK_CUR);
13330                 }
13331                 file_pos = ftello(tng_data->output_file);
13332                 if(block->id == TNG_PARTICLE_MAPPING)
13333                 {
13334                     mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
13335                     if(val_first_particle >= mapping->num_first_particle &&
13336                        val_first_particle < mapping->num_first_particle +
13337                        mapping->n_particles &&
13338                        val_first_particle + val_n_particles <=
13339                        mapping->num_first_particle + mapping->n_particles)
13340                     {
13341                         mapping_block_end_pos = file_pos;
13342                     }
13343                 }
13344                 if(file_pos < output_file_len)
13345                 {
13346                     stat = tng_block_header_read(tng_data, block);
13347                 }
13348             }
13349             if(stat == TNG_CRITICAL)
13350             {
13351                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13352                        file_pos, __FILE__, __LINE__);
13353                 tng_block_destroy(&block);
13354                 tng_data->input_file = temp;
13355
13356                 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13357                 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13358                 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13359                 return(stat);
13360             }
13361             if(mapping_block_end_pos < 0)
13362             {
13363                 tng_block_destroy(&block);
13364                 tng_data->input_file = temp;
13365
13366                 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13367                 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13368                 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13369                 return(TNG_FAILURE);
13370             }
13371             fseeko(tng_data->output_file, mapping_block_end_pos, SEEK_SET);
13372         }
13373     }
13374
13375     /* Read all block headers until next frame set block or
13376      * until the wanted block id is found */
13377     stat = tng_block_header_read(tng_data, block);
13378     while(file_pos < output_file_len &&
13379             stat != TNG_CRITICAL &&
13380             block->id != block_id &&
13381             (is_particle_data != TNG_TRUE || block->id != TNG_PARTICLE_MAPPING) &&
13382             block->id != TNG_TRAJECTORY_FRAME_SET &&
13383             block->id != -1)
13384     {
13385         fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
13386         file_pos = ftello(tng_data->output_file);
13387         if(file_pos < output_file_len)
13388         {
13389             stat = tng_block_header_read(tng_data, block);
13390         }
13391     }
13392     if(stat == TNG_CRITICAL)
13393     {
13394         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13395                file_pos, __FILE__, __LINE__);
13396         tng_block_destroy(&block);
13397         tng_data->input_file = temp;
13398         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13399         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13400         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13401         return(stat);
13402     }
13403
13404     contents_size = block->block_contents_size;
13405     header_size = block->header_contents_size;
13406
13407     header_pos = ftello(tng_data->output_file) - header_size;
13408     frame_set = &tng_data->current_trajectory_frame_set;
13409
13410     if(tng_file_input_numerical(tng_data, &datatype,
13411                                  sizeof(datatype),
13412                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13413     {
13414         tng_block_destroy(&block);
13415         return(TNG_CRITICAL);
13416     }
13417     if(tng_file_input_numerical(tng_data, &dependency,
13418                                  sizeof(dependency),
13419                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13420     {
13421         tng_block_destroy(&block);
13422         return(TNG_CRITICAL);
13423     }
13424     data.datatype = datatype;
13425
13426     if(!(dependency & TNG_FRAME_DEPENDENT) ||
13427        (is_particle_data == TNG_FALSE && dependency & TNG_PARTICLE_DEPENDENT) ||
13428        (is_particle_data == TNG_TRUE && !(dependency & TNG_PARTICLE_DEPENDENT)))
13429     {
13430         tng_block_destroy(&block);
13431         tng_data->input_file = temp;
13432
13433         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13434         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13435         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13436         return(TNG_FAILURE);
13437     }
13438
13439     if(tng_file_input_numerical(tng_data, &sparse_data,
13440                                  sizeof(sparse_data),
13441                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13442     {
13443         tng_block_destroy(&block);
13444         return(TNG_CRITICAL);
13445     }
13446
13447     if(tng_file_input_numerical(tng_data, &data.n_values_per_frame,
13448                                  sizeof(data.n_values_per_frame),
13449                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13450     {
13451         tng_block_destroy(&block);
13452         return(TNG_CRITICAL);
13453     }
13454
13455     if(tng_file_input_numerical(tng_data, &data.codec_id,
13456                                  sizeof(data.codec_id),
13457                                  TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13458     {
13459         tng_block_destroy(&block);
13460         return(TNG_CRITICAL);
13461     }
13462
13463     if(data.codec_id != TNG_UNCOMPRESSED)
13464     {
13465         if(tng_file_input_numerical(tng_data, &data.compression_multiplier,
13466                                      sizeof(data.compression_multiplier),
13467                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13468         {
13469             tng_block_destroy(&block);
13470             return(TNG_CRITICAL);
13471         }
13472     }
13473     else
13474     {
13475         data.compression_multiplier = 1;
13476     }
13477
13478     if(sparse_data)
13479     {
13480         if(tng_file_input_numerical(tng_data, &data.first_frame_with_data,
13481                                      sizeof(data.first_frame_with_data),
13482                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13483         {
13484             tng_block_destroy(&block);
13485             return(TNG_CRITICAL);
13486         }
13487
13488         if(tng_file_input_numerical(tng_data, &data.stride_length,
13489                                      sizeof(data.stride_length),
13490                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13491         {
13492             tng_block_destroy(&block);
13493             return(TNG_CRITICAL);
13494         }
13495     }
13496     else
13497     {
13498         data.first_frame_with_data = 0;
13499         data.stride_length = 1;
13500     }
13501     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
13502
13503     if(is_particle_data == TNG_TRUE)
13504     {
13505         if(tng_file_input_numerical(tng_data, &num_first_particle,
13506                                      sizeof(num_first_particle),
13507                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13508         {
13509             tng_block_destroy(&block);
13510             return(TNG_CRITICAL);
13511         }
13512
13513         if(tng_file_input_numerical(tng_data, &block_n_particles,
13514                                      sizeof(block_n_particles),
13515                                      TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13516         {
13517             tng_block_destroy(&block);
13518             return(TNG_CRITICAL);
13519         }
13520     }
13521
13522     tng_data->input_file = temp;
13523
13524     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13525     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13526     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13527
13528     switch(data.datatype)
13529     {
13530         case(TNG_INT_DATA):
13531             size = sizeof(int64_t);
13532             break;
13533         case(TNG_FLOAT_DATA):
13534             size = sizeof(float);
13535             break;
13536         case(TNG_DOUBLE_DATA):
13537             size = sizeof(double);
13538             break;
13539         default:
13540             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
13541                    __LINE__);
13542             tng_block_destroy(&block);
13543             return(TNG_FAILURE);
13544     }
13545
13546     n_values_per_frame = data.n_values_per_frame;
13547
13548     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
13549                                data.first_frame_with_data)) /
13550                 data.stride_length;
13551     if(is_particle_data == TNG_TRUE)
13552     {
13553         file_pos *= block_n_particles * size * n_values_per_frame;
13554     }
13555     else
13556     {
13557         file_pos *= size * n_values_per_frame;
13558     }
13559
13560     if(file_pos > contents_size)
13561     {
13562         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
13563                __LINE__);
13564         tng_block_destroy(&block);
13565         return(TNG_FAILURE);
13566     }
13567
13568     fseeko(tng_data->output_file, file_pos, SEEK_CUR);
13569
13570     if(is_particle_data == TNG_TRUE)
13571     {
13572         write_n_particles = val_n_particles;
13573     }
13574     else
13575     {
13576         write_n_particles = 1;
13577     }
13578
13579     /* If the endianness is not big endian the data needs to be swapped */
13580     if((data.datatype == TNG_INT_DATA ||
13581         data.datatype == TNG_DOUBLE_DATA) &&
13582        tng_data->output_endianness_swap_func_64)
13583     {
13584         copy = malloc(write_n_particles * n_values_per_frame * size);
13585         memcpy(copy, values, write_n_particles * n_values_per_frame * size);
13586         for(i = 0; i < write_n_particles * n_values_per_frame; i++)
13587         {
13588             if(tng_data->output_endianness_swap_func_64(tng_data,
13589                 (int64_t *) copy+i)
13590                 != TNG_SUCCESS)
13591             {
13592                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13593                         __FILE__, __LINE__);
13594             }
13595         }
13596         fwrite(copy, write_n_particles * n_values_per_frame, size,
13597                tng_data->output_file);
13598         free(copy);
13599     }
13600     else if(data.datatype == TNG_FLOAT_DATA &&
13601             tng_data->output_endianness_swap_func_32)
13602     {
13603         copy = malloc(write_n_particles * n_values_per_frame * size);
13604         memcpy(copy, values, write_n_particles * n_values_per_frame * size);
13605         for(i = 0; i < write_n_particles * n_values_per_frame; i++)
13606         {
13607             if(tng_data->output_endianness_swap_func_32(tng_data,
13608                 (int32_t *) copy+i)
13609                 != TNG_SUCCESS)
13610             {
13611                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13612                         __FILE__, __LINE__);
13613             }
13614         }
13615         fwrite(copy, write_n_particles * n_values_per_frame, size,
13616                tng_data->output_file);
13617         free(copy);
13618     }
13619
13620     else
13621     {
13622         fwrite(values, write_n_particles * n_values_per_frame, size, tng_data->output_file);
13623     }
13624
13625     fflush(tng_data->output_file);
13626
13627     /* Update the number of written frames in the frame set. */
13628     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
13629     {
13630         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
13631     }
13632
13633     /* If the last frame has been written update the hash */
13634     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
13635        data.first_frame_with_data) >=
13636        frame_set->n_frames)
13637     {
13638         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
13639                             header_size);
13640     }
13641
13642     tng_block_destroy(&block);
13643
13644     return(TNG_SUCCESS);
13645 }
13646
13647 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
13648                 (const tng_trajectory_t tng_data,
13649                  const int64_t frame_nr,
13650                  const int64_t block_id,
13651                  const void *values,
13652                  const char hash_mode)
13653 {
13654     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13655     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13656     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13657
13658     /* This is now just calling the generic data writing function. This
13659      * function must keep its signature to let the API be backwards
13660      * compatible. */
13661     return(tng_frame_gen_data_write(tng_data, frame_nr, block_id,
13662                                     TNG_FALSE, 0, 0, values, hash_mode));
13663 }
13664
13665 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
13666                 (const tng_trajectory_t tng_data,
13667                  const int64_t frame_nr,
13668                  const int64_t block_id,
13669                  const int64_t val_first_particle,
13670                  const int64_t val_n_particles,
13671                  const void *values,
13672                  const char hash_mode)
13673 {
13674     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13675     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13676     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13677     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
13678     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
13679
13680     /* This is now just calling the generic data writing function. This
13681      * function must keep its signature to let the API be backwards
13682      * compatible. */
13683     return(tng_frame_gen_data_write(tng_data, frame_nr, block_id,
13684                                     TNG_TRUE, val_first_particle, val_n_particles,
13685                                     values, hash_mode));
13686 }
13687
13688 static tng_function_status tng_data_values_alloc
13689                 (const tng_trajectory_t tng_data,
13690                  union data_values ***values,
13691                  const int64_t n_frames,
13692                  const int64_t n_values_per_frame,
13693                  const char type)
13694 {
13695     int64_t i;
13696     tng_function_status stat;
13697
13698     if(n_frames <= 0 || n_values_per_frame <= 0)
13699     {
13700         return(TNG_FAILURE);
13701     }
13702
13703     if(*values)
13704     {
13705         stat = tng_data_values_free(tng_data, *values, n_frames,
13706                                     n_values_per_frame,
13707                                     type);
13708         if(stat != TNG_SUCCESS)
13709         {
13710             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
13711                    __FILE__, __LINE__);
13712             return(stat);
13713         }
13714     }
13715     *values = malloc(sizeof(union data_values *) * n_frames);
13716     if(!*values)
13717     {
13718         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
13719                sizeof(union data_values **) * n_frames,
13720                __FILE__, __LINE__);
13721         return(TNG_CRITICAL);
13722
13723     }
13724
13725     for(i = 0; i < n_frames; i++)
13726     {
13727         (*values)[i] = malloc(sizeof(union data_values) *
13728                            n_values_per_frame);
13729         if(!(*values)[i])
13730         {
13731             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
13732                    sizeof(union data_values) * n_values_per_frame,
13733                    __FILE__, __LINE__);
13734             free(values);
13735             values = 0;
13736             return(TNG_CRITICAL);
13737         }
13738     }
13739     return(TNG_SUCCESS);
13740 }
13741
13742 /* FIXME: This needs ***values */
13743 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
13744                 (const tng_trajectory_t tng_data,
13745                  union data_values **values,
13746                  const int64_t n_frames,
13747                  const int64_t n_values_per_frame,
13748                  const char type)
13749 {
13750     int64_t i, j;
13751     (void)tng_data;
13752
13753     if(values)
13754     {
13755         for(i = 0; i < n_frames; i++)
13756         {
13757             if(values[i])
13758             {
13759                 if(type == TNG_CHAR_DATA)
13760                 {
13761                     for(j = 0; j < n_values_per_frame; j++)
13762                     {
13763                         if(values[i][j].c)
13764                         {
13765                             free(values[i][j].c);
13766                             values[i][j].c = 0;
13767                         }
13768                     }
13769                 }
13770                 free(values[i]);
13771                 values[i] = 0;
13772             }
13773         }
13774         free(values);
13775         values = 0;
13776     }
13777
13778     return(TNG_SUCCESS);
13779 }
13780
13781 static tng_function_status tng_particle_data_values_alloc
13782                 (const tng_trajectory_t tng_data,
13783                  union data_values ****values,
13784                  const int64_t n_frames,
13785                  const int64_t n_particles,
13786                  const int64_t n_values_per_frame,
13787                  const char type)
13788 {
13789     int64_t i, j;
13790     tng_function_status stat;
13791
13792     if(n_particles == 0 || n_values_per_frame == 0)
13793     {
13794         return(TNG_FAILURE);
13795     }
13796
13797     if(*values)
13798     {
13799         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
13800                                              n_particles, n_values_per_frame,
13801                                              type);
13802         if(stat != TNG_SUCCESS)
13803         {
13804             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
13805                    __FILE__, __LINE__);
13806             return(stat);
13807         }
13808     }
13809     *values = malloc(sizeof(union data_values **) * n_frames);
13810     if(!*values)
13811     {
13812         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
13813                sizeof(union data_values **) * n_frames,
13814                __FILE__, __LINE__);
13815         return(TNG_CRITICAL);
13816
13817     }
13818
13819     for(i = 0; i < n_frames; i++)
13820     {
13821         (*values)[i] = malloc(sizeof(union data_values *) *
13822                            n_particles);
13823         if(!(*values)[i])
13824         {
13825             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
13826                    sizeof(union data_values *) * n_particles,
13827                    __FILE__, __LINE__);
13828             free(*values);
13829             *values = 0;
13830             return(TNG_CRITICAL);
13831         }
13832         for(j = 0; j < n_particles; j++)
13833         {
13834             (*values)[i][j] = malloc(sizeof(union data_values) *
13835                                   n_values_per_frame);
13836             if(!(*values)[i][j])
13837             {
13838                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
13839                     sizeof(union data_values *) * n_particles,
13840                     __FILE__, __LINE__);
13841                 tng_particle_data_values_free(tng_data, *values, n_frames,
13842                                               n_particles, n_values_per_frame,
13843                                               type);
13844                 *values = 0;
13845                 return(TNG_CRITICAL);
13846             }
13847         }
13848     }
13849     return(TNG_SUCCESS);
13850 }
13851
13852 /* FIXME: This needs ****values */
13853 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
13854                 (const tng_trajectory_t tng_data,
13855                  union data_values ***values,
13856                  const int64_t n_frames,
13857                  const int64_t n_particles,
13858                  const int64_t n_values_per_frame,
13859                  const char type)
13860 {
13861     int64_t i, j, k;
13862     (void)tng_data;
13863
13864     if(values)
13865     {
13866         for(i = 0; i < n_frames; i++)
13867         {
13868             if(values[i])
13869             {
13870                 for(j = 0; j < n_particles; j++)
13871                 {
13872                     if(type == TNG_CHAR_DATA)
13873                     {
13874                         for(k = 0; k < n_values_per_frame; k++)
13875                         {
13876                             if(values[i][j][k].c)
13877                             {
13878                                 free(values[i][j][k].c);
13879                                 values[i][j][k].c = 0;
13880                             }
13881                         }
13882                     }
13883                     free(values[i][j]);
13884                     values[i][j] = 0;
13885                 }
13886                 free(values[i]);
13887                 values[i] = 0;
13888             }
13889         }
13890         free(values);
13891         values = 0;
13892     }
13893
13894     return(TNG_SUCCESS);
13895 }
13896
13897 static tng_function_status tng_gen_data_get
13898                 (const tng_trajectory_t tng_data,
13899                  const int64_t block_id,
13900                  const tng_bool is_particle_data,
13901                  union data_values ****values,
13902                  int64_t *n_frames,
13903                  int64_t *n_particles,
13904                  int64_t *n_values_per_frame,
13905                  char *type)
13906 {
13907     int64_t i, j, k, mapping, file_pos, i_step, block_index;
13908     int size;
13909     size_t len;
13910     tng_data_t data;
13911     tng_trajectory_frame_set_t frame_set;
13912     tng_gen_block_t block;
13913     char block_type_flag;
13914     tng_function_status stat;
13915
13916     frame_set = &tng_data->current_trajectory_frame_set;
13917
13918     block_index = -1;
13919     data = 0;
13920
13921     if(is_particle_data == TNG_TRUE)
13922     {
13923         stat = tng_particle_data_find(tng_data, block_id, &data);
13924     }
13925     else
13926     {
13927         stat = tng_data_find(tng_data, block_id, &data);
13928     }
13929
13930     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
13931     {
13932         block_type_flag = TNG_TRAJECTORY_BLOCK;
13933     }
13934     else
13935     {
13936         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
13937     }
13938
13939     if(stat != TNG_SUCCESS)
13940     {
13941         tng_block_init(&block);
13942         file_pos = ftello(tng_data->input_file);
13943         /* Read all blocks until next frame set block */
13944         stat = tng_block_header_read(tng_data, block);
13945         while(file_pos < tng_data->input_file_len &&
13946                 stat != TNG_CRITICAL &&
13947                 block->id != TNG_TRAJECTORY_FRAME_SET &&
13948                 block->id != -1)
13949         {
13950             /* Use hash by default */
13951             stat = tng_block_read_next(tng_data, block,
13952                                     TNG_USE_HASH);
13953             if(stat != TNG_CRITICAL)
13954             {
13955                 file_pos = ftello(tng_data->input_file);
13956                 if(file_pos < tng_data->input_file_len)
13957                 {
13958                     stat = tng_block_header_read(tng_data, block);
13959                 }
13960             }
13961         }
13962         tng_block_destroy(&block);
13963         if(stat == TNG_CRITICAL)
13964         {
13965             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13966                     file_pos, __FILE__, __LINE__);
13967             return(stat);
13968         }
13969
13970         if(is_particle_data == TNG_TRUE)
13971         {
13972             for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13973             {
13974                 data = &frame_set->tr_particle_data[i];
13975                 if(data->block_id == block_id)
13976                 {
13977                     block_index = i;
13978                     block_type_flag = TNG_TRAJECTORY_BLOCK;
13979                     break;
13980                 }
13981             }
13982         }
13983         else
13984         {
13985             for(i = 0; i < frame_set->n_data_blocks; i++)
13986             {
13987                 data = &frame_set->tr_data[i];
13988                 if(data->block_id == block_id)
13989                 {
13990                     block_index = i;
13991                     break;
13992                 }
13993             }
13994         }
13995         if(block_index < 0)
13996         {
13997             return(TNG_FAILURE);
13998         }
13999     }
14000
14001     if(is_particle_data == TNG_TRUE)
14002     {
14003         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
14004            tng_data->var_num_atoms_flag)
14005         {
14006             *n_particles = frame_set->n_particles;
14007         }
14008         else
14009         {
14010             *n_particles = tng_data->n_particles;
14011         }
14012     }
14013
14014     *n_frames = tng_max_i64(1, data->n_frames);
14015     *n_values_per_frame = data->n_values_per_frame;
14016     *type = data->datatype;
14017
14018     if(is_particle_data == TNG_TRUE)
14019     {
14020         if(*values == 0)
14021         {
14022             if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
14023                                              *n_particles, *n_values_per_frame,
14024                                              *type) != TNG_SUCCESS)
14025             {
14026                 return(TNG_CRITICAL);
14027             }
14028         }
14029
14030         i_step = (*n_particles) * (*n_values_per_frame);
14031
14032         /* It's not very elegant to reuse so much of the code in the different case
14033          * statements, but it's unnecessarily slow to have the switch-case block
14034          * inside the for loops. */
14035         switch(*type)
14036         {
14037         case TNG_CHAR_DATA:
14038             for(i = 0; i < *n_frames; i++)
14039             {
14040                 for(j = 0; j < *n_particles; j++)
14041                 {
14042                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14043                     for(k = 0; k < *n_values_per_frame; k++)
14044                     {
14045                         len = strlen(data->strings[i][j][k]) + 1;
14046                         (*values)[i][mapping][k].c = malloc(len);
14047                         strncpy((*values)[i][mapping][k].c,
14048                                 data->strings[i][j][k], len);
14049                     }
14050                 }
14051             }
14052             break;
14053         case TNG_INT_DATA:
14054             size = sizeof(int);
14055             for(i = 0; i < *n_frames; i++)
14056             {
14057                 for(j = 0; j < *n_particles; j++)
14058                 {
14059                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14060                     for(k = 0; k < *n_values_per_frame; k++)
14061                     {
14062                         (*values)[i][mapping][k].i = *(int *)
14063                                                      ((char *)data->values + size *
14064                                                      (i * i_step + j *
14065                                                       (*n_values_per_frame) + k));
14066                     }
14067                 }
14068             }
14069             break;
14070         case TNG_FLOAT_DATA:
14071             size = sizeof(float);
14072             for(i = 0; i < *n_frames; i++)
14073             {
14074                 for(j = 0; j < *n_particles; j++)
14075                 {
14076                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14077                     for(k = 0; k < *n_values_per_frame; k++)
14078                     {
14079                         (*values)[i][mapping][k].f = *(float *)
14080                                                      ((char *)data->values + size *
14081                                                      (i * i_step + j *
14082                                                       (*n_values_per_frame) + k));
14083                     }
14084                 }
14085             }
14086             break;
14087         case TNG_DOUBLE_DATA:
14088         default:
14089             size = sizeof(double);
14090             for(i = 0; i < *n_frames; i++)
14091             {
14092                 for(j = 0; j < *n_particles; j++)
14093                 {
14094                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14095                     for(k = 0; k < *n_values_per_frame; k++)
14096                     {
14097                         (*values)[i][mapping][k].d = *(double *)
14098                                                      ((char *)data->values + size *
14099                                                      (i * i_step + j *
14100                                                       (*n_values_per_frame) + k));
14101                     }
14102                 }
14103             }
14104         }
14105     }
14106     else
14107     {
14108         if(*(values[0]) == 0)
14109         {
14110             if(tng_data_values_alloc(tng_data, values[0], *n_frames,
14111                                      *n_values_per_frame,
14112                                      *type) != TNG_SUCCESS)
14113             {
14114                 return(TNG_CRITICAL);
14115             }
14116         }
14117         switch(*type)
14118         {
14119         case TNG_CHAR_DATA:
14120             for(i = 0; i < *n_frames; i++)
14121             {
14122                 for(j = 0; j < *n_values_per_frame; j++)
14123                 {
14124                     len = strlen(data->strings[0][i][j]) + 1;
14125                     (*values)[0][i][j].c = malloc(len);
14126                     strncpy((*values)[0][i][j].c, data->strings[0][i][j], len);
14127                 }
14128             }
14129             break;
14130         case TNG_INT_DATA:
14131             size = sizeof(int);
14132             for(i = 0; i < *n_frames; i++)
14133             {
14134                 for(j = 0; j < *n_values_per_frame; j++)
14135                 {
14136                     (*values)[0][i][j].i = *(int *)((char *)data->values + size *
14137                                                     (i*(*n_values_per_frame) + j));
14138                 }
14139             }
14140             break;
14141         case TNG_FLOAT_DATA:
14142             size = sizeof(float);
14143             for(i = 0; i < *n_frames; i++)
14144             {
14145                 for(j = 0; j < *n_values_per_frame; j++)
14146                 {
14147                     (*values)[0][i][j].f = *(float *)((char *)data->values + size *
14148                                                    (i*(*n_values_per_frame) + j));
14149                 }
14150             }
14151             break;
14152         case TNG_DOUBLE_DATA:
14153         default:
14154             size = sizeof(double);
14155             for(i = 0; i < *n_frames; i++)
14156             {
14157                 for(j = 0; j < *n_values_per_frame; j++)
14158                 {
14159                     (*values)[0][i][j].d = *(double *)((char *)data->values + size *
14160                                                        (i*(*n_values_per_frame) + j));
14161                 }
14162             }
14163         }
14164     }
14165
14166     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14167
14168     return(TNG_SUCCESS);
14169 }
14170
14171 tng_function_status DECLSPECDLLEXPORT tng_data_get
14172                 (const tng_trajectory_t tng_data,
14173                  const int64_t block_id,
14174                  union data_values ***values,
14175                  int64_t *n_frames,
14176                  int64_t *n_values_per_frame,
14177                  char *type)
14178 {
14179     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14180     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14181     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14182     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14183
14184     return(tng_gen_data_get(tng_data, block_id, TNG_FALSE, &values, n_frames, 0,
14185                             n_values_per_frame, type));
14186 }
14187
14188 static tng_function_status tng_gen_data_vector_get
14189                 (const tng_trajectory_t tng_data,
14190                  const int64_t block_id,
14191                  const tng_bool is_particle_data,
14192                  void **values,
14193                  int64_t *n_frames,
14194                  int64_t *stride_length,
14195                  int64_t *n_particles,
14196                  int64_t *n_values_per_frame,
14197                  char *type)
14198 {
14199     int64_t i, j, mapping, file_pos, i_step, full_data_len, n_frames_div;
14200     int64_t block_index;
14201     int size;
14202     tng_data_t data;
14203     tng_trajectory_frame_set_t frame_set;
14204     tng_gen_block_t block;
14205     void *temp;
14206     char block_type_flag;
14207     tng_function_status stat;
14208
14209     frame_set = &tng_data->current_trajectory_frame_set;
14210
14211     block_index = -1;
14212     data = 0;
14213
14214     if(is_particle_data == TNG_TRUE)
14215     {
14216         stat = tng_particle_data_find(tng_data, block_id, &data);
14217     }
14218     else
14219     {
14220         stat = tng_data_find(tng_data, block_id, &data);
14221     }
14222
14223     if(stat != TNG_SUCCESS)
14224     {
14225         tng_block_init(&block);
14226         file_pos = ftello(tng_data->input_file);
14227         /* Read all blocks until next frame set block */
14228         stat = tng_block_header_read(tng_data, block);
14229         while(file_pos < tng_data->input_file_len &&
14230                 stat != TNG_CRITICAL &&
14231                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14232                 block->id != -1)
14233         {
14234             /* Use hash by default */
14235             stat = tng_block_read_next(tng_data, block,
14236                                     TNG_USE_HASH);
14237             if(stat != TNG_CRITICAL)
14238             {
14239                 file_pos = ftello(tng_data->input_file);
14240                 if(file_pos < tng_data->input_file_len)
14241                 {
14242                     stat = tng_block_header_read(tng_data, block);
14243                 }
14244             }
14245         }
14246         tng_block_destroy(&block);
14247         if(stat == TNG_CRITICAL)
14248         {
14249             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14250                     file_pos, __FILE__, __LINE__);
14251             return(stat);
14252         }
14253
14254         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
14255         {
14256             data = &frame_set->tr_particle_data[i];
14257             if(data->block_id == block_id)
14258             {
14259                 block_index = i;
14260                 break;
14261             }
14262         }
14263         if(block_index < 0)
14264         {
14265             return(TNG_FAILURE);
14266         }
14267     }
14268
14269     if(is_particle_data == TNG_TRUE)
14270     {
14271         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
14272         {
14273             block_type_flag = TNG_TRAJECTORY_BLOCK;
14274         }
14275         else
14276         {
14277             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
14278         }
14279
14280        if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
14281           tng_data->var_num_atoms_flag)
14282         {
14283             *n_particles = frame_set->n_particles;
14284         }
14285         else
14286         {
14287             *n_particles = tng_data->n_particles;
14288         }
14289     }
14290
14291     *type = data->datatype;
14292
14293     switch(*type)
14294     {
14295     case TNG_CHAR_DATA:
14296         return(TNG_FAILURE);
14297     case TNG_INT_DATA:
14298         size = sizeof(int64_t);
14299         break;
14300     case TNG_FLOAT_DATA:
14301         size = sizeof(float);
14302         break;
14303     case TNG_DOUBLE_DATA:
14304     default:
14305         size = sizeof(double);
14306     }
14307
14308     *n_frames = tng_max_i64(1, data->n_frames);
14309     *n_values_per_frame = data->n_values_per_frame;
14310     *stride_length = data->stride_length;
14311
14312     n_frames_div = (*n_frames % *stride_length) ?
14313                    *n_frames / *stride_length + 1:
14314                    *n_frames / *stride_length;
14315
14316     full_data_len = n_frames_div * size *
14317                 (*n_values_per_frame);
14318     if(is_particle_data == TNG_TRUE)
14319     {
14320         full_data_len *= (*n_particles);
14321     }
14322
14323     temp = realloc(*values, full_data_len);
14324     if(!temp)
14325     {
14326         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14327                full_data_len, __FILE__, __LINE__);
14328         free(*values);
14329         *values = 0;
14330         return(TNG_CRITICAL);
14331     }
14332
14333     *values = temp;
14334
14335     if(is_particle_data != TNG_TRUE || frame_set->n_mapping_blocks <= 0)
14336     {
14337         memcpy(*values, data->values, full_data_len);
14338     }
14339     else
14340     {
14341         i_step = (*n_particles) * (*n_values_per_frame);
14342         for(i = 0; i < *n_frames; i++)
14343         {
14344             for(j = 0; j < *n_particles; j++)
14345             {
14346                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14347                 memcpy(((char *)*values) + size * (i * i_step + mapping *
14348                        (*n_values_per_frame)),
14349                        (char *)data->values + size *
14350                        (i * i_step + j * (*n_values_per_frame)),
14351                        size * (*n_values_per_frame));
14352             }
14353         }
14354     }
14355
14356     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14357
14358     return(TNG_SUCCESS);
14359 }
14360
14361 tng_function_status DECLSPECDLLEXPORT tng_data_vector_get
14362                 (const tng_trajectory_t tng_data,
14363                  const int64_t block_id,
14364                  void **values,
14365                  int64_t *n_frames,
14366                  int64_t *stride_length,
14367                  int64_t *n_values_per_frame,
14368                  char *type)
14369 {
14370     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14371     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14372     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14373     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14374     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14375
14376     return(tng_gen_data_vector_get(tng_data, block_id, TNG_FALSE, values,
14377                                    n_frames, stride_length, 0, n_values_per_frame,
14378                                    type));
14379 }
14380
14381 static tng_function_status tng_gen_data_interval_get
14382                 (const tng_trajectory_t tng_data,
14383                  const int64_t block_id,
14384                  const tng_bool is_particle_data,
14385                  const int64_t start_frame_nr,
14386                  const int64_t end_frame_nr,
14387                  const char hash_mode,
14388                  union data_values ****values,
14389                  int64_t *n_particles,
14390                  int64_t *n_values_per_frame,
14391                  char *type)
14392 {
14393     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
14394     int64_t first_frame, block_index;
14395     int size;
14396     size_t len;
14397     tng_data_t data;
14398     tng_trajectory_frame_set_t frame_set;
14399     tng_gen_block_t block;
14400     char block_type_flag;
14401     tng_function_status stat;
14402
14403     block_index = -1;
14404
14405     frame_set = &tng_data->current_trajectory_frame_set;
14406     first_frame = frame_set->first_frame;
14407
14408     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14409     if(stat != TNG_SUCCESS)
14410     {
14411         return(stat);
14412     }
14413
14414     /* Do not re-read the frame set. */
14415     if((is_particle_data == TNG_TRUE &&
14416        (first_frame != frame_set->first_frame ||
14417         frame_set->n_particle_data_blocks <= 0)) ||
14418        (is_particle_data == TNG_FALSE &&
14419        (first_frame != frame_set->first_frame ||
14420         frame_set->n_data_blocks <= 0)))
14421     {
14422         tng_block_init(&block);
14423         file_pos = ftello(tng_data->input_file);
14424         /* Read all blocks until next frame set block */
14425         stat = tng_block_header_read(tng_data, block);
14426         while(file_pos < tng_data->input_file_len &&
14427                 stat != TNG_CRITICAL &&
14428                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14429                 block->id != -1)
14430         {
14431             stat = tng_block_read_next(tng_data, block,
14432                                     hash_mode);
14433             if(stat != TNG_CRITICAL)
14434             {
14435                 file_pos = ftello(tng_data->input_file);
14436                 if(file_pos < tng_data->input_file_len)
14437                 {
14438                     stat = tng_block_header_read(tng_data, block);
14439                 }
14440             }
14441         }
14442         tng_block_destroy(&block);
14443         if(stat == TNG_CRITICAL)
14444         {
14445             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14446                     file_pos, __FILE__, __LINE__);
14447             return(stat);
14448         }
14449     }
14450
14451     /* See if there is already a data block of this ID.
14452      * Start checking the last read frame set */
14453     if(is_particle_data == TNG_TRUE)
14454     {
14455         for(i = frame_set->n_particle_data_blocks; i-- ;)
14456         {
14457             data = &frame_set->tr_particle_data[i];
14458             if(data->block_id == block_id)
14459             {
14460                 block_index = i;
14461                 block_type_flag = TNG_TRAJECTORY_BLOCK;
14462                 break;
14463             }
14464         }
14465     }
14466     else
14467     {
14468         for(i = 0; i < frame_set->n_data_blocks; i++)
14469         {
14470             data = &frame_set->tr_data[i];
14471             if(data->block_id == block_id)
14472             {
14473                 block_index = i;
14474                 break;
14475             }
14476         }
14477     }
14478
14479     if(block_index < 0)
14480     {
14481         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
14482                 block_id, __FILE__, __LINE__);
14483         return(TNG_FAILURE);
14484     }
14485
14486     if(is_particle_data ==  TNG_TRUE)
14487     {
14488         if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
14489            tng_data->var_num_atoms_flag)
14490         {
14491             *n_particles = frame_set->n_particles;
14492         }
14493         else
14494         {
14495             *n_particles = tng_data->n_particles;
14496         }
14497     }
14498
14499     n_frames = end_frame_nr - start_frame_nr + 1;
14500     *n_values_per_frame = data->n_values_per_frame;
14501     *type = data->datatype;
14502
14503     if(*values == 0)
14504     {
14505         if(is_particle_data == TNG_TRUE)
14506         {
14507             if(tng_particle_data_values_alloc(tng_data, values, n_frames,
14508                                              *n_particles, *n_values_per_frame,
14509                                              *type) != TNG_SUCCESS)
14510             {
14511                 return(TNG_CRITICAL);
14512             }
14513         }
14514         else
14515         {
14516             if(tng_data_values_alloc(tng_data, *values, n_frames,
14517                                      *n_values_per_frame,
14518                                      *type) != TNG_SUCCESS)
14519             {
14520                 return(TNG_CRITICAL);
14521             }
14522         }
14523     }
14524
14525     current_frame_pos = start_frame_nr - frame_set->first_frame;
14526
14527     if(is_particle_data == TNG_TRUE)
14528     {
14529         i_step = (*n_particles) * (*n_values_per_frame);
14530     }
14531     else
14532     {
14533         i_step = (*n_values_per_frame);
14534     }
14535     /* It's not very elegant to reuse so much of the code in the different case
14536      * statements, but it's unnecessarily slow to have the switch-case block
14537      * inside the for loops. */
14538     switch(*type)
14539     {
14540     case TNG_CHAR_DATA:
14541         for(i=0; i<n_frames; i++)
14542         {
14543             if(current_frame_pos == frame_set->n_frames)
14544             {
14545                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14546                 if(stat != TNG_SUCCESS)
14547                 {
14548                     return(stat);
14549                 }
14550                 current_frame_pos = 0;
14551             }
14552             if(is_particle_data == TNG_TRUE)
14553             {
14554                 for(j = 0; j < *n_particles; j++)
14555                 {
14556                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14557                     for(k = 0; k < *n_values_per_frame; k++)
14558                     {
14559                         len = strlen(data->strings[current_frame_pos][j][k]) + 1;
14560                         (*values)[i][mapping][k].c = malloc(len);
14561                         strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
14562                     }
14563                 }
14564             }
14565             else
14566             {
14567                 for(j = 0; j < *n_values_per_frame; j++)
14568                 {
14569                     len = strlen(data->strings[0][current_frame_pos][j]) + 1;
14570                     (*values)[0][i][j].c = malloc(len);
14571                     strncpy((*values)[0][i][j].c, data->strings[0][current_frame_pos][j], len);
14572                 }
14573             }
14574             current_frame_pos++;
14575         }
14576         break;
14577     case TNG_INT_DATA:
14578         size = sizeof(int);
14579         for(i=0; i<n_frames; i++)
14580         {
14581             if(current_frame_pos == frame_set->n_frames)
14582             {
14583                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14584                 if(stat != TNG_SUCCESS)
14585                 {
14586                     return(stat);
14587                 }
14588                 current_frame_pos = 0;
14589             }
14590             if(is_particle_data == TNG_TRUE)
14591             {
14592                 for(j = 0; j < *n_particles; j++)
14593                 {
14594                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14595                     for(k = 0; k < *n_values_per_frame; k++)
14596                     {
14597                         (*values)[i][mapping][k].i = *(int *)
14598                                                      ((char *)data->values + size *
14599                                                       (current_frame_pos *
14600                                                        i_step + j *
14601                                                        (*n_values_per_frame) + k));
14602                     }
14603                 }
14604                 current_frame_pos++;
14605             }
14606             else
14607             {
14608                 for(j = 0; j < *n_values_per_frame; j++)
14609                 {
14610                     (*values)[0][i][j].i = *(int *)((char *)data->values + size *
14611                                                 (current_frame_pos *
14612                                                  i_step + j));
14613                 }
14614             }
14615         }
14616         break;
14617     case TNG_FLOAT_DATA:
14618         size = sizeof(float);
14619         for(i=0; i<n_frames; i++)
14620         {
14621             if(current_frame_pos == frame_set->n_frames)
14622             {
14623                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14624                 if(stat != TNG_SUCCESS)
14625                 {
14626                     return(stat);
14627                 }
14628                 current_frame_pos = 0;
14629             }
14630             if(is_particle_data == TNG_TRUE)
14631             {
14632                 for(j=0; j<*n_particles; j++)
14633                 {
14634                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14635                     for(k=0; k<*n_values_per_frame; k++)
14636                     {
14637                         (*values)[i][mapping][k].f = *(float *)
14638                                                      ((char *)data->values + size *
14639                                                       (current_frame_pos *
14640                                                        i_step + j *
14641                                                        (*n_values_per_frame) + k));
14642                     }
14643                 }
14644             }
14645             else
14646             {
14647                 for(j = 0; j < *n_values_per_frame; j++)
14648                 {
14649                     (*values)[0][i][j].f = *(float *)((char *)data->values + size *
14650                                                    (current_frame_pos *
14651                                                     i_step + j));
14652                 }
14653             }
14654             current_frame_pos++;
14655         }
14656         break;
14657     case TNG_DOUBLE_DATA:
14658     default:
14659         size = sizeof(double);
14660         for(i=0; i<n_frames; i++)
14661         {
14662             if(current_frame_pos == frame_set->n_frames)
14663             {
14664                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14665                 if(stat != TNG_SUCCESS)
14666                 {
14667                     return(stat);
14668                 }
14669                 current_frame_pos = 0;
14670             }
14671             if(is_particle_data == TNG_TRUE)
14672             {
14673                 for(j=0; j<*n_particles; j++)
14674                 {
14675                     tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14676                     for(k=0; k<*n_values_per_frame; k++)
14677                     {
14678                         (*values)[i][mapping][k].d = *(double *)
14679                                                      ((char *)data->values + size *
14680                                                       (current_frame_pos *
14681                                                        i_step + j *
14682                                                        (*n_values_per_frame) + k));
14683                     }
14684                 }
14685             }
14686             else
14687             {
14688                 for(j = 0; j < *n_values_per_frame; j++)
14689                 {
14690                     (*values)[0][i][j].d = *(double *)((char *)data->values + size *
14691                                                     (current_frame_pos *
14692                                                      i_step + j));
14693                 }
14694             }
14695             current_frame_pos++;
14696         }
14697     }
14698
14699     data->last_retrieved_frame = end_frame_nr;
14700
14701     return(TNG_SUCCESS);
14702 }
14703
14704 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
14705                 (const tng_trajectory_t tng_data,
14706                  const int64_t block_id,
14707                  const int64_t start_frame_nr,
14708                  const int64_t end_frame_nr,
14709                  const char hash_mode,
14710                  union data_values ***values,
14711                  int64_t *n_values_per_frame,
14712                  char *type)
14713 {
14714     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14715     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
14716     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14717     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14718
14719     return(tng_gen_data_interval_get(tng_data, block_id, TNG_FALSE, start_frame_nr,
14720                                      end_frame_nr, hash_mode, &values, 0,
14721                                      n_values_per_frame, type));
14722 }
14723
14724 static tng_function_status tng_gen_data_vector_interval_get
14725                 (const tng_trajectory_t tng_data,
14726                  const int64_t block_id,
14727                  const tng_bool is_particle_data,
14728                  const int64_t start_frame_nr,
14729                  const int64_t end_frame_nr,
14730                  const char hash_mode,
14731                  void **values,
14732                  int64_t *n_particles,
14733                  int64_t *stride_length,
14734                  int64_t *n_values_per_frame,
14735                  char *type)
14736 {
14737     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
14738     int64_t file_pos, current_frame_pos, last_frame_pos, full_data_len, frame_size;
14739     int size;
14740     tng_trajectory_frame_set_t frame_set;
14741     tng_data_t data;
14742     tng_gen_block_t block;
14743     void *current_values = 0, *temp;
14744     tng_function_status stat;
14745
14746     frame_set = &tng_data->current_trajectory_frame_set;
14747     first_frame = frame_set->first_frame;
14748
14749     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14750     if(stat != TNG_SUCCESS)
14751     {
14752         return(stat);
14753     }
14754
14755     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
14756     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
14757     if(is_particle_data == TNG_TRUE)
14758     {
14759         stat = tng_particle_data_find(tng_data, block_id, &data);
14760     }
14761     else
14762     {
14763         stat = tng_data_find(tng_data, block_id, &data);
14764     }
14765
14766     if(first_frame != frame_set->first_frame ||
14767        stat != TNG_SUCCESS)
14768     {
14769         tng_block_init(&block);
14770         if(stat != TNG_SUCCESS)
14771         {
14772             fseeko(tng_data->input_file,
14773                   tng_data->current_trajectory_frame_set_input_file_pos,
14774                   SEEK_SET);
14775             stat = tng_block_header_read(tng_data, block);
14776             if(stat != TNG_SUCCESS)
14777             {
14778                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
14779                         __FILE__, __LINE__);
14780                 return(stat);
14781             }
14782
14783             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
14784         }
14785         file_pos = ftello(tng_data->input_file);
14786         /* Read until next frame set block */
14787         stat = tng_block_header_read(tng_data, block);
14788         while(file_pos < tng_data->input_file_len &&
14789             stat != TNG_CRITICAL &&
14790             block->id != TNG_TRAJECTORY_FRAME_SET &&
14791             block->id != -1)
14792         {
14793             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
14794             {
14795                 stat = tng_block_read_next(tng_data, block,
14796                                         hash_mode);
14797                 if(stat != TNG_CRITICAL)
14798                 {
14799                     file_pos = ftello(tng_data->input_file);
14800                     if(file_pos < tng_data->input_file_len)
14801                     {
14802                         stat = tng_block_header_read(tng_data, block);
14803                     }
14804                 }
14805             }
14806             else
14807             {
14808                 file_pos += block->block_contents_size + block->header_contents_size;
14809                 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
14810                 if(file_pos < tng_data->input_file_len)
14811                 {
14812                     stat = tng_block_header_read(tng_data, block);
14813                 }
14814             }
14815         }
14816         tng_block_destroy(&block);
14817         if(stat == TNG_CRITICAL)
14818         {
14819             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14820                     file_pos, __FILE__, __LINE__);
14821             return(stat);
14822         }
14823     }
14824     if(is_particle_data == TNG_TRUE)
14825     {
14826         stat = tng_particle_data_find(tng_data, block_id, &data);
14827     }
14828     else
14829     {
14830         stat = tng_data_find(tng_data, block_id, &data);
14831     }
14832     if(stat != TNG_SUCCESS)
14833     {
14834         return(stat);
14835     }
14836
14837     stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data,
14838                                    &current_values, &n_frames, stride_length,
14839                                    n_particles, n_values_per_frame, type);
14840
14841     if(stat != TNG_SUCCESS || (is_particle_data && *n_particles == 0))
14842     {
14843         if(current_values)
14844         {
14845             free(current_values);
14846         }
14847         return(stat);
14848     }
14849
14850     if(n_frames == 1 && n_frames < frame_set->n_frames)
14851     {
14852         tot_n_frames = 1;
14853     }
14854     else
14855     {
14856         tot_n_frames = end_frame_nr - start_frame_nr + 1;
14857     }
14858
14859     switch(*type)
14860     {
14861     case TNG_CHAR_DATA:
14862         return(TNG_FAILURE);
14863     case TNG_INT_DATA:
14864         size = sizeof(int64_t);
14865         break;
14866     case TNG_FLOAT_DATA:
14867         size = sizeof(float);
14868         break;
14869     case TNG_DOUBLE_DATA:
14870     default:
14871         size = sizeof(double);
14872     }
14873
14874     n_frames_div = (tot_n_frames % *stride_length) ?
14875                  tot_n_frames / *stride_length + 1:
14876                  tot_n_frames / *stride_length;
14877
14878     full_data_len = n_frames_div * size * (*n_values_per_frame);
14879     if(is_particle_data)
14880     {
14881         full_data_len *= (*n_particles);
14882     }
14883
14884     temp = realloc(*values, full_data_len);
14885     if(!temp)
14886     {
14887         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14888                full_data_len, __FILE__, __LINE__);
14889         free(*values);
14890         *values = 0;
14891         return(TNG_CRITICAL);
14892     }
14893
14894     *values = temp;
14895
14896     if( n_frames == 1 && n_frames < frame_set->n_frames)
14897     {
14898         if(is_particle_data)
14899         {
14900             memcpy(*values, current_values, size * (*n_particles) *
14901                    (*n_values_per_frame));
14902         }
14903         else
14904         {
14905             memcpy(*values, current_values, size * (*n_values_per_frame));
14906         }
14907     }
14908     else
14909     {
14910         current_frame_pos = start_frame_nr - frame_set->first_frame;
14911
14912         frame_size = size * (*n_values_per_frame);
14913         if(is_particle_data)
14914         {
14915             frame_size *= (*n_particles);
14916         }
14917
14918         last_frame_pos = tng_min_i64(n_frames,
14919                                      end_frame_nr - start_frame_nr);
14920
14921         n_frames_div = current_frame_pos / *stride_length;
14922         n_frames_div_2 = (last_frame_pos % *stride_length) ?
14923                        last_frame_pos / *stride_length + 1:
14924                        last_frame_pos / *stride_length;
14925         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
14926
14927         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
14928                n_frames_div_2 * frame_size);
14929
14930         current_frame_pos += n_frames - current_frame_pos;
14931
14932         while(current_frame_pos <= end_frame_nr - start_frame_nr)
14933         {
14934             stat = tng_frame_set_read_next(tng_data, hash_mode);
14935             if(stat != TNG_SUCCESS)
14936             {
14937                 if(current_values)
14938                 {
14939                     free(current_values);
14940                 }
14941                 free(*values);
14942                 *values = 0;
14943                 return(stat);
14944             }
14945
14946             stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data,
14947                                            &current_values, &n_frames,
14948                                            stride_length, n_particles,
14949                                            n_values_per_frame, type);
14950
14951             if(stat != TNG_SUCCESS)
14952             {
14953                 if(current_values)
14954                 {
14955                     free(current_values);
14956                 }
14957                 free(*values);
14958                 *values = 0;
14959                 return(stat);
14960             }
14961
14962             last_frame_pos = tng_min_i64(n_frames,
14963                                          end_frame_nr - current_frame_pos);
14964
14965             n_frames_div = current_frame_pos / *stride_length;
14966             n_frames_div_2 = (last_frame_pos % *stride_length) ?
14967                            last_frame_pos / *stride_length + 1:
14968                            last_frame_pos / *stride_length;
14969             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
14970
14971             memcpy(((char *)*values) + n_frames_div * frame_size,
14972                    current_values,
14973                    n_frames_div_2 * frame_size);
14974
14975             current_frame_pos += n_frames;
14976         }
14977     }
14978
14979     if(current_values)
14980     {
14981         free(current_values);
14982     }
14983
14984     data->last_retrieved_frame = end_frame_nr;
14985
14986     return(TNG_SUCCESS);
14987 }
14988
14989
14990 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
14991                 (const tng_trajectory_t tng_data,
14992                  const int64_t block_id,
14993                  const int64_t start_frame_nr,
14994                  const int64_t end_frame_nr,
14995                  const char hash_mode,
14996                  void **values,
14997                  int64_t *stride_length,
14998                  int64_t *n_values_per_frame,
14999                  char *type)
15000 {
15001     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15002     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
15003     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15004     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15005     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15006
15007     return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_FALSE,
15008                                             start_frame_nr, end_frame_nr,
15009                                             hash_mode, values, 0, stride_length,
15010                                             n_values_per_frame, type));
15011 }
15012
15013 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15014                 (const tng_trajectory_t tng_data,
15015                  const int64_t block_id,
15016                  union data_values ****values,
15017                  int64_t *n_frames,
15018                  int64_t *n_particles,
15019                  int64_t *n_values_per_frame,
15020                  char *type)
15021 {
15022     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15023     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15024     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15025     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15026     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15027
15028     return(tng_gen_data_get(tng_data, block_id, TNG_TRUE, values, n_frames, n_particles,
15029                             n_values_per_frame, type));
15030 }
15031
15032 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
15033                 (const tng_trajectory_t tng_data,
15034                  const int64_t block_id,
15035                  void **values,
15036                  int64_t *n_frames,
15037                  int64_t *stride_length,
15038                  int64_t *n_particles,
15039                  int64_t *n_values_per_frame,
15040                  char *type)
15041 {
15042     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15043     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15044     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15045     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15046     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15047
15048     return(tng_gen_data_vector_get(tng_data, block_id, TNG_TRUE, values,
15049                                    n_frames, stride_length, n_particles,
15050                                    n_values_per_frame, type));
15051 }
15052
15053 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
15054                 (const tng_trajectory_t tng_data,
15055                  const int64_t block_id,
15056                  const int64_t start_frame_nr,
15057                  const int64_t end_frame_nr,
15058                  const char hash_mode,
15059                  union data_values ****values,
15060                  int64_t *n_particles,
15061                  int64_t *n_values_per_frame,
15062                  char *type)
15063 {
15064     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15065     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15066     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15067     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15068     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15069
15070     return(tng_gen_data_interval_get(tng_data, block_id, TNG_TRUE, start_frame_nr,
15071                                      end_frame_nr, hash_mode, values, n_particles,
15072                                      n_values_per_frame, type));
15073 }
15074
15075 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
15076                 (const tng_trajectory_t tng_data,
15077                  const int64_t block_id,
15078                  const int64_t start_frame_nr,
15079                  const int64_t end_frame_nr,
15080                  const char hash_mode,
15081                  void **values,
15082                  int64_t *n_particles,
15083                  int64_t *stride_length,
15084                  int64_t *n_values_per_frame,
15085                  char *type)
15086 {
15087     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15088     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15089     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15090     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15091     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15092     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15093
15094     return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_TRUE,
15095                                             start_frame_nr, end_frame_nr,
15096                                             hash_mode, values, n_particles,
15097                                             stride_length, n_values_per_frame,
15098                                             type));
15099 }
15100
15101 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
15102                 (const tng_trajectory_t tng_data,
15103                  const int64_t block_id,
15104                  int64_t frame,
15105                  int64_t *stride_length)
15106 {
15107     tng_function_status stat;
15108     tng_data_t data;
15109     int64_t orig_file_pos, file_pos;
15110     int is_particle_data;
15111
15112     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
15113     {
15114         frame = 0;
15115     }
15116
15117     if(frame >= 0)
15118     {
15119         stat = tng_frame_set_of_frame_find(tng_data, frame);
15120         if(stat != TNG_SUCCESS)
15121         {
15122             return(stat);
15123         }
15124     }
15125     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
15126     stat = tng_data_find(tng_data, block_id, &data);
15127     if(stat != TNG_SUCCESS)
15128     {
15129         stat = tng_particle_data_find(tng_data, block_id, &data);
15130         if(stat != TNG_SUCCESS)
15131         {
15132             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15133             /* If no specific frame was required read until this data block is found */
15134             if(frame < 0)
15135             {
15136                 file_pos = ftello(tng_data->input_file);
15137                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15138                 {
15139                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15140                     file_pos = ftello(tng_data->input_file);
15141                 }
15142             }
15143             if(stat != TNG_SUCCESS)
15144             {
15145                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15146
15147                 return(stat);
15148             }
15149             stat = tng_data_find(tng_data, block_id, &data);
15150             if(stat != TNG_SUCCESS)
15151             {
15152                 stat = tng_particle_data_find(tng_data, block_id, &data);
15153                 if(stat != TNG_SUCCESS)
15154                 {
15155                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15156
15157                     return(stat);
15158                 }
15159                 else
15160                 {
15161                     is_particle_data = 1;
15162                 }
15163             }
15164             else
15165             {
15166                 is_particle_data = 0;
15167             }
15168         }
15169         else
15170         {
15171             is_particle_data = 1;
15172         }
15173     }
15174     else
15175     {
15176         is_particle_data = 0;
15177     }
15178     if(is_particle_data)
15179     {
15180         *stride_length = data->stride_length;
15181     }
15182     else
15183     {
15184         *stride_length = data->stride_length;
15185     }
15186     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15187
15188     return(TNG_SUCCESS);
15189 }
15190
15191 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
15192                 (const tng_trajectory_t tng_data,
15193                  char *time)
15194 {
15195     struct tm *time_data;
15196     time_t secs;
15197
15198     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15199     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
15200
15201     secs = tng_data->time;
15202
15203     time_data = localtime(&secs); /* Returns a statically allocated variable. */
15204     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
15205              "%4d-%02d-%02d %02d:%02d:%02d",
15206              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
15207              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
15208
15209     return(TNG_SUCCESS);
15210 }
15211
15212
15213 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
15214                 (const char *filename,
15215                  const char mode,
15216                  tng_trajectory_t *tng_data_p)
15217 {
15218     tng_function_status stat;
15219
15220     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
15221
15222     if(mode != 'r' && mode != 'w' && mode != 'a')
15223     {
15224         return(TNG_FAILURE);
15225     }
15226
15227     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
15228     {
15229         tng_trajectory_destroy(tng_data_p);
15230         return(TNG_CRITICAL);
15231     }
15232
15233     if(mode == 'w')
15234     {
15235         stat = tng_output_file_set(*tng_data_p, filename);
15236         return(stat);
15237     }
15238     tng_input_file_set(*tng_data_p, filename);
15239
15240     /* Read the file headers */
15241     tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
15242
15243     stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
15244
15245     if(stat != TNG_SUCCESS)
15246     {
15247         return(stat);
15248     }
15249
15250     if(mode == 'a')
15251     {
15252         if((*tng_data_p)->output_file)
15253         {
15254             fclose((*tng_data_p)->output_file);
15255         }
15256         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
15257         fseeko((*tng_data_p)->input_file,
15258                 (*tng_data_p)->last_trajectory_frame_set_input_file_pos,
15259                 SEEK_SET);
15260
15261         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
15262         if(stat != TNG_SUCCESS)
15263         {
15264             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
15265                    __FILE__, __LINE__);
15266         }
15267         (*tng_data_p)->output_file = 0;
15268
15269         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
15270         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
15271         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
15272         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
15273         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
15274         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
15275         if((*tng_data_p)->input_file)
15276         {
15277             fclose((*tng_data_p)->input_file);
15278             (*tng_data_p)->input_file = 0;
15279         }
15280         if((*tng_data_p)->input_file_path)
15281         {
15282             free((*tng_data_p)->input_file_path);
15283             (*tng_data_p)->input_file_path = 0;
15284         }
15285         tng_output_append_file_set(*tng_data_p, filename);
15286
15287         fseeko((*tng_data_p)->output_file, 0, SEEK_END);
15288     }
15289
15290     return(stat);
15291 }
15292
15293 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
15294                 (tng_trajectory_t *tng_data_p)
15295 {
15296     tng_trajectory_frame_set_t frame_set;
15297
15298     if(tng_data_p == 0)
15299     {
15300         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
15301                __FILE__, __LINE__);
15302         return(TNG_FAILURE);
15303     }
15304
15305     if(*tng_data_p == 0)
15306     {
15307         return(TNG_SUCCESS);
15308     }
15309
15310     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
15311
15312     if(frame_set->n_unwritten_frames > 0)
15313     {
15314         frame_set->n_frames = frame_set->n_unwritten_frames;
15315         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
15316     }
15317
15318     return(tng_trajectory_destroy(tng_data_p));
15319 }
15320
15321 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
15322                 (const tng_trajectory_t tng_data,
15323                  const int64_t frame_nr,
15324                  double *time)
15325 {
15326     int64_t first_frame;
15327     tng_trajectory_frame_set_t frame_set;
15328     tng_function_status stat;
15329
15330     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15331     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
15332
15333     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
15334     if(stat != TNG_SUCCESS)
15335     {
15336         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
15337                frame_nr, __FILE__, __LINE__);
15338         return(stat);
15339     }
15340
15341     frame_set = &tng_data->current_trajectory_frame_set;
15342     first_frame = frame_set->first_frame;
15343
15344     if(tng_data->time_per_frame <= 0)
15345     {
15346         return(TNG_FAILURE);
15347     }
15348
15349     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
15350
15351     return(TNG_SUCCESS);
15352 }
15353
15354 /*
15355 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
15356                 (const tng_trajectory_t tng_data,
15357                  int64_t *n_mols,
15358                  int64_t **molecule_cnt_list,
15359                  tng_molecule_t *mols)
15360 {
15361     tng_trajectory_frame_set_t frame_set;
15362
15363     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15364     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
15365
15366     *n_mols = tng_data->n_molecules;
15367
15368     frame_set = &tng_data->current_trajectory_frame_set;
15369     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
15370     {
15371         *molecule_cnt_list = frame_set->molecule_cnt_list;
15372     }
15373     else
15374     {
15375         *molecule_cnt_list = tng_data->molecule_cnt_list;
15376     }
15377
15378     *mols = tng_data->molecules;
15379
15380     return(TNG_SUCCESS);
15381 }
15382 */
15383 /*
15384 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
15385                 (const tng_trajectory_t tng_data,
15386                  const char *name,
15387                  const int64_t cnt,
15388                  tng_molecule_t *mol)
15389 {
15390     tng_function_status stat;
15391
15392     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
15393     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
15394
15395     stat = tng_molecule_add(tng_data, name, mol);
15396     if(stat != TNG_SUCCESS)
15397     {
15398         return(stat);
15399     }
15400     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
15401
15402     return(stat);
15403 }
15404 */
15405 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
15406                 (const tng_trajectory_t tng_data,
15407                  const tng_molecule_t mol,
15408                  int64_t *n_particles,
15409                  char ***names,
15410                  char ***types,
15411                  char ***res_names,
15412                  int64_t **res_ids,
15413                  char ***chain_names,
15414                  int64_t **chain_ids)
15415 {
15416     tng_atom_t atom;
15417     tng_residue_t res;
15418     tng_chain_t chain;
15419     int64_t i;
15420     (void)tng_data;
15421
15422     *n_particles = mol->n_atoms;
15423
15424     *names = malloc(sizeof(char *) * *n_particles);
15425     *types = malloc(sizeof(char *) * *n_particles);
15426     *res_names = malloc(sizeof(char *) * *n_particles);
15427     *chain_names = malloc(sizeof(char *) * *n_particles);
15428     *res_ids = malloc(sizeof(int64_t) * *n_particles);
15429     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
15430
15431     for(i = 0; i < *n_particles; i++)
15432     {
15433         atom = &mol->atoms[i];
15434         res = atom->residue;
15435         chain = res->chain;
15436         (*names)[i] = malloc(strlen(atom->name));
15437         strcpy(*names[i], atom->name);
15438         (*types)[i] = malloc(strlen(atom->atom_type));
15439         strcpy(*types[i], atom->atom_type);
15440         (*res_names)[i] = malloc(strlen(res->name));
15441         strcpy(*res_names[i], res->name);
15442         (*chain_names)[i] = malloc(strlen(chain->name));
15443         strcpy(*chain_names[i], chain->name);
15444         (*res_ids)[i] = res->id;
15445         (*chain_ids)[i] = chain->id;
15446     }
15447
15448     return(TNG_SUCCESS);
15449 }
15450
15451 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
15452                 (const tng_trajectory_t tng_data,
15453                  const tng_molecule_t mol,
15454                  const int64_t n_particles,
15455                  const char **names,
15456                  const char **types,
15457                  const char **res_names,
15458                  const int64_t *res_ids,
15459                  const char **chain_names,
15460                  const int64_t *chain_ids)
15461 {
15462     int64_t i;
15463     tng_chain_t chain;
15464     tng_residue_t residue;
15465     tng_atom_t atom;
15466     tng_function_status stat;
15467
15468     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15469     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
15470     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
15471     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
15472     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
15473     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
15474     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
15475
15476     for(i = 0; i < n_particles; i++)
15477     {
15478         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
15479            &chain) == TNG_FAILURE)
15480         {
15481             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
15482                                           &chain);
15483             if(stat != TNG_SUCCESS)
15484             {
15485                 return(stat);
15486             }
15487         }
15488         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
15489            &residue) == TNG_FAILURE)
15490         {
15491             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
15492                                          &residue);
15493             if(stat != TNG_SUCCESS)
15494             {
15495                 return(stat);
15496             }
15497         }
15498         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
15499         if(stat != TNG_SUCCESS)
15500         {
15501             return(stat);
15502         }
15503     }
15504     return(TNG_SUCCESS);
15505 }
15506
15507 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
15508                 (const tng_trajectory_t tng_data,
15509                  float **positions, int64_t *stride_length)
15510 {
15511     int64_t n_frames, n_particles, n_values_per_frame;
15512     char type;
15513     tng_function_status stat;
15514
15515     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15516     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
15517     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15518
15519     stat = tng_num_frames_get(tng_data, &n_frames);
15520     if(stat != TNG_SUCCESS)
15521     {
15522         return(stat);
15523     }
15524
15525     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
15526                                                  0, n_frames - 1, TNG_USE_HASH,
15527                                                  (void **)positions,
15528                                                  &n_particles,
15529                                                  stride_length,
15530                                                  &n_values_per_frame,
15531                                                  &type);
15532
15533     return(stat);
15534 }
15535
15536 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
15537                 (const tng_trajectory_t tng_data,
15538                  float **velocities, int64_t *stride_length)
15539 {
15540     int64_t n_frames, n_particles, n_values_per_frame;
15541     char type;
15542     tng_function_status stat;
15543
15544     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15545     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
15546     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15547
15548     stat = tng_num_frames_get(tng_data, &n_frames);
15549     if(stat != TNG_SUCCESS)
15550     {
15551         return(stat);
15552     }
15553
15554     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
15555                                                  0, n_frames - 1, TNG_USE_HASH,
15556                                                  (void **)velocities,
15557                                                  &n_particles,
15558                                                  stride_length,
15559                                                  &n_values_per_frame,
15560                                                  &type);
15561
15562     return(stat);
15563 }
15564
15565 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
15566                 (const tng_trajectory_t tng_data,
15567                  float **forces, int64_t *stride_length)
15568 {
15569     int64_t n_frames, n_particles, n_values_per_frame;
15570     char type;
15571     tng_function_status stat;
15572
15573     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15574     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
15575     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15576
15577     stat = tng_num_frames_get(tng_data, &n_frames);
15578     if(stat != TNG_SUCCESS)
15579     {
15580         return(stat);
15581     }
15582
15583     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
15584                                                  0, n_frames - 1, TNG_USE_HASH,
15585                                                  (void **)forces,
15586                                                  &n_particles,
15587                                                  stride_length,
15588                                                  &n_values_per_frame,
15589                                                  &type);
15590
15591     return(stat);
15592 }
15593
15594 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
15595                 (const tng_trajectory_t tng_data,
15596                  float **box_shape,
15597                  int64_t *stride_length)
15598 {
15599     int64_t n_frames, n_values_per_frame;
15600     char type;
15601     tng_function_status stat;
15602
15603     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15604     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
15605     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15606
15607     stat = tng_num_frames_get(tng_data, &n_frames);
15608     if(stat != TNG_SUCCESS)
15609     {
15610         return(stat);
15611     }
15612
15613     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
15614                                         0, n_frames - 1, TNG_USE_HASH,
15615                                         (void **)box_shape,
15616                                         stride_length,
15617                                         &n_values_per_frame,
15618                                         &type);
15619
15620     return(stat);
15621 }
15622
15623 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
15624                 (const tng_trajectory_t tng_data,
15625                  const int64_t block_id,
15626                  void **values,
15627                  char *data_type,
15628                  int64_t *retrieved_frame_number,
15629                  double *retrieved_time)
15630 {
15631     tng_trajectory_frame_set_t frame_set;
15632     tng_data_t data = 0;
15633     tng_function_status stat;
15634     int size;
15635     int64_t i, full_data_len, n_particles;
15636     void *temp;
15637     int64_t file_pos;
15638
15639     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15640     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
15641     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
15642     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
15643     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
15644
15645     frame_set = &tng_data->current_trajectory_frame_set;
15646
15647     stat = tng_particle_data_find(tng_data, block_id, &data);
15648     if(stat != TNG_SUCCESS)
15649     {
15650         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15651         file_pos = ftello(tng_data->input_file);
15652         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15653         {
15654             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15655             file_pos = ftello(tng_data->input_file);
15656         }
15657         if(stat != TNG_SUCCESS)
15658         {
15659             return(stat);
15660         }
15661         stat = tng_particle_data_find(tng_data, block_id, &data);
15662         if(stat != TNG_SUCCESS)
15663         {
15664             return(stat);
15665         }
15666     }
15667     if(data->last_retrieved_frame < 0)
15668     {
15669         fseeko(tng_data->input_file,
15670               tng_data->first_trajectory_frame_set_input_file_pos,
15671               SEEK_SET);
15672         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
15673         if(stat != TNG_SUCCESS)
15674         {
15675             return(stat);
15676         }
15677         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15678         if(stat != TNG_SUCCESS)
15679         {
15680             return(stat);
15681         }
15682
15683         i = data->first_frame_with_data;
15684     }
15685     else
15686     {
15687         if(data->n_frames == 1 && frame_set->n_frames == 1)
15688         {
15689             i = data->last_retrieved_frame + 1;
15690         }
15691         else
15692         {
15693             i = data->last_retrieved_frame + data->stride_length;
15694         }
15695         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
15696         {
15697             stat = tng_frame_set_of_frame_find(tng_data, i);
15698             if(stat != TNG_SUCCESS)
15699             {
15700                 /* If the frame set search found the frame set after the starting
15701                  * frame set there is a gap in the frame sets. So, even if the frame
15702                  * was not found the next frame with data is still in the found
15703                  * frame set. */
15704                 if(stat == TNG_CRITICAL)
15705                 {
15706                     return(stat);
15707                 }
15708                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
15709                 {
15710                     return(TNG_FAILURE);
15711                 }
15712                 i = frame_set->first_frame;
15713             }
15714         }
15715         if(data->last_retrieved_frame < frame_set->first_frame)
15716         {
15717             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15718             if(stat != TNG_SUCCESS)
15719             {
15720                 return(stat);
15721             }
15722         }
15723     }
15724     data->last_retrieved_frame = i;
15725     *retrieved_frame_number = i;
15726     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
15727     {
15728         *retrieved_time = frame_set->first_frame_time +
15729                         (i - frame_set->first_frame) *
15730                         tng_data->time_per_frame;
15731     }
15732     else
15733     {
15734         *retrieved_time = 0;
15735     }
15736
15737     if(data->stride_length > 1)
15738     {
15739         i = (i - data->first_frame_with_data) / data->stride_length;
15740     }
15741     else
15742     {
15743         i = (i - frame_set->first_frame);
15744     }
15745
15746     tng_num_particles_get(tng_data, &n_particles);
15747
15748     *data_type = data->datatype;
15749
15750     switch(*data_type)
15751     {
15752     case TNG_CHAR_DATA:
15753         return(TNG_FAILURE);
15754     case TNG_INT_DATA:
15755         size = sizeof(int64_t);
15756         break;
15757     case TNG_FLOAT_DATA:
15758         size = sizeof(float);
15759         break;
15760     case TNG_DOUBLE_DATA:
15761     default:
15762         size = sizeof(double);
15763     }
15764
15765     full_data_len = size * n_particles * data->n_values_per_frame;
15766
15767 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", full_data_len = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
15768 //            i, full_data_len, size, n_particles, data->n_values_per_frame);
15769
15770     temp = realloc(*values, full_data_len);
15771     if(!temp)
15772     {
15773         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15774                full_data_len, __FILE__, __LINE__);
15775         free(*values);
15776         *values = 0;
15777         return(TNG_CRITICAL);
15778     }
15779
15780     *values = temp;
15781
15782     memcpy(*values, (char *)data->values + i * full_data_len, full_data_len);
15783
15784     return(TNG_SUCCESS);
15785 }
15786
15787 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
15788                 (const tng_trajectory_t tng_data,
15789                  const int64_t block_id,
15790                  void **values,
15791                  char *data_type,
15792                  int64_t *retrieved_frame_number,
15793                  double *retrieved_time)
15794 {
15795     tng_trajectory_frame_set_t frame_set;
15796     tng_data_t data = 0;
15797     tng_function_status stat;
15798     int size;
15799     int64_t i, full_data_len;
15800     void *temp;
15801     int64_t file_pos;
15802
15803     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15804     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
15805     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
15806     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
15807     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
15808
15809     frame_set = &tng_data->current_trajectory_frame_set;
15810
15811     stat = tng_data_find(tng_data, block_id, &data);
15812     if(stat != TNG_SUCCESS)
15813     {
15814         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15815         file_pos = ftello(tng_data->input_file);
15816         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15817         {
15818             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15819             file_pos = ftello(tng_data->input_file);
15820         }
15821         if(stat != TNG_SUCCESS)
15822         {
15823             return(stat);
15824         }
15825         stat = tng_data_find(tng_data, block_id, &data);
15826         if(stat != TNG_SUCCESS)
15827         {
15828             return(stat);
15829         }
15830     }
15831     if(data->last_retrieved_frame < 0)
15832     {
15833         fseeko(tng_data->input_file,
15834                 tng_data->first_trajectory_frame_set_input_file_pos,
15835                 SEEK_SET);
15836         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
15837         if(stat != TNG_SUCCESS)
15838         {
15839             return(stat);
15840         }
15841         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15842         if(stat != TNG_SUCCESS)
15843         {
15844             return(stat);
15845         }
15846
15847         i = data->first_frame_with_data;
15848     }
15849     else
15850     {
15851         if(data->n_frames == 1 && frame_set->n_frames == 1)
15852         {
15853             i = data->last_retrieved_frame + 1;
15854         }
15855         else
15856         {
15857             i = data->last_retrieved_frame + data->stride_length;
15858         }
15859         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
15860         {
15861             stat = tng_frame_set_of_frame_find(tng_data, i);
15862             if(stat != TNG_SUCCESS)
15863             {
15864                 /* If the frame set search found the frame set after the starting
15865                  * frame set there is a gap in the frame sets. So, even if the frame
15866                  * was not found the next frame with data is still in the found
15867                  * frame set. */
15868                 if(stat == TNG_CRITICAL)
15869                 {
15870                     return(stat);
15871                 }
15872                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
15873                 {
15874                     return(TNG_FAILURE);
15875                 }
15876                 i = frame_set->first_frame;
15877             }
15878         }
15879         if(data->last_retrieved_frame < frame_set->first_frame)
15880         {
15881             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15882             if(stat != TNG_SUCCESS)
15883             {
15884                 return(stat);
15885             }
15886         }
15887     }
15888     data->last_retrieved_frame = i;
15889     *retrieved_frame_number = i;
15890     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
15891     {
15892         *retrieved_time = frame_set->first_frame_time +
15893                         (i - frame_set->first_frame) *
15894                         tng_data->time_per_frame;
15895     }
15896     else
15897     {
15898         *retrieved_time = 0;
15899     }
15900
15901     if(data->stride_length > 1)
15902     {
15903         i = (i - data->first_frame_with_data) / data->stride_length;
15904     }
15905     else
15906     {
15907         i = (i - frame_set->first_frame);
15908     }
15909
15910     *data_type = data->datatype;
15911
15912     switch(*data_type)
15913     {
15914     case TNG_CHAR_DATA:
15915         return(TNG_FAILURE);
15916     case TNG_INT_DATA:
15917         size = sizeof(int64_t);
15918         break;
15919     case TNG_FLOAT_DATA:
15920         size = sizeof(float);
15921         break;
15922     case TNG_DOUBLE_DATA:
15923     default:
15924         size = sizeof(double);
15925     }
15926
15927     full_data_len = size * data->n_values_per_frame;
15928
15929     temp = realloc(*values, full_data_len);
15930     if(!temp)
15931     {
15932         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15933                full_data_len, __FILE__, __LINE__);
15934         free(*values);
15935         *values = 0;
15936         return(TNG_CRITICAL);
15937     }
15938
15939     *values = temp;
15940
15941     memcpy(*values, (char *)data->values + i * full_data_len, full_data_len);
15942
15943     return(TNG_SUCCESS);
15944 }
15945
15946 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
15947                 (const tng_trajectory_t tng_data,
15948                  const int64_t first_frame,
15949                  const int64_t last_frame,
15950                  float **positions,
15951                  int64_t *stride_length)
15952 {
15953     int64_t n_particles, n_values_per_frame;
15954     char type;
15955     tng_function_status stat;
15956
15957     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15958     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
15959     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
15960     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15961
15962     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
15963                                                  first_frame, last_frame,
15964                                                  TNG_USE_HASH,
15965                                                  (void **)positions,
15966                                                  &n_particles,
15967                                                  stride_length,
15968                                                  &n_values_per_frame,
15969                                                  &type);
15970
15971     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15972     {
15973         return(TNG_FAILURE);
15974     }
15975
15976     return(stat);
15977 }
15978
15979 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
15980                 (const tng_trajectory_t tng_data,
15981                  const int64_t first_frame,
15982                  const int64_t last_frame,
15983                  float **velocities,
15984                  int64_t *stride_length)
15985 {
15986     int64_t n_particles, n_values_per_frame;
15987     char type;
15988     tng_function_status stat;
15989
15990     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15991     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
15992     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
15993     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15994
15995     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
15996                                                  first_frame, last_frame,
15997                                                  TNG_USE_HASH,
15998                                                  (void **)velocities,
15999                                                  &n_particles,
16000                                                  stride_length,
16001                                                  &n_values_per_frame,
16002                                                  &type);
16003
16004     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16005     {
16006         return(TNG_FAILURE);
16007     }
16008
16009     return(stat);
16010 }
16011
16012 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
16013                 (const tng_trajectory_t tng_data,
16014                  const int64_t first_frame,
16015                  const int64_t last_frame,
16016                  float **forces,
16017                  int64_t *stride_length)
16018 {
16019     int64_t n_particles, n_values_per_frame;
16020     char type;
16021     tng_function_status stat;
16022
16023     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16024     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
16025     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16026     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16027
16028     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16029                                                  first_frame, last_frame,
16030                                                  TNG_USE_HASH,
16031                                                  (void **)forces,
16032                                                  &n_particles,
16033                                                  stride_length,
16034                                                  &n_values_per_frame,
16035                                                  &type);
16036
16037     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16038     {
16039         return(TNG_FAILURE);
16040     }
16041
16042     return(stat);
16043 }
16044
16045 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
16046                 (const tng_trajectory_t tng_data,
16047                  const int64_t first_frame,
16048                  const int64_t last_frame,
16049                  float **box_shape,
16050                  int64_t *stride_length)
16051 {
16052     int64_t n_values_per_frame;
16053     char type;
16054     tng_function_status stat;
16055
16056     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16057     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16058     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16059     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16060
16061     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16062                                         first_frame, last_frame,
16063                                         TNG_USE_HASH,
16064                                         (void **)box_shape,
16065                                         stride_length,
16066                                         &n_values_per_frame,
16067                                         &type);
16068
16069     if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16070     {
16071         return(TNG_FAILURE);
16072     }
16073
16074     return(stat);
16075 }
16076
16077 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
16078                 (const tng_trajectory_t tng_data,
16079                  const int64_t i,
16080                  const int64_t n_values_per_frame,
16081                  const int64_t block_id,
16082                  const char *block_name,
16083                  const char particle_dependency,
16084                  const char compression)
16085 {
16086     tng_trajectory_frame_set_t frame_set;
16087     tng_data_t data;
16088     int64_t n_particles, n_frames;
16089     tng_function_status stat;
16090
16091     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16092     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16093
16094     if(i <= 0)
16095     {
16096         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
16097                i, __FILE__, __LINE__);
16098         return(TNG_FAILURE);
16099     }
16100
16101     frame_set = &tng_data->current_trajectory_frame_set;
16102
16103     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16104     {
16105         n_frames = tng_data->frame_set_n_frames;
16106
16107         stat = tng_frame_set_new(tng_data, 0, n_frames);
16108         if(stat != TNG_SUCCESS)
16109         {
16110             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16111                 __LINE__);
16112             return(stat);
16113         }
16114     }
16115     else
16116     {
16117         n_frames = frame_set->n_frames;
16118     }
16119
16120     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16121     {
16122         tng_num_particles_get(tng_data, &n_particles);
16123         if(n_particles <= 0)
16124         {
16125             return(TNG_FAILURE);
16126         }
16127
16128         if(tng_particle_data_find(tng_data, block_id, &data)
16129         != TNG_SUCCESS)
16130         {
16131             stat = tng_particle_data_block_add(tng_data, block_id,
16132                                                block_name,
16133                                                TNG_FLOAT_DATA,
16134                                                TNG_TRAJECTORY_BLOCK,
16135                                                n_frames, n_values_per_frame, i,
16136                                                0, n_particles,
16137                                                compression, 0);
16138             if(stat != TNG_SUCCESS)
16139             {
16140                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16141                        __FILE__, __LINE__);
16142                 return(stat);
16143             }
16144             data = &frame_set->tr_particle_data[frame_set->
16145                                                   n_particle_data_blocks - 1];
16146             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16147                                                   i, n_particles,
16148                                                   n_values_per_frame);
16149             if(stat != TNG_SUCCESS)
16150             {
16151                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16152                        __FILE__, __LINE__);
16153                 return(stat);
16154             }
16155         }
16156         else
16157         {
16158             if(data->stride_length != i)
16159             {
16160                 data->stride_length = i;
16161                 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16162                                                       i, n_particles,
16163                                                       n_values_per_frame);
16164                 if(stat != TNG_SUCCESS)
16165                 {
16166                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16167                            __FILE__, __LINE__);
16168                     return(stat);
16169                 }
16170             }
16171         }
16172     }
16173     else
16174     {
16175         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16176         {
16177             stat = tng_data_block_add(tng_data, block_id, block_name,
16178                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
16179                                       n_frames, n_values_per_frame,
16180                                       i, compression, 0);
16181             if(stat != TNG_SUCCESS)
16182             {
16183                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16184                        __FILE__, __LINE__);
16185                 return(stat);
16186             }
16187             data = &frame_set->tr_data[frame_set->
16188                                           n_data_blocks - 1];
16189             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16190                                          i, n_values_per_frame);
16191             if(stat != TNG_SUCCESS)
16192             {
16193                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16194                        __FILE__, __LINE__);
16195                 return(stat);
16196             }
16197         }
16198         else
16199         {
16200             if(data->stride_length != i)
16201             {
16202                 data->stride_length = i;
16203                 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16204                                              i, n_values_per_frame);
16205                 if(stat != TNG_SUCCESS)
16206                 {
16207                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16208                            __FILE__, __LINE__);
16209                     return(stat);
16210                 }
16211             }
16212         }
16213     }
16214
16215     return(TNG_SUCCESS);
16216 }
16217
16218 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
16219                 (const tng_trajectory_t tng_data,
16220                  const int64_t i,
16221                  const int64_t n_values_per_frame,
16222                  const int64_t block_id,
16223                  const char *block_name,
16224                  const char particle_dependency,
16225                  const char compression)
16226 {
16227     tng_trajectory_frame_set_t frame_set;
16228     tng_data_t data;
16229     int64_t n_particles, n_frames;
16230     tng_function_status stat;
16231
16232     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16233     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16234
16235     if(i <= 0)
16236     {
16237         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
16238                i, __FILE__, __LINE__);
16239         return(TNG_FAILURE);
16240     }
16241
16242     frame_set = &tng_data->current_trajectory_frame_set;
16243
16244     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16245     {
16246         n_frames = tng_data->frame_set_n_frames;
16247
16248         stat = tng_frame_set_new(tng_data, 0, n_frames);
16249         if(stat != TNG_SUCCESS)
16250         {
16251             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16252                 __LINE__);
16253             return(stat);
16254         }
16255     }
16256     else
16257     {
16258         n_frames = frame_set->n_frames;
16259     }
16260
16261     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16262     {
16263         tng_num_particles_get(tng_data, &n_particles);
16264
16265         if(n_particles <= 0)
16266         {
16267             return(TNG_FAILURE);
16268         }
16269
16270         if(tng_particle_data_find(tng_data, block_id, &data)
16271         != TNG_SUCCESS)
16272         {
16273             stat = tng_particle_data_block_add(tng_data, block_id,
16274                                             block_name,
16275                                             TNG_DOUBLE_DATA,
16276                                             TNG_TRAJECTORY_BLOCK,
16277                                             n_frames, n_values_per_frame, i,
16278                                             0, n_particles,
16279                                             compression, 0);
16280             if(stat != TNG_SUCCESS)
16281             {
16282                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16283                        __FILE__, __LINE__);
16284                 return(stat);
16285             }
16286             data = &frame_set->tr_particle_data[frame_set->
16287                                                   n_particle_data_blocks - 1];
16288             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16289                                                   i, n_particles,
16290                                                   n_values_per_frame);
16291             if(stat != TNG_SUCCESS)
16292             {
16293                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16294                        __FILE__, __LINE__);
16295                 return(stat);
16296             }
16297         }
16298         else
16299         {
16300             data->stride_length = i;
16301         }
16302     }
16303     else
16304     {
16305         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16306         {
16307             stat = tng_data_block_add(tng_data, block_id, block_name,
16308                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
16309                                       n_frames, n_values_per_frame,
16310                                       i, compression, 0);
16311             if(stat != TNG_SUCCESS)
16312             {
16313                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16314                        __FILE__, __LINE__);
16315                 return(stat);
16316             }
16317             data = &frame_set->tr_data[frame_set->
16318                                           n_data_blocks - 1];
16319             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16320                                          i, n_values_per_frame);
16321             if(stat != TNG_SUCCESS)
16322             {
16323                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16324                        __FILE__, __LINE__);
16325                 return(stat);
16326             }
16327         }
16328         else
16329         {
16330             data->stride_length = i;
16331         }
16332     }
16333
16334     return(TNG_SUCCESS);
16335 }
16336
16337 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
16338                 (const tng_trajectory_t tng_data,
16339                  const int64_t i,
16340                  const int64_t n_values_per_frame,
16341                  const int64_t block_id,
16342                  const char *block_name,
16343                  const char particle_dependency,
16344                  const char compression)
16345 {
16346     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
16347            "See documentation. %s: %d", __FILE__, __LINE__);
16348     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
16349                                                block_id, block_name,
16350                                                particle_dependency,
16351                                                compression));
16352 }
16353 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
16354                 (const tng_trajectory_t tng_data,
16355                  const int64_t i)
16356 {
16357     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16358     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16359
16360     return(tng_util_generic_write_interval_set(tng_data, i, 3,
16361                                                TNG_TRAJ_POSITIONS,
16362                                                "POSITIONS",
16363                                                TNG_PARTICLE_BLOCK_DATA,
16364                                                TNG_TNG_COMPRESSION));
16365 }
16366
16367 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
16368                 (const tng_trajectory_t tng_data,
16369                  const int64_t i)
16370 {
16371     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16372     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16373
16374     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16375                                                       TNG_TRAJ_POSITIONS,
16376                                                       "POSITIONS",
16377                                                       TNG_PARTICLE_BLOCK_DATA,
16378                                                       TNG_TNG_COMPRESSION));
16379 }
16380
16381 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
16382                 (const tng_trajectory_t tng_data,
16383                  const int64_t i)
16384 {
16385     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
16386            "See documentation. %s: %d", __FILE__, __LINE__);
16387     return(tng_util_pos_write_interval_set(tng_data, i));
16388 }
16389
16390 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
16391                 (const tng_trajectory_t tng_data,
16392                  const int64_t i)
16393 {
16394     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16395     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16396
16397     return(tng_util_generic_write_interval_set(tng_data, i, 3,
16398                                                TNG_TRAJ_VELOCITIES,
16399                                                "VELOCITIES",
16400                                                TNG_PARTICLE_BLOCK_DATA,
16401                                                TNG_TNG_COMPRESSION));
16402 }
16403
16404 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
16405                 (const tng_trajectory_t tng_data,
16406                  const int64_t i)
16407 {
16408     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16409     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16410
16411     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16412                                                       TNG_TRAJ_VELOCITIES,
16413                                                       "VELOCITIES",
16414                                                       TNG_PARTICLE_BLOCK_DATA,
16415                                                       TNG_TNG_COMPRESSION));
16416 }
16417
16418 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
16419                 (const tng_trajectory_t tng_data,
16420                  const int64_t i)
16421 {
16422     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
16423            "See documentation. %s: %d", __FILE__, __LINE__);
16424     return(tng_util_vel_write_interval_set(tng_data, i));
16425 }
16426
16427 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
16428                 (const tng_trajectory_t tng_data,
16429                  const int64_t i)
16430 {
16431     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16432     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16433
16434     return(tng_util_generic_write_interval_set(tng_data, i, 3,
16435                                                TNG_TRAJ_FORCES,
16436                                                "FORCES",
16437                                                TNG_PARTICLE_BLOCK_DATA,
16438                                                TNG_GZIP_COMPRESSION));
16439 }
16440
16441 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
16442                 (const tng_trajectory_t tng_data,
16443                  const int64_t i)
16444 {
16445     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16446     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16447
16448     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16449                                                       TNG_TRAJ_FORCES,
16450                                                       "FORCES",
16451                                                       TNG_PARTICLE_BLOCK_DATA,
16452                                                       TNG_GZIP_COMPRESSION));
16453 }
16454
16455 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
16456                 (const tng_trajectory_t tng_data,
16457                  const int64_t i)
16458 {
16459     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
16460            "See documentation. %s: %d", __FILE__, __LINE__);
16461     return(tng_util_force_write_interval_set(tng_data, i));
16462 }
16463
16464 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
16465                 (const tng_trajectory_t tng_data,
16466                  const int64_t i)
16467 {
16468     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16469     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16470
16471     return(tng_util_generic_write_interval_set(tng_data, i, 9,
16472                                                TNG_TRAJ_BOX_SHAPE,
16473                                                "BOX SHAPE",
16474                                                TNG_NON_PARTICLE_BLOCK_DATA,
16475                                                TNG_GZIP_COMPRESSION));
16476 }
16477
16478 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
16479                 (const tng_trajectory_t tng_data,
16480                  const int64_t i)
16481 {
16482     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16483     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16484
16485     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
16486                                                       TNG_TRAJ_BOX_SHAPE,
16487                                                       "BOX SHAPE",
16488                                                       TNG_NON_PARTICLE_BLOCK_DATA,
16489                                                       TNG_GZIP_COMPRESSION));
16490 }
16491
16492 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
16493                 (const tng_trajectory_t tng_data,
16494                  const int64_t i)
16495 {
16496     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
16497            "See documentation. %s: %d", __FILE__, __LINE__);
16498     return(tng_util_box_shape_write_interval_set(tng_data, i));
16499 }
16500
16501 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
16502                 (const tng_trajectory_t tng_data,
16503                  const int64_t frame_nr,
16504                  const float *values,
16505                  const int64_t n_values_per_frame,
16506                  const int64_t block_id,
16507                  const char *block_name,
16508                  const char particle_dependency,
16509                  const char compression)
16510 {
16511     tng_trajectory_frame_set_t frame_set;
16512     tng_data_t data;
16513     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
16514     int64_t last_frame;
16515     int is_first_frame_flag = 0;
16516     char block_type_flag;
16517     tng_function_status stat;
16518
16519     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16520     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
16521
16522     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16523     {
16524         tng_num_particles_get(tng_data, &n_particles);
16525         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
16526     }
16527
16528     if(values == 0)
16529     {
16530         return(TNG_FAILURE);
16531     }
16532
16533     frame_set = &tng_data->current_trajectory_frame_set;
16534
16535     if(frame_nr < 0)
16536     {
16537         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16538         n_frames = stride_length = 1;
16539     }
16540     else
16541     {
16542         block_type_flag = TNG_TRAJECTORY_BLOCK;
16543
16544         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16545         {
16546             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
16547             if(stat != TNG_SUCCESS)
16548             {
16549                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16550                     __LINE__);
16551                 return(stat);
16552             }
16553         }
16554         last_frame = frame_set->first_frame +
16555                      frame_set->n_frames - 1;
16556         if(frame_nr > last_frame)
16557         {
16558             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
16559             if(stat != TNG_SUCCESS)
16560             {
16561                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
16562                     __LINE__);
16563                 return(stat);
16564             }
16565             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
16566             {
16567                 last_frame = frame_nr - 1;
16568             }
16569             stat = tng_frame_set_new(tng_data, last_frame + 1,
16570                                      tng_data->frame_set_n_frames);
16571             if(stat != TNG_SUCCESS)
16572             {
16573                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16574                     __LINE__);
16575                 return(stat);
16576             }
16577         }
16578         if(frame_set->n_unwritten_frames == 0)
16579         {
16580             is_first_frame_flag = 1;
16581         }
16582         frame_set->n_unwritten_frames = frame_nr -
16583                                         frame_set->first_frame + 1;
16584
16585         n_frames = frame_set->n_frames;
16586     }
16587
16588     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16589     {
16590         if(tng_particle_data_find(tng_data, block_id, &data)
16591         != TNG_SUCCESS)
16592         {
16593             stat = tng_particle_data_block_add(tng_data, block_id,
16594                                                block_name,
16595                                                TNG_FLOAT_DATA,
16596                                                block_type_flag,
16597                                                n_frames, n_values_per_frame,
16598                                                stride_length,
16599                                                0, n_particles,
16600                                                compression, 0);
16601             if(stat != TNG_SUCCESS)
16602             {
16603                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16604                        __FILE__, __LINE__);
16605                 return(stat);
16606             }
16607             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16608             {
16609                 data = &frame_set->tr_particle_data[frame_set->
16610                                                     n_particle_data_blocks - 1];
16611             }
16612             else
16613             {
16614                 data = &tng_data->non_tr_particle_data[tng_data->
16615                                                        n_particle_data_blocks - 1];
16616             }
16617             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16618                                                   stride_length, n_particles,
16619                                                   n_values_per_frame);
16620             if(stat != TNG_SUCCESS)
16621             {
16622                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16623                        __FILE__, __LINE__);
16624                 return(stat);
16625             }
16626         }
16627         /* FIXME: Here we must be able to handle modified n_particles as well. */
16628         else if(n_frames > data->n_frames)
16629         {
16630             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16631                                                   data->stride_length, n_particles,
16632                                                   n_values_per_frame);
16633             if(stat != TNG_SUCCESS)
16634             {
16635                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16636                        __FILE__, __LINE__);
16637                 return(stat);
16638             }
16639         }
16640
16641         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16642         {
16643             stride_length = data->stride_length;
16644
16645             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16646             {
16647                 data->first_frame_with_data = frame_nr;
16648                 frame_pos = 0;
16649             }
16650             else
16651             {
16652                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16653             }
16654
16655             memcpy((char *)data->values + sizeof(float) * frame_pos * n_particles *
16656                    n_values_per_frame, values, sizeof(float) *
16657                    n_particles * n_values_per_frame);
16658         }
16659         else
16660         {
16661             memcpy(data->values, values, sizeof(float) * n_particles *
16662                    n_values_per_frame);
16663         }
16664     }
16665     else
16666     {
16667         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16668         {
16669             stat = tng_data_block_add(tng_data, block_id, block_name,
16670                                       TNG_FLOAT_DATA, block_type_flag,
16671                                       n_frames, n_values_per_frame,
16672                                       stride_length, compression, 0);
16673             if(stat != TNG_SUCCESS)
16674             {
16675                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16676                        __FILE__, __LINE__);
16677                 return(stat);
16678             }
16679             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16680             {
16681                 data = &frame_set->tr_data[frame_set->
16682                                               n_data_blocks - 1];
16683             }
16684             else
16685             {
16686                 data = &tng_data->non_tr_data[tng_data->
16687                                                  n_data_blocks - 1];
16688             }
16689             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16690                                          stride_length, n_values_per_frame);
16691             if(stat != TNG_SUCCESS)
16692             {
16693                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16694                        __FILE__, __LINE__);
16695                 return(stat);
16696             }
16697         }
16698         /* FIXME: Here we must be able to handle modified n_particles as well. */
16699         else if(n_frames > data->n_frames)
16700         {
16701             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16702                                          data->stride_length, n_values_per_frame);
16703             if(stat != TNG_SUCCESS)
16704             {
16705                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16706                        __FILE__, __LINE__);
16707                 return(stat);
16708             }
16709         }
16710
16711         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16712         {
16713             stride_length = data->stride_length;
16714
16715             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16716             {
16717                 data->first_frame_with_data = frame_nr;
16718                 frame_pos = 0;
16719             }
16720             else
16721             {
16722                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16723             }
16724
16725             memcpy((char *)data->values + sizeof(float) * frame_pos *
16726                    n_values_per_frame, values, sizeof(float) *
16727                    n_values_per_frame);
16728         }
16729         else
16730         {
16731             memcpy(data->values, values, sizeof(float) * n_values_per_frame);
16732         }
16733     }
16734
16735     return(TNG_SUCCESS);
16736 }
16737
16738 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
16739                 (const tng_trajectory_t tng_data,
16740                  const int64_t frame_nr,
16741                  const double *values,
16742                  const int64_t n_values_per_frame,
16743                  const int64_t block_id,
16744                  const char *block_name,
16745                  const char particle_dependency,
16746                  const char compression)
16747 {
16748     tng_trajectory_frame_set_t frame_set;
16749     tng_data_t data;
16750     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
16751     int64_t last_frame;
16752     int is_first_frame_flag = 0;
16753     char block_type_flag;
16754     tng_function_status stat;
16755
16756     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16757     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
16758
16759     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16760     {
16761         tng_num_particles_get(tng_data, &n_particles);
16762         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
16763     }
16764
16765     if(values == 0)
16766     {
16767         return(TNG_FAILURE);
16768     }
16769
16770     frame_set = &tng_data->current_trajectory_frame_set;
16771
16772     if(frame_nr < 0)
16773     {
16774         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16775         n_frames = stride_length = 1;
16776     }
16777     else
16778     {
16779         block_type_flag = TNG_TRAJECTORY_BLOCK;
16780
16781         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16782         {
16783             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
16784             if(stat != TNG_SUCCESS)
16785             {
16786                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16787                     __LINE__);
16788                 return(stat);
16789             }
16790         }
16791         last_frame = frame_set->first_frame +
16792                      frame_set->n_frames - 1;
16793         if(frame_nr > last_frame)
16794         {
16795             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
16796             if(stat != TNG_SUCCESS)
16797             {
16798                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
16799                     __LINE__);
16800                 return(stat);
16801             }
16802             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
16803             {
16804                 last_frame = frame_nr - 1;
16805             }
16806             stat = tng_frame_set_new(tng_data, last_frame + 1,
16807                                      tng_data->frame_set_n_frames);
16808             if(stat != TNG_SUCCESS)
16809             {
16810                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16811                     __LINE__);
16812                 return(stat);
16813             }
16814         }
16815         if(frame_set->n_unwritten_frames == 0)
16816         {
16817             is_first_frame_flag = 1;
16818         }
16819         frame_set->n_unwritten_frames = frame_nr -
16820                                         frame_set->first_frame + 1;
16821
16822         n_frames = frame_set->n_frames;
16823     }
16824
16825
16826     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16827     {
16828         if(tng_particle_data_find(tng_data, block_id, &data)
16829         != TNG_SUCCESS)
16830         {
16831             stat = tng_particle_data_block_add(tng_data, block_id,
16832                                             block_name,
16833                                             TNG_DOUBLE_DATA,
16834                                             block_type_flag,
16835                                             n_frames, n_values_per_frame,
16836                                             stride_length,
16837                                             0, n_particles,
16838                                             compression, 0);
16839             if(stat != TNG_SUCCESS)
16840             {
16841                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16842                        __FILE__, __LINE__);
16843                 return(stat);
16844             }
16845             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16846             {
16847                 data = &frame_set->tr_particle_data[frame_set->
16848                                                     n_particle_data_blocks - 1];
16849             }
16850             else
16851             {
16852                 data = &tng_data->non_tr_particle_data[tng_data->
16853                                                     n_particle_data_blocks - 1];
16854             }
16855             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16856                                                   stride_length, n_particles,
16857                                                   n_values_per_frame);
16858             if(stat != TNG_SUCCESS)
16859             {
16860                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16861                        __FILE__, __LINE__);
16862                 return(stat);
16863             }
16864         }
16865         /* FIXME: Here we must be able to handle modified n_particles as well. */
16866         else if(n_frames > data->n_frames)
16867         {
16868             stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16869                                                   data->stride_length, n_particles,
16870                                                   n_values_per_frame);
16871             if(stat != TNG_SUCCESS)
16872             {
16873                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16874                        __FILE__, __LINE__);
16875                 return(stat);
16876             }
16877         }
16878
16879         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16880         {
16881             stride_length = data->stride_length;
16882
16883             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16884             {
16885                 data->first_frame_with_data = frame_nr;
16886                 frame_pos = 0;
16887             }
16888             else
16889             {
16890                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16891             }
16892
16893             memcpy((char *)data->values + sizeof(double) * frame_pos * n_particles *
16894                    n_values_per_frame, values, sizeof(double) *
16895                    n_particles * n_values_per_frame);
16896         }
16897         else
16898         {
16899             memcpy(data->values, values, sizeof(double) * n_particles *
16900                    n_values_per_frame);
16901         }
16902     }
16903     else
16904     {
16905         if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16906         {
16907             stat = tng_data_block_add(tng_data, block_id, block_name,
16908                                       TNG_DOUBLE_DATA, block_type_flag,
16909                                       n_frames, n_values_per_frame,
16910                                       stride_length, compression, 0);
16911             if(stat != TNG_SUCCESS)
16912             {
16913                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16914                        __FILE__, __LINE__);
16915                 return(stat);
16916             }
16917             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16918             {
16919                 data = &frame_set->tr_data[frame_set->
16920                                               n_data_blocks - 1];
16921             }
16922             else
16923             {
16924                 data = &tng_data->non_tr_data[tng_data->
16925                                                  n_data_blocks - 1];
16926             }
16927             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16928                                          stride_length, n_values_per_frame);
16929             if(stat != TNG_SUCCESS)
16930             {
16931                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16932                        __FILE__, __LINE__);
16933                 return(stat);
16934             }
16935         }
16936         /* FIXME: Here we must be able to handle modified n_particles as well. */
16937         else if(n_frames > data->n_frames)
16938         {
16939             stat = tng_allocate_data_mem(tng_data, data, n_frames,
16940                                          data->stride_length, n_values_per_frame);
16941             if(stat != TNG_SUCCESS)
16942             {
16943                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16944                        __FILE__, __LINE__);
16945                 return(stat);
16946             }
16947         }
16948
16949         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16950         {
16951             stride_length = data->stride_length;
16952
16953             if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16954             {
16955                 data->first_frame_with_data = frame_nr;
16956                 frame_pos = 0;
16957             }
16958             else
16959             {
16960                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16961             }
16962
16963             memcpy((char *)data->values + sizeof(double) * frame_pos *
16964                    n_values_per_frame, values, sizeof(double) *
16965                    n_values_per_frame);
16966         }
16967         else
16968         {
16969             memcpy(data->values, values, sizeof(double) * n_values_per_frame);
16970         }
16971     }
16972
16973     return(TNG_SUCCESS);
16974 }
16975
16976 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
16977                 (const tng_trajectory_t tng_data,
16978                  const int64_t frame_nr,
16979                  const float *positions)
16980 {
16981     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16982     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16983
16984     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
16985                                   TNG_TRAJ_POSITIONS, "POSITIONS",
16986                                   TNG_PARTICLE_BLOCK_DATA,
16987                                   TNG_TNG_COMPRESSION));
16988 }
16989
16990 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
16991                 (const tng_trajectory_t tng_data,
16992                  const int64_t frame_nr,
16993                  const double *positions)
16994 {
16995     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16996     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16997
16998     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
16999                                          TNG_TRAJ_POSITIONS, "POSITIONS",
17000                                          TNG_PARTICLE_BLOCK_DATA,
17001                                          TNG_TNG_COMPRESSION));
17002 }
17003
17004 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
17005                 (const tng_trajectory_t tng_data,
17006                  const int64_t frame_nr,
17007                  const float *velocities)
17008 {
17009     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17010     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17011
17012     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
17013                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
17014                                   TNG_PARTICLE_BLOCK_DATA,
17015                                   TNG_TNG_COMPRESSION));
17016 }
17017
17018 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
17019                 (const tng_trajectory_t tng_data,
17020                  const int64_t frame_nr,
17021                  const double *velocities)
17022 {
17023     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17024     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17025
17026     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
17027                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
17028                                          TNG_PARTICLE_BLOCK_DATA,
17029                                          TNG_TNG_COMPRESSION));
17030 }
17031
17032 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
17033                 (const tng_trajectory_t tng_data,
17034                  const int64_t frame_nr,
17035                  const float *forces)
17036 {
17037     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17038     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17039
17040     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
17041                                   TNG_TRAJ_FORCES, "FORCES",
17042                                   TNG_PARTICLE_BLOCK_DATA,
17043                                   TNG_GZIP_COMPRESSION));
17044 }
17045
17046 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
17047                 (const tng_trajectory_t tng_data,
17048                  const int64_t frame_nr,
17049                  const double *forces)
17050 {
17051     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17052     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17053
17054     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
17055                                          TNG_TRAJ_FORCES, "FORCES",
17056                                          TNG_PARTICLE_BLOCK_DATA,
17057                                          TNG_GZIP_COMPRESSION));
17058 }
17059
17060 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
17061                 (const tng_trajectory_t tng_data,
17062                  const int64_t frame_nr,
17063                  const float *box_shape)
17064 {
17065     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17066     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17067
17068     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
17069                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17070                                   TNG_NON_PARTICLE_BLOCK_DATA,
17071                                   TNG_GZIP_COMPRESSION));
17072 }
17073
17074 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
17075                 (const tng_trajectory_t tng_data,
17076                  const int64_t frame_nr,
17077                  const double *box_shape)
17078 {
17079     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17080     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17081
17082     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
17083                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17084                                          TNG_NON_PARTICLE_BLOCK_DATA,
17085                                          TNG_GZIP_COMPRESSION));
17086 }
17087
17088 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
17089                 (const tng_trajectory_t tng_data,
17090                  const int64_t frame_nr,
17091                  const double time,
17092                  const float *values,
17093                  const int64_t n_values_per_frame,
17094                  const int64_t block_id,
17095                  const char *block_name,
17096                  const char particle_dependency,
17097                  const char compression)
17098 {
17099     tng_trajectory_frame_set_t frame_set;
17100     tng_function_status stat;
17101
17102     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17103     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17104     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17105     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17106
17107     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
17108                                   block_id, block_name,
17109                                   particle_dependency,
17110                                   compression);
17111
17112     if(stat != TNG_SUCCESS)
17113     {
17114         return(stat);
17115     }
17116
17117     frame_set = &tng_data->current_trajectory_frame_set;
17118
17119     /* first_frame_time is -1 when it is not yet set. */
17120     if(frame_set->first_frame_time < -0.1)
17121     {
17122         if(frame_nr > frame_set->first_frame)
17123         {
17124             stat = tng_frame_set_first_frame_time_set(tng_data,
17125                                                       time -
17126                                                       (frame_nr -
17127                                                        frame_set->first_frame) *
17128                                                       tng_data->time_per_frame);
17129         }
17130         else
17131         {
17132             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17133         }
17134     }
17135     return(stat);
17136 }
17137
17138 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
17139                 (const tng_trajectory_t tng_data,
17140                  const int64_t frame_nr,
17141                  const double time,
17142                  const double *values,
17143                  const int64_t n_values_per_frame,
17144                  const int64_t block_id,
17145                  const char *block_name,
17146                  const char particle_dependency,
17147                  const char compression)
17148 {
17149     tng_trajectory_frame_set_t frame_set;
17150     tng_function_status stat;
17151
17152     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17153     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17154     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17155     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17156
17157     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
17158                                          block_id, block_name,
17159                                          particle_dependency,
17160                                          compression);
17161
17162     if(stat != TNG_SUCCESS)
17163     {
17164         return(stat);
17165     }
17166
17167     frame_set = &tng_data->current_trajectory_frame_set;
17168
17169     /* first_frame_time is -1 when it is not yet set. */
17170     if(frame_set->first_frame_time < -0.1)
17171     {
17172         if(frame_nr > frame_set->first_frame)
17173         {
17174             stat = tng_frame_set_first_frame_time_set(tng_data,
17175                                                       time -
17176                                                       (frame_nr -
17177                                                        frame_set->first_frame) *
17178                                                       tng_data->time_per_frame);
17179         }
17180         else
17181         {
17182             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17183         }
17184     }
17185     return(stat);
17186 }
17187
17188 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
17189                 (const tng_trajectory_t tng_data,
17190                  const int64_t frame_nr,
17191                  const double time,
17192                  const float *positions)
17193 {
17194     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17195     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17196     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17197     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17198
17199     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
17200                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
17201                                             TNG_PARTICLE_BLOCK_DATA,
17202                                             TNG_TNG_COMPRESSION));
17203 }
17204
17205 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
17206                 (const tng_trajectory_t tng_data,
17207                  const int64_t frame_nr,
17208                  const double time,
17209                  const double *positions)
17210 {
17211     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17212     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17213     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17214     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17215
17216     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17217                                                    positions, 3,
17218                                                    TNG_TRAJ_POSITIONS,
17219                                                    "POSITIONS",
17220                                                    TNG_PARTICLE_BLOCK_DATA,
17221                                                    TNG_TNG_COMPRESSION));
17222 }
17223
17224 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
17225                 (const tng_trajectory_t tng_data,
17226                  const int64_t frame_nr,
17227                  const double time,
17228                  const float *velocities)
17229 {
17230     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17231     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17232     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17233     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17234
17235     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
17236                                             velocities, 3,
17237                                             TNG_TRAJ_VELOCITIES,
17238                                             "VELOCITIES",
17239                                             TNG_PARTICLE_BLOCK_DATA,
17240                                             TNG_TNG_COMPRESSION));
17241 }
17242
17243 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
17244                 (const tng_trajectory_t tng_data,
17245                  const int64_t frame_nr,
17246                  const double time,
17247                  const double *velocities)
17248 {
17249     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17250     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17251     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17252     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17253
17254     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17255                                                    velocities, 3,
17256                                                    TNG_TRAJ_VELOCITIES,
17257                                                    "VELOCITIES",
17258                                                    TNG_PARTICLE_BLOCK_DATA,
17259                                                    TNG_TNG_COMPRESSION));
17260 }
17261
17262 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
17263                 (const tng_trajectory_t tng_data,
17264                  const int64_t frame_nr,
17265                  const double time,
17266                  const float *forces)
17267 {
17268     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17269     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17270     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17271     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17272
17273     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
17274                                             3, TNG_TRAJ_FORCES, "FORCES",
17275                                             TNG_PARTICLE_BLOCK_DATA,
17276                                             TNG_GZIP_COMPRESSION));
17277 }
17278
17279 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
17280                 (const tng_trajectory_t tng_data,
17281                  const int64_t frame_nr,
17282                  const double time,
17283                  const double *forces)
17284 {
17285     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17286     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17287     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17288     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17289
17290     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17291                                                    forces, 3,
17292                                                    TNG_TRAJ_FORCES, "FORCES",
17293                                                    TNG_PARTICLE_BLOCK_DATA,
17294                                                    TNG_GZIP_COMPRESSION));
17295 }
17296
17297 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
17298                 (const tng_trajectory_t tng_data,
17299                  const int64_t frame_nr,
17300                  const double time,
17301                  const float *box_shape)
17302 {
17303     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17304     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17305     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17306     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17307
17308     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
17309                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17310                                             TNG_NON_PARTICLE_BLOCK_DATA,
17311                                             TNG_GZIP_COMPRESSION));
17312 }
17313
17314 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
17315                 (const tng_trajectory_t tng_data,
17316                  const int64_t frame_nr,
17317                  const double time,
17318                  const double *box_shape)
17319 {
17320     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17321     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17322     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17323     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17324
17325     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
17326                                                    time, box_shape, 9,
17327                                                    TNG_TRAJ_BOX_SHAPE,
17328                                                    "BOX SHAPE",
17329                                                    TNG_NON_PARTICLE_BLOCK_DATA,
17330                                                    TNG_GZIP_COMPRESSION));
17331 }
17332
17333 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
17334                 (const tng_trajectory_t tng_data,
17335                  const int64_t block_id,
17336                  int64_t *codec_id,
17337                  double *factor)
17338 {
17339     tng_trajectory_frame_set_t frame_set;
17340     tng_data_t data = 0;
17341     tng_function_status stat;
17342     int64_t i;
17343     int block_type = -1;
17344
17345     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17346     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
17347     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
17348
17349     frame_set = &tng_data->current_trajectory_frame_set;
17350
17351     stat = tng_particle_data_find(tng_data, block_id, &data);
17352     if(stat == TNG_SUCCESS)
17353     {
17354         block_type = TNG_PARTICLE_BLOCK_DATA;
17355     }
17356     else
17357     {
17358         stat = tng_data_find(tng_data, block_id, &data);
17359         if(stat == TNG_SUCCESS)
17360         {
17361             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
17362         }
17363         else
17364         {
17365             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17366             if(stat != TNG_SUCCESS)
17367             {
17368                 return(stat);
17369             }
17370             stat = tng_particle_data_find(tng_data, block_id, &data);
17371             if(stat == TNG_SUCCESS)
17372             {
17373                 block_type = TNG_PARTICLE_BLOCK_DATA;
17374             }
17375             else
17376             {
17377                 stat = tng_data_find(tng_data, block_id, &data);
17378                 if(stat == TNG_SUCCESS)
17379                 {
17380                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
17381                 }
17382                 else
17383                 {
17384                     return(stat);
17385                 }
17386             }
17387         }
17388     }
17389     if(block_type == TNG_PARTICLE_BLOCK_DATA)
17390     {
17391         if(data->last_retrieved_frame < 0)
17392         {
17393             i = data->first_frame_with_data;
17394         }
17395         else
17396         {
17397             i = data->last_retrieved_frame;
17398         }
17399     }
17400     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
17401     {
17402         if(data->last_retrieved_frame < 0)
17403         {
17404             i = data->first_frame_with_data;
17405         }
17406         else
17407         {
17408             i = data->last_retrieved_frame;
17409         }
17410     }
17411     else
17412     {
17413         return(TNG_FAILURE);
17414     }
17415     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17416     {
17417         stat = tng_frame_set_of_frame_find(tng_data, i);
17418         if(stat != TNG_SUCCESS)
17419         {
17420             return(stat);
17421         }
17422         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17423         if(stat != TNG_SUCCESS)
17424         {
17425             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17426                 __FILE__, __LINE__);
17427             return(stat);
17428         }
17429     }
17430     if(block_type == TNG_PARTICLE_BLOCK_DATA)
17431     {
17432         *codec_id = data->codec_id;
17433         *factor   = data->compression_multiplier;
17434     }
17435     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
17436     {
17437         *codec_id = data->codec_id;
17438         *factor   = data->compression_multiplier;
17439     }
17440     return(TNG_SUCCESS);
17441 }
17442
17443 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
17444                 (const tng_trajectory_t tng_data,
17445                  int64_t current_frame,
17446                  const int64_t n_requested_data_block_ids,
17447                  const int64_t *requested_data_block_ids,
17448                  int64_t *next_frame,
17449                  int64_t *n_data_blocks_in_next_frame,
17450                  int64_t **data_block_ids_in_next_frame)
17451 {
17452     tng_trajectory_frame_set_t frame_set;
17453     tng_function_status stat;
17454     tng_data_t data;
17455     tng_gen_block_t block;
17456     int64_t i, j, block_id, *temp;
17457     int64_t data_frame, frame_diff, min_diff;
17458     int64_t size, frame_set_file_pos;
17459     int found, read_all = 0;
17460     int64_t file_pos;
17461
17462     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17463     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
17464     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
17465     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
17466
17467     if(n_requested_data_block_ids)
17468     {
17469         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.");
17470         size = sizeof(int64_t) * n_requested_data_block_ids;
17471         temp = realloc(*data_block_ids_in_next_frame, size);
17472         if(!temp)
17473         {
17474             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
17475                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
17476                     __FILE__, __LINE__);
17477             free(*data_block_ids_in_next_frame);
17478             *data_block_ids_in_next_frame = 0;
17479             return(TNG_CRITICAL);
17480         }
17481         *data_block_ids_in_next_frame = temp;
17482     }
17483
17484     frame_set = &tng_data->current_trajectory_frame_set;
17485
17486     current_frame += 1;
17487
17488     if(current_frame < frame_set->first_frame ||
17489        current_frame >= frame_set->first_frame + frame_set->n_frames)
17490     {
17491         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
17492         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
17493         if(stat != TNG_SUCCESS)
17494         {
17495             /* If the frame set search found the frame set after the starting
17496              * frame set there is a gap in the frame sets. So, even if the frame
17497              * was not found the next frame with data is still in the found
17498              * frame set. */
17499             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
17500                frame_set_file_pos)
17501             {
17502                 return(stat);
17503             }
17504             current_frame = frame_set->first_frame;
17505         }
17506     }
17507
17508     /* Check for data blocks only if they have not already been found. */
17509     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
17510     {
17511         file_pos = ftello(tng_data->input_file);
17512         if(file_pos < tng_data->input_file_len)
17513         {
17514             tng_block_init(&block);
17515             stat = tng_block_header_read(tng_data, block);
17516             while(file_pos < tng_data->input_file_len &&
17517                 stat != TNG_CRITICAL &&
17518                 block->id != TNG_TRAJECTORY_FRAME_SET &&
17519                 block->id != -1)
17520             {
17521                 stat = tng_block_read_next(tng_data, block,
17522                                         TNG_USE_HASH);
17523                 if(stat != TNG_CRITICAL)
17524                 {
17525                     file_pos = ftello(tng_data->input_file);
17526                     if(file_pos < tng_data->input_file_len)
17527                     {
17528                         stat = tng_block_header_read(tng_data, block);
17529                     }
17530                 }
17531             }
17532             tng_block_destroy(&block);
17533             if(stat == TNG_CRITICAL)
17534             {
17535                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
17536                         file_pos, __FILE__, __LINE__);
17537                 return(stat);
17538             }
17539         }
17540         read_all = 1;
17541     }
17542
17543     min_diff = -1;
17544
17545     *n_data_blocks_in_next_frame = 0;
17546
17547     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
17548     {
17549         data = &frame_set->tr_particle_data[i];
17550         block_id = data->block_id;
17551
17552         if(n_requested_data_block_ids > 0)
17553         {
17554             found = 0;
17555             for(j = 0; j < n_requested_data_block_ids; j++)
17556             {
17557                 if(block_id == requested_data_block_ids[j])
17558                 {
17559                     found = 1;
17560                     break;
17561                 }
17562             }
17563             if(!found)
17564             {
17565                 continue;
17566             }
17567         }
17568
17569         if(!read_all && (data->last_retrieved_frame < frame_set->first_frame ||
17570            data->last_retrieved_frame >=
17571            frame_set->first_frame + frame_set->n_frames))
17572         {
17573             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
17574                                                                       TNG_USE_HASH, block_id);
17575             if(stat == TNG_CRITICAL)
17576             {
17577                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17578                     __FILE__, __LINE__);
17579                 return(stat);
17580             }
17581             if(stat == TNG_FAILURE)
17582             {
17583                 continue;
17584             }
17585         }
17586         if(frame_set->first_frame != current_frame &&
17587            data->last_retrieved_frame >= 0)
17588         {
17589             data_frame = data->last_retrieved_frame + data->stride_length;
17590         }
17591         else
17592         {
17593             data_frame = data->first_frame_with_data;
17594         }
17595         frame_diff = data_frame - current_frame;
17596         if(frame_diff < 0)
17597         {
17598             continue;
17599         }
17600         if(min_diff == -1 || frame_diff <= min_diff)
17601         {
17602             if(frame_diff < min_diff)
17603             {
17604                 *n_data_blocks_in_next_frame = 1;
17605             }
17606             else
17607             {
17608                 *n_data_blocks_in_next_frame += 1;
17609             }
17610             if(n_requested_data_block_ids <= 0)
17611             {
17612                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
17613                 temp = realloc(*data_block_ids_in_next_frame, size);
17614                 if(!temp)
17615                 {
17616                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
17617                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
17618                            __FILE__, __LINE__);
17619                     free(*data_block_ids_in_next_frame);
17620                     *data_block_ids_in_next_frame = 0;
17621                     return(TNG_CRITICAL);
17622                 }
17623                 *data_block_ids_in_next_frame = temp;
17624             }
17625             else
17626             {
17627                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
17628             }
17629             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
17630
17631             min_diff = frame_diff;
17632         }
17633     }
17634     for(i = 0; i < frame_set->n_data_blocks; i++)
17635     {
17636         data = &frame_set->tr_data[i];
17637         block_id = data->block_id;
17638
17639         if(n_requested_data_block_ids > 0)
17640         {
17641             found = 0;
17642             for(j = 0; j < n_requested_data_block_ids; j++)
17643             {
17644                 if(block_id == requested_data_block_ids[j])
17645                 {
17646                     found = 1;
17647                     break;
17648                 }
17649             }
17650             if(!found)
17651             {
17652                 continue;
17653             }
17654         }
17655
17656         if(!read_all && (data->last_retrieved_frame < frame_set->first_frame ||
17657            data->last_retrieved_frame >=
17658            frame_set->first_frame + frame_set->n_frames))
17659         {
17660             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
17661                                                                       TNG_USE_HASH, block_id);
17662             if(stat == TNG_CRITICAL)
17663             {
17664                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17665                     __FILE__, __LINE__);
17666                 return(stat);
17667             }
17668             if(stat == TNG_FAILURE)
17669             {
17670                 continue;
17671             }
17672         }
17673         if(frame_set->first_frame != current_frame &&
17674            data->last_retrieved_frame >= 0)
17675         {
17676             data_frame = data->last_retrieved_frame + data->stride_length;
17677         }
17678         else
17679         {
17680             data_frame = data->first_frame_with_data;
17681         }
17682         frame_diff = data_frame - current_frame;
17683         if(frame_diff < 0)
17684         {
17685             continue;
17686         }
17687         if(min_diff == -1 || frame_diff <= min_diff)
17688         {
17689             if(frame_diff < min_diff)
17690             {
17691                 *n_data_blocks_in_next_frame = 1;
17692             }
17693             else
17694             {
17695                 *n_data_blocks_in_next_frame += 1;
17696             }
17697             if(n_requested_data_block_ids <= 0)
17698             {
17699                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
17700                 temp = realloc(*data_block_ids_in_next_frame, size);
17701                 if(!temp)
17702                 {
17703                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
17704                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
17705                            __FILE__, __LINE__);
17706                     free(*data_block_ids_in_next_frame);
17707                     *data_block_ids_in_next_frame = 0;
17708                     return(TNG_CRITICAL);
17709                 }
17710                 *data_block_ids_in_next_frame = temp;
17711             }
17712             else
17713             {
17714                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
17715             }
17716             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
17717
17718             min_diff = frame_diff;
17719         }
17720     }
17721     if(min_diff < 0)
17722     {
17723         return(TNG_FAILURE);
17724     }
17725     *next_frame = current_frame + min_diff;
17726
17727     return(TNG_SUCCESS);
17728 }
17729
17730 /*
17731 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
17732                 (const tng_trajectory_t tng_data,
17733                  int64_t *n_data_blocks,
17734                  int64_t **data_block_ids,
17735                  char ***data_block_names,
17736                  int64_t **stride_lengths,
17737                  int64_t **n_values_per_frame,
17738                  char **block_types,
17739                  char **dependencies,
17740                  char **compressions)
17741 {
17742     tng_gen_block_t block;
17743     int64_t orig_file_pos, file_pos;
17744
17745     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17746     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
17747     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
17748     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
17749     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
17750
17751     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
17752     {
17753         return(TNG_CRITICAL);
17754     }
17755
17756     orig_file_pos = ftello(tng_data->input_file);
17757
17758     fseeko(tng_data->input_file, 0, SEEK_SET);
17759     file_pos = 0;
17760
17761     *n_data_blocks = 0;
17762
17763     tng_block_init(&block);
17764
17765     while(file_pos < tng_data->input_file_len &&
17766           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
17767     {
17768         if(block->id > TNG_TRAJECTORY_FRAME_SET)
17769         {
17770
17771         }
17772         file_pos += (block->block_contents_size + block->header_contents_size);
17773         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
17774     }
17775
17776     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
17777
17778     return(TNG_SUCCESS);
17779 }
17780 */
17781 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
17782                 (const tng_trajectory_t tng_data,
17783                  const int64_t prev_frame)
17784 {
17785     tng_function_status stat;
17786     FILE *temp = tng_data->input_file;
17787
17788     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17789     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
17790
17791     tng_data->input_file = tng_data->output_file;
17792
17793     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
17794     if(stat != TNG_SUCCESS)
17795     {
17796         return(stat);
17797     }
17798
17799     tng_data->current_trajectory_frame_set_output_file_pos =
17800     tng_data->current_trajectory_frame_set_input_file_pos;
17801
17802     tng_data->input_file = temp;
17803
17804     return(TNG_SUCCESS);
17805 }
17806
17807 tng_function_status DECLSPECDLLEXPORT tng_util_num_frames_with_data_of_block_id_get
17808                 (const tng_trajectory_t tng_data,
17809                  const int64_t block_id,
17810                  int64_t *n_frames)
17811 {
17812     int64_t curr_file_pos, first_frame_set_file_pos, curr_n_frames;
17813     tng_function_status stat;
17814
17815     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17816
17817     *n_frames = 0;
17818
17819     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
17820     {
17821         return(TNG_CRITICAL);
17822     }
17823
17824     first_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
17825     curr_file_pos = ftello(tng_data->input_file);
17826     fseeko(tng_data->input_file, first_frame_set_file_pos, SEEK_SET);
17827
17828     stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames);
17829
17830     while(stat == TNG_SUCCESS && tng_data->current_trajectory_frame_set.next_frame_set_file_pos != -1)
17831     {
17832         *n_frames += curr_n_frames;
17833         fseeko(tng_data->input_file,
17834                tng_data->current_trajectory_frame_set.next_frame_set_file_pos,
17835                SEEK_SET);
17836         stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames);
17837     }
17838     if(stat == TNG_SUCCESS)
17839     {
17840         *n_frames += curr_n_frames;
17841     }
17842     fseeko(tng_data->input_file, curr_file_pos, SEEK_SET);
17843     if(stat == TNG_CRITICAL)
17844     {
17845         return(TNG_CRITICAL);
17846     }
17847     return(TNG_SUCCESS);
17848 }