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