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