Add TNG writing and reading support
[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  *                      VERSION 1.4
4  *
5  * Written by Magnus Lundborg
6  * Copyright (c) 2012-2013, The GROMACS development team.
7  * Check out http://www.gromacs.org for more information.
8  *
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the Revised BSD License.
12  */
13
14 #ifdef USE_STD_INTTYPES_H
15 #include <inttypes.h>
16 #endif
17
18 #include <limits.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 #include <math.h>
23 #ifdef USE_ZLIB
24 #include <zlib.h>
25 #endif
26
27 #include "../../include/tng_io.h"
28 #include "../../include/md5.h"
29 #include "../../include/compression/tng_compress.h"
30
31
32 struct tng_bond {
33     /** One of the atoms of the bond */
34     int64_t from_atom_id;
35     /** The other atom of the bond */
36     int64_t to_atom_id;
37 };
38
39 struct tng_atom {
40     /** The residue containing this atom */
41     tng_residue_t residue;
42     /** A unique (per molecule) ID number of the atom */
43     int64_t id;
44     /** The atom_type (depending on the forcefield) */
45     char *atom_type;
46     /** The name of the atom */
47     char *name;
48 };
49
50 struct tng_residue {
51     /** The chain containing this residue */
52     tng_chain_t chain;
53     /** A unique (per chain) ID number of the residue */
54     int64_t id;
55     /** The name of the residue */
56     char *name;
57     /** The number of atoms in the residue */
58     int64_t n_atoms;
59     /** A list of atoms in the residue */
60     int64_t atoms_offset;
61 };
62
63 struct tng_chain {
64     /** The molecule containing this chain */
65     tng_molecule_t molecule;
66     /** A unique (per molecule) ID number of the chain */
67     int64_t id;
68     /** The name of the chain */
69     char *name;
70     /** The number of residues in the chain */
71     int64_t n_residues;
72     /** A list of residues in the chain */
73     tng_residue_t residues;
74 };
75
76 struct tng_molecule {
77     /** A unique ID number of the molecule */
78     int64_t id;
79     /** Quaternary structure of the molecule.
80      *  1 => monomeric
81      *  2 => dimeric
82      *  3 => trimeric
83      *  etc */
84     int64_t quaternary_str;
85     /** The number of chains in the molecule */
86     int64_t n_chains;
87     /** The number of residues in the molecule */
88     int64_t n_residues;
89     /** The number of atoms in the molecule */
90     int64_t n_atoms;
91     /** The number of bonds in the molecule. If the bonds are not specified this
92      * value can be 0. */
93     int64_t n_bonds;
94     /** The name of the molecule */
95     char *name;
96     /** A list of chains in the molecule */
97     tng_chain_t chains;
98     /** A list of residues in the molecule */
99     tng_residue_t residues;
100     /** A list of the atoms in the molecule */
101     tng_atom_t atoms;
102     /** A list of the bonds in the molecule */
103     tng_bond_t bonds;
104 };
105
106 struct tng_gen_block {
107     /** The size of the block header in bytes */
108     int64_t header_contents_size;
109     /** The size of the block contents in bytes */
110     int64_t block_contents_size;
111     /** The ID of the block to determine its type */
112     int64_t id;
113     /** The MD5 hash of the block to verify integrity */
114     char md5_hash[TNG_MD5_HASH_LEN];
115     /** The name of the block */
116     char *name;
117     /** The library version used to write the block */
118     int64_t block_version;
119     int64_t alt_hash_type;
120     int64_t alt_hash_len;
121     char *alt_hash;
122     int64_t signature_type;
123     int64_t signature_len;
124     char *signature;
125     /** The full block header contents */
126     char *header_contents;
127     /** The full block contents */
128     char *block_contents;
129 };
130
131 struct tng_particle_mapping {
132     /** The index number of the first particle in this mapping block */
133     int64_t num_first_particle;
134     /** The number of particles list in this mapping block */
135     int64_t n_particles;
136     /** the mapping of index numbers to the real particle numbers in the
137      * trajectory. real_particle_numbers[0] is the real particle number
138      * (as it is numbered in the molecular system) of the first particle
139      * in the data blocks covered by this particle mapping block */
140     int64_t *real_particle_numbers;
141 };
142
143 struct tng_trajectory_frame_set {
144     /** The number of different particle mapping blocks present. */
145     int64_t n_mapping_blocks;
146     /** The atom mappings of this frame set */
147     struct tng_particle_mapping *mappings;
148     /** The first frame of this frame set */
149     int64_t first_frame;
150     /** The number of frames in this frame set */
151     int64_t n_frames;
152     /** The number of written frames in this frame set (used when writing one
153      * frame at a time). */
154     int64_t n_written_frames;
155     /** The number of frames not yet written to file in this frame set
156      * (used from the utility functions to finish the writing properly. */
157     int64_t n_unwritten_frames;
158
159
160     /** A list of the number of each molecule type - only used when using
161      * variable number of atoms */
162     int64_t *molecule_cnt_list;
163     /** The number of particles/atoms - only used when using variable number
164      * of atoms */
165     int64_t n_particles;
166     /** The file position of the next frame set */
167     int64_t next_frame_set_file_pos;
168     /** The file position of the previous frame set */
169     int64_t prev_frame_set_file_pos;
170     /** The file position of the frame set one long stride step ahead */
171     int64_t medium_stride_next_frame_set_file_pos;
172     /** The file position of the frame set one long stride step behind */
173     int64_t medium_stride_prev_frame_set_file_pos;
174     /** The file position of the frame set one long stride step ahead */
175     int64_t long_stride_next_frame_set_file_pos;
176     /** The file position of the frame set one long stride step behind */
177     int64_t long_stride_prev_frame_set_file_pos;
178     /** Time stamp (in seconds) of first frame in frame set */
179     double first_frame_time;
180
181     /* The data blocks in a frame set are trajectory data blocks */
182     /** The number of trajectory data blocks of particle dependent data */
183     int n_particle_data_blocks;
184     /** A list of data blocks containing particle dependent data */
185     struct tng_particle_data *tr_particle_data;
186     /** The number of trajectory data blocks independent of particles */
187     int n_data_blocks;
188     /** A list of data blocks containing particle indepdendent data */
189     struct tng_non_particle_data *tr_data;
190 };
191
192 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
193 struct tng_particle_data {
194     /** The block ID of the data block containing this particle data.
195      *  This is used to determine the kind of data that is stored */
196     int64_t block_id;
197     /** The name of the data block. This is used to determine the kind of
198      *  data that is stored */
199     char *block_name;
200     /** The type of data stored. */
201     char datatype;
202     /** The frame number of the first data value */
203     int64_t first_frame_with_data;
204     /** The number of frames in this frame set */
205     int64_t n_frames;
206     /** The number of values stored per frame */
207     int64_t n_values_per_frame;
208     /** The number of frames between each data point - e.g. when
209      *  storing sparse data. */
210     int64_t stride_length;
211     /** ID of the CODEC used for compression 0 == no compression. */
212     int64_t codec_id;
213     /** If reading one frame at a time this is the last read frame */
214     int64_t last_retrieved_frame;
215     /** The multiplier used for getting integer values for compression */
216     double compression_multiplier;
217     /** A 1-dimensional array of values of length
218      *  [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
219     void *values;
220     /** If storing character data store it in a 3-dimensional array */
221     char ****strings;
222 };
223
224 struct tng_non_particle_data {
225     /** The ID of the data block */
226     int64_t block_id;
227     /** The name of the data block. This is used to determine the kind of
228      *  data that is stored */
229     char *block_name;
230     /** The type of data stored. */
231     char datatype;
232     /** The first frame number of the first data value */
233     int64_t first_frame_with_data;
234     /** The number of frames in this data block */
235     int64_t n_frames;
236     /** The number of values stored per frame */
237     int64_t n_values_per_frame;
238     /** The number of frames between each data value, e.g. if storing data
239      *  that is not saved every frame. */
240     int64_t stride_length;
241     /** ID of the CODEC used for compression. 0 == no compression. */
242     int64_t codec_id;
243     /** If reading one frame at a time this is the last read frame */
244     int64_t last_retrieved_frame;
245     /** Compressed data is stored as integers. This compression multiplier is
246      *  the multiplication factor to convert from integer to float/double */
247     double compression_multiplier;
248     /** A 1-dimensional array of values of length
249      *  [sizeof (datatype)] * n_frames * n_values_per_frame */
250     void *values;
251     /** If storing character data store it in a 3-dimensional array */
252     char ***strings;
253 };
254
255
256
257 struct tng_trajectory {
258     /** The path of the input trajectory file */
259     char *input_file_path;
260     /** A handle to the input file */
261     FILE *input_file;
262     /** The length of the input file */
263     long input_file_len;
264     /** The path of the output trajectory file */
265     char *output_file_path;
266     /** A handle to the output file */
267     FILE *output_file;
268     /** Function to swap 32 bit values to and from the endianness of the
269      * input file */
270     tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
271     /** Function to swap 64 bit values to and from the endianness of the
272      * input file */
273     tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
274     /** Function to swap 32 bit values to and from the endianness of the
275      * input file */
276     tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
277     /** Function to swap 64 bit values to and from the endianness of the
278      * input file */
279     tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
280     /** The endianness of 32 bit values of the current computer */
281     char endianness_32;
282     /** The endianness of 64 bit values of the current computer */
283     char endianness_64;
284
285     /** The name of the program producing this trajectory */
286     char *first_program_name;
287     /** The forcefield used in the simulations */
288     char *forcefield_name;
289     /** The name of the user running the simulations */
290     char *first_user_name;
291     /** The name of the computer on which the simulations were performed */
292     char *first_computer_name;
293     /** The PGP signature of the user creating the file. */
294     char *first_pgp_signature;
295     /** The name of the program used when making last modifications to the
296      *  file */
297     char *last_program_name;
298     /** The name of the user making the last modifications to the file */
299     char *last_user_name;
300     /** The name of the computer on which the last modifications were made */
301     char *last_computer_name;
302     /** The PGP signature of the user making the last modifications to the
303      *  file. */
304     char *last_pgp_signature;
305     /** The time (n seconds since 1970) when the file was created */
306     int64_t time;
307     /** The exponential of the value of the distance unit used. The default
308      * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
309      * the measurements are in Ã… the distance_unit_exponential = -10. */
310     int64_t distance_unit_exponential;
311
312     /** A flag indicating if the number of atoms can vary throughout the
313      *  simulation, e.g. using a grand canonical ensemble */
314     char var_num_atoms_flag;
315     /** The number of frames in a frame set. It is allowed to have frame sets
316      *  with fewer frames, but this will help searching for specific frames */
317     int64_t frame_set_n_frames;
318     /** The number of frame sets in a medium stride step */
319     int64_t medium_stride_length;
320     /** The number of frame sets in a long stride step */
321     int64_t long_stride_length;
322     /** The current (can change from one frame set to another) time length
323      *  (in seconds) of one frame */
324     double time_per_frame;
325
326     /** The number of different kinds of molecules in the trajectory */
327     int64_t n_molecules;
328     /** A list of molecules in the trajectory */
329     tng_molecule_t molecules;
330     /** A list of the count of each molecule - if using variable number of
331      *  particles this will be specified in each frame set */
332     int64_t *molecule_cnt_list;
333     /** The total number of particles/atoms. If using variable number of
334      *  particles this will be specified in each frame set */
335     int64_t n_particles;
336
337      /** The pos in the src file of the first frame set */
338     int64_t first_trajectory_frame_set_input_file_pos;
339     /** The pos in the dest file of the first frame set */
340     int64_t first_trajectory_frame_set_output_file_pos;
341     /** The pos in the src file of the last frame set */
342     int64_t last_trajectory_frame_set_input_file_pos;
343     /** The pos in the dest file of the last frame set */
344     int64_t last_trajectory_frame_set_output_file_pos;
345     /** The currently active frame set */
346     struct tng_trajectory_frame_set current_trajectory_frame_set;
347     /** The pos in the src file of the current frame set */
348     long current_trajectory_frame_set_input_file_pos;
349     /** The pos in the dest file of the current frame set */
350     long current_trajectory_frame_set_output_file_pos;
351     /** The number of frame sets in the trajectory N.B. Not saved in file and
352      *  cannot be trusted to be up-to-date */
353     int64_t n_trajectory_frame_sets;
354
355     /** The number of trajectory blocks in the file */
356     int64_t n_trajectory_blocks;
357
358     /* These data blocks are non-trajectory data blocks */
359     /** The number of non-frame dependent particle dependent data blocks */
360     int n_particle_data_blocks;
361     /** A list of data blocks containing particle dependent data */
362     struct tng_particle_data *non_tr_particle_data;
363
364     /** The number of frame and particle independent data blocks */
365     int n_data_blocks;
366     /** A list of frame and particle indepdendent data blocks */
367     struct tng_non_particle_data *non_tr_data;
368
369     /** TNG compression algorithm for compressing positions */
370     int *compress_algo_pos;
371     /** TNG compression algorithm for compressing velocities */
372     int *compress_algo_vel;
373     /** The precision used for lossy compression */
374     double compression_precision;
375 };
376
377 #ifndef USE_WINDOWS
378 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
379 #define USE_WINDOWS
380 #endif /* win32... */
381 #endif /* not defined USE_WINDOWS */
382
383 #ifdef USE_WINDOWS
384 #define TNG_INLINE __inline
385 #define TNG_SNPRINTF _snprintf
386 #else
387 #define TNG_INLINE inline
388 #define TNG_SNPRINTF snprintf
389 #endif
390
391 static TNG_INLINE int tng_min_i(int a, int b)
392 {
393     return (a < b ? a : b);
394 }
395
396 /*
397 static TNG_INLINE int tng_max_i(int a, int b)
398 {
399     return (a > b ? a : b);
400 }
401 */
402 static TNG_INLINE int64_t tng_min_i64(int64_t a, int64_t b)
403 {
404     return (a < b ? a : b);
405 }
406
407 static TNG_INLINE int64_t tng_max_i64(int64_t a, int64_t b)
408 {
409     return (a > b ? a : b);
410 }
411
412 /*
413 static TNG_INLINE float tng_min_f(float a, float b)
414 {
415     return (a < b ? a : b);
416 }
417
418 static TNG_INLINE float tng_max_f(float a, float b)
419 {
420     return (a > b ? a : b);
421 }
422
423 static TNG_INLINE double tng_min_d(double a, double b)
424 {
425     return (a < b ? a : b);
426 }
427
428 static TNG_INLINE double tng_max_d(double a, double b)
429 {
430     return (a > b ? a : b);
431 }
432 */
433
434 /** This function swaps the byte order of a 32 bit numerical variable
435  * to big endian.
436  * It does not only work with integer, but e.g. floats need casting.
437  * If the byte order is already big endian no change is needed.
438  * @param tng_data is a trajectory data container.
439  * @param v is a pointer to a 32 bit numerical value (float or integer).
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_32
444                 (const tng_trajectory_t tng_data, int32_t *v)
445 {
446     switch(tng_data->endianness_32)
447     {
448     case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
449         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
450              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
451              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
452              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
453
454         return(TNG_SUCCESS);
455
456     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
457         *v = ((*v & 0xFFFF0000) >> 16) |
458              ((*v & 0x0000FFFF) << 16);
459
460         return(TNG_SUCCESS);
461
462     case TNG_BIG_ENDIAN_32: /* Already correct */
463         return(TNG_SUCCESS);
464
465     default:
466         return(TNG_FAILURE);
467     }
468 }
469
470 /** This function swaps the byte order of a 64 bit numerical variable
471  * to big endian.
472  * It does not only work with integer, but e.g. floats need casting.
473  * The byte order swapping routine can convert four different byte
474  * orders to big endian.
475  * If the byte order is already big endian no change is needed.
476  * @param tng_data is a trajectory data container.
477  * @param v is a pointer to a 64 bit numerical value (double or integer).
478  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
479  * byte order is not recognised.
480  */
481 static tng_function_status tng_swap_byte_order_big_endian_64
482                 (const tng_trajectory_t tng_data, int64_t *v)
483 {
484     switch(tng_data->endianness_64)
485     {
486     case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
487         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
488              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
489              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
490              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
491              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
492              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
493              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
494              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
495
496         return(TNG_SUCCESS);
497
498     case TNG_QUAD_SWAP_64: /* Byte quad swap */
499         *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
500              ((*v & 0x00000000FFFFFFFFLL) << 32);
501
502         return(TNG_SUCCESS);
503
504     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
505         *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
506              ((*v & 0x0000FFFF0000FFFFLL) << 16);
507
508         return(TNG_SUCCESS);
509
510     case TNG_BYTE_SWAP_64: /* Byte swap */
511         *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
512              ((*v & 0x00FF00FF00FF00FFLL) << 8);
513
514         return(TNG_SUCCESS);
515
516     case TNG_BIG_ENDIAN_64: /* Already correct */
517         return(TNG_SUCCESS);
518
519     default:
520         return(TNG_FAILURE);
521     }
522 }
523
524 /** This function swaps the byte order of a 32 bit numerical variable
525  * to little endian.
526  * It does not only work with integer, but e.g. floats need casting.
527  * If the byte order is already little endian no change is needed.
528  * @param tng_data is a trajectory data container.
529  * @param v is a pointer to a 32 bit numerical value (float or integer).
530  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
531  * byte order is not recognised.
532  */
533 static tng_function_status tng_swap_byte_order_little_endian_32
534                 (const tng_trajectory_t tng_data, int32_t *v)
535 {
536     switch(tng_data->endianness_32)
537     {
538     case TNG_LITTLE_ENDIAN_32: /* Already correct */
539         return(TNG_SUCCESS);
540
541     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
542         *v = ((*v & 0xFF00FF00) >> 8) |
543              ((*v & 0x00FF00FF) << 8);
544
545         return(TNG_SUCCESS);
546
547     case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
548         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
549              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
550              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
551              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
552
553         return(TNG_SUCCESS);
554
555     default:
556         return(TNG_FAILURE);
557     }
558 }
559
560 /** This function swaps the byte order of a 64 bit numerical variable
561  * to little endian.
562  * It does not only work with integer, but e.g. floats need casting.
563  * The byte order swapping routine can convert four different byte
564  * orders to little endian.
565  * If the byte order is already little endian no change is needed.
566  * @param tng_data is a trajectory data container.
567  * @param v is a pointer to a 64 bit numerical value (double or integer).
568  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
569  * byte order is not recognised.
570  */
571 static tng_function_status tng_swap_byte_order_little_endian_64
572                 (const tng_trajectory_t tng_data, int64_t *v)
573 {
574     switch(tng_data->endianness_64)
575     {
576     case TNG_LITTLE_ENDIAN_64: /* Already correct */
577         return(TNG_SUCCESS);
578
579     case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
580         *v = ((*v & 0xFF000000FF000000LL) >> 24) |
581              ((*v & 0x00FF000000FF0000LL) >> 8) |
582              ((*v & 0x0000FF000000FF00LL) << 8) |
583              ((*v & 0x000000FF000000FFLL) << 24);
584
585         return(TNG_SUCCESS);
586
587     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
588         *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
589              ((*v & 0x00FF00FF00000000LL) >> 24) |
590              ((*v & 0x00000000FF00FF00LL) << 24) |
591              ((*v & 0x0000000000FF00FFLL) << 40);
592
593         return(TNG_SUCCESS);
594
595     case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
596         *v = ((*v & 0xFFFF000000000000LL) >> 48) |
597              ((*v & 0x0000FFFF00000000LL) >> 16) |
598              ((*v & 0x00000000FFFF0000LL) << 16) |
599              ((*v & 0x000000000000FFFFLL) << 48);
600
601         return(TNG_SUCCESS);
602
603     case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
604         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
605              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
606              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
607              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
608              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
609              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
610              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
611              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
612
613         return(TNG_SUCCESS);
614
615     default:
616         return(TNG_FAILURE);
617     }
618 }
619 /** Generate the md5 hash of a block.
620  * The hash is created based on the actual block contents.
621  * @param block is a general block container.
622  * @return TNG_SUCCESS (0) if successful.
623  */
624 static tng_function_status tng_block_md5_hash_generate(tng_gen_block_t block)
625 {
626     md5_state_t md5_state;
627
628     md5_init(&md5_state);
629     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
630                (int)block->block_contents_size);
631     md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
632
633     return(TNG_SUCCESS);
634 }
635
636 /** Compare the current block md5 hash (e.g. read from file) with the md5 hash
637  * calculated from the current contents.
638  * If the current md5 hash is not set skip the comparison.
639  * @param block is a general block container.
640  * @param results If the hashes match results is set to TNG_TRUE, otherwise it is
641  * set to TNG_FALSE. If the hash was not set results is set to TNG_TRUE.
642  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the hash was not
643  * set.
644  */
645 static tng_function_status tng_md5_hash_match_verify(tng_gen_block_t block,
646                                                      tng_bool *results)
647 {
648     md5_state_t md5_state;
649     char hash[TNG_MD5_HASH_LEN];
650
651     TNG_ASSERT(block->block_contents_size > 0, "The block contents size must be > 0");
652
653     *results = TNG_TRUE;
654     if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0)
655     {
656         return(TNG_FAILURE);
657     }
658     md5_init(&md5_state);
659     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
660                (int)block->block_contents_size);
661     md5_finish(&md5_state, (md5_byte_t *)hash);
662
663     if(strncmp(block->md5_hash, hash, 16) != 0)
664     {
665         *results = TNG_FALSE;
666     }
667
668     return(TNG_SUCCESS);
669 }
670
671 /** Open the input file if it is not already opened.
672  * @param tng_data is a trajectory data container.
673  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
674  * error has occured.
675  */
676 static tng_function_status tng_input_file_init(tng_trajectory_t tng_data)
677 {
678     if(!tng_data->input_file)
679     {
680         if(!tng_data->input_file_path)
681         {
682             fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
683                    __FILE__, __LINE__);
684             return(TNG_CRITICAL);
685         }
686         tng_data->input_file = fopen(tng_data->input_file_path, "r");
687         if(!tng_data->input_file)
688         {
689             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
690                    tng_data->input_file_path, __FILE__, __LINE__);
691             return(TNG_CRITICAL);
692         }
693     }
694     return(TNG_SUCCESS);
695 }
696
697 /** Open the output file if it is not already opened
698  * @param tng_data is a trajectory data container.
699  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
700  * error has occured.
701  */
702 static tng_function_status tng_output_file_init(tng_trajectory_t tng_data)
703 {
704     if(!tng_data->output_file)
705     {
706         if(!tng_data->output_file_path)
707         {
708             fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
709                    __FILE__, __LINE__);
710             return(TNG_CRITICAL);
711         }
712
713         tng_data->output_file = fopen(tng_data->output_file_path, "w+");
714
715         if(!tng_data->output_file)
716         {
717             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
718                    tng_data->output_file_path, __FILE__, __LINE__);
719             return(TNG_CRITICAL);
720         }
721     }
722     return(TNG_SUCCESS);
723 }
724
725 /** Setup a file block container.
726  * @param block_p a pointer to memory to initialise as a file block container.
727  * @details Memory is allocated during initialisation.
728  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
729  * error has occured.
730  */
731 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
732 {
733     tng_gen_block_t block;
734
735     *block_p = malloc(sizeof(struct tng_gen_block));
736
737     if(!*block_p)
738     {
739         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
740                sizeof(struct tng_gen_block), __FILE__, __LINE__);
741         return(TNG_CRITICAL);
742     }
743
744     block = *block_p;
745
746     block->id = -1;
747     /* Reset the md5_hash */
748     memcpy(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN);
749     block->name = 0;
750     block->block_version = TNG_VERSION;
751     block->header_contents = 0;
752     block->header_contents_size = 0;
753     block->block_contents = 0;
754     block->block_contents_size = 0;
755
756     return(TNG_SUCCESS);
757 }
758
759 /**
760  * @brief Clean up a file block container.
761  * @param block_p a pointer to the file block container to destroy.
762  * @details All allocated memory in the data structure is freed, as well as
763  * block_p itself.
764  * @return TNG_SUCCESS (0) if successful.
765  */
766 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
767 {
768     tng_gen_block_t block = *block_p;
769
770     if(!*block_p)
771     {
772         return(TNG_SUCCESS);
773     }
774
775 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
776     if(block->name)
777     {
778         free(block->name);
779         block->name = 0;
780     }
781     if(block->header_contents)
782     {
783         free(block->header_contents);
784         block->header_contents = 0;
785     }
786     if(block->block_contents)
787     {
788         free(block->block_contents);
789         block->block_contents = 0;
790     }
791
792     free(*block_p);
793     *block_p = 0;
794
795     return(TNG_SUCCESS);
796 }
797
798 /** Read the header of a data block, regardless of its type
799  * @param tng_data is a trajectory data container.
800  * @param block is a general block container.
801  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
802  * error has occured.
803  */
804 static tng_function_status tng_block_header_read
805                 (tng_trajectory_t tng_data, tng_gen_block_t block)
806 {
807     int len, offset = 0;
808
809     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
810
811     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
812     {
813         return(TNG_CRITICAL);
814     }
815
816     /* First read the header size to be able to read the whole header. */
817     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
818         1, tng_data->input_file) == 0)
819     {
820         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
821                __FILE__, __LINE__);
822         return(TNG_CRITICAL);
823     }
824
825     /* If this was the size of the general info block check the endianness */
826     if(ftell(tng_data->input_file) < 9)
827     {
828         /* File is little endian */
829         if ( *((const char*)&block->header_contents_size) != 0x00 &&
830              *((const char*)(&block->header_contents_size) + 7) == 0x00)
831         {
832             /* If the architecture endianness is little endian no byte swap
833              * will be needed. Otherwise use the functions to swap to little
834              * endian */
835             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
836             {
837                 tng_data->input_endianness_swap_func_32 = 0;
838             }
839             else
840             {
841                 tng_data->input_endianness_swap_func_32 =
842                 &tng_swap_byte_order_little_endian_32;
843             }
844             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
845             {
846                 tng_data->input_endianness_swap_func_64 = 0;
847             }
848             else
849             {
850                 tng_data->input_endianness_swap_func_64 =
851                 &tng_swap_byte_order_little_endian_64;
852             }
853         }
854         /* File is big endian */
855         else
856         {
857             /* If the architecture endianness is big endian no byte swap
858              * will be needed. Otherwise use the functions to swap to big
859              * endian */
860             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
861             {
862                 tng_data->input_endianness_swap_func_32 = 0;
863             }
864             else
865             {
866                 tng_data->input_endianness_swap_func_32 =
867                 &tng_swap_byte_order_big_endian_32;
868             }
869             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
870             {
871                 tng_data->input_endianness_swap_func_64 = 0;
872             }
873             else
874             {
875                 tng_data->input_endianness_swap_func_64 =
876                 &tng_swap_byte_order_big_endian_64;
877             }
878         }
879     }
880
881     if(tng_data->input_endianness_swap_func_64)
882     {
883         if(tng_data->input_endianness_swap_func_64(tng_data,
884                                                    &block->header_contents_size)
885             != TNG_SUCCESS)
886         {
887             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
888                     __FILE__, __LINE__);
889         }
890     }
891
892     /* Move the reading position to the beginning of the header. */
893     fseek(tng_data->input_file, -(long)sizeof(block->header_contents_size),
894           SEEK_CUR);
895
896     /* If there is already memory allocated for the contents free it (we do not
897      * know if the size is correct). */
898     if(block->header_contents)
899     {
900         free(block->header_contents);
901     }
902
903     block->header_contents = malloc(block->header_contents_size);
904     if(!block->header_contents)
905     {
906         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
907                block->header_contents_size, __FILE__, __LINE__);
908         return(TNG_CRITICAL);
909     }
910
911     /* Read the whole header into header_contents. This way it can be saved
912      * even if it cannot be interpreted
913      * for one reason or another. */
914     if(fread(block->header_contents, block->header_contents_size, 1,
915         tng_data->input_file) == 0)
916     {
917         fprintf(stderr, "TNG library: Cannot read header. %s: %d\n", __FILE__, __LINE__);
918         return(TNG_CRITICAL);
919     }
920
921     /* The header contents size has already been read. Skip ahead. */
922     offset = sizeof(block->header_contents_size);
923
924
925     /* Copy the respective parameters from the header contents block */
926     memcpy(&block->block_contents_size, block->header_contents+offset,
927            sizeof(block->block_contents_size));
928     if(tng_data->input_endianness_swap_func_64)
929     {
930         if(tng_data->input_endianness_swap_func_64(tng_data,
931                                                    &block->block_contents_size)
932             != TNG_SUCCESS)
933         {
934             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
935                     __FILE__, __LINE__);
936         }
937     }
938
939     offset += sizeof(block->block_contents_size);
940
941     memcpy(&block->id, block->header_contents+offset, sizeof(block->id));
942     if(tng_data->input_endianness_swap_func_64)
943     {
944         if(tng_data->input_endianness_swap_func_64(tng_data,
945                                                    &block->id)
946             != TNG_SUCCESS)
947         {
948             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
949                     __FILE__, __LINE__);
950         }
951     }
952
953     offset += sizeof(block->id);
954
955     memcpy(block->md5_hash, block->header_contents+offset, TNG_MD5_HASH_LEN);
956     offset += TNG_MD5_HASH_LEN;
957
958     if(block->name && strcmp(block->name, block->header_contents+offset) != 0)
959     {
960         free(block->name);
961         block->name = 0;
962     }
963     len = tng_min_i((int)strlen(block->header_contents+offset) + 1, TNG_MAX_STR_LEN);
964     if(!block->name)
965     {
966         block->name = malloc(len);
967         if(!block->name)
968         {
969             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
970                     __FILE__, __LINE__);
971             return(TNG_CRITICAL);
972         }
973         strncpy(block->name, block->header_contents+offset, len);
974     }
975     offset += len;
976
977     memcpy(&block->block_version, block->header_contents+offset,
978            sizeof(block->block_version));
979     if(tng_data->input_endianness_swap_func_64)
980     {
981         if(tng_data->input_endianness_swap_func_64(tng_data,
982                                                    &block->block_version)
983             != TNG_SUCCESS)
984         {
985             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
986                     __FILE__, __LINE__);
987         }
988     }
989
990     return(TNG_SUCCESS);
991 }
992
993 /** Write a whole block, both header and contents, regardless of it type
994  * @param tng_data is a trajectory data container.
995  * @param block is a general block container.
996  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
997  * has occurred or TNG_CRITICAL (2) if a major error has occured.
998  */
999 /* Disabled until it is used.*/
1000 /*
1001 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1002 //                                                     tng_gen_block_t block)
1003 // {
1004 //     if(!block->header_contents)
1005 //     {
1006 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1007 //         return(TNG_FAILURE);
1008 //     }
1009 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1010 //                 tng_data->output_file) != 1)
1011 //     {
1012 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1013 //                 __FILE__, __LINE__);
1014 //         return(TNG_CRITICAL);
1015 //     }
1016 //
1017 //     if(!block->block_contents)
1018 //     {
1019 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1020 //                 __FILE__, __LINE__);
1021 //         return(TNG_FAILURE);
1022 //     }
1023 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1024 //                 tng_data->output_file) != 1)
1025 //     {
1026 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1027 //                 __FILE__, __LINE__);
1028 //         return(TNG_CRITICAL);
1029 //     }
1030 //     return(TNG_SUCCESS);
1031 // }
1032 */
1033 /** Write the header of a data block, regardless of its type
1034  * @param tng_data is a trajectory data container.
1035  * @param block is a general block container.
1036  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1037  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1038  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1039  * error has occured.
1040  */
1041 static tng_function_status tng_block_header_write
1042                 (tng_trajectory_t tng_data,
1043                  tng_gen_block_t block,
1044                  const char hash_mode)
1045 {
1046     int name_len, offset = 0;
1047
1048     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
1049
1050     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1051     {
1052         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1053                __FILE__, __LINE__);
1054         return(TNG_CRITICAL);
1055     }
1056
1057     if(!block->name)
1058     {
1059         block->name = malloc(1);
1060         if(!block->name)
1061         {
1062             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1063                    __FILE__, __LINE__);
1064             return(TNG_CRITICAL);
1065         }
1066         block->name[0] = 0;
1067     }
1068
1069     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1070
1071     if(hash_mode == TNG_USE_HASH)
1072     {
1073         tng_block_md5_hash_generate(block);
1074     }
1075
1076     /* Calculate the size of the header to write */
1077     block->header_contents_size = sizeof(block->header_contents_size) +
1078                                   sizeof(block->block_contents_size) +
1079                                   sizeof(block->id) +
1080                                   sizeof(block->block_version) +
1081                                   TNG_MD5_HASH_LEN +
1082                                   name_len;
1083
1084     if(block->header_contents)
1085     {
1086         free(block->header_contents);
1087     }
1088
1089     block->header_contents = malloc(block->header_contents_size);
1090     if(!block->header_contents)
1091     {
1092         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1093                block->header_contents_size, __FILE__, __LINE__);
1094         return(TNG_CRITICAL);
1095     }
1096
1097     /* First copy all data into the header_contents block and finally write
1098      * the whole block at once. */
1099     memcpy(block->header_contents, &block->header_contents_size,
1100            sizeof(block->header_contents_size));
1101     if(tng_data->output_endianness_swap_func_64)
1102     {
1103         if(tng_data->output_endianness_swap_func_64(tng_data,
1104                                       (int64_t *)block->header_contents+offset)
1105             != TNG_SUCCESS)
1106         {
1107             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1108                     __FILE__, __LINE__);
1109         }
1110     }
1111     offset += sizeof(block->header_contents_size);
1112
1113     memcpy(block->header_contents+offset, &block->block_contents_size,
1114            sizeof(block->block_contents_size));
1115     if(tng_data->output_endianness_swap_func_64)
1116     {
1117         if(tng_data->output_endianness_swap_func_64(tng_data,
1118                                       (int64_t *)block->header_contents+offset)
1119             != TNG_SUCCESS)
1120         {
1121             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1122                     __FILE__, __LINE__);
1123         }
1124     }
1125     offset += sizeof(block->block_contents_size);
1126
1127     memcpy(block->header_contents+offset, &block->id, sizeof(block->id));
1128     if(tng_data->output_endianness_swap_func_64)
1129     {
1130         if(tng_data->output_endianness_swap_func_64(tng_data,
1131                                       (int64_t *)block->header_contents+offset)
1132             != TNG_SUCCESS)
1133         {
1134             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1135                     __FILE__, __LINE__);
1136         }
1137     }
1138     offset += sizeof(block->id);
1139
1140     memcpy(block->header_contents+offset, block->md5_hash, TNG_MD5_HASH_LEN);
1141     offset += TNG_MD5_HASH_LEN;
1142
1143     strncpy(block->header_contents+offset, block->name, name_len);
1144     offset += name_len;
1145
1146     memcpy(block->header_contents+offset, &block->block_version,
1147            sizeof(block->block_version));
1148     if(tng_data->output_endianness_swap_func_64)
1149     {
1150         if(tng_data->output_endianness_swap_func_64(tng_data,
1151                                       (int64_t *)block->header_contents+offset)
1152             != TNG_SUCCESS)
1153         {
1154             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1155                     __FILE__, __LINE__);
1156         }
1157     }
1158
1159     if(fwrite(block->header_contents, block->header_contents_size,
1160        1, tng_data->output_file) != 1)
1161     {
1162         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__);
1163         return(TNG_CRITICAL);
1164     }
1165     return(TNG_SUCCESS);
1166 }
1167
1168 /** Read a general info block. This is the first block of a TNG file.
1169  *  Populate the fields in tng_data.
1170  * @param tng_data is a trajectory data container.
1171  * @param block is a general block container.
1172  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1173  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
1174  * compared to the md5 hash of the read contents to ensure valid data.
1175  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1176  * error has occured.
1177  */
1178 static tng_function_status tng_general_info_block_read
1179                 (tng_trajectory_t tng_data, tng_gen_block_t block,
1180                  const char hash_mode)
1181 {
1182     int len, offset = 0;
1183     tng_bool same_hash;
1184
1185     void *temp;
1186
1187     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
1188
1189     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1190     {
1191         return(TNG_CRITICAL);
1192     }
1193
1194     temp = realloc(block->block_contents, block->block_contents_size);
1195     if(!temp)
1196     {
1197         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1198                block->block_contents_size, __FILE__, __LINE__);
1199         free(block->block_contents);
1200         block->block_contents = 0;
1201         return(TNG_CRITICAL);
1202     }
1203     block->block_contents = temp;
1204
1205     /* Read the whole block into block_contents to be able to write it to disk
1206      * even if it cannot be interpreted. */
1207     if(fread(block->block_contents, block->block_contents_size, 1,
1208              tng_data->input_file) == 0)
1209     {
1210         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1211         return(TNG_CRITICAL);
1212     }
1213
1214     /* FIXME: Does not check if the size of the contents matches the expected
1215      * size or if the contents can be read. */
1216
1217     if(hash_mode == TNG_USE_HASH)
1218     {
1219         tng_md5_hash_match_verify(block, &same_hash);
1220         if(same_hash != TNG_TRUE)
1221         {
1222             fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
1223                 "%s: %d\n",
1224                 __FILE__, __LINE__);
1225     /*         return(TNG_FAILURE); */
1226         }
1227     }
1228
1229     len = tng_min_i((int)strlen(block->block_contents) + 1, TNG_MAX_STR_LEN);
1230     temp = realloc(tng_data->first_program_name, len);
1231     if(!temp)
1232     {
1233         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1234                __FILE__, __LINE__);
1235         free(tng_data->first_program_name);
1236         tng_data->first_program_name = 0;
1237         return(TNG_CRITICAL);
1238     }
1239     tng_data->first_program_name = temp;
1240     strncpy(tng_data->first_program_name, block->block_contents, len);
1241     offset += len;
1242
1243     len = tng_min_i((int)strlen(block->block_contents + offset) + 1, TNG_MAX_STR_LEN);
1244     temp = realloc(tng_data->last_program_name, len);
1245     if(!temp)
1246     {
1247         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1248                __FILE__, __LINE__);
1249         free(tng_data->last_program_name);
1250         tng_data->last_program_name = 0;
1251         return(TNG_CRITICAL);
1252     }
1253     tng_data->last_program_name = temp;
1254     strncpy(tng_data->last_program_name, block->block_contents + offset, len);
1255     offset += len;
1256
1257     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1258     temp = realloc(tng_data->first_user_name, len);
1259     if(!temp)
1260     {
1261         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1262                __FILE__, __LINE__);
1263         free(tng_data->first_user_name);
1264         tng_data->first_user_name = 0;
1265         return(TNG_CRITICAL);
1266     }
1267     tng_data->first_user_name = temp;
1268     strncpy(tng_data->first_user_name, block->block_contents+offset, len);
1269     offset += len;
1270
1271     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1272     temp = realloc(tng_data->last_user_name, len);
1273     if(!temp)
1274     {
1275         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1276                __FILE__, __LINE__);
1277         free(tng_data->last_user_name);
1278         tng_data->last_user_name = 0;
1279         return(TNG_CRITICAL);
1280     }
1281     tng_data->last_user_name = temp;
1282     strncpy(tng_data->last_user_name, block->block_contents+offset, len);
1283     offset += len;
1284
1285     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1286     temp = realloc(tng_data->first_computer_name, len);
1287     if(!temp)
1288     {
1289         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1290                __FILE__, __LINE__);
1291         free(tng_data->first_computer_name);
1292         tng_data->first_computer_name = 0;
1293         return(TNG_CRITICAL);
1294     }
1295     tng_data->first_computer_name = temp;
1296     strncpy(tng_data->first_computer_name, block->block_contents+offset, len);
1297     offset += len;
1298
1299     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1300     temp = realloc(tng_data->last_computer_name, len);
1301     if(!temp)
1302     {
1303         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1304                __FILE__, __LINE__);
1305         free(tng_data->last_computer_name);
1306         tng_data->last_computer_name = 0;
1307         return(TNG_CRITICAL);
1308     }
1309     tng_data->last_computer_name = temp;
1310     strncpy(tng_data->last_computer_name, block->block_contents+offset, len);
1311     offset += len;
1312
1313     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1314     temp = realloc(tng_data->first_pgp_signature, len);
1315     if(!temp)
1316     {
1317         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1318                __FILE__, __LINE__);
1319         free(tng_data->first_pgp_signature);
1320         tng_data->first_pgp_signature = 0;
1321         return(TNG_CRITICAL);
1322     }
1323     tng_data->first_pgp_signature = temp;
1324     strncpy(tng_data->first_pgp_signature, block->block_contents+offset, len);
1325     offset += len;
1326
1327     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1328     temp = realloc(tng_data->last_pgp_signature, len);
1329     if(!temp)
1330     {
1331         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1332                __FILE__, __LINE__);
1333         free(tng_data->last_pgp_signature);
1334         tng_data->last_pgp_signature = 0;
1335         return(TNG_CRITICAL);
1336     }
1337     tng_data->last_pgp_signature = temp;
1338     strncpy(tng_data->last_pgp_signature, block->block_contents+offset, len);
1339     offset += len;
1340
1341     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1342     temp = realloc(tng_data->forcefield_name, len);
1343     if(!temp)
1344     {
1345         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1346                __FILE__, __LINE__);
1347         free(tng_data->forcefield_name);
1348         tng_data->forcefield_name = 0;
1349         return(TNG_CRITICAL);
1350     }
1351     tng_data->forcefield_name = temp;
1352     strncpy(tng_data->forcefield_name, block->block_contents+offset, len);
1353     offset += len;
1354
1355     memcpy(&tng_data->time, block->block_contents+offset,
1356            sizeof(tng_data->time));
1357     if(tng_data->input_endianness_swap_func_64)
1358     {
1359         if(tng_data->input_endianness_swap_func_64(tng_data,
1360                                                    &tng_data->time)
1361             != TNG_SUCCESS)
1362         {
1363             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1364                     __FILE__, __LINE__);
1365         }
1366     }
1367     offset += sizeof(tng_data->time);
1368
1369     memcpy(&tng_data->var_num_atoms_flag, block->block_contents+offset,
1370            sizeof(tng_data->var_num_atoms_flag));
1371     offset += sizeof(tng_data->var_num_atoms_flag);
1372
1373     memcpy(&tng_data->frame_set_n_frames, block->block_contents+offset,
1374            sizeof(tng_data->frame_set_n_frames));
1375     if(tng_data->input_endianness_swap_func_64)
1376     {
1377         if(tng_data->input_endianness_swap_func_64(tng_data,
1378                                                  &tng_data->frame_set_n_frames)
1379             != TNG_SUCCESS)
1380         {
1381             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1382                     __FILE__, __LINE__);
1383         }
1384     }
1385     offset += sizeof(tng_data->frame_set_n_frames);
1386
1387     memcpy(&tng_data->first_trajectory_frame_set_input_file_pos,
1388            block->block_contents+offset,
1389            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
1390     if(tng_data->input_endianness_swap_func_64)
1391     {
1392         if(tng_data->input_endianness_swap_func_64(tng_data,
1393                           &tng_data->first_trajectory_frame_set_input_file_pos)
1394             != TNG_SUCCESS)
1395         {
1396             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1397                     __FILE__, __LINE__);
1398         }
1399     }
1400     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
1401
1402     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
1403     tng_data->first_trajectory_frame_set_input_file_pos;
1404
1405
1406     memcpy(&tng_data->last_trajectory_frame_set_input_file_pos,
1407            block->block_contents+offset,
1408            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
1409     if(tng_data->input_endianness_swap_func_64)
1410     {
1411         if(tng_data->input_endianness_swap_func_64(tng_data,
1412                           &tng_data->last_trajectory_frame_set_input_file_pos)
1413             != TNG_SUCCESS)
1414         {
1415             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1416                     __FILE__, __LINE__);
1417         }
1418     }
1419     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
1420
1421     memcpy(&tng_data->medium_stride_length, block->block_contents+offset,
1422            sizeof(tng_data->medium_stride_length));
1423     if(tng_data->input_endianness_swap_func_64)
1424     {
1425         if(tng_data->input_endianness_swap_func_64(tng_data,
1426                                                &tng_data->medium_stride_length)
1427             != TNG_SUCCESS)
1428         {
1429             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1430                     __FILE__, __LINE__);
1431         }
1432     }
1433     offset += sizeof(tng_data->medium_stride_length);
1434
1435     memcpy(&tng_data->long_stride_length, block->block_contents+offset,
1436            sizeof(tng_data->long_stride_length));
1437     if(tng_data->input_endianness_swap_func_64)
1438     {
1439         if(tng_data->input_endianness_swap_func_64(tng_data,
1440                                                  &tng_data->long_stride_length)
1441             != TNG_SUCCESS)
1442         {
1443             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1444                     __FILE__, __LINE__);
1445         }
1446     }
1447     offset += sizeof(tng_data->long_stride_length);
1448
1449     if(block->block_version >= 3)
1450     {
1451         memcpy(&tng_data->distance_unit_exponential, block->block_contents+offset,
1452             sizeof(tng_data->distance_unit_exponential));
1453         if(tng_data->input_endianness_swap_func_64)
1454         {
1455             if(tng_data->input_endianness_swap_func_64(tng_data,
1456                                           &tng_data->distance_unit_exponential)
1457                 != TNG_SUCCESS)
1458             {
1459                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1460                         __FILE__, __LINE__);
1461             }
1462         }
1463     }
1464
1465     return(TNG_SUCCESS);
1466 }
1467
1468 /** Write a general info block. This is the first block of a TNG file.
1469  * @param tng_data is a trajectory data container.
1470  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1471  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1472  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1473  * error has occured.
1474  */
1475 static tng_function_status tng_general_info_block_write
1476                 (tng_trajectory_t tng_data,
1477                  const char hash_mode)
1478 {
1479     int first_program_name_len, first_user_name_len;
1480     int first_computer_name_len, first_pgp_signature_len;
1481     int last_program_name_len, last_user_name_len;
1482     int last_computer_name_len, last_pgp_signature_len;
1483     int forcefield_name_len, name_len;
1484     int offset = 0;
1485     tng_gen_block_t block;
1486
1487     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1488     {
1489         return(TNG_CRITICAL);
1490     }
1491
1492     fseek(tng_data->output_file, 0, SEEK_SET);
1493
1494     /* If the strings are unallocated allocate memory for just string
1495      * termination */
1496     if(!tng_data->first_program_name)
1497     {
1498         tng_data->first_program_name = malloc(1);
1499         if(!tng_data->first_program_name)
1500         {
1501             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1502                    __FILE__, __LINE__);
1503             return(TNG_CRITICAL);
1504         }
1505         tng_data->first_program_name[0] = 0;
1506     }
1507     if(!tng_data->last_program_name)
1508     {
1509         tng_data->last_program_name = malloc(1);
1510         if(!tng_data->last_program_name)
1511         {
1512             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1513                    __FILE__, __LINE__);
1514             return(TNG_CRITICAL);
1515         }
1516         tng_data->last_program_name[0] = 0;
1517     }
1518     if(!tng_data->first_user_name)
1519     {
1520         tng_data->first_user_name = malloc(1);
1521         if(!tng_data->first_user_name)
1522         {
1523             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1524                    __FILE__, __LINE__);
1525             return(TNG_CRITICAL);
1526         }
1527         tng_data->first_user_name[0] = 0;
1528     }
1529     if(!tng_data->last_user_name)
1530     {
1531         tng_data->last_user_name = malloc(1);
1532         if(!tng_data->last_user_name)
1533         {
1534             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1535                    __FILE__, __LINE__);
1536             return(TNG_CRITICAL);
1537         }
1538         tng_data->last_user_name[0] = 0;
1539     }
1540     if(!tng_data->first_computer_name)
1541     {
1542         tng_data->first_computer_name = malloc(1);
1543         if(!tng_data->first_computer_name)
1544         {
1545             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1546                    __FILE__, __LINE__);
1547             return(TNG_CRITICAL);
1548         }
1549         tng_data->first_computer_name[0] = 0;
1550     }
1551     if(!tng_data->last_computer_name)
1552     {
1553         tng_data->last_computer_name = malloc(1);
1554         if(!tng_data->last_computer_name)
1555         {
1556             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1557                    __FILE__, __LINE__);
1558             return(TNG_CRITICAL);
1559         }
1560         tng_data->last_computer_name[0] = 0;
1561     }
1562     if(!tng_data->first_pgp_signature)
1563     {
1564         tng_data->first_pgp_signature = malloc(1);
1565         if(!tng_data->first_pgp_signature)
1566         {
1567             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1568                    __FILE__, __LINE__);
1569             return(TNG_CRITICAL);
1570         }
1571         tng_data->first_pgp_signature[0] = 0;
1572     }
1573     if(!tng_data->last_pgp_signature)
1574     {
1575         tng_data->last_pgp_signature = malloc(1);
1576         if(!tng_data->last_pgp_signature)
1577         {
1578             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1579                    __FILE__, __LINE__);
1580             return(TNG_CRITICAL);
1581         }
1582         tng_data->last_pgp_signature[0] = 0;
1583     }
1584     if(!tng_data->forcefield_name)
1585     {
1586         tng_data->forcefield_name = malloc(1);
1587         if(!tng_data->forcefield_name)
1588         {
1589             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1590                    __FILE__, __LINE__);
1591             return(TNG_CRITICAL);
1592         }
1593         tng_data->forcefield_name[0] = 0;
1594     }
1595
1596     tng_block_init(&block);
1597
1598     name_len = (int)strlen("GENERAL INFO");
1599
1600     block->name = malloc(name_len + 1);
1601     if(!block->name)
1602     {
1603         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
1604                 name_len+1, __FILE__, __LINE__);
1605         tng_block_destroy(&block);
1606         return(TNG_CRITICAL);
1607     }
1608
1609     strcpy(block->name, "GENERAL INFO");
1610     block->id = TNG_GENERAL_INFO;
1611
1612     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
1613                            TNG_MAX_STR_LEN);
1614     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
1615                            TNG_MAX_STR_LEN);
1616     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
1617                         TNG_MAX_STR_LEN);
1618     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
1619                         TNG_MAX_STR_LEN);
1620     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
1621                             TNG_MAX_STR_LEN);
1622     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
1623                             TNG_MAX_STR_LEN);
1624     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
1625                             TNG_MAX_STR_LEN);
1626     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
1627                             TNG_MAX_STR_LEN);
1628     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
1629                               TNG_MAX_STR_LEN);
1630
1631     block->block_contents_size = sizeof(tng_data->time) +
1632                 sizeof(tng_data->var_num_atoms_flag) +
1633                 sizeof(tng_data->frame_set_n_frames) +
1634                 sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
1635                 sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
1636                 sizeof(tng_data->medium_stride_length) +
1637                 sizeof(tng_data->long_stride_length) +
1638                 sizeof(tng_data->distance_unit_exponential) +
1639                 first_program_name_len +
1640                 last_program_name_len +
1641                 first_user_name_len +
1642                 last_user_name_len +
1643                 first_computer_name_len +
1644                 last_computer_name_len +
1645                 first_pgp_signature_len +
1646                 last_pgp_signature_len +
1647                 forcefield_name_len;
1648
1649     if(block->block_contents)
1650     {
1651         free(block->block_contents);
1652     }
1653     block->block_contents = malloc(block->block_contents_size);
1654     if(!block->block_contents)
1655     {
1656         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1657                block->block_contents_size, __FILE__, __LINE__);
1658         tng_block_destroy(&block);
1659         return(TNG_CRITICAL);
1660     }
1661
1662     strncpy(block->block_contents, tng_data->first_program_name, first_program_name_len);
1663     offset += first_program_name_len;
1664
1665     strncpy(block->block_contents+offset, tng_data->last_program_name, last_program_name_len);
1666     offset += last_program_name_len;
1667
1668     strncpy(block->block_contents+offset, tng_data->first_user_name, first_user_name_len);
1669     offset += first_user_name_len;
1670
1671     strncpy(block->block_contents+offset, tng_data->last_user_name, last_user_name_len);
1672     offset += last_user_name_len;
1673
1674     strncpy(block->block_contents+offset, tng_data->first_computer_name,
1675             first_computer_name_len);
1676     offset += first_computer_name_len;
1677
1678     strncpy(block->block_contents+offset, tng_data->last_computer_name,
1679             last_computer_name_len);
1680     offset += last_computer_name_len;
1681
1682     strncpy(block->block_contents+offset, tng_data->first_pgp_signature,
1683             first_pgp_signature_len);
1684     offset += first_pgp_signature_len;
1685
1686     strncpy(block->block_contents+offset, tng_data->last_pgp_signature,
1687             last_pgp_signature_len);
1688     offset += last_pgp_signature_len;
1689
1690     strncpy(block->block_contents+offset, tng_data->forcefield_name,
1691             forcefield_name_len);
1692     offset += forcefield_name_len;
1693
1694     memcpy(block->block_contents+offset, &tng_data->time,
1695            sizeof(tng_data->time));
1696     if(tng_data->output_endianness_swap_func_64)
1697     {
1698         if(tng_data->output_endianness_swap_func_64(tng_data,
1699                                       (int64_t *)block->header_contents+offset)
1700             != TNG_SUCCESS)
1701         {
1702             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1703                     __FILE__, __LINE__);
1704         }
1705     }
1706     offset += sizeof(tng_data->time);
1707
1708     memcpy(block->block_contents+offset, &tng_data->var_num_atoms_flag,
1709            sizeof(tng_data->var_num_atoms_flag));
1710     offset += sizeof(tng_data->var_num_atoms_flag);
1711
1712     memcpy(block->block_contents+offset, &tng_data->frame_set_n_frames,
1713            sizeof(tng_data->frame_set_n_frames));
1714     if(tng_data->output_endianness_swap_func_64)
1715     {
1716         if(tng_data->output_endianness_swap_func_64(tng_data,
1717                                       (int64_t *)block->header_contents+offset)
1718             != TNG_SUCCESS)
1719         {
1720             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1721                     __FILE__, __LINE__);
1722         }
1723     }
1724     offset += sizeof(tng_data->frame_set_n_frames);
1725
1726     memcpy(block->block_contents+offset,
1727            &tng_data->first_trajectory_frame_set_input_file_pos,
1728            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
1729     if(tng_data->output_endianness_swap_func_64)
1730     {
1731         if(tng_data->output_endianness_swap_func_64(tng_data,
1732                                       (int64_t *)block->header_contents+offset)
1733             != TNG_SUCCESS)
1734         {
1735             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1736                     __FILE__, __LINE__);
1737         }
1738     }
1739     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
1740
1741     memcpy(block->block_contents+offset,
1742            &tng_data->last_trajectory_frame_set_input_file_pos,
1743            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
1744     if(tng_data->output_endianness_swap_func_64)
1745     {
1746         if(tng_data->output_endianness_swap_func_64(tng_data,
1747                                       (int64_t *)block->header_contents+offset)
1748             != TNG_SUCCESS)
1749         {
1750             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1751                     __FILE__, __LINE__);
1752         }
1753     }
1754     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
1755
1756     memcpy(block->block_contents+offset, &tng_data->medium_stride_length,
1757            sizeof(tng_data->medium_stride_length));
1758     if(tng_data->output_endianness_swap_func_64)
1759     {
1760         if(tng_data->output_endianness_swap_func_64(tng_data,
1761                                       (int64_t *)block->header_contents+offset)
1762             != TNG_SUCCESS)
1763         {
1764             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1765                     __FILE__, __LINE__);
1766         }
1767     }
1768     offset += sizeof(tng_data->medium_stride_length);
1769
1770     memcpy(block->block_contents+offset, &tng_data->long_stride_length,
1771            sizeof(tng_data->long_stride_length));
1772     if(tng_data->output_endianness_swap_func_64)
1773     {
1774         if(tng_data->output_endianness_swap_func_64(tng_data,
1775                                       (int64_t *)block->header_contents+offset)
1776             != TNG_SUCCESS)
1777         {
1778             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1779                     __FILE__, __LINE__);
1780         }
1781     }
1782     offset += sizeof(tng_data->long_stride_length);
1783
1784     memcpy(block->block_contents+offset, &tng_data->distance_unit_exponential,
1785            sizeof(tng_data->distance_unit_exponential));
1786     if(tng_data->output_endianness_swap_func_64)
1787     {
1788         if(tng_data->output_endianness_swap_func_64(tng_data,
1789                                       (int64_t *)block->header_contents+offset)
1790             != TNG_SUCCESS)
1791         {
1792             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1793                     __FILE__, __LINE__);
1794         }
1795     }
1796
1797     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
1798     {
1799         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
1800                tng_data->output_file_path, __FILE__, __LINE__);
1801         tng_block_destroy(&block);
1802         return(TNG_CRITICAL);
1803     }
1804
1805     if(fwrite(block->block_contents, block->block_contents_size, 1,
1806         tng_data->output_file) != 1)
1807     {
1808         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
1809         tng_block_destroy(&block);
1810         return(TNG_CRITICAL);
1811     }
1812
1813     tng_block_destroy(&block);
1814
1815     return(TNG_SUCCESS);
1816 }
1817
1818 /** Read the chain data of a molecules block.
1819  * @param tng_data is a trajectory data container.
1820  * @param block is a general block container.
1821  * @param chain is the chain data container.
1822  * @param offset is the offset of the block input and is updated when reading.
1823  * @return TNG_SUCCESS(0) is successful.
1824  */
1825 static tng_function_status tng_chain_data_read(tng_trajectory_t tng_data,
1826                                                tng_gen_block_t block,
1827                                                tng_chain_t chain,
1828                                                int *offset)
1829 {
1830     int len;
1831
1832     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1833
1834     memcpy(&chain->id, block->block_contents+*offset,
1835             sizeof(chain->id));
1836     if(tng_data->input_endianness_swap_func_64)
1837     {
1838         if(tng_data->input_endianness_swap_func_64(tng_data,
1839                                                    &chain->id)
1840             != TNG_SUCCESS)
1841         {
1842             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1843                     __FILE__, __LINE__);
1844         }
1845     }
1846     *offset += sizeof(chain->id);
1847
1848     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
1849             TNG_MAX_STR_LEN);
1850     chain->name = malloc(len);
1851     strncpy(chain->name,
1852             block->block_contents+*offset, len);
1853     *offset += len;
1854
1855     memcpy(&chain->n_residues, block->block_contents+*offset,
1856         sizeof(chain->n_residues));
1857     if(tng_data->input_endianness_swap_func_64)
1858     {
1859         if(tng_data->input_endianness_swap_func_64(tng_data,
1860                                                    &chain->n_residues)
1861             != TNG_SUCCESS)
1862         {
1863             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1864                     __FILE__, __LINE__);
1865         }
1866     }
1867     *offset += sizeof(chain->n_residues);
1868
1869     return(TNG_SUCCESS);
1870 }
1871
1872 /** Write the chain data of a molecules block.
1873  * @param tng_data is a trajectory data container.
1874  * @param block is a general block container.
1875  * @param chain is the chain data container.
1876  * @param offset is the offset of the block output and is updated when writing.
1877  * @return TNG_SUCCESS(0) is successful.
1878  */
1879 static tng_function_status tng_chain_data_write(tng_trajectory_t tng_data,
1880                                                 tng_gen_block_t block,
1881                                                 tng_chain_t chain,
1882                                                 int *offset)
1883 {
1884     int len;
1885
1886     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1887
1888     memcpy(block->block_contents+*offset, &chain->id, sizeof(chain->id));
1889     if(tng_data->output_endianness_swap_func_64)
1890     {
1891         if(tng_data->output_endianness_swap_func_64(tng_data,
1892                                     (int64_t *)block->header_contents+*offset)
1893             != TNG_SUCCESS)
1894         {
1895             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1896                     __FILE__, __LINE__);
1897         }
1898     }
1899     *offset += sizeof(chain->id);
1900
1901     len = tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
1902     strncpy(block->block_contents + *offset, chain->name, len);
1903     *offset += len;
1904
1905     memcpy(block->block_contents+*offset, &chain->n_residues,
1906         sizeof(chain->n_residues));
1907     if(tng_data->output_endianness_swap_func_64)
1908     {
1909         if(tng_data->output_endianness_swap_func_64(tng_data,
1910                                     (int64_t *)block->header_contents+*offset)
1911             != TNG_SUCCESS)
1912         {
1913             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1914                     __FILE__, __LINE__);
1915         }
1916     }
1917     *offset += sizeof(chain->n_residues);
1918
1919     return(TNG_SUCCESS);
1920 }
1921
1922 /** Read the residue data of a molecules block.
1923  * @param tng_data is a trajectory data container.
1924  * @param block is a general block container.
1925  * @param residue is the residue data container.
1926  * @param offset is the offset of the block input and is updated when reading.
1927  * @return TNG_SUCCESS(0) is successful.
1928  */
1929 static tng_function_status tng_residue_data_read(tng_trajectory_t tng_data,
1930                                                  tng_gen_block_t block,
1931                                                  tng_residue_t residue,
1932                                                  int *offset)
1933 {
1934     int len;
1935
1936     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1937
1938     memcpy(&residue->id, block->block_contents+*offset,
1939         sizeof(residue->id));
1940     if(tng_data->input_endianness_swap_func_64)
1941     {
1942         if(tng_data->input_endianness_swap_func_64(tng_data,
1943                                                    &residue->id)
1944             != TNG_SUCCESS)
1945         {
1946             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1947                     __FILE__, __LINE__);
1948         }
1949     }
1950     *offset += sizeof(residue->id);
1951
1952     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
1953             TNG_MAX_STR_LEN);
1954     residue->name = malloc(len);
1955     strncpy(residue->name,
1956             block->block_contents+*offset, len);
1957     *offset += len;
1958
1959     memcpy(&residue->n_atoms, block->block_contents+*offset,
1960             sizeof(residue->n_atoms));
1961     if(tng_data->input_endianness_swap_func_64)
1962     {
1963         if(tng_data->input_endianness_swap_func_64(tng_data,
1964                                                    &residue->n_atoms)
1965             != TNG_SUCCESS)
1966         {
1967             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1968                     __FILE__, __LINE__);
1969         }
1970     }
1971     *offset += sizeof(residue->n_atoms);
1972
1973     return(TNG_SUCCESS);
1974 }
1975
1976 /** Write the residue data of a molecules block.
1977  * @param tng_data is a trajectory data container.
1978  * @param block is a general block container.
1979  * @param residue is the residue data container.
1980  * @param offset is the offset of the block output and is updated when writing.
1981  * @return TNG_SUCCESS(0) is successful.
1982  */
1983 static tng_function_status tng_residue_data_write(tng_trajectory_t tng_data,
1984                                                   tng_gen_block_t block,
1985                                                   tng_residue_t residue,
1986                                                   int *offset)
1987 {
1988     int len;
1989
1990     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1991
1992     memcpy(block->block_contents+*offset, &residue->id, sizeof(residue->id));
1993     if(tng_data->output_endianness_swap_func_64)
1994     {
1995         if(tng_data->output_endianness_swap_func_64(tng_data,
1996                                     (int64_t *)block->header_contents+*offset)
1997             != TNG_SUCCESS)
1998         {
1999             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2000                     __FILE__, __LINE__);
2001         }
2002     }
2003     *offset += sizeof(residue->id);
2004
2005     len = tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2006     strncpy(block->block_contents + *offset, residue->name, len);
2007     *offset += len;
2008
2009     memcpy(block->block_contents+*offset, &residue->n_atoms,
2010         sizeof(residue->n_atoms));
2011     if(tng_data->output_endianness_swap_func_64)
2012     {
2013         if(tng_data->output_endianness_swap_func_64(tng_data,
2014                                     (int64_t *)block->header_contents+*offset)
2015             != TNG_SUCCESS)
2016         {
2017             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2018                     __FILE__, __LINE__);
2019         }
2020     }
2021     *offset += sizeof(residue->n_atoms);
2022
2023     return(TNG_SUCCESS);
2024 }
2025
2026 /** Read the atom data of a molecules block.
2027  * @param tng_data is a trajectory data container.
2028  * @param block is a general block container.
2029  * @param atom is the atom data container.
2030  * @param offset is the offset of the block input and is updated when reading.
2031  * @return TNG_SUCCESS(0) is successful.
2032  */
2033 static tng_function_status tng_atom_data_read(tng_trajectory_t tng_data,
2034                                               tng_gen_block_t block,
2035                                               tng_atom_t atom,
2036                                               int *offset)
2037 {
2038     int len;
2039
2040     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2041
2042     memcpy(&atom->id, block->block_contents+*offset,
2043         sizeof(atom->id));
2044     if(tng_data->input_endianness_swap_func_64)
2045     {
2046         if(tng_data->input_endianness_swap_func_64(tng_data,
2047                                                     &atom->id)
2048             != TNG_SUCCESS)
2049         {
2050             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2051                     __FILE__, __LINE__);
2052         }
2053     }
2054     *offset += sizeof(atom->id);
2055
2056     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2057             TNG_MAX_STR_LEN);
2058     atom->name = malloc(len);
2059     strncpy(atom->name,
2060             block->block_contents+*offset, len);
2061     *offset += len;
2062
2063     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2064             TNG_MAX_STR_LEN);
2065     atom->atom_type = malloc(len);
2066     strncpy(atom->atom_type,
2067             block->block_contents+*offset, len);
2068     *offset += len;
2069
2070     return(TNG_SUCCESS);
2071 }
2072
2073 /** Write the atom data of a molecules block.
2074  * @param tng_data is a trajectory data container.
2075  * @param block is a general block container.
2076  * @param atom is the atom data container.
2077  * @param offset is the offset of the block output and is updated when writing.
2078  * @return TNG_SUCCESS(0) is successful.
2079  */
2080 static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data,
2081                                                tng_gen_block_t block,
2082                                                tng_atom_t atom,
2083                                                int *offset)
2084 {
2085     int len;
2086
2087     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2088
2089     memcpy(block->block_contents+*offset, &atom->id,
2090             sizeof(atom->id));
2091     if(tng_data->output_endianness_swap_func_64)
2092     {
2093         if(tng_data->output_endianness_swap_func_64(tng_data,
2094                                     (int64_t *)block->header_contents+*offset)
2095             != TNG_SUCCESS)
2096         {
2097             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2098                     __FILE__, __LINE__);
2099         }
2100     }
2101     *offset += sizeof(atom->id);
2102
2103     len = tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2104     strncpy(block->block_contents + *offset, atom->name, len);
2105     *offset += len;
2106
2107     len = tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2108     strncpy(block->block_contents + *offset, atom->atom_type, len);
2109     *offset += len;
2110
2111     return(TNG_SUCCESS);
2112 }
2113
2114 /** Read a molecules block. Contains chain, residue and atom data
2115  * @param tng_data is a trajectory data container.
2116  * @param block is a general block container.
2117  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2118  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2119  * compared to the md5 hash of the read contents to ensure valid data.
2120  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2121  * error has occured.
2122  */
2123 static tng_function_status tng_molecules_block_read
2124                 (tng_trajectory_t tng_data,
2125                  tng_gen_block_t block,
2126                  const char hash_mode)
2127 {
2128     int64_t i, j, k, l;
2129     int len, offset = 0;
2130     tng_molecule_t molecule;
2131     tng_chain_t chain;
2132     tng_residue_t residue;
2133     tng_atom_t atom;
2134     tng_bond_t bond;
2135     tng_bool same_hash;
2136
2137     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2138     {
2139         return(TNG_CRITICAL);
2140     }
2141
2142     if(block->block_contents)
2143     {
2144         free(block->block_contents);
2145     }
2146
2147     block->block_contents = malloc(block->block_contents_size);
2148     if(!block->block_contents)
2149     {
2150         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2151                block->block_contents_size, __FILE__, __LINE__);
2152         return(TNG_CRITICAL);
2153     }
2154
2155     /* Read the whole block into block_contents to be able to write it to disk
2156      * even if it cannot be interpreted. */
2157     if(fread(block->block_contents, block->block_contents_size, 1,
2158              tng_data->input_file) == 0)
2159     {
2160         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
2161     }
2162
2163     /* FIXME: Does not check if the size of the contents matches the expected
2164      * size or if the contents can be read. */
2165
2166     if(hash_mode == TNG_USE_HASH)
2167     {
2168         tng_md5_hash_match_verify(block, &same_hash);
2169         if(same_hash != TNG_TRUE)
2170         {
2171             fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
2172                 "%s: %d\n",
2173                 __FILE__, __LINE__);
2174         }
2175     }
2176
2177     if(tng_data->molecules)
2178     {
2179         for(i=tng_data->n_molecules; i--;)
2180         {
2181             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
2182         }
2183         free(tng_data->molecules);
2184         tng_data->molecules = 0;
2185         tng_data->n_molecules = 0;
2186     }
2187
2188     memcpy(&tng_data->n_molecules, block->block_contents,
2189            sizeof(tng_data->n_molecules));
2190     if(tng_data->input_endianness_swap_func_64)
2191     {
2192         if(tng_data->input_endianness_swap_func_64(tng_data,
2193                                                    &tng_data->n_molecules)
2194             != TNG_SUCCESS)
2195         {
2196             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2197                     __FILE__, __LINE__);
2198         }
2199     }
2200     offset += sizeof(tng_data->n_molecules);
2201
2202     if(tng_data->molecules)
2203     {
2204         free(tng_data->molecules);
2205     }
2206
2207     tng_data->n_particles = 0;
2208
2209     tng_data->molecules = malloc(tng_data->n_molecules *
2210                           sizeof(struct tng_molecule));
2211     if(!tng_data->molecules)
2212     {
2213         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2214                tng_data->n_molecules * sizeof(struct tng_molecule),
2215                __FILE__, __LINE__);
2216         return(TNG_CRITICAL);
2217     }
2218
2219     if(!tng_data->var_num_atoms_flag)
2220     {
2221         if(tng_data->molecule_cnt_list)
2222         {
2223             free(tng_data->molecule_cnt_list);
2224         }
2225         tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
2226                                       tng_data->n_molecules);
2227         if(!tng_data->molecule_cnt_list)
2228         {
2229             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2230                    tng_data->n_molecules * sizeof(struct tng_molecule),
2231                    __FILE__, __LINE__);
2232             return(TNG_CRITICAL);
2233         }
2234     }
2235
2236     /* Read each molecule from file */
2237     for(i=0; i < tng_data->n_molecules; i++)
2238     {
2239         molecule = &tng_data->molecules[i];
2240
2241         memcpy(&molecule->id, block->block_contents+offset,
2242                sizeof(molecule->id));
2243         if(tng_data->input_endianness_swap_func_64)
2244         {
2245             if(tng_data->input_endianness_swap_func_64(tng_data,
2246                                                        &molecule->id)
2247                 != TNG_SUCCESS)
2248             {
2249                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2250                         __FILE__, __LINE__);
2251             }
2252         }
2253         offset += sizeof(molecule->id);
2254
2255 /*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
2256         len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2257         molecule->name = malloc(len);
2258         strncpy(molecule->name, block->block_contents+offset, len);
2259         offset += len;
2260
2261         memcpy(&molecule->quaternary_str, block->block_contents+offset,
2262                sizeof(molecule->quaternary_str));
2263         if(tng_data->input_endianness_swap_func_64)
2264         {
2265             if(tng_data->input_endianness_swap_func_64(tng_data,
2266                                                      &molecule->quaternary_str)
2267                 != TNG_SUCCESS)
2268             {
2269                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2270                         __FILE__, __LINE__);
2271             }
2272         }
2273         offset += sizeof(molecule->quaternary_str);
2274
2275         if(!tng_data->var_num_atoms_flag)
2276         {
2277             memcpy(&tng_data->molecule_cnt_list[i],
2278                    block->block_contents+offset,
2279                    sizeof(int64_t));
2280             if(tng_data->input_endianness_swap_func_64)
2281             {
2282                 if(tng_data->input_endianness_swap_func_64(tng_data,
2283                                                &tng_data->molecule_cnt_list[i])
2284                     != TNG_SUCCESS)
2285                 {
2286                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2287                             __FILE__, __LINE__);
2288                 }
2289             }
2290             offset += sizeof(int64_t);
2291         }
2292
2293
2294         memcpy(&molecule->n_chains, block->block_contents+offset,
2295                sizeof(molecule->n_chains));
2296         if(tng_data->input_endianness_swap_func_64)
2297         {
2298             if(tng_data->input_endianness_swap_func_64(tng_data,
2299                                                        &molecule->n_chains)
2300                 != TNG_SUCCESS)
2301             {
2302                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2303                         __FILE__, __LINE__);
2304             }
2305         }
2306         offset += sizeof(molecule->n_chains);
2307
2308         memcpy(&molecule->n_residues, block->block_contents+offset,
2309                sizeof(molecule->n_residues));
2310         if(tng_data->input_endianness_swap_func_64)
2311         {
2312             if(tng_data->input_endianness_swap_func_64(tng_data,
2313                                                        &molecule->n_residues)
2314                 != TNG_SUCCESS)
2315             {
2316                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2317                         __FILE__, __LINE__);
2318             }
2319         }
2320         offset += sizeof(molecule->n_residues);
2321
2322         memcpy(&molecule->n_atoms, block->block_contents+offset,
2323                sizeof(molecule->n_atoms));
2324         if(tng_data->input_endianness_swap_func_64)
2325         {
2326             if(tng_data->input_endianness_swap_func_64(tng_data,
2327                                                        &molecule->n_atoms)
2328                 != TNG_SUCCESS)
2329             {
2330                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2331                         __FILE__, __LINE__);
2332             }
2333         }
2334         offset += sizeof(molecule->n_atoms);
2335
2336         tng_data->n_particles += molecule->n_atoms *
2337                                  tng_data->molecule_cnt_list[i];
2338
2339         if(molecule->n_chains > 0)
2340         {
2341             molecule->chains = malloc(molecule->n_chains *
2342                                     sizeof(struct tng_chain));
2343             if(!molecule->chains)
2344             {
2345                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2346                     molecule->n_chains * sizeof(struct tng_chain),
2347                     __FILE__, __LINE__);
2348                 return(TNG_CRITICAL);
2349             }
2350
2351             chain = molecule->chains;
2352         }
2353         else
2354         {
2355             chain = 0;
2356         }
2357
2358         if(molecule->n_residues > 0)
2359         {
2360             molecule->residues = malloc(molecule->n_residues *
2361                                 sizeof(struct tng_residue));
2362             if(!molecule->residues)
2363             {
2364                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2365                     molecule->n_residues * sizeof(struct tng_residue),
2366                     __FILE__, __LINE__);
2367                 if(molecule->chains)
2368                 {
2369                     free(molecule->chains);
2370                     molecule->chains = 0;
2371                 }
2372                 return(TNG_CRITICAL);
2373             }
2374
2375             residue = molecule->residues;
2376         }
2377         else
2378         {
2379             residue = 0;
2380         }
2381
2382         molecule->atoms = malloc(molecule->n_atoms *
2383                                  sizeof(struct tng_atom));
2384         if(!molecule->atoms)
2385         {
2386             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2387                    molecule->n_atoms * sizeof(struct tng_atom),
2388                    __FILE__, __LINE__);
2389             if(molecule->chains)
2390             {
2391                 free(molecule->chains);
2392                 molecule->chains = 0;
2393             }
2394             if(molecule->residues)
2395             {
2396                 free(molecule->residues);
2397                 molecule->residues = 0;
2398             }
2399             return(TNG_CRITICAL);
2400         }
2401
2402         atom = molecule->atoms;
2403
2404         if(molecule->n_chains > 0)
2405         {
2406             /* Read the chains of the molecule */
2407             for(j=molecule->n_chains; j--;)
2408             {
2409                 chain->molecule = molecule;
2410
2411                 tng_chain_data_read(tng_data, block, chain, &offset);
2412
2413                 chain->residues = molecule->residues;
2414                 residue = chain->residues;
2415
2416                 /* Read the residues of the chain */
2417                 for(k=chain->n_residues; k--;)
2418                 {
2419                     residue->chain = chain;
2420
2421                     tng_residue_data_read(tng_data, block, residue, &offset);
2422
2423                     residue->atoms_offset = atom - molecule->atoms;
2424                     /* Read the atoms of the residue */
2425                     for(l=residue->n_atoms; l--;)
2426                     {
2427                         atom->residue = residue;
2428
2429                         tng_atom_data_read(tng_data, block, atom, &offset);
2430
2431                         atom++;
2432                     }
2433                     residue++;
2434                 }
2435                 chain++;
2436             }
2437         }
2438         else
2439         {
2440             if(molecule->n_residues > 0)
2441             {
2442                 for(k=molecule->n_residues; k--;)
2443                 {
2444                     residue->chain = 0;
2445
2446                     tng_residue_data_read(tng_data, block, residue, &offset);
2447
2448                     residue->atoms_offset = atom - molecule->atoms;
2449                     /* Read the atoms of the residue */
2450                     for(l=residue->n_atoms; l--;)
2451                     {
2452                         atom->residue = residue;
2453
2454                         tng_atom_data_read(tng_data, block, atom, &offset);
2455
2456                         atom++;
2457                     }
2458                     residue++;
2459                 }
2460             }
2461             else
2462             {
2463                 for(l=molecule->n_atoms; l--;)
2464                 {
2465                     atom->residue = 0;
2466
2467                     tng_atom_data_read(tng_data, block, atom, &offset);
2468
2469                     atom++;
2470                 }
2471             }
2472         }
2473
2474         memcpy(&molecule->n_bonds, block->block_contents+offset,
2475                sizeof(molecule->n_bonds));
2476         if(tng_data->input_endianness_swap_func_64)
2477         {
2478             if(tng_data->input_endianness_swap_func_64(tng_data,
2479                                                        &molecule->n_bonds)
2480                 != TNG_SUCCESS)
2481             {
2482                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2483                         __FILE__, __LINE__);
2484             }
2485         }
2486         offset += sizeof(molecule->n_bonds);
2487
2488         if(molecule->n_bonds > 0)
2489         {
2490             tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
2491                                            sizeof(struct tng_bond));
2492             if(!molecule->bonds)
2493             {
2494                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2495                        molecule->n_bonds * sizeof(struct tng_bond),
2496                        __FILE__, __LINE__);
2497                 if(molecule->chains)
2498                 {
2499                     free(molecule->chains);
2500                     molecule->chains = 0;
2501                 }
2502                 if(molecule->residues)
2503                 {
2504                     free(molecule->residues);
2505                     molecule->residues = 0;
2506                 }
2507                 if(molecule->atoms)
2508                 {
2509                     free(molecule->atoms);
2510                     molecule->atoms = 0;
2511                 }
2512                 return(TNG_CRITICAL);
2513             }
2514
2515             bond = molecule->bonds;
2516
2517             for(j=molecule->n_bonds; j--;)
2518             {
2519                 memcpy(&bond->from_atom_id, block->block_contents+offset,
2520                     sizeof(bond->from_atom_id));
2521                 if(tng_data->input_endianness_swap_func_64)
2522                 {
2523                     if(tng_data->input_endianness_swap_func_64(tng_data,
2524                                                                &bond->from_atom_id)
2525                         != TNG_SUCCESS)
2526                     {
2527                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2528                                 __FILE__, __LINE__);
2529                     }
2530                 }
2531                 offset += sizeof(bond->from_atom_id);
2532
2533                 memcpy(&bond->to_atom_id, block->block_contents+offset,
2534                     sizeof(bond->to_atom_id));
2535                 if(tng_data->input_endianness_swap_func_64)
2536                 {
2537                     if(tng_data->input_endianness_swap_func_64(tng_data,
2538                                                                &bond->to_atom_id)
2539                         != TNG_SUCCESS)
2540                     {
2541                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2542                                 __FILE__, __LINE__);
2543                     }
2544                 }
2545                 offset += sizeof(bond->to_atom_id);
2546
2547                 bond++;
2548             }
2549         }
2550         else
2551         {
2552             molecule->bonds = 0;
2553         }
2554     }
2555
2556     return(TNG_SUCCESS);
2557 }
2558
2559 /** Write a molecules block.
2560  * @param tng_data is a trajectory data container.
2561  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2562  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2563  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2564  * error has occured.
2565  */
2566 static tng_function_status tng_molecules_block_write
2567                 (tng_trajectory_t tng_data,
2568                  const char hash_mode)
2569 {
2570     int len = 0, name_len, offset = 0;
2571     int64_t i, j, k, l;
2572     tng_molecule_t molecule;
2573     tng_chain_t chain;
2574     tng_residue_t residue;
2575     tng_atom_t atom;
2576     tng_bond_t bond;
2577     tng_gen_block_t block;
2578
2579     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2580     {
2581         return(TNG_CRITICAL);
2582     }
2583
2584     /* First predict the size of the block */
2585     for(i = 0; i < tng_data->n_molecules; i++)
2586     {
2587         molecule = &tng_data->molecules[i];
2588         if(!molecule->name)
2589         {
2590             molecule->name = malloc(1);
2591             if(!molecule->name)
2592             {
2593                 fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2594                        __FILE__, __LINE__);
2595                 return(TNG_CRITICAL);
2596             }
2597             molecule->name[0] = 0;
2598         }
2599         len += tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
2600
2601         chain = molecule->chains;
2602         for(j = molecule->n_chains; j--;)
2603         {
2604             len += sizeof(chain->id);
2605
2606             if(!chain->name)
2607             {
2608                 chain->name = malloc(1);
2609                 if(!chain->name)
2610                 {
2611                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2612                            __FILE__, __LINE__);
2613                     return(TNG_CRITICAL);
2614                 }
2615                 chain->name[0] = 0;
2616             }
2617             len += tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2618
2619             len += sizeof(chain->n_residues);
2620
2621             chain++;
2622         }
2623
2624         residue = molecule->residues;
2625         for(j = molecule->n_residues; j--;)
2626         {
2627             len += sizeof(residue->id);
2628
2629             if(!residue->name)
2630             {
2631                 residue->name = malloc(1);
2632                 if(!residue->name)
2633                 {
2634                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2635                            __FILE__, __LINE__);
2636                     return(TNG_CRITICAL);
2637                 }
2638                 residue->name[0] = 0;
2639             }
2640             len += tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2641
2642             len += sizeof(residue->n_atoms);
2643
2644             residue++;
2645         }
2646
2647         atom = molecule->atoms;
2648         for(j = molecule->n_atoms; j--;)
2649         {
2650             len += sizeof(atom->id);
2651             if(!atom->name)
2652             {
2653                 atom->name = malloc(1);
2654                 if(!atom->name)
2655                 {
2656                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2657                            __FILE__, __LINE__);
2658                     return(TNG_CRITICAL);
2659                 }
2660                 atom->name[0] = 0;
2661             }
2662             len += tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2663
2664             if(!atom->atom_type)
2665             {
2666                 atom->atom_type = malloc(1);
2667                 if(!atom->atom_type)
2668                 {
2669                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2670                            __FILE__, __LINE__);
2671                     return(TNG_CRITICAL);
2672                 }
2673                 atom->atom_type[0] = 0;
2674             }
2675             len += tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2676
2677             atom++;
2678         }
2679
2680         for(j = molecule->n_bonds; j--;)
2681         {
2682             len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
2683         }
2684     }
2685
2686     tng_block_init(&block);
2687
2688     name_len = (int)strlen("MOLECULES");
2689
2690     block->name = malloc(name_len + 1);
2691     if(!block->name)
2692     {
2693         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
2694                 name_len+1, __FILE__, __LINE__);
2695         tng_block_destroy(&block);
2696         return(TNG_CRITICAL);
2697     }
2698
2699     strcpy(block->name, "MOLECULES");
2700     block->id = TNG_MOLECULES;
2701
2702     block->block_contents_size = sizeof(tng_data->n_molecules) +
2703                                  (sizeof(molecule->id) +
2704                                  sizeof(molecule->quaternary_str) +
2705                                  sizeof(molecule->n_chains) +
2706                                  sizeof(molecule->n_residues) +
2707                                  sizeof(molecule->n_atoms) +
2708                                  sizeof(molecule->n_bonds)) *
2709                                  tng_data->n_molecules +
2710                                  len;
2711
2712     if(!tng_data->var_num_atoms_flag)
2713     {
2714         block->block_contents_size += tng_data->n_molecules * sizeof(int64_t);
2715     }
2716
2717     block->block_contents = malloc(block->block_contents_size);
2718     if(!block->block_contents)
2719     {
2720         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2721                block->block_contents_size, __FILE__, __LINE__);
2722         tng_block_destroy(&block);
2723         return(TNG_CRITICAL);
2724     }
2725
2726     memcpy(block->block_contents+offset, &tng_data->n_molecules,
2727            sizeof(tng_data->n_molecules));
2728     if(tng_data->output_endianness_swap_func_64)
2729     {
2730         if(tng_data->output_endianness_swap_func_64(tng_data,
2731                                       (int64_t *)block->header_contents+offset)
2732             != TNG_SUCCESS)
2733         {
2734             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2735                     __FILE__, __LINE__);
2736         }
2737     }
2738     offset += sizeof(tng_data->n_molecules);
2739
2740     for(i = 0; i < tng_data->n_molecules; i++)
2741     {
2742         molecule = &tng_data->molecules[i];
2743         memcpy(block->block_contents+offset, &molecule->id,
2744                sizeof(molecule->id));
2745         if(tng_data->output_endianness_swap_func_64)
2746         {
2747             if(tng_data->output_endianness_swap_func_64(tng_data,
2748                                         (int64_t *)block->header_contents+offset)
2749                 != TNG_SUCCESS)
2750             {
2751                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2752                         __FILE__, __LINE__);
2753             }
2754         }
2755         offset += sizeof(molecule->id);
2756
2757 /*         fprintf(stderr, "TNG library: Wrote id: %"PRId64" offset: %d\n", molecule->id, offset); */
2758         len = tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
2759         strncpy(block->block_contents + offset, molecule->name, len);
2760         offset += len;
2761
2762         memcpy(block->block_contents+offset, &molecule->quaternary_str,
2763                sizeof(molecule->quaternary_str));
2764         if(tng_data->output_endianness_swap_func_64)
2765         {
2766             if(tng_data->output_endianness_swap_func_64(tng_data,
2767                                         (int64_t *)block->header_contents+offset)
2768                 != TNG_SUCCESS)
2769             {
2770                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2771                         __FILE__, __LINE__);
2772             }
2773         }
2774         offset += sizeof(molecule->quaternary_str);
2775
2776         if(!tng_data->var_num_atoms_flag)
2777         {
2778             memcpy(block->block_contents+offset,
2779                    &tng_data->molecule_cnt_list[i], sizeof(int64_t));
2780             if(tng_data->output_endianness_swap_func_64)
2781             {
2782                 if(tng_data->output_endianness_swap_func_64(tng_data,
2783                                             (int64_t *)block->header_contents+offset)
2784                     != TNG_SUCCESS)
2785                 {
2786                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2787                             __FILE__, __LINE__);
2788                 }
2789             }
2790             offset += sizeof(int64_t);
2791         }
2792
2793         memcpy(block->block_contents+offset, &molecule->n_chains,
2794                sizeof(molecule->n_chains));
2795         if(tng_data->output_endianness_swap_func_64)
2796         {
2797             if(tng_data->output_endianness_swap_func_64(tng_data,
2798                                         (int64_t *)block->header_contents+offset)
2799                 != TNG_SUCCESS)
2800             {
2801                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2802                         __FILE__, __LINE__);
2803             }
2804         }
2805         offset += sizeof(molecule->n_chains);
2806
2807         memcpy(block->block_contents+offset, &molecule->n_residues,
2808                sizeof(molecule->n_residues));
2809         if(tng_data->output_endianness_swap_func_64)
2810         {
2811             if(tng_data->output_endianness_swap_func_64(tng_data,
2812                                         (int64_t *)block->header_contents+offset)
2813                 != TNG_SUCCESS)
2814             {
2815                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2816                         __FILE__, __LINE__);
2817             }
2818         }
2819         offset += sizeof(molecule->n_residues);
2820
2821         memcpy(block->block_contents+offset, &molecule->n_atoms,
2822                sizeof(molecule->n_atoms));
2823         if(tng_data->output_endianness_swap_func_64)
2824         {
2825             if(tng_data->output_endianness_swap_func_64(tng_data,
2826                                         (int64_t *)block->header_contents+offset)
2827                 != TNG_SUCCESS)
2828             {
2829                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2830                         __FILE__, __LINE__);
2831             }
2832         }
2833         offset += sizeof(molecule->n_atoms);
2834
2835         if(molecule->n_chains > 0)
2836         {
2837             chain = molecule->chains;
2838             for(j = molecule->n_chains; j--;)
2839             {
2840                 tng_chain_data_write(tng_data, block, chain, &offset);
2841
2842                 residue = chain->residues;
2843                 for(k = chain->n_residues; k--;)
2844                 {
2845                     tng_residue_data_write(tng_data, block, residue, &offset);
2846
2847                     atom = molecule->atoms + residue->atoms_offset;
2848                     for(l = residue->n_atoms; l--;)
2849                     {
2850                         tng_atom_data_write(tng_data, block, atom, &offset);
2851
2852                         atom++;
2853                     }
2854                     residue++;
2855                 }
2856                 chain++;
2857             }
2858         }
2859         else
2860         {
2861             if(molecule->n_residues > 0)
2862             {
2863                 residue = molecule->residues;
2864                 for(k = molecule->n_residues; k--;)
2865                 {
2866                     tng_residue_data_write(tng_data, block, residue, &offset);
2867
2868                     atom = molecule->atoms + residue->atoms_offset;
2869                     for(l = residue->n_atoms; l--;)
2870                     {
2871                         tng_atom_data_write(tng_data, block, atom, &offset);
2872
2873                         atom++;
2874                     }
2875                     residue++;
2876                 }
2877             }
2878             else
2879             {
2880                 atom = molecule->atoms;
2881                 for(l = molecule->n_atoms; l--;)
2882                 {
2883                     tng_atom_data_write(tng_data, block, atom, &offset);
2884
2885                     atom++;
2886                 }
2887             }
2888         }
2889
2890         memcpy(block->block_contents+offset, &molecule->n_bonds,
2891                sizeof(molecule->n_bonds));
2892         if(tng_data->output_endianness_swap_func_64)
2893         {
2894             if(tng_data->output_endianness_swap_func_64(tng_data,
2895                                         (int64_t *)block->header_contents+offset)
2896                 != TNG_SUCCESS)
2897             {
2898                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2899                         __FILE__, __LINE__);
2900             }
2901         }
2902         offset += sizeof(molecule->n_bonds);
2903
2904         bond = molecule->bonds;
2905         for(j = molecule->n_bonds; j--;)
2906         {
2907             memcpy(block->block_contents+offset, &bond->from_atom_id,
2908                    sizeof(bond->from_atom_id));
2909             if(tng_data->output_endianness_swap_func_64)
2910             {
2911                 if(tng_data->output_endianness_swap_func_64(tng_data,
2912                                             (int64_t *)block->header_contents+offset)
2913                     != TNG_SUCCESS)
2914                 {
2915                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2916                             __FILE__, __LINE__);
2917                 }
2918             }
2919             offset += sizeof(bond->from_atom_id);
2920
2921             memcpy(block->block_contents+offset, &bond->to_atom_id,
2922                    sizeof(bond->to_atom_id));
2923             if(tng_data->output_endianness_swap_func_64)
2924             {
2925                 if(tng_data->output_endianness_swap_func_64(tng_data,
2926                                             (int64_t *)block->header_contents+offset)
2927                     != TNG_SUCCESS)
2928                 {
2929                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2930                             __FILE__, __LINE__);
2931                 }
2932             }
2933             offset += sizeof(bond->to_atom_id);
2934
2935             bond++;
2936         }
2937     }
2938
2939     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
2940     {
2941         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2942                tng_data->output_file_path, __FILE__, __LINE__);
2943         tng_block_destroy(&block);
2944         return(TNG_CRITICAL);
2945     }
2946
2947     if(fwrite(block->block_contents, block->block_contents_size, 1,
2948               tng_data->output_file) != 1)
2949     {
2950         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
2951                __FILE__, __LINE__);
2952         tng_block_destroy(&block);
2953         return(TNG_CRITICAL);
2954     }
2955
2956     tng_block_destroy(&block);
2957
2958     return(TNG_SUCCESS);
2959 }
2960
2961 /** Read a frame set block. Update tng_data->current_trajectory_frame_set
2962  * @param tng_data is a trajectory data container.
2963  * @param block is a general block container.
2964  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2965  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2966  * compared to the md5 hash of the read contents to ensure valid data.
2967  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2968  * error has occured.
2969  */
2970 static tng_function_status tng_frame_set_block_read
2971                 (tng_trajectory_t tng_data,
2972                  tng_gen_block_t block,
2973                  const char hash_mode)
2974 {
2975     long file_pos;
2976     int offset = 0;
2977     int64_t i, prev_n_particles;
2978     tng_bool same_hash;
2979     tng_trajectory_frame_set_t frame_set =
2980     &tng_data->current_trajectory_frame_set;
2981
2982     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2983     {
2984         return(TNG_CRITICAL);
2985     }
2986
2987     if(block->block_contents)
2988     {
2989         free(block->block_contents);
2990     }
2991
2992     block->block_contents = malloc(block->block_contents_size);
2993     if(!block->block_contents)
2994     {
2995         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2996                block->block_contents_size, __FILE__, __LINE__);
2997         return(TNG_CRITICAL);
2998     }
2999
3000     /* Read the whole block into block_contents to be able to write it to
3001      * disk even if it cannot be interpreted. */
3002     if(fread(block->block_contents, block->block_contents_size, 1,
3003              tng_data->input_file) == 0)
3004     {
3005         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3006         return(TNG_CRITICAL);
3007     }
3008
3009     /* FIXME: Does not check if the size of the contents matches the expected
3010      * size or if the contents can be read. */
3011
3012     file_pos = (int64_t)ftell(tng_data->input_file) -
3013                (long)(block->block_contents_size + block->header_contents_size);
3014
3015     if(hash_mode == TNG_USE_HASH)
3016     {
3017         tng_md5_hash_match_verify(block, &same_hash);
3018         if(same_hash != TNG_TRUE)
3019         {
3020             fprintf(stderr, "TNG library: Frame set block contents corrupt. File pos %ld Hashes do not match. "
3021                 "%s: %d\n",
3022                 file_pos, __FILE__, __LINE__);
3023     /*         return(TNG_FAILURE); */
3024         }
3025     }
3026
3027     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3028
3029     tng_frame_set_particle_mapping_free(tng_data);
3030
3031     if(tng_data->first_trajectory_frame_set_input_file_pos <= 0)
3032     {
3033         tng_data->first_trajectory_frame_set_input_file_pos = file_pos;
3034     }
3035     /* FIXME: Should check the frame number instead of the file_pos, in case
3036      * frame sets are not in order */
3037     if(tng_data->last_trajectory_frame_set_input_file_pos < file_pos)
3038     {
3039         tng_data->last_trajectory_frame_set_input_file_pos = file_pos;
3040     }
3041
3042     memcpy(&frame_set->first_frame, block->block_contents,
3043            sizeof(frame_set->first_frame));
3044     if(tng_data->input_endianness_swap_func_64)
3045     {
3046         if(tng_data->input_endianness_swap_func_64(tng_data,
3047                                                    &frame_set->first_frame)
3048             != TNG_SUCCESS)
3049         {
3050             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3051                     __FILE__, __LINE__);
3052         }
3053     }
3054     offset += sizeof(frame_set->first_frame);
3055
3056     memcpy(&frame_set->n_frames, block->block_contents + offset,
3057            sizeof(frame_set->n_frames));
3058     if(tng_data->input_endianness_swap_func_64)
3059     {
3060         if(tng_data->input_endianness_swap_func_64(tng_data,
3061                                                    &frame_set->n_frames)
3062             != TNG_SUCCESS)
3063         {
3064             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3065                     __FILE__, __LINE__);
3066         }
3067     }
3068     offset += sizeof(frame_set->n_frames);
3069
3070     if(tng_data->var_num_atoms_flag)
3071     {
3072         prev_n_particles = frame_set->n_particles;
3073         frame_set->n_particles = 0;
3074         /* If the list of molecule counts has already been created assume that
3075          * it is of correct size. */
3076         if(!frame_set->molecule_cnt_list)
3077         {
3078                 frame_set->molecule_cnt_list =
3079                 malloc(sizeof(int64_t) * tng_data->n_molecules);
3080
3081                 if(!frame_set->molecule_cnt_list)
3082                 {
3083                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3084                            sizeof(int64_t) * tng_data->n_molecules,
3085                            __FILE__, __LINE__);
3086                     return(TNG_CRITICAL);
3087                 }
3088         }
3089         for(i = 0; i < tng_data->n_molecules; i++)
3090         {
3091             memcpy(&frame_set->molecule_cnt_list[i],
3092                    block->block_contents + offset,
3093                    sizeof(int64_t));
3094             if(tng_data->input_endianness_swap_func_64)
3095             {
3096                 if(tng_data->input_endianness_swap_func_64(tng_data,
3097                                               &frame_set->molecule_cnt_list[i])
3098                     != TNG_SUCCESS)
3099                 {
3100                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3101                             __FILE__, __LINE__);
3102                 }
3103             }
3104             offset += sizeof(int64_t);
3105             frame_set->n_particles += tng_data->molecules[i].n_atoms *
3106                                       frame_set->molecule_cnt_list[i];
3107         }
3108         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
3109         {
3110             /* FIXME: Particle dependent data memory management */
3111         }
3112     }
3113
3114     memcpy(&frame_set->next_frame_set_file_pos,
3115            block->block_contents + offset,
3116            sizeof(frame_set->next_frame_set_file_pos));
3117     if(tng_data->input_endianness_swap_func_64)
3118     {
3119         if(tng_data->input_endianness_swap_func_64(tng_data,
3120                                            &frame_set->next_frame_set_file_pos)
3121             != TNG_SUCCESS)
3122         {
3123             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3124                     __FILE__, __LINE__);
3125         }
3126     }
3127     offset += sizeof(frame_set->next_frame_set_file_pos);
3128
3129     memcpy(&frame_set->prev_frame_set_file_pos,
3130            block->block_contents + offset,
3131            sizeof(frame_set->prev_frame_set_file_pos));
3132     if(tng_data->input_endianness_swap_func_64)
3133     {
3134         if(tng_data->input_endianness_swap_func_64(tng_data,
3135                                            &frame_set->prev_frame_set_file_pos)
3136             != TNG_SUCCESS)
3137         {
3138             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3139                     __FILE__, __LINE__);
3140         }
3141     }
3142     offset += sizeof(frame_set->prev_frame_set_file_pos);
3143
3144     memcpy(&frame_set->medium_stride_next_frame_set_file_pos,
3145            block->block_contents + offset,
3146            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
3147     if(tng_data->input_endianness_swap_func_64)
3148     {
3149         if(tng_data->input_endianness_swap_func_64(tng_data,
3150                              &frame_set->medium_stride_next_frame_set_file_pos)
3151             != TNG_SUCCESS)
3152         {
3153             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3154                     __FILE__, __LINE__);
3155         }
3156     }
3157     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
3158
3159     memcpy(&frame_set->medium_stride_prev_frame_set_file_pos,
3160            block->block_contents + offset,
3161            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
3162     if(tng_data->input_endianness_swap_func_64)
3163     {
3164         if(tng_data->input_endianness_swap_func_64(tng_data,
3165                              &frame_set->medium_stride_prev_frame_set_file_pos)
3166             != TNG_SUCCESS)
3167         {
3168             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3169                     __FILE__, __LINE__);
3170         }
3171     }
3172     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
3173
3174     memcpy(&frame_set->long_stride_next_frame_set_file_pos,
3175            block->block_contents + offset,
3176            sizeof(frame_set->long_stride_next_frame_set_file_pos));
3177     if(tng_data->input_endianness_swap_func_64)
3178     {
3179         if(tng_data->input_endianness_swap_func_64(tng_data,
3180                                &frame_set->long_stride_next_frame_set_file_pos)
3181             != TNG_SUCCESS)
3182         {
3183             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3184                     __FILE__, __LINE__);
3185         }
3186     }
3187     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
3188
3189     memcpy(&frame_set->long_stride_prev_frame_set_file_pos,
3190            block->block_contents + offset,
3191            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
3192     if(tng_data->input_endianness_swap_func_64)
3193     {
3194         if(tng_data->input_endianness_swap_func_64(tng_data,
3195                                &frame_set->long_stride_prev_frame_set_file_pos)
3196             != TNG_SUCCESS)
3197         {
3198             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3199                     __FILE__, __LINE__);
3200         }
3201     }
3202     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
3203
3204     if(block->block_version >= 3)
3205     {
3206         memcpy(&frame_set->first_frame_time,
3207             block->block_contents + offset,
3208             sizeof(frame_set->first_frame_time));
3209         if(tng_data->input_endianness_swap_func_64)
3210         {
3211             if(tng_data->input_endianness_swap_func_64(tng_data,
3212                                 (int64_t *)&frame_set->first_frame_time)
3213                 != TNG_SUCCESS)
3214             {
3215                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3216                         __FILE__, __LINE__);
3217             }
3218         }
3219         offset += sizeof(frame_set->first_frame_time);
3220
3221         memcpy(&tng_data->time_per_frame,
3222             block->block_contents + offset,
3223             sizeof(tng_data->time_per_frame));
3224         if(tng_data->input_endianness_swap_func_64)
3225         {
3226             if(tng_data->input_endianness_swap_func_64(tng_data,
3227                                 (int64_t *)&tng_data->time_per_frame)
3228                 != TNG_SUCCESS)
3229             {
3230                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3231                         __FILE__, __LINE__);
3232             }
3233         }
3234     }
3235     else
3236     {
3237         frame_set->first_frame_time = -1;
3238         tng_data->time_per_frame = -1;
3239     }
3240
3241     frame_set->n_written_frames = frame_set->n_frames;
3242
3243     return(TNG_SUCCESS);
3244 }
3245
3246 /** Write tng_data->current_trajectory_frame_set to file
3247  * @param tng_data is a trajectory data container.
3248  * @param block is a general block container.
3249  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3250  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3251  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3252  * error has occured.
3253  */
3254 static tng_function_status tng_frame_set_block_write
3255                 (tng_trajectory_t tng_data,
3256                  tng_gen_block_t block,
3257                  const char hash_mode)
3258 {
3259     char *temp_name;
3260     int64_t i;
3261     int offset = 0;
3262     unsigned int name_len;
3263     tng_trajectory_frame_set_t frame_set =
3264     &tng_data->current_trajectory_frame_set;
3265
3266     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3267     {
3268         return(TNG_CRITICAL);
3269     }
3270
3271     name_len = (int)strlen("TRAJECTORY FRAME SET");
3272
3273     if(!block->name || strlen(block->name) < name_len)
3274     {
3275         temp_name = realloc(block->name, name_len + 1);
3276         if(!temp_name)
3277         {
3278             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3279                    name_len+1, __FILE__, __LINE__);
3280             free(block->name);
3281             block->name = 0;
3282             return(TNG_CRITICAL);
3283         }
3284         block->name = temp_name;
3285     }
3286     strcpy(block->name, "TRAJECTORY FRAME SET");
3287     block->id = TNG_TRAJECTORY_FRAME_SET;
3288
3289     block->block_contents_size = sizeof(int64_t) * 8;
3290     block->block_contents_size += sizeof(double) * 2;
3291
3292     if(tng_data->var_num_atoms_flag)
3293     {
3294         block->block_contents_size += sizeof(int64_t) * tng_data->n_molecules;
3295     }
3296
3297     if(block->block_contents)
3298     {
3299         free(block->block_contents);
3300     }
3301     block->block_contents = malloc(block->block_contents_size);
3302     if(!block->block_contents)
3303     {
3304         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3305                block->block_contents_size, __FILE__, __LINE__);
3306         return(TNG_CRITICAL);
3307     }
3308
3309     memcpy(block->block_contents, &frame_set->first_frame,
3310            sizeof(frame_set->first_frame));
3311     if(tng_data->output_endianness_swap_func_64)
3312     {
3313         if(tng_data->output_endianness_swap_func_64(tng_data,
3314                                       (int64_t *)block->header_contents+offset)
3315             != TNG_SUCCESS)
3316         {
3317             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3318                     __FILE__, __LINE__);
3319         }
3320     }
3321     offset += sizeof(frame_set->first_frame);
3322
3323     memcpy(block->block_contents+offset, &frame_set->n_frames,
3324            sizeof(frame_set->n_frames));
3325     if(tng_data->output_endianness_swap_func_64)
3326     {
3327         if(tng_data->output_endianness_swap_func_64(tng_data,
3328                                       (int64_t *)block->header_contents+offset)
3329             != TNG_SUCCESS)
3330         {
3331             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3332                     __FILE__, __LINE__);
3333         }
3334     }
3335     offset += sizeof(frame_set->n_frames);
3336
3337     if(tng_data->var_num_atoms_flag)
3338     {
3339         for(i = 0; i < tng_data->n_molecules; i++)
3340         {
3341             memcpy(block->block_contents+offset,
3342                    &frame_set->molecule_cnt_list[i],
3343                    sizeof(int64_t));
3344             if(tng_data->output_endianness_swap_func_64)
3345             {
3346                 if(tng_data->output_endianness_swap_func_64(tng_data,
3347                                             (int64_t *)block->header_contents+offset)
3348                     != TNG_SUCCESS)
3349                 {
3350                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3351                             __FILE__, __LINE__);
3352                 }
3353             }
3354             offset += sizeof(int64_t);
3355         }
3356     }
3357
3358
3359     memcpy(block->block_contents+offset, &frame_set->next_frame_set_file_pos,
3360            sizeof(frame_set->next_frame_set_file_pos));
3361     if(tng_data->output_endianness_swap_func_64)
3362     {
3363         if(tng_data->output_endianness_swap_func_64(tng_data,
3364                                       (int64_t *)block->header_contents+offset)
3365             != TNG_SUCCESS)
3366         {
3367             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3368                     __FILE__, __LINE__);
3369         }
3370     }
3371     offset += sizeof(frame_set->next_frame_set_file_pos);
3372
3373     memcpy(block->block_contents+offset, &frame_set->prev_frame_set_file_pos,
3374            sizeof(frame_set->prev_frame_set_file_pos));
3375     if(tng_data->output_endianness_swap_func_64)
3376     {
3377         if(tng_data->output_endianness_swap_func_64(tng_data,
3378                                       (int64_t *)block->header_contents+offset)
3379             != TNG_SUCCESS)
3380         {
3381             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3382                     __FILE__, __LINE__);
3383         }
3384     }
3385     offset += sizeof(frame_set->prev_frame_set_file_pos);
3386
3387     memcpy(block->block_contents+offset,
3388            &frame_set->medium_stride_next_frame_set_file_pos,
3389            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
3390     if(tng_data->output_endianness_swap_func_64)
3391     {
3392         if(tng_data->output_endianness_swap_func_64(tng_data,
3393                                       (int64_t *)block->header_contents+offset)
3394             != TNG_SUCCESS)
3395         {
3396             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3397                     __FILE__, __LINE__);
3398         }
3399     }
3400     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
3401
3402     memcpy(block->block_contents+offset,
3403            &frame_set->medium_stride_prev_frame_set_file_pos,
3404            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
3405     if(tng_data->output_endianness_swap_func_64)
3406     {
3407         if(tng_data->output_endianness_swap_func_64(tng_data,
3408                                       (int64_t *)block->header_contents+offset)
3409             != TNG_SUCCESS)
3410         {
3411             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3412                     __FILE__, __LINE__);
3413         }
3414     }
3415     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
3416
3417     memcpy(block->block_contents+offset,
3418            &frame_set->long_stride_next_frame_set_file_pos,
3419            sizeof(frame_set->long_stride_next_frame_set_file_pos));
3420     if(tng_data->output_endianness_swap_func_64)
3421     {
3422         if(tng_data->output_endianness_swap_func_64(tng_data,
3423                                       (int64_t *)block->header_contents+offset)
3424             != TNG_SUCCESS)
3425         {
3426             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3427                     __FILE__, __LINE__);
3428         }
3429     }
3430     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
3431
3432     memcpy(block->block_contents+offset,
3433            &frame_set->long_stride_prev_frame_set_file_pos,
3434            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
3435     if(tng_data->output_endianness_swap_func_64)
3436     {
3437         if(tng_data->output_endianness_swap_func_64(tng_data,
3438                                       (int64_t *)block->header_contents+offset)
3439             != TNG_SUCCESS)
3440         {
3441             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3442                     __FILE__, __LINE__);
3443         }
3444     }
3445     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
3446
3447     memcpy(block->block_contents+offset,
3448            &frame_set->first_frame_time,
3449            sizeof(frame_set->first_frame_time));
3450     if(tng_data->output_endianness_swap_func_64)
3451     {
3452         if(tng_data->output_endianness_swap_func_64(tng_data,
3453                                       (int64_t *)block->header_contents+offset)
3454             != TNG_SUCCESS)
3455         {
3456             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3457                     __FILE__, __LINE__);
3458         }
3459     }
3460     offset += sizeof(frame_set->first_frame_time);
3461
3462     memcpy(block->block_contents+offset,
3463            &tng_data->time_per_frame,
3464            sizeof(tng_data->time_per_frame));
3465     if(tng_data->output_endianness_swap_func_64)
3466     {
3467         if(tng_data->output_endianness_swap_func_64(tng_data,
3468                                       (int64_t *)block->header_contents+offset)
3469             != TNG_SUCCESS)
3470         {
3471             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3472                     __FILE__, __LINE__);
3473         }
3474     }
3475
3476     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3477     {
3478         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3479                tng_data->output_file_path, __FILE__, __LINE__);
3480         return(TNG_CRITICAL);
3481     }
3482
3483     if(fwrite(block->block_contents, block->block_contents_size, 1,
3484               tng_data->output_file) != 1)
3485     {
3486         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
3487         return(TNG_CRITICAL);
3488     }
3489
3490     return(TNG_SUCCESS);
3491 }
3492
3493
3494 /** Read an atom mappings block (translating between real atom indexes and how
3495  *  the atom info is written in this frame set).
3496  * @param tng_data is a trajectory data container.
3497  * @param block is a general block container.
3498  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3499  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3500  * compared to the md5 hash of the read contents to ensure valid data.
3501  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3502  * error has occured.
3503  */
3504 static tng_function_status tng_trajectory_mapping_block_read
3505                 (tng_trajectory_t tng_data,
3506                  tng_gen_block_t block,
3507                  const char hash_mode)
3508 {
3509     int64_t i;
3510     int offset = 0;
3511     tng_bool same_hash;
3512     tng_trajectory_frame_set_t frame_set =
3513     &tng_data->current_trajectory_frame_set;
3514
3515     tng_particle_mapping_t mapping, mappings;
3516
3517     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3518     {
3519         return(TNG_CRITICAL);
3520     }
3521
3522     if(block->block_contents)
3523     {
3524         free(block->block_contents);
3525     }
3526
3527     block->block_contents = malloc(block->block_contents_size);
3528     if(!block->block_contents)
3529     {
3530         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3531                block->block_contents_size, __FILE__, __LINE__);
3532         return(TNG_CRITICAL);
3533     }
3534
3535     /* Read the whole block into block_contents to be able to write it to disk
3536      *  even if it cannot be interpreted. */
3537     if(fread(block->block_contents, block->block_contents_size, 1,
3538         tng_data->input_file) == 0)
3539     {
3540         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3541         return(TNG_CRITICAL);
3542     }
3543
3544     /* FIXME: Does not check if the size of the contents matches the expected
3545      * size or if the contents can be read. */
3546
3547     if(hash_mode == TNG_USE_HASH)
3548     {
3549         tng_md5_hash_match_verify(block, &same_hash);
3550         if(same_hash != TNG_TRUE)
3551         {
3552             fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
3553                 "%s: %d\n",
3554                 __FILE__, __LINE__);
3555     /*         return(TNG_FAILURE); */
3556         }
3557     }
3558
3559     frame_set->n_mapping_blocks++;
3560     mappings = realloc(frame_set->mappings,
3561                        sizeof(struct tng_particle_mapping) *
3562                        frame_set->n_mapping_blocks);
3563     if(!mappings)
3564     {
3565         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3566                block->block_contents_size, __FILE__, __LINE__);
3567         free(frame_set->mappings);
3568         frame_set->mappings = 0;
3569         return(TNG_CRITICAL);
3570     }
3571     frame_set->mappings = mappings;
3572     mapping = &mappings[frame_set->n_mapping_blocks - 1];
3573
3574
3575     memcpy(&mapping->num_first_particle, block->block_contents+offset,
3576            sizeof(mapping->num_first_particle));
3577     if(tng_data->input_endianness_swap_func_64)
3578     {
3579         if(tng_data->input_endianness_swap_func_64(tng_data,
3580                                                    &mapping->num_first_particle)
3581             != TNG_SUCCESS)
3582         {
3583             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3584                     __FILE__, __LINE__);
3585         }
3586     }
3587     offset += sizeof(mapping->num_first_particle);
3588
3589     memcpy(&mapping->n_particles, block->block_contents+offset,
3590            sizeof(mapping->n_particles));
3591     if(tng_data->input_endianness_swap_func_64)
3592     {
3593         if(tng_data->input_endianness_swap_func_64(tng_data,
3594                                                    &mapping->n_particles)
3595             != TNG_SUCCESS)
3596         {
3597             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3598                     __FILE__, __LINE__);
3599         }
3600     }
3601     offset += sizeof(mapping->n_particles);
3602
3603     mapping->real_particle_numbers = malloc(mapping->n_particles *
3604                                             sizeof(int64_t));
3605     if(!mapping->real_particle_numbers)
3606     {
3607         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3608                 mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
3609         return(TNG_CRITICAL);
3610     }
3611
3612     /* If the byte order needs to be swapped the data must be read one value at
3613      * a time and swapped */
3614     if(tng_data->input_endianness_swap_func_64)
3615     {
3616         for(i = 0; i < mapping->n_particles; i++)
3617         {
3618             memcpy(&mapping->real_particle_numbers[i],
3619                     block->block_contents + offset,
3620                     sizeof(int64_t));
3621             if(tng_data->input_endianness_swap_func_64(tng_data,
3622                                             &mapping->real_particle_numbers[i])
3623                 != TNG_SUCCESS)
3624             {
3625                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3626                         __FILE__, __LINE__);
3627             }
3628             offset += sizeof(int64_t);
3629         }
3630     }
3631     /* Otherwise the data can be read all at once */
3632     else
3633     {
3634         memcpy(mapping->real_particle_numbers, block->block_contents + offset,
3635                mapping->n_particles * sizeof(int64_t));
3636     }
3637
3638
3639     return(TNG_SUCCESS);
3640 }
3641
3642 /** Write the atom mappings of the current trajectory frame set
3643  * @param tng_data is a trajectory data container.
3644  * @param block is a general block container.
3645  * @param mapping_block_nr is the index of the mapping block to write.
3646  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3647  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3648  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
3649  * has occurred or TNG_CRITICAL (2) if a major error has occured.
3650  */
3651 static tng_function_status tng_trajectory_mapping_block_write
3652                 (tng_trajectory_t tng_data,
3653                  tng_gen_block_t block,
3654                  int mapping_block_nr,
3655                  const char hash_mode)
3656 {
3657     char *temp_name;
3658     int i, offset = 0;
3659     unsigned int name_len;
3660     tng_particle_mapping_t mapping =
3661     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
3662
3663     if(mapping_block_nr >=
3664        tng_data->current_trajectory_frame_set.n_mapping_blocks)
3665     {
3666         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
3667                __FILE__, __LINE__);
3668         return(TNG_FAILURE);
3669     }
3670
3671     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3672     {
3673         return(TNG_CRITICAL);
3674     }
3675
3676     name_len = (int)strlen("PARTICLE MAPPING");
3677
3678     if(!block->name || strlen(block->name) < name_len)
3679     {
3680         temp_name = realloc(block->name, name_len + 1);
3681         if(!temp_name)
3682         {
3683             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3684                    name_len+1, __FILE__, __LINE__);
3685             free(block->name);
3686             block->name = 0;
3687             return(TNG_CRITICAL);
3688         }
3689         block->name = temp_name;
3690     }
3691     strcpy(block->name, "PARTICLE MAPPING");
3692     block->id = TNG_PARTICLE_MAPPING;
3693
3694     block->block_contents_size = sizeof(int64_t) * (2 + mapping->n_particles);
3695
3696     if(block->block_contents)
3697     {
3698         free(block->block_contents);
3699     }
3700     block->block_contents = malloc(block->block_contents_size);
3701     if(!block->block_contents)
3702     {
3703         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3704                block->block_contents_size, __FILE__, __LINE__);
3705         return(TNG_CRITICAL);
3706     }
3707
3708     memcpy(block->block_contents, &mapping->num_first_particle,
3709            sizeof(mapping->num_first_particle));
3710     if(tng_data->output_endianness_swap_func_64)
3711     {
3712         if(tng_data->output_endianness_swap_func_64(tng_data,
3713                                       (int64_t *)block->header_contents+offset)
3714             != TNG_SUCCESS)
3715         {
3716             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3717                     __FILE__, __LINE__);
3718         }
3719     }
3720     offset += sizeof(mapping->num_first_particle);
3721
3722     memcpy(block->block_contents+offset, &mapping->n_particles,
3723            sizeof(mapping->n_particles));
3724     if(tng_data->output_endianness_swap_func_64)
3725     {
3726         if(tng_data->output_endianness_swap_func_64(tng_data,
3727                                       (int64_t *)block->header_contents+offset)
3728             != TNG_SUCCESS)
3729         {
3730             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3731                     __FILE__, __LINE__);
3732         }
3733     }
3734     offset += sizeof(mapping->n_particles);
3735
3736     if(tng_data->output_endianness_swap_func_64)
3737     {
3738         for(i = 0; i < mapping->n_particles; i++)
3739         {
3740             memcpy(block->block_contents+offset, &mapping->real_particle_numbers[i],
3741                 sizeof(int64_t));
3742             if(tng_data->output_endianness_swap_func_64(tng_data,
3743                                         (int64_t *)block->header_contents+offset)
3744                 != TNG_SUCCESS)
3745             {
3746                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3747                         __FILE__, __LINE__);
3748             }
3749             offset += sizeof(int64_t);
3750         }
3751     }
3752     else
3753     {
3754         memcpy(block->block_contents+offset, mapping->real_particle_numbers,
3755                mapping->n_particles * sizeof(int64_t));
3756     }
3757
3758
3759     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3760     {
3761         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3762                tng_data->output_file_path, __FILE__, __LINE__);
3763         return(TNG_CRITICAL);
3764     }
3765
3766     if(fwrite(block->block_contents, block->block_contents_size, 1,
3767               tng_data->output_file) != 1)
3768     {
3769         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
3770         return(TNG_CRITICAL);
3771     }
3772
3773     return(TNG_SUCCESS);
3774 }
3775
3776 /** Prepare a block for storing particle data
3777  * @param tng_data is a trajectory data container.
3778  * @param block_type_flag specifies if this is a trajectory block or a
3779  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
3780  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3781  * error has occured.
3782  */
3783 static tng_function_status tng_particle_data_block_create
3784                 (tng_trajectory_t tng_data,
3785                  const char block_type_flag)
3786 {
3787     tng_trajectory_frame_set_t frame_set =
3788     &tng_data->current_trajectory_frame_set;
3789
3790     tng_particle_data_t data;
3791
3792     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
3793     {
3794         frame_set->n_particle_data_blocks++;
3795         data = realloc(frame_set->tr_particle_data,
3796                     sizeof(struct tng_particle_data) *
3797                     frame_set->n_particle_data_blocks);
3798         if(!data)
3799         {
3800             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
3801                 sizeof(struct tng_particle_data) *
3802                 frame_set->n_particle_data_blocks,
3803                 __FILE__, __LINE__);
3804             free(frame_set->tr_particle_data);
3805             frame_set->tr_particle_data = 0;
3806             return(TNG_CRITICAL);
3807         }
3808         frame_set->tr_particle_data = data;
3809     }
3810     else
3811     {
3812         tng_data->n_particle_data_blocks++;
3813         data = realloc(tng_data->non_tr_particle_data,
3814                         sizeof(struct tng_particle_data) *
3815                         tng_data->n_particle_data_blocks);
3816         if(!data)
3817         {
3818             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
3819                     sizeof(struct tng_particle_data) *
3820                     tng_data->n_particle_data_blocks,
3821                     __FILE__, __LINE__);
3822             free(tng_data->non_tr_particle_data);
3823             tng_data->non_tr_particle_data = 0;
3824             return(TNG_CRITICAL);
3825         }
3826         tng_data->non_tr_particle_data = data;
3827     }
3828
3829     return(TNG_SUCCESS);
3830 }
3831
3832 static tng_function_status tng_compress(tng_trajectory_t tng_data,
3833                                         tng_gen_block_t block,
3834                                         const int64_t n_frames,
3835                                         const int64_t n_particles,
3836                                         const char type,
3837                                         void *start_pos)
3838 {
3839     int nalgo;
3840     int new_len;
3841     int *alt_algo = 0;
3842     char *dest, *temp;
3843     int64_t algo_find_n_frames;
3844     unsigned long offset;
3845     float f_precision;
3846     double d_precision;
3847
3848     if(block->id != TNG_TRAJ_POSITIONS &&
3849        block->id != TNG_TRAJ_VELOCITIES)
3850     {
3851         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
3852                "TNG method. %s: %d\n", __FILE__, __LINE__);
3853         return(TNG_FAILURE);
3854     }
3855     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
3856     {
3857         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
3858         return(TNG_FAILURE);
3859     }
3860
3861     if(n_frames <= 0 || n_particles <= 0)
3862     {
3863         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
3864                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
3865         return(TNG_FAILURE);
3866     }
3867
3868     f_precision = 1/tng_data->compression_precision;
3869     d_precision = 1/tng_data->compression_precision;
3870
3871     if(block->id == TNG_TRAJ_POSITIONS)
3872     {
3873         /* If there is only one frame in this frame set and there might be more
3874          * do not store the algorithm as the compression algorithm, but find
3875          * the best one without storing it */
3876         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
3877         {
3878             nalgo = tng_compress_nalgo();
3879             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
3880             if(type == TNG_FLOAT_DATA)
3881             {
3882                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
3883                                                         (int)n_frames,
3884                                                         f_precision,
3885                                                         0, alt_algo,
3886                                                         &new_len);
3887
3888             }
3889             else
3890             {
3891                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
3892                                            (int)n_frames,
3893                                            d_precision,
3894                                            0, alt_algo,
3895                                            &new_len);
3896             }
3897         }
3898         else if(!tng_data->compress_algo_pos)
3899         {
3900             if(n_frames > 10)
3901             {
3902                 algo_find_n_frames = 5;
3903             }
3904             else
3905             {
3906                 algo_find_n_frames = n_frames;
3907             }
3908
3909             nalgo = tng_compress_nalgo();
3910             tng_data->compress_algo_pos=malloc(nalgo *
3911                                            sizeof *tng_data->compress_algo_pos);
3912             if(type == TNG_FLOAT_DATA)
3913             {
3914                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
3915                                                         (int)algo_find_n_frames,
3916                                                         f_precision,
3917                                                         0, tng_data->
3918                                                         compress_algo_pos,
3919                                                         &new_len);
3920
3921                 if(algo_find_n_frames < n_frames)
3922                 {
3923                     dest = tng_compress_pos_float(start_pos, (int)n_particles,
3924                                                   (int)n_frames,
3925                                                   f_precision,
3926                                                   0, tng_data->compress_algo_pos,
3927                                                   &new_len);
3928                 }
3929             }
3930             else
3931             {
3932                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
3933                                            (int)algo_find_n_frames,
3934                                            d_precision,
3935                                            0, tng_data->
3936                                            compress_algo_pos,
3937                                            &new_len);
3938
3939                 if(algo_find_n_frames < n_frames)
3940                 {
3941                     dest = tng_compress_pos(start_pos, (int)n_particles,
3942                                             (int)n_frames,
3943                                             d_precision, 0,
3944                                             tng_data->compress_algo_pos,
3945                                             &new_len);
3946                 }
3947             }
3948         }
3949         else
3950         {
3951             if(type == TNG_FLOAT_DATA)
3952             {
3953                 dest = tng_compress_pos_float(start_pos, (int)n_particles,
3954                                               (int)n_frames,
3955                                               f_precision, 0,
3956                                               tng_data->compress_algo_pos, &new_len);
3957             }
3958             else
3959             {
3960                 dest = tng_compress_pos(start_pos, (int)n_particles,
3961                                         (int)n_frames,
3962                                         d_precision, 0,
3963                                         tng_data->compress_algo_pos,
3964                                         &new_len);
3965             }
3966         }
3967     }
3968     else if(block->id == TNG_TRAJ_VELOCITIES)
3969     {
3970         /* If there is only one frame in this frame set and there might be more
3971          * do not store the algorithm as the compression algorithm, but find
3972          * the best one without storing it */
3973         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
3974         {
3975             nalgo = tng_compress_nalgo();
3976             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
3977             if(type == TNG_FLOAT_DATA)
3978             {
3979                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
3980                                                         (int)n_frames,
3981                                                         f_precision,
3982                                                         0, alt_algo,
3983                                                         &new_len);
3984
3985             }
3986             else
3987             {
3988                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
3989                                                   (int)n_frames,
3990                                                   d_precision,
3991                                                   0, alt_algo,
3992                                                   &new_len);
3993             }
3994         }
3995         else if(!tng_data->compress_algo_vel)
3996         {
3997             if(n_frames > 10)
3998             {
3999                 algo_find_n_frames = 5;
4000             }
4001             else
4002             {
4003                 algo_find_n_frames = n_frames;
4004             }
4005
4006             nalgo = tng_compress_nalgo();
4007             tng_data->compress_algo_vel=malloc(nalgo *
4008                                            sizeof *tng_data->compress_algo_vel);
4009
4010             if(type == TNG_FLOAT_DATA)
4011             {
4012                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4013                                                         (int)algo_find_n_frames,
4014                                                         f_precision,
4015                                                         0, tng_data->
4016                                                         compress_algo_vel,
4017                                                         &new_len);
4018                 if(algo_find_n_frames < n_frames)
4019                 {
4020                     dest = tng_compress_vel_float(start_pos, (int)n_particles,
4021                                                   (int)n_frames,
4022                                                   f_precision,
4023                                                   0, tng_data->compress_algo_vel,
4024                                                   &new_len);
4025                 }
4026             }
4027             else
4028             {
4029                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4030                                                   (int)algo_find_n_frames,
4031                                                   d_precision,
4032                                                   0, tng_data->
4033                                                   compress_algo_vel,
4034                                                   &new_len);
4035                 if(algo_find_n_frames < n_frames)
4036                 {
4037                     dest = tng_compress_vel(start_pos, (int)n_particles,
4038                                             (int)n_frames,
4039                                             d_precision,
4040                                             0, tng_data->compress_algo_vel,
4041                                             &new_len);
4042                 }
4043             }
4044         }
4045         else
4046         {
4047             if(type == TNG_FLOAT_DATA)
4048             {
4049                 dest = tng_compress_vel_float(start_pos, (int)n_particles,
4050                                               (int)n_frames,
4051                                               f_precision,
4052                                               0, tng_data->
4053                                               compress_algo_vel,
4054                                               &new_len);
4055             }
4056             else
4057             {
4058                 dest = tng_compress_vel(start_pos, (int)n_particles,
4059                                         (int)n_frames,
4060                                         d_precision,
4061                                         0, tng_data->
4062                                         compress_algo_vel,
4063                                         &new_len);
4064             }
4065         }
4066     }
4067     else
4068     {
4069         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
4070         return(TNG_FAILURE);
4071     }
4072
4073     offset = (unsigned long)((char *)start_pos - block->block_contents);
4074
4075     if(alt_algo)
4076     {
4077         free(alt_algo);
4078     }
4079
4080     block->block_contents_size = new_len + offset;
4081
4082     temp = realloc(block->block_contents, block->block_contents_size);
4083     if(!temp)
4084     {
4085         free(block->block_contents);
4086         block->block_contents = 0;
4087         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4088                block->block_contents_size, __FILE__, __LINE__);
4089         return(TNG_CRITICAL);
4090     }
4091     block->block_contents = temp;
4092     if(dest)
4093     {
4094         memcpy(temp + offset, dest, new_len);
4095         free(dest);
4096     }
4097     else
4098     {
4099         fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
4100         return(TNG_FAILURE);
4101     }
4102
4103     return(TNG_SUCCESS);
4104 }
4105
4106 static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
4107                                           tng_gen_block_t block,
4108                                           const char type,
4109                                           void *start_pos,
4110                                           const unsigned long uncompressed_len)
4111 {
4112     char *temp;
4113     double *d_dest = 0;
4114     float *f_dest = 0;
4115     unsigned long offset;
4116     int result;
4117     (void)tng_data;
4118
4119     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
4120
4121     if(block->id != TNG_TRAJ_POSITIONS &&
4122        block->id != TNG_TRAJ_VELOCITIES)
4123     {
4124         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
4125                "TNG method.\n");
4126         return(TNG_FAILURE);
4127     }
4128     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4129     {
4130         fprintf(stderr, "TNG library: Data type not supported.\n");
4131         return(TNG_FAILURE);
4132     }
4133
4134     if(type == TNG_FLOAT_DATA)
4135     {
4136         f_dest = malloc(uncompressed_len);
4137         if(!f_dest)
4138         {
4139             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4140                 uncompressed_len, __FILE__, __LINE__);
4141             return(TNG_CRITICAL);
4142         }
4143         result = tng_compress_uncompress_float(start_pos, f_dest);
4144     }
4145     else
4146     {
4147         d_dest = malloc(uncompressed_len);
4148         if(!d_dest)
4149         {
4150             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4151                 uncompressed_len, __FILE__, __LINE__);
4152             return(TNG_CRITICAL);
4153         }
4154         result = tng_compress_uncompress(start_pos, d_dest);
4155     }
4156
4157     if(result == 1)
4158     {
4159         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
4160         return(TNG_FAILURE);
4161     }
4162
4163     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
4164
4165     block->block_contents_size = (int64_t)(uncompressed_len + offset);
4166
4167     temp = realloc(block->block_contents, uncompressed_len + offset);
4168     if(!temp)
4169     {
4170         free(block->block_contents);
4171         block->block_contents = 0;
4172         if(d_dest)
4173         {
4174             free(d_dest);
4175         }
4176         if(f_dest)
4177         {
4178             free(f_dest);
4179         }
4180         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4181                block->block_contents_size, __FILE__, __LINE__);
4182         return(TNG_CRITICAL);
4183     }
4184
4185     if(type == TNG_FLOAT_DATA)
4186     {
4187         memcpy(temp + offset, f_dest, uncompressed_len);
4188     }
4189     else
4190     {
4191         memcpy(temp + offset, d_dest, uncompressed_len);
4192     }
4193
4194     block->block_contents = temp;
4195
4196     if(d_dest)
4197     {
4198         free(d_dest);
4199     }
4200     if(f_dest)
4201     {
4202         free(f_dest);
4203     }
4204     return(TNG_SUCCESS);
4205 }
4206
4207 #ifdef USE_ZLIB
4208 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
4209                                              tng_gen_block_t block,
4210                                              void *start_pos, const int len)
4211 {
4212     Bytef *dest;
4213     char *temp;
4214     unsigned long max_len, stat, offset;
4215     (void)tng_data;
4216
4217     max_len = compressBound(len);
4218     dest = malloc(max_len);
4219
4220     stat = compress(dest, &max_len, start_pos, len);
4221     if(stat != (unsigned long)Z_OK)
4222     {
4223         free(dest);
4224         if(stat == (unsigned long)Z_MEM_ERROR)
4225         {
4226             fprintf(stderr, "TNG library: Not enough memory. ");
4227         }
4228         else if(stat == (unsigned long)Z_BUF_ERROR)
4229         {
4230             fprintf(stderr, "TNG library: Destination buffer too small. ");
4231         }
4232         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
4233         return(TNG_FAILURE);
4234     }
4235
4236     offset = (char *)start_pos - block->block_contents;
4237
4238     block->block_contents_size = max_len + offset;
4239
4240     temp = realloc(block->block_contents, block->block_contents_size);
4241     if(!temp)
4242     {
4243         free(block->block_contents);
4244         free(dest);
4245         block->block_contents = 0;
4246         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4247                block->block_contents_size, __FILE__, __LINE__);
4248         return(TNG_CRITICAL);
4249     }
4250
4251     block->block_contents = temp;
4252
4253     memcpy(temp + offset, dest, max_len);
4254
4255     free(dest);
4256
4257     return(TNG_SUCCESS);
4258 }
4259
4260 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
4261                                                tng_gen_block_t block,
4262                                                void *start_pos,
4263                                                unsigned long uncompressed_len)
4264 {
4265     Bytef *dest;
4266     char *temp;
4267     unsigned long stat;
4268     int offset;
4269     (void)tng_data;
4270
4271     offset = (char *)start_pos - (char *)block->block_contents;
4272
4273     dest = malloc(uncompressed_len);
4274
4275     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
4276                       block->block_contents_size - offset);
4277
4278     if(stat != Z_OK)
4279     {
4280         free(dest);
4281         if(stat == (unsigned long)Z_MEM_ERROR)
4282         {
4283             fprintf(stderr, "TNG library: Not enough memory. ");
4284         }
4285         else if(stat == (unsigned long)Z_BUF_ERROR)
4286         {
4287             fprintf(stderr, "TNG library: Destination buffer too small. ");
4288         }
4289         else if(stat == (unsigned long)Z_DATA_ERROR)
4290         {
4291             fprintf(stderr, "TNG library: Data corrupt. ");
4292         }
4293         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
4294                __LINE__);
4295         return(TNG_FAILURE);
4296     }
4297
4298
4299     block->block_contents_size = uncompressed_len + offset;
4300
4301     temp = realloc(block->block_contents, uncompressed_len + offset);
4302     if(!temp)
4303     {
4304         free(block->block_contents);
4305         block->block_contents = 0;
4306         free(dest);
4307         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4308                block->block_contents_size, __FILE__, __LINE__);
4309         return(TNG_CRITICAL);
4310     }
4311
4312     memcpy(temp + offset, dest, uncompressed_len);
4313
4314     block->block_contents = temp;
4315
4316     free(dest);
4317     return(TNG_SUCCESS);
4318 }
4319 #endif
4320
4321 /** Allocate memory for storing particle data.
4322  * The allocated block will be refered to by data->values.
4323  * @param tng_data is a trajectory data container.
4324  * @param data is the data struct, which will contain the allocated memory in
4325  * data->values.
4326  * @param n_frames is the number of frames of data to store.
4327  * @param n_particles is the number of particles with data.
4328  * @param n_values_per_frame is the number of data values per particle and
4329  * frame.
4330  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4331  * error has occured.
4332  */
4333 static tng_function_status tng_allocate_particle_data_mem
4334                 (tng_trajectory_t tng_data,
4335                  tng_particle_data_t data,
4336                  int64_t n_frames,
4337                  int64_t stride_length,
4338                  const int64_t n_particles,
4339                  const int64_t n_values_per_frame)
4340 {
4341     void ***values;
4342     int64_t i, j, k, size, frame_alloc;
4343     (void)tng_data;
4344
4345     if(n_particles == 0 || n_values_per_frame == 0)
4346     {
4347         return(TNG_FAILURE);
4348     }
4349
4350     if(data->strings && data->datatype == TNG_CHAR_DATA)
4351     {
4352         for(i = data->n_frames; i--;)
4353         {
4354             for(j = n_particles; j--;)
4355             {
4356                 for(k = data->n_values_per_frame; k--;)
4357                 {
4358                     if(data->strings[i][j][k])
4359                     {
4360                         free(data->strings[i][j][k]);
4361                     }
4362                 }
4363                 free(data->strings[i][j]);
4364             }
4365             free(data->strings[i]);
4366         }
4367         free(data->strings);
4368     }
4369     data->n_frames = n_frames;
4370     n_frames = tng_max_i64(1, n_frames);
4371     data->stride_length = tng_max_i64(1, stride_length);
4372     data->n_values_per_frame = n_values_per_frame;
4373     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
4374
4375     if(data->datatype == TNG_CHAR_DATA)
4376     {
4377         data->strings = malloc(sizeof(char ***) * frame_alloc);
4378         for(i = frame_alloc; i-- ;)
4379         {
4380             data->strings[i] = malloc(sizeof(char **) *
4381                                     n_particles);
4382             if(!data->strings[i])
4383             {
4384                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4385                     sizeof(union data_values *) * n_particles,
4386                     __FILE__, __LINE__);
4387                 return(TNG_CRITICAL);
4388             }
4389             for(j = n_particles; j--;)
4390             {
4391                 data->strings[i][j] = malloc(sizeof(char *) *
4392                                             n_values_per_frame);
4393                 if(!data->strings[i][j])
4394                 {
4395                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4396                         sizeof(union data_values) * n_values_per_frame,
4397                         __FILE__, __LINE__);
4398                     return(TNG_CRITICAL);
4399                 }
4400                 for(k = n_values_per_frame; k--;)
4401                 {
4402                     data->strings[i][j][k] = 0;
4403                 }
4404             }
4405         }
4406     }
4407     else
4408     {
4409         switch(data->datatype)
4410         {
4411         case TNG_INT_DATA:
4412             size = sizeof(int64_t);
4413             break;
4414         case TNG_FLOAT_DATA:
4415             size = sizeof(float);
4416             break;
4417         case TNG_DOUBLE_DATA:
4418         default:
4419             size = sizeof(double);
4420         }
4421
4422         values = realloc(data->values,
4423                          size * frame_alloc *
4424                          n_particles * n_values_per_frame);
4425         if(!values)
4426         {
4427             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4428                    size * frame_alloc *
4429                    n_particles * n_values_per_frame,
4430                    __FILE__, __LINE__);
4431             free(data->values);
4432             data->values = 0;
4433             return(TNG_CRITICAL);
4434         }
4435         data->values = values;
4436     }
4437     return(TNG_SUCCESS);
4438 }
4439
4440 static tng_function_status tng_particle_data_find
4441                 (tng_trajectory_t tng_data,
4442                  const int64_t id,
4443                  tng_particle_data_t *data)
4444 {
4445     int64_t block_index, i;
4446     tng_trajectory_frame_set_t frame_set = &tng_data->
4447                                            current_trajectory_frame_set;
4448     char block_type_flag;
4449
4450     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4451        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4452     {
4453         block_type_flag = TNG_TRAJECTORY_BLOCK;
4454     }
4455     else
4456     {
4457         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4458     }
4459
4460     block_index = -1;
4461     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4462     {
4463         for(i = frame_set->n_particle_data_blocks; i-- ;)
4464         {
4465             *data = &frame_set->tr_particle_data[i];
4466             if((*data)->block_id == id)
4467             {
4468                 block_index = i;
4469                 break;
4470             }
4471         }
4472     }
4473     else
4474     {
4475         for(i = tng_data->n_particle_data_blocks; i-- ;)
4476         {
4477             *data = &tng_data->non_tr_particle_data[i];
4478             if((*data)->block_id == id)
4479             {
4480                 block_index = i;
4481                 break;
4482             }
4483         }
4484     }
4485     if(block_index == -1)
4486     {
4487         return(TNG_FAILURE);
4488     }
4489     return(TNG_SUCCESS);
4490 }
4491
4492 static tng_function_status tng_data_find
4493                 (tng_trajectory_t tng_data,
4494                  const int64_t id,
4495                  tng_non_particle_data_t *data)
4496 {
4497     int64_t block_index, i;
4498     tng_trajectory_frame_set_t frame_set = &tng_data->
4499                                            current_trajectory_frame_set;
4500     char block_type_flag;
4501
4502     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4503        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4504     {
4505         block_type_flag = TNG_TRAJECTORY_BLOCK;
4506     }
4507     else
4508     {
4509         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4510     }
4511
4512     block_index = -1;
4513     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4514     {
4515         for(i = frame_set->n_data_blocks; i-- ;)
4516         {
4517             *data = &frame_set->tr_data[i];
4518             if((*data)->block_id == id)
4519             {
4520                 block_index = i;
4521                 break;
4522             }
4523         }
4524         if(block_index == -1)
4525         {
4526             for(i = tng_data->n_data_blocks; i-- ;)
4527             {
4528                 *data = &tng_data->non_tr_data[i];
4529                 if((*data)->block_id == id)
4530                 {
4531                     block_index = i;
4532                     break;
4533                 }
4534             }
4535         }
4536     }
4537     else
4538     {
4539         for(i = tng_data->n_data_blocks; i-- ;)
4540         {
4541             *data = &tng_data->non_tr_data[i];
4542             if((*data)->block_id == id)
4543             {
4544                 block_index = i;
4545                 break;
4546             }
4547         }
4548     }
4549     if(block_index == -1)
4550     {
4551         return(TNG_FAILURE);
4552     }
4553     return(TNG_SUCCESS);
4554 }
4555
4556 /** Read the values of a particle data block
4557  * @param tng_data is a trajectory data container.
4558  * @param block is the block to store the data (should already contain
4559  * the block headers and the block contents).
4560  * @param offset is the reading offset to point at the place where the actual
4561  * values are stored, starting from the beginning of the block_contents. The
4562  * offset is changed during the reading.
4563  * @param datatype is the type of data of the data block (char, int, float or
4564  * double).
4565  * @param num_first_particle is the number of the first particle in the data
4566  * block. This should be the same as in the corresponding particle mapping
4567  * block.
4568  * @param n_particles is the number of particles in the data block. This should
4569  * be the same as in the corresponding particle mapping block.
4570  * @param first_frame_with_data is the frame number of the first frame with data
4571  * in this data block.
4572  * @param stride_length is the number of frames between each data entry.
4573  * @param n_frames is the number of frames in this data block.
4574  * @param n_values is the number of values per particle and frame stored in this
4575  * data block.
4576  * @param codec_id is the ID of the codec to compress the data.
4577  * @param multiplier is the multiplication factor applied to each data value
4578  * before compression. This factor is applied since some compression algorithms
4579  * work only on integers.
4580  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4581  * error has occured.
4582  */
4583 static tng_function_status tng_particle_data_read
4584                 (tng_trajectory_t tng_data,
4585                  tng_gen_block_t block,
4586                  int *offset,
4587                  const char datatype,
4588                  const int64_t num_first_particle,
4589                  const int64_t n_particles,
4590                  const int64_t first_frame_with_data,
4591                  const int64_t stride_length,
4592                  int64_t n_frames,
4593                  const int64_t n_values,
4594                  const int64_t codec_id,
4595                  const double multiplier)
4596 {
4597     int64_t i, j, k, tot_n_particles, n_frames_div;
4598     int size, len;
4599     unsigned long data_size;
4600     char ***first_dim_values, **second_dim_values;
4601     tng_particle_data_t data;
4602     tng_trajectory_frame_set_t frame_set =
4603     &tng_data->current_trajectory_frame_set;
4604     char block_type_flag;
4605
4606     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
4607
4608     switch(datatype)
4609     {
4610     case TNG_CHAR_DATA:
4611         size = 1;
4612         break;
4613     case TNG_INT_DATA:
4614         size = sizeof(int64_t);
4615         break;
4616     case TNG_FLOAT_DATA:
4617         size = sizeof(float);
4618         break;
4619     case TNG_DOUBLE_DATA:
4620     default:
4621         size = sizeof(double);
4622     }
4623
4624     /* If the block does not exist, create it */
4625     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
4626     {
4627         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
4628         {
4629             block_type_flag = TNG_TRAJECTORY_BLOCK;
4630         }
4631         else
4632         {
4633             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4634         }
4635
4636         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
4637            TNG_SUCCESS)
4638         {
4639             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
4640                    __FILE__, __LINE__);
4641             return(TNG_CRITICAL);
4642         }
4643         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4644         {
4645             data = &frame_set->tr_particle_data[frame_set->
4646                                                 n_particle_data_blocks - 1];
4647         }
4648         else
4649         {
4650             data = &tng_data->non_tr_particle_data[tng_data->
4651                                                    n_particle_data_blocks - 1];
4652         }
4653         data->block_id = block->id;
4654
4655         data->block_name = malloc(strlen(block->name) + 1);
4656         if(!data->block_name)
4657         {
4658             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4659                    (int)strlen(block->name)+1, __FILE__, __LINE__);
4660             return(TNG_CRITICAL);
4661         }
4662         strcpy(data->block_name, block->name);
4663
4664         data->datatype = datatype;
4665
4666         data->values = 0;
4667         /* FIXME: Memory leak from strings. */
4668         data->strings = 0;
4669         data->n_frames = 0;
4670         data->codec_id = codec_id;
4671         data->compression_multiplier = multiplier;
4672         data->last_retrieved_frame = -1;
4673     }
4674
4675     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
4676        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
4677        tng_data->var_num_atoms_flag)
4678     {
4679         tot_n_particles = frame_set->n_particles;
4680     }
4681     else
4682     {
4683         tot_n_particles = tng_data->n_particles;
4684     }
4685
4686     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
4687
4688     if(codec_id != TNG_UNCOMPRESSED)
4689     {
4690         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
4691         switch(codec_id)
4692         {
4693         case TNG_XTC_COMPRESSION:
4694             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
4695             break;
4696         case TNG_TNG_COMPRESSION:
4697 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
4698             if(tng_uncompress(tng_data, block, datatype,
4699                               block->block_contents + *offset,
4700                               data_size) != TNG_SUCCESS)
4701             {
4702                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
4703                        __FILE__, __LINE__);
4704                 return(TNG_CRITICAL);
4705             }
4706 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
4707             break;
4708 #ifdef USE_ZLIB
4709         case TNG_GZIP_COMPRESSION:
4710 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
4711             if(tng_gzip_uncompress(tng_data, block,
4712                                    block->block_contents + *offset,
4713                                    data_size) != TNG_SUCCESS)
4714             {
4715                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
4716                     __LINE__);
4717                 return(TNG_CRITICAL);
4718             }
4719 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
4720             break;
4721 #endif
4722         }
4723     }
4724     /* Allocate memory */
4725     if(!data->values || data->n_frames != n_frames ||
4726        data->n_values_per_frame != n_values)
4727     {
4728         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
4729                                           stride_length,
4730                                           tot_n_particles, n_values) !=
4731            TNG_SUCCESS)
4732         {
4733             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
4734                    __FILE__, __LINE__);
4735             return(TNG_CRITICAL);
4736         }
4737     }
4738
4739     data->first_frame_with_data = first_frame_with_data;
4740
4741     if(datatype == TNG_CHAR_DATA)
4742     {
4743         for(i = 0; i < n_frames_div; i++)
4744         {
4745             first_dim_values = data->strings[i];
4746             for(j = num_first_particle; j < num_first_particle + n_particles;
4747                 j++)
4748             {
4749                 second_dim_values = first_dim_values[j];
4750                 for(k = 0; k < n_values; k++)
4751                 {
4752                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
4753                               TNG_MAX_STR_LEN);
4754                     if(second_dim_values[k])
4755                     {
4756                         free(second_dim_values[k]);
4757                     }
4758                     second_dim_values[k] = malloc(len);
4759                     if(!second_dim_values[k])
4760                     {
4761                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4762                             len, __FILE__, __LINE__);
4763                         return(TNG_CRITICAL);
4764                     }
4765                     strncpy(second_dim_values[k],
4766                             block->block_contents+*offset, len);
4767                     *offset += len;
4768                 }
4769             }
4770         }
4771     }
4772     else
4773     {
4774         memcpy((char *)data->values + n_frames_div * size * n_values *
4775                num_first_particle,
4776                block->block_contents + *offset,
4777                block->block_contents_size - *offset);
4778         switch(datatype)
4779         {
4780         case TNG_FLOAT_DATA:
4781             if(tng_data->input_endianness_swap_func_32)
4782             {
4783                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
4784                 {
4785                     if(tng_data->input_endianness_swap_func_32(tng_data,
4786                         (int32_t *)((char *)data->values + i))
4787                         != TNG_SUCCESS)
4788                     {
4789                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4790                                 __FILE__, __LINE__);
4791                     }
4792                 }
4793             }
4794             break;
4795         case TNG_INT_DATA:
4796         case TNG_DOUBLE_DATA:
4797             if(tng_data->input_endianness_swap_func_64)
4798             {
4799                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
4800                 {
4801                     if(tng_data->input_endianness_swap_func_64(tng_data,
4802                         (int64_t *)((char *)data->values + i))
4803                         != TNG_SUCCESS)
4804                     {
4805                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4806                                 __FILE__, __LINE__);
4807                     }
4808                 }
4809             }
4810             break;
4811         case TNG_CHAR_DATA:
4812             break;
4813         }
4814     }
4815     return(TNG_SUCCESS);
4816 }
4817
4818 /** Write a particle data block
4819  * @param tng_data is a trajectory data container.
4820  * @param block is the block to store the data (should already contain
4821  * the block headers and the block contents).
4822  * @param block_index is the index number of the data block in the frame set.
4823  * @param mapping is the particle mapping that is relevant for the data block.
4824  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4825  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4826  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4827  * error has occured.
4828  */
4829 static tng_function_status tng_particle_data_block_write
4830                 (tng_trajectory_t tng_data,
4831                  tng_gen_block_t block,
4832                  const int64_t block_index,
4833                  const tng_particle_mapping_t mapping,
4834                  const char hash_mode)
4835 {
4836     int64_t n_particles, num_first_particle, n_frames, stride_length;
4837     int64_t frame_step, data_start_pos;
4838     int64_t i, j, k;
4839     int size;
4840     size_t len, offset = 0;
4841     char dependency, temp, *temp_name;
4842     double multiplier;
4843     char ***first_dim_values, **second_dim_values;
4844     tng_trajectory_frame_set_t frame_set;
4845     tng_function_status stat;
4846
4847     tng_particle_data_t data;
4848     char block_type_flag;
4849
4850     frame_set = &tng_data->current_trajectory_frame_set;
4851
4852     /* If we have already started writing frame sets it is too late to write
4853      * non-trajectory data blocks */
4854     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
4855     {
4856         block_type_flag = TNG_TRAJECTORY_BLOCK;
4857     }
4858     else
4859     {
4860         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4861     }
4862
4863     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4864     {
4865         return(TNG_CRITICAL);
4866     }
4867
4868     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4869     {
4870         data = &frame_set->tr_particle_data[block_index];
4871
4872         /* If this data block has not had any data added in this frame set
4873          * do not write it. */
4874         if(data->first_frame_with_data < frame_set->first_frame)
4875         {
4876             return(TNG_SUCCESS);
4877         }
4878
4879         stride_length = tng_max_i64(1, data->stride_length);
4880     }
4881     else
4882     {
4883         data = &tng_data->non_tr_particle_data[block_index];
4884         stride_length = 1;
4885     }
4886
4887     switch(data->datatype)
4888     {
4889     case TNG_CHAR_DATA:
4890         size = 1;
4891         break;
4892     case TNG_INT_DATA:
4893         size = sizeof(int64_t);
4894         break;
4895     case TNG_FLOAT_DATA:
4896         size = sizeof(float);
4897         break;
4898     case TNG_DOUBLE_DATA:
4899     default:
4900         size = sizeof(double);
4901     }
4902
4903     len = strlen(data->block_name) + 1;
4904
4905     if(!block->name || strlen(block->name) < len)
4906     {
4907         temp_name = realloc(block->name, len);
4908         if(!temp_name)
4909         {
4910             fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
4911                    __FILE__, __LINE__);
4912             free(block->name);
4913             block->name = 0;
4914             return(TNG_CRITICAL);
4915         }
4916         block->name = temp_name;
4917     }
4918     strncpy(block->name, data->block_name, len);
4919     block->id = data->block_id;
4920
4921     /* If writing frame independent data data->n_frames is 0, but n_frames
4922        is used for the loop writing the data (and reserving memory) and needs
4923        to be at least 1 */
4924     n_frames = tng_max_i64(1, data->n_frames);
4925
4926     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4927     {
4928         /* If the frame set is finished before writing the full number of frames
4929            make sure the data block is not longer than the frame set. */
4930         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
4931
4932         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
4933     }
4934
4935     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
4936                  n_frames / stride_length;
4937
4938     /* TNG compression will use compression precision to get integers from
4939      * floating point data. The compression multiplier stores that information
4940      * to be able to return the precision of the compressed data. */
4941     if(data->codec_id == TNG_TNG_COMPRESSION)
4942     {
4943         data->compression_multiplier = tng_data->compression_precision;
4944     }
4945     /* Uncompressed data blocks do not use compression multipliers at all.
4946      * GZip compression does not need it either. */
4947     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
4948     {
4949         data->compression_multiplier = 1.0;
4950     }
4951
4952     if(mapping && mapping->n_particles != 0)
4953     {
4954         n_particles = mapping->n_particles;
4955         num_first_particle = mapping->num_first_particle;
4956     }
4957     else
4958     {
4959         num_first_particle = 0;
4960         if(tng_data->var_num_atoms_flag)
4961         {
4962             n_particles = frame_set->n_particles;
4963         }
4964         else
4965         {
4966             n_particles = tng_data->n_particles;
4967         }
4968     }
4969
4970     block->block_contents_size = sizeof(char) * 2 +
4971                                  sizeof(data->n_values_per_frame) +
4972                                  sizeof(data->codec_id) +
4973                                  sizeof(num_first_particle) +
4974                                  sizeof(n_particles);
4975
4976     if(stride_length > 1)
4977     {
4978         block->block_contents_size += sizeof(data->first_frame_with_data) +
4979                                       sizeof(data->stride_length);
4980     }
4981
4982     if(data->codec_id != TNG_UNCOMPRESSED)
4983     {
4984         block->block_contents_size += sizeof(data->compression_multiplier);
4985     }
4986
4987     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
4988     {
4989         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
4990     }
4991     else
4992     {
4993         dependency = TNG_PARTICLE_DEPENDENT;
4994     }
4995     if(dependency & TNG_FRAME_DEPENDENT)
4996     {
4997         block->block_contents_size += sizeof(char);
4998     }
4999
5000     data_start_pos = block->block_contents_size;
5001
5002     if(data->datatype == TNG_CHAR_DATA)
5003     {
5004         for(i = n_frames; i--;)
5005         {
5006             first_dim_values = data->strings[i];
5007             for(j = num_first_particle; j < num_first_particle + n_particles;
5008                 j++)
5009             {
5010                 second_dim_values = first_dim_values[j];
5011                 for(k = data->n_values_per_frame; k--;)
5012                 {
5013                     block->block_contents_size +=
5014                     strlen(second_dim_values[k]) + 1;
5015                 }
5016             }
5017         }
5018     }
5019     else
5020     {
5021         block->block_contents_size += size * frame_step *
5022                                       n_particles * data->n_values_per_frame;
5023     }
5024
5025     if(block->block_contents)
5026     {
5027         free(block->block_contents);
5028     }
5029     block->block_contents = malloc(block->block_contents_size);
5030     if(!block->block_contents)
5031     {
5032         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5033                block->block_contents_size, __FILE__, __LINE__);
5034         return(TNG_CRITICAL);
5035     }
5036
5037
5038     memcpy(block->block_contents, &data->datatype, sizeof(char));
5039     offset += sizeof(char);
5040
5041     memcpy(block->block_contents+offset, &dependency, sizeof(char));
5042     offset += sizeof(char);
5043
5044     if(dependency & TNG_FRAME_DEPENDENT)
5045     {
5046         if(stride_length > 1)
5047         {
5048             temp = 1;
5049         }
5050         else
5051         {
5052             temp = 0;
5053         }
5054         memcpy(block->block_contents+offset, &temp, sizeof(char));
5055         offset += sizeof(char);
5056     }
5057
5058     memcpy(block->block_contents+offset, &data->n_values_per_frame,
5059            sizeof(data->n_values_per_frame));
5060     if(tng_data->output_endianness_swap_func_64)
5061     {
5062         if(tng_data->output_endianness_swap_func_64(tng_data,
5063            (int64_t *)block->header_contents+offset)
5064             != TNG_SUCCESS)
5065         {
5066             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5067                     __FILE__, __LINE__);
5068         }
5069     }
5070     offset += sizeof(data->n_values_per_frame);
5071
5072     memcpy(block->block_contents+offset, &data->codec_id,
5073            sizeof(data->codec_id));
5074     if(tng_data->output_endianness_swap_func_64)
5075     {
5076         if(tng_data->output_endianness_swap_func_64(tng_data,
5077            (int64_t *)block->header_contents+offset)
5078             != TNG_SUCCESS)
5079         {
5080             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5081                     __FILE__, __LINE__);
5082         }
5083     }
5084     offset += sizeof(data->codec_id);
5085
5086     if(data->codec_id != TNG_UNCOMPRESSED)
5087     {
5088         memcpy(block->block_contents+offset, &data->compression_multiplier,
5089                sizeof(data->compression_multiplier));
5090         if(tng_data->output_endianness_swap_func_64)
5091         {
5092             if(tng_data->output_endianness_swap_func_64(tng_data,
5093                (int64_t *)block->header_contents+offset)
5094                 != TNG_SUCCESS)
5095             {
5096                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5097                         __FILE__, __LINE__);
5098             }
5099         }
5100         offset += sizeof(data->compression_multiplier);
5101     }
5102
5103     if(data->n_frames > 0 && stride_length > 1)
5104     {
5105         /* FIXME: first_frame_with_data is not reliably set */
5106         if(data->first_frame_with_data == 0)
5107         {
5108             data->first_frame_with_data = frame_set->first_frame;
5109         }
5110         memcpy(block->block_contents+offset, &data->first_frame_with_data,
5111                sizeof(data->first_frame_with_data));
5112         if(tng_data->output_endianness_swap_func_64)
5113         {
5114             if(tng_data->output_endianness_swap_func_64(tng_data,
5115                (int64_t *)block->header_contents+offset)
5116                 != TNG_SUCCESS)
5117             {
5118                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5119                         __FILE__, __LINE__);
5120             }
5121         }
5122         offset += sizeof(data->first_frame_with_data);
5123
5124         memcpy(block->block_contents+offset, &stride_length,
5125                sizeof(stride_length));
5126         if(tng_data->output_endianness_swap_func_64)
5127         {
5128             if(tng_data->output_endianness_swap_func_64(tng_data,
5129                (int64_t *)block->header_contents+offset)
5130                 != TNG_SUCCESS)
5131             {
5132                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5133                         __FILE__, __LINE__);
5134             }
5135         }
5136         offset += sizeof(stride_length);
5137     }
5138
5139
5140     memcpy(block->block_contents+offset, &num_first_particle,
5141            sizeof(num_first_particle));
5142     if(tng_data->output_endianness_swap_func_64)
5143     {
5144         if(tng_data->output_endianness_swap_func_64(tng_data,
5145            (int64_t *)block->header_contents+offset)
5146             != TNG_SUCCESS)
5147         {
5148             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5149                     __FILE__, __LINE__);
5150         }
5151     }
5152     offset += sizeof(num_first_particle);
5153
5154     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
5155     if(tng_data->output_endianness_swap_func_64)
5156     {
5157         if(tng_data->output_endianness_swap_func_64(tng_data,
5158            (int64_t *)block->header_contents+offset)
5159             != TNG_SUCCESS)
5160         {
5161             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5162                     __FILE__, __LINE__);
5163         }
5164     }
5165     offset += sizeof(n_particles);
5166
5167     if(data->datatype == TNG_CHAR_DATA)
5168     {
5169         if(data->strings)
5170         {
5171             for(i = 0; i < frame_step; i++)
5172             {
5173                 first_dim_values = data->strings[i];
5174                 for(j = num_first_particle; j < num_first_particle + n_particles;
5175                     j++)
5176                 {
5177                     second_dim_values = first_dim_values[j];
5178                     for(k = 0; k < data->n_values_per_frame; k++)
5179                     {
5180                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
5181                         strncpy(block->block_contents+offset,
5182                                 second_dim_values[k], len);
5183                         offset += len;
5184                     }
5185                 }
5186             }
5187         }
5188     }
5189     else if(data->values)
5190     {
5191         memcpy(block->block_contents + offset, data->values,
5192                block->block_contents_size - offset);
5193
5194         switch(data->datatype)
5195         {
5196         case TNG_FLOAT_DATA:
5197             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
5198                data->codec_id == TNG_TNG_COMPRESSION)
5199             {
5200                 if(tng_data->input_endianness_swap_func_32)
5201                 {
5202                     for(i = offset; i < block->block_contents_size; i+=size)
5203                     {
5204                         if(tng_data->input_endianness_swap_func_32(tng_data,
5205                            (int32_t *)(block->block_contents + i))
5206                            != TNG_SUCCESS)
5207                         {
5208                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5209                                     __FILE__, __LINE__);
5210                         }
5211                     }
5212                 }
5213             }
5214             else
5215             {
5216                 multiplier = data->compression_multiplier;
5217                 if(fabs(multiplier - 1.0) > 0.00001 ||
5218                    tng_data->input_endianness_swap_func_32)
5219                 {
5220                     for(i = offset; i < block->block_contents_size; i+=size)
5221                     {
5222                         *(float *)(block->block_contents + i) *= (float)multiplier;
5223                         if(tng_data->input_endianness_swap_func_32 &&
5224                         tng_data->input_endianness_swap_func_32(tng_data,
5225                         (int32_t *)(block->block_contents + i))
5226                         != TNG_SUCCESS)
5227                         {
5228                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5229                                     __FILE__, __LINE__);
5230                         }
5231                     }
5232                 }
5233             }
5234             break;
5235         case TNG_INT_DATA:
5236             if(tng_data->input_endianness_swap_func_64)
5237             {
5238                 for(i = offset; i < block->block_contents_size; i+=size)
5239                 {
5240                     if(tng_data->input_endianness_swap_func_64(tng_data,
5241                        (int64_t *)(block->block_contents + i))
5242                        != TNG_SUCCESS)
5243                     {
5244                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5245                                 __FILE__, __LINE__);
5246                     }
5247                 }
5248             }
5249             break;
5250         case TNG_DOUBLE_DATA:
5251             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
5252                data->codec_id == TNG_TNG_COMPRESSION)
5253             {
5254                 if(tng_data->input_endianness_swap_func_64)
5255                 {
5256                     for(i = offset; i < block->block_contents_size; i+=size)
5257                     {
5258                         if(tng_data->input_endianness_swap_func_64(tng_data,
5259                            (int64_t *)(block->block_contents + i))
5260                            != TNG_SUCCESS)
5261                         {
5262                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5263                                     __FILE__, __LINE__);
5264                         }
5265                     }
5266                 }
5267             }
5268             else
5269             {
5270                 multiplier = data->compression_multiplier;
5271                 if(fabs(multiplier - 1.0) > 0.00001 ||
5272                    tng_data->input_endianness_swap_func_64)
5273                 {
5274                     for(i = offset; i < block->block_contents_size; i+=size)
5275                     {
5276                         *(double *)(block->block_contents + i) *= multiplier;
5277                         if(tng_data->input_endianness_swap_func_64 &&
5278                         tng_data->input_endianness_swap_func_64(tng_data,
5279                         (int64_t *)(block->block_contents + i))
5280                         != TNG_SUCCESS)
5281                         {
5282                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5283                                     __FILE__, __LINE__);
5284                         }
5285                     }
5286                 }
5287             }
5288             break;
5289         case TNG_CHAR_DATA:
5290             break;
5291         }
5292     }
5293     else
5294     {
5295         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
5296     }
5297
5298     frame_set->n_written_frames += frame_set->n_unwritten_frames;
5299     frame_set->n_unwritten_frames = 0;
5300
5301     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
5302     {
5303         switch(data->codec_id)
5304         {
5305         case TNG_XTC_COMPRESSION:
5306             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5307             data->codec_id = TNG_UNCOMPRESSED;
5308             break;
5309         case TNG_TNG_COMPRESSION:
5310             stat = tng_compress(tng_data, block, frame_step,
5311                                 n_particles, data->datatype,
5312                                 block->block_contents + data_start_pos);
5313             if(stat != TNG_SUCCESS)
5314             {
5315                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
5316                     __FILE__, __LINE__);
5317                 if(stat == TNG_CRITICAL)
5318                 {
5319                     return(TNG_CRITICAL);
5320                 }
5321                 /* Set the data again, but with no compression (to write only
5322                  * the relevant data) */
5323                 data->codec_id = TNG_UNCOMPRESSED;
5324                 stat = tng_particle_data_block_write(tng_data, block,
5325                                                      block_index, mapping,
5326                                                      hash_mode);
5327                 return(stat);
5328             }
5329             break;
5330 #ifdef USE_ZLIB
5331         case TNG_GZIP_COMPRESSION:
5332     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
5333             stat = tng_gzip_compress(tng_data, block,
5334                                      block->block_contents + data_start_pos,
5335                                      block->block_contents_size - data_start_pos);
5336             if(stat != TNG_SUCCESS)
5337             {
5338                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
5339                     __LINE__);
5340                 if(stat == TNG_CRITICAL)
5341                 {
5342                     return(TNG_CRITICAL);
5343                 }
5344                 /* Set the data again, but with no compression (to write only
5345                  * the relevant data) */
5346                 data->codec_id = TNG_UNCOMPRESSED;
5347                 stat = tng_particle_data_block_write(tng_data, block,
5348                                                      block_index, mapping,
5349                                                      hash_mode);
5350                 return(stat);
5351             }
5352     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
5353             break;
5354 #endif
5355         }
5356     }
5357
5358     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
5359     {
5360         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
5361                tng_data->output_file_path, __FILE__, __LINE__);
5362         return(TNG_CRITICAL);
5363     }
5364
5365     if(fwrite(block->block_contents, block->block_contents_size, 1,
5366         tng_data->output_file) != 1)
5367     {
5368         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
5369                 __LINE__);
5370         return(TNG_CRITICAL);
5371     }
5372
5373     return(TNG_SUCCESS);
5374 }
5375
5376 /* TEST: */
5377 /** Create a non-particle data block
5378  * @param tng_data is a trajectory data container.
5379  * @param block_type_flag specifies if this is a trajectory block or a
5380  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
5381  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5382  * error has occured.
5383  */
5384 static tng_function_status tng_data_block_create
5385                 (tng_trajectory_t tng_data,
5386                  const char block_type_flag)
5387 {
5388     tng_trajectory_frame_set_t frame_set =
5389     &tng_data->current_trajectory_frame_set;
5390
5391     tng_non_particle_data_t data;
5392
5393     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5394     {
5395         frame_set->n_data_blocks++;
5396         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
5397                        frame_set->n_data_blocks);
5398         if(!data)
5399         {
5400             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5401                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
5402                 __FILE__, __LINE__);
5403             free(frame_set->tr_data);
5404             frame_set->tr_data = 0;
5405             return(TNG_CRITICAL);
5406         }
5407         frame_set->tr_data = data;
5408     }
5409     else
5410     {
5411         tng_data->n_data_blocks++;
5412         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
5413                         tng_data->n_data_blocks);
5414         if(!data)
5415         {
5416             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5417                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
5418                 __FILE__, __LINE__);
5419             free(tng_data->non_tr_data);
5420             tng_data->non_tr_data = 0;
5421             return(TNG_CRITICAL);
5422         }
5423         tng_data->non_tr_data = data;
5424     }
5425
5426     return(TNG_SUCCESS);
5427 }
5428
5429 /* TEST: */
5430 /** Allocate memory for storing non-particle data.
5431  * The allocated block will be refered to by data->values.
5432  * @param tng_data is a trajectory data container.
5433  * @param data is the data struct, which will contain the allocated memory in
5434  * data->values.
5435  * @param n_frames is the number of frames of data to store.
5436  * @param n_values_per_frame is the number of data values per frame.
5437  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5438  * error has occured.
5439  */
5440 static tng_function_status tng_allocate_data_mem
5441                 (tng_trajectory_t tng_data,
5442                  tng_non_particle_data_t data,
5443                  int64_t n_frames,
5444                  int64_t stride_length,
5445                  const int64_t n_values_per_frame)
5446 {
5447     void **values;
5448     int64_t i, j, size, frame_alloc;
5449     (void)tng_data;
5450
5451     if(data->strings && data->datatype == TNG_CHAR_DATA)
5452     {
5453         for(i = data->n_frames; i--;)
5454         {
5455             for(j = data->n_values_per_frame; j--;)
5456             {
5457                 if(data->strings[i][j])
5458                 {
5459                     free(data->strings[i][j]);
5460                     data->strings[i][j] = 0;
5461                 }
5462             }
5463             free(data->strings[i]);
5464             data->strings[i] = 0;
5465         }
5466         free(data->strings);
5467     }
5468     data->n_frames = n_frames;
5469     data->stride_length = tng_max_i64(1, stride_length);
5470     n_frames = tng_max_i64(1, n_frames);
5471     data->n_values_per_frame = n_values_per_frame;
5472     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5473
5474     if(data->datatype == TNG_CHAR_DATA)
5475     {
5476         data->strings = malloc(sizeof(char **) * frame_alloc);
5477         for(i = frame_alloc; i-- ;)
5478         {
5479             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
5480             if(!data->strings[i])
5481             {
5482                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5483                        n_values_per_frame,
5484                        __FILE__, __LINE__);
5485                 return(TNG_CRITICAL);
5486             }
5487             for(j = n_values_per_frame; j--;)
5488             {
5489                 data->strings[i][j] = 0;
5490             }
5491         }
5492     }
5493     else
5494     {
5495         switch(data->datatype)
5496         {
5497         case TNG_INT_DATA:
5498             size = sizeof(int64_t);
5499             break;
5500         case TNG_FLOAT_DATA:
5501             size = sizeof(float);
5502             break;
5503         case TNG_DOUBLE_DATA:
5504         default:
5505             size = sizeof(double);
5506         }
5507
5508         values = realloc(data->values,
5509                          size * frame_alloc *
5510                          n_values_per_frame);
5511         if(!values)
5512         {
5513             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5514                    size * frame_alloc *
5515                    n_values_per_frame,
5516                    __FILE__, __LINE__);
5517             free(data->values);
5518             data->values = 0;
5519             return(TNG_CRITICAL);
5520         }
5521         data->values = values;
5522     }
5523
5524     return(TNG_SUCCESS);
5525 }
5526
5527 /** Read the values of a non-particle data block
5528  * @param tng_data is a trajectory data container.
5529  * @param block is the block to store the data (should already contain
5530  * the block headers and the block contents).
5531  * @param offset is the reading offset to point at the place where the actual
5532  * values are stored, starting from the beginning of the block_contents. The
5533  * offset is changed during the reading.
5534  * @param datatype is the type of data of the data block (char, int, float or
5535  * double).
5536  * @param first_frame_with_data is the frame number of the first frame with data
5537  * in this data block.
5538  * @param stride_length is the number of frames between each data entry.
5539  * @param n_frames is the number of frames in this data block.
5540  * @param n_values is the number of values per frame stored in this data block.
5541  * @param codec_id is the ID of the codec to compress the data.
5542  * @param multiplier is the multiplication factor applied to each data value
5543  * before compression. This factor is applied since some compression algorithms
5544  * work only on integers.
5545  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5546  * error has occured.
5547  */
5548 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
5549                                          tng_gen_block_t block,
5550                                          int *offset,
5551                                          const char datatype,
5552                                          const int64_t first_frame_with_data,
5553                                          const int64_t stride_length,
5554                                          int64_t n_frames,
5555                                          const int64_t n_values,
5556                                          const int64_t codec_id,
5557                                          const double multiplier)
5558 {
5559     int64_t i, j, n_frames_div;
5560     int size, len;
5561 #ifdef USE_ZLIB
5562     unsigned long data_size;
5563 #endif
5564     tng_non_particle_data_t data;
5565     tng_trajectory_frame_set_t frame_set =
5566     &tng_data->current_trajectory_frame_set;
5567     char block_type_flag;
5568
5569     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5570
5571 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
5572
5573     switch(datatype)
5574     {
5575     case TNG_CHAR_DATA:
5576         size = 1;
5577         break;
5578     case TNG_INT_DATA:
5579         size = sizeof(int64_t);
5580         break;
5581     case TNG_FLOAT_DATA:
5582         size = sizeof(float);
5583         break;
5584     case TNG_DOUBLE_DATA:
5585     default:
5586         size = sizeof(double);
5587     }
5588
5589     /* If the block does not exist, create it */
5590     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5591     {
5592         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5593         {
5594             block_type_flag = TNG_TRAJECTORY_BLOCK;
5595         }
5596         else
5597         {
5598             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5599         }
5600
5601         if(tng_data_block_create(tng_data, block_type_flag) !=
5602             TNG_SUCCESS)
5603         {
5604             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5605                    __FILE__, __LINE__);
5606             return(TNG_CRITICAL);
5607         }
5608         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5609         {
5610             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
5611         }
5612         else
5613         {
5614             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
5615         }
5616         data->block_id = block->id;
5617
5618         data->block_name = malloc(strlen(block->name) + 1);
5619         if(!data->block_name)
5620         {
5621             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5622                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5623             return(TNG_CRITICAL);
5624         }
5625         strcpy(data->block_name, block->name);
5626
5627         data->datatype = datatype;
5628
5629         data->values = 0;
5630         /* FIXME: Memory leak from strings. */
5631         data->strings = 0;
5632         data->n_frames = 0;
5633         data->codec_id = codec_id;
5634         data->compression_multiplier = multiplier;
5635         data->last_retrieved_frame = -1;
5636     }
5637
5638     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5639
5640     if(codec_id != TNG_UNCOMPRESSED)
5641     {
5642         switch(codec_id)
5643         {
5644 #ifdef USE_ZLIB
5645         case TNG_GZIP_COMPRESSION:
5646             data_size = n_frames_div * size * n_values;
5647     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
5648             if(tng_gzip_uncompress(tng_data, block,
5649                                    block->block_contents + *offset,
5650                                    data_size) != TNG_SUCCESS)
5651             {
5652                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5653                     __LINE__);
5654                 return(TNG_CRITICAL);
5655             }
5656     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
5657             break;
5658 #endif
5659         }
5660     }
5661
5662     /* Allocate memory */
5663     if(!data->values || data->n_frames != n_frames ||
5664        data->n_values_per_frame != n_values)
5665     {
5666         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
5667                                  n_values) !=
5668            TNG_SUCCESS)
5669         {
5670             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
5671                    __FILE__, __LINE__);
5672             return(TNG_CRITICAL);
5673         }
5674     }
5675
5676     data->first_frame_with_data = first_frame_with_data;
5677
5678     if(datatype == TNG_CHAR_DATA)
5679     {
5680         for(i = 0; i < n_frames_div; i++)
5681         {
5682             for(j = 0; j < n_values; j++)
5683             {
5684                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5685                               TNG_MAX_STR_LEN);
5686                 if(data->strings[i][j])
5687                 {
5688                     free(data->strings[i][j]);
5689                 }
5690                 data->strings[i][j] = malloc(len);
5691                 if(!data->strings[i][j])
5692                 {
5693                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5694                            len, __FILE__, __LINE__);
5695                     return(TNG_CRITICAL);
5696                 }
5697                 strncpy(data->strings[i][j], block->block_contents+*offset,
5698                         len);
5699                 *offset += len;
5700             }
5701         }
5702     }
5703     else
5704     {
5705         memcpy(data->values, block->block_contents + *offset,
5706                block->block_contents_size - *offset);
5707         switch(datatype)
5708         {
5709         case TNG_FLOAT_DATA:
5710             if(tng_data->input_endianness_swap_func_32)
5711             {
5712                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5713                 {
5714                     if(tng_data->input_endianness_swap_func_32(tng_data,
5715                         (int32_t *)((char *)data->values + i))
5716                         != TNG_SUCCESS)
5717                     {
5718                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5719                                 __FILE__, __LINE__);
5720                     }
5721                 }
5722             }
5723             break;
5724         case TNG_INT_DATA:
5725         case TNG_DOUBLE_DATA:
5726             if(tng_data->input_endianness_swap_func_64)
5727             {
5728                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5729                 {
5730                     if(tng_data->input_endianness_swap_func_64(tng_data,
5731                         (int64_t *)((char *)data->values + i))
5732                         != TNG_SUCCESS)
5733                     {
5734                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5735                                 __FILE__, __LINE__);
5736                     }
5737                 }
5738             }
5739             break;
5740         case TNG_CHAR_DATA:
5741             break;
5742         }
5743     }
5744     return(TNG_SUCCESS);
5745 }
5746
5747 /** Write a non-particle data block
5748  * @param tng_data is a trajectory data container.
5749  * @param block is the block to store the data (should already contain
5750  * the block headers and the block contents).
5751  * @param block_index is the index number of the data block in the frame set.
5752  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5753  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5754  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5755  * error has occured.
5756  */
5757 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
5758                                                 tng_gen_block_t block,
5759                                                 const int64_t block_index,
5760                                                 const char hash_mode)
5761 {
5762     int64_t n_frames, stride_length, frame_step;
5763     int64_t i, j;
5764     int offset = 0, size;
5765     unsigned int len;
5766 #ifdef USE_ZLIB
5767     int data_start_pos;
5768     tng_function_status stat;
5769 #endif
5770     char temp, dependency, *temp_name;
5771     double multiplier;
5772     tng_trajectory_frame_set_t frame_set =
5773     &tng_data->current_trajectory_frame_set;
5774
5775     tng_non_particle_data_t data;
5776     char block_type_flag;
5777
5778     /* If we have already started writing frame sets it is too late to write
5779      * non-trajectory data blocks */
5780     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5781     {
5782         block_type_flag = TNG_TRAJECTORY_BLOCK;
5783     }
5784     else
5785     {
5786         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5787     }
5788
5789     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5790     {
5791         return(TNG_CRITICAL);
5792     }
5793
5794     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5795     {
5796         data = &frame_set->tr_data[block_index];
5797
5798         /* If this data block has not had any data added in this frame set
5799          * do not write it. */
5800         if(data->first_frame_with_data < frame_set->first_frame)
5801         {
5802             return(TNG_SUCCESS);
5803         }
5804
5805         stride_length = tng_max_i64(1, data->stride_length);
5806     }
5807     else
5808     {
5809         data = &tng_data->non_tr_data[block_index];
5810         stride_length = 1;
5811     }
5812
5813     switch(data->datatype)
5814     {
5815     case TNG_CHAR_DATA:
5816         size = 1;
5817         break;
5818     case TNG_INT_DATA:
5819         size = sizeof(int64_t);
5820         break;
5821     case TNG_FLOAT_DATA:
5822         size = sizeof(float);
5823         break;
5824     case TNG_DOUBLE_DATA:
5825     default:
5826         size = sizeof(double);
5827     }
5828
5829     len = (unsigned int)strlen(data->block_name) + 1;
5830
5831     if(!block->name || strlen(block->name) < len)
5832     {
5833         temp_name = realloc(block->name, len);
5834         if(!temp_name)
5835         {
5836             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
5837                    __FILE__, __LINE__);
5838             free(block->name);
5839             block->name = 0;
5840             return(TNG_CRITICAL);
5841         }
5842         block->name = temp_name;
5843     }
5844     strncpy(block->name, data->block_name, len);
5845     block->id = data->block_id;
5846
5847     /* If writing frame independent data data->n_frames is 0, but n_frames
5848        is used for the loop writing the data (and reserving memory) and needs
5849        to be at least 1 */
5850     n_frames = tng_max_i64(1, data->n_frames);
5851
5852     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5853     {
5854         /* If the frame set is finished before writing the full number of frames
5855            make sure the data block is not longer than the frame set. */
5856         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5857
5858         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5859     }
5860
5861     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
5862                  n_frames / stride_length;
5863
5864     /* TNG compression will use compression precision to get integers from
5865      * floating point data. The compression multiplier stores that information
5866      * to be able to return the precision of the compressed data. */
5867     if(data->codec_id == TNG_TNG_COMPRESSION)
5868     {
5869         data->compression_multiplier = tng_data->compression_precision;
5870     }
5871     /* Uncompressed data blocks do not use compression multipliers at all.
5872      * GZip compression does not need it either. */
5873     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
5874     {
5875         data->compression_multiplier = 1.0;
5876     }
5877
5878     block->block_contents_size = sizeof(char) * 2 +
5879                                  sizeof(data->n_values_per_frame) +
5880                                  sizeof(data->codec_id);
5881
5882     if(stride_length > 1)
5883     {
5884         block->block_contents_size += sizeof(data->first_frame_with_data) +
5885                                       sizeof(data->stride_length);
5886     }
5887
5888     if(data->codec_id != TNG_UNCOMPRESSED)
5889     {
5890         block->block_contents_size += sizeof(data->compression_multiplier);
5891     }
5892
5893     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
5894     {
5895         dependency = TNG_FRAME_DEPENDENT;
5896     }
5897     else
5898     {
5899         dependency = 0;
5900     }
5901     if(dependency & TNG_FRAME_DEPENDENT)
5902     {
5903         block->block_contents_size += sizeof(char);
5904     }
5905
5906 #ifdef USE_ZLIB
5907     data_start_pos = block->block_contents_size;
5908 #endif
5909
5910     if(data->datatype == TNG_CHAR_DATA)
5911     {
5912         for(i = n_frames; i--;)
5913         {
5914             for(j = data->n_values_per_frame; j--;)
5915             {
5916                 block->block_contents_size += strlen(data->strings[i][j]) + 1;
5917             }
5918         }
5919     }
5920     else
5921     {
5922         block->block_contents_size += size * frame_step *
5923         data->n_values_per_frame;
5924     }
5925
5926     if(block->block_contents)
5927     {
5928         free(block->block_contents);
5929     }
5930     block->block_contents = malloc(block->block_contents_size);
5931     if(!block->block_contents)
5932     {
5933         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5934                block->block_contents_size, __FILE__, __LINE__);
5935         return(TNG_CRITICAL);
5936     }
5937
5938
5939     memcpy(block->block_contents, &data->datatype, sizeof(char));
5940     offset += sizeof(char);
5941
5942     memcpy(block->block_contents+offset, &dependency, sizeof(char));
5943     offset += sizeof(char);
5944
5945     if(dependency & TNG_FRAME_DEPENDENT)
5946     {
5947         if(stride_length > 1)
5948         {
5949             temp = 1;
5950         }
5951         else
5952         {
5953             temp = 0;
5954         }
5955         memcpy(block->block_contents+offset, &temp, sizeof(char));
5956         offset += sizeof(char);
5957     }
5958
5959     memcpy(block->block_contents+offset, &data->n_values_per_frame,
5960            sizeof(data->n_values_per_frame));
5961     if(tng_data->output_endianness_swap_func_64)
5962     {
5963         if(tng_data->output_endianness_swap_func_64(tng_data,
5964            (int64_t *)block->header_contents+offset)
5965             != TNG_SUCCESS)
5966         {
5967             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5968                     __FILE__, __LINE__);
5969         }
5970     }
5971     offset += sizeof(data->n_values_per_frame);
5972
5973     memcpy(block->block_contents+offset, &data->codec_id,
5974            sizeof(data->codec_id));
5975     if(tng_data->output_endianness_swap_func_64)
5976     {
5977         if(tng_data->output_endianness_swap_func_64(tng_data,
5978            (int64_t *)block->header_contents+offset)
5979             != TNG_SUCCESS)
5980         {
5981             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5982                     __FILE__, __LINE__);
5983         }
5984     }
5985     offset += sizeof(data->codec_id);
5986
5987     if(data->codec_id != TNG_UNCOMPRESSED)
5988     {
5989         memcpy(block->block_contents+offset, &data->compression_multiplier,
5990                sizeof(data->compression_multiplier));
5991         if(tng_data->output_endianness_swap_func_64)
5992         {
5993             if(tng_data->output_endianness_swap_func_64(tng_data,
5994             (int64_t *)block->header_contents+offset)
5995                 != TNG_SUCCESS)
5996             {
5997                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5998                         __FILE__, __LINE__);
5999             }
6000         }
6001         offset += sizeof(data->compression_multiplier);
6002     }
6003
6004     if(data->n_frames > 0 && stride_length > 1)
6005     {
6006         /* FIXME: first_frame_with_data is not reliably set */
6007         if(data->first_frame_with_data == 0)
6008         {
6009             data->first_frame_with_data = frame_set->first_frame;
6010         }
6011         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6012                sizeof(data->first_frame_with_data));
6013         if(tng_data->output_endianness_swap_func_64)
6014         {
6015             if(tng_data->output_endianness_swap_func_64(tng_data,
6016             (int64_t *)block->header_contents+offset)
6017                 != TNG_SUCCESS)
6018             {
6019                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6020                         __FILE__, __LINE__);
6021             }
6022         }
6023         offset += sizeof(data->first_frame_with_data);
6024
6025         memcpy(block->block_contents+offset, &stride_length,
6026                sizeof(data->stride_length));
6027         if(tng_data->output_endianness_swap_func_64)
6028         {
6029             if(tng_data->output_endianness_swap_func_64(tng_data,
6030             (int64_t *)block->header_contents+offset)
6031                 != TNG_SUCCESS)
6032             {
6033                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6034                         __FILE__, __LINE__);
6035             }
6036         }
6037         offset += sizeof(data->stride_length);
6038     }
6039
6040     if(data->datatype == TNG_CHAR_DATA)
6041     {
6042         if(data->strings)
6043         {
6044             for(i = 0; i < frame_step; i++)
6045             {
6046                 for(j = 0; j < data->n_values_per_frame; j++)
6047                 {
6048                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
6049                     strncpy(block->block_contents+offset, data->strings[i][j],
6050                             len);
6051                     offset += len;
6052                 }
6053             }
6054         }
6055     }
6056     else if(data->values)
6057     {
6058         memcpy(block->block_contents + offset, data->values,
6059                block->block_contents_size - offset);
6060         switch(data->datatype)
6061         {
6062         case TNG_FLOAT_DATA:
6063             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6064                data->codec_id == TNG_TNG_COMPRESSION)
6065             {
6066                 if(tng_data->input_endianness_swap_func_32)
6067                 {
6068                     for(i = offset; i < block->block_contents_size; i+=size)
6069                     {
6070                         if(tng_data->input_endianness_swap_func_32(tng_data,
6071                            (int32_t *)(block->block_contents + i))
6072                            != TNG_SUCCESS)
6073                         {
6074                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6075                                     __FILE__, __LINE__);
6076                         }
6077                     }
6078                 }
6079             }
6080             else
6081             {
6082                 multiplier = data->compression_multiplier;
6083                 if(fabs(multiplier - 1.0) > 0.00001 ||
6084                    tng_data->input_endianness_swap_func_32)
6085                 {
6086                     for(i = offset; block->block_contents_size; i+=size)
6087                     {
6088                         *(float *)(block->block_contents + i) *= (float)multiplier;
6089                         if(tng_data->input_endianness_swap_func_32 &&
6090                         tng_data->input_endianness_swap_func_32(tng_data,
6091                         (int32_t *)(block->block_contents + i))
6092                         != TNG_SUCCESS)
6093                         {
6094                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6095                                     __FILE__, __LINE__);
6096                         }
6097                     }
6098                 }
6099             }
6100             break;
6101         case TNG_INT_DATA:
6102             if(tng_data->input_endianness_swap_func_64)
6103             {
6104                 for(i = offset; i < block->block_contents_size; i+=size)
6105                 {
6106                     if(tng_data->input_endianness_swap_func_64(tng_data,
6107                        (int64_t *)(block->block_contents + i))
6108                        != TNG_SUCCESS)
6109                     {
6110                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6111                                 __FILE__, __LINE__);
6112                     }
6113                 }
6114             }
6115             break;
6116         case TNG_DOUBLE_DATA:
6117             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6118                data->codec_id == TNG_TNG_COMPRESSION)
6119             {
6120                 if(tng_data->input_endianness_swap_func_64)
6121                 {
6122                     for(i = offset; i < block->block_contents_size; i+=size)
6123                     {
6124                         if(tng_data->input_endianness_swap_func_64(tng_data,
6125                            (int64_t *)(block->block_contents + i))
6126                            != TNG_SUCCESS)
6127                         {
6128                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6129                                     __FILE__, __LINE__);
6130                         }
6131                     }
6132                 }
6133             }
6134             else
6135             {
6136                 multiplier = data->compression_multiplier;
6137                 if(fabs(multiplier - 1.0) > 0.00001 ||
6138                    tng_data->input_endianness_swap_func_64)
6139                 {
6140                     for(i = offset; i < block->block_contents_size; i+=size)
6141                     {
6142                         *(double *)(block->block_contents + i) *= multiplier;
6143                         if(tng_data->input_endianness_swap_func_64 &&
6144                         tng_data->input_endianness_swap_func_64(tng_data,
6145                         (int64_t *)(block->block_contents + i))
6146                         != TNG_SUCCESS)
6147                         {
6148                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6149                                     __FILE__, __LINE__);
6150                         }
6151                     }
6152                 }
6153             }
6154             break;
6155         case TNG_CHAR_DATA:
6156             break;
6157         }
6158     }
6159     else
6160     {
6161         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6162     }
6163
6164     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6165     frame_set->n_unwritten_frames = 0;
6166
6167     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6168     {
6169         switch(data->codec_id)
6170         {
6171 #ifdef USE_ZLIB
6172         case TNG_GZIP_COMPRESSION:
6173     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6174             stat = tng_gzip_compress(tng_data, block,
6175                                      block->block_contents + data_start_pos,
6176                                      block->block_contents_size - data_start_pos);
6177             if(stat != TNG_SUCCESS)
6178             {
6179                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6180                     __LINE__);
6181                 if(stat == TNG_CRITICAL)
6182                 {
6183                     return(TNG_CRITICAL);
6184                 }
6185                 data->codec_id = TNG_UNCOMPRESSED;
6186             }
6187     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6188             break;
6189 #endif
6190         }
6191     }
6192
6193     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6194     {
6195         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6196                tng_data->output_file_path, __FILE__, __LINE__);
6197         return(TNG_CRITICAL);
6198     }
6199
6200     if(fwrite(block->block_contents, block->block_contents_size, 1,
6201               tng_data->output_file) != 1)
6202     {
6203         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
6204                __FILE__, __LINE__);
6205         return(TNG_CRITICAL);
6206     }
6207
6208     return(TNG_SUCCESS);
6209 }
6210
6211 /** Read the meta information of a data block (particle or non-particle data).
6212  * @param tng_data is a trajectory data container.
6213  * @param block is the block to store the data (should already contain
6214  * the block headers).
6215  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6216  * error has occured.
6217  */
6218 static tng_function_status tng_data_block_meta_information_read
6219                 (tng_trajectory_t tng_data,
6220                  tng_gen_block_t block,
6221                  int *offset,
6222                  char *datatype,
6223                  char *dependency,
6224                  char *sparse_data,
6225                  int64_t *n_values,
6226                  int64_t *codec_id,
6227                  int64_t *first_frame_with_data,
6228                  int64_t *stride_length,
6229                  int64_t *n_frames,
6230                  int64_t *num_first_particle,
6231                  int64_t *block_n_particles,
6232                  double *multiplier)
6233 {
6234     int meta_size;
6235     char *contents;
6236
6237     if(block->block_contents)
6238     {
6239         contents = block->block_contents;
6240     }
6241     else
6242     {
6243         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
6244         contents = malloc(meta_size);
6245
6246         if(!contents)
6247         {
6248             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6249                meta_size, __FILE__, __LINE__);
6250         }
6251
6252         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
6253         {
6254             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
6255             free(contents);
6256             return(TNG_CRITICAL);
6257         }
6258     }
6259
6260     memcpy(datatype, contents+*offset,
6261            sizeof(*datatype));
6262     *offset += sizeof(*datatype);
6263
6264     memcpy(dependency, contents+*offset,
6265            sizeof(*dependency));
6266     *offset += sizeof(*dependency);
6267
6268     if(*dependency & TNG_FRAME_DEPENDENT)
6269     {
6270         memcpy(sparse_data, contents+*offset,
6271                sizeof(*sparse_data));
6272         *offset += sizeof(*sparse_data);
6273     }
6274
6275     memcpy(n_values, contents+*offset,
6276         sizeof(*n_values));
6277     if(tng_data->input_endianness_swap_func_64)
6278     {
6279         if(tng_data->input_endianness_swap_func_64(tng_data,
6280                                                    n_values)
6281             != TNG_SUCCESS)
6282         {
6283             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6284                     __FILE__, __LINE__);
6285         }
6286     }
6287     *offset += sizeof(*n_values);
6288
6289     memcpy(codec_id, contents+*offset,
6290         sizeof(*codec_id));
6291     if(tng_data->input_endianness_swap_func_64)
6292     {
6293         if(tng_data->input_endianness_swap_func_64(tng_data,
6294                                                    codec_id)
6295             != TNG_SUCCESS)
6296         {
6297             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6298                     __FILE__, __LINE__);
6299         }
6300     }
6301     *offset += sizeof(*codec_id);
6302
6303     if(*codec_id != TNG_UNCOMPRESSED)
6304     {
6305         memcpy(multiplier, contents+*offset,
6306             sizeof(*multiplier));
6307         if(tng_data->input_endianness_swap_func_64)
6308         {
6309             if(tng_data->input_endianness_swap_func_64(tng_data,
6310                                                        (int64_t *) multiplier)
6311                 != TNG_SUCCESS)
6312             {
6313                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6314                         __FILE__, __LINE__);
6315             }
6316         }
6317         *offset += sizeof(*multiplier);
6318     }
6319     else
6320     {
6321         *multiplier = 1;
6322     }
6323
6324     if(*dependency & TNG_FRAME_DEPENDENT)
6325     {
6326         if(*sparse_data)
6327         {
6328             memcpy(first_frame_with_data, contents+*offset,
6329                 sizeof(*first_frame_with_data));
6330             if(tng_data->input_endianness_swap_func_64)
6331             {
6332                 if(tng_data->input_endianness_swap_func_64(tng_data,
6333                                                            first_frame_with_data)
6334                     != TNG_SUCCESS)
6335                 {
6336                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6337                             __FILE__, __LINE__);
6338                 }
6339             }
6340             *offset += sizeof(*first_frame_with_data);
6341
6342             memcpy(stride_length, contents+*offset,
6343                 sizeof(*stride_length));
6344             if(tng_data->input_endianness_swap_func_64)
6345             {
6346                 if(tng_data->input_endianness_swap_func_64(tng_data,
6347                                                            stride_length)
6348                     != TNG_SUCCESS)
6349                 {
6350                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6351                             __FILE__, __LINE__);
6352                 }
6353             }
6354             *offset += sizeof(*stride_length);
6355             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
6356                         (*first_frame_with_data -
6357                         tng_data->current_trajectory_frame_set.first_frame);
6358         }
6359         else
6360         {
6361             *first_frame_with_data = 0;
6362             *stride_length = 1;
6363             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
6364         }
6365     }
6366     else
6367     {
6368         *first_frame_with_data = 0;
6369         *stride_length = 1;
6370         *n_frames = 1;
6371     }
6372
6373     if (*dependency & TNG_PARTICLE_DEPENDENT)
6374     {
6375         memcpy(num_first_particle, contents+*offset,
6376                sizeof(*num_first_particle));
6377         if(tng_data->input_endianness_swap_func_64)
6378         {
6379             if(tng_data->input_endianness_swap_func_64(tng_data,
6380                                                        num_first_particle)
6381                 != TNG_SUCCESS)
6382             {
6383                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6384                         __FILE__, __LINE__);
6385             }
6386         }
6387         *offset += sizeof(*num_first_particle);
6388
6389         memcpy(block_n_particles, contents+*offset,
6390             sizeof(*block_n_particles));
6391         if(tng_data->input_endianness_swap_func_64)
6392         {
6393             if(tng_data->input_endianness_swap_func_64(tng_data,
6394                                                        block_n_particles)
6395                 != TNG_SUCCESS)
6396             {
6397                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6398                         __FILE__, __LINE__);
6399             }
6400         }
6401         *offset += sizeof(*block_n_particles);
6402     }
6403
6404     if(!block->block_contents)
6405     {
6406         free(contents);
6407     }
6408     return(TNG_SUCCESS);
6409 }
6410
6411 /** Read the contents of a data block (particle or non-particle data).
6412  * @param tng_data is a trajectory data container.
6413  * @param block is the block to store the data (should already contain
6414  * the block headers).
6415  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6416  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
6417  * compared to the md5 hash of the read contents to ensure valid data.
6418  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6419  * error has occured.
6420  */
6421 static tng_function_status tng_data_block_contents_read
6422                 (tng_trajectory_t tng_data,
6423                  tng_gen_block_t block,
6424                  const char hash_mode)
6425 {
6426     int64_t n_values, codec_id, n_frames, first_frame_with_data;
6427     int64_t stride_length, block_n_particles, num_first_particle;
6428     double multiplier;
6429     char datatype, dependency, sparse_data;
6430     int offset = 0;
6431     tng_bool same_hash;
6432
6433     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
6434     {
6435         return(TNG_CRITICAL);
6436     }
6437
6438     if(block->block_contents)
6439     {
6440         free(block->block_contents);
6441     }
6442
6443     block->block_contents = malloc(block->block_contents_size);
6444     if(!block->block_contents)
6445     {
6446         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6447                block->block_contents_size, __FILE__, __LINE__);
6448         return(TNG_CRITICAL);
6449     }
6450
6451     /* Read the whole block into block_contents to be able to write it to
6452      * disk even if it cannot be interpreted. */
6453     if(fread(block->block_contents, block->block_contents_size, 1,
6454              tng_data->input_file) == 0)
6455     {
6456         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
6457         return(TNG_CRITICAL);
6458     }
6459
6460     /* FIXME: Does not check if the size of the contents matches the expected
6461      * size or if the contents can be read. */
6462
6463     if(hash_mode == TNG_USE_HASH)
6464     {
6465         tng_md5_hash_match_verify(block, &same_hash);
6466         if(same_hash != TNG_TRUE)
6467         {
6468             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
6469                 block->name, __FILE__, __LINE__);
6470     /*         return(TNG_FAILURE); */
6471         }
6472     }
6473
6474     if(tng_data_block_meta_information_read(tng_data, block,
6475                                             &offset, &datatype,
6476                                             &dependency, &sparse_data,
6477                                             &n_values, &codec_id,
6478                                             &first_frame_with_data,
6479                                             &stride_length, &n_frames,
6480                                             &num_first_particle,
6481                                             &block_n_particles,
6482                                             &multiplier) == TNG_CRITICAL)
6483     {
6484         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
6485             block->name, __FILE__, __LINE__);
6486         return(TNG_CRITICAL);
6487     }
6488
6489     if (dependency & TNG_PARTICLE_DEPENDENT)
6490     {
6491         return(tng_particle_data_read(tng_data, block,
6492                                       &offset, datatype,
6493                                       num_first_particle,
6494                                       block_n_particles,
6495                                       first_frame_with_data,
6496                                       stride_length,
6497                                       n_frames, n_values,
6498                                       codec_id, multiplier));
6499     }
6500     else
6501     {
6502         return(tng_data_read(tng_data, block,
6503                              &offset, datatype,
6504                              first_frame_with_data,
6505                              stride_length,
6506                              n_frames, n_values,
6507                              codec_id, multiplier));
6508     }
6509 }
6510
6511 /** Update the md5 hash of a block already written to the file
6512  * @param tng_data is a trajectory data container.
6513  * @param block is the block, of which to update the md5 hash.
6514  * @param header_start_pos is the file position where the block header starts.
6515  * @param contents_start_pos is the file position where the block contents
6516  * start.
6517  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6518  * error has occured.
6519  */
6520 static tng_function_status tng_md5_hash_update(tng_trajectory_t tng_data,
6521                                                tng_gen_block_t block,
6522                                                const int64_t header_start_pos,
6523                                                const int64_t contents_start_pos)
6524 {
6525     if(block->block_contents)
6526     {
6527         free(block->block_contents);
6528     }
6529
6530     block->block_contents = malloc(block->block_contents_size);
6531     fseek(tng_data->output_file, (long)contents_start_pos, SEEK_SET);
6532     if(fread(block->block_contents, block->block_contents_size, 1,
6533             tng_data->output_file) == 0)
6534     {
6535         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
6536         return(TNG_CRITICAL);
6537     }
6538
6539     tng_block_md5_hash_generate(block);
6540
6541     fseek(tng_data->output_file, (long)header_start_pos + 3 * sizeof(int64_t),
6542           SEEK_SET);
6543     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
6544
6545     return(TNG_SUCCESS);
6546 }
6547
6548 /** Update the frame set pointers in the file header (general info block),
6549  * already written to disk
6550  * @param tng_data is a trajectory data container.
6551  * @param hash_mode specifies whether to update the block md5 hash when
6552  * updating the pointers.
6553  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6554  * error has occured.
6555  */
6556 static tng_function_status tng_header_pointers_update
6557                 (tng_trajectory_t tng_data, const char hash_mode)
6558 {
6559     tng_gen_block_t block;
6560     FILE *temp = tng_data->input_file;
6561     int64_t output_file_pos, pos, contents_start_pos;
6562
6563     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6564     {
6565         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6566                __FILE__, __LINE__);
6567         return(TNG_CRITICAL);
6568     }
6569
6570     tng_data->input_file = tng_data->output_file;
6571
6572     tng_block_init(&block);
6573
6574     output_file_pos = ftell(tng_data->output_file);
6575     fseek(tng_data->output_file, 0, SEEK_SET);
6576
6577     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6578     {
6579         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
6580                __FILE__, __LINE__);
6581         tng_data->input_file = temp;
6582         tng_block_destroy(&block);
6583         return(TNG_CRITICAL);
6584     }
6585
6586     contents_start_pos = ftell(tng_data->output_file);
6587
6588     fseek(tng_data->output_file, (long)block->block_contents_size - 5 *
6589           sizeof(int64_t), SEEK_CUR);
6590
6591     tng_data->input_file = temp;
6592
6593     pos = tng_data->first_trajectory_frame_set_output_file_pos;
6594
6595     if(tng_data->input_endianness_swap_func_64)
6596     {
6597         if(tng_data->input_endianness_swap_func_64(tng_data,
6598                                                     &pos)
6599             != TNG_SUCCESS)
6600         {
6601             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6602                     __FILE__, __LINE__);
6603         }
6604     }
6605
6606     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6607     {
6608         tng_block_destroy(&block);
6609         return(TNG_CRITICAL);
6610     }
6611
6612     pos = tng_data->last_trajectory_frame_set_output_file_pos;
6613
6614     if(tng_data->input_endianness_swap_func_64)
6615     {
6616         if(tng_data->input_endianness_swap_func_64(tng_data,
6617                                                     &pos)
6618             != TNG_SUCCESS)
6619         {
6620             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6621                     __FILE__, __LINE__);
6622         }
6623     }
6624
6625     if(fwrite(&pos,
6626         sizeof(int64_t), 1, tng_data->output_file) != 1)
6627     {
6628         tng_block_destroy(&block);
6629         return(TNG_CRITICAL);
6630     }
6631
6632     if(hash_mode == TNG_USE_HASH)
6633     {
6634         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
6635     }
6636
6637     tng_block_destroy(&block);
6638
6639     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
6640
6641     return(TNG_SUCCESS);
6642 }
6643
6644 /** Update the frame set pointers in the current frame set block, already
6645  * written to disk. It also updates the pointers of the blocks pointing to
6646  * the current frame set block.
6647  * @param tng_data is a trajectory data container.
6648  * @param hash_mode specifies whether to update the block md5 hash when
6649  * updating the pointers.
6650  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6651  * error has occured.
6652  */
6653 static tng_function_status tng_frame_set_pointers_update
6654                 (tng_trajectory_t tng_data, const char hash_mode)
6655 {
6656     tng_gen_block_t block;
6657     tng_trajectory_frame_set_t frame_set;
6658     FILE *temp = tng_data->input_file;
6659     int64_t pos, output_file_pos, header_start_pos, contents_start_pos;
6660
6661     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6662     {
6663         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6664                __FILE__, __LINE__);
6665         return(TNG_CRITICAL);
6666     }
6667
6668     tng_block_init(&block);
6669     output_file_pos = ftell(tng_data->output_file);
6670
6671     tng_data->input_file = tng_data->output_file;
6672
6673     frame_set = &tng_data->current_trajectory_frame_set;
6674
6675     /* Update previous frame set */
6676     if(frame_set->prev_frame_set_file_pos != -1 &&
6677        frame_set->prev_frame_set_file_pos != 0)
6678     {
6679         fseek(tng_data->output_file, (long)frame_set->prev_frame_set_file_pos,
6680               SEEK_SET);
6681
6682         header_start_pos = frame_set->prev_frame_set_file_pos;
6683
6684         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6685         {
6686             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
6687                 __FILE__, __LINE__);
6688             tng_data->input_file = temp;
6689             tng_block_destroy(&block);
6690             return(TNG_CRITICAL);
6691         }
6692
6693         contents_start_pos = ftell(tng_data->output_file);
6694
6695         fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
6696             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
6697
6698         pos = tng_data->current_trajectory_frame_set_output_file_pos;
6699
6700         if(tng_data->input_endianness_swap_func_64)
6701         {
6702             if(tng_data->input_endianness_swap_func_64(tng_data,
6703                                                         &pos)
6704                 != TNG_SUCCESS)
6705             {
6706                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6707                         __FILE__, __LINE__);
6708             }
6709         }
6710
6711         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6712         {
6713             tng_data->input_file = temp;
6714             tng_block_destroy(&block);
6715             return(TNG_CRITICAL);
6716         }
6717
6718         if(hash_mode == TNG_USE_HASH)
6719         {
6720             tng_md5_hash_update(tng_data, block, header_start_pos,
6721                                 contents_start_pos);
6722         }
6723         fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
6724     }
6725
6726     /* Update the frame set one medium stride step before */
6727     if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
6728        frame_set->medium_stride_prev_frame_set_file_pos != 0)
6729     {
6730         fseek(tng_data->output_file,
6731               (long)frame_set->medium_stride_prev_frame_set_file_pos,
6732               SEEK_SET);
6733
6734         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6735         {
6736             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6737                 __FILE__, __LINE__);
6738             tng_data->input_file = temp;
6739             tng_block_destroy(&block);
6740             return(TNG_CRITICAL);
6741         }
6742
6743         contents_start_pos = ftell(tng_data->output_file);
6744
6745         fseek(tng_data->output_file, (long)block->block_contents_size - (4 *
6746             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
6747
6748         pos = tng_data->current_trajectory_frame_set_output_file_pos;
6749
6750         if(tng_data->input_endianness_swap_func_64)
6751         {
6752             if(tng_data->input_endianness_swap_func_64(tng_data,
6753                                                         &pos)
6754                 != TNG_SUCCESS)
6755             {
6756                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6757                         __FILE__, __LINE__);
6758             }
6759         }
6760
6761         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6762         {
6763             tng_data->input_file = temp;
6764             tng_block_destroy(&block);
6765             return(TNG_CRITICAL);
6766         }
6767
6768         if(hash_mode == TNG_USE_HASH)
6769         {
6770             tng_md5_hash_update(tng_data, block,
6771                                 frame_set->medium_stride_prev_frame_set_file_pos,
6772                                 contents_start_pos);
6773         }
6774     }
6775
6776     /* Update the frame set one long stride step before */
6777     if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
6778        frame_set->long_stride_prev_frame_set_file_pos != 0)
6779     {
6780         fseek(tng_data->output_file,
6781               (long)frame_set->long_stride_prev_frame_set_file_pos,
6782               SEEK_SET);
6783
6784         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6785         {
6786             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6787                 __FILE__, __LINE__);
6788             tng_data->input_file = temp;
6789             tng_block_destroy(&block);
6790             return(TNG_CRITICAL);
6791         }
6792
6793         contents_start_pos = ftell(tng_data->output_file);
6794
6795         fseek(tng_data->output_file, (long)block->block_contents_size - (2 *
6796             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
6797
6798         pos = tng_data->current_trajectory_frame_set_output_file_pos;
6799
6800         if(tng_data->input_endianness_swap_func_64)
6801         {
6802             if(tng_data->input_endianness_swap_func_64(tng_data,
6803                                                         &pos)
6804                 != TNG_SUCCESS)
6805             {
6806                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6807                         __FILE__, __LINE__);
6808             }
6809         }
6810
6811         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6812         {
6813             tng_data->input_file = temp;
6814             tng_block_destroy(&block);
6815             return(TNG_CRITICAL);
6816         }
6817
6818         if(hash_mode == TNG_USE_HASH)
6819         {
6820             tng_md5_hash_update(tng_data, block,
6821                                 frame_set->long_stride_prev_frame_set_file_pos,
6822                                 contents_start_pos);
6823         }
6824     }
6825
6826     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
6827
6828     tng_data->input_file = temp;
6829
6830     tng_block_destroy(&block);
6831
6832     return(TNG_SUCCESS);
6833 }
6834 /*
6835 // ** Move the blocks in a frame set so that there is no unused space between
6836 //  * them. This can only be done on the last frame set in the file and should
6837 //  * be done e.g. if the last frame set in the file has fewer frames than
6838 //  * default or after compressing data blocks in a frame set.
6839 //  * @param tng_data is a trajectory data container.
6840 //  * @details the current_trajectory_frame_set is the one that will be modified.
6841 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
6842 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
6843 //  * FIXME: This function is not finished!!!
6844 //  *
6845 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
6846 // {
6847 //     tng_gen_block_t block;
6848 //     tng_trajectory_frame_set_t frame_set;
6849 //     FILE *temp = tng_data->input_file;
6850 //     int64_t pos, contents_start_pos, output_file_len;
6851 //
6852 //     frame_set = &tng_data->current_trajectory_frame_set;
6853 //
6854 //     if(frame_set->n_written_frames == frame_set->n_frames)
6855 //     {
6856 //         return(TNG_SUCCESS);
6857 //     }
6858 //
6859 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
6860 //        tng_data->last_trajectory_frame_set_output_file_pos)
6861 //     {
6862 //     }
6863 //
6864 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6865 //     {
6866 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6867 //                __FILE__, __LINE__);
6868 //         return(TNG_CRITICAL);
6869 //     }
6870 //
6871 //     tng_block_init(&block);
6872 // //     output_file_pos = ftell(tng_data->output_file);
6873 //
6874 //     tng_data->input_file = tng_data->output_file;
6875 //
6876 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
6877 //
6878 //     fseek(tng_data->output_file, pos, SEEK_SET);
6879 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6880 //     {
6881 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6882 //             __FILE__, __LINE__);
6883 //         tng_data->input_file = temp;
6884 //         tng_block_destroy(&block);
6885 //         return(TNG_CRITICAL);
6886 //     }
6887 //
6888 //     contents_start_pos = ftell(tng_data->output_file);
6889 //
6890 //     fseek(tng_data->output_file, 0, SEEK_END);
6891 //     output_file_len = ftell(tng_data->output_file);
6892 //     pos = contents_start_pos + block->block_contents_size;
6893 //     fseek(tng_data->output_file, pos,
6894 //           SEEK_SET);
6895 //
6896 //     while(pos < output_file_len)
6897 //     {
6898 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6899 //         {
6900 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
6901 //                    __FILE__, __LINE__);
6902 //             tng_data->input_file = temp;
6903 //             tng_block_destroy(&block);
6904 //             return(TNG_CRITICAL);
6905 //         }
6906 //         pos += block->header_contents_size + block->block_contents_size;
6907 //         fseek(tng_data->output_file, pos, SEEK_SET);
6908 //     }
6909 //
6910 //     return(TNG_SUCCESS);
6911 // }
6912 */
6913 /** Finish writing the current frame set. Update the number of frames
6914  * and the hashes of the frame set and all its data blocks (if hash_mode
6915  * == TNG_USE_HASH).
6916  * @param tng_data is a trajectory data container.
6917  * @param hash_mode specifies whether to update the block md5 hash when
6918  * updating the pointers.
6919  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6920  * error has occured.
6921  */
6922 static tng_function_status tng_frame_set_finalize
6923                 (tng_trajectory_t tng_data, const char hash_mode)
6924 {
6925     tng_gen_block_t block;
6926     tng_trajectory_frame_set_t frame_set;
6927     FILE *temp = tng_data->input_file;
6928     int64_t pos, contents_start_pos, output_file_len;
6929
6930     frame_set = &tng_data->current_trajectory_frame_set;
6931
6932     if(frame_set->n_written_frames == frame_set->n_frames)
6933     {
6934         return(TNG_SUCCESS);
6935     }
6936
6937     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6938     {
6939         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6940                __FILE__, __LINE__);
6941         return(TNG_CRITICAL);
6942     }
6943
6944     tng_block_init(&block);
6945 /*     output_file_pos = ftell(tng_data->output_file); */
6946
6947     tng_data->input_file = tng_data->output_file;
6948
6949     pos = tng_data->current_trajectory_frame_set_output_file_pos;
6950
6951     fseek(tng_data->output_file, (long)pos, SEEK_SET);
6952
6953     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6954     {
6955         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6956             __FILE__, __LINE__);
6957         tng_data->input_file = temp;
6958         tng_block_destroy(&block);
6959         return(TNG_CRITICAL);
6960     }
6961
6962     contents_start_pos = ftell(tng_data->output_file);
6963
6964     fseek(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
6965     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
6966               1, tng_data->output_file) != 1)
6967     {
6968         tng_data->input_file = temp;
6969         tng_block_destroy(&block);
6970         return(TNG_CRITICAL);
6971     }
6972
6973
6974     if(hash_mode == TNG_USE_HASH)
6975     {
6976         tng_md5_hash_update(tng_data, block, pos,
6977                             pos + block->header_contents_size);
6978     }
6979
6980     fseek(tng_data->output_file, 0, SEEK_END);
6981     output_file_len = ftell(tng_data->output_file);
6982     pos = contents_start_pos + block->block_contents_size;
6983     fseek(tng_data->output_file, (long)pos, SEEK_SET);
6984
6985     while(pos < output_file_len)
6986     {
6987         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6988         {
6989             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
6990                    __FILE__, __LINE__);
6991             tng_data->input_file = temp;
6992             tng_block_destroy(&block);
6993             return(TNG_CRITICAL);
6994         }
6995
6996         if(hash_mode == TNG_USE_HASH)
6997         {
6998             tng_md5_hash_update(tng_data, block, pos,
6999                                 pos + block->header_contents_size);
7000         }
7001         pos += block->header_contents_size + block->block_contents_size;
7002         fseek(tng_data->output_file, (long)pos, SEEK_SET);
7003     }
7004
7005     tng_data->input_file = temp;
7006     tng_block_destroy(&block);
7007     return(TNG_SUCCESS);
7008 }
7009
7010 /*
7011 // ** Sets the name of a file contents block
7012 //  * @param tng_data is a trajectory data container.
7013 //  * @param block is the block, of which to change names.
7014 //  * @param new_name is the new name of the block.
7015 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7016 //  * error has occured.
7017 //
7018 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7019 //                                               tng_gen_block_t block,
7020 //                                               const char *new_name)
7021 // {
7022 //     int len;
7023 //
7024 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7025 //
7026 //      * If the currently stored string length is not enough to store the new
7027 //      * string it is freed and reallocated. *
7028 //     if(block->name && strlen(block->name) < len)
7029 //     {
7030 //         free(block->name);
7031 //         block->name = 0;
7032 //     }
7033 //     if(!block->name)
7034 //     {
7035 //         block->name = malloc(len);
7036 //         if(!block->name)
7037 //         {
7038 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7039 //                    __FILE__, __LINE__);
7040 //             return(TNG_CRITICAL);
7041 //         }
7042 //     }
7043 //
7044 //     strncpy(block->name, new_name, len);
7045 //
7046 //     return(TNG_SUCCESS);
7047 // }
7048 */
7049
7050 tng_function_status tng_atom_residue_get(tng_trajectory_t tng_data,
7051                                          const tng_atom_t atom,
7052                                          tng_residue_t *residue)
7053 {
7054     (void) tng_data;
7055
7056     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7057
7058     *residue = atom->residue;
7059
7060     return(TNG_SUCCESS);
7061 }
7062
7063 tng_function_status tng_atom_name_get(tng_trajectory_t tng_data,
7064                                       const tng_atom_t atom,
7065                                       char *name,
7066                                       const int max_len)
7067 {
7068     (void) tng_data;
7069     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7070     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7071
7072     strncpy(name, atom->name, max_len - 1);
7073     name[max_len - 1] = 0;
7074
7075     if(strlen(atom->name) > (unsigned int)max_len - 1)
7076     {
7077         return(TNG_FAILURE);
7078     }
7079     return(TNG_SUCCESS);
7080 }
7081
7082 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7083                                       tng_atom_t atom,
7084                                       const char *new_name)
7085 {
7086     unsigned int len;
7087     (void)tng_data;
7088
7089     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7090     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7091
7092     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7093
7094     /* If the currently stored string length is not enough to store the new
7095      * string it is freed and reallocated. */
7096     if(atom->name && strlen(atom->name) < len)
7097     {
7098         free(atom->name);
7099         atom->name = 0;
7100     }
7101     if(!atom->name)
7102     {
7103         atom->name = malloc(len);
7104         if(!atom->name)
7105         {
7106             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7107                    __FILE__, __LINE__);
7108             return(TNG_CRITICAL);
7109         }
7110     }
7111
7112     strncpy(atom->name, new_name, len);
7113
7114     return(TNG_SUCCESS);
7115 }
7116
7117 tng_function_status tng_atom_type_get(tng_trajectory_t tng_data,
7118                                       const tng_atom_t atom,
7119                                       char *type,
7120                                       const int max_len)
7121 {
7122     (void) tng_data;
7123     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7124     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7125
7126     strncpy(type, atom->atom_type, max_len - 1);
7127     type[max_len - 1] = 0;
7128
7129     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7130     {
7131         return(TNG_FAILURE);
7132     }
7133     return(TNG_SUCCESS);
7134 }
7135
7136 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7137                                       tng_atom_t atom,
7138                                       const char *new_type)
7139 {
7140     unsigned int len;
7141     (void)tng_data;
7142
7143     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7144     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7145
7146     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7147
7148     /* If the currently stored string length is not enough to store the new
7149      * string it is freed and reallocated. */
7150     if(atom->atom_type && strlen(atom->atom_type) < len)
7151     {
7152         free(atom->atom_type);
7153         atom->atom_type = 0;
7154     }
7155     if(!atom->atom_type)
7156     {
7157         atom->atom_type = malloc(len);
7158         if(!atom->atom_type)
7159         {
7160             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7161                    __FILE__, __LINE__);
7162             return(TNG_CRITICAL);
7163         }
7164     }
7165
7166     strncpy(atom->atom_type, new_type, len);
7167
7168     return(TNG_SUCCESS);
7169 }
7170
7171 /** Initialise an atom struct
7172  * @param atom is the atom to initialise.
7173  * @return TNG_SUCCESS (0) if successful.
7174  */
7175 static tng_function_status tng_atom_init(tng_atom_t atom)
7176 {
7177     atom->name = 0;
7178     atom->atom_type = 0;
7179
7180     return(TNG_SUCCESS);
7181 }
7182
7183 /** Free the memory in an atom struct
7184  * @param atom is the atom to destroy.
7185  * @return TNG_SUCCESS (0) if successful.
7186  */
7187 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7188 {
7189     if(atom->name)
7190     {
7191         free(atom->name);
7192         atom->name = 0;
7193     }
7194     if(atom->atom_type)
7195     {
7196         free(atom->atom_type);
7197         atom->atom_type = 0;
7198     }
7199
7200     return(TNG_SUCCESS);
7201 }
7202
7203 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7204                 (tng_trajectory_t tng_data,
7205                  const char *name,
7206                  tng_molecule_t *molecule)
7207 {
7208     int64_t id, i;
7209     tng_bool found_id = TNG_TRUE;
7210
7211     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7212     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7213
7214     /* Find an unused ID */
7215     id = 0;
7216     while(found_id)
7217     {
7218         found_id = TNG_FALSE;
7219         for(i = tng_data->n_molecules; i--;)
7220         {
7221             if(tng_data->molecules[i].id == id)
7222             {
7223                 found_id = TNG_TRUE;
7224                 i = 0;
7225             }
7226         }
7227         if(found_id)
7228         {
7229             id++;
7230         }
7231     }
7232
7233     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7234 }
7235
7236 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7237                 (tng_trajectory_t tng_data,
7238                  const char *name,
7239                  const int64_t id,
7240                  tng_molecule_t *molecule)
7241 {
7242     tng_molecule_t new_molecules;
7243     int64_t *new_molecule_cnt_list, i;
7244     tng_function_status stat = TNG_SUCCESS;
7245
7246     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7247     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7248
7249     new_molecules = realloc(tng_data->molecules,
7250                             sizeof(struct tng_molecule) *
7251                             (tng_data->n_molecules + 1));
7252
7253     if(!new_molecules)
7254     {
7255         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7256                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7257                __FILE__, __LINE__);
7258         free(tng_data->molecules);
7259         tng_data->molecules = 0;
7260         return(TNG_CRITICAL);
7261     }
7262
7263     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7264                                     sizeof(int64_t) *
7265                                     (tng_data->n_molecules + 1));
7266
7267     if(!new_molecule_cnt_list)
7268     {
7269         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7270                sizeof(int64_t) * (tng_data->n_molecules + 1),
7271                __FILE__, __LINE__);
7272         free(tng_data->molecule_cnt_list);
7273         tng_data->molecule_cnt_list = 0;
7274         free(new_molecules);
7275         return(TNG_CRITICAL);
7276     }
7277
7278     tng_data->molecules = new_molecules;
7279     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7280
7281     *molecule = &new_molecules[tng_data->n_molecules];
7282
7283     tng_molecule_init(tng_data, *molecule);
7284     tng_molecule_name_set(tng_data, *molecule, name);
7285
7286     /* FIXME: Should this be a function argument instead? */
7287     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7288
7289     for(i = tng_data->n_molecules; i--;)
7290     {
7291         if(tng_data->molecules[i].id == id)
7292         {
7293             stat = TNG_FAILURE;
7294             fprintf(stderr, "TNG library: Molecule ID %"PRId64" already in use. %s: %d\n", id,
7295                    __FILE__, __LINE__);
7296             break;
7297         }
7298     }
7299
7300     (*molecule)->id = id;
7301
7302     tng_data->n_molecules++;
7303
7304     return(stat);
7305 }
7306
7307 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
7308                 (tng_trajectory_t tng_data,
7309                  tng_molecule_t *molecule_p)
7310 {
7311     tng_bool found_id = TNG_TRUE;
7312     tng_molecule_t new_molecules, molecule;
7313     int64_t *new_molecule_cnt_list, i, id;
7314
7315     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7316
7317     /* Find an unused ID */
7318     id = 0;
7319     while(found_id)
7320     {
7321         found_id = TNG_FALSE;
7322         for(i = tng_data->n_molecules; i--;)
7323         {
7324             if(tng_data->molecules[i].id == id)
7325             {
7326                 found_id = TNG_TRUE;
7327                 i = 0;
7328             }
7329         }
7330         if(found_id)
7331         {
7332             id++;
7333         }
7334     }
7335
7336     new_molecules = realloc(tng_data->molecules,
7337                             sizeof(struct tng_molecule) *
7338                             (tng_data->n_molecules + 1));
7339
7340     if(!new_molecules)
7341     {
7342         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7343                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7344                __FILE__, __LINE__);
7345         free(tng_data->molecules);
7346         tng_data->molecules = 0;
7347         return(TNG_CRITICAL);
7348     }
7349
7350     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7351                                     sizeof(int64_t) *
7352                                     (tng_data->n_molecules + 1));
7353
7354     if(!new_molecule_cnt_list)
7355     {
7356         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7357                sizeof(int64_t) * (tng_data->n_molecules + 1),
7358                __FILE__, __LINE__);
7359         free(tng_data->molecule_cnt_list);
7360         tng_data->molecule_cnt_list = 0;
7361         free(new_molecules);
7362         return(TNG_CRITICAL);
7363     }
7364
7365     molecule = *molecule_p;
7366
7367     tng_data->molecules = new_molecules;
7368     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7369
7370     new_molecules[tng_data->n_molecules] = *molecule;
7371
7372     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7373
7374     free(*molecule_p);
7375
7376     molecule = &new_molecules[tng_data->n_molecules];
7377
7378     *molecule_p = molecule;
7379
7380     molecule->id = id;
7381
7382     tng_data->n_molecules++;
7383
7384     return(TNG_SUCCESS);
7385 }
7386
7387 tng_function_status tng_molecule_name_get(tng_trajectory_t tng_data,
7388                                           const tng_molecule_t molecule,
7389                                           char *name,
7390                                           const int max_len)
7391 {
7392     (void) tng_data;
7393     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7394     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7395
7396     strncpy(name, molecule->name, max_len - 1);
7397     name[max_len - 1] = 0;
7398
7399     if(strlen(molecule->name) > (unsigned int)max_len - 1)
7400     {
7401         return(TNG_FAILURE);
7402     }
7403     return(TNG_SUCCESS);
7404 }
7405
7406 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
7407                 (tng_trajectory_t tng_data,
7408                  tng_molecule_t molecule,
7409                  const char *new_name)
7410 {
7411     unsigned int len;
7412     (void)tng_data;
7413
7414     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7415     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7416
7417     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7418
7419     /* If the currently stored string length is not enough to store the new
7420      * string it is freed and reallocated. */
7421     if(molecule->name && strlen(molecule->name) < len)
7422     {
7423         free(molecule->name);
7424         molecule->name = 0;
7425     }
7426     if(!molecule->name)
7427     {
7428         molecule->name = malloc(len);
7429         if(!molecule->name)
7430         {
7431             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7432                    __FILE__, __LINE__);
7433             return(TNG_CRITICAL);
7434         }
7435     }
7436
7437     strncpy(molecule->name, new_name, len);
7438
7439     return(TNG_SUCCESS);
7440 }
7441
7442 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
7443                 (tng_trajectory_t tng_data,
7444                  tng_molecule_t molecule,
7445                  int64_t *cnt)
7446 {
7447     int64_t i, index = -1;
7448
7449     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7450     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
7451
7452     for(i = tng_data->n_molecules; i--;)
7453     {
7454         if(&tng_data->molecules[i] == molecule)
7455         {
7456             index = i;
7457             i = 0;
7458         }
7459     }
7460     if(index == -1)
7461     {
7462         return(TNG_FAILURE);
7463     }
7464     *cnt = tng_data->molecule_cnt_list[index];
7465
7466     return(TNG_SUCCESS);
7467 }
7468
7469 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
7470                 (tng_trajectory_t tng_data,
7471                  tng_molecule_t molecule,
7472                  const int64_t cnt)
7473 {
7474     int64_t i, old_cnt, index = -1;
7475
7476     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7477
7478     for(i = tng_data->n_molecules; i--;)
7479     {
7480         if(&tng_data->molecules[i] == molecule)
7481         {
7482             index = i;
7483             i = 0;
7484         }
7485     }
7486     if(index == -1)
7487     {
7488         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
7489                __FILE__, __LINE__);
7490         return(TNG_FAILURE);
7491     }
7492     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
7493     {
7494         old_cnt = tng_data->molecule_cnt_list[index];
7495         tng_data->molecule_cnt_list[index] = cnt;
7496
7497         tng_data->n_particles += (cnt-old_cnt) *
7498                                  tng_data->molecules[index].n_atoms;
7499     }
7500     else
7501     {
7502         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
7503         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
7504
7505         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
7506                 tng_data->molecules[index].n_atoms;
7507     }
7508
7509     return(TNG_SUCCESS);
7510 }
7511
7512 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
7513                 (tng_trajectory_t tng_data,
7514                  const char *name,
7515                  int64_t nr,
7516                  tng_molecule_t *molecule)
7517 {
7518     int64_t i, n_molecules;
7519
7520     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7521     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7522     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7523
7524     n_molecules = tng_data->n_molecules;
7525
7526     for(i = 0; i < n_molecules; i++)
7527     {
7528         *molecule = &tng_data->molecules[i];
7529         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
7530         {
7531             if(nr == -1 || nr == (*molecule)->id)
7532             {
7533                 return(TNG_SUCCESS);
7534             }
7535         }
7536     }
7537
7538     *molecule = 0;
7539
7540     return(TNG_FAILURE);
7541 }
7542
7543 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
7544                 (tng_trajectory_t tng_data,
7545                  int64_t index,
7546                  tng_molecule_t *molecule)
7547 {
7548     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7549     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7550
7551     if(index >= tng_data->n_molecules)
7552     {
7553         *molecule = 0;
7554         return(TNG_FAILURE);
7555     }
7556     *molecule = &tng_data->molecules[index];
7557     return(TNG_SUCCESS);
7558 }
7559
7560 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
7561                                                                tng_trajectory_t tng_data_dest)
7562 {
7563     tng_molecule_t molecule, molecule_temp;
7564     tng_chain_t chain, chain_temp;
7565     tng_residue_t residue, residue_temp;
7566     tng_atom_t atom, atom_temp;
7567     tng_bond_t bond_temp;
7568     tng_function_status stat;
7569     int64_t i, j, k, l, *list_temp;
7570
7571     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
7572     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
7573
7574     for(i = 0; i < tng_data_dest->n_molecules; i++)
7575     {
7576         molecule = &tng_data_dest->molecules[i];
7577         tng_molecule_destroy(tng_data_dest, molecule);
7578     }
7579
7580     tng_data_dest->n_molecules = 0;
7581     tng_data_dest->n_particles = 0;
7582
7583     molecule_temp = realloc(tng_data_dest->molecules,
7584                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
7585     if(!molecule_temp)
7586     {
7587         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7588                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
7589                __FILE__, __LINE__);
7590         free(tng_data_dest->molecules);
7591         tng_data_dest->molecules = 0;
7592         return(TNG_CRITICAL);
7593     }
7594     list_temp = realloc(tng_data_dest->molecule_cnt_list,
7595                                      sizeof(int64_t) * tng_data_src->n_molecules);
7596     if(!list_temp)
7597     {
7598         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7599                sizeof(int64_t) * tng_data_src->n_molecules,
7600                __FILE__, __LINE__);
7601         free(tng_data_dest->molecule_cnt_list);
7602         tng_data_dest->molecule_cnt_list = 0;
7603         free(molecule_temp);
7604         return(TNG_CRITICAL);
7605     }
7606
7607     tng_data_dest->molecules = molecule_temp;
7608     tng_data_dest->molecule_cnt_list = list_temp;
7609
7610     for(i = 0; i < tng_data_src->n_molecules; i++)
7611     {
7612         molecule = &tng_data_src->molecules[i];
7613         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
7614                                      &molecule_temp);
7615         if(stat != TNG_SUCCESS)
7616         {
7617             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
7618                    __FILE__, __LINE__);
7619             return(stat);
7620         }
7621         molecule_temp->quaternary_str = molecule->quaternary_str;
7622         for(j = 0; j < molecule->n_chains; j++)
7623         {
7624             chain = &molecule->chains[j];
7625             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
7626                                                chain->name, chain->id,
7627                                                &chain_temp);
7628             if(stat != TNG_SUCCESS)
7629             {
7630                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
7631                        __FILE__, __LINE__);
7632                 return(stat);
7633             }
7634             for(k = 0; k < chain->n_residues; k++)
7635             {
7636                 residue = &chain->residues[k];
7637                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
7638                                                   residue->name, residue->id,
7639                                                   &residue_temp);
7640                 if(stat != TNG_SUCCESS)
7641                 {
7642                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
7643                            __FILE__, __LINE__);
7644                     return(stat);
7645                 }
7646                 for(l = 0; l < residue->n_atoms; l++)
7647                 {
7648                     atom = &molecule->atoms[residue->atoms_offset + l];
7649                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
7650                                                      atom->name, atom->atom_type,
7651                                                      atom->id, &atom_temp);
7652                     if(stat != TNG_SUCCESS)
7653                     {
7654                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
7655                            __FILE__, __LINE__);
7656                         return(stat);
7657                     }
7658                 }
7659             }
7660         }
7661         molecule_temp->n_bonds = molecule->n_bonds;
7662         bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
7663                             molecule->n_bonds);
7664         if(!bond_temp)
7665         {
7666             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7667                    sizeof(struct tng_bond) * molecule->n_bonds,
7668                    __FILE__, __LINE__);
7669             free(molecule_temp->bonds);
7670             molecule_temp->n_bonds = 0;
7671             return(TNG_CRITICAL);
7672         }
7673         molecule_temp->bonds = bond_temp;
7674         for(j = 0; j < molecule->n_bonds; j++)
7675         {
7676             molecule_temp->bonds[j] = molecule->bonds[j];
7677         }
7678         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
7679                                     tng_data_src->molecule_cnt_list[i]);
7680         if(stat != TNG_SUCCESS)
7681         {
7682             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
7683                    __FILE__, __LINE__);
7684             return(stat);
7685         }
7686     }
7687     return(TNG_SUCCESS);
7688 }
7689
7690 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
7691                 (const tng_trajectory_t tng_data,
7692                  const tng_molecule_t molecule,
7693                  int64_t *n)
7694 {
7695     (void) tng_data;
7696     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7697     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7698
7699     *n = molecule->n_chains;
7700
7701     return(TNG_SUCCESS);
7702 }
7703
7704 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
7705                 (tng_trajectory_t tng_data,
7706                  tng_molecule_t molecule,
7707                  int64_t index,
7708                  tng_chain_t *chain)
7709 {
7710     (void) tng_data;
7711     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7712     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7713
7714     if(index >= molecule->n_chains)
7715     {
7716         *chain = 0;
7717         return(TNG_FAILURE);
7718     }
7719     *chain = &molecule->chains[index];
7720     return(TNG_SUCCESS);
7721 }
7722
7723 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
7724                 (const tng_trajectory_t tng_data,
7725                  const tng_molecule_t molecule,
7726                  int64_t *n)
7727 {
7728     (void) tng_data;
7729     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7730     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7731
7732     *n = molecule->n_residues;
7733
7734     return(TNG_SUCCESS);
7735 }
7736
7737 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
7738                 (tng_trajectory_t tng_data,
7739                  tng_molecule_t molecule,
7740                  int64_t index,
7741                  tng_residue_t *residue)
7742 {
7743     (void) tng_data;
7744     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7745     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7746
7747     if(index >= molecule->n_residues)
7748     {
7749         *residue = 0;
7750         return(TNG_FAILURE);
7751     }
7752     *residue = &molecule->residues[index];
7753     return(TNG_SUCCESS);
7754 }
7755
7756 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
7757                 (const tng_trajectory_t tng_data,
7758                  const tng_molecule_t molecule,
7759                  int64_t *n)
7760 {
7761     (void) tng_data;
7762     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7763     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7764
7765     *n = molecule->n_atoms;
7766
7767     return(TNG_SUCCESS);
7768 }
7769
7770 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
7771                 (tng_trajectory_t tng_data,
7772                  tng_molecule_t molecule,
7773                  int64_t index,
7774                  tng_atom_t *atom)
7775 {
7776     (void) tng_data;
7777     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7778     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7779
7780     if(index >= molecule->n_atoms)
7781     {
7782         *atom = 0;
7783         return(TNG_FAILURE);
7784     }
7785     *atom = &molecule->atoms[index];
7786     return(TNG_SUCCESS);
7787 }
7788
7789 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
7790                 (tng_trajectory_t tng_data,
7791                  tng_molecule_t molecule,
7792                  const char *name,
7793                  int64_t nr,
7794                  tng_chain_t *chain)
7795 {
7796     int64_t i, n_chains;
7797     (void)tng_data;
7798
7799     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7800     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7801
7802     n_chains = molecule->n_chains;
7803
7804     for(i = 0; i < n_chains; i++)
7805     {
7806         *chain = &molecule->chains[i];
7807         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
7808         {
7809             if(nr == -1 || nr == (*chain)->id)
7810             {
7811                 return(TNG_SUCCESS);
7812             }
7813         }
7814     }
7815
7816     *chain = 0;
7817
7818     return(TNG_FAILURE);
7819 }
7820
7821 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
7822                 (tng_trajectory_t tng_data,
7823                  tng_molecule_t molecule,
7824                  const char *name,
7825                  tng_chain_t *chain)
7826 {
7827     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7828     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7829
7830     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
7831                                        molecule->n_chains + 1, chain));
7832 }
7833
7834 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
7835                 (tng_trajectory_t tng_data,
7836                  tng_molecule_t molecule,
7837                  const char *name,
7838                  const int64_t id,
7839                  tng_chain_t *chain)
7840 {
7841     int64_t i;
7842     tng_chain_t new_chains;
7843     tng_function_status stat = TNG_SUCCESS;
7844
7845     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7846     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7847
7848     new_chains = realloc(molecule->chains,
7849                          sizeof(struct tng_chain) *
7850                          (molecule->n_chains + 1));
7851
7852     if(!new_chains)
7853     {
7854         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7855                sizeof(struct tng_chain) * (molecule->n_chains + 1),
7856                __FILE__, __LINE__);
7857         free(molecule->chains);
7858         molecule->chains = 0;
7859         return(TNG_CRITICAL);
7860     }
7861
7862     molecule->chains = new_chains;
7863
7864     *chain = &new_chains[molecule->n_chains];
7865     (*chain)->name = 0;
7866
7867     tng_chain_name_set(tng_data, *chain, name);
7868
7869     (*chain)->molecule = molecule;
7870     (*chain)->n_residues = 0;
7871
7872     for(i = molecule->n_chains; i--;)
7873     {
7874         if(molecule->chains[i].id == id)
7875         {
7876             stat = TNG_FAILURE;
7877             fprintf(stderr, "TNG library: Chain ID already in use. %s: %d\n", __FILE__, __LINE__);
7878             break;
7879         }
7880     }
7881
7882     molecule->n_chains++;
7883
7884     (*chain)->id = id;
7885
7886     return(stat);
7887 }
7888
7889 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
7890                 (const tng_trajectory_t tng_data,
7891                  tng_molecule_t molecule,
7892                  const int64_t from_atom_id,
7893                  const int64_t to_atom_id,
7894                  tng_bond_t *bond)
7895 {
7896     int64_t i;
7897     tng_bond_t new_bonds;
7898     (void)tng_data;
7899
7900     for(i = 0; i < molecule->n_bonds; i++)
7901     {
7902         *bond = &molecule->bonds[i];
7903         /* Check if the bond already exists */
7904         if(((*bond)->from_atom_id == from_atom_id && (*bond)->to_atom_id == to_atom_id) ||
7905            ((*bond)->to_atom_id == from_atom_id && (*bond)->from_atom_id == to_atom_id))
7906         {
7907             return(TNG_SUCCESS);
7908         }
7909     }
7910
7911     new_bonds = realloc(molecule->bonds,
7912                         sizeof(struct tng_bond) *
7913                         (molecule->n_bonds + 1));
7914
7915     if(!new_bonds)
7916     {
7917         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7918                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
7919                __FILE__, __LINE__);
7920         *bond = 0;
7921         free(molecule->bonds);
7922         molecule->bonds = 0;
7923         return(TNG_CRITICAL);
7924     }
7925
7926     molecule->bonds = new_bonds;
7927
7928     *bond = &new_bonds[molecule->n_bonds];
7929
7930     (*bond)->from_atom_id = from_atom_id;
7931     (*bond)->to_atom_id = to_atom_id;
7932
7933     molecule->n_bonds++;
7934
7935     return(TNG_SUCCESS);
7936 }
7937
7938 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
7939                 (tng_trajectory_t tng_data,
7940                  tng_molecule_t molecule,
7941                  const char *name,
7942                  int64_t id,
7943                  tng_atom_t *atom)
7944 {
7945     int64_t i, n_atoms;
7946     (void)tng_data;
7947
7948     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7949
7950     n_atoms = molecule->n_atoms;
7951
7952     for(i = 0; i < n_atoms; i++)
7953     {
7954         *atom = &molecule->atoms[i];
7955         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
7956         {
7957             if(id == -1 || id == (*atom)->id)
7958             {
7959                 return(TNG_SUCCESS);
7960             }
7961         }
7962     }
7963
7964     *atom = 0;
7965
7966     return(TNG_FAILURE);
7967 }
7968
7969 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
7970                                        const tng_chain_t chain,
7971                                        char *name,
7972                                        const int max_len)
7973 {
7974     (void) tng_data;
7975     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7976     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7977
7978     strncpy(name, chain->name, max_len - 1);
7979     name[max_len - 1] = 0;
7980
7981     if(strlen(chain->name) > (unsigned int)max_len - 1)
7982     {
7983         return(TNG_FAILURE);
7984     }
7985     return(TNG_SUCCESS);
7986 }
7987
7988 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
7989                 (tng_trajectory_t tng_data,
7990                  tng_chain_t chain,
7991                  const char *new_name)
7992 {
7993     unsigned int len;
7994     (void)tng_data;
7995
7996     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7997
7998     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7999
8000     /* If the currently stored string length is not enough to store the new
8001      * string it is freed and reallocated. */
8002     if(chain->name && strlen(chain->name) < len)
8003     {
8004         free(chain->name);
8005         chain->name = 0;
8006     }
8007     if(!chain->name)
8008     {
8009         chain->name = malloc(len);
8010         if(!chain->name)
8011         {
8012             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8013                    __FILE__, __LINE__);
8014             return(TNG_CRITICAL);
8015         }
8016     }
8017
8018     strncpy(chain->name, new_name, len);
8019
8020     return(TNG_SUCCESS);
8021 }
8022
8023 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8024                 (const tng_trajectory_t tng_data,
8025                  const tng_chain_t chain,
8026                  int64_t *n)
8027 {
8028     (void) tng_data;
8029     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8030     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8031
8032     *n = chain->n_residues;
8033
8034     return(TNG_SUCCESS);
8035 }
8036
8037 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8038                 (tng_trajectory_t tng_data,
8039                  tng_chain_t chain,
8040                  int64_t index,
8041                  tng_residue_t *residue)
8042 {
8043     (void) tng_data;
8044     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8045     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8046
8047     if(index >= chain->n_residues)
8048     {
8049         *residue = 0;
8050         return(TNG_FAILURE);
8051     }
8052     *residue = &chain->residues[index];
8053     return(TNG_SUCCESS);
8054 }
8055
8056 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8057                 (tng_trajectory_t tng_data,
8058                  tng_chain_t chain,
8059                  const char *name,
8060                  int64_t id,
8061                  tng_residue_t *residue)
8062 {
8063     int64_t i, n_residues;
8064     (void)tng_data;
8065
8066     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8067
8068     n_residues = chain->n_residues;
8069
8070     for(i = 0; i < n_residues; i++)
8071     {
8072         *residue = &chain->residues[i];
8073         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8074         {
8075             if(id == -1 || id == (*residue)->id)
8076             {
8077                 return(TNG_SUCCESS);
8078             }
8079         }
8080     }
8081
8082     *residue = 0;
8083
8084     return(TNG_FAILURE);
8085 }
8086
8087 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8088                 (tng_trajectory_t tng_data,
8089                  tng_chain_t chain,
8090                  const char *name,
8091                  tng_residue_t *residue)
8092 {
8093     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8094     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8095
8096     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8097                                       chain->n_residues + 1, residue));
8098 }
8099
8100 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8101                 (tng_trajectory_t tng_data,
8102                  tng_chain_t chain,
8103                  const char *name,
8104                  const int64_t id,
8105                  tng_residue_t *residue)
8106 {
8107     int64_t i, curr_index;
8108     tng_residue_t new_residues, temp_residue, last_residue;
8109     tng_molecule_t molecule = chain->molecule;
8110     tng_function_status stat = TNG_SUCCESS;
8111
8112     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8113     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8114
8115     if(chain->n_residues)
8116     {
8117         curr_index = chain->residues - molecule->residues;
8118     }
8119     else
8120     {
8121         curr_index = -1;
8122     }
8123
8124     new_residues = realloc(molecule->residues,
8125                            sizeof(struct tng_residue) *
8126                            (molecule->n_residues + 1));
8127
8128     if(!new_residues)
8129     {
8130         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8131                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8132                __FILE__, __LINE__);
8133         free(molecule->residues);
8134         molecule->residues = 0;
8135         return(TNG_CRITICAL);
8136     }
8137
8138     molecule->residues = new_residues;
8139
8140     if(curr_index != -1)
8141     {
8142         chain->residues = new_residues + curr_index;
8143         if(molecule->n_residues)
8144         {
8145             last_residue = &new_residues[molecule->n_residues - 1];
8146
8147             temp_residue = chain->residues + (chain->n_residues - 1);
8148             /* Make space in list of residues to add the new residues together with the other
8149             * residues of this chain */
8150             if(temp_residue != last_residue)
8151             {
8152                 ++temp_residue;
8153                 memmove(temp_residue + 1, temp_residue,
8154                         last_residue - temp_residue);
8155             }
8156         }
8157     }
8158     else
8159     {
8160         curr_index = molecule->n_residues;
8161     }
8162
8163     *residue = &molecule->residues[curr_index + chain->n_residues];
8164
8165     if(!chain->n_residues)
8166     {
8167         chain->residues = *residue;
8168     }
8169
8170     (*residue)->name = 0;
8171     tng_residue_name_set(tng_data, *residue, name);
8172
8173     (*residue)->chain = chain;
8174     (*residue)->n_atoms = 0;
8175     (*residue)->atoms_offset = 0;
8176
8177     for(i = chain->n_residues; i--;)
8178     {
8179         if(chain->residues[i].id == id)
8180         {
8181             stat = TNG_FAILURE;
8182             fprintf(stderr, "TNG library: Residue ID already in use. %s: %d\n", __FILE__, __LINE__);
8183             break;
8184         }
8185     }
8186
8187     chain->n_residues++;
8188     molecule->n_residues++;
8189
8190     (*residue)->id = id;
8191
8192     return(stat);
8193 }
8194
8195 tng_function_status tng_residue_name_get(tng_trajectory_t tng_data,
8196                                          const tng_residue_t residue,
8197                                          char *name,
8198                                          const int max_len)
8199 {
8200     (void) tng_data;
8201     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8202     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8203
8204     strncpy(name, residue->name, max_len - 1);
8205     name[max_len - 1] = 0;
8206
8207     if(strlen(residue->name) > (unsigned int)max_len - 1)
8208     {
8209         return(TNG_FAILURE);
8210     }
8211     return(TNG_SUCCESS);
8212 }
8213
8214 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8215                                                            tng_residue_t residue,
8216                                                            const char *new_name)
8217 {
8218     unsigned int len;
8219     (void)tng_data;
8220
8221     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8222     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8223
8224     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8225
8226     /* If the currently stored string length is not enough to store the new
8227      * string it is freed and reallocated. */
8228     if(residue->name && strlen(residue->name) < len)
8229     {
8230         free(residue->name);
8231         residue->name = 0;
8232     }
8233     if(!residue->name)
8234     {
8235         residue->name = malloc(len);
8236         if(!residue->name)
8237         {
8238             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8239                    __FILE__, __LINE__);
8240             return(TNG_CRITICAL);
8241         }
8242     }
8243
8244     strncpy(residue->name, new_name, len);
8245
8246     return(TNG_SUCCESS);
8247 }
8248
8249 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8250                 (const tng_trajectory_t tng_data,
8251                  const tng_residue_t residue,
8252                  int64_t *n)
8253 {
8254     (void) tng_data;
8255     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8256     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8257
8258     *n = residue->n_atoms;
8259
8260     return(TNG_SUCCESS);
8261 }
8262
8263 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8264                 (tng_trajectory_t tng_data,
8265                  tng_residue_t residue,
8266                  int64_t index,
8267                  tng_atom_t *atom)
8268 {
8269     tng_chain_t chain;
8270     tng_molecule_t molecule;
8271
8272     (void) tng_data;
8273     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8274     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8275
8276     if(index >= residue->n_atoms)
8277     {
8278         *atom = 0;
8279         return(TNG_FAILURE);
8280     }
8281     chain = residue->chain;
8282     molecule = chain->molecule;
8283
8284     if(index + residue->atoms_offset >= molecule->n_atoms)
8285     {
8286         *atom = 0;
8287         return(TNG_FAILURE);
8288     }
8289
8290     *atom = &molecule->atoms[residue->atoms_offset + index];
8291     return(TNG_SUCCESS);
8292 }
8293
8294 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
8295                 (tng_trajectory_t tng_data,
8296                  tng_residue_t residue,
8297                  const char *atom_name,
8298                  const char *atom_type,
8299                  tng_atom_t *atom)
8300 {
8301     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8302     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8303     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8304
8305     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
8306                                      residue->chain->molecule->n_atoms + 1,
8307                                      atom));
8308 }
8309
8310 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
8311                 (tng_trajectory_t tng_data,
8312                  tng_residue_t residue,
8313                  const char *atom_name,
8314                  const char *atom_type,
8315                  const int64_t id,
8316                  tng_atom_t *atom)
8317 {
8318     int64_t i;
8319     tng_atom_t new_atoms;
8320     tng_molecule_t molecule = residue->chain->molecule;
8321     tng_function_status stat = TNG_SUCCESS;
8322
8323     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8324     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8325     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8326
8327     if(!residue->n_atoms)
8328     {
8329         residue->atoms_offset = molecule->n_atoms;
8330     }
8331
8332     new_atoms = realloc(molecule->atoms,
8333                         sizeof(struct tng_atom) *
8334                         (molecule->n_atoms + 1));
8335
8336     if(!new_atoms)
8337     {
8338         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8339                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
8340                __FILE__, __LINE__);
8341         free(molecule->atoms);
8342         molecule->atoms = 0;
8343         return(TNG_CRITICAL);
8344     }
8345
8346     molecule->atoms = new_atoms;
8347
8348     *atom = &new_atoms[molecule->n_atoms];
8349
8350     tng_atom_init(*atom);
8351     tng_atom_name_set(tng_data, *atom, atom_name);
8352     tng_atom_type_set(tng_data, *atom, atom_type);
8353
8354     (*atom)->residue = residue;
8355
8356     for(i = molecule->n_atoms; i--;)
8357     {
8358         if(molecule->atoms[i].id == id)
8359         {
8360             stat = TNG_FAILURE;
8361             fprintf(stderr, "TNG library: Atom ID %"PRId64" already in use. %s: %d\n", id, __FILE__, __LINE__);
8362             break;
8363         }
8364     }
8365
8366     residue->n_atoms++;
8367     molecule->n_atoms++;
8368
8369     (*atom)->id = id;
8370
8371     return(stat);
8372 }
8373
8374 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
8375                                                          tng_molecule_t *molecule_p)
8376 {
8377     *molecule_p = malloc(sizeof(struct tng_molecule));
8378     if(!*molecule_p)
8379     {
8380         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
8381                sizeof(struct tng_molecule), __FILE__, __LINE__);
8382         return(TNG_CRITICAL);
8383     }
8384
8385     tng_molecule_init(tng_data, *molecule_p);
8386
8387     return(TNG_SUCCESS);
8388 }
8389
8390 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
8391                                                         tng_molecule_t *molecule_p)
8392 {
8393     if(!*molecule_p)
8394     {
8395         return(TNG_SUCCESS);
8396     }
8397
8398     tng_molecule_destroy(tng_data, *molecule_p);
8399
8400     free(*molecule_p);
8401     *molecule_p = 0;
8402
8403     return(TNG_SUCCESS);
8404 }
8405
8406 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
8407                                                         tng_molecule_t molecule)
8408 {
8409     (void)tng_data;
8410     molecule->quaternary_str = 1;
8411     molecule->name = 0;
8412     molecule->n_chains = 0;
8413     molecule->chains = 0;
8414     molecule->n_residues = 0;
8415     molecule->residues = 0;
8416     molecule->n_atoms = 0;
8417     molecule->atoms = 0;
8418     molecule->n_bonds = 0;
8419     molecule->bonds = 0;
8420
8421     return(TNG_SUCCESS);
8422 }
8423
8424 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
8425                                                            tng_molecule_t molecule)
8426 {
8427     int64_t i;
8428     (void)tng_data;
8429
8430     if(molecule->name)
8431     {
8432         free(molecule->name);
8433         molecule->name = 0;
8434     }
8435
8436     if(molecule->chains)
8437     {
8438         for(i = molecule->n_chains; i--;)
8439         {
8440             if(molecule->chains[i].name)
8441             {
8442                 free(molecule->chains[i].name);
8443                 molecule->chains[i].name = 0;
8444             }
8445         }
8446         free(molecule->chains);
8447         molecule->chains = 0;
8448     }
8449     molecule->n_chains = 0;
8450
8451     if(molecule->residues)
8452     {
8453         for(i = molecule->n_residues; i--;)
8454         {
8455             if(molecule->residues[i].name)
8456             {
8457                 free(molecule->residues[i].name);
8458                 molecule->residues[i].name = 0;
8459             }
8460         }
8461         free(molecule->residues);
8462         molecule->residues = 0;
8463     }
8464     molecule->n_residues = 0;
8465
8466     if(molecule->atoms)
8467     {
8468         for(i = molecule->n_atoms; i--;)
8469         {
8470             tng_atom_destroy(&molecule->atoms[i]);
8471         }
8472         free(molecule->atoms);
8473         molecule->atoms = 0;
8474     }
8475     molecule->n_atoms = 0;
8476
8477     if(molecule->bonds)
8478     {
8479         free(molecule->bonds);
8480         molecule->bonds = 0;
8481     }
8482     molecule->n_bonds = 0;
8483
8484     return(TNG_SUCCESS);
8485 }
8486
8487 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
8488                 (const tng_trajectory_t tng_data,
8489                  const int64_t nr,
8490                  char *name,
8491                  int max_len)
8492 {
8493     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8494     tng_molecule_t mol;
8495     tng_bool found = TNG_FALSE;
8496
8497     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8498     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8499
8500     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8501
8502     if(!molecule_cnt_list)
8503     {
8504         return(TNG_FAILURE);
8505     }
8506
8507     for(i = 0; i < tng_data->n_molecules; i++)
8508     {
8509         mol = &tng_data->molecules[i];
8510         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8511         {
8512             cnt += mol->n_atoms * molecule_cnt_list[i];
8513             continue;
8514         }
8515         found = TNG_TRUE;
8516         break;
8517     }
8518     if(!found)
8519     {
8520         return(TNG_FAILURE);
8521     }
8522
8523     strncpy(name, mol->name, max_len - 1);
8524     name[max_len - 1] = 0;
8525
8526     if(strlen(mol->name) > (unsigned int)max_len - 1)
8527     {
8528         return(TNG_FAILURE);
8529     }
8530     return(TNG_SUCCESS);
8531 }
8532
8533 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
8534                 (const tng_trajectory_t tng_data,
8535                  const int64_t nr,
8536                  int64_t *id)
8537 {
8538     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8539     tng_molecule_t mol;
8540     tng_bool found = TNG_FALSE;
8541
8542     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8543     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8544
8545     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8546
8547     if(!molecule_cnt_list)
8548     {
8549         return(TNG_FAILURE);
8550     }
8551
8552     for(i = 0; i < tng_data->n_molecules; i++)
8553     {
8554         mol = &tng_data->molecules[i];
8555         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8556         {
8557             cnt += mol->n_atoms * molecule_cnt_list[i];
8558             continue;
8559         }
8560         found = TNG_TRUE;
8561         break;
8562     }
8563     if(!found)
8564     {
8565         return(TNG_FAILURE);
8566     }
8567
8568     *id = mol->id;
8569
8570     return(TNG_SUCCESS);
8571 }
8572
8573 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
8574                 (const tng_trajectory_t tng_data,
8575                  int64_t *n_bonds,
8576                  int64_t **from_atoms,
8577                  int64_t **to_atoms)
8578 {
8579     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
8580     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
8581     tng_molecule_t mol;
8582     tng_bond_t bond;
8583
8584     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8585     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
8586     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
8587     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
8588
8589     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8590
8591     if(!molecule_cnt_list)
8592     {
8593         return(TNG_FAILURE);
8594     }
8595
8596     *n_bonds = 0;
8597     /* First count the total number of bonds to allocate memory */
8598     for(i = 0; i < tng_data->n_molecules; i++)
8599     {
8600         mol = &tng_data->molecules[i];
8601         mol_cnt = molecule_cnt_list[i];
8602         *n_bonds += mol_cnt * mol->n_bonds;
8603     }
8604     if(*n_bonds == 0)
8605     {
8606         return(TNG_SUCCESS);
8607     }
8608
8609     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
8610     if(!*from_atoms)
8611     {
8612         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8613                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
8614         return(TNG_CRITICAL);
8615     }
8616     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
8617     if(!*to_atoms)
8618     {
8619         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8620                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
8621         free(*from_atoms);
8622         *from_atoms = 0;
8623         return(TNG_CRITICAL);
8624     }
8625
8626     cnt = 0;
8627     for(i = 0; i < tng_data->n_molecules; i++)
8628     {
8629         mol = &tng_data->molecules[i];
8630         mol_cnt = molecule_cnt_list[i];
8631         for(j = 0; j < mol_cnt; j++)
8632         {
8633             for(k = 0; k < mol->n_bonds; k++)
8634             {
8635                 bond = &mol->bonds[k];
8636                 from_atom = atom_cnt + bond->from_atom_id;
8637                 to_atom = atom_cnt + bond->to_atom_id;
8638                 (*from_atoms)[cnt] = from_atom;
8639                 (*to_atoms)[cnt++] = to_atom;
8640             }
8641             atom_cnt += mol->n_atoms;
8642         }
8643     }
8644
8645     return(TNG_SUCCESS);
8646 }
8647
8648 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
8649                 (const tng_trajectory_t tng_data,
8650                  const int64_t nr,
8651                  char *name,
8652                  int max_len)
8653 {
8654     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8655     tng_molecule_t mol;
8656     tng_atom_t atom;
8657     tng_bool found = TNG_FALSE;
8658
8659     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8660     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8661
8662     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8663
8664     if(!molecule_cnt_list)
8665     {
8666         return(TNG_FAILURE);
8667     }
8668
8669     for(i = 0; i < tng_data->n_molecules; i++)
8670     {
8671         mol = &tng_data->molecules[i];
8672         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8673         {
8674             cnt += mol->n_atoms * molecule_cnt_list[i];
8675             continue;
8676         }
8677         atom = &mol->atoms[nr % mol->n_atoms];
8678         found = TNG_TRUE;
8679         break;
8680     }
8681     if(!found)
8682     {
8683         return(TNG_FAILURE);
8684     }
8685     if(!atom->residue || !atom->residue->chain)
8686     {
8687         return(TNG_FAILURE);
8688     }
8689
8690     strncpy(name, atom->residue->chain->name, max_len - 1);
8691     name[max_len - 1] = 0;
8692
8693     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
8694     {
8695         return(TNG_FAILURE);
8696     }
8697     return(TNG_SUCCESS);
8698 }
8699
8700 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
8701                 (const tng_trajectory_t tng_data,
8702                  const int64_t nr,
8703                  char *name,
8704                  int max_len)
8705 {
8706     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8707     tng_molecule_t mol;
8708     tng_atom_t atom;
8709     tng_bool found = TNG_FALSE;
8710
8711     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8712     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8713
8714     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8715
8716     if(!molecule_cnt_list)
8717     {
8718         return(TNG_FAILURE);
8719     }
8720
8721     for(i = 0; i < tng_data->n_molecules; i++)
8722     {
8723         mol = &tng_data->molecules[i];
8724         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8725         {
8726             cnt += mol->n_atoms * molecule_cnt_list[i];
8727             continue;
8728         }
8729         atom = &mol->atoms[nr % mol->n_atoms];
8730         found = TNG_TRUE;
8731         break;
8732     }
8733     if(!found)
8734     {
8735         return(TNG_FAILURE);
8736     }
8737     if(!atom->residue)
8738     {
8739         return(TNG_FAILURE);
8740     }
8741
8742     strncpy(name, atom->residue->name, max_len - 1);
8743     name[max_len - 1] = 0;
8744
8745     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
8746     {
8747         return(TNG_FAILURE);
8748     }
8749     return(TNG_SUCCESS);
8750 }
8751
8752 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
8753                 (const tng_trajectory_t tng_data,
8754                  const int64_t nr,
8755                  int64_t *id)
8756 {
8757     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8758     tng_molecule_t mol;
8759     tng_atom_t atom;
8760     tng_bool found = TNG_FALSE;
8761
8762     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8763     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8764
8765     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8766
8767     if(!molecule_cnt_list)
8768     {
8769         return(TNG_FAILURE);
8770     }
8771
8772     for(i = 0; i < tng_data->n_molecules; i++)
8773     {
8774         mol = &tng_data->molecules[i];
8775         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8776         {
8777             cnt += mol->n_atoms * molecule_cnt_list[i];
8778             continue;
8779         }
8780         atom = &mol->atoms[nr % mol->n_atoms];
8781         found = TNG_TRUE;
8782         break;
8783     }
8784     if(!found)
8785     {
8786         return(TNG_FAILURE);
8787     }
8788     if(!atom->residue)
8789     {
8790         return(TNG_FAILURE);
8791     }
8792
8793     *id = atom->residue->id;
8794
8795     return(TNG_SUCCESS);
8796 }
8797
8798 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
8799                 (const tng_trajectory_t tng_data,
8800                  const int64_t nr,
8801                  int64_t *id)
8802 {
8803     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
8804     tng_molecule_t mol;
8805     tng_atom_t atom;
8806     tng_bool found = TNG_FALSE;
8807
8808     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8809     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8810
8811     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8812
8813     if(!molecule_cnt_list)
8814     {
8815         return(TNG_FAILURE);
8816     }
8817
8818     for(i = 0; i < tng_data->n_molecules; i++)
8819     {
8820         mol = &tng_data->molecules[i];
8821         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8822         {
8823             cnt += mol->n_atoms * molecule_cnt_list[i];
8824             offset += mol->n_residues * molecule_cnt_list[i];
8825             continue;
8826         }
8827         atom = &mol->atoms[nr % mol->n_atoms];
8828         found = TNG_TRUE;
8829         break;
8830     }
8831     if(!found)
8832     {
8833         return(TNG_FAILURE);
8834     }
8835     if(!atom->residue)
8836     {
8837         return(TNG_FAILURE);
8838     }
8839
8840     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
8841
8842     *id = atom->residue->id + offset;
8843
8844     return(TNG_SUCCESS);
8845 }
8846
8847 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
8848                 (const tng_trajectory_t tng_data,
8849                  const int64_t nr,
8850                  char *name,
8851                  int max_len)
8852 {
8853     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8854     tng_molecule_t mol;
8855     tng_atom_t atom;
8856     tng_bool found = TNG_FALSE;
8857
8858     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8859     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8860
8861     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8862
8863     if(!molecule_cnt_list)
8864     {
8865         return(TNG_FAILURE);
8866     }
8867
8868     for(i = 0; i < tng_data->n_molecules; i++)
8869     {
8870         mol = &tng_data->molecules[i];
8871         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8872         {
8873             cnt += mol->n_atoms * molecule_cnt_list[i];
8874             continue;
8875         }
8876         atom = &mol->atoms[nr % mol->n_atoms];
8877         found = TNG_TRUE;
8878         break;
8879     }
8880     if(!found)
8881     {
8882         return(TNG_FAILURE);
8883     }
8884
8885     strncpy(name, atom->name, max_len - 1);
8886     name[max_len - 1] = 0;
8887
8888     if(strlen(atom->name) > (unsigned int)max_len - 1)
8889     {
8890         return(TNG_FAILURE);
8891     }
8892     return(TNG_SUCCESS);
8893 }
8894
8895 tng_function_status tng_atom_type_of_particle_nr_get
8896                 (const tng_trajectory_t tng_data,
8897                  const int64_t nr,
8898                  char *type,
8899                  int max_len)
8900 {
8901     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8902     tng_molecule_t mol;
8903     tng_atom_t atom;
8904     tng_bool found = TNG_FALSE;
8905
8906     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8907     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
8908
8909     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8910
8911     if(!molecule_cnt_list)
8912     {
8913         return(TNG_FAILURE);
8914     }
8915
8916     for(i = 0; i < tng_data->n_molecules; i++)
8917     {
8918         mol = &tng_data->molecules[i];
8919         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8920         {
8921             cnt += mol->n_atoms * molecule_cnt_list[i];
8922             continue;
8923         }
8924         atom = &mol->atoms[nr % mol->n_atoms];
8925         found = TNG_TRUE;
8926         break;
8927     }
8928     if(!found)
8929     {
8930         return(TNG_FAILURE);
8931     }
8932
8933     strncpy(type, atom->atom_type, max_len - 1);
8934     type[max_len - 1] = 0;
8935
8936     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
8937     {
8938         return(TNG_FAILURE);
8939     }
8940     return(TNG_SUCCESS);
8941 }
8942
8943 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
8944                 (tng_trajectory_t tng_data,
8945                  const int64_t num_first_particle,
8946                  const int64_t n_particles,
8947                  const int64_t *mapping_table)
8948 {
8949     int64_t i;
8950     tng_particle_mapping_t mapping;
8951     tng_trajectory_frame_set_t frame_set;
8952
8953     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8954
8955     frame_set = &tng_data->current_trajectory_frame_set;
8956
8957     /* Sanity check of the particle ranges. Split into multiple if
8958      * statements for improved readability */
8959     for(i = 0; i < frame_set->n_mapping_blocks; i++)
8960     {
8961         mapping = &frame_set->mappings[i];
8962         if(num_first_particle >= mapping->num_first_particle &&
8963            num_first_particle < mapping->num_first_particle +
8964                                    mapping->n_particles)
8965         {
8966             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8967             return(TNG_FAILURE);
8968         }
8969         if(num_first_particle + n_particles >=
8970            mapping->num_first_particle &&
8971            num_first_particle + n_particles <
8972            mapping->num_first_particle + mapping->n_particles)
8973         {
8974             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8975             return(TNG_FAILURE);
8976         }
8977         if(mapping->num_first_particle >= num_first_particle &&
8978            mapping->num_first_particle < num_first_particle +
8979                                             n_particles)
8980         {
8981             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8982             return(TNG_FAILURE);
8983         }
8984         if(mapping->num_first_particle + mapping->n_particles >
8985            num_first_particle &&
8986            mapping->num_first_particle + mapping->n_particles <
8987            num_first_particle + n_particles)
8988         {
8989             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8990             return(TNG_FAILURE);
8991         }
8992     }
8993
8994     frame_set->n_mapping_blocks++;
8995
8996     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
8997                       frame_set->n_mapping_blocks);
8998
8999     if(!mapping)
9000     {
9001         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9002                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9003                __FILE__, __LINE__);
9004         free(frame_set->mappings);
9005         frame_set->mappings = 0;
9006         return(TNG_CRITICAL);
9007     }
9008     frame_set->mappings = mapping;
9009
9010     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9011     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9012
9013     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9014     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9015     {
9016         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9017                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9018         return(TNG_CRITICAL);
9019     }
9020
9021     for(i=0; i<n_particles; i++)
9022     {
9023         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9024     }
9025
9026     return(TNG_SUCCESS);
9027 }
9028
9029 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9030 {
9031     tng_trajectory_frame_set_t frame_set;
9032     tng_particle_mapping_t mapping;
9033     int64_t i;
9034
9035     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9036
9037     frame_set = &tng_data->current_trajectory_frame_set;
9038
9039     if(frame_set->n_mapping_blocks && frame_set->mappings)
9040     {
9041         for(i = frame_set->n_mapping_blocks; i--;)
9042         {
9043             mapping = &frame_set->mappings[i];
9044             if(mapping->real_particle_numbers)
9045             {
9046                 free(mapping->real_particle_numbers);
9047                 mapping->real_particle_numbers = 0;
9048             }
9049         }
9050         free(frame_set->mappings);
9051         frame_set->mappings = 0;
9052         frame_set->n_mapping_blocks = 0;
9053     }
9054
9055     return(TNG_SUCCESS);
9056 }
9057
9058 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9059 {
9060     time_t seconds;
9061     tng_trajectory_frame_set_t frame_set;
9062     tng_trajectory_t tng_data;
9063
9064     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9065     if(!*tng_data_p)
9066     {
9067         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9068                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9069         return(TNG_CRITICAL);
9070     }
9071
9072     tng_data = *tng_data_p;
9073
9074     frame_set = &tng_data->current_trajectory_frame_set;
9075
9076     tng_data->input_file_path = 0;
9077     tng_data->input_file = 0;
9078     tng_data->input_file_len = 0;
9079     tng_data->output_file_path = 0;
9080     tng_data->output_file = 0;
9081
9082     tng_data->first_program_name = 0;
9083     tng_data->first_user_name = 0;
9084     tng_data->first_computer_name = 0;
9085     tng_data->first_pgp_signature = 0;
9086     tng_data->last_program_name = 0;
9087     tng_data->last_user_name = 0;
9088     tng_data->last_computer_name = 0;
9089     tng_data->last_pgp_signature = 0;
9090     tng_data->forcefield_name = 0;
9091
9092     seconds = time(0);
9093     if ( seconds == -1)
9094     {
9095         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9096     }
9097     else
9098     {
9099         tng_data->time = seconds;
9100     }
9101
9102     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9103     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9104     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9105     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9106     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9107     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9108     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9109     tng_data->frame_set_n_frames = 100;
9110     tng_data->n_trajectory_frame_sets = 0;
9111     tng_data->n_trajectory_blocks = 0;
9112     tng_data->medium_stride_length = 100;
9113     tng_data->long_stride_length = 10000;
9114
9115     tng_data->time_per_frame = -1;
9116
9117     tng_data->n_particle_data_blocks = 0;
9118     tng_data->n_data_blocks = 0;
9119
9120     tng_data->non_tr_particle_data = 0;
9121     tng_data->non_tr_data = 0;
9122
9123     tng_data->compress_algo_pos = 0;
9124     tng_data->compress_algo_vel = 0;
9125     tng_data->compression_precision = 1000;
9126     tng_data->distance_unit_exponential = -9;
9127
9128     frame_set->first_frame = -1;
9129     frame_set->n_mapping_blocks = 0;
9130     frame_set->mappings = 0;
9131     frame_set->molecule_cnt_list = 0;
9132
9133     frame_set->n_particle_data_blocks = 0;
9134     frame_set->n_data_blocks = 0;
9135
9136     frame_set->tr_particle_data = 0;
9137     frame_set->tr_data = 0;
9138
9139     frame_set->n_written_frames = 0;
9140     frame_set->n_unwritten_frames = 0;
9141
9142     frame_set->next_frame_set_file_pos = -1;
9143     frame_set->prev_frame_set_file_pos = -1;
9144     frame_set->medium_stride_next_frame_set_file_pos = -1;
9145     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9146     frame_set->long_stride_next_frame_set_file_pos = -1;
9147     frame_set->long_stride_prev_frame_set_file_pos = -1;
9148
9149     frame_set->first_frame_time = -1;
9150
9151     tng_data->n_molecules = 0;
9152     tng_data->molecules = 0;
9153     tng_data->molecule_cnt_list = 0;
9154     tng_data->n_particles = 0;
9155
9156     {
9157       /* Check the endianness of the computer */
9158       static int32_t endianness_32 = 0x01234567;
9159       /* 0x01234567 */
9160       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9161         {
9162           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9163         }
9164
9165       /* 0x67452301 */
9166       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9167         {
9168           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9169
9170         }
9171
9172       /* 0x45670123 */
9173       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9174         {
9175           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9176         }
9177     }
9178     {
9179       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9180       /* 0x0123456789ABCDEF */
9181       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9182         {
9183           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9184         }
9185
9186       /* 0xEFCDAB8967452301 */
9187       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9188         {
9189           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9190         }
9191
9192       /* 0x89ABCDEF01234567 */
9193       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9194         {
9195           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9196         }
9197
9198       /* 0x45670123CDEF89AB */
9199       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9200         {
9201           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9202         }
9203
9204       /* 0x23016745AB89EFCD */
9205       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9206         {
9207           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9208         }
9209     }
9210
9211     /* By default do not swap the byte order, i.e. keep the byte order of the
9212      * architecture. The input file endianness will be set when reading the
9213      * header. The output endianness can be changed - before the file is
9214      * written. */
9215     tng_data->input_endianness_swap_func_32 = 0;
9216     tng_data->input_endianness_swap_func_64 = 0;
9217     tng_data->output_endianness_swap_func_32 = 0;
9218     tng_data->output_endianness_swap_func_64 = 0;
9219
9220     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9221     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9222     tng_data->current_trajectory_frame_set.n_frames = 0;
9223
9224     return(TNG_SUCCESS);
9225 }
9226
9227 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9228 {
9229     int64_t i, j, k, l;
9230     int64_t n_particles, n_values_per_frame;
9231     tng_trajectory_t tng_data = *tng_data_p;
9232     tng_trajectory_frame_set_t frame_set;
9233
9234     if(!*tng_data_p)
9235     {
9236         return(TNG_SUCCESS);
9237     }
9238
9239     frame_set = &tng_data->current_trajectory_frame_set;
9240
9241     if(tng_data->input_file_path)
9242     {
9243         free(tng_data->input_file_path);
9244         tng_data->input_file_path = 0;
9245     }
9246
9247     if(tng_data->input_file)
9248     {
9249         fclose(tng_data->input_file);
9250         tng_data->input_file = 0;
9251     }
9252
9253     if(tng_data->output_file_path)
9254     {
9255         free(tng_data->output_file_path);
9256         tng_data->output_file_path = 0;
9257     }
9258
9259     if(tng_data->output_file)
9260     {
9261         /* FIXME: Do not always write the hash */
9262         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9263         fclose(tng_data->output_file);
9264         tng_data->output_file = 0;
9265     }
9266
9267     if(tng_data->first_program_name)
9268     {
9269         free(tng_data->first_program_name);
9270         tng_data->first_program_name = 0;
9271     }
9272
9273     if(tng_data->last_program_name)
9274     {
9275         free(tng_data->last_program_name);
9276         tng_data->last_program_name = 0;
9277     }
9278
9279     if(tng_data->first_user_name)
9280     {
9281         free(tng_data->first_user_name);
9282         tng_data->first_user_name = 0;
9283     }
9284
9285     if(tng_data->last_user_name)
9286     {
9287         free(tng_data->last_user_name);
9288         tng_data->last_user_name = 0;
9289     }
9290
9291     if(tng_data->first_computer_name)
9292     {
9293         free(tng_data->first_computer_name);
9294         tng_data->first_computer_name = 0;
9295     }
9296
9297     if(tng_data->last_computer_name)
9298     {
9299         free(tng_data->last_computer_name);
9300         tng_data->last_computer_name = 0;
9301     }
9302
9303     if(tng_data->first_pgp_signature)
9304     {
9305         free(tng_data->first_pgp_signature);
9306         tng_data->first_pgp_signature = 0;
9307     }
9308
9309     if(tng_data->last_pgp_signature)
9310     {
9311         free(tng_data->last_pgp_signature);
9312         tng_data->last_pgp_signature = 0;
9313     }
9314
9315     if(tng_data->forcefield_name)
9316     {
9317         free(tng_data->forcefield_name);
9318         tng_data->forcefield_name = 0;
9319     }
9320
9321     tng_frame_set_particle_mapping_free(tng_data);
9322
9323     if(frame_set->molecule_cnt_list)
9324     {
9325         free(frame_set->molecule_cnt_list);
9326         frame_set->molecule_cnt_list = 0;
9327     }
9328
9329     if(tng_data->var_num_atoms_flag)
9330     {
9331         n_particles = frame_set->n_particles;
9332     }
9333     else
9334     {
9335         n_particles = tng_data->n_particles;
9336     }
9337
9338     if(tng_data->non_tr_particle_data)
9339     {
9340         for(i = tng_data->n_particle_data_blocks; i--; )
9341         {
9342             if(tng_data->non_tr_particle_data[i].values)
9343             {
9344                 free(tng_data->non_tr_particle_data[i].values);
9345                 tng_data->non_tr_particle_data[i].values = 0;
9346             }
9347
9348             if(tng_data->non_tr_particle_data[i].strings)
9349             {
9350                 n_values_per_frame = tng_data->non_tr_particle_data[i].
9351                                      n_values_per_frame;
9352                 if(tng_data->non_tr_particle_data[i].strings[0])
9353                 {
9354                     for(j = n_particles; j--;)
9355                     {
9356                         if(tng_data->non_tr_particle_data[i].strings[0][j])
9357                         {
9358                             for(k = n_values_per_frame; k--;)
9359                             {
9360                                 if(tng_data->non_tr_particle_data[i].
9361                                    strings[0][j][k])
9362                                 {
9363                                     free(tng_data->non_tr_particle_data[i].
9364                                          strings[0][j][k]);
9365                                     tng_data->non_tr_particle_data[i].
9366                                     strings[0][j][k] = 0;
9367                                 }
9368                             }
9369                             free(tng_data->non_tr_particle_data[i].
9370                                  strings[0][j]);
9371                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
9372                         }
9373                     }
9374                     free(tng_data->non_tr_particle_data[i].strings[0]);
9375                     tng_data->non_tr_particle_data[i].strings[0] = 0;
9376                 }
9377                 free(tng_data->non_tr_particle_data[i].strings);
9378                 tng_data->non_tr_particle_data[i].strings = 0;
9379             }
9380
9381             if(tng_data->non_tr_particle_data[i].block_name)
9382             {
9383                 free(tng_data->non_tr_particle_data[i].block_name);
9384                 tng_data->non_tr_particle_data[i].block_name = 0;
9385             }
9386         }
9387         free(tng_data->non_tr_particle_data);
9388         tng_data->non_tr_particle_data = 0;
9389     }
9390
9391     if(tng_data->non_tr_data)
9392     {
9393         for(i = tng_data->n_data_blocks; i--;)
9394         {
9395             if(tng_data->non_tr_data[i].values)
9396             {
9397                 free(tng_data->non_tr_data[i].values);
9398                 tng_data->non_tr_data[i].values = 0;
9399             }
9400
9401             if(tng_data->non_tr_data[i].strings)
9402             {
9403                 n_values_per_frame = tng_data->non_tr_data[i].
9404                                      n_values_per_frame;
9405                 if(tng_data->non_tr_data[i].strings[0])
9406                 {
9407                     for(j = n_values_per_frame; j--;)
9408                     {
9409                         if(tng_data->non_tr_data[i].strings[0][j])
9410                         {
9411                             free(tng_data->non_tr_data[i].strings[0][j]);
9412                             tng_data->non_tr_data[i].strings[0][j] = 0;
9413                         }
9414                     }
9415                     free(tng_data->non_tr_data[i].strings[0]);
9416                     tng_data->non_tr_data[i].strings[0] = 0;
9417                 }
9418                 free(tng_data->non_tr_data[i].strings);
9419                 tng_data->non_tr_data[i].strings = 0;
9420             }
9421
9422             if(tng_data->non_tr_data[i].block_name)
9423             {
9424                 free(tng_data->non_tr_data[i].block_name);
9425                 tng_data->non_tr_data[i].block_name = 0;
9426             }
9427         }
9428         free(tng_data->non_tr_data);
9429         tng_data->non_tr_data = 0;
9430     }
9431
9432     tng_data->n_particle_data_blocks = 0;
9433     tng_data->n_data_blocks = 0;
9434
9435     if(tng_data->compress_algo_pos)
9436     {
9437         free(tng_data->compress_algo_pos);
9438         tng_data->compress_algo_pos = 0;
9439     }
9440     if(tng_data->compress_algo_vel)
9441     {
9442         free(tng_data->compress_algo_vel);
9443         tng_data->compress_algo_vel = 0;
9444     }
9445
9446     if(frame_set->tr_particle_data)
9447     {
9448         for(i = frame_set->n_particle_data_blocks; i--; )
9449         {
9450             if(frame_set->tr_particle_data[i].values)
9451             {
9452                 free(frame_set->tr_particle_data[i].values);
9453                 frame_set->tr_particle_data[i].values = 0;
9454             }
9455
9456             if(frame_set->tr_particle_data[i].strings)
9457             {
9458                 n_values_per_frame = frame_set->tr_particle_data[i].
9459                                      n_values_per_frame;
9460                 for(j = frame_set->tr_particle_data[i].n_frames; j--;)
9461                 {
9462                     if(frame_set->tr_particle_data[i].strings[j])
9463                     {
9464                         for(k = n_particles; k--;)
9465                         {
9466                             if(frame_set->tr_particle_data[i].
9467                                 strings[j][k])
9468                             {
9469                                 for(l = n_values_per_frame; l--;)
9470                                 {
9471                                     if(frame_set->tr_particle_data[i].
9472                                         strings[j][k][l])
9473                                     {
9474                                         free(frame_set->tr_particle_data[i].
9475                                                 strings[j][k][l]);
9476                                         frame_set->tr_particle_data[i].
9477                                         strings[j][k][l] = 0;
9478                                     }
9479                                 }
9480                                 free(frame_set->tr_particle_data[i].
9481                                         strings[j][k]);
9482                                 frame_set->tr_particle_data[i].
9483                                 strings[j][k] = 0;
9484                             }
9485                         }
9486                         free(frame_set->tr_particle_data[i].strings[j]);
9487                         frame_set->tr_particle_data[i].strings[j] = 0;
9488                     }
9489                 }
9490                 free(frame_set->tr_particle_data[i].strings);
9491                 frame_set->tr_particle_data[i].strings = 0;
9492             }
9493
9494             if(frame_set->tr_particle_data[i].block_name)
9495             {
9496                 free(frame_set->tr_particle_data[i].block_name);
9497                 frame_set->tr_particle_data[i].block_name = 0;
9498             }
9499         }
9500         free(frame_set->tr_particle_data);
9501         frame_set->tr_particle_data = 0;
9502     }
9503
9504     if(frame_set->tr_data)
9505     {
9506         for(i = frame_set->n_data_blocks; i--;)
9507         {
9508             if(frame_set->tr_data[i].values)
9509             {
9510                 free(frame_set->tr_data[i].values);
9511                 frame_set->tr_data[i].values = 0;
9512             }
9513
9514             if(frame_set->tr_data[i].strings)
9515             {
9516                 n_values_per_frame = frame_set->tr_data[i].
9517                                      n_values_per_frame;
9518                 for(j = frame_set->tr_data[i].n_frames; j--;)
9519                 {
9520                     if(frame_set->tr_data[i].strings[j])
9521                     {
9522                         for(k = n_values_per_frame; k--;)
9523                         {
9524                             if(frame_set->tr_data[i].strings[j][k])
9525                             {
9526                                 free(frame_set->tr_data[i].strings[j][k]);
9527                                 frame_set->tr_data[i].strings[j][k] = 0;
9528                             }
9529                         }
9530                         free(frame_set->tr_data[i].strings[j]);
9531                         frame_set->tr_data[i].strings[j] = 0;
9532                     }
9533                 }
9534                 free(frame_set->tr_data[i].strings);
9535                 frame_set->tr_data[i].strings = 0;
9536             }
9537
9538             if(frame_set->tr_data[i].block_name)
9539             {
9540                 free(frame_set->tr_data[i].block_name);
9541                 frame_set->tr_data[i].block_name = 0;
9542             }
9543         }
9544         free(frame_set->tr_data);
9545         frame_set->tr_data = 0;
9546     }
9547
9548     frame_set->n_particle_data_blocks = 0;
9549     frame_set->n_data_blocks = 0;
9550
9551     if(tng_data->molecules)
9552     {
9553         for(i=tng_data->n_molecules; i--;)
9554         {
9555             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
9556         }
9557         free(tng_data->molecules);
9558         tng_data->molecules = 0;
9559         tng_data->n_molecules = 0;
9560     }
9561     if(tng_data->molecule_cnt_list)
9562     {
9563         free(tng_data->molecule_cnt_list);
9564         tng_data->molecule_cnt_list = 0;
9565     }
9566
9567     free(*tng_data_p);
9568     *tng_data_p = 0;
9569
9570     return(TNG_SUCCESS);
9571 }
9572
9573 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
9574                                                  tng_trajectory_t *dest_p)
9575 {
9576     tng_trajectory_frame_set_t frame_set;
9577     tng_trajectory_t dest;
9578
9579     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
9580
9581     *dest_p = malloc(sizeof(struct tng_trajectory));
9582     if(!*dest_p)
9583     {
9584         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9585                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9586         return(TNG_CRITICAL);
9587     }
9588
9589     dest = *dest_p;
9590
9591     frame_set = &dest->current_trajectory_frame_set;
9592
9593     strcpy(dest->input_file_path, src->input_file_path);
9594     dest->input_file = 0;
9595     dest->input_file_len = src->input_file_len;
9596     strcpy(dest->output_file_path, src->output_file_path);
9597     dest->output_file = 0;
9598
9599     dest->first_program_name = 0;
9600     dest->first_user_name = 0;
9601     dest->first_computer_name = 0;
9602     dest->first_pgp_signature = 0;
9603     dest->last_program_name = 0;
9604     dest->last_user_name = 0;
9605     dest->last_computer_name = 0;
9606     dest->last_pgp_signature = 0;
9607     dest->forcefield_name = 0;
9608
9609     dest->var_num_atoms_flag = src->var_num_atoms_flag;
9610     dest->first_trajectory_frame_set_input_file_pos =
9611     src->first_trajectory_frame_set_input_file_pos;
9612     dest->last_trajectory_frame_set_input_file_pos =
9613     src->last_trajectory_frame_set_input_file_pos;
9614     dest->current_trajectory_frame_set_input_file_pos =
9615     src->current_trajectory_frame_set_input_file_pos;
9616     dest->first_trajectory_frame_set_output_file_pos =
9617     src->first_trajectory_frame_set_output_file_pos;
9618     dest->last_trajectory_frame_set_output_file_pos =
9619     src->last_trajectory_frame_set_output_file_pos;
9620     dest->current_trajectory_frame_set_output_file_pos =
9621     src->current_trajectory_frame_set_output_file_pos;
9622     dest->frame_set_n_frames = src->frame_set_n_frames;
9623     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
9624     dest->n_trajectory_blocks = src->n_trajectory_blocks;
9625     dest->medium_stride_length = src->medium_stride_length;
9626     dest->long_stride_length = src->long_stride_length;
9627
9628     dest->time_per_frame = src->time_per_frame;
9629
9630     /* Currently the non trajectory data blocks are not copied since it
9631      * can lead to problems when freeing memory in a parallel block. */
9632     dest->n_particle_data_blocks = 0;
9633     dest->n_data_blocks = 0;
9634     dest->non_tr_particle_data = 0;
9635     dest->non_tr_data = 0;
9636
9637     dest->compress_algo_pos = 0;
9638     dest->compress_algo_vel = 0;
9639     dest->distance_unit_exponential = -9;
9640     dest->compression_precision = 1000;
9641
9642     frame_set->n_mapping_blocks = 0;
9643     frame_set->mappings = 0;
9644     frame_set->molecule_cnt_list = 0;
9645
9646     frame_set->n_particle_data_blocks = 0;
9647     frame_set->n_data_blocks = 0;
9648
9649     frame_set->tr_particle_data = 0;
9650     frame_set->tr_data = 0;
9651
9652     frame_set->next_frame_set_file_pos = -1;
9653     frame_set->prev_frame_set_file_pos = -1;
9654     frame_set->medium_stride_next_frame_set_file_pos = -1;
9655     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9656     frame_set->long_stride_next_frame_set_file_pos = -1;
9657     frame_set->long_stride_prev_frame_set_file_pos = -1;
9658     frame_set->first_frame = -1;
9659
9660     dest->n_molecules = 0;
9661     dest->molecules = 0;
9662     dest->molecule_cnt_list = 0;
9663     dest->n_particles = src->n_particles;
9664
9665     dest->endianness_32 = src->endianness_32;
9666     dest->endianness_64 = src->endianness_64;
9667     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
9668     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
9669     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
9670     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
9671
9672     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9673     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9674     dest->current_trajectory_frame_set.n_frames = 0;
9675
9676     return(TNG_SUCCESS);
9677 }
9678
9679 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
9680                                        char *file_name, const int max_len)
9681 {
9682     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9683     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9684
9685     strncpy(file_name, tng_data->input_file_path, max_len - 1);
9686     file_name[max_len - 1] = 0;
9687
9688     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
9689     {
9690         return(TNG_FAILURE);
9691     }
9692     return(TNG_SUCCESS);
9693 }
9694
9695 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
9696                                                          const char *file_name)
9697 {
9698     unsigned int len;
9699     char *temp;
9700
9701     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9702     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9703
9704
9705     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
9706                                            file_name) == 0)
9707     {
9708         return(TNG_SUCCESS);
9709     }
9710
9711     if(tng_data->input_file)
9712     {
9713         fclose(tng_data->input_file);
9714     }
9715
9716     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
9717     temp = realloc(tng_data->input_file_path, len);
9718     if(!temp)
9719     {
9720         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9721                __FILE__, __LINE__);
9722         free(tng_data->input_file_path);
9723         tng_data->input_file_path = 0;
9724         return(TNG_CRITICAL);
9725     }
9726     tng_data->input_file_path = temp;
9727
9728     strncpy(tng_data->input_file_path, file_name, len);
9729
9730     return(tng_input_file_init(tng_data));
9731 }
9732
9733 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
9734                                        char *file_name, const int max_len)
9735 {
9736     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9737     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9738
9739     strncpy(file_name, tng_data->output_file_path, max_len - 1);
9740     file_name[max_len - 1] = 0;
9741
9742     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
9743     {
9744         return(TNG_FAILURE);
9745     }
9746     return(TNG_SUCCESS);
9747 }
9748
9749 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
9750                                                           const char *file_name)
9751 {
9752     int len;
9753     char *temp;
9754
9755     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9756     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9757
9758     if(tng_data->output_file_path &&
9759        strcmp(tng_data->output_file_path, file_name) == 0)
9760     {
9761         return(TNG_SUCCESS);
9762     }
9763
9764     if(tng_data->output_file)
9765     {
9766         fclose(tng_data->output_file);
9767     }
9768
9769     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
9770     temp = realloc(tng_data->output_file_path, len);
9771     if(!temp)
9772     {
9773         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
9774                __FILE__, __LINE__);
9775         free(tng_data->output_file_path);
9776         tng_data->output_file_path = 0;
9777         return(TNG_CRITICAL);
9778     }
9779     tng_data->output_file_path = temp;
9780
9781     strncpy(tng_data->output_file_path, file_name, len);
9782
9783     return(tng_output_file_init(tng_data));
9784 }
9785
9786 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
9787                 (tng_trajectory_t tng_data,
9788                  const char *file_name)
9789 {
9790     int len;
9791     char *temp;
9792
9793     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9794     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9795
9796     if(tng_data->output_file_path &&
9797        strcmp(tng_data->output_file_path, file_name) == 0)
9798     {
9799         return(TNG_SUCCESS);
9800     }
9801
9802     if(tng_data->output_file)
9803     {
9804         fclose(tng_data->output_file);
9805     }
9806
9807     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
9808     temp = realloc(tng_data->output_file_path, len);
9809     if(!temp)
9810     {
9811         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
9812                __FILE__, __LINE__);
9813         free(tng_data->output_file_path);
9814         tng_data->output_file_path = 0;
9815         return(TNG_CRITICAL);
9816     }
9817     tng_data->output_file_path = temp;
9818
9819     strncpy(tng_data->output_file_path, file_name, len);
9820
9821     tng_data->output_file = fopen(tng_data->output_file_path, "r+");
9822     if(!tng_data->output_file)
9823     {
9824         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
9825                 tng_data->output_file_path, __FILE__, __LINE__);
9826         return(TNG_CRITICAL);
9827     }
9828
9829     return(TNG_SUCCESS);
9830 }
9831
9832 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
9833                 (tng_trajectory_t tng_data, tng_file_endianness *endianness)
9834 {
9835     tng_endianness_32 end_32;
9836     tng_endianness_64 end_64;
9837
9838     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9839     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
9840
9841     if(tng_data->output_endianness_swap_func_32)
9842     {
9843         /* If other endianness variants are added they must be added here as well */
9844         if(tng_data->output_endianness_swap_func_32 ==
9845            &tng_swap_byte_order_big_endian_32)
9846         {
9847             end_32 = TNG_BIG_ENDIAN_32;
9848         }
9849         else if(tng_data->output_endianness_swap_func_32 ==
9850                 &tng_swap_byte_order_little_endian_32)
9851         {
9852             end_32 = TNG_LITTLE_ENDIAN_32;
9853         }
9854         else
9855         {
9856             return(TNG_FAILURE);
9857         }
9858     }
9859     else
9860     {
9861         end_32 = (tng_endianness_32)tng_data->endianness_32;
9862     }
9863
9864     if(tng_data->output_endianness_swap_func_64)
9865     {
9866         /* If other endianness variants are added they must be added here as well */
9867         if(tng_data->output_endianness_swap_func_64 ==
9868            &tng_swap_byte_order_big_endian_64)
9869         {
9870             end_64 = TNG_BIG_ENDIAN_64;
9871         }
9872         else if(tng_data->output_endianness_swap_func_64 ==
9873                 &tng_swap_byte_order_little_endian_64)
9874         {
9875             end_64 = TNG_LITTLE_ENDIAN_64;
9876         }
9877         else
9878         {
9879             return(TNG_FAILURE);
9880         }
9881     }
9882     else
9883     {
9884         end_64 = (tng_endianness_64)tng_data->endianness_64;
9885     }
9886
9887     if((int)end_32 != (int)end_64)
9888     {
9889         return(TNG_FAILURE);
9890     }
9891
9892     if(end_32 == TNG_LITTLE_ENDIAN_32)
9893     {
9894         *endianness = TNG_LITTLE_ENDIAN;
9895     }
9896
9897     else if(end_32 == TNG_BIG_ENDIAN_32)
9898     {
9899         *endianness = TNG_BIG_ENDIAN;
9900     }
9901     else
9902     {
9903         return(TNG_FAILURE);
9904     }
9905
9906     return(TNG_SUCCESS);
9907 }
9908
9909 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
9910                 (tng_trajectory_t tng_data,
9911                  const tng_file_endianness endianness)
9912 {
9913     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9914
9915     /* Tne endianness cannot be changed if the data has already been written
9916      * to the output file. */
9917     if(ftell(tng_data->output_file) > 0)
9918     {
9919         return(TNG_FAILURE);
9920     }
9921
9922     if(endianness == TNG_BIG_ENDIAN)
9923     {
9924         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
9925         {
9926             tng_data->output_endianness_swap_func_32 = 0;
9927         }
9928         else
9929         {
9930             tng_data->output_endianness_swap_func_32 =
9931             &tng_swap_byte_order_big_endian_32;
9932         }
9933         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
9934         {
9935             tng_data->output_endianness_swap_func_64 = 0;
9936         }
9937         else
9938         {
9939             tng_data->output_endianness_swap_func_64 =
9940             &tng_swap_byte_order_big_endian_64;
9941         }
9942         return(TNG_SUCCESS);
9943     }
9944     else if(endianness == TNG_LITTLE_ENDIAN)
9945     {
9946         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
9947         {
9948             tng_data->output_endianness_swap_func_32 = 0;
9949         }
9950         else
9951         {
9952             tng_data->output_endianness_swap_func_32 =
9953             &tng_swap_byte_order_little_endian_32;
9954         }
9955         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
9956         {
9957             tng_data->output_endianness_swap_func_64 = 0;
9958         }
9959         else
9960         {
9961             tng_data->output_endianness_swap_func_64 =
9962             &tng_swap_byte_order_little_endian_64;
9963         }
9964         return(TNG_SUCCESS);
9965     }
9966
9967     /* If the specified endianness is neither big nor little endian return a
9968      * failure. */
9969     return(TNG_FAILURE);
9970 }
9971
9972 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
9973                     (const tng_trajectory_t tng_data,
9974                      char *name, const int max_len)
9975 {
9976     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9977     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9978
9979     strncpy(name, tng_data->first_program_name, max_len - 1);
9980     name[max_len - 1] = 0;
9981
9982     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
9983     {
9984         return(TNG_FAILURE);
9985     }
9986     return(TNG_SUCCESS);
9987 }
9988
9989 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
9990                                                                  const char *new_name)
9991 {
9992     unsigned int len;
9993
9994     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9995     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9996
9997     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
9998
9999     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10000     {
10001         free(tng_data->first_program_name);
10002         tng_data->first_program_name = 0;
10003     }
10004     if(!tng_data->first_program_name)
10005     {
10006         tng_data->first_program_name = malloc(len);
10007         if(!tng_data->first_program_name)
10008         {
10009             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10010                    __FILE__, __LINE__);
10011             return(TNG_CRITICAL);
10012         }
10013     }
10014
10015     strncpy(tng_data->first_program_name, new_name, len);
10016
10017     return(TNG_SUCCESS);
10018 }
10019
10020 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10021                     (const tng_trajectory_t tng_data,
10022                      char *name, const int max_len)
10023 {
10024     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10025     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10026
10027     strncpy(name, tng_data->last_program_name, max_len - 1);
10028     name[max_len - 1] = 0;
10029
10030     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10031     {
10032         return(TNG_FAILURE);
10033     }
10034     return(TNG_SUCCESS);
10035 }
10036
10037 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10038                     (tng_trajectory_t tng_data,
10039                      const char *new_name)
10040 {
10041     unsigned int len;
10042
10043     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10044     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10045
10046     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10047
10048     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10049     {
10050         free(tng_data->last_program_name);
10051         tng_data->last_program_name = 0;
10052     }
10053     if(!tng_data->last_program_name)
10054     {
10055         tng_data->last_program_name = malloc(len);
10056         if(!tng_data->last_program_name)
10057         {
10058             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10059                    __FILE__, __LINE__);
10060             return(TNG_CRITICAL);
10061         }
10062     }
10063
10064     strncpy(tng_data->last_program_name, new_name, len);
10065
10066     return(TNG_SUCCESS);
10067 }
10068
10069 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10070                     (const tng_trajectory_t tng_data,
10071                      char *name, const int max_len)
10072 {
10073     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10074     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10075
10076     strncpy(name, tng_data->first_user_name, max_len - 1);
10077     name[max_len - 1] = 0;
10078
10079     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10080     {
10081         return(TNG_FAILURE);
10082     }
10083     return(TNG_SUCCESS);
10084 }
10085
10086 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10087                     (tng_trajectory_t tng_data,
10088                      const char *new_name)
10089 {
10090     unsigned int len;
10091
10092     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10093     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10094
10095     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10096
10097     /* If the currently stored string length is not enough to store the new
10098      * string it is freed and reallocated. */
10099     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10100     {
10101         free(tng_data->first_user_name);
10102         tng_data->first_user_name = 0;
10103     }
10104     if(!tng_data->first_user_name)
10105     {
10106         tng_data->first_user_name = malloc(len);
10107         if(!tng_data->first_user_name)
10108         {
10109             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10110                    __FILE__, __LINE__);
10111             return(TNG_CRITICAL);
10112         }
10113     }
10114
10115     strncpy(tng_data->first_user_name, new_name, len);
10116
10117     return(TNG_SUCCESS);
10118 }
10119
10120 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10121                     (const tng_trajectory_t tng_data,
10122                      char *name, const int max_len)
10123 {
10124     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10125     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10126
10127     strncpy(name, tng_data->last_user_name, max_len - 1);
10128     name[max_len - 1] = 0;
10129
10130     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10131     {
10132         return(TNG_FAILURE);
10133     }
10134     return(TNG_SUCCESS);
10135 }
10136
10137 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10138                     (tng_trajectory_t tng_data,
10139                      const char *new_name)
10140 {
10141     unsigned int len;
10142
10143     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10144     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10145
10146     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10147
10148     /* If the currently stored string length is not enough to store the new
10149      * string it is freed and reallocated. */
10150     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10151     {
10152         free(tng_data->last_user_name);
10153         tng_data->last_user_name = 0;
10154     }
10155     if(!tng_data->last_user_name)
10156     {
10157         tng_data->last_user_name = malloc(len);
10158         if(!tng_data->last_user_name)
10159         {
10160             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10161                    __FILE__, __LINE__);
10162             return(TNG_CRITICAL);
10163         }
10164     }
10165
10166     strncpy(tng_data->last_user_name, new_name, len);
10167
10168     return(TNG_SUCCESS);
10169 }
10170
10171 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10172                     (const tng_trajectory_t tng_data,
10173                      char *name, const int max_len)
10174 {
10175     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10176     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10177
10178     strncpy(name, tng_data->first_computer_name, max_len - 1);
10179     name[max_len - 1] = 0;
10180
10181     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10182     {
10183         return(TNG_FAILURE);
10184     }
10185     return(TNG_SUCCESS);
10186 }
10187
10188 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10189                     (tng_trajectory_t tng_data,
10190                      const char *new_name)
10191 {
10192     unsigned int len;
10193
10194     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10195     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10196
10197     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10198
10199     /* If the currently stored string length is not enough to store the new
10200      * string it is freed and reallocated. */
10201     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10202     {
10203         free(tng_data->first_computer_name);
10204         tng_data->first_computer_name = 0;
10205     }
10206     if(!tng_data->first_computer_name)
10207     {
10208         tng_data->first_computer_name = malloc(len);
10209         if(!tng_data->first_computer_name)
10210         {
10211             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10212                    __FILE__, __LINE__);
10213             return(TNG_CRITICAL);
10214         }
10215     }
10216
10217     strncpy(tng_data->first_computer_name, new_name, len);
10218
10219     return(TNG_SUCCESS);
10220 }
10221
10222 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10223                     (const tng_trajectory_t tng_data,
10224                      char *name, const int max_len)
10225 {
10226     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10227     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10228
10229     strncpy(name, tng_data->last_computer_name, max_len - 1);
10230     name[max_len - 1] = 0;
10231
10232     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10233     {
10234         return(TNG_FAILURE);
10235     }
10236     return(TNG_SUCCESS);
10237 }
10238
10239 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10240                     (tng_trajectory_t tng_data,
10241                      const char *new_name)
10242 {
10243     unsigned int len;
10244
10245     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10246     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10247
10248     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10249
10250     /* If the currently stored string length is not enough to store the new
10251      * string it is freed and reallocated. */
10252     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
10253         len)
10254     {
10255         free(tng_data->last_computer_name);
10256         tng_data->last_computer_name = 0;
10257     }
10258     if(!tng_data->last_computer_name)
10259     {
10260         tng_data->last_computer_name = malloc(len);
10261         if(!tng_data->last_computer_name)
10262         {
10263             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10264                    __FILE__, __LINE__);
10265             return(TNG_CRITICAL);
10266         }
10267     }
10268
10269     strncpy(tng_data->last_computer_name, new_name, len);
10270
10271     return(TNG_SUCCESS);
10272 }
10273
10274 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
10275                     (const tng_trajectory_t tng_data,
10276                      char *signature, const int max_len)
10277 {
10278     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10279     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10280
10281     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
10282     signature[max_len - 1] = 0;
10283
10284     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
10285     {
10286         return(TNG_FAILURE);
10287     }
10288     return(TNG_SUCCESS);
10289 }
10290
10291 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
10292                     (tng_trajectory_t tng_data,
10293                      const char *signature)
10294 {
10295     unsigned int len;
10296
10297     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10298     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10299
10300     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10301
10302     /* If the currently stored string length is not enough to store the new
10303      * string it is freed and reallocated. */
10304     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
10305         len)
10306     {
10307         free(tng_data->first_pgp_signature);
10308         tng_data->first_pgp_signature = 0;
10309     }
10310     if(!tng_data->first_pgp_signature)
10311     {
10312         tng_data->first_pgp_signature = malloc(len);
10313         if(!tng_data->first_pgp_signature)
10314         {
10315             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10316                    __FILE__, __LINE__);
10317             return(TNG_CRITICAL);
10318         }
10319     }
10320
10321     strncpy(tng_data->first_pgp_signature, signature, len);
10322
10323     return(TNG_SUCCESS);
10324 }
10325
10326 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
10327                     (const tng_trajectory_t tng_data,
10328                      char *signature, const int max_len)
10329 {
10330     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10331     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10332
10333     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
10334     signature[max_len - 1] = 0;
10335
10336     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
10337     {
10338         return(TNG_FAILURE);
10339     }
10340     return(TNG_SUCCESS);
10341 }
10342
10343 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
10344                     (tng_trajectory_t tng_data,
10345                      const char *signature)
10346 {
10347     unsigned int len;
10348
10349     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10350     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10351
10352     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10353
10354     /* If the currently stored string length is not enough to store the new
10355      * string it is freed and reallocated. */
10356     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
10357         len)
10358     {
10359         free(tng_data->last_pgp_signature);
10360         tng_data->last_pgp_signature = 0;
10361     }
10362     if(!tng_data->last_pgp_signature)
10363     {
10364         tng_data->last_pgp_signature = malloc(len);
10365         if(!tng_data->last_pgp_signature)
10366         {
10367             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10368                    __FILE__, __LINE__);
10369             return(TNG_CRITICAL);
10370         }
10371     }
10372
10373     strncpy(tng_data->last_pgp_signature, signature, len);
10374
10375     return(TNG_SUCCESS);
10376 }
10377
10378 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
10379                     (const tng_trajectory_t tng_data,
10380                      char *name, const int max_len)
10381 {
10382     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10383     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10384
10385     strncpy(name, tng_data->forcefield_name, max_len - 1);
10386     name[max_len - 1] = 0;
10387
10388     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
10389     {
10390         return(TNG_FAILURE);
10391     }
10392     return(TNG_SUCCESS);
10393 }
10394
10395 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
10396                     (tng_trajectory_t tng_data,
10397                      const char *new_name)
10398 {
10399     unsigned int len;
10400
10401     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10402     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10403
10404     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10405
10406     /* If the currently stored string length is not enough to store the new
10407      * string it is freed and reallocated. */
10408     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
10409     {
10410         free(tng_data->forcefield_name);
10411         tng_data->forcefield_name = 0;
10412     }
10413     if(!tng_data->forcefield_name)
10414     {
10415         tng_data->forcefield_name = malloc(len);
10416         if(!tng_data->forcefield_name)
10417         {
10418             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10419                    __FILE__, __LINE__);
10420             return(TNG_CRITICAL);
10421         }
10422     }
10423
10424     strncpy(tng_data->forcefield_name, new_name, len);
10425
10426     return(TNG_SUCCESS);
10427 }
10428
10429 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
10430                     (const tng_trajectory_t tng_data,
10431                      int64_t *len)
10432 {
10433     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10434     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10435
10436     *len = tng_data->medium_stride_length;
10437
10438     return(TNG_SUCCESS);
10439 }
10440
10441 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
10442                     (tng_trajectory_t tng_data,
10443                      const int64_t len)
10444 {
10445     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10446
10447     if(len >= tng_data->long_stride_length)
10448     {
10449         return(TNG_FAILURE);
10450     }
10451     tng_data->medium_stride_length = len;
10452
10453     return(TNG_SUCCESS);
10454 }
10455
10456 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
10457                 (const tng_trajectory_t tng_data,
10458                  int64_t *len)
10459 {
10460     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10461     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10462
10463     *len = tng_data->long_stride_length;
10464
10465     return(TNG_SUCCESS);
10466 }
10467
10468 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
10469                 (tng_trajectory_t tng_data,
10470                  const int64_t len)
10471 {
10472     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10473
10474     if(len <= tng_data->medium_stride_length)
10475     {
10476         return(TNG_FAILURE);
10477     }
10478     tng_data->long_stride_length = len;
10479
10480     return(TNG_SUCCESS);
10481 }
10482
10483 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
10484                 (const tng_trajectory_t tng_data,
10485                  double *time)
10486 {
10487     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10488     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
10489
10490     *time = tng_data->time_per_frame;
10491
10492     return(TNG_SUCCESS);
10493 }
10494
10495 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
10496                 (tng_trajectory_t tng_data,
10497                  const double time)
10498 {
10499     tng_trajectory_frame_set_t frame_set;
10500
10501     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10502     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
10503
10504     if(fabs(time - tng_data->time_per_frame) < 0.00001)
10505     {
10506         return(TNG_SUCCESS);
10507     }
10508
10509     frame_set = &tng_data->current_trajectory_frame_set;
10510
10511     /* If the current frame set is not finished write it to disk before
10512        changing time per frame. */
10513     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
10514     {
10515         frame_set->n_frames = frame_set->n_unwritten_frames;
10516         tng_frame_set_write(tng_data, TNG_USE_HASH);
10517     }
10518     tng_data->time_per_frame = time;
10519
10520     return(TNG_SUCCESS);
10521 }
10522
10523 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
10524                     (const tng_trajectory_t tng_data,
10525                      int64_t *len)
10526 {
10527     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10528     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10529
10530     *len = tng_data->input_file_len;
10531
10532     return(TNG_SUCCESS);
10533 }
10534
10535 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
10536                     (const tng_trajectory_t tng_data,
10537                      int64_t *n)
10538 {
10539     tng_gen_block_t block;
10540     tng_function_status stat;
10541     long file_pos;
10542     int64_t last_file_pos, first_frame, n_frames;
10543
10544     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10545     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
10546     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10547
10548     file_pos = ftell(tng_data->input_file);
10549     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10550
10551     if(last_file_pos <= 0)
10552     {
10553         return(TNG_FAILURE);
10554     }
10555
10556     tng_block_init(&block);
10557     fseek(tng_data->input_file,
10558           (long)last_file_pos,
10559           SEEK_SET);
10560     /* Read block headers first to see that a frame set block is found. */
10561     stat = tng_block_header_read(tng_data, block);
10562     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10563     {
10564         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
10565                 __FILE__, __LINE__);
10566         tng_block_destroy(&block);
10567         return(TNG_FAILURE);
10568     }
10569     tng_block_destroy(&block);
10570
10571     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
10572     {
10573         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
10574                __FILE__, __LINE__);
10575         return(TNG_CRITICAL);
10576     }
10577     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
10578     {
10579         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
10580                __FILE__, __LINE__);
10581         return(TNG_CRITICAL);
10582     }
10583     fseek(tng_data->input_file, file_pos, SEEK_SET);
10584
10585     *n = first_frame + n_frames;
10586
10587     return(TNG_SUCCESS);
10588 }
10589
10590 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
10591                 (const tng_trajectory_t tng_data,
10592                  double *precision)
10593 {
10594     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10595
10596     *precision = tng_data->compression_precision;
10597
10598     return(TNG_SUCCESS);
10599 }
10600
10601 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
10602                 (tng_trajectory_t tng_data,
10603                  const double precision)
10604 {
10605     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10606
10607     tng_data->compression_precision = precision;
10608
10609     return(TNG_SUCCESS);
10610 }
10611
10612 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
10613                 (tng_trajectory_t tng_data,
10614                  const int64_t n)
10615 {
10616     tng_molecule_t mol;
10617     tng_chain_t chain;
10618     tng_residue_t res;
10619     tng_atom_t atom;
10620     tng_function_status stat;
10621     int64_t diff, n_mod, n_impl;
10622
10623     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
10624
10625     diff = n - tng_data->n_particles;
10626
10627     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
10628     if(stat == TNG_SUCCESS)
10629     {
10630         tng_molecule_cnt_get(tng_data, mol, &n_impl);
10631         diff -= n_impl * mol->n_atoms;
10632     }
10633
10634     if(diff == 0)
10635     {
10636         if(stat == TNG_SUCCESS)
10637         {
10638             stat = tng_molecule_cnt_set(tng_data, mol, 0);
10639             return(stat);
10640         }
10641         return(TNG_SUCCESS);
10642     }
10643     else if(diff < 0)
10644     {
10645         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
10646         fprintf(stderr, "particle count.\n");
10647         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10648                 __FILE__, __LINE__);
10649         /* FIXME: Should we set the count of all other molecules to 0 and add
10650          * implicit molecules? */
10651         return(TNG_FAILURE);
10652     }
10653     if(stat != TNG_SUCCESS)
10654     {
10655         stat = tng_molecule_add(tng_data,
10656                                 "TNG_IMPLICIT_MOL",
10657                                 &mol);
10658         if(stat != TNG_SUCCESS)
10659         {
10660             return(stat);
10661         }
10662         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
10663         if(stat != TNG_SUCCESS)
10664         {
10665             return(stat);
10666         }
10667         stat = tng_chain_residue_add(tng_data, chain, "", &res);
10668         if(stat != TNG_SUCCESS)
10669         {
10670             return(stat);
10671         }
10672         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
10673         if(stat != TNG_SUCCESS)
10674         {
10675             return(stat);
10676         }
10677     }
10678     else
10679     {
10680         if(mol->n_atoms > 1)
10681         {
10682             n_mod = diff % mol->n_atoms;
10683             if(n_mod != 0)
10684             {
10685                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
10686                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
10687                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10688                         __FILE__, __LINE__);
10689                 return(TNG_FAILURE);
10690             }
10691             diff /= mol->n_atoms;
10692         }
10693     }
10694     stat = tng_molecule_cnt_set(tng_data, mol, diff);
10695
10696     return(stat);
10697 }
10698
10699 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
10700                 (const tng_trajectory_t tng_data,
10701                  int64_t *n)
10702 {
10703     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10704     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10705
10706     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
10707     {
10708         *n = tng_data->n_particles;
10709     }
10710     else
10711     {
10712         *n = tng_data->current_trajectory_frame_set.n_particles;
10713     }
10714
10715     return(TNG_SUCCESS);
10716 }
10717
10718 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
10719                 (const tng_trajectory_t tng_data,
10720                  char *variable)
10721 {
10722     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10723     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
10724
10725     *variable = tng_data->var_num_atoms_flag;
10726
10727     return(TNG_SUCCESS);
10728 }
10729
10730 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
10731                     (const tng_trajectory_t tng_data,
10732                      int64_t *n)
10733 {
10734     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10735     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10736
10737     *n = tng_data->n_molecules;
10738
10739     return(TNG_SUCCESS);
10740 }
10741
10742 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
10743                     (const tng_trajectory_t tng_data,
10744                      int64_t *n)
10745 {
10746     int64_t *cnt_list = 0, cnt = 0, i;
10747
10748     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10749     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10750
10751     tng_molecule_cnt_list_get(tng_data, &cnt_list);
10752
10753     if(!cnt_list)
10754     {
10755         return(TNG_FAILURE);
10756     }
10757
10758     for(i = tng_data->n_molecules; i --;)
10759     {
10760         cnt += cnt_list[i];
10761     }
10762
10763     *n = cnt;
10764
10765     return(TNG_SUCCESS);
10766 }
10767
10768 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
10769                 (const tng_trajectory_t tng_data,
10770                  int64_t **mol_cnt_list)
10771 {
10772     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10773
10774     if(tng_data->var_num_atoms_flag)
10775     {
10776         *mol_cnt_list = tng_data->current_trajectory_frame_set.
10777                        molecule_cnt_list;
10778     }
10779     else
10780     {
10781         *mol_cnt_list = tng_data->molecule_cnt_list;
10782     }
10783     if(*mol_cnt_list == 0)
10784     {
10785         return(TNG_FAILURE);
10786     }
10787     return(TNG_SUCCESS);
10788 }
10789
10790 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
10791                 (const tng_trajectory_t tng_data,
10792                  int64_t *exp)
10793 {
10794     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10795     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
10796
10797     *exp = tng_data->distance_unit_exponential;
10798
10799     return(TNG_SUCCESS);
10800 }
10801
10802 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
10803                 (const tng_trajectory_t tng_data,
10804                  const int64_t exp)
10805 {
10806     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10807
10808     tng_data->distance_unit_exponential = exp;
10809
10810     return(TNG_SUCCESS);
10811 }
10812
10813 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
10814                 (const tng_trajectory_t tng_data,
10815                  int64_t *n)
10816 {
10817     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10818     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10819
10820     *n = tng_data->frame_set_n_frames;
10821
10822     return(TNG_SUCCESS);
10823 }
10824
10825 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
10826                 (const tng_trajectory_t tng_data,
10827                  const int64_t n)
10828 {
10829     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10830
10831     tng_data->frame_set_n_frames = n;
10832
10833     return(TNG_SUCCESS);
10834 }
10835
10836 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
10837                 (const tng_trajectory_t tng_data,
10838                  int64_t *n)
10839 {
10840     int64_t long_stride_length, medium_stride_length;
10841     int64_t file_pos, orig_frame_set_file_pos;
10842     tng_trajectory_frame_set_t frame_set;
10843     struct tng_trajectory_frame_set   orig_frame_set;
10844     tng_gen_block_t block;
10845     tng_function_status stat;
10846     int64_t cnt = 0;
10847
10848     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10849     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10850
10851     orig_frame_set = tng_data->current_trajectory_frame_set;
10852
10853     frame_set = &tng_data->current_trajectory_frame_set;
10854
10855     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10856     file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
10857
10858     tng_block_init(&block);
10859     fseek(tng_data->input_file,
10860           (long)file_pos,
10861           SEEK_SET);
10862     tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
10863     /* Read block headers first to see what block is found. */
10864     stat = tng_block_header_read(tng_data, block);
10865     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10866     {
10867         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
10868                 __FILE__, __LINE__);
10869         tng_block_destroy(&block);
10870         return(TNG_CRITICAL);
10871     }
10872
10873     if(tng_block_read_next(tng_data, block,
10874                         TNG_SKIP_HASH) != TNG_SUCCESS)
10875     {
10876         tng_block_destroy(&block);
10877         return(TNG_CRITICAL);
10878     }
10879
10880     ++cnt;
10881
10882     long_stride_length = tng_data->long_stride_length;
10883     medium_stride_length = tng_data->medium_stride_length;
10884
10885     /* Take long steps forward until a long step forward would be too long or
10886      * the last frame set is found */
10887     file_pos = frame_set->long_stride_next_frame_set_file_pos;
10888     while(file_pos > 0)
10889     {
10890         if(file_pos > 0)
10891         {
10892             cnt += long_stride_length;
10893             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
10894             /* Read block headers first to see what block is found. */
10895             stat = tng_block_header_read(tng_data, block);
10896             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10897             {
10898                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10899                        file_pos, __FILE__, __LINE__);
10900                 tng_block_destroy(&block);
10901                 return(TNG_CRITICAL);
10902             }
10903
10904             if(tng_block_read_next(tng_data, block,
10905                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10906             {
10907                 tng_block_destroy(&block);
10908                 return(TNG_CRITICAL);
10909             }
10910         }
10911         file_pos = frame_set->long_stride_next_frame_set_file_pos;
10912     }
10913
10914     /* Take medium steps forward until a medium step forward would be too long
10915      * or the last frame set is found */
10916     file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10917     while(file_pos > 0)
10918     {
10919         if(file_pos > 0)
10920         {
10921             cnt += medium_stride_length;
10922             fseek(tng_data->input_file,
10923                   (long)file_pos,
10924                   SEEK_SET);
10925             /* Read block headers first to see what block is found. */
10926             stat = tng_block_header_read(tng_data, block);
10927             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10928             {
10929                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10930                        file_pos, __FILE__, __LINE__);
10931                 tng_block_destroy(&block);
10932                 return(TNG_CRITICAL);
10933             }
10934
10935             if(tng_block_read_next(tng_data, block,
10936                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10937             {
10938                 tng_block_destroy(&block);
10939                 return(TNG_CRITICAL);
10940             }
10941         }
10942         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10943     }
10944
10945     /* Take one step forward until the last frame set is found */
10946     file_pos = frame_set->next_frame_set_file_pos;
10947     while(file_pos > 0)
10948     {
10949         if(file_pos > 0)
10950         {
10951             ++cnt;
10952             fseek(tng_data->input_file,
10953                   (long)file_pos,
10954                   SEEK_SET);
10955             /* Read block headers first to see what block is found. */
10956             stat = tng_block_header_read(tng_data, block);
10957             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10958             {
10959                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
10960                        file_pos, __FILE__, __LINE__);
10961                 tng_block_destroy(&block);
10962                 return(TNG_CRITICAL);
10963             }
10964
10965             if(tng_block_read_next(tng_data, block,
10966                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10967             {
10968                 tng_block_destroy(&block);
10969                 return(TNG_CRITICAL);
10970             }
10971         }
10972         file_pos = frame_set->next_frame_set_file_pos;
10973     }
10974
10975     tng_block_destroy(&block);
10976
10977     *n = tng_data->n_trajectory_frame_sets = cnt;
10978
10979     *frame_set = orig_frame_set;
10980
10981     fseek(tng_data->input_file,
10982           (long)tng_data->first_trajectory_frame_set_input_file_pos,
10983           SEEK_SET);
10984
10985     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
10986
10987     return(TNG_SUCCESS);
10988 }
10989
10990 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
10991                 (tng_trajectory_t tng_data,
10992                  tng_trajectory_frame_set_t *frame_set_p)
10993 {
10994     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10995
10996     *frame_set_p = &tng_data->current_trajectory_frame_set;
10997
10998     return(TNG_SUCCESS);
10999 }
11000
11001 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11002                 (tng_trajectory_t tng_data,
11003                  const int64_t nr)
11004 {
11005     int64_t long_stride_length, medium_stride_length;
11006     int64_t file_pos, curr_nr = 0, n_frame_sets;
11007     tng_trajectory_frame_set_t frame_set;
11008     tng_gen_block_t block;
11009     tng_function_status stat;
11010
11011     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11012     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11013
11014     frame_set = &tng_data->current_trajectory_frame_set;
11015
11016     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11017
11018     if(stat != TNG_SUCCESS)
11019     {
11020         return(stat);
11021     }
11022
11023     if(nr >= n_frame_sets)
11024     {
11025         return(TNG_FAILURE);
11026     }
11027
11028     long_stride_length = tng_data->long_stride_length;
11029     medium_stride_length = tng_data->medium_stride_length;
11030
11031     /* FIXME: The frame set number of the current frame set is not stored */
11032
11033     if(nr < n_frame_sets - 1 - nr)
11034     {
11035         /* Start from the beginning */
11036         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11037     }
11038     else
11039     {
11040         /* Start from the end */
11041         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11042         curr_nr = n_frame_sets - 1;
11043     }
11044     if(file_pos <= 0)
11045     {
11046         return(TNG_FAILURE);
11047     }
11048
11049     tng_block_init(&block);
11050     fseek(tng_data->input_file,
11051           (long)file_pos,
11052           SEEK_SET);
11053     tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11054     /* Read block headers first to see what block is found. */
11055     stat = tng_block_header_read(tng_data, block);
11056     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11057     {
11058         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11059                 __FILE__, __LINE__);
11060         tng_block_destroy(&block);
11061         return(TNG_CRITICAL);
11062     }
11063
11064     if(tng_block_read_next(tng_data, block,
11065                         TNG_SKIP_HASH) != TNG_SUCCESS)
11066     {
11067         tng_block_destroy(&block);
11068         return(TNG_CRITICAL);
11069     }
11070
11071     if(curr_nr == nr)
11072     {
11073         tng_block_destroy(&block);
11074         return(TNG_SUCCESS);
11075     }
11076
11077     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11078
11079     /* Take long steps forward until a long step forward would be too long or
11080      * the right frame set is found */
11081     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11082     {
11083         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11084         if(file_pos > 0)
11085         {
11086             curr_nr += long_stride_length;
11087             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11088             /* Read block headers first to see what block is found. */
11089             stat = tng_block_header_read(tng_data, block);
11090             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11091             {
11092                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11093                        file_pos,  __FILE__, __LINE__);
11094                 tng_block_destroy(&block);
11095                 return(TNG_CRITICAL);
11096             }
11097
11098             if(tng_block_read_next(tng_data, block,
11099                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11100             {
11101                 tng_block_destroy(&block);
11102                 return(TNG_CRITICAL);
11103             }
11104             if(curr_nr == nr)
11105             {
11106                 tng_block_destroy(&block);
11107                 return(TNG_SUCCESS);
11108             }
11109         }
11110     }
11111
11112     /* Take medium steps forward until a medium step forward would be too long
11113      * or the right frame set is found */
11114     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11115     {
11116         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11117         if(file_pos > 0)
11118         {
11119             curr_nr += medium_stride_length;
11120             fseek(tng_data->input_file,
11121                   (long)file_pos,
11122                   SEEK_SET);
11123             /* Read block headers first to see what block is found. */
11124             stat = tng_block_header_read(tng_data, block);
11125             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11126             {
11127                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11128                        file_pos, __FILE__, __LINE__);
11129                 tng_block_destroy(&block);
11130                 return(TNG_CRITICAL);
11131             }
11132
11133             if(tng_block_read_next(tng_data, block,
11134                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11135             {
11136                 tng_block_destroy(&block);
11137                 return(TNG_CRITICAL);
11138             }
11139             if(curr_nr == nr)
11140             {
11141                 tng_block_destroy(&block);
11142                 return(TNG_SUCCESS);
11143             }
11144         }
11145     }
11146
11147     /* Take one step forward until the right frame set is found */
11148     while(file_pos > 0 && curr_nr < nr)
11149     {
11150         file_pos = frame_set->next_frame_set_file_pos;
11151
11152         if(file_pos > 0)
11153         {
11154             ++curr_nr;
11155             fseek(tng_data->input_file,
11156                   (long)file_pos,
11157                   SEEK_SET);
11158             /* Read block headers first to see what block is found. */
11159             stat = tng_block_header_read(tng_data, block);
11160             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11161             {
11162                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11163                        file_pos, __FILE__, __LINE__);
11164                 tng_block_destroy(&block);
11165                 return(TNG_CRITICAL);
11166             }
11167
11168             if(tng_block_read_next(tng_data, block,
11169                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11170             {
11171                 tng_block_destroy(&block);
11172                 return(TNG_CRITICAL);
11173             }
11174             if(curr_nr == nr)
11175             {
11176                 tng_block_destroy(&block);
11177                 return(TNG_SUCCESS);
11178             }
11179         }
11180     }
11181
11182     /* Take long steps backward until a long step backward would be too long
11183      * or the right frame set is found */
11184     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11185     {
11186         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11187         if(file_pos > 0)
11188         {
11189             curr_nr -= long_stride_length;
11190             fseek(tng_data->input_file,
11191                   (long)file_pos,
11192                   SEEK_SET);
11193             /* Read block headers first to see what block is found. */
11194             stat = tng_block_header_read(tng_data, block);
11195             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11196             {
11197                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11198                        file_pos, __FILE__, __LINE__);
11199                 tng_block_destroy(&block);
11200                 return(TNG_CRITICAL);
11201             }
11202
11203             if(tng_block_read_next(tng_data, block,
11204                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11205             {
11206                 tng_block_destroy(&block);
11207                 return(TNG_CRITICAL);
11208             }
11209             if(curr_nr == nr)
11210             {
11211                 tng_block_destroy(&block);
11212                 return(TNG_SUCCESS);
11213             }
11214         }
11215     }
11216
11217     /* Take medium steps backward until a medium step backward would be too long
11218      * or the right frame set is found */
11219     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11220     {
11221         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11222         if(file_pos > 0)
11223         {
11224             curr_nr -= medium_stride_length;
11225             fseek(tng_data->input_file,
11226                   (long)file_pos,
11227                   SEEK_SET);
11228             /* Read block headers first to see what block is found. */
11229             stat = tng_block_header_read(tng_data, block);
11230             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11231             {
11232                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11233                        file_pos, __FILE__, __LINE__);
11234                 tng_block_destroy(&block);
11235                 return(TNG_CRITICAL);
11236             }
11237
11238             if(tng_block_read_next(tng_data, block,
11239                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11240             {
11241                 tng_block_destroy(&block);
11242                 return(TNG_CRITICAL);
11243             }
11244             if(curr_nr == nr)
11245             {
11246                 tng_block_destroy(&block);
11247                 return(TNG_SUCCESS);
11248             }
11249         }
11250     }
11251
11252     /* Take one step backward until the right frame set is found */
11253     while(file_pos > 0 && curr_nr > nr)
11254     {
11255         file_pos = frame_set->prev_frame_set_file_pos;
11256         if(file_pos > 0)
11257         {
11258             --curr_nr;
11259             fseek(tng_data->input_file,
11260                   (long)file_pos,
11261                   SEEK_SET);
11262             /* Read block headers first to see what block is found. */
11263             stat = tng_block_header_read(tng_data, block);
11264             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11265             {
11266                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11267                        file_pos, __FILE__, __LINE__);
11268                 tng_block_destroy(&block);
11269                 return(TNG_CRITICAL);
11270             }
11271
11272             if(tng_block_read_next(tng_data, block,
11273                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11274             {
11275                 tng_block_destroy(&block);
11276                 return(TNG_CRITICAL);
11277             }
11278             if(curr_nr == nr)
11279             {
11280                 tng_block_destroy(&block);
11281                 return(TNG_SUCCESS);
11282             }
11283         }
11284     }
11285
11286     /* If for some reason the current frame set is not yet found,
11287      * take one step forward until the right frame set is found */
11288     while(file_pos > 0 && curr_nr < nr)
11289     {
11290         file_pos = frame_set->next_frame_set_file_pos;
11291         if(file_pos > 0)
11292         {
11293             ++curr_nr;
11294             fseek(tng_data->input_file,
11295                   (long)file_pos,
11296                   SEEK_SET);
11297             /* Read block headers first to see what block is found. */
11298             stat = tng_block_header_read(tng_data, block);
11299             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11300             {
11301                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11302                        file_pos, __FILE__, __LINE__);
11303                 tng_block_destroy(&block);
11304                 return(TNG_CRITICAL);
11305             }
11306
11307             if(tng_block_read_next(tng_data, block,
11308                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11309             {
11310                 tng_block_destroy(&block);
11311                 return(TNG_CRITICAL);
11312             }
11313             if(curr_nr == nr)
11314             {
11315                 tng_block_destroy(&block);
11316                 return(TNG_SUCCESS);
11317             }
11318         }
11319     }
11320
11321     tng_block_destroy(&block);
11322     return(TNG_FAILURE);
11323 }
11324
11325 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
11326                 (tng_trajectory_t tng_data,
11327                  const int64_t frame)
11328 {
11329     int64_t first_frame, last_frame, n_frames_per_frame_set;
11330     int64_t long_stride_length, medium_stride_length;
11331     int64_t file_pos, temp_frame, n_frames;
11332     tng_trajectory_frame_set_t frame_set;
11333     tng_gen_block_t block;
11334     tng_function_status stat;
11335
11336     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11337     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
11338
11339     frame_set = &tng_data->current_trajectory_frame_set;
11340
11341     tng_block_init(&block);
11342
11343     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
11344     {
11345         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11346         fseek(tng_data->input_file,
11347                 (long)file_pos,
11348                 SEEK_SET);
11349         tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11350         /* Read block headers first to see what block is found. */
11351         stat = tng_block_header_read(tng_data, block);
11352         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11353         {
11354             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11355                     file_pos, __FILE__, __LINE__);
11356             tng_block_destroy(&block);
11357             return(TNG_CRITICAL);
11358         }
11359
11360         if(tng_block_read_next(tng_data, block,
11361                             TNG_SKIP_HASH) != TNG_SUCCESS)
11362         {
11363             tng_block_destroy(&block);
11364             return(TNG_CRITICAL);
11365         }
11366     }
11367
11368     first_frame = tng_max_i64(frame_set->first_frame, 0);
11369     last_frame = first_frame + frame_set->n_frames - 1;
11370     /* Is this the right frame set? */
11371     if(first_frame <= frame && frame <= last_frame)
11372     {
11373         tng_block_destroy(&block);
11374         return(TNG_SUCCESS);
11375     }
11376
11377     n_frames_per_frame_set = tng_data->frame_set_n_frames;
11378     long_stride_length = tng_data->long_stride_length;
11379     medium_stride_length = tng_data->medium_stride_length;
11380
11381     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
11382        TNG_SUCCESS)
11383     {
11384         if(temp_frame - first_frame > n_frames_per_frame_set)
11385         {
11386             n_frames_per_frame_set = temp_frame - first_frame;
11387         }
11388     }
11389
11390     tng_num_frames_get(tng_data, &n_frames);
11391
11392     if(frame >= n_frames)
11393     {
11394         tng_block_destroy(&block);
11395         return(TNG_FAILURE);
11396     }
11397
11398     if(first_frame - frame >= frame ||
11399        frame - last_frame >
11400        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
11401     {
11402         /* Start from the beginning */
11403         if(first_frame - frame >= frame)
11404         {
11405             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11406
11407             if(file_pos <= 0)
11408             {
11409                 tng_block_destroy(&block);
11410                 return(TNG_FAILURE);
11411             }
11412         }
11413         /* Start from the end */
11414         else if(frame - first_frame > (n_frames - 1) - frame)
11415         {
11416             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11417
11418             /* If the last frame set position is not set start from the current
11419              * frame set, since it will be closer than the first frame set. */
11420         }
11421         /* Start from current */
11422         else
11423         {
11424             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11425         }
11426
11427         if(file_pos > 0)
11428         {
11429             fseek(tng_data->input_file,
11430                   (long)file_pos,
11431                   SEEK_SET);
11432             tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11433             /* Read block headers first to see what block is found. */
11434             stat = tng_block_header_read(tng_data, block);
11435             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11436             {
11437                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11438                        file_pos, __FILE__, __LINE__);
11439                 tng_block_destroy(&block);
11440                 return(TNG_CRITICAL);
11441             }
11442
11443             if(tng_block_read_next(tng_data, block,
11444                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11445             {
11446                 tng_block_destroy(&block);
11447                 return(TNG_CRITICAL);
11448             }
11449         }
11450     }
11451
11452     first_frame = tng_max_i64(frame_set->first_frame, 0);
11453     last_frame = first_frame + frame_set->n_frames - 1;
11454
11455     if(frame >= first_frame && frame <= last_frame)
11456     {
11457         tng_block_destroy(&block);
11458         return(TNG_SUCCESS);
11459     }
11460
11461     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11462
11463     /* Take long steps forward until a long step forward would be too long or
11464      * the right frame set is found */
11465     while(file_pos > 0 && first_frame + long_stride_length *
11466           n_frames_per_frame_set <= frame)
11467     {
11468         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11469         if(file_pos > 0)
11470         {
11471             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11472             /* Read block headers first to see what block is found. */
11473             stat = tng_block_header_read(tng_data, block);
11474             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11475             {
11476                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11477                        file_pos, __FILE__, __LINE__);
11478                 tng_block_destroy(&block);
11479                 return(TNG_CRITICAL);
11480             }
11481
11482             if(tng_block_read_next(tng_data, block,
11483                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11484             {
11485                 tng_block_destroy(&block);
11486                 return(TNG_CRITICAL);
11487             }
11488         }
11489         first_frame = tng_max_i64(frame_set->first_frame, 0);
11490         last_frame = first_frame + frame_set->n_frames - 1;
11491         if(frame >= first_frame && frame <= last_frame)
11492         {
11493             tng_block_destroy(&block);
11494             return(TNG_SUCCESS);
11495         }
11496     }
11497
11498     /* Take medium steps forward until a medium step forward would be too long
11499      * or the right frame set is found */
11500     while(file_pos > 0 && first_frame + medium_stride_length *
11501           n_frames_per_frame_set <= frame)
11502     {
11503         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11504         if(file_pos > 0)
11505         {
11506             fseek(tng_data->input_file,
11507                   (long)file_pos,
11508                   SEEK_SET);
11509             /* Read block headers first to see what block is found. */
11510             stat = tng_block_header_read(tng_data, block);
11511             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11512             {
11513                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11514                        file_pos, __FILE__, __LINE__);
11515                 tng_block_destroy(&block);
11516                 return(TNG_CRITICAL);
11517             }
11518
11519             if(tng_block_read_next(tng_data, block,
11520                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11521             {
11522                 tng_block_destroy(&block);
11523                 return(TNG_CRITICAL);
11524             }
11525         }
11526         first_frame = tng_max_i64(frame_set->first_frame, 0);
11527         last_frame = first_frame + frame_set->n_frames - 1;
11528         if(frame >= first_frame && frame <= last_frame)
11529         {
11530             tng_block_destroy(&block);
11531             return(TNG_SUCCESS);
11532         }
11533     }
11534
11535     /* Take one step forward until the right frame set is found */
11536     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11537     {
11538         file_pos = frame_set->next_frame_set_file_pos;
11539         if(file_pos > 0)
11540         {
11541             fseek(tng_data->input_file,
11542                   (long)file_pos,
11543                   SEEK_SET);
11544             /* Read block headers first to see what block is found. */
11545             stat = tng_block_header_read(tng_data, block);
11546             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11547             {
11548                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11549                        file_pos, __FILE__, __LINE__);
11550                 tng_block_destroy(&block);
11551                 return(TNG_CRITICAL);
11552             }
11553
11554             if(tng_block_read_next(tng_data, block,
11555                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11556             {
11557                 tng_block_destroy(&block);
11558                 return(TNG_CRITICAL);
11559             }
11560         }
11561         first_frame = tng_max_i64(frame_set->first_frame, 0);
11562         last_frame = first_frame + frame_set->n_frames - 1;
11563         if(frame >= first_frame && frame <= last_frame)
11564         {
11565             tng_block_destroy(&block);
11566             return(TNG_SUCCESS);
11567         }
11568     }
11569
11570     /* Take long steps backward until a long step backward would be too long
11571      * or the right frame set is found */
11572     while(file_pos > 0 && first_frame - long_stride_length *
11573           n_frames_per_frame_set >= frame)
11574     {
11575         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11576         if(file_pos > 0)
11577         {
11578             fseek(tng_data->input_file,
11579                   (long)file_pos,
11580                   SEEK_SET);
11581             /* Read block headers first to see what block is found. */
11582             stat = tng_block_header_read(tng_data, block);
11583             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11584             {
11585                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11586                        file_pos, __FILE__, __LINE__);
11587                 tng_block_destroy(&block);
11588                 return(TNG_CRITICAL);
11589             }
11590
11591             if(tng_block_read_next(tng_data, block,
11592                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11593             {
11594                 tng_block_destroy(&block);
11595                 return(TNG_CRITICAL);
11596             }
11597         }
11598         first_frame = tng_max_i64(frame_set->first_frame, 0);
11599         last_frame = first_frame + frame_set->n_frames - 1;
11600         if(frame >= first_frame && frame <= last_frame)
11601         {
11602             tng_block_destroy(&block);
11603             return(TNG_SUCCESS);
11604         }
11605     }
11606
11607     /* Take medium steps backward until a medium step backward would be too long
11608      * or the right frame set is found */
11609     while(file_pos > 0 && first_frame - medium_stride_length *
11610           n_frames_per_frame_set >= frame)
11611     {
11612         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11613         if(file_pos > 0)
11614         {
11615             fseek(tng_data->input_file,
11616                   (long)file_pos,
11617                   SEEK_SET);
11618             /* Read block headers first to see what block is found. */
11619             stat = tng_block_header_read(tng_data, block);
11620             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11621             {
11622                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11623                        file_pos, __FILE__, __LINE__);
11624                 tng_block_destroy(&block);
11625                 return(TNG_CRITICAL);
11626             }
11627
11628             if(tng_block_read_next(tng_data, block,
11629                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11630             {
11631                 tng_block_destroy(&block);
11632                 return(TNG_CRITICAL);
11633             }
11634         }
11635         first_frame = tng_max_i64(frame_set->first_frame, 0);
11636         last_frame = first_frame + frame_set->n_frames - 1;
11637         if(frame >= first_frame && frame <= last_frame)
11638         {
11639             tng_block_destroy(&block);
11640             return(TNG_SUCCESS);
11641         }
11642     }
11643
11644     /* Take one step backward until the right frame set is found */
11645     while(file_pos > 0 && first_frame > frame && last_frame > frame)
11646     {
11647         file_pos = frame_set->prev_frame_set_file_pos;
11648         if(file_pos > 0)
11649         {
11650             fseek(tng_data->input_file,
11651                   (long)file_pos,
11652                   SEEK_SET);
11653             /* Read block headers first to see what block is found. */
11654             stat = tng_block_header_read(tng_data, block);
11655             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11656             {
11657                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11658                        file_pos, __FILE__, __LINE__);
11659                 tng_block_destroy(&block);
11660                 return(TNG_CRITICAL);
11661             }
11662
11663             if(tng_block_read_next(tng_data, block,
11664                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11665             {
11666                 tng_block_destroy(&block);
11667                 return(TNG_CRITICAL);
11668             }
11669         }
11670         first_frame = tng_max_i64(frame_set->first_frame, 0);
11671         last_frame = first_frame + frame_set->n_frames - 1;
11672         if(frame >= first_frame && frame <= last_frame)
11673         {
11674             tng_block_destroy(&block);
11675             return(TNG_SUCCESS);
11676         }
11677     }
11678
11679     /* If for some reason the current frame set is not yet found,
11680      * take one step forward until the right frame set is found */
11681     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11682     {
11683         file_pos = frame_set->next_frame_set_file_pos;
11684         if(file_pos > 0)
11685         {
11686             fseek(tng_data->input_file,
11687                   (long)file_pos,
11688                   SEEK_SET);
11689             /* Read block headers first to see what block is found. */
11690             stat = tng_block_header_read(tng_data, block);
11691             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11692             {
11693                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11694                        file_pos, __FILE__, __LINE__);
11695                 tng_block_destroy(&block);
11696                 return(TNG_CRITICAL);
11697             }
11698
11699             if(tng_block_read_next(tng_data, block,
11700                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11701             {
11702                 tng_block_destroy(&block);
11703                 return(TNG_CRITICAL);
11704             }
11705         }
11706         first_frame = tng_max_i64(frame_set->first_frame, 0);
11707         last_frame = first_frame + frame_set->n_frames - 1;
11708         if(frame >= first_frame && frame <= last_frame)
11709         {
11710             tng_block_destroy(&block);
11711             return(TNG_SUCCESS);
11712         }
11713     }
11714
11715     tng_block_destroy(&block);
11716     return(TNG_FAILURE);
11717 }
11718
11719 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
11720                 (const tng_trajectory_t tng_data,
11721                  const tng_trajectory_frame_set_t frame_set,
11722                  int64_t *pos)
11723 {
11724     (void)tng_data;
11725
11726     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11727     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11728
11729     *pos = frame_set->next_frame_set_file_pos;
11730
11731     return(TNG_SUCCESS);
11732 }
11733
11734 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
11735                 (const tng_trajectory_t tng_data,
11736                  const tng_trajectory_frame_set_t frame_set,
11737                  int64_t *pos)
11738 {
11739     (void)tng_data;
11740
11741     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11742     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11743
11744     *pos = frame_set->prev_frame_set_file_pos;
11745
11746     return(TNG_SUCCESS);
11747 }
11748
11749 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
11750                 (const tng_trajectory_t tng_data,
11751                  const tng_trajectory_frame_set_t frame_set,
11752                  int64_t *first_frame,
11753                  int64_t *last_frame)
11754 {
11755     (void)tng_data;
11756
11757     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
11758     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
11759     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
11760
11761     *first_frame = frame_set->first_frame;
11762     *last_frame = *first_frame + frame_set->n_frames - 1;
11763
11764     return(TNG_SUCCESS);
11765 }
11766
11767 /** Translate from the particle numbering used in a frame set to the real
11768  *  particle numbering - used in the molecule description.
11769  * @param frame_set is the frame_set containing the mappings to use.
11770  * @param local is the index number of the atom in this frame set
11771  * @param real is set to the index of the atom in the molecular system.
11772  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11773  * cannot be found.
11774  */
11775 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
11776                 (const tng_trajectory_frame_set_t frame_set,
11777                  const int64_t local,
11778                  int64_t *real)
11779 {
11780     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
11781     tng_particle_mapping_t mapping;
11782     if(n_blocks <= 0)
11783     {
11784         *real = local;
11785         return(TNG_SUCCESS);
11786     }
11787     for(i = 0; i < n_blocks; i++)
11788     {
11789         mapping = &frame_set->mappings[i];
11790         first = mapping->num_first_particle;
11791         if(local < first ||
11792            local >= first + mapping->n_particles)
11793         {
11794             continue;
11795         }
11796         *real = mapping->real_particle_numbers[local-first];
11797         return(TNG_SUCCESS);
11798     }
11799     *real = local;
11800     return(TNG_FAILURE);
11801 }
11802
11803 /** Translate from the real particle numbering to the particle numbering
11804  *  used in a frame set.
11805  * @param frame_set is the frame_set containing the mappings to use.
11806  * @param real is the index number of the atom in the molecular system.
11807  * @param local is set to the index of the atom in this frame set.
11808  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11809  * cannot be found.
11810  */
11811 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
11812                 (const tng_trajectory_frame_set_t frame_set,
11813                  const int64_t real,
11814                  int64_t *local)
11815 {
11816     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
11817     tng_particle_mapping_t mapping;
11818     if(n_blocks <= 0)
11819     {
11820         *local = real;
11821         return(TNG_SUCCESS);
11822     }
11823     for(i = 0; i < n_blocks; i++)
11824     {
11825         mapping = &frame_set->mappings[i];
11826         for(j = mapping->n_particles; j--;)
11827         {
11828             if(mapping->real_particle_numbers[j] == real)
11829             {
11830                 *local = j;
11831                 return(TNG_SUCCESS);
11832             }
11833         }
11834     }
11835     return(TNG_FAILURE);
11836 }
11837 */
11838
11839 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
11840                 (tng_trajectory_t tng_data,
11841                  const char hash_mode)
11842 {
11843     int cnt = 0, prev_pos = 0;
11844     tng_gen_block_t block;
11845
11846     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11847
11848     tng_data->n_trajectory_frame_sets = 0;
11849
11850     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11851     {
11852         return(TNG_CRITICAL);
11853     }
11854
11855     if(!tng_data->input_file_len)
11856     {
11857         fseek(tng_data->input_file, 0, SEEK_END);
11858         tng_data->input_file_len = ftell(tng_data->input_file);
11859         fseek(tng_data->input_file, 0, SEEK_SET);
11860     }
11861
11862     tng_block_init(&block);
11863     /* Non trajectory blocks (they come before the trajectory
11864      * blocks in the file) */
11865     while (prev_pos < tng_data->input_file_len &&
11866            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11867            block->id != -1 &&
11868            block->id != TNG_TRAJECTORY_FRAME_SET)
11869     {
11870         if(tng_block_read_next(tng_data, block,
11871                                hash_mode) == TNG_SUCCESS)
11872         {
11873             cnt++;
11874         }
11875         prev_pos = ftell(tng_data->input_file);
11876     }
11877
11878     /* Go back if a trajectory block was encountered */
11879     if(block->id == TNG_TRAJECTORY_FRAME_SET)
11880     {
11881         fseek(tng_data->input_file, prev_pos, SEEK_SET);
11882     }
11883
11884     tng_block_destroy(&block);
11885
11886     return(TNG_SUCCESS);
11887 }
11888
11889 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
11890                 (tng_trajectory_t tng_data,
11891                  const char hash_mode)
11892 {
11893     int i;
11894     tng_gen_block_t data_block;
11895
11896     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11897
11898     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
11899     {
11900         return(TNG_CRITICAL);
11901     }
11902
11903     /* TODO: If there is already frame set data written to this file (e.g. when
11904      * appending to an already existing file we might need to move frame sets to
11905      * the end of the file. */
11906
11907     if(tng_general_info_block_write(tng_data, hash_mode)
11908        != TNG_SUCCESS)
11909     {
11910         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
11911                 tng_data->input_file_path, __FILE__, __LINE__);
11912         return(TNG_CRITICAL);
11913     }
11914
11915     if(tng_molecules_block_write(tng_data, hash_mode)
11916         != TNG_SUCCESS)
11917     {
11918         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
11919                 tng_data->input_file_path, __FILE__, __LINE__);
11920         return(TNG_CRITICAL);
11921     }
11922
11923     /* FIXME: Currently writing non-trajectory data blocks here.
11924      * Should perhaps be moved. */
11925     tng_block_init(&data_block);
11926     for(i = 0; i < tng_data->n_data_blocks; i++)
11927     {
11928         data_block->id = tng_data->non_tr_data[i].block_id;
11929         tng_data_block_write(tng_data, data_block,
11930                              i, hash_mode);
11931     }
11932
11933     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11934     {
11935         data_block->id = tng_data->non_tr_particle_data[i].block_id;
11936         tng_particle_data_block_write(tng_data, data_block,
11937                                       i, 0, hash_mode);
11938     }
11939
11940     tng_block_destroy(&data_block);
11941
11942     return(TNG_SUCCESS);
11943 }
11944
11945 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
11946                                         tng_gen_block_t block,
11947                                         const char hash_mode)
11948 {
11949     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11950     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
11951
11952     switch(block->id)
11953     {
11954     case TNG_TRAJECTORY_FRAME_SET:
11955         return(tng_frame_set_block_read(tng_data, block, hash_mode));
11956     case TNG_PARTICLE_MAPPING:
11957         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
11958     case TNG_GENERAL_INFO:
11959         return(tng_general_info_block_read(tng_data, block, hash_mode));
11960     case TNG_MOLECULES:
11961         return(tng_molecules_block_read(tng_data, block, hash_mode));
11962     default:
11963         if(block->id >= TNG_TRAJ_BOX_SHAPE)
11964         {
11965             return(tng_data_block_contents_read(tng_data, block, hash_mode));
11966         }
11967         else
11968         {
11969             /* Skip to the next block */
11970             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
11971             return(TNG_FAILURE);
11972         }
11973     }
11974 }
11975
11976 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
11977                 (tng_trajectory_t tng_data,
11978                  const char hash_mode)
11979 {
11980     long file_pos;
11981     tng_gen_block_t block;
11982     tng_function_status stat;
11983
11984     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11985
11986     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11987     {
11988         return(TNG_CRITICAL);
11989     }
11990
11991     file_pos = ftell(tng_data->input_file);
11992
11993     tng_block_init(&block);
11994
11995     if(!tng_data->input_file_len)
11996     {
11997         fseek(tng_data->input_file, 0, SEEK_END);
11998         tng_data->input_file_len = ftell(tng_data->input_file);
11999         fseek(tng_data->input_file, file_pos, SEEK_SET);
12000     }
12001
12002     /* Read block headers first to see what block is found. */
12003     stat = tng_block_header_read(tng_data, block);
12004     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12005     {
12006         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12007                file_pos, __FILE__, __LINE__);
12008         tng_block_destroy(&block);
12009         return(TNG_CRITICAL);
12010     }
12011
12012     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12013
12014     if(tng_block_read_next(tng_data, block,
12015                            hash_mode) == TNG_SUCCESS)
12016     {
12017         tng_data->n_trajectory_frame_sets++;
12018         file_pos = ftell(tng_data->input_file);
12019         /* Read all blocks until next frame set block */
12020         stat = tng_block_header_read(tng_data, block);
12021         while(file_pos < tng_data->input_file_len &&
12022               stat != TNG_CRITICAL &&
12023               block->id != TNG_TRAJECTORY_FRAME_SET)
12024         {
12025             stat = tng_block_read_next(tng_data, block,
12026                                        hash_mode);
12027             if(stat != TNG_CRITICAL)
12028             {
12029                 file_pos = ftell(tng_data->input_file);
12030                 if(file_pos < tng_data->input_file_len)
12031                 {
12032                     stat = tng_block_header_read(tng_data, block);
12033                 }
12034             }
12035         }
12036         if(stat == TNG_CRITICAL)
12037         {
12038             fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12039                    file_pos, __FILE__, __LINE__);
12040             tng_block_destroy(&block);
12041             return(stat);
12042         }
12043
12044         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12045         {
12046             fseek(tng_data->input_file, file_pos, SEEK_SET);
12047         }
12048     }
12049
12050     tng_block_destroy(&block);
12051
12052     return(TNG_SUCCESS);
12053 }
12054
12055
12056 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12057                 (tng_trajectory_t tng_data,
12058                  const char hash_mode,
12059                  const int64_t block_id)
12060 {
12061     long file_pos;
12062     tng_gen_block_t block;
12063     tng_function_status stat;
12064     int found_flag = 1;
12065
12066     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12067
12068     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12069     {
12070         return(TNG_CRITICAL);
12071     }
12072
12073     file_pos = (long)tng_data->current_trajectory_frame_set_input_file_pos;
12074
12075     if(file_pos < 0)
12076     {
12077         /* No current frame set. This means that the first frame set must be
12078          * read */
12079         found_flag = 0;
12080         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12081     }
12082
12083     if(file_pos > 0)
12084     {
12085         fseek(tng_data->input_file,
12086               file_pos,
12087               SEEK_SET);
12088     }
12089     else
12090     {
12091         return(TNG_FAILURE);
12092     }
12093
12094     tng_block_init(&block);
12095
12096     if(!tng_data->input_file_len)
12097     {
12098         fseek(tng_data->input_file, 0, SEEK_END);
12099         tng_data->input_file_len = ftell(tng_data->input_file);
12100         fseek(tng_data->input_file, file_pos, SEEK_SET);
12101     }
12102
12103     /* Read block headers first to see what block is found. */
12104     stat = tng_block_header_read(tng_data, block);
12105     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12106     {
12107         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12108                file_pos, __FILE__, __LINE__);
12109         tng_block_destroy(&block);
12110         return(TNG_CRITICAL);
12111     }
12112     /* If the current frame set had already been read skip its block contents */
12113     if(found_flag)
12114     {
12115         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12116     }
12117     /* Otherwiese read the frame set block */
12118     else
12119     {
12120         stat = tng_block_read_next(tng_data, block,
12121                                    hash_mode);
12122         if(stat != TNG_SUCCESS)
12123         {
12124             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12125             tng_block_destroy(&block);
12126             return(stat);
12127         }
12128     }
12129     file_pos = ftell(tng_data->input_file);
12130
12131     found_flag = 0;
12132
12133     /* Read only blocks of the requested ID
12134         * until next frame set block */
12135     stat = tng_block_header_read(tng_data, block);
12136     while(file_pos < tng_data->input_file_len &&
12137             stat != TNG_CRITICAL &&
12138             block->id != TNG_TRAJECTORY_FRAME_SET)
12139     {
12140         if(block->id == block_id)
12141         {
12142             stat = tng_block_read_next(tng_data, block,
12143                                        hash_mode);
12144             if(stat != TNG_CRITICAL)
12145             {
12146                 file_pos = ftell(tng_data->input_file);
12147                 found_flag = 1;
12148                 if(file_pos < tng_data->input_file_len)
12149                 {
12150                     stat = tng_block_header_read(tng_data, block);
12151                 }
12152             }
12153         }
12154         else
12155         {
12156             file_pos += (long)(block->block_contents_size + block->header_contents_size);
12157             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12158             if(file_pos < tng_data->input_file_len)
12159             {
12160                 stat = tng_block_header_read(tng_data, block);
12161             }
12162         }
12163     }
12164     if(stat == TNG_CRITICAL)
12165     {
12166         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12167                 file_pos, __FILE__, __LINE__);
12168         tng_block_destroy(&block);
12169         return(stat);
12170     }
12171
12172     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12173     {
12174         fseek(tng_data->input_file, file_pos, SEEK_SET);
12175     }
12176
12177     tng_block_destroy(&block);
12178
12179     if(found_flag)
12180     {
12181         return(TNG_SUCCESS);
12182     }
12183     else
12184     {
12185         return(TNG_FAILURE);
12186     }
12187 }
12188
12189 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
12190                 (tng_trajectory_t tng_data,
12191                  const char hash_mode)
12192 {
12193     long file_pos;
12194
12195     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12196
12197     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12198     {
12199         return(TNG_CRITICAL);
12200     }
12201
12202     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12203
12204     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12205     {
12206         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12207     }
12208
12209     if(file_pos > 0)
12210     {
12211         fseek(tng_data->input_file,
12212               file_pos,
12213               SEEK_SET);
12214     }
12215     else
12216     {
12217         return(TNG_FAILURE);
12218     }
12219
12220     return(tng_frame_set_read(tng_data, hash_mode));
12221 }
12222
12223 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
12224                 (tng_trajectory_t tng_data,
12225                  const char hash_mode,
12226                  const int64_t block_id)
12227 {
12228     long file_pos;
12229     tng_gen_block_t block;
12230     tng_function_status stat;
12231
12232     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12233
12234     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12235     {
12236         return(TNG_CRITICAL);
12237     }
12238
12239     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12240
12241     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12242     {
12243         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12244     }
12245
12246     if(file_pos > 0)
12247     {
12248         fseek(tng_data->input_file,
12249               file_pos,
12250               SEEK_SET);
12251     }
12252     else
12253     {
12254         return(TNG_FAILURE);
12255     }
12256
12257     tng_block_init(&block);
12258
12259     if(!tng_data->input_file_len)
12260     {
12261         fseek(tng_data->input_file, 0, SEEK_END);
12262         tng_data->input_file_len = ftell(tng_data->input_file);
12263         fseek(tng_data->input_file, file_pos, SEEK_SET);
12264     }
12265
12266     /* Read block headers first to see what block is found. */
12267     stat = tng_block_header_read(tng_data, block);
12268     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12269     {
12270         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12271                file_pos, __FILE__, __LINE__);
12272         tng_block_destroy(&block);
12273         return(TNG_CRITICAL);
12274     }
12275
12276     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12277
12278     if(tng_block_read_next(tng_data, block,
12279                            hash_mode) == TNG_SUCCESS)
12280     {
12281         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
12282     }
12283
12284     tng_block_destroy(&block);
12285
12286     return(stat);
12287 }
12288
12289 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
12290                                         const char hash_mode)
12291 {
12292     int i, j;
12293     tng_gen_block_t block;
12294     tng_trajectory_frame_set_t frame_set;
12295     tng_function_status stat;
12296
12297     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12298
12299     frame_set = &tng_data->current_trajectory_frame_set;
12300
12301     if(frame_set->n_written_frames == frame_set->n_frames)
12302     {
12303         return(TNG_SUCCESS);
12304     }
12305
12306     tng_data->current_trajectory_frame_set_output_file_pos =
12307     ftell(tng_data->output_file);
12308     tng_data->last_trajectory_frame_set_output_file_pos =
12309     tng_data->current_trajectory_frame_set_output_file_pos;
12310
12311     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
12312     {
12313         return(TNG_FAILURE);
12314     }
12315
12316     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
12317     {
12318         tng_data->first_trajectory_frame_set_output_file_pos =
12319         tng_data->current_trajectory_frame_set_output_file_pos;
12320     }
12321
12322     tng_block_init(&block);
12323
12324     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
12325     {
12326         tng_block_destroy(&block);
12327         return(TNG_FAILURE);
12328     }
12329
12330     /* Write non-particle data blocks */
12331     for(i = 0; i<frame_set->n_data_blocks; i++)
12332     {
12333         block->id = frame_set->tr_data[i].block_id;
12334         tng_data_block_write(tng_data, block, i, hash_mode);
12335     }
12336     /* Write the mapping blocks and particle data blocks*/
12337     if(frame_set->n_mapping_blocks)
12338     {
12339         for(i = 0; i < frame_set->n_mapping_blocks; i++)
12340         {
12341             block->id = TNG_PARTICLE_MAPPING;
12342             if(frame_set->mappings[i].n_particles > 0)
12343             {
12344                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
12345                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
12346                 {
12347                     block->id = frame_set->tr_particle_data[j].block_id;
12348                     tng_particle_data_block_write(tng_data, block,
12349                                                   j, &frame_set->mappings[i],
12350                                                   hash_mode);
12351                 }
12352             }
12353         }
12354     }
12355     else
12356     {
12357         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
12358         {
12359             block->id = frame_set->tr_particle_data[i].block_id;
12360             tng_particle_data_block_write(tng_data, block,
12361                                           i, 0, hash_mode);
12362         }
12363     }
12364
12365
12366     /* Update pointers in the general info block */
12367     stat = tng_header_pointers_update(tng_data, hash_mode);
12368
12369     if(stat == TNG_SUCCESS)
12370     {
12371         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
12372     }
12373
12374     tng_block_destroy(&block);
12375
12376     frame_set->n_unwritten_frames = 0;
12377
12378     fflush(tng_data->output_file);
12379
12380     return(stat);
12381 }
12382
12383 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
12384                 (tng_trajectory_t tng_data,
12385                  const char hash_mode)
12386 {
12387     tng_trajectory_frame_set_t frame_set;
12388
12389     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12390
12391     frame_set = &tng_data->current_trajectory_frame_set;
12392
12393     if(frame_set->n_unwritten_frames == 0)
12394     {
12395         return(TNG_SUCCESS);
12396     }
12397     frame_set->n_frames = frame_set->n_unwritten_frames;
12398
12399     return(tng_frame_set_write(tng_data, hash_mode));
12400 }
12401
12402 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
12403                 (tng_trajectory_t tng_data,
12404                  const int64_t first_frame,
12405                  const int64_t n_frames)
12406 {
12407     tng_gen_block_t block;
12408     tng_trajectory_frame_set_t frame_set;
12409     FILE *temp = tng_data->input_file;
12410     int64_t curr_pos;
12411
12412     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12413     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12414     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12415
12416     frame_set = &tng_data->current_trajectory_frame_set;
12417
12418     curr_pos = ftell(tng_data->output_file);
12419
12420     if(curr_pos <= 10)
12421     {
12422         tng_file_headers_write(tng_data, TNG_USE_HASH);
12423     }
12424
12425     /* Set pointer to previous frame set to the one that was loaded
12426      * before.
12427      * FIXME: This is a bit risky. If they are not added in order
12428      * it will be wrong. */
12429     if(tng_data->n_trajectory_frame_sets)
12430     {
12431         frame_set->prev_frame_set_file_pos =
12432         tng_data->current_trajectory_frame_set_output_file_pos;
12433     }
12434
12435     tng_data->current_trajectory_frame_set_output_file_pos =
12436     ftell(tng_data->output_file);
12437
12438     tng_data->n_trajectory_frame_sets++;
12439
12440     /* Set the medium range pointers */
12441     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
12442     {
12443         frame_set->medium_stride_prev_frame_set_file_pos =
12444         tng_data->first_trajectory_frame_set_output_file_pos;
12445     }
12446     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12447     {
12448         /* FIXME: Currently only working if the previous frame set has its
12449          * medium stride pointer already set. This might need some fixing. */
12450         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
12451            frame_set->medium_stride_prev_frame_set_file_pos != 0)
12452         {
12453             tng_block_init(&block);
12454             tng_data->input_file = tng_data->output_file;
12455
12456             curr_pos = ftell(tng_data->output_file);
12457             fseek(tng_data->output_file,
12458                   (long)frame_set->medium_stride_prev_frame_set_file_pos,
12459                   SEEK_SET);
12460
12461             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12462             {
12463                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12464                     __FILE__, __LINE__);
12465                 tng_data->input_file = temp;
12466                 tng_block_destroy(&block);
12467                 return(TNG_CRITICAL);
12468             }
12469
12470             /* Read the next frame set from the previous frame set and one
12471              * medium stride step back */
12472             fseek(tng_data->output_file, (long)block->block_contents_size - 6 *
12473                 sizeof(int64_t), SEEK_CUR);
12474             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
12475                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
12476                1, tng_data->output_file) == 0)
12477             {
12478                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12479                 tng_data->input_file = temp;
12480                 tng_block_destroy(&block);
12481                 return(TNG_CRITICAL);
12482             }
12483
12484             if(tng_data->input_endianness_swap_func_64)
12485             {
12486                 if(tng_data->input_endianness_swap_func_64(tng_data,
12487                    &frame_set->medium_stride_prev_frame_set_file_pos)
12488                     != TNG_SUCCESS)
12489                 {
12490                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12491                             __FILE__, __LINE__);
12492                 }
12493             }
12494
12495             tng_block_destroy(&block);
12496
12497             /* Set the long range pointers */
12498             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
12499             {
12500                 frame_set->long_stride_prev_frame_set_file_pos =
12501                 tng_data->first_trajectory_frame_set_output_file_pos;
12502             }
12503             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12504             {
12505                 /* FIXME: Currently only working if the previous frame set has its
12506                 * long stride pointer already set. This might need some fixing. */
12507                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
12508                 frame_set->long_stride_prev_frame_set_file_pos != 0)
12509                 {
12510                     tng_block_init(&block);
12511                     tng_data->input_file = tng_data->output_file;
12512
12513                     fseek(tng_data->output_file,
12514                           (long)frame_set->long_stride_prev_frame_set_file_pos,
12515                           SEEK_SET);
12516
12517                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12518                     {
12519                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12520                             __FILE__, __LINE__);
12521                         tng_data->input_file = temp;
12522                         tng_block_destroy(&block);
12523                         return(TNG_CRITICAL);
12524                     }
12525
12526                     /* Read the next frame set from the previous frame set and one
12527                     * long stride step back */
12528                     fseek(tng_data->output_file, (long)block->block_contents_size - 6 *
12529                           sizeof(int64_t), SEEK_CUR);
12530
12531                     tng_block_destroy(&block);
12532
12533                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
12534                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
12535                     1, tng_data->output_file) == 0)
12536                     {
12537                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12538                         tng_data->input_file = temp;
12539                         return(TNG_CRITICAL);
12540                     }
12541
12542                     if(tng_data->input_endianness_swap_func_64)
12543                     {
12544                         if(tng_data->input_endianness_swap_func_64(tng_data,
12545                            &frame_set->long_stride_prev_frame_set_file_pos)
12546                             != TNG_SUCCESS)
12547                         {
12548                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12549                                     __FILE__, __LINE__);
12550                         }
12551                     }
12552
12553                 }
12554             }
12555
12556             tng_data->input_file = temp;
12557             fseek(tng_data->output_file, (long)curr_pos, SEEK_SET);
12558         }
12559     }
12560
12561     frame_set->first_frame = first_frame;
12562     frame_set->n_frames = n_frames;
12563     frame_set->n_written_frames = 0;
12564     frame_set->n_unwritten_frames = 0;
12565     frame_set->first_frame_time = -1;
12566
12567     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
12568        tng_data->first_trajectory_frame_set_output_file_pos == 0)
12569     {
12570         tng_data->first_trajectory_frame_set_output_file_pos =
12571         tng_data->current_trajectory_frame_set_output_file_pos;
12572     }
12573     /* FIXME: Should check the frame number instead of the file_pos,
12574      * in case frame sets are not in order */
12575     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
12576        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
12577        tng_data->last_trajectory_frame_set_output_file_pos <
12578        tng_data->current_trajectory_frame_set_output_file_pos)
12579     {
12580         tng_data->last_trajectory_frame_set_output_file_pos =
12581         tng_data->current_trajectory_frame_set_output_file_pos;
12582     }
12583
12584     return(TNG_SUCCESS);
12585 }
12586
12587 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
12588                 (tng_trajectory_t tng_data,
12589                  const int64_t first_frame,
12590                  const int64_t n_frames,
12591                  const double first_frame_time)
12592 {
12593     tng_function_status stat;
12594
12595     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12596     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12597     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12598     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12599
12600
12601     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
12602     if(stat != TNG_SUCCESS)
12603     {
12604         return(stat);
12605     }
12606     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
12607
12608     return(stat);
12609 }
12610
12611 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
12612                 (tng_trajectory_t tng_data,
12613                  const double first_frame_time)
12614 {
12615     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12616     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12617
12618     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
12619
12620     return(TNG_SUCCESS);
12621 }
12622
12623 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
12624                 (tng_trajectory_t tng_data,
12625                  int64_t *frame)
12626 {
12627     long file_pos, next_frame_set_file_pos;
12628     tng_gen_block_t block;
12629     tng_function_status stat;
12630
12631     tng_trajectory_frame_set_t frame_set;
12632
12633     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12634     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
12635     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
12636
12637     file_pos = ftell(tng_data->input_file);
12638
12639     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12640     {
12641         next_frame_set_file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12642     }
12643     else
12644     {
12645         frame_set = &tng_data->current_trajectory_frame_set;
12646         next_frame_set_file_pos = (long)frame_set->next_frame_set_file_pos;
12647     }
12648
12649     if(next_frame_set_file_pos <= 0)
12650     {
12651         return(TNG_FAILURE);
12652     }
12653
12654     fseek(tng_data->input_file, (long)next_frame_set_file_pos, SEEK_SET);
12655     /* Read block headers first to see that a frame set block is found. */
12656     tng_block_init(&block);
12657     stat = tng_block_header_read(tng_data, block);
12658     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12659     {
12660         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12661                file_pos, __FILE__, __LINE__);
12662         return(TNG_CRITICAL);
12663     }
12664 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12665     {
12666         tng_block_read_next(tng_data, block, TNG_USE_HASH);
12667     }*/
12668     tng_block_destroy(&block);
12669
12670     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
12671     {
12672         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
12673                __FILE__, __LINE__);
12674         return(TNG_CRITICAL);
12675     }
12676     fseek(tng_data->input_file, file_pos, SEEK_SET);
12677
12678     return(TNG_SUCCESS);
12679 }
12680
12681 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
12682                 (tng_trajectory_t tng_data,
12683                  const int64_t id,
12684                  const char *block_name,
12685                  const char datatype,
12686                  const char block_type_flag,
12687                  int64_t n_frames,
12688                  const int64_t n_values_per_frame,
12689                  int64_t stride_length,
12690                  const int64_t codec_id,
12691                  void *new_data)
12692 {
12693     int i, j, size, len;
12694     tng_trajectory_frame_set_t frame_set;
12695     tng_non_particle_data_t data;
12696     char **first_dim_values;
12697     char *new_data_c=new_data;
12698     int64_t n_frames_div;
12699
12700     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12701     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
12702     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12703
12704     frame_set = &tng_data->current_trajectory_frame_set;
12705
12706     if(stride_length <= 0)
12707     {
12708         stride_length = 1;
12709     }
12710
12711     /* If the block does not exist, create it */
12712     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
12713     {
12714         if(tng_data_block_create(tng_data, block_type_flag) !=
12715             TNG_SUCCESS)
12716         {
12717             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
12718                    __FILE__, __LINE__);
12719             return(TNG_CRITICAL);
12720         }
12721         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12722         {
12723             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
12724         }
12725         else
12726         {
12727             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
12728         }
12729         data->block_id = id;
12730
12731         data->block_name = malloc(strlen(block_name) + 1);
12732         if(!data->block_name)
12733         {
12734             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12735                    (int)strlen(block_name)+1, __FILE__, __LINE__);
12736             return(TNG_CRITICAL);
12737         }
12738         strncpy(data->block_name, block_name, strlen(block_name) + 1);
12739
12740         data->values = 0;
12741         /* FIXME: Memory leak from strings. */
12742         data->strings = 0;
12743         data->last_retrieved_frame = -1;
12744     }
12745
12746     data->datatype = datatype;
12747     data->stride_length = tng_max_i64(stride_length, 1);
12748     data->n_values_per_frame = n_values_per_frame;
12749     data->n_frames = n_frames;
12750     data->codec_id = codec_id;
12751     data->compression_multiplier = 1.0;
12752     /* FIXME: This can cause problems. */
12753     data->first_frame_with_data = frame_set->first_frame;
12754
12755     switch(datatype)
12756     {
12757     case TNG_FLOAT_DATA:
12758         size = sizeof(float);
12759         break;
12760     case TNG_INT_DATA:
12761         size = sizeof(int64_t);
12762         break;
12763     case TNG_DOUBLE_DATA:
12764     default:
12765         size = sizeof(double);
12766         break;
12767     }
12768
12769     if(new_data_c)
12770     {
12771         /* Allocate memory */
12772         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
12773                                  n_values_per_frame) !=
12774         TNG_SUCCESS)
12775         {
12776             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
12777                 __FILE__, __LINE__);
12778             return(TNG_CRITICAL);
12779         }
12780
12781         if(n_frames > frame_set->n_unwritten_frames)
12782         {
12783             frame_set->n_unwritten_frames = n_frames;
12784         }
12785
12786         n_frames_div = (n_frames % stride_length) ?
12787                      n_frames / stride_length + 1:
12788                      n_frames / stride_length;
12789
12790         if(datatype == TNG_CHAR_DATA)
12791         {
12792             for(i = 0; i < n_frames_div; i++)
12793             {
12794                 first_dim_values = data->strings[i];
12795                 for(j = 0; j < n_values_per_frame; j++)
12796                 {
12797                     len = tng_min_i((int)strlen(new_data_c) + 1,
12798                                 TNG_MAX_STR_LEN);
12799                     if(first_dim_values[j])
12800                     {
12801                         free(first_dim_values[j]);
12802                     }
12803                     first_dim_values[j] = malloc(len);
12804                     if(!first_dim_values[j])
12805                     {
12806                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12807                             len, __FILE__, __LINE__);
12808                         return(TNG_CRITICAL);
12809                     }
12810                     strncpy(first_dim_values[j],
12811                             new_data_c, len);
12812                     new_data_c += len;
12813                 }
12814             }
12815         }
12816         else
12817         {
12818             memcpy(data->values, new_data, size * n_frames_div *
12819                    n_values_per_frame);
12820         }
12821     }
12822
12823     return(TNG_SUCCESS);
12824 }
12825
12826 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
12827                 (tng_trajectory_t tng_data,
12828                  const int64_t id,
12829                  const char *block_name,
12830                  const char datatype,
12831                  const char block_type_flag,
12832                  int64_t n_frames,
12833                  const int64_t n_values_per_frame,
12834                  int64_t stride_length,
12835                  const int64_t num_first_particle,
12836                  const int64_t n_particles,
12837                  const int64_t codec_id,
12838                  void *new_data)
12839 {
12840     int i, size, len;
12841     int64_t j, k;
12842     int64_t tot_n_particles, n_frames_div;
12843     char ***first_dim_values, **second_dim_values;
12844     tng_trajectory_frame_set_t frame_set;
12845     tng_particle_data_t data;
12846     char *new_data_c=new_data;
12847
12848     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12849     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
12850     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12851     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
12852     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
12853
12854
12855     frame_set = &tng_data->current_trajectory_frame_set;
12856
12857     if(stride_length <= 0)
12858     {
12859         stride_length = 1;
12860     }
12861
12862     /* If the block does not exist, create it */
12863     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
12864     {
12865         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
12866             TNG_SUCCESS)
12867         {
12868             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
12869                    __FILE__, __LINE__);
12870             return(TNG_CRITICAL);
12871         }
12872         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12873         {
12874             data = &frame_set->tr_particle_data[frame_set->
12875                                                 n_particle_data_blocks - 1];
12876         }
12877         else
12878         {
12879             data = &tng_data->non_tr_particle_data[tng_data->
12880                                                    n_particle_data_blocks - 1];
12881         }
12882         data->block_id = id;
12883
12884         data->block_name = malloc(strlen(block_name) + 1);
12885         if(!data->block_name)
12886         {
12887             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12888                    (int)strlen(block_name)+1, __FILE__, __LINE__);
12889             return(TNG_CRITICAL);
12890         }
12891         strncpy(data->block_name, block_name, strlen(block_name) + 1);
12892
12893         data->datatype = datatype;
12894
12895         data->values = 0;
12896         /* FIXME: Memory leak from strings. */
12897         data->strings = 0;
12898         data->last_retrieved_frame = -1;
12899     }
12900
12901     data->stride_length = tng_max_i64(stride_length, 1);
12902     data->n_values_per_frame = n_values_per_frame;
12903     data->n_frames = n_frames;
12904     data->codec_id = codec_id;
12905     data->compression_multiplier = 1.0;
12906     /* FIXME: This can cause problems. */
12907     data->first_frame_with_data = frame_set->first_frame;
12908
12909     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
12910     {
12911         tot_n_particles = frame_set->n_particles;
12912     }
12913     else
12914     {
12915         tot_n_particles = tng_data->n_particles;
12916     }
12917
12918     /* If data values are supplied add that data to the data block. */
12919     if(new_data_c)
12920     {
12921         /* Allocate memory */
12922         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
12923                                           stride_length, tot_n_particles,
12924                                           n_values_per_frame) !=
12925         TNG_SUCCESS)
12926         {
12927             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
12928                 __FILE__, __LINE__);
12929             return(TNG_CRITICAL);
12930         }
12931
12932         if(n_frames > frame_set->n_unwritten_frames)
12933         {
12934             frame_set->n_unwritten_frames = n_frames;
12935         }
12936
12937         n_frames_div = (n_frames % stride_length) ?
12938                      n_frames / stride_length + 1:
12939                      n_frames / stride_length;
12940
12941         if(datatype == TNG_CHAR_DATA)
12942         {
12943             for(i = 0; i < n_frames_div; i++)
12944             {
12945                 first_dim_values = data->strings[i];
12946                 for(j = num_first_particle; j < num_first_particle + n_particles;
12947                     j++)
12948                 {
12949                     second_dim_values = first_dim_values[j];
12950                     for(k = 0; k < n_values_per_frame; k++)
12951                     {
12952                         len = tng_min_i((int)strlen(new_data_c) + 1,
12953                                 TNG_MAX_STR_LEN);
12954                         if(second_dim_values[k])
12955                         {
12956                             free(second_dim_values[k]);
12957                         }
12958                         second_dim_values[k] = malloc(len);
12959                         if(!second_dim_values[k])
12960                         {
12961                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12962                                 len, __FILE__, __LINE__);
12963                             return(TNG_CRITICAL);
12964                         }
12965                         strncpy(second_dim_values[k],
12966                                 new_data_c, len);
12967                         new_data_c += len;
12968                     }
12969                 }
12970             }
12971         }
12972         else
12973         {
12974             switch(datatype)
12975             {
12976             case TNG_INT_DATA:
12977                 size = sizeof(int64_t);
12978                 break;
12979             case TNG_FLOAT_DATA:
12980                 size = sizeof(float);
12981                 break;
12982             case TNG_DOUBLE_DATA:
12983             default:
12984                 size = sizeof(double);
12985             }
12986
12987             memcpy(data->values, new_data, size * n_frames_div *
12988                    n_particles * n_values_per_frame);
12989         }
12990     }
12991
12992     return(TNG_SUCCESS);
12993 }
12994
12995 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
12996                 (tng_trajectory_t tng_data,
12997                  int64_t block_id,
12998                  char *name,
12999                  int max_len)
13000 {
13001     int64_t i;
13002     tng_trajectory_frame_set_t frame_set;
13003     tng_function_status stat;
13004     tng_particle_data_t p_data;
13005     tng_non_particle_data_t np_data;
13006     int block_type = -1;
13007
13008     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13009     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13010
13011     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13012     {
13013         p_data = &tng_data->non_tr_particle_data[i];
13014         if(p_data->block_id == block_id)
13015         {
13016             strncpy(name, p_data->block_name, max_len);
13017             name[max_len - 1] = '\0';
13018             return(TNG_SUCCESS);
13019         }
13020     }
13021     for(i = 0; i < tng_data->n_data_blocks; i++)
13022     {
13023         np_data = &tng_data->non_tr_data[i];
13024         if(np_data->block_id == block_id)
13025         {
13026             strncpy(name, np_data->block_name, max_len);
13027             name[max_len - 1] = '\0';
13028             return(TNG_SUCCESS);
13029         }
13030     }
13031
13032     frame_set = &tng_data->current_trajectory_frame_set;
13033
13034     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13035     if(stat == TNG_SUCCESS)
13036     {
13037         block_type = TNG_PARTICLE_BLOCK_DATA;
13038     }
13039     else
13040     {
13041         stat = tng_data_find(tng_data, block_id, &np_data);
13042         if(stat == TNG_SUCCESS)
13043         {
13044             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13045         }
13046         else
13047         {
13048             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13049             if(stat != TNG_SUCCESS)
13050             {
13051                 return(stat);
13052             }
13053             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13054             if(stat == TNG_SUCCESS)
13055             {
13056                 block_type = TNG_PARTICLE_BLOCK_DATA;
13057             }
13058             else
13059             {
13060                 stat = tng_data_find(tng_data, block_id, &np_data);
13061                 if(stat == TNG_SUCCESS)
13062                 {
13063                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13064                 }
13065             }
13066         }
13067     }
13068     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13069     {
13070         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13071         {
13072             p_data = &frame_set->tr_particle_data[i];
13073             if(p_data->block_id == block_id)
13074             {
13075                 strncpy(name, p_data->block_name, max_len);
13076                 name[max_len - 1] = '\0';
13077                 return(TNG_SUCCESS);
13078             }
13079         }
13080     }
13081     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13082     {
13083         for(i = 0; i < frame_set->n_data_blocks; i++)
13084         {
13085             np_data = &frame_set->tr_data[i];
13086             if(np_data->block_id == block_id)
13087             {
13088                 strncpy(name, np_data->block_name, max_len);
13089                 name[max_len - 1] = '\0';
13090                 return(TNG_SUCCESS);
13091             }
13092         }
13093     }
13094
13095     return(TNG_FAILURE);
13096 }
13097
13098 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13099                 (tng_trajectory_t tng_data,
13100                  int64_t block_id,
13101                  int *block_dependency)
13102 {
13103     int64_t i;
13104     tng_function_status stat;
13105     tng_particle_data_t p_data;
13106     tng_non_particle_data_t np_data;
13107
13108     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13109     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13110
13111     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13112     {
13113         p_data = &tng_data->non_tr_particle_data[i];
13114         if(p_data->block_id == block_id)
13115         {
13116             *block_dependency = TNG_PARTICLE_DEPENDENT;
13117             return(TNG_SUCCESS);
13118         }
13119     }
13120     for(i = 0; i < tng_data->n_data_blocks; i++)
13121     {
13122         np_data = &tng_data->non_tr_data[i];
13123         if(np_data->block_id == block_id)
13124         {
13125             *block_dependency = 0;
13126             return(TNG_SUCCESS);
13127         }
13128     }
13129
13130     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13131     if(stat == TNG_SUCCESS)
13132     {
13133         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13134         return(TNG_SUCCESS);
13135     }
13136     else
13137     {
13138         stat = tng_data_find(tng_data, block_id, &np_data);
13139         if(stat == TNG_SUCCESS)
13140         {
13141             *block_dependency = TNG_FRAME_DEPENDENT;
13142             return(TNG_SUCCESS);
13143         }
13144         else
13145         {
13146             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13147             if(stat != TNG_SUCCESS)
13148             {
13149                 return(stat);
13150             }
13151             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13152             if(stat == TNG_SUCCESS)
13153             {
13154                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13155                 return(TNG_SUCCESS);
13156             }
13157             else
13158             {
13159                 stat = tng_data_find(tng_data, block_id, &np_data);
13160                 if(stat == TNG_SUCCESS)
13161                 {
13162                     *block_dependency = TNG_FRAME_DEPENDENT;
13163                     return(TNG_SUCCESS);
13164                 }
13165             }
13166         }
13167     }
13168
13169     return(TNG_FAILURE);
13170 }
13171
13172 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
13173                 (tng_trajectory_t tng_data,
13174                  int64_t block_id,
13175                  int64_t *n_values_per_frame)
13176 {
13177     int64_t i;
13178     tng_function_status stat;
13179     tng_particle_data_t p_data;
13180     tng_non_particle_data_t np_data;
13181
13182     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13183     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
13184
13185     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13186     {
13187         p_data = &tng_data->non_tr_particle_data[i];
13188         if(p_data->block_id == block_id)
13189         {
13190             *n_values_per_frame = p_data->n_values_per_frame;
13191             return(TNG_SUCCESS);
13192         }
13193     }
13194     for(i = 0; i < tng_data->n_data_blocks; i++)
13195     {
13196         np_data = &tng_data->non_tr_data[i];
13197         if(np_data->block_id == block_id)
13198         {
13199             *n_values_per_frame = np_data->n_values_per_frame;
13200             return(TNG_SUCCESS);
13201         }
13202     }
13203
13204     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13205     if(stat == TNG_SUCCESS)
13206     {
13207         *n_values_per_frame = p_data->n_values_per_frame;
13208         return(TNG_SUCCESS);
13209     }
13210     else
13211     {
13212         stat = tng_data_find(tng_data, block_id, &np_data);
13213         if(stat == TNG_SUCCESS)
13214         {
13215             *n_values_per_frame = np_data->n_values_per_frame;
13216             return(TNG_SUCCESS);
13217         }
13218         else
13219         {
13220             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13221             if(stat != TNG_SUCCESS)
13222             {
13223                 return(stat);
13224             }
13225             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13226             if(stat == TNG_SUCCESS)
13227             {
13228                 *n_values_per_frame = p_data->n_values_per_frame;
13229                 return(TNG_SUCCESS);
13230             }
13231             else
13232             {
13233                 stat = tng_data_find(tng_data, block_id, &np_data);
13234                 if(stat == TNG_SUCCESS)
13235                 {
13236                     *n_values_per_frame = np_data->n_values_per_frame;
13237                     return(TNG_SUCCESS);
13238                 }
13239             }
13240         }
13241     }
13242
13243     return(TNG_FAILURE);
13244 }
13245
13246 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
13247                 (tng_trajectory_t tng_data,
13248                  const int64_t frame_nr,
13249                  const int64_t block_id,
13250                  const void *values,
13251                  const char hash_mode)
13252 {
13253     int64_t header_pos, file_pos;
13254     int64_t output_file_len, n_values_per_frame, size, contents_size;
13255     int64_t header_size, temp_first, temp_last;
13256     int64_t i, last_frame;
13257     long temp_current;
13258     tng_gen_block_t block;
13259     tng_trajectory_frame_set_t frame_set;
13260     FILE *temp = tng_data->input_file;
13261     struct tng_non_particle_data data;
13262     tng_function_status stat;
13263     char dependency, sparse_data, datatype;
13264     void *copy;
13265
13266     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13267     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13268     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13269
13270     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13271     {
13272         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13273                __FILE__, __LINE__);
13274         return(TNG_CRITICAL);
13275     }
13276
13277     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13278     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13279     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13280     tng_data->first_trajectory_frame_set_input_file_pos =
13281     tng_data->first_trajectory_frame_set_output_file_pos;
13282     tng_data->last_trajectory_frame_set_input_file_pos =
13283     tng_data->last_trajectory_frame_set_output_file_pos;
13284     tng_data->current_trajectory_frame_set_input_file_pos =
13285     tng_data->current_trajectory_frame_set_output_file_pos;
13286
13287     tng_data->input_file = tng_data->output_file;
13288
13289     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13290
13291     frame_set = &tng_data->current_trajectory_frame_set;
13292
13293     if(stat != TNG_SUCCESS)
13294     {
13295         last_frame = frame_set->first_frame +
13296                      frame_set->n_frames - 1;
13297         /* If the wanted frame would be in the frame set after the last
13298             * frame set create a new frame set. */
13299         if(stat == TNG_FAILURE &&
13300             last_frame < frame_nr)
13301 /*           (last_frame < frame_nr &&
13302             tng_data->current_trajectory_frame_set.first_frame +
13303             tng_data->frame_set_n_frames >= frame_nr))*/
13304         {
13305             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13306             {
13307                 last_frame = frame_nr - 1;
13308             }
13309             tng_frame_set_new(tng_data,
13310                               last_frame+1,
13311                               tng_data->frame_set_n_frames);
13312             file_pos = ftell(tng_data->output_file);
13313             fseek(tng_data->output_file, 0, SEEK_END);
13314             output_file_len = ftell(tng_data->output_file);
13315             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13316
13317             /* Read mapping blocks from the last frame set */
13318             tng_block_init(&block);
13319
13320             stat = tng_block_header_read(tng_data, block);
13321             while(file_pos < output_file_len &&
13322                   stat != TNG_CRITICAL &&
13323                   block->id != TNG_TRAJECTORY_FRAME_SET)
13324             {
13325                 if(block->id == TNG_PARTICLE_MAPPING)
13326                 {
13327                     tng_trajectory_mapping_block_read(tng_data, block,
13328                                                       hash_mode);
13329                 }
13330                 else
13331                 {
13332                     fseek(tng_data->output_file, (long)block->block_contents_size,
13333                         SEEK_CUR);
13334                 }
13335                 file_pos = ftell(tng_data->output_file);
13336                 if(file_pos < output_file_len)
13337                 {
13338                     stat = tng_block_header_read(tng_data, block);
13339                 }
13340             }
13341
13342             tng_block_destroy(&block);
13343             /* Write the frame set to disk */
13344             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13345             {
13346                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13347                 return(TNG_CRITICAL);
13348             }
13349         }
13350         else
13351         {
13352             tng_data->input_file = temp;
13353             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13354             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13355             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13356             return(stat);
13357         }
13358     }
13359
13360     tng_block_init(&block);
13361
13362     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13363
13364     fseek(tng_data->output_file, 0, SEEK_END);
13365     output_file_len = ftell(tng_data->output_file);
13366     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13367
13368     /* Read past the frame set block first */
13369     stat = tng_block_header_read(tng_data, block);
13370     if(stat == TNG_CRITICAL)
13371     {
13372         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13373                file_pos, __FILE__, __LINE__);
13374         tng_block_destroy(&block);
13375         tng_data->input_file = temp;
13376
13377         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13378         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13379         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13380         return(stat);
13381     }
13382     fseek(tng_data->output_file, (long)block->block_contents_size,
13383             SEEK_CUR);
13384
13385     /* Read all block headers until next frame set block or
13386      * until the wanted block id is found */
13387     stat = tng_block_header_read(tng_data, block);
13388     while(file_pos < output_file_len &&
13389             stat != TNG_CRITICAL &&
13390             block->id != block_id &&
13391             block->id != TNG_TRAJECTORY_FRAME_SET)
13392     {
13393         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
13394         file_pos = ftell(tng_data->output_file);
13395         if(file_pos < output_file_len)
13396         {
13397             stat = tng_block_header_read(tng_data, block);
13398         }
13399     }
13400     if(stat == TNG_CRITICAL)
13401     {
13402         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13403                file_pos, __FILE__, __LINE__);
13404         tng_block_destroy(&block);
13405         tng_data->input_file = temp;
13406         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13407         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13408         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13409         return(stat);
13410     }
13411
13412     contents_size = block->block_contents_size;
13413     header_size = block->header_contents_size;
13414
13415     header_pos = ftell(tng_data->output_file) - header_size;
13416     frame_set = &tng_data->current_trajectory_frame_set;
13417
13418     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
13419     {
13420         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13421         tng_block_destroy(&block);
13422         return(TNG_CRITICAL);
13423     }
13424     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
13425     {
13426         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13427         tng_block_destroy(&block);
13428         return(TNG_CRITICAL);
13429     }
13430     data.datatype = datatype;
13431
13432     if(!(dependency & TNG_FRAME_DEPENDENT) ||
13433        (dependency & TNG_PARTICLE_DEPENDENT))
13434     {
13435         tng_block_destroy(&block);
13436         tng_data->input_file = temp;
13437
13438         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13439         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13440         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13441         return(TNG_FAILURE);
13442     }
13443
13444     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
13445     {
13446         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13447         tng_block_destroy(&block);
13448         return(TNG_CRITICAL);
13449     }
13450
13451     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
13452              tng_data->input_file) == 0)
13453     {
13454         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13455         tng_block_destroy(&block);
13456         return(TNG_CRITICAL);
13457     }
13458     if(tng_data->output_endianness_swap_func_64)
13459     {
13460         if(tng_data->output_endianness_swap_func_64(tng_data,
13461             &data.n_values_per_frame)
13462             != TNG_SUCCESS)
13463         {
13464             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13465                     __FILE__, __LINE__);
13466         }
13467     }
13468
13469     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
13470              tng_data->input_file) == 0)
13471     {
13472         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13473         tng_block_destroy(&block);
13474         return(TNG_CRITICAL);
13475     }
13476     if(tng_data->output_endianness_swap_func_64)
13477     {
13478         if(tng_data->output_endianness_swap_func_64(tng_data,
13479             &data.codec_id)
13480             != TNG_SUCCESS)
13481         {
13482             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13483                     __FILE__, __LINE__);
13484         }
13485     }
13486
13487     if(data.codec_id != TNG_UNCOMPRESSED)
13488     {
13489         if(fread(&data.compression_multiplier,
13490                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
13491             == 0)
13492         {
13493             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13494             tng_block_destroy(&block);
13495             return(TNG_CRITICAL);
13496         }
13497         if(tng_data->output_endianness_swap_func_64)
13498         {
13499             if(tng_data->output_endianness_swap_func_64(tng_data,
13500                 (int64_t *)&data.compression_multiplier)
13501                 != TNG_SUCCESS)
13502             {
13503                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13504                         __FILE__, __LINE__);
13505             }
13506         }
13507     }
13508     else
13509     {
13510         data.compression_multiplier = 1;
13511     }
13512
13513     if(sparse_data)
13514     {
13515         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
13516                  1, tng_data->input_file) == 0)
13517         {
13518             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13519             tng_block_destroy(&block);
13520             return(TNG_CRITICAL);
13521         }
13522         if(tng_data->output_endianness_swap_func_64)
13523         {
13524             if(tng_data->output_endianness_swap_func_64(tng_data,
13525                 &data.first_frame_with_data)
13526                 != TNG_SUCCESS)
13527             {
13528                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13529                         __FILE__, __LINE__);
13530             }
13531         }
13532
13533         if(fread(&data.stride_length, sizeof(data.stride_length),
13534                  1, tng_data->input_file) == 0)
13535         {
13536             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13537             tng_block_destroy(&block);
13538             return(TNG_CRITICAL);
13539         }
13540         if(tng_data->output_endianness_swap_func_64)
13541         {
13542             if(tng_data->output_endianness_swap_func_64(tng_data,
13543                 &data.stride_length)
13544                 != TNG_SUCCESS)
13545             {
13546                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13547                         __FILE__, __LINE__);
13548             }
13549         }
13550     }
13551     else
13552     {
13553         data.first_frame_with_data = 0;
13554         data.stride_length = 1;
13555     }
13556     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
13557
13558     tng_data->input_file = temp;
13559
13560     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13561     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13562     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13563
13564     switch(data.datatype)
13565     {
13566         case(TNG_INT_DATA):
13567             size = sizeof(int64_t);
13568             break;
13569         case(TNG_FLOAT_DATA):
13570             size = sizeof(float);
13571             break;
13572         case(TNG_DOUBLE_DATA):
13573             size = sizeof(double);
13574             break;
13575         default:
13576             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
13577                    __LINE__);
13578             tng_block_destroy(&block);
13579             return(TNG_FAILURE);
13580     }
13581
13582     n_values_per_frame = data.n_values_per_frame;
13583
13584     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
13585                                data.first_frame_with_data)) /
13586                 data.stride_length;
13587     file_pos *= size * n_values_per_frame;
13588
13589     if(file_pos > contents_size)
13590     {
13591         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
13592                __LINE__);
13593         tng_block_destroy(&block);
13594         return(TNG_FAILURE);
13595     }
13596
13597     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
13598
13599     /* If the endianness is not big endian the data needs to be swapped */
13600     if((data.datatype == TNG_INT_DATA ||
13601         data.datatype == TNG_DOUBLE_DATA) &&
13602        tng_data->output_endianness_swap_func_64)
13603     {
13604         copy = malloc(n_values_per_frame * size);
13605         memcpy(copy, values, n_values_per_frame * size);
13606         for(i = 0; i < n_values_per_frame; i++)
13607         {
13608             if(tng_data->output_endianness_swap_func_64(tng_data,
13609                 (int64_t *)copy+i)
13610                 != TNG_SUCCESS)
13611             {
13612                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13613                         __FILE__, __LINE__);
13614             }
13615         }
13616         fwrite(copy, n_values_per_frame, size,
13617                tng_data->output_file);
13618         free(copy);
13619     }
13620     else if(data.datatype == TNG_FLOAT_DATA &&
13621             tng_data->output_endianness_swap_func_32)
13622     {
13623         copy = malloc(n_values_per_frame * size);
13624         memcpy(copy, values, n_values_per_frame * size);
13625         for(i = 0; i < n_values_per_frame; i++)
13626         {
13627             if(tng_data->output_endianness_swap_func_32(tng_data,
13628                 (int32_t *)copy+i)
13629                 != TNG_SUCCESS)
13630             {
13631                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13632                         __FILE__, __LINE__);
13633             }
13634         }
13635         fwrite(copy, n_values_per_frame, size,
13636                tng_data->output_file);
13637         free(copy);
13638     }
13639
13640     else
13641     {
13642         fwrite(values, n_values_per_frame, size, tng_data->output_file);
13643     }
13644
13645     fflush(tng_data->output_file);
13646
13647     /* Update the number of written frames in the frame set. */
13648     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
13649     {
13650         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
13651     }
13652
13653     /* If the last frame has been written update the hash */
13654     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
13655        data.first_frame_with_data) >=
13656        frame_set->n_frames)
13657     {
13658         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
13659                             header_size);
13660     }
13661
13662     tng_block_destroy(&block);
13663
13664     return(TNG_SUCCESS);
13665 }
13666
13667 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
13668                 (tng_trajectory_t tng_data,
13669                  const int64_t frame_nr,
13670                  const int64_t block_id,
13671                  const int64_t val_first_particle,
13672                  const int64_t val_n_particles,
13673                  const void *values,
13674                  const char hash_mode)
13675 {
13676     int64_t header_pos, file_pos, tot_n_particles;
13677     int64_t output_file_len, n_values_per_frame, size, contents_size;
13678     int64_t header_size, temp_first, temp_last;
13679     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
13680     int64_t i, last_frame;
13681     long temp_current;
13682     tng_gen_block_t block;
13683     tng_trajectory_frame_set_t frame_set;
13684     FILE *temp = tng_data->input_file;
13685     struct tng_particle_data data;
13686     tng_function_status stat;
13687     tng_particle_mapping_t mapping;
13688     char dependency, sparse_data, datatype;
13689     void *copy;
13690
13691     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13692     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13693     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13694     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
13695     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
13696
13697     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13698     {
13699         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13700                __FILE__, __LINE__);
13701         return(TNG_CRITICAL);
13702     }
13703
13704     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13705     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13706     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13707     tng_data->first_trajectory_frame_set_input_file_pos =
13708     tng_data->first_trajectory_frame_set_output_file_pos;
13709     tng_data->last_trajectory_frame_set_input_file_pos =
13710     tng_data->last_trajectory_frame_set_output_file_pos;
13711     tng_data->current_trajectory_frame_set_input_file_pos =
13712     tng_data->current_trajectory_frame_set_output_file_pos;
13713
13714     tng_data->input_file = tng_data->output_file;
13715
13716     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13717
13718     frame_set = &tng_data->current_trajectory_frame_set;
13719
13720     if(stat != TNG_SUCCESS)
13721     {
13722         last_frame = frame_set->first_frame +
13723                      frame_set->n_frames - 1;
13724 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
13725                   last_frame); */
13726         /* If the wanted frame would be in the frame set after the last
13727          * frame set create a new frame set. */
13728         if(stat == TNG_FAILURE &&
13729            (last_frame < frame_nr &&
13730             last_frame + tng_data->frame_set_n_frames >= frame_nr))
13731         {
13732             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13733             {
13734                 last_frame = frame_nr - 1;
13735             }
13736             tng_frame_set_new(tng_data,
13737                               last_frame+1,
13738                               tng_data->frame_set_n_frames);
13739
13740             file_pos = ftell(tng_data->output_file);
13741             fseek(tng_data->output_file, 0, SEEK_END);
13742             output_file_len = ftell(tng_data->output_file);
13743             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13744
13745             /* Read mapping blocks from the last frame set */
13746             tng_block_init(&block);
13747
13748             stat = tng_block_header_read(tng_data, block);
13749             while(file_pos < output_file_len &&
13750                   stat != TNG_CRITICAL &&
13751                   block->id != TNG_TRAJECTORY_FRAME_SET)
13752             {
13753                 if(block->id == TNG_PARTICLE_MAPPING)
13754                 {
13755                     tng_trajectory_mapping_block_read(tng_data, block,
13756                                                       hash_mode);
13757                 }
13758                 else
13759                 {
13760                     fseek(tng_data->output_file, (long)block->block_contents_size,
13761                         SEEK_CUR);
13762                 }
13763                 file_pos = ftell(tng_data->output_file);
13764                 if(file_pos < output_file_len)
13765                 {
13766                     stat = tng_block_header_read(tng_data, block);
13767                 }
13768             }
13769
13770             tng_block_destroy(&block);
13771             /* Write the frame set to disk */
13772             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13773             {
13774                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13775                 exit(1);
13776             }
13777         }
13778         else
13779         {
13780             tng_data->input_file = temp;
13781             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13782             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13783             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13784             return(stat);
13785         }
13786     }
13787
13788
13789     tng_block_init(&block);
13790
13791     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13792
13793     fseek(tng_data->output_file, 0, SEEK_END);
13794     output_file_len = ftell(tng_data->output_file);
13795     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13796
13797     /* Read past the frame set block first */
13798     stat = tng_block_header_read(tng_data, block);
13799     if(stat == TNG_CRITICAL)
13800     {
13801         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13802                file_pos, __FILE__, __LINE__);
13803         tng_block_destroy(&block);
13804         tng_data->input_file = temp;
13805
13806         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13807         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13808         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13809         return(stat);
13810     }
13811     fseek(tng_data->output_file, (long)block->block_contents_size,
13812             SEEK_CUR);
13813
13814     if(tng_data->var_num_atoms_flag)
13815     {
13816         tot_n_particles = frame_set->n_particles;
13817     }
13818     else
13819     {
13820         tot_n_particles = tng_data->n_particles;
13821     }
13822
13823     if(val_n_particles < tot_n_particles)
13824     {
13825         mapping_block_end_pos = -1;
13826         /* Read all mapping blocks to find the right place to put the data */
13827         stat = tng_block_header_read(tng_data, block);
13828         while(file_pos < output_file_len &&
13829                 stat != TNG_CRITICAL &&
13830                 block->id != TNG_TRAJECTORY_FRAME_SET)
13831         {
13832             if(block->id == TNG_PARTICLE_MAPPING)
13833             {
13834                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
13835             }
13836             else
13837             {
13838                 fseek(tng_data->output_file, (long)block->block_contents_size,
13839                       SEEK_CUR);
13840             }
13841             file_pos = ftell(tng_data->output_file);
13842             if(block->id == TNG_PARTICLE_MAPPING)
13843             {
13844                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
13845                 if(val_first_particle >= mapping->num_first_particle &&
13846                    val_first_particle < mapping->num_first_particle +
13847                    mapping->n_particles &&
13848                    val_first_particle + val_n_particles <=
13849                    mapping->num_first_particle + mapping->n_particles)
13850                 {
13851                     mapping_block_end_pos = file_pos;
13852                 }
13853             }
13854             if(file_pos < output_file_len)
13855             {
13856                 stat = tng_block_header_read(tng_data, block);
13857             }
13858         }
13859         if(stat == TNG_CRITICAL)
13860         {
13861             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13862                    file_pos, __FILE__, __LINE__);
13863             tng_block_destroy(&block);
13864             tng_data->input_file = temp;
13865
13866             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13867             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13868             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13869             return(stat);
13870         }
13871         if(mapping_block_end_pos < 0)
13872         {
13873             tng_block_destroy(&block);
13874             tng_data->input_file = temp;
13875
13876             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13877             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13878             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13879             return(TNG_FAILURE);
13880         }
13881         fseek(tng_data->output_file, (long)mapping_block_end_pos, SEEK_SET);
13882     }
13883
13884     /* Read all block headers until next frame set block or
13885      * until the wanted block id is found */
13886     stat = tng_block_header_read(tng_data, block);
13887     while(file_pos < output_file_len &&
13888             stat != TNG_CRITICAL &&
13889             block->id != block_id &&
13890             block->id != TNG_PARTICLE_MAPPING &&
13891             block->id != TNG_TRAJECTORY_FRAME_SET)
13892     {
13893         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
13894         file_pos = ftell(tng_data->output_file);
13895         if(file_pos < output_file_len)
13896         {
13897             stat = tng_block_header_read(tng_data, block);
13898         }
13899     }
13900     if(stat == TNG_CRITICAL)
13901     {
13902         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13903                 file_pos, __FILE__, __LINE__);
13904         tng_block_destroy(&block);
13905         tng_data->input_file = temp;
13906
13907         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13908         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13909         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13910         return(stat);
13911     }
13912
13913     contents_size = block->block_contents_size;
13914     header_size = block->header_contents_size;
13915
13916     header_pos = ftell(tng_data->output_file) - header_size;
13917     frame_set = &tng_data->current_trajectory_frame_set;
13918
13919     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
13920     {
13921         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13922         tng_block_destroy(&block);
13923         return(TNG_CRITICAL);
13924     }
13925
13926     data.datatype = datatype;
13927
13928     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
13929     {
13930         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13931         tng_block_destroy(&block);
13932         return(TNG_CRITICAL);
13933     }
13934
13935     if(!(dependency & TNG_FRAME_DEPENDENT) ||
13936        !(dependency & TNG_PARTICLE_DEPENDENT))
13937     {
13938         tng_block_destroy(&block);
13939         tng_data->input_file = temp;
13940
13941         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13942         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13943         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13944         return(TNG_FAILURE);
13945     }
13946
13947     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
13948     {
13949         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13950         tng_block_destroy(&block);
13951         return(TNG_CRITICAL);
13952     }
13953
13954     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
13955              tng_data->input_file) == 0)
13956     {
13957         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13958         tng_block_destroy(&block);
13959         return(TNG_CRITICAL);
13960     }
13961     if(tng_data->output_endianness_swap_func_64)
13962     {
13963         if(tng_data->output_endianness_swap_func_64(tng_data,
13964             &data.n_values_per_frame)
13965             != TNG_SUCCESS)
13966         {
13967             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13968                     __FILE__, __LINE__);
13969         }
13970     }
13971
13972     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
13973              tng_data->input_file) == 0)
13974     {
13975         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13976         tng_block_destroy(&block);
13977         return(TNG_CRITICAL);
13978     }
13979     if(tng_data->output_endianness_swap_func_64)
13980     {
13981         if(tng_data->output_endianness_swap_func_64(tng_data,
13982             &data.codec_id)
13983             != TNG_SUCCESS)
13984         {
13985             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13986                     __FILE__, __LINE__);
13987         }
13988     }
13989
13990     if(data.codec_id != TNG_UNCOMPRESSED)
13991     {
13992         if(fread(&data.compression_multiplier,
13993                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
13994             == 0)
13995         {
13996             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13997             tng_block_destroy(&block);
13998             return(TNG_CRITICAL);
13999         }
14000
14001         if(tng_data->output_endianness_swap_func_64)
14002         {
14003             if(tng_data->output_endianness_swap_func_64(tng_data,
14004                (int64_t *)&data.compression_multiplier)
14005                 != TNG_SUCCESS)
14006             {
14007                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14008                         __FILE__, __LINE__);
14009             }
14010         }
14011     }
14012     else
14013     {
14014         data.compression_multiplier = 1;
14015     }
14016
14017     if(sparse_data)
14018     {
14019         if(fread(&data.first_frame_with_data,
14020                  sizeof(data.first_frame_with_data),
14021                  1, tng_data->input_file) == 0)
14022         {
14023             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14024             tng_block_destroy(&block);
14025             return(TNG_CRITICAL);
14026         }
14027         if(tng_data->output_endianness_swap_func_64)
14028         {
14029             if(tng_data->output_endianness_swap_func_64(tng_data,
14030                 &data.first_frame_with_data)
14031                 != TNG_SUCCESS)
14032             {
14033                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14034                         __FILE__, __LINE__);
14035             }
14036         }
14037
14038         if(fread(&data.stride_length, sizeof(data.stride_length),
14039                  1, tng_data->input_file) == 0)
14040         {
14041             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14042             tng_block_destroy(&block);
14043             return(TNG_CRITICAL);
14044         }
14045         if(tng_data->output_endianness_swap_func_64)
14046         {
14047             if(tng_data->output_endianness_swap_func_64(tng_data,
14048                 &data.stride_length)
14049                 != TNG_SUCCESS)
14050             {
14051                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14052                         __FILE__, __LINE__);
14053             }
14054         }
14055     }
14056     else
14057     {
14058         data.first_frame_with_data = 0;
14059         data.stride_length = 1;
14060     }
14061     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14062
14063     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14064              tng_data->input_file) == 0)
14065     {
14066         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14067         tng_block_destroy(&block);
14068         return(TNG_CRITICAL);
14069     }
14070     if(tng_data->output_endianness_swap_func_64)
14071     {
14072         if(tng_data->output_endianness_swap_func_64(tng_data,
14073             &num_first_particle)
14074             != TNG_SUCCESS)
14075         {
14076             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14077                     __FILE__, __LINE__);
14078         }
14079     }
14080
14081     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14082              tng_data->input_file) == 0)
14083     {
14084         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14085         tng_block_destroy(&block);
14086         return(TNG_CRITICAL);
14087     }
14088     if(tng_data->output_endianness_swap_func_64)
14089     {
14090         if(tng_data->output_endianness_swap_func_64(tng_data,
14091             &block_n_particles)
14092             != TNG_SUCCESS)
14093         {
14094             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14095                     __FILE__, __LINE__);
14096         }
14097     }
14098
14099
14100     tng_data->input_file = temp;
14101
14102     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14103     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14104     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14105
14106
14107     switch(data.datatype)
14108     {
14109         case(TNG_INT_DATA):
14110             size = sizeof(int64_t);
14111             break;
14112         case(TNG_FLOAT_DATA):
14113             size = sizeof(float);
14114             break;
14115         case(TNG_DOUBLE_DATA):
14116             size = sizeof(double);
14117             break;
14118         default:
14119             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14120                    __LINE__);
14121             tng_block_destroy(&block);
14122             return(TNG_FAILURE);
14123     }
14124
14125     n_values_per_frame = data.n_values_per_frame;
14126
14127     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14128                                data.first_frame_with_data)) /
14129                 data.stride_length;
14130     file_pos *= block_n_particles * size * n_values_per_frame;
14131
14132     if(file_pos > contents_size)
14133     {
14134         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14135                __LINE__);
14136         tng_block_destroy(&block);
14137         return(TNG_FAILURE);
14138     }
14139
14140     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14141
14142     /* If the endianness is not big endian the data needs to be swapped */
14143     if((data.datatype == TNG_INT_DATA ||
14144         data.datatype == TNG_DOUBLE_DATA) &&
14145        tng_data->output_endianness_swap_func_64)
14146     {
14147         copy = malloc(val_n_particles * n_values_per_frame * size);
14148         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14149         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14150         {
14151             if(tng_data->output_endianness_swap_func_64(tng_data,
14152                 (int64_t *) copy+i)
14153                 != TNG_SUCCESS)
14154             {
14155                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14156                         __FILE__, __LINE__);
14157             }
14158         }
14159         fwrite(copy, val_n_particles * n_values_per_frame, size,
14160                tng_data->output_file);
14161         free(copy);
14162     }
14163     else if(data.datatype == TNG_FLOAT_DATA &&
14164        tng_data->output_endianness_swap_func_32)
14165     {
14166         copy = malloc(val_n_particles * n_values_per_frame * size);
14167         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14168         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14169         {
14170             if(tng_data->output_endianness_swap_func_32(tng_data,
14171                 (int32_t *) copy+i)
14172                 != TNG_SUCCESS)
14173             {
14174                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14175                         __FILE__, __LINE__);
14176             }
14177         }
14178         fwrite(copy, val_n_particles * n_values_per_frame, size,
14179                tng_data->output_file);
14180         free(copy);
14181     }
14182
14183     else
14184     {
14185         fwrite(values, val_n_particles * n_values_per_frame, size,
14186                tng_data->output_file);
14187     }
14188     fflush(tng_data->output_file);
14189
14190     /* Update the number of written frames in the frame set. */
14191     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14192     {
14193         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14194     }
14195
14196     /* If the last frame has been written update the hash */
14197     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14198        data.first_frame_with_data) >=
14199        frame_set->n_frames)
14200     {
14201         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14202                             header_size);
14203     }
14204
14205     tng_block_destroy(&block);
14206     return(TNG_SUCCESS);
14207 }
14208
14209 static tng_function_status tng_data_values_alloc
14210                 (const tng_trajectory_t tng_data,
14211                  union data_values ***values,
14212                  const int64_t n_frames,
14213                  const int64_t n_values_per_frame,
14214                  const char type)
14215 {
14216     int64_t i;
14217     tng_function_status stat;
14218
14219     if(n_frames <= 0 || n_values_per_frame <= 0)
14220     {
14221         return(TNG_FAILURE);
14222     }
14223
14224     if(*values)
14225     {
14226         stat = tng_data_values_free(tng_data, *values, n_frames,
14227                                     n_values_per_frame,
14228                                     type);
14229         if(stat != TNG_SUCCESS)
14230         {
14231             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
14232                    __FILE__, __LINE__);
14233             return(stat);
14234         }
14235     }
14236     *values = malloc(sizeof(union data_values *) * n_frames);
14237     if(!*values)
14238     {
14239         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14240                sizeof(union data_values **) * n_frames,
14241                __FILE__, __LINE__);
14242         return(TNG_CRITICAL);
14243
14244     }
14245
14246     for(i = n_frames; i--;)
14247     {
14248         (*values)[i] = malloc(sizeof(union data_values) *
14249                            n_values_per_frame);
14250         if(!(*values)[i])
14251         {
14252             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14253                    sizeof(union data_values) * n_values_per_frame,
14254                    __FILE__, __LINE__);
14255             free(values);
14256             values = 0;
14257             return(TNG_CRITICAL);
14258         }
14259     }
14260     return(TNG_SUCCESS);
14261 }
14262
14263 /* FIXME: This needs ***values */
14264 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
14265                 (const tng_trajectory_t tng_data,
14266                  union data_values **values,
14267                  const int64_t n_frames,
14268                  const int64_t n_values_per_frame,
14269                  const char type)
14270 {
14271     int64_t i, j;
14272     (void)tng_data;
14273
14274     if(values)
14275     {
14276         for(i = 0; i < n_frames; i++)
14277         {
14278             if(values[i])
14279             {
14280                 if(type == TNG_CHAR_DATA)
14281                 {
14282                     for(j = n_values_per_frame; j--;)
14283                     {
14284                         if(values[i][j].c)
14285                         {
14286                             free(values[i][j].c);
14287                             values[i][j].c = 0;
14288                         }
14289                     }
14290                 }
14291                 free(values[i]);
14292                 values[i] = 0;
14293             }
14294         }
14295         free(values);
14296         values = 0;
14297     }
14298
14299     return(TNG_SUCCESS);
14300 }
14301
14302 static tng_function_status tng_particle_data_values_alloc
14303                 (const tng_trajectory_t tng_data,
14304                  union data_values ****values,
14305                  const int64_t n_frames,
14306                  const int64_t n_particles,
14307                  const int64_t n_values_per_frame,
14308                  const char type)
14309 {
14310     int64_t i, j;
14311     tng_function_status stat;
14312
14313     if(n_particles == 0 || n_values_per_frame == 0)
14314     {
14315         return(TNG_FAILURE);
14316     }
14317
14318     if(*values)
14319     {
14320         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
14321                                              n_particles, n_values_per_frame,
14322                                              type);
14323         if(stat != TNG_SUCCESS)
14324         {
14325             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
14326                    __FILE__, __LINE__);
14327             return(stat);
14328         }
14329     }
14330     *values = malloc(sizeof(union data_values **) * n_frames);
14331     if(!*values)
14332     {
14333         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14334                sizeof(union data_values **) * n_frames,
14335                __FILE__, __LINE__);
14336         return(TNG_CRITICAL);
14337
14338     }
14339
14340     for(i = n_frames; i--;)
14341     {
14342         (*values)[i] = malloc(sizeof(union data_values *) *
14343                            n_particles);
14344         if(!(*values)[i])
14345         {
14346             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14347                    sizeof(union data_values *) * n_particles,
14348                    __FILE__, __LINE__);
14349             free(*values);
14350             *values = 0;
14351             return(TNG_CRITICAL);
14352         }
14353         for(j = n_particles; j--;)
14354         {
14355             (*values)[i][j] = malloc(sizeof(union data_values) *
14356                                   n_values_per_frame);
14357             if(!(*values)[i][j])
14358             {
14359                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14360                     sizeof(union data_values *) * n_particles,
14361                     __FILE__, __LINE__);
14362                 tng_particle_data_values_free(tng_data, *values, n_frames,
14363                                               n_particles, n_values_per_frame,
14364                                               type);
14365                 *values = 0;
14366                 return(TNG_CRITICAL);
14367             }
14368         }
14369     }
14370     return(TNG_SUCCESS);
14371 }
14372
14373 /* FIXME: This needs ****values */
14374 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
14375                 (const tng_trajectory_t tng_data,
14376                  union data_values ***values,
14377                  const int64_t n_frames,
14378                  const int64_t n_particles,
14379                  const int64_t n_values_per_frame,
14380                  const char type)
14381 {
14382     int64_t i, j, k;
14383     (void)tng_data;
14384
14385     if(values)
14386     {
14387         for(i = 0; i < n_frames; i++)
14388         {
14389             if(values[i])
14390             {
14391                 for(j = 0; j < n_particles; j++)
14392                 {
14393                     if(type == TNG_CHAR_DATA)
14394                     {
14395                         for(k = n_values_per_frame; k--;)
14396                         {
14397                             if(values[i][j][k].c)
14398                             {
14399                                 free(values[i][j][k].c);
14400                                 values[i][j][k].c = 0;
14401                             }
14402                         }
14403                     }
14404                     free(values[i][j]);
14405                     values[i][j] = 0;
14406                 }
14407                 free(values[i]);
14408                 values[i] = 0;
14409             }
14410         }
14411         free(values);
14412         values = 0;
14413     }
14414
14415     return(TNG_SUCCESS);
14416 }
14417
14418
14419 tng_function_status DECLSPECDLLEXPORT tng_data_get
14420                 (tng_trajectory_t tng_data,
14421                  const int64_t block_id,
14422                  union data_values ***values,
14423                  int64_t *n_frames,
14424                  int64_t *n_values_per_frame,
14425                  char *type)
14426 {
14427     int64_t i, j, file_pos, block_index;
14428     int size;
14429     size_t len;
14430     tng_non_particle_data_t data;
14431     tng_trajectory_frame_set_t frame_set;
14432     tng_gen_block_t block;
14433     tng_function_status stat;
14434
14435     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14436     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14437     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14438     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14439
14440     frame_set = &tng_data->current_trajectory_frame_set;
14441
14442     block_index = -1;
14443     data = 0;
14444
14445     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
14446     {
14447         tng_block_init(&block);
14448         file_pos = ftell(tng_data->input_file);
14449         /* Read all blocks until next frame set block */
14450         stat = tng_block_header_read(tng_data, block);
14451         while(file_pos < tng_data->input_file_len &&
14452                 stat != TNG_CRITICAL &&
14453                 block->id != TNG_TRAJECTORY_FRAME_SET)
14454         {
14455             /* Use hash by default */
14456             stat = tng_block_read_next(tng_data, block,
14457                                     TNG_USE_HASH);
14458             if(stat != TNG_CRITICAL)
14459             {
14460                 file_pos = ftell(tng_data->input_file);
14461                 if(file_pos < tng_data->input_file_len)
14462                 {
14463                     stat = tng_block_header_read(tng_data, block);
14464                 }
14465             }
14466         }
14467         tng_block_destroy(&block);
14468         if(stat == TNG_CRITICAL)
14469         {
14470             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14471                     file_pos, __FILE__, __LINE__);
14472             return(stat);
14473         }
14474
14475         for(i = frame_set->n_data_blocks; i-- ;)
14476         {
14477             data = &frame_set->tr_data[i];
14478             if(data->block_id == block_id)
14479             {
14480                 block_index = i;
14481                 break;
14482             }
14483         }
14484         if(block_index < 0)
14485         {
14486             return(TNG_FAILURE);
14487         }
14488     }
14489
14490     *n_frames = tng_max_i64(1, data->n_frames);
14491     *n_values_per_frame = data->n_values_per_frame;
14492     *type = data->datatype;
14493
14494     if(*values == 0)
14495     {
14496         if(tng_data_values_alloc(tng_data, values, *n_frames,
14497                                  *n_values_per_frame,
14498                                  *type)
14499         != TNG_SUCCESS)
14500         {
14501             return(TNG_CRITICAL);
14502         }
14503     }
14504
14505     switch(*type)
14506     {
14507     case TNG_CHAR_DATA:
14508         for(i=*n_frames; i--;)
14509         {
14510             for(j=*n_values_per_frame; j--;)
14511             {
14512                 len = strlen(data->strings[i][j]) + 1;
14513                 (*values)[i][j].c = malloc(len);
14514                 strncpy((*values)[i][j].c, data->strings[i][j], len);
14515             }
14516         }
14517         break;
14518     case TNG_INT_DATA:
14519         size = sizeof(int);
14520         for(i=*n_frames; i--;)
14521         {
14522             for(j=*n_values_per_frame; j--;)
14523             {
14524                 (*values)[i][j].i = *(int *)((char *)data->values + size *
14525                                              (i*(*n_values_per_frame) + j));
14526             }
14527         }
14528         break;
14529     case TNG_FLOAT_DATA:
14530         size = sizeof(float);
14531         for(i=*n_frames; i--;)
14532         {
14533             for(j=*n_values_per_frame; j--;)
14534             {
14535                 (*values)[i][j].f = *(float *)((char *)data->values + size *
14536                                                (i*(*n_values_per_frame) + j));
14537             }
14538         }
14539         break;
14540     case TNG_DOUBLE_DATA:
14541     default:
14542         size = sizeof(double);
14543         for(i=*n_frames; i--;)
14544         {
14545             for(j=*n_values_per_frame; j--;)
14546             {
14547                 (*values)[i][j].d = *(double *)((char *)data->values + size *
14548                                                 (i*(*n_values_per_frame) + j));
14549             }
14550         }
14551     }
14552
14553     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14554
14555     return(TNG_SUCCESS);
14556 }
14557
14558 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
14559                                         const int64_t block_id,
14560                                         void **values,
14561                                         int64_t *n_frames,
14562                                         int64_t *stride_length,
14563                                         int64_t *n_values_per_frame,
14564                                         char *type)
14565 {
14566     int64_t file_pos, data_size, n_frames_div, block_index;
14567     int i, size;
14568     tng_non_particle_data_t data;
14569     tng_trajectory_frame_set_t frame_set;
14570     tng_gen_block_t block;
14571     void *temp;
14572     tng_function_status stat;
14573
14574     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14575     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14576     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14577     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14578     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14579
14580     frame_set = &tng_data->current_trajectory_frame_set;
14581
14582     block_index = -1;
14583     data = 0;
14584
14585     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
14586     {
14587         tng_block_init(&block);
14588         file_pos = ftell(tng_data->input_file);
14589         /* Read all blocks until next frame set block */
14590         stat = tng_block_header_read(tng_data, block);
14591         while(file_pos < tng_data->input_file_len &&
14592                 stat != TNG_CRITICAL &&
14593                 block->id != TNG_TRAJECTORY_FRAME_SET)
14594         {
14595             /* Use hash by default */
14596             stat = tng_block_read_next(tng_data, block,
14597                                     TNG_USE_HASH);
14598             if(stat != TNG_CRITICAL)
14599             {
14600                 file_pos = ftell(tng_data->input_file);
14601                 if(file_pos < tng_data->input_file_len)
14602                 {
14603                     stat = tng_block_header_read(tng_data, block);
14604                 }
14605             }
14606         }
14607         tng_block_destroy(&block);
14608         if(stat == TNG_CRITICAL)
14609         {
14610             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14611                     file_pos, __FILE__, __LINE__);
14612             return(stat);
14613         }
14614
14615         for(i = frame_set->n_data_blocks; i-- ;)
14616         {
14617             data = &frame_set->tr_data[i];
14618             if(data->block_id == block_id)
14619             {
14620                 block_index = i;
14621                 break;
14622             }
14623         }
14624         if(block_index < 0)
14625         {
14626             return(TNG_FAILURE);
14627         }
14628     }
14629
14630     *type = data->datatype;
14631
14632     switch(*type)
14633     {
14634     case TNG_CHAR_DATA:
14635         return(TNG_FAILURE);
14636     case TNG_INT_DATA:
14637         size = sizeof(int64_t);
14638         break;
14639     case TNG_FLOAT_DATA:
14640         size = sizeof(float);
14641         break;
14642     case TNG_DOUBLE_DATA:
14643     default:
14644         size = sizeof(double);
14645     }
14646
14647     *n_frames = data->n_frames;
14648     *n_values_per_frame = data->n_values_per_frame;
14649     *stride_length = data->stride_length;
14650     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
14651                    *n_frames / *stride_length;
14652
14653     data_size = n_frames_div * size *
14654                 *n_values_per_frame;
14655
14656     temp = realloc(*values, data_size);
14657     if(!temp)
14658     {
14659         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14660                data_size, __FILE__, __LINE__);
14661         free(*values);
14662         *values = 0;
14663         return(TNG_CRITICAL);
14664     }
14665
14666     *values = temp;
14667
14668     memcpy(*values, data->values, data_size);
14669
14670     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14671
14672     return(TNG_SUCCESS);
14673 }
14674
14675 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
14676                 (tng_trajectory_t tng_data,
14677                  const int64_t block_id,
14678                  const int64_t start_frame_nr,
14679                  const int64_t end_frame_nr,
14680                  const char hash_mode,
14681                  union data_values ***values,
14682                  int64_t *n_values_per_frame,
14683                  char *type)
14684 {
14685     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
14686     int64_t block_index;
14687     int size;
14688     size_t len;
14689     tng_non_particle_data_t data;
14690     tng_trajectory_frame_set_t frame_set;
14691     tng_gen_block_t block;
14692     tng_function_status stat;
14693
14694     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14695     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
14696     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14697     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14698
14699     block_index = -1;
14700
14701     frame_set = &tng_data->current_trajectory_frame_set;
14702     first_frame = frame_set->first_frame;
14703
14704     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14705     if(stat != TNG_SUCCESS)
14706     {
14707         return(stat);
14708     }
14709
14710
14711     /* Do not re-read the frame set. */
14712     if(first_frame != frame_set->first_frame ||
14713        frame_set->n_data_blocks <= 0)
14714     {
14715         tng_block_init(&block);
14716         file_pos = ftell(tng_data->input_file);
14717         /* Read all blocks until next frame set block */
14718         stat = tng_block_header_read(tng_data, block);
14719         while(file_pos < tng_data->input_file_len &&
14720             stat != TNG_CRITICAL &&
14721             block->id != TNG_TRAJECTORY_FRAME_SET)
14722         {
14723             stat = tng_block_read_next(tng_data, block,
14724                                     hash_mode);
14725             if(stat != TNG_CRITICAL)
14726             {
14727                 file_pos = ftell(tng_data->input_file);
14728                 if(file_pos < tng_data->input_file_len)
14729                 {
14730                     stat = tng_block_header_read(tng_data, block);
14731                 }
14732             }
14733         }
14734         tng_block_destroy(&block);
14735         if(stat == TNG_CRITICAL)
14736         {
14737             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14738                     file_pos, __FILE__, __LINE__);
14739             return(stat);
14740         }
14741     }
14742
14743
14744     /* See if there is a data block of this ID.
14745      * Start checking the last read frame set */
14746     for(i = frame_set->n_data_blocks; i-- ;)
14747     {
14748         data = &frame_set->tr_data[i];
14749         if(data->block_id == block_id)
14750         {
14751             block_index = i;
14752             break;
14753         }
14754     }
14755
14756     if(block_index < 0)
14757     {
14758         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
14759                 block_id, __FILE__, __LINE__);
14760         return(TNG_FAILURE);
14761     }
14762
14763     n_frames = end_frame_nr - start_frame_nr + 1;
14764     *n_values_per_frame = data->n_values_per_frame;
14765     *type = data->datatype;
14766
14767     if(*values == 0)
14768     {
14769         if(tng_data_values_alloc(tng_data, values, n_frames,
14770                                  *n_values_per_frame,
14771                                  *type) != TNG_SUCCESS)
14772         {
14773             return(TNG_CRITICAL);
14774         }
14775     }
14776
14777     current_frame_pos = start_frame_nr - frame_set->first_frame;
14778     /* It's not very elegant to reuse so much of the code in the different case
14779      * statements, but it's unnecessarily slow to have the switch-case block
14780      * inside the for loops. */
14781     switch(*type)
14782     {
14783     case TNG_CHAR_DATA:
14784         for(i=0; i<n_frames; i++)
14785         {
14786             if(current_frame_pos == frame_set->n_frames)
14787             {
14788                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14789                 if(stat != TNG_SUCCESS)
14790                 {
14791                     return(stat);
14792                 }
14793                 current_frame_pos = 0;
14794             }
14795             for(j=*n_values_per_frame; j--;)
14796             {
14797                 len = strlen(data->strings[current_frame_pos][j]) + 1;
14798                 (*values)[i][j].c = malloc(len);
14799                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
14800             }
14801             current_frame_pos++;
14802         }
14803         break;
14804     case TNG_INT_DATA:
14805         size = sizeof(int);
14806         for(i=0; i<n_frames; i++)
14807         {
14808             if(current_frame_pos == frame_set->n_frames)
14809             {
14810                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14811                 if(stat != TNG_SUCCESS)
14812                 {
14813                     return(stat);
14814                 }
14815                 current_frame_pos = 0;
14816             }
14817             for(j=*n_values_per_frame; j--;)
14818             {
14819                 (*values)[i][j].i = *(int *)((char *)data->values + size *
14820                                             (current_frame_pos *
14821                                              (*n_values_per_frame) + j));
14822             }
14823             current_frame_pos++;
14824         }
14825         break;
14826     case TNG_FLOAT_DATA:
14827         size = sizeof(float);
14828         for(i=0; i<n_frames; i++)
14829         {
14830             if(current_frame_pos == frame_set->n_frames)
14831             {
14832                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14833                 if(stat != TNG_SUCCESS)
14834                 {
14835                     return(stat);
14836                 }
14837                 current_frame_pos = 0;
14838             }
14839             for(j=*n_values_per_frame; j--;)
14840             {
14841                 (*values)[i][j].f = *(float *)((char *)data->values + size *
14842                                                (current_frame_pos *
14843                                                 (*n_values_per_frame) + j));
14844             }
14845             current_frame_pos++;
14846         }
14847         break;
14848     case TNG_DOUBLE_DATA:
14849     default:
14850         size = sizeof(double);
14851         for(i=0; i<n_frames; i++)
14852         {
14853             if(current_frame_pos == frame_set->n_frames)
14854             {
14855                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14856                 if(stat != TNG_SUCCESS)
14857                 {
14858                     return(stat);
14859                 }
14860                 current_frame_pos = 0;
14861             }
14862             for(j=*n_values_per_frame; j--;)
14863             {
14864                 (*values)[i][j].d = *(double *)((char *)data->values + size *
14865                                                 (current_frame_pos *
14866                                                  (*n_values_per_frame) + j));
14867             }
14868             current_frame_pos++;
14869         }
14870     }
14871
14872     data->last_retrieved_frame = end_frame_nr;
14873
14874     return(TNG_SUCCESS);
14875 }
14876
14877 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
14878                 (tng_trajectory_t tng_data,
14879                  const int64_t block_id,
14880                  const int64_t start_frame_nr,
14881                  const int64_t end_frame_nr,
14882                  const char hash_mode,
14883                  void **values,
14884                  int64_t *stride_length,
14885                  int64_t *n_values_per_frame,
14886                  char *type)
14887 {
14888     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
14889     int64_t file_pos, current_frame_pos, data_size, frame_size;
14890     int64_t last_frame_pos;
14891     int size;
14892     tng_trajectory_frame_set_t frame_set;
14893     tng_non_particle_data_t np_data;
14894     tng_gen_block_t block;
14895     void *current_values = 0, *temp;
14896     tng_function_status stat;
14897
14898     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14899     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
14900     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14901     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14902     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14903
14904     frame_set = &tng_data->current_trajectory_frame_set;
14905     first_frame = frame_set->first_frame;
14906
14907     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14908     if(stat != TNG_SUCCESS)
14909     {
14910         return(stat);
14911     }
14912
14913     /* Do not re-read the frame set and only need the requested block. */
14914     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
14915     stat = tng_data_find(tng_data, block_id, &np_data);
14916     if(first_frame != frame_set->first_frame ||
14917        stat != TNG_SUCCESS)
14918     {
14919         tng_block_init(&block);
14920         if(stat != TNG_SUCCESS)
14921         {
14922             fseek(tng_data->input_file,
14923                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
14924                   SEEK_SET);
14925             stat = tng_block_header_read(tng_data, block);
14926             if(stat != TNG_SUCCESS)
14927             {
14928                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
14929                         __FILE__, __LINE__);
14930                 return(stat);
14931             }
14932
14933             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
14934         }
14935         file_pos = ftell(tng_data->input_file);
14936         /* Read until next frame set block */
14937         stat = tng_block_header_read(tng_data, block);
14938         while(file_pos < tng_data->input_file_len &&
14939             stat != TNG_CRITICAL &&
14940             block->id != TNG_TRAJECTORY_FRAME_SET)
14941         {
14942             if(block->id == block_id)
14943             {
14944                 stat = tng_block_read_next(tng_data, block,
14945                                         hash_mode);
14946                 if(stat != TNG_CRITICAL)
14947                 {
14948                     file_pos = ftell(tng_data->input_file);
14949                     if(file_pos < tng_data->input_file_len)
14950                     {
14951                         stat = tng_block_header_read(tng_data, block);
14952                     }
14953                 }
14954             }
14955             else
14956             {
14957                 file_pos += block->block_contents_size + block->header_contents_size;
14958                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
14959                 if(file_pos < tng_data->input_file_len)
14960                 {
14961                     stat = tng_block_header_read(tng_data, block);
14962                 }
14963             }
14964         }
14965         tng_block_destroy(&block);
14966         if(stat == TNG_CRITICAL)
14967         {
14968             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14969                     file_pos, __FILE__, __LINE__);
14970             return(stat);
14971         }
14972     }
14973
14974     stat = tng_data_find(tng_data, block_id, &np_data);
14975     if(stat != TNG_SUCCESS)
14976     {
14977         return(stat);
14978     }
14979
14980     stat = tng_data_vector_get(tng_data, block_id, &current_values,
14981                                &n_frames, stride_length,
14982                                n_values_per_frame, type);
14983
14984     if(stat != TNG_SUCCESS)
14985     {
14986         if(current_values)
14987         {
14988             free(current_values);
14989         }
14990         return(stat);
14991     }
14992
14993     if(n_frames == 1 && n_frames < frame_set->n_frames)
14994     {
14995         tot_n_frames = 1;
14996     }
14997     else
14998     {
14999         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15000     }
15001
15002     switch(*type)
15003     {
15004     case TNG_CHAR_DATA:
15005         return(TNG_FAILURE);
15006     case TNG_INT_DATA:
15007         size = sizeof(int64_t);
15008         break;
15009     case TNG_FLOAT_DATA:
15010         size = sizeof(float);
15011         break;
15012     case TNG_DOUBLE_DATA:
15013     default:
15014         size = sizeof(double);
15015     }
15016
15017     n_frames_div = (tot_n_frames % *stride_length) ?
15018                  tot_n_frames / *stride_length + 1:
15019                  tot_n_frames / *stride_length;
15020     data_size = n_frames_div * size * (*n_values_per_frame);
15021
15022 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15023               size, n_frames_div, data_size);
15024 */
15025     temp = realloc(*values, data_size);
15026     if(!temp)
15027     {
15028         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15029                data_size, __FILE__, __LINE__);
15030         free(*values);
15031         *values = 0;
15032         return(TNG_CRITICAL);
15033     }
15034
15035     *values = temp;
15036
15037     if( n_frames == 1 && n_frames < frame_set->n_frames)
15038     {
15039         memcpy(*values, current_values, size * (*n_values_per_frame));
15040     }
15041     else
15042     {
15043         current_frame_pos = start_frame_nr - frame_set->first_frame;
15044
15045         frame_size = size * (*n_values_per_frame);
15046
15047         last_frame_pos = tng_min_i64(n_frames,
15048                                      end_frame_nr - start_frame_nr);
15049
15050         n_frames_div = current_frame_pos / *stride_length;
15051         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15052                        last_frame_pos / *stride_length + 1:
15053                        last_frame_pos / *stride_length;
15054         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15055
15056         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15057                n_frames_div_2 * frame_size);
15058
15059         current_frame_pos += n_frames - current_frame_pos;
15060
15061         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15062         {
15063             stat = tng_frame_set_read_next(tng_data, hash_mode);
15064             if(stat != TNG_SUCCESS)
15065             {
15066                 if(current_values)
15067                 {
15068                     free(current_values);
15069                 }
15070                 free(*values);
15071                 *values = 0;
15072                 return(stat);
15073             }
15074
15075             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15076                                     &n_frames, stride_length,
15077                                     n_values_per_frame, type);
15078
15079             if(stat != TNG_SUCCESS)
15080             {
15081                 if(current_values)
15082                 {
15083                     free(current_values);
15084                 }
15085                 free(*values);
15086                 *values = 0;
15087                 return(stat);
15088             }
15089
15090             last_frame_pos = tng_min_i64(n_frames,
15091                                          end_frame_nr - current_frame_pos);
15092
15093             n_frames_div = current_frame_pos / *stride_length;
15094             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15095                            last_frame_pos / *stride_length + 1:
15096                            last_frame_pos / *stride_length;
15097             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15098
15099             memcpy(((char *)*values) + n_frames_div * frame_size,
15100                    current_values,
15101                    n_frames_div_2 * frame_size);
15102
15103             current_frame_pos += n_frames;
15104         }
15105     }
15106
15107     if(current_values)
15108     {
15109         free(current_values);
15110     }
15111
15112     np_data->last_retrieved_frame = end_frame_nr;
15113
15114     return(TNG_SUCCESS);
15115 }
15116
15117 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15118                 (tng_trajectory_t tng_data,
15119                  const int64_t block_id,
15120                  union data_values ****values,
15121                  int64_t *n_frames,
15122                  int64_t *n_particles,
15123                  int64_t *n_values_per_frame,
15124                  char *type)
15125 {
15126     int64_t i, j, k, mapping, file_pos, i_step, block_index;
15127     int size;
15128     size_t len;
15129     tng_particle_data_t data;
15130     tng_trajectory_frame_set_t frame_set;
15131     tng_gen_block_t block;
15132     char block_type_flag;
15133     tng_function_status stat;
15134
15135     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15136     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15137     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15138     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15139     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15140
15141     frame_set = &tng_data->current_trajectory_frame_set;
15142
15143     block_index = -1;
15144     data = 0;
15145
15146     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15147     {
15148         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15149         {
15150             block_type_flag = TNG_TRAJECTORY_BLOCK;
15151         }
15152         else
15153         {
15154             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15155         }
15156
15157         tng_block_init(&block);
15158         file_pos = ftell(tng_data->input_file);
15159         /* Read all blocks until next frame set block */
15160         stat = tng_block_header_read(tng_data, block);
15161         while(file_pos < tng_data->input_file_len &&
15162                 stat != TNG_CRITICAL &&
15163                 block->id != TNG_TRAJECTORY_FRAME_SET)
15164         {
15165             /* Use hash by default */
15166             stat = tng_block_read_next(tng_data, block,
15167                                     TNG_USE_HASH);
15168             if(stat != TNG_CRITICAL)
15169             {
15170                 file_pos = ftell(tng_data->input_file);
15171                 if(file_pos < tng_data->input_file_len)
15172                 {
15173                     stat = tng_block_header_read(tng_data, block);
15174                 }
15175             }
15176         }
15177         tng_block_destroy(&block);
15178         if(stat == TNG_CRITICAL)
15179         {
15180             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15181                     file_pos, __FILE__, __LINE__);
15182             return(stat);
15183         }
15184
15185         for(i = frame_set->n_particle_data_blocks; i-- ;)
15186         {
15187             data = &frame_set->tr_particle_data[i];
15188             if(data->block_id == block_id)
15189             {
15190                 block_index = i;
15191                 block_type_flag = TNG_TRAJECTORY_BLOCK;
15192                 break;
15193             }
15194         }
15195         if(block_index < 0)
15196         {
15197             return(TNG_FAILURE);
15198         }
15199     }
15200     else
15201     {
15202         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15203         {
15204             block_type_flag = TNG_TRAJECTORY_BLOCK;
15205         }
15206         else
15207         {
15208             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15209         }
15210     }
15211
15212     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15213        tng_data->var_num_atoms_flag)
15214     {
15215         *n_particles = frame_set->n_particles;
15216     }
15217     else
15218     {
15219         *n_particles = tng_data->n_particles;
15220     }
15221
15222     *n_frames = tng_max_i64(1, data->n_frames);
15223     *n_values_per_frame = data->n_values_per_frame;
15224     *type = data->datatype;
15225
15226     if(*values == 0)
15227     {
15228         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
15229                                          *n_particles, *n_values_per_frame,
15230                                          *type)
15231             != TNG_SUCCESS)
15232         {
15233             return(TNG_CRITICAL);
15234         }
15235     }
15236
15237     /* It's not very elegant to reuse so much of the code in the different case
15238      * statements, but it's unnecessarily slow to have the switch-case block
15239      * inside the for loops. */
15240     switch(*type)
15241     {
15242     case TNG_CHAR_DATA:
15243         for(i=*n_frames; i--;)
15244         {
15245             for(j=*n_particles; j--;)
15246             {
15247                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15248                 for(k=*n_values_per_frame; k--;)
15249                 {
15250                     len = strlen(data->strings[i][j][k]) + 1;
15251                     (*values)[i][mapping][k].c = malloc(len);
15252                     strncpy((*values)[i][mapping][k].c,
15253                             data->strings[i][j][k], len);
15254                 }
15255             }
15256         }
15257         break;
15258     case TNG_INT_DATA:
15259         size = sizeof(int);
15260         i_step = (*n_particles) * (*n_values_per_frame);
15261         for(i=*n_frames; i--;)
15262         {
15263             for(j=*n_particles; j--;)
15264             {
15265                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15266                 for(k=*n_values_per_frame; k--;)
15267                 {
15268                     (*values)[i][mapping][k].i = *(int *)
15269                                                  ((char *)data->values + size *
15270                                                  (i * i_step + j *
15271                                                   (*n_values_per_frame) + k));
15272                 }
15273             }
15274         }
15275         break;
15276     case TNG_FLOAT_DATA:
15277         size = sizeof(float);
15278         i_step = (*n_particles) * (*n_values_per_frame);
15279         for(i=*n_frames; i--;)
15280         {
15281             for(j=*n_particles; j--;)
15282             {
15283                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15284                 for(k=*n_values_per_frame; k--;)
15285                 {
15286                     (*values)[i][mapping][k].f = *(float *)
15287                                                  ((char *)data->values + size *
15288                                                  (i * i_step + j *
15289                                                   (*n_values_per_frame) + k));
15290                 }
15291             }
15292         }
15293         break;
15294     case TNG_DOUBLE_DATA:
15295     default:
15296         size = sizeof(double);
15297         i_step = (*n_particles) * (*n_values_per_frame);
15298         for(i=*n_frames; i--;)
15299         {
15300             for(j=*n_particles; j--;)
15301             {
15302                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15303                 for(k=*n_values_per_frame; k--;)
15304                 {
15305                     (*values)[i][mapping][k].d = *(double *)
15306                                                  ((char *)data->values + size *
15307                                                  (i * i_step + j *
15308                                                   (*n_values_per_frame) + k));
15309                 }
15310             }
15311         }
15312     }
15313
15314     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15315
15316     return(TNG_SUCCESS);
15317 }
15318
15319 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
15320                 (tng_trajectory_t tng_data,
15321                  const int64_t block_id,
15322                  void **values,
15323                  int64_t *n_frames,
15324                  int64_t *stride_length,
15325                  int64_t *n_particles,
15326                  int64_t *n_values_per_frame,
15327                  char *type)
15328 {
15329     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
15330     int64_t block_index;
15331     int size;
15332     tng_particle_data_t data;
15333     tng_trajectory_frame_set_t frame_set;
15334     tng_gen_block_t block;
15335     void *temp;
15336     char block_type_flag;
15337     tng_function_status stat;
15338
15339     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15340     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15341     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15342     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15343     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15344
15345     frame_set = &tng_data->current_trajectory_frame_set;
15346
15347     block_index = -1;
15348     data = 0;
15349
15350     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15351     {
15352         tng_block_init(&block);
15353         file_pos = ftell(tng_data->input_file);
15354         /* Read all blocks until next frame set block */
15355         stat = tng_block_header_read(tng_data, block);
15356         while(file_pos < tng_data->input_file_len &&
15357                 stat != TNG_CRITICAL &&
15358                 block->id != TNG_TRAJECTORY_FRAME_SET)
15359         {
15360             /* Use hash by default */
15361             stat = tng_block_read_next(tng_data, block,
15362                                     TNG_USE_HASH);
15363             if(stat != TNG_CRITICAL)
15364             {
15365                 file_pos = ftell(tng_data->input_file);
15366                 if(file_pos < tng_data->input_file_len)
15367                 {
15368                     stat = tng_block_header_read(tng_data, block);
15369                 }
15370             }
15371         }
15372         tng_block_destroy(&block);
15373         if(stat == TNG_CRITICAL)
15374         {
15375             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15376                     file_pos, __FILE__, __LINE__);
15377             return(stat);
15378         }
15379
15380         for(i = frame_set->n_particle_data_blocks; i-- ;)
15381         {
15382             data = &frame_set->tr_particle_data[i];
15383             if(data->block_id == block_id)
15384             {
15385                 block_index = i;
15386                 break;
15387             }
15388         }
15389         if(block_index < 0)
15390         {
15391             return(TNG_FAILURE);
15392         }
15393     }
15394
15395     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15396     {
15397         block_type_flag = TNG_TRAJECTORY_BLOCK;
15398     }
15399     else
15400     {
15401         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15402     }
15403
15404    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15405       tng_data->var_num_atoms_flag)
15406     {
15407         *n_particles = frame_set->n_particles;
15408     }
15409     else
15410     {
15411         *n_particles = tng_data->n_particles;
15412     }
15413
15414     *type = data->datatype;
15415
15416     switch(*type)
15417     {
15418     case TNG_CHAR_DATA:
15419         return(TNG_FAILURE);
15420     case TNG_INT_DATA:
15421         size = sizeof(int64_t);
15422         break;
15423     case TNG_FLOAT_DATA:
15424         size = sizeof(float);
15425         break;
15426     case TNG_DOUBLE_DATA:
15427     default:
15428         size = sizeof(double);
15429     }
15430
15431     *n_frames = tng_max_i64(1, data->n_frames);
15432     *n_values_per_frame = data->n_values_per_frame;
15433     *stride_length = data->stride_length;
15434
15435     n_frames_div = (*n_frames % *stride_length) ?
15436                    *n_frames / *stride_length + 1:
15437                    *n_frames / *stride_length;
15438
15439     data_size = n_frames_div * size * (*n_particles) *
15440                 (*n_values_per_frame);
15441
15442     temp = realloc(*values, data_size);
15443     if(!temp)
15444     {
15445         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15446                data_size, __FILE__, __LINE__);
15447         free(*values);
15448         *values = 0;
15449         return(TNG_CRITICAL);
15450     }
15451
15452     *values = temp;
15453
15454     if(frame_set->n_mapping_blocks <= 0)
15455     {
15456         memcpy(*values, data->values, data_size);
15457     }
15458     else
15459     {
15460         i_step = (*n_particles) * (*n_values_per_frame);
15461         for(i = *n_frames; i--;)
15462         {
15463             for(j = *n_particles; j--;)
15464             {
15465                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15466                 memcpy(((char *)*values) + size * (i * i_step + mapping *
15467                        (*n_values_per_frame)),
15468                        (char *)data->values + size *
15469                        (i * i_step + j * (*n_values_per_frame)),
15470                        size * (*n_values_per_frame));
15471             }
15472         }
15473     }
15474
15475     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15476
15477     return(TNG_SUCCESS);
15478 }
15479
15480 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
15481                 (tng_trajectory_t tng_data,
15482                  const int64_t block_id,
15483                  const int64_t start_frame_nr,
15484                  const int64_t end_frame_nr,
15485                  const char hash_mode,
15486                  union data_values ****values,
15487                  int64_t *n_particles,
15488                  int64_t *n_values_per_frame,
15489                  char *type)
15490 {
15491     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
15492     int64_t first_frame, block_index;
15493     int size;
15494     size_t len;
15495     tng_particle_data_t data;
15496     tng_trajectory_frame_set_t frame_set;
15497     tng_gen_block_t block;
15498     char block_type_flag;
15499     tng_function_status stat;
15500
15501     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15502     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15503     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15504     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15505     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15506
15507     block_index = -1;
15508
15509     frame_set = &tng_data->current_trajectory_frame_set;
15510     first_frame = frame_set->first_frame;
15511
15512     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15513     if(stat != TNG_SUCCESS)
15514     {
15515         return(stat);
15516     }
15517
15518     /* Do not re-read the frame set. */
15519     if(first_frame != frame_set->first_frame ||
15520        frame_set->n_particle_data_blocks <= 0)
15521     {
15522         tng_block_init(&block);
15523         file_pos = ftell(tng_data->input_file);
15524         /* Read all blocks until next frame set block */
15525         stat = tng_block_header_read(tng_data, block);
15526         while(file_pos < tng_data->input_file_len &&
15527                 stat != TNG_CRITICAL &&
15528                 block->id != TNG_TRAJECTORY_FRAME_SET)
15529         {
15530             stat = tng_block_read_next(tng_data, block,
15531                                     hash_mode);
15532             if(stat != TNG_CRITICAL)
15533             {
15534                 file_pos = ftell(tng_data->input_file);
15535                 if(file_pos < tng_data->input_file_len)
15536                 {
15537                     stat = tng_block_header_read(tng_data, block);
15538                 }
15539             }
15540         }
15541         tng_block_destroy(&block);
15542         if(stat == TNG_CRITICAL)
15543         {
15544             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15545                     file_pos, __FILE__, __LINE__);
15546             return(stat);
15547         }
15548     }
15549
15550     /* See if there is already a data block of this ID.
15551      * Start checking the last read frame set */
15552     for(i = frame_set->n_particle_data_blocks; i-- ;)
15553     {
15554         data = &frame_set->tr_particle_data[i];
15555         if(data->block_id == block_id)
15556         {
15557             block_index = i;
15558             block_type_flag = TNG_TRAJECTORY_BLOCK;
15559             break;
15560         }
15561     }
15562
15563     if(block_index < 0)
15564     {
15565         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
15566                 block_id, __FILE__, __LINE__);
15567         return(TNG_FAILURE);
15568     }
15569
15570     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15571        tng_data->var_num_atoms_flag)
15572     {
15573         *n_particles = frame_set->n_particles;
15574     }
15575     else
15576     {
15577         *n_particles = tng_data->n_particles;
15578     }
15579
15580     n_frames = end_frame_nr - start_frame_nr + 1;
15581     *n_values_per_frame = data->n_values_per_frame;
15582     *type = data->datatype;
15583
15584     if(*values == 0)
15585     {
15586         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
15587                                          *n_particles, *n_values_per_frame,
15588                                          *type)
15589             != TNG_SUCCESS)
15590         {
15591             return(TNG_CRITICAL);
15592         }
15593     }
15594
15595     current_frame_pos = start_frame_nr - frame_set->first_frame;
15596     /* It's not very elegant to reuse so much of the code in the different case
15597      * statements, but it's unnecessarily slow to have the switch-case block
15598      * inside the for loops. */
15599     switch(*type)
15600     {
15601     case TNG_CHAR_DATA:
15602         for(i=0; i<n_frames; i++)
15603         {
15604             if(current_frame_pos == frame_set->n_frames)
15605             {
15606                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15607                 if(stat != TNG_SUCCESS)
15608                 {
15609                     return(stat);
15610                 }
15611                 current_frame_pos = 0;
15612             }
15613             for(j=*n_particles; j--;)
15614             {
15615                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15616                 for(k=*n_values_per_frame; k--;)
15617                 {
15618                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
15619                     (*values)[i][mapping][k].c = malloc(len);
15620                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
15621                 }
15622             }
15623             current_frame_pos++;
15624         }
15625         break;
15626     case TNG_INT_DATA:
15627         size = sizeof(int);
15628         i_step = (*n_particles) * (*n_values_per_frame);
15629         for(i=0; i<n_frames; i++)
15630         {
15631             if(current_frame_pos == frame_set->n_frames)
15632             {
15633                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15634                 if(stat != TNG_SUCCESS)
15635                 {
15636                     return(stat);
15637                 }
15638                 current_frame_pos = 0;
15639             }
15640             for(j=*n_particles; j--;)
15641             {
15642                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15643                 for(k=*n_values_per_frame; k--;)
15644                 {
15645                     (*values)[i][mapping][k].i = *(int *)
15646                                                  ((char *)data->values + size *
15647                                                   (current_frame_pos *
15648                                                    i_step + j *
15649                                                    (*n_values_per_frame) + k));
15650                 }
15651             }
15652             current_frame_pos++;
15653         }
15654         break;
15655     case TNG_FLOAT_DATA:
15656         size = sizeof(float);
15657         i_step = (*n_particles) * (*n_values_per_frame);
15658         for(i=0; i<n_frames; i++)
15659         {
15660             if(current_frame_pos == frame_set->n_frames)
15661             {
15662                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15663                 if(stat != TNG_SUCCESS)
15664                 {
15665                     return(stat);
15666                 }
15667                 current_frame_pos = 0;
15668             }
15669             for(j=*n_particles; j--;)
15670             {
15671                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15672                 for(k=*n_values_per_frame; k--;)
15673                 {
15674                     (*values)[i][mapping][k].f = *(float *)
15675                                                  ((char *)data->values + size *
15676                                                   (current_frame_pos *
15677                                                    i_step + j *
15678                                                    (*n_values_per_frame) + k));
15679                 }
15680             }
15681             current_frame_pos++;
15682         }
15683         break;
15684     case TNG_DOUBLE_DATA:
15685     default:
15686         size = sizeof(double);
15687         i_step = (*n_particles) * (*n_values_per_frame);
15688         for(i=0; i<n_frames; i++)
15689         {
15690             if(current_frame_pos == frame_set->n_frames)
15691             {
15692                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15693                 if(stat != TNG_SUCCESS)
15694                 {
15695                     return(stat);
15696                 }
15697                 current_frame_pos = 0;
15698             }
15699             for(j=*n_particles; j--;)
15700             {
15701                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15702                 for(k=*n_values_per_frame; k--;)
15703                 {
15704                     (*values)[i][mapping][k].d = *(double *)
15705                                                  ((char *)data->values + size *
15706                                                   (current_frame_pos *
15707                                                    i_step + j *
15708                                                    (*n_values_per_frame) + k));
15709                 }
15710             }
15711             current_frame_pos++;
15712         }
15713     }
15714
15715     data->last_retrieved_frame = end_frame_nr;
15716
15717     return(TNG_SUCCESS);
15718 }
15719
15720 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
15721                 (tng_trajectory_t tng_data,
15722                  const int64_t block_id,
15723                  const int64_t start_frame_nr,
15724                  const int64_t end_frame_nr,
15725                  const char hash_mode,
15726                  void **values,
15727                  int64_t *n_particles,
15728                  int64_t *stride_length,
15729                  int64_t *n_values_per_frame,
15730                  char *type)
15731 {
15732     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15733     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
15734     int size;
15735     tng_trajectory_frame_set_t frame_set;
15736     tng_particle_data_t p_data;
15737     tng_gen_block_t block;
15738     void *current_values = 0, *temp;
15739     tng_function_status stat;
15740
15741     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15742     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15743     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15744     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15745     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15746     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15747
15748     frame_set = &tng_data->current_trajectory_frame_set;
15749     first_frame = frame_set->first_frame;
15750
15751     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15752     if(stat != TNG_SUCCESS)
15753     {
15754         return(stat);
15755     }
15756
15757     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
15758     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
15759     stat = tng_particle_data_find(tng_data, block_id, &p_data);
15760     if(first_frame != frame_set->first_frame ||
15761        stat != TNG_SUCCESS)
15762     {
15763         tng_block_init(&block);
15764         if(stat != TNG_SUCCESS)
15765         {
15766             fseek(tng_data->input_file,
15767                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
15768                   SEEK_SET);
15769             stat = tng_block_header_read(tng_data, block);
15770             if(stat != TNG_SUCCESS)
15771             {
15772                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15773                         __FILE__, __LINE__);
15774                 return(stat);
15775             }
15776
15777             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15778         }
15779         file_pos = ftell(tng_data->input_file);
15780         /* Read until next frame set block */
15781         stat = tng_block_header_read(tng_data, block);
15782         while(file_pos < tng_data->input_file_len &&
15783             stat != TNG_CRITICAL &&
15784             block->id != TNG_TRAJECTORY_FRAME_SET)
15785         {
15786             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
15787             {
15788                 stat = tng_block_read_next(tng_data, block,
15789                                         hash_mode);
15790                 if(stat != TNG_CRITICAL)
15791                 {
15792                     file_pos = ftell(tng_data->input_file);
15793                     if(file_pos < tng_data->input_file_len)
15794                     {
15795                         stat = tng_block_header_read(tng_data, block);
15796                     }
15797                 }
15798             }
15799             else
15800             {
15801                 file_pos += block->block_contents_size + block->header_contents_size;
15802                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15803                 if(file_pos < tng_data->input_file_len)
15804                 {
15805                     stat = tng_block_header_read(tng_data, block);
15806                 }
15807             }
15808         }
15809         tng_block_destroy(&block);
15810         if(stat == TNG_CRITICAL)
15811         {
15812             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15813                     file_pos, __FILE__, __LINE__);
15814             return(stat);
15815         }
15816     }
15817     stat = tng_particle_data_find(tng_data, block_id, &p_data);
15818     if(stat != TNG_SUCCESS)
15819     {
15820         return(stat);
15821     }
15822
15823     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
15824                                         &n_frames, stride_length, n_particles,
15825                                         n_values_per_frame, type);
15826
15827     if(stat != TNG_SUCCESS || *n_particles == 0)
15828     {
15829         if(current_values)
15830         {
15831             free(current_values);
15832         }
15833         return(stat);
15834     }
15835
15836     if(n_frames == 1 && n_frames < frame_set->n_frames)
15837     {
15838         tot_n_frames = 1;
15839     }
15840     else
15841     {
15842         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15843     }
15844
15845     switch(*type)
15846     {
15847     case TNG_CHAR_DATA:
15848         return(TNG_FAILURE);
15849     case TNG_INT_DATA:
15850         size = sizeof(int64_t);
15851         break;
15852     case TNG_FLOAT_DATA:
15853         size = sizeof(float);
15854         break;
15855     case TNG_DOUBLE_DATA:
15856     default:
15857         size = sizeof(double);
15858     }
15859
15860     n_frames_div = (tot_n_frames % *stride_length) ?
15861                  tot_n_frames / *stride_length + 1:
15862                  tot_n_frames / *stride_length;
15863
15864     data_size = n_frames_div * size * (*n_particles) *
15865                 (*n_values_per_frame);
15866
15867     temp = realloc(*values, data_size);
15868     if(!temp)
15869     {
15870         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15871                data_size, __FILE__, __LINE__);
15872         free(*values);
15873         *values = 0;
15874         return(TNG_CRITICAL);
15875     }
15876
15877     *values = temp;
15878
15879     if( n_frames == 1 && n_frames < frame_set->n_frames)
15880     {
15881         memcpy(*values, current_values, size * (*n_particles) *
15882                (*n_values_per_frame));
15883     }
15884     else
15885     {
15886         current_frame_pos = start_frame_nr - frame_set->first_frame;
15887
15888         frame_size = size * (*n_particles) * (*n_values_per_frame);
15889
15890         last_frame_pos = tng_min_i64(n_frames,
15891                                      end_frame_nr - start_frame_nr);
15892
15893         n_frames_div = current_frame_pos / *stride_length;
15894         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15895                        last_frame_pos / *stride_length + 1:
15896                        last_frame_pos / *stride_length;
15897         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
15898
15899         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15900                n_frames_div_2 * frame_size);
15901
15902         current_frame_pos += n_frames - current_frame_pos;
15903
15904         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15905         {
15906             stat = tng_frame_set_read_next(tng_data, hash_mode);
15907             if(stat != TNG_SUCCESS)
15908             {
15909                 if(current_values)
15910                 {
15911                     free(current_values);
15912                 }
15913                 free(*values);
15914                 *values = 0;
15915                 return(stat);
15916             }
15917
15918             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
15919                                                 &n_frames, stride_length, n_particles,
15920                                                 n_values_per_frame, type);
15921
15922             if(stat != TNG_SUCCESS)
15923             {
15924                 if(current_values)
15925                 {
15926                     free(current_values);
15927                 }
15928                 free(*values);
15929                 *values = 0;
15930                 return(stat);
15931             }
15932
15933             last_frame_pos = tng_min_i64(n_frames,
15934                                          end_frame_nr - current_frame_pos);
15935
15936             n_frames_div = current_frame_pos / *stride_length;
15937             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15938                            last_frame_pos / *stride_length + 1:
15939                            last_frame_pos / *stride_length;
15940             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15941
15942             memcpy(((char *)*values) + n_frames_div * frame_size,
15943                    current_values,
15944                    n_frames_div_2 * frame_size);
15945
15946             current_frame_pos += n_frames;
15947         }
15948     }
15949
15950     if(current_values)
15951     {
15952         free(current_values);
15953     }
15954
15955     p_data->last_retrieved_frame = end_frame_nr;
15956
15957     return(TNG_SUCCESS);
15958 }
15959
15960 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
15961                 (tng_trajectory_t tng_data,
15962                  const int64_t block_id,
15963                  int64_t frame,
15964                  int64_t *stride_length)
15965 {
15966     tng_function_status stat;
15967     tng_non_particle_data_t np_data;
15968     tng_particle_data_t p_data;
15969     long file_pos;
15970     int is_particle_data;
15971
15972     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
15973     {
15974         frame = 0;
15975     }
15976
15977     if(frame >= 0)
15978     {
15979         stat = tng_frame_set_of_frame_find(tng_data, frame);
15980         if(stat != TNG_SUCCESS)
15981         {
15982             return(stat);
15983         }
15984     }
15985     stat = tng_data_find(tng_data, block_id, &np_data);
15986     if(stat != TNG_SUCCESS)
15987     {
15988         stat = tng_particle_data_find(tng_data, block_id, &p_data);
15989         if(stat != TNG_SUCCESS)
15990         {
15991             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15992             /* If no specific frame was required read until this data block is found */
15993             if(frame < 0)
15994             {
15995                 file_pos = ftell(tng_data->input_file);
15996                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15997                 {
15998                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15999                     file_pos = ftell(tng_data->input_file);
16000                 }
16001             }
16002             if(stat != TNG_SUCCESS)
16003             {
16004                 return(stat);
16005             }
16006             stat = tng_data_find(tng_data, block_id, &np_data);
16007             if(stat != TNG_SUCCESS)
16008             {
16009                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16010                 if(stat != TNG_SUCCESS)
16011                 {
16012                     return(stat);
16013                 }
16014                 else
16015                 {
16016                     is_particle_data = 1;
16017                 }
16018             }
16019             else
16020             {
16021                 is_particle_data = 0;
16022             }
16023         }
16024         else
16025         {
16026             is_particle_data = 1;
16027         }
16028     }
16029     else
16030     {
16031         is_particle_data = 0;
16032     }
16033     if(is_particle_data)
16034     {
16035         *stride_length = p_data->stride_length;
16036     }
16037     else
16038     {
16039         *stride_length = np_data->stride_length;
16040     }
16041     return(TNG_SUCCESS);
16042 }
16043
16044 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16045                 (const tng_trajectory_t tng_data,
16046                  char *time)
16047 {
16048     struct tm *time_data;
16049     time_t secs;
16050
16051     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16052     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16053
16054     secs = tng_data->time;
16055
16056     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16057     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16058              "%4d-%02d-%02d %02d:%02d:%02d",
16059              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16060              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16061
16062     return(TNG_SUCCESS);
16063 }
16064
16065
16066 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16067                 (const char *filename,
16068                  const char mode,
16069                  tng_trajectory_t *tng_data_p)
16070 {
16071     tng_function_status stat;
16072
16073     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16074
16075     if(mode != 'r' && mode != 'w' && mode != 'a')
16076     {
16077         return(TNG_FAILURE);
16078     }
16079
16080     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16081     {
16082         tng_trajectory_destroy(tng_data_p);
16083         return(TNG_CRITICAL);
16084     }
16085
16086     if(mode == 'r' || mode == 'a')
16087     {
16088         tng_input_file_set(*tng_data_p, filename);
16089
16090         /* Read the file headers */
16091         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16092
16093         tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16094     }
16095
16096     if(mode == 'w')
16097     {
16098         tng_output_file_set(*tng_data_p, filename);
16099     }
16100     else if(mode == 'a')
16101     {
16102         fseek((*tng_data_p)->input_file,
16103                 (long)(*tng_data_p)->last_trajectory_frame_set_input_file_pos,
16104                 SEEK_SET);
16105
16106         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
16107         if(stat != TNG_SUCCESS)
16108         {
16109             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
16110                    __FILE__, __LINE__);
16111         }
16112
16113         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
16114         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
16115         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
16116         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
16117         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
16118         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
16119         (*tng_data_p)->first_trajectory_frame_set_input_file_pos = -1;
16120         (*tng_data_p)->last_trajectory_frame_set_input_file_pos = -1;
16121         (*tng_data_p)->current_trajectory_frame_set_input_file_pos = -1;
16122         if((*tng_data_p)->input_file)
16123         {
16124             fclose((*tng_data_p)->input_file);
16125             (*tng_data_p)->input_file = 0;
16126         }
16127         if((*tng_data_p)->input_file_path)
16128         {
16129             free((*tng_data_p)->input_file_path);
16130             (*tng_data_p)->input_file_path = 0;
16131         }
16132         tng_output_append_file_set(*tng_data_p, filename);
16133
16134         fseek((*tng_data_p)->output_file, 0, SEEK_END);
16135     }
16136
16137     return(TNG_SUCCESS);
16138 }
16139
16140 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
16141                 (tng_trajectory_t *tng_data_p)
16142 {
16143     tng_trajectory_frame_set_t frame_set;
16144
16145     if(tng_data_p == 0)
16146     {
16147         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
16148                __FILE__, __LINE__);
16149         return(TNG_FAILURE);
16150     }
16151
16152     if(*tng_data_p == 0)
16153     {
16154         return(TNG_SUCCESS);
16155     }
16156
16157     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
16158
16159     if(frame_set->n_unwritten_frames > 0)
16160     {
16161         frame_set->n_frames = frame_set->n_unwritten_frames;
16162         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
16163     }
16164
16165     return(tng_trajectory_destroy(tng_data_p));
16166 }
16167
16168 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
16169                 (tng_trajectory_t tng_data,
16170                  const int64_t frame_nr,
16171                  double *time)
16172 {
16173     int64_t first_frame;
16174     tng_trajectory_frame_set_t frame_set;
16175     tng_function_status stat;
16176
16177     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16178     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16179
16180     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
16181     if(stat != TNG_SUCCESS)
16182     {
16183         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
16184                frame_nr, __FILE__, __LINE__);
16185         return(stat);
16186     }
16187
16188     frame_set = &tng_data->current_trajectory_frame_set;
16189     first_frame = frame_set->first_frame;
16190
16191     if(tng_data->time_per_frame <= 0)
16192     {
16193         return(TNG_FAILURE);
16194     }
16195
16196     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
16197
16198     return(TNG_SUCCESS);
16199 }
16200
16201 /*
16202 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
16203                 (tng_trajectory_t tng_data,
16204                  int64_t *n_mols,
16205                  int64_t **molecule_cnt_list,
16206                  tng_molecule_t *mols)
16207 {
16208     tng_trajectory_frame_set_t frame_set;
16209
16210     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16211     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
16212
16213     *n_mols = tng_data->n_molecules;
16214
16215     frame_set = &tng_data->current_trajectory_frame_set;
16216     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
16217     {
16218         *molecule_cnt_list = frame_set->molecule_cnt_list;
16219     }
16220     else
16221     {
16222         *molecule_cnt_list = tng_data->molecule_cnt_list;
16223     }
16224
16225     *mols = tng_data->molecules;
16226
16227     return(TNG_SUCCESS);
16228 }
16229 */
16230 /*
16231 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
16232                 (tng_trajectory_t tng_data,
16233                  const char *name,
16234                  const int64_t cnt,
16235                  tng_molecule_t *mol)
16236 {
16237     tng_function_status stat;
16238
16239     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
16240     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
16241
16242     stat = tng_molecule_add(tng_data, name, mol);
16243     if(stat != TNG_SUCCESS)
16244     {
16245         return(stat);
16246     }
16247     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
16248
16249     return(stat);
16250 }
16251 */
16252 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
16253                 (tng_trajectory_t tng_data,
16254                  const tng_molecule_t mol,
16255                  int64_t *n_particles,
16256                  char ***names,
16257                  char ***types,
16258                  char ***res_names,
16259                  int64_t **res_ids,
16260                  char ***chain_names,
16261                  int64_t **chain_ids)
16262 {
16263     tng_atom_t atom;
16264     tng_residue_t res;
16265     tng_chain_t chain;
16266     int64_t i;
16267     (void)tng_data;
16268
16269     *n_particles = mol->n_atoms;
16270
16271     *names = malloc(sizeof(char *) * *n_particles);
16272     *types = malloc(sizeof(char *) * *n_particles);
16273     *res_names = malloc(sizeof(char *) * *n_particles);
16274     *chain_names = malloc(sizeof(char *) * *n_particles);
16275     *res_ids = malloc(sizeof(int64_t) * *n_particles);
16276     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
16277
16278     for(i = 0; i < *n_particles; i++)
16279     {
16280         atom = &mol->atoms[i];
16281         res = atom->residue;
16282         chain = res->chain;
16283         (*names)[i] = malloc(strlen(atom->name));
16284         strcpy(*names[i], atom->name);
16285         (*types)[i] = malloc(strlen(atom->atom_type));
16286         strcpy(*types[i], atom->atom_type);
16287         (*res_names)[i] = malloc(strlen(res->name));
16288         strcpy(*res_names[i], res->name);
16289         (*chain_names)[i] = malloc(strlen(chain->name));
16290         strcpy(*chain_names[i], chain->name);
16291         (*res_ids)[i] = res->id;
16292         (*chain_ids)[i] = chain->id;
16293     }
16294
16295     return(TNG_SUCCESS);
16296 }
16297
16298 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
16299                 (tng_trajectory_t tng_data,
16300                  tng_molecule_t mol,
16301                  const int64_t n_particles,
16302                  const char **names,
16303                  const char **types,
16304                  const char **res_names,
16305                  const int64_t *res_ids,
16306                  const char **chain_names,
16307                  const int64_t *chain_ids)
16308 {
16309     int64_t i;
16310     tng_chain_t chain;
16311     tng_residue_t residue;
16312     tng_atom_t atom;
16313     tng_function_status stat;
16314
16315     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16316     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
16317     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
16318     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
16319     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
16320     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
16321     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
16322
16323     for(i = 0; i < n_particles; i++)
16324     {
16325         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
16326            &chain) == TNG_FAILURE)
16327         {
16328             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
16329                                           &chain);
16330             if(stat != TNG_SUCCESS)
16331             {
16332                 return(stat);
16333             }
16334         }
16335         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
16336            &residue) == TNG_FAILURE)
16337         {
16338             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
16339                                          &residue);
16340             if(stat != TNG_SUCCESS)
16341             {
16342                 return(stat);
16343             }
16344         }
16345         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
16346         if(stat != TNG_SUCCESS)
16347         {
16348             return(stat);
16349         }
16350     }
16351     return(TNG_SUCCESS);
16352 }
16353
16354 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
16355                 (tng_trajectory_t tng_data,
16356                  float **positions, int64_t *stride_length)
16357 {
16358     int64_t n_frames, n_particles, n_values_per_frame;
16359     char type;
16360     tng_function_status stat;
16361
16362     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16363     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16364     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16365
16366     stat = tng_num_frames_get(tng_data, &n_frames);
16367     if(stat != TNG_SUCCESS)
16368     {
16369         return(stat);
16370     }
16371
16372     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
16373                                                  0, n_frames - 1, TNG_USE_HASH,
16374                                                  (void **)positions,
16375                                                  &n_particles,
16376                                                  stride_length,
16377                                                  &n_values_per_frame,
16378                                                  &type);
16379
16380     return(stat);
16381 }
16382
16383 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
16384                 (tng_trajectory_t tng_data,
16385                  float **velocities, int64_t *stride_length)
16386 {
16387     int64_t n_frames, n_particles, n_values_per_frame;
16388     char type;
16389     tng_function_status stat;
16390
16391     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16392     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16393     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16394
16395     stat = tng_num_frames_get(tng_data, &n_frames);
16396     if(stat != TNG_SUCCESS)
16397     {
16398         return(stat);
16399     }
16400
16401     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
16402                                                  0, n_frames - 1, TNG_USE_HASH,
16403                                                  (void **)velocities,
16404                                                  &n_particles,
16405                                                  stride_length,
16406                                                  &n_values_per_frame,
16407                                                  &type);
16408
16409     return(stat);
16410 }
16411
16412 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
16413                 (tng_trajectory_t tng_data,
16414                  float **forces, int64_t *stride_length)
16415 {
16416     int64_t n_frames, n_particles, n_values_per_frame;
16417     char type;
16418     tng_function_status stat;
16419
16420     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16421     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
16422     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16423
16424     stat = tng_num_frames_get(tng_data, &n_frames);
16425     if(stat != TNG_SUCCESS)
16426     {
16427         return(stat);
16428     }
16429
16430     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16431                                                  0, n_frames - 1, TNG_USE_HASH,
16432                                                  (void **)forces,
16433                                                  &n_particles,
16434                                                  stride_length,
16435                                                  &n_values_per_frame,
16436                                                  &type);
16437
16438     return(stat);
16439 }
16440
16441 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
16442                 (tng_trajectory_t tng_data,
16443                  float **box_shape,
16444                  int64_t *stride_length)
16445 {
16446     int64_t n_frames, n_values_per_frame;
16447     char type;
16448     tng_function_status stat;
16449
16450     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16451     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16452     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16453
16454     stat = tng_num_frames_get(tng_data, &n_frames);
16455     if(stat != TNG_SUCCESS)
16456     {
16457         return(stat);
16458     }
16459
16460     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16461                                         0, n_frames - 1, TNG_USE_HASH,
16462                                         (void **)box_shape,
16463                                         stride_length,
16464                                         &n_values_per_frame,
16465                                         &type);
16466
16467     return(stat);
16468 }
16469
16470 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
16471                 (tng_trajectory_t tng_data,
16472                  const int64_t block_id,
16473                  void **values,
16474                  char *data_type,
16475                  int64_t *retrieved_frame_number,
16476                  double *retrieved_time)
16477 {
16478     tng_trajectory_frame_set_t frame_set;
16479     tng_particle_data_t data;
16480     tng_function_status stat;
16481     int size;
16482     int64_t i, data_size, n_particles;
16483     void *temp;
16484     long file_pos;
16485
16486     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16487     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
16488     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
16489     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
16490     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
16491
16492     frame_set = &tng_data->current_trajectory_frame_set;
16493
16494     stat = tng_particle_data_find(tng_data, block_id, &data);
16495     if(stat != TNG_SUCCESS)
16496     {
16497         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16498         file_pos = ftell(tng_data->input_file);
16499         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16500         {
16501             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16502             file_pos = ftell(tng_data->input_file);
16503         }
16504         if(stat != TNG_SUCCESS)
16505         {
16506             return(stat);
16507         }
16508         stat = tng_particle_data_find(tng_data, block_id, &data);
16509         if(stat != TNG_SUCCESS)
16510         {
16511             return(stat);
16512         }
16513     }
16514     if(data->last_retrieved_frame < 0)
16515     {
16516         fseek(tng_data->input_file,
16517               (long)tng_data->first_trajectory_frame_set_input_file_pos,
16518               SEEK_SET);
16519         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
16520         if(stat != TNG_SUCCESS)
16521         {
16522             return(stat);
16523         }
16524         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16525         if(stat != TNG_SUCCESS)
16526         {
16527             return(stat);
16528         }
16529
16530         i = data->first_frame_with_data;
16531     }
16532     else
16533     {
16534         i = data->last_retrieved_frame + data->stride_length;
16535         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
16536         {
16537             stat = tng_frame_set_of_frame_find(tng_data, i);
16538             if(stat != TNG_SUCCESS)
16539             {
16540                 /* If the frame set search found the frame set after the starting
16541                  * frame set there is a gap in the frame sets. So, even if the frame
16542                  * was not found the next frame with data is still in the found
16543                  * frame set. */
16544                 if(stat == TNG_CRITICAL)
16545                 {
16546                     return(stat);
16547                 }
16548                 i = frame_set->first_frame;
16549             }
16550         }
16551         if(data->last_retrieved_frame < frame_set->first_frame)
16552         {
16553             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16554             if(stat != TNG_SUCCESS)
16555             {
16556                 return(stat);
16557             }
16558         }
16559     }
16560     data->last_retrieved_frame = i;
16561     *retrieved_frame_number = i;
16562     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
16563     {
16564         *retrieved_time = frame_set->first_frame_time +
16565                         (i - frame_set->first_frame) *
16566                         tng_data->time_per_frame;
16567     }
16568     else
16569     {
16570         *retrieved_time = 0;
16571     }
16572
16573     if(data->stride_length > 1)
16574     {
16575         i = (i - data->first_frame_with_data) / data->stride_length;
16576     }
16577     else
16578     {
16579         i = (i - frame_set->first_frame);
16580     }
16581
16582     tng_num_particles_get(tng_data, &n_particles);
16583
16584     *data_type = data->datatype;
16585
16586     switch(*data_type)
16587     {
16588     case TNG_CHAR_DATA:
16589         return(TNG_FAILURE);
16590     case TNG_INT_DATA:
16591         size = sizeof(int64_t);
16592         break;
16593     case TNG_FLOAT_DATA:
16594         size = sizeof(float);
16595         break;
16596     case TNG_DOUBLE_DATA:
16597     default:
16598         size = sizeof(double);
16599     }
16600
16601     data_size = size * n_particles * data->n_values_per_frame;
16602
16603 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
16604 //            i, data_size, size, n_particles, data->n_values_per_frame);
16605
16606     temp = realloc(*values, data_size);
16607     if(!temp)
16608     {
16609         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16610                data_size, __FILE__, __LINE__);
16611         free(*values);
16612         *values = 0;
16613         return(TNG_CRITICAL);
16614     }
16615
16616     *values = temp;
16617
16618     memcpy(*values, (char *)data->values + i * data_size, data_size);
16619
16620     return(TNG_SUCCESS);
16621 }
16622
16623 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
16624                 (tng_trajectory_t tng_data,
16625                  const int64_t block_id,
16626                  void **values,
16627                  char *data_type,
16628                  int64_t *retrieved_frame_number,
16629                  double *retrieved_time)
16630 {
16631     tng_trajectory_frame_set_t frame_set;
16632     tng_non_particle_data_t data;
16633     tng_function_status stat;
16634     int size;
16635     int64_t i, data_size;
16636     void *temp;
16637     long file_pos;
16638
16639     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16640     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
16641     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
16642     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
16643     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
16644
16645     frame_set = &tng_data->current_trajectory_frame_set;
16646
16647     stat = tng_data_find(tng_data, block_id, &data);
16648     if(stat != TNG_SUCCESS)
16649     {
16650         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16651         file_pos = ftell(tng_data->input_file);
16652         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16653         {
16654             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16655             file_pos = ftell(tng_data->input_file);
16656         }
16657         if(stat != TNG_SUCCESS)
16658         {
16659             return(stat);
16660         }
16661         stat = tng_data_find(tng_data, block_id, &data);
16662         if(stat != TNG_SUCCESS)
16663         {
16664             return(stat);
16665         }
16666     }
16667     if(data->last_retrieved_frame < 0)
16668     {
16669         fseek(tng_data->input_file,
16670                 (long)tng_data->first_trajectory_frame_set_input_file_pos,
16671                 SEEK_SET);
16672         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
16673         if(stat != TNG_SUCCESS)
16674         {
16675             return(stat);
16676         }
16677         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16678         if(stat != TNG_SUCCESS)
16679         {
16680             return(stat);
16681         }
16682
16683         i = data->first_frame_with_data;
16684     }
16685     else
16686     {
16687         i = data->last_retrieved_frame + data->stride_length;
16688         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
16689         {
16690             stat = tng_frame_set_of_frame_find(tng_data, i);
16691             if(stat != TNG_SUCCESS)
16692             {
16693                 /* If the frame set search found the frame set after the starting
16694                  * frame set there is a gap in the frame sets. So, even if the frame
16695                  * was not found the next frame with data is still in the found
16696                  * frame set. */
16697                 if(stat == TNG_CRITICAL)
16698                 {
16699                     return(stat);
16700                 }
16701                 i = frame_set->first_frame;
16702             }
16703         }
16704         if(data->last_retrieved_frame < frame_set->first_frame)
16705         {
16706             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16707             if(stat != TNG_SUCCESS)
16708             {
16709                 return(stat);
16710             }
16711         }
16712     }
16713     data->last_retrieved_frame = i;
16714     *retrieved_frame_number = i;
16715     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
16716     {
16717         *retrieved_time = frame_set->first_frame_time +
16718                         (i - frame_set->first_frame) *
16719                         tng_data->time_per_frame;
16720     }
16721     else
16722     {
16723         *retrieved_time = 0;
16724     }
16725
16726     if(data->stride_length > 1)
16727     {
16728         i = (i - data->first_frame_with_data) / data->stride_length;
16729     }
16730     else
16731     {
16732         i = (i - frame_set->first_frame);
16733     }
16734
16735     *data_type = data->datatype;
16736
16737     switch(*data_type)
16738     {
16739     case TNG_CHAR_DATA:
16740         return(TNG_FAILURE);
16741     case TNG_INT_DATA:
16742         size = sizeof(int64_t);
16743         break;
16744     case TNG_FLOAT_DATA:
16745         size = sizeof(float);
16746         break;
16747     case TNG_DOUBLE_DATA:
16748     default:
16749         size = sizeof(double);
16750     }
16751
16752     data_size = size * data->n_values_per_frame;
16753
16754     temp = realloc(*values, data_size);
16755     if(!temp)
16756     {
16757         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16758                data_size, __FILE__, __LINE__);
16759         free(*values);
16760         *values = 0;
16761         return(TNG_CRITICAL);
16762     }
16763
16764     *values = temp;
16765
16766     memcpy(*values, (char *)data->values + i * data_size, data_size);
16767
16768     return(TNG_SUCCESS);
16769 }
16770
16771 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
16772                 (tng_trajectory_t tng_data,
16773                  const int64_t first_frame,
16774                  const int64_t last_frame,
16775                  float **positions,
16776                  int64_t *stride_length)
16777 {
16778     int64_t n_particles, n_values_per_frame;
16779     char type;
16780     tng_function_status stat;
16781
16782     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16783     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16784     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16785     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16786
16787     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
16788                                                  first_frame, last_frame,
16789                                                  TNG_USE_HASH,
16790                                                  (void **)positions,
16791                                                  &n_particles,
16792                                                  stride_length,
16793                                                  &n_values_per_frame,
16794                                                  &type);
16795
16796     return(stat);
16797 }
16798
16799 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
16800                 (tng_trajectory_t tng_data,
16801                  const int64_t first_frame,
16802                  const int64_t last_frame,
16803                  float **velocities,
16804                  int64_t *stride_length)
16805 {
16806     int64_t n_particles, n_values_per_frame;
16807     char type;
16808     tng_function_status stat;
16809
16810     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16811     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16812     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16813     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16814
16815     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
16816                                                  first_frame, last_frame,
16817                                                  TNG_USE_HASH,
16818                                                  (void **)velocities,
16819                                                  &n_particles,
16820                                                  stride_length,
16821                                                  &n_values_per_frame,
16822                                                  &type);
16823
16824     return(stat);
16825 }
16826
16827 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
16828                 (tng_trajectory_t tng_data,
16829                  const int64_t first_frame,
16830                  const int64_t last_frame,
16831                  float **forces,
16832                  int64_t *stride_length)
16833 {
16834     int64_t n_particles, n_values_per_frame;
16835     char type;
16836     tng_function_status stat;
16837
16838     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16839     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
16840     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16841     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16842
16843     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16844                                                  first_frame, last_frame,
16845                                                  TNG_USE_HASH,
16846                                                  (void **)forces,
16847                                                  &n_particles,
16848                                                  stride_length,
16849                                                  &n_values_per_frame,
16850                                                  &type);
16851
16852     return(stat);
16853 }
16854
16855 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
16856                 (tng_trajectory_t tng_data,
16857                  const int64_t first_frame,
16858                  const int64_t last_frame,
16859                  float **box_shape,
16860                  int64_t *stride_length)
16861 {
16862     int64_t n_values_per_frame;
16863     char type;
16864     tng_function_status stat;
16865
16866     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16867     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16868     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16869     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16870
16871     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16872                                         first_frame, last_frame,
16873                                         TNG_USE_HASH,
16874                                         (void **)box_shape,
16875                                         stride_length,
16876                                         &n_values_per_frame,
16877                                         &type);
16878
16879     return(stat);
16880 }
16881
16882 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
16883                 (tng_trajectory_t tng_data,
16884                  const int64_t i,
16885                  const int64_t n_values_per_frame,
16886                  const int64_t block_id,
16887                  const char *block_name,
16888                  const char particle_dependency,
16889                  const char compression)
16890 {
16891     tng_trajectory_frame_set_t frame_set;
16892     tng_particle_data_t p_data;
16893     tng_non_particle_data_t np_data;
16894     int64_t n_particles, n_frames;
16895     tng_function_status stat;
16896
16897     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16898     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16899
16900     if(i <= 0)
16901     {
16902         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
16903                i, __FILE__, __LINE__);
16904         return(TNG_FAILURE);
16905     }
16906
16907     frame_set = &tng_data->current_trajectory_frame_set;
16908
16909     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16910     {
16911         n_frames = tng_data->frame_set_n_frames;
16912
16913         stat = tng_frame_set_new(tng_data, 0, n_frames);
16914         if(stat != TNG_SUCCESS)
16915         {
16916             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
16917                 __LINE__);
16918             return(stat);
16919         }
16920     }
16921     else
16922     {
16923         n_frames = frame_set->n_frames;
16924     }
16925
16926     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16927     {
16928         tng_num_particles_get(tng_data, &n_particles);
16929         if(n_particles <= 0)
16930         {
16931             return(TNG_FAILURE);
16932         }
16933
16934         if(tng_particle_data_find(tng_data, block_id, &p_data)
16935         != TNG_SUCCESS)
16936         {
16937             stat = tng_particle_data_block_add(tng_data, block_id,
16938                                                block_name,
16939                                                TNG_FLOAT_DATA,
16940                                                TNG_TRAJECTORY_BLOCK,
16941                                                n_frames, n_values_per_frame, i,
16942                                                0, n_particles,
16943                                                compression, 0);
16944             if(stat != TNG_SUCCESS)
16945             {
16946                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16947                        __FILE__, __LINE__);
16948                 return(stat);
16949             }
16950             p_data = &frame_set->tr_particle_data[frame_set->
16951                                                   n_particle_data_blocks - 1];
16952             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
16953                                                   i, n_particles,
16954                                                   n_values_per_frame);
16955             if(stat != TNG_SUCCESS)
16956             {
16957                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16958                        __FILE__, __LINE__);
16959                 return(stat);
16960             }
16961         }
16962         else
16963         {
16964             if(p_data->stride_length != i)
16965             {
16966                 p_data->stride_length = i;
16967                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
16968                                                       i, n_particles,
16969                                                       n_values_per_frame);
16970                 if(stat != TNG_SUCCESS)
16971                 {
16972                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16973                            __FILE__, __LINE__);
16974                     return(stat);
16975                 }
16976             }
16977         }
16978     }
16979     else
16980     {
16981         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
16982         {
16983             stat = tng_data_block_add(tng_data, block_id, block_name,
16984                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
16985                                       n_frames, n_values_per_frame,
16986                                       i, compression, 0);
16987             if(stat != TNG_SUCCESS)
16988             {
16989                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16990                        __FILE__, __LINE__);
16991                 return(stat);
16992             }
16993             np_data = &frame_set->tr_data[frame_set->
16994                                           n_data_blocks - 1];
16995             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
16996                                          i, n_values_per_frame);
16997             if(stat != TNG_SUCCESS)
16998             {
16999                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17000                        __FILE__, __LINE__);
17001                 return(stat);
17002             }
17003         }
17004         else
17005         {
17006             if(np_data->stride_length != i)
17007             {
17008                 np_data->stride_length = i;
17009                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17010                                              i, n_values_per_frame);
17011                 if(stat != TNG_SUCCESS)
17012                 {
17013                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17014                            __FILE__, __LINE__);
17015                     return(stat);
17016                 }
17017             }
17018         }
17019     }
17020
17021     return(TNG_SUCCESS);
17022 }
17023
17024 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17025                 (tng_trajectory_t tng_data,
17026                  const int64_t i,
17027                  const int64_t n_values_per_frame,
17028                  const int64_t block_id,
17029                  const char *block_name,
17030                  const char particle_dependency,
17031                  const char compression)
17032 {
17033     tng_trajectory_frame_set_t frame_set;
17034     tng_particle_data_t p_data;
17035     tng_non_particle_data_t np_data;
17036     int64_t n_particles, n_frames;
17037     tng_function_status stat;
17038
17039     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17040     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17041
17042     if(i <= 0)
17043     {
17044         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17045                i, __FILE__, __LINE__);
17046         return(TNG_FAILURE);
17047     }
17048
17049     frame_set = &tng_data->current_trajectory_frame_set;
17050
17051     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17052     {
17053         n_frames = tng_data->frame_set_n_frames;
17054
17055         stat = tng_frame_set_new(tng_data, 0, n_frames);
17056         if(stat != TNG_SUCCESS)
17057         {
17058             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17059                 __LINE__);
17060             return(stat);
17061         }
17062     }
17063     else
17064     {
17065         n_frames = frame_set->n_frames;
17066     }
17067
17068     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17069     {
17070         tng_num_particles_get(tng_data, &n_particles);
17071
17072         if(n_particles <= 0)
17073         {
17074             return(TNG_FAILURE);
17075         }
17076
17077         if(tng_particle_data_find(tng_data, block_id, &p_data)
17078         != TNG_SUCCESS)
17079         {
17080             stat = tng_particle_data_block_add(tng_data, block_id,
17081                                             block_name,
17082                                             TNG_DOUBLE_DATA,
17083                                             TNG_TRAJECTORY_BLOCK,
17084                                             n_frames, n_values_per_frame, i,
17085                                             0, n_particles,
17086                                             compression, 0);
17087             if(stat != TNG_SUCCESS)
17088             {
17089                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17090                        __FILE__, __LINE__);
17091                 return(stat);
17092             }
17093             p_data = &frame_set->tr_particle_data[frame_set->
17094                                                   n_particle_data_blocks - 1];
17095             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17096                                                   i, n_particles,
17097                                                   n_values_per_frame);
17098             if(stat != TNG_SUCCESS)
17099             {
17100                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17101                        __FILE__, __LINE__);
17102                 return(stat);
17103             }
17104         }
17105         else
17106         {
17107             p_data->stride_length = i;
17108         }
17109     }
17110     else
17111     {
17112         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17113         {
17114             stat = tng_data_block_add(tng_data, block_id, block_name,
17115                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
17116                                       n_frames, n_values_per_frame,
17117                                       i, compression, 0);
17118             if(stat != TNG_SUCCESS)
17119             {
17120                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17121                        __FILE__, __LINE__);
17122                 return(stat);
17123             }
17124             np_data = &frame_set->tr_data[frame_set->
17125                                           n_data_blocks - 1];
17126             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17127                                          i, n_values_per_frame);
17128             if(stat != TNG_SUCCESS)
17129             {
17130                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17131                        __FILE__, __LINE__);
17132                 return(stat);
17133             }
17134         }
17135         else
17136         {
17137             np_data->stride_length = i;
17138         }
17139     }
17140
17141     return(TNG_SUCCESS);
17142 }
17143
17144 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
17145                 (tng_trajectory_t tng_data,
17146                  const int64_t i,
17147                  const int64_t n_values_per_frame,
17148                  const int64_t block_id,
17149                  const char *block_name,
17150                  const char particle_dependency,
17151                  const char compression)
17152 {
17153     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
17154            "See documentation. %s: %d", __FILE__, __LINE__);
17155     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
17156                                                block_id, block_name,
17157                                                particle_dependency,
17158                                                compression));
17159 }
17160 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
17161                 (tng_trajectory_t tng_data,
17162                  const int64_t i)
17163 {
17164     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17165     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17166
17167     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17168                                                TNG_TRAJ_POSITIONS,
17169                                                "POSITIONS",
17170                                                TNG_PARTICLE_BLOCK_DATA,
17171                                                TNG_TNG_COMPRESSION));
17172 }
17173
17174 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
17175                 (tng_trajectory_t tng_data,
17176                  const int64_t i)
17177 {
17178     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17179     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17180
17181     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
17182                                                       TNG_TRAJ_POSITIONS,
17183                                                       "POSITIONS",
17184                                                       TNG_PARTICLE_BLOCK_DATA,
17185                                                       TNG_TNG_COMPRESSION));
17186 }
17187
17188 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
17189                 (tng_trajectory_t tng_data,
17190                  const int64_t i)
17191 {
17192     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
17193            "See documentation. %s: %d", __FILE__, __LINE__);
17194     return(tng_util_pos_write_interval_set(tng_data, i));
17195 }
17196
17197 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
17198                 (tng_trajectory_t tng_data,
17199                  const int64_t i)
17200 {
17201     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17202     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17203
17204     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17205                                                TNG_TRAJ_VELOCITIES,
17206                                                "VELOCITIES",
17207                                                TNG_PARTICLE_BLOCK_DATA,
17208                                                TNG_TNG_COMPRESSION));
17209 }
17210
17211 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
17212                 (tng_trajectory_t tng_data,
17213                  const int64_t i)
17214 {
17215     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17216     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17217
17218     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
17219                                                       TNG_TRAJ_VELOCITIES,
17220                                                       "VELOCITIES",
17221                                                       TNG_PARTICLE_BLOCK_DATA,
17222                                                       TNG_TNG_COMPRESSION));
17223 }
17224
17225 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
17226                 (tng_trajectory_t tng_data,
17227                  const int64_t i)
17228 {
17229     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
17230            "See documentation. %s: %d", __FILE__, __LINE__);
17231     return(tng_util_vel_write_interval_set(tng_data, i));
17232 }
17233
17234 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
17235                 (tng_trajectory_t tng_data,
17236                  const int64_t i)
17237 {
17238     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17239     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17240
17241     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17242                                                TNG_TRAJ_FORCES,
17243                                                "FORCES",
17244                                                TNG_PARTICLE_BLOCK_DATA,
17245                                                TNG_GZIP_COMPRESSION));
17246 }
17247
17248 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
17249                 (tng_trajectory_t tng_data,
17250                  const int64_t i)
17251 {
17252     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17253     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17254
17255     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
17256                                                       TNG_TRAJ_FORCES,
17257                                                       "FORCES",
17258                                                       TNG_PARTICLE_BLOCK_DATA,
17259                                                       TNG_GZIP_COMPRESSION));
17260 }
17261
17262 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
17263                 (tng_trajectory_t tng_data,
17264                  const int64_t i)
17265 {
17266     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
17267            "See documentation. %s: %d", __FILE__, __LINE__);
17268     return(tng_util_force_write_interval_set(tng_data, i));
17269 }
17270
17271 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
17272                 (tng_trajectory_t tng_data,
17273                  const int64_t i)
17274 {
17275     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17276     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17277
17278     return(tng_util_generic_write_interval_set(tng_data, i, 9,
17279                                                TNG_TRAJ_BOX_SHAPE,
17280                                                "BOX SHAPE",
17281                                                TNG_NON_PARTICLE_BLOCK_DATA,
17282                                                TNG_GZIP_COMPRESSION));
17283 }
17284
17285 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
17286                 (tng_trajectory_t tng_data,
17287                  const int64_t i)
17288 {
17289     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17290     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17291
17292     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
17293                                                       TNG_TRAJ_BOX_SHAPE,
17294                                                       "BOX SHAPE",
17295                                                       TNG_NON_PARTICLE_BLOCK_DATA,
17296                                                       TNG_GZIP_COMPRESSION));
17297 }
17298
17299 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
17300                 (tng_trajectory_t tng_data,
17301                  const int64_t i)
17302 {
17303     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
17304            "See documentation. %s: %d", __FILE__, __LINE__);
17305     return(tng_util_box_shape_write_interval_set(tng_data, i));
17306 }
17307
17308 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
17309                 (tng_trajectory_t tng_data,
17310                  const int64_t frame_nr,
17311                  const float *values,
17312                  const int64_t n_values_per_frame,
17313                  const int64_t block_id,
17314                  const char *block_name,
17315                  const char particle_dependency,
17316                  const char compression)
17317 {
17318     tng_trajectory_frame_set_t frame_set;
17319     tng_particle_data_t p_data;
17320     tng_non_particle_data_t np_data;
17321     int64_t n_particles, n_frames, stride_length = 100, frame_pos;
17322     int64_t last_frame;
17323     int is_first_frame_flag = 0;
17324     char block_type_flag;
17325     tng_function_status stat;
17326
17327     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17328     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17329     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17330
17331     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17332     {
17333         tng_num_particles_get(tng_data, &n_particles);
17334         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
17335     }
17336
17337     if(values == 0)
17338     {
17339         return(TNG_FAILURE);
17340     }
17341
17342     frame_set = &tng_data->current_trajectory_frame_set;
17343
17344     if(frame_nr < 0)
17345     {
17346         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
17347         n_frames = stride_length = 1;
17348     }
17349     else
17350     {
17351         block_type_flag = TNG_TRAJECTORY_BLOCK;
17352
17353         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17354         {
17355             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
17356             if(stat != TNG_SUCCESS)
17357             {
17358                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17359                     __LINE__);
17360                 return(stat);
17361             }
17362         }
17363         last_frame = frame_set->first_frame +
17364                      frame_set->n_frames - 1;
17365         if(frame_nr > last_frame)
17366         {
17367             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
17368             if(stat != TNG_SUCCESS)
17369             {
17370                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
17371                     __LINE__);
17372                 return(stat);
17373             }
17374             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
17375             {
17376                 last_frame = frame_nr - 1;
17377             }
17378             stat = tng_frame_set_new(tng_data, last_frame + 1,
17379                                      tng_data->frame_set_n_frames);
17380             if(stat != TNG_SUCCESS)
17381             {
17382                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17383                     __LINE__);
17384                 return(stat);
17385             }
17386         }
17387         if(frame_set->n_unwritten_frames == 0)
17388         {
17389             is_first_frame_flag = 1;
17390         }
17391         frame_set->n_unwritten_frames = frame_nr -
17392                                         frame_set->first_frame + 1;
17393
17394         n_frames = frame_set->n_frames;
17395     }
17396
17397     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17398     {
17399         if(tng_particle_data_find(tng_data, block_id, &p_data)
17400         != TNG_SUCCESS)
17401         {
17402             stat = tng_particle_data_block_add(tng_data, block_id,
17403                                                block_name,
17404                                                TNG_FLOAT_DATA,
17405                                                block_type_flag,
17406                                                n_frames, n_values_per_frame,
17407                                                stride_length,
17408                                                0, n_particles,
17409                                                compression, 0);
17410             if(stat != TNG_SUCCESS)
17411             {
17412                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17413                        __FILE__, __LINE__);
17414                 return(stat);
17415             }
17416             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17417             {
17418                 p_data = &frame_set->tr_particle_data[frame_set->
17419                                                     n_particle_data_blocks - 1];
17420             }
17421             else
17422             {
17423                 p_data = &tng_data->non_tr_particle_data[tng_data->
17424                                                     n_particle_data_blocks - 1];
17425             }
17426             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17427                                                   stride_length, n_particles,
17428                                                   n_values_per_frame);
17429             if(stat != TNG_SUCCESS)
17430             {
17431                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17432                        __FILE__, __LINE__);
17433                 return(stat);
17434             }
17435         }
17436
17437         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17438         {
17439             stride_length = p_data->stride_length;
17440
17441             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
17442             {
17443                 p_data->first_frame_with_data = frame_nr;
17444                 frame_pos = 0;
17445             }
17446             else
17447             {
17448                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17449             }
17450
17451             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
17452                    n_values_per_frame, values, sizeof(float) *
17453                    n_particles * n_values_per_frame);
17454         }
17455         else
17456         {
17457             memcpy(p_data->values, values, sizeof(float) * n_particles *
17458                    n_values_per_frame);
17459         }
17460     }
17461     else
17462     {
17463         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17464         {
17465             stat = tng_data_block_add(tng_data, block_id, block_name,
17466                                       TNG_FLOAT_DATA, block_type_flag,
17467                                       n_frames, n_values_per_frame,
17468                                       stride_length, compression, 0);
17469             if(stat != TNG_SUCCESS)
17470             {
17471                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17472                        __FILE__, __LINE__);
17473                 return(stat);
17474             }
17475             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17476             {
17477                 np_data = &frame_set->tr_data[frame_set->
17478                                               n_data_blocks - 1];
17479             }
17480             else
17481             {
17482                 np_data = &tng_data->non_tr_data[tng_data->
17483                                                  n_data_blocks - 1];
17484             }
17485             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17486                                          stride_length, n_values_per_frame);
17487             if(stat != TNG_SUCCESS)
17488             {
17489                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17490                        __FILE__, __LINE__);
17491                 return(stat);
17492             }
17493         }
17494
17495         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17496         {
17497             stride_length = np_data->stride_length;
17498
17499             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
17500             {
17501                 np_data->first_frame_with_data = frame_nr;
17502                 frame_pos = 0;
17503             }
17504             else
17505             {
17506                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17507             }
17508
17509             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
17510                    n_values_per_frame, values, sizeof(float) *
17511                    n_values_per_frame);
17512         }
17513         else
17514         {
17515             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
17516         }
17517     }
17518
17519     return(TNG_SUCCESS);
17520 }
17521
17522 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
17523                 (tng_trajectory_t tng_data,
17524                  const int64_t frame_nr,
17525                  const double *values,
17526                  const int64_t n_values_per_frame,
17527                  const int64_t block_id,
17528                  const char *block_name,
17529                  const char particle_dependency,
17530                  const char compression)
17531 {
17532     tng_trajectory_frame_set_t frame_set;
17533     tng_particle_data_t p_data;
17534     tng_non_particle_data_t np_data;
17535     int64_t n_particles, n_frames, stride_length = 100, frame_pos;
17536     int64_t last_frame;
17537     int is_first_frame_flag = 0;
17538     char block_type_flag;
17539     tng_function_status stat;
17540
17541     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17542     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17543     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17544
17545     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17546     {
17547         tng_num_particles_get(tng_data, &n_particles);
17548         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
17549     }
17550
17551     if(values == 0)
17552     {
17553         return(TNG_FAILURE);
17554     }
17555
17556     frame_set = &tng_data->current_trajectory_frame_set;
17557
17558     if(frame_nr < 0)
17559     {
17560         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
17561         n_frames = stride_length = 1;
17562     }
17563     else
17564     {
17565         block_type_flag = TNG_TRAJECTORY_BLOCK;
17566
17567         n_frames = tng_data->frame_set_n_frames;
17568
17569         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17570         {
17571             stat = tng_frame_set_new(tng_data, 0, n_frames);
17572             if(stat != TNG_SUCCESS)
17573             {
17574                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17575                     __LINE__);
17576                 return(stat);
17577             }
17578         }
17579         else
17580         {
17581             n_frames = frame_set->n_frames;
17582         }
17583         last_frame = frame_set->first_frame +
17584                      frame_set->n_frames - 1;
17585         if(frame_nr > last_frame)
17586         {
17587             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
17588             if(stat != TNG_SUCCESS)
17589             {
17590                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
17591                     __LINE__);
17592                 return(stat);
17593             }
17594             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
17595             {
17596                 last_frame = frame_nr - 1;
17597             }
17598             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
17599             if(stat != TNG_SUCCESS)
17600             {
17601                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17602                     __LINE__);
17603                 return(stat);
17604             }
17605         }
17606         if(frame_set->n_unwritten_frames == 0)
17607         {
17608             is_first_frame_flag = 1;
17609         }
17610         frame_set->n_unwritten_frames = frame_nr -
17611                                         frame_set->first_frame + 1;
17612     }
17613
17614     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17615     {
17616         if(tng_particle_data_find(tng_data, block_id, &p_data)
17617         != TNG_SUCCESS)
17618         {
17619             stat = tng_particle_data_block_add(tng_data, block_id,
17620                                             block_name,
17621                                             TNG_DOUBLE_DATA,
17622                                             block_type_flag,
17623                                             n_frames, n_values_per_frame,
17624                                             stride_length,
17625                                             0, n_particles,
17626                                             compression, 0);
17627             if(stat != TNG_SUCCESS)
17628             {
17629                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17630                        __FILE__, __LINE__);
17631                 return(stat);
17632             }
17633             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17634             {
17635                 p_data = &frame_set->tr_particle_data[frame_set->
17636                                                     n_particle_data_blocks - 1];
17637             }
17638             else
17639             {
17640                 p_data = &tng_data->non_tr_particle_data[tng_data->
17641                                                     n_particle_data_blocks - 1];
17642             }
17643             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17644                                                   stride_length, n_particles,
17645                                                   n_values_per_frame);
17646             if(stat != TNG_SUCCESS)
17647             {
17648                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17649                        __FILE__, __LINE__);
17650                 return(stat);
17651             }
17652         }
17653
17654         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17655         {
17656             stride_length = p_data->stride_length;
17657
17658             if(is_first_frame_flag)
17659             {
17660                 p_data->first_frame_with_data = frame_nr;
17661                 frame_pos = 0;
17662             }
17663             else
17664             {
17665                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17666             }
17667
17668             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
17669                    n_values_per_frame, values, sizeof(double) *
17670                    n_particles * n_values_per_frame);
17671         }
17672         else
17673         {
17674             memcpy(p_data->values, values, sizeof(double) * n_particles *
17675                    n_values_per_frame);
17676         }
17677     }
17678     else
17679     {
17680         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17681         {
17682             stat = tng_data_block_add(tng_data, block_id, block_name,
17683                                       TNG_DOUBLE_DATA, block_type_flag,
17684                                       n_frames, n_values_per_frame,
17685                                       stride_length, compression, 0);
17686             if(stat != TNG_SUCCESS)
17687             {
17688                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17689                        __FILE__, __LINE__);
17690                 return(stat);
17691             }
17692             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17693             {
17694                 np_data = &frame_set->tr_data[frame_set->
17695                                               n_data_blocks - 1];
17696             }
17697             else
17698             {
17699                 np_data = &tng_data->non_tr_data[tng_data->
17700                                                  n_data_blocks - 1];
17701             }
17702             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17703                                          stride_length, n_values_per_frame);
17704             if(stat != TNG_SUCCESS)
17705             {
17706                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17707                        __FILE__, __LINE__);
17708                 return(stat);
17709             }
17710         }
17711
17712         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17713         {
17714             stride_length = np_data->stride_length;
17715
17716             if(is_first_frame_flag)
17717             {
17718                 np_data->first_frame_with_data = frame_nr;
17719                 frame_pos = 0;
17720             }
17721             else
17722             {
17723                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17724             }
17725
17726             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
17727                    n_values_per_frame, values, sizeof(double) *
17728                    n_values_per_frame);
17729         }
17730         else
17731         {
17732             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
17733         }
17734     }
17735
17736     return(TNG_SUCCESS);
17737 }
17738
17739 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
17740                 (tng_trajectory_t tng_data,
17741                  const int64_t frame_nr,
17742                  const float *positions)
17743 {
17744     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17745     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17746     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17747
17748     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
17749                                   TNG_TRAJ_POSITIONS, "POSITIONS",
17750                                   TNG_PARTICLE_BLOCK_DATA,
17751                                   TNG_TNG_COMPRESSION));
17752 }
17753
17754 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
17755                 (tng_trajectory_t tng_data,
17756                  const int64_t frame_nr,
17757                  const double *positions)
17758 {
17759     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17760     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17761     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17762
17763     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
17764                                          TNG_TRAJ_POSITIONS, "POSITIONS",
17765                                          TNG_PARTICLE_BLOCK_DATA,
17766                                          TNG_TNG_COMPRESSION));
17767 }
17768
17769 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
17770                 (tng_trajectory_t tng_data,
17771                  const int64_t frame_nr,
17772                  const float *velocities)
17773 {
17774     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17775     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17776     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17777
17778     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
17779                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
17780                                   TNG_PARTICLE_BLOCK_DATA,
17781                                   TNG_TNG_COMPRESSION));
17782 }
17783
17784 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
17785                 (tng_trajectory_t tng_data,
17786                  const int64_t frame_nr,
17787                  const double *velocities)
17788 {
17789     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17790     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17791     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17792
17793     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
17794                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
17795                                          TNG_PARTICLE_BLOCK_DATA,
17796                                          TNG_TNG_COMPRESSION));
17797 }
17798
17799 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
17800                 (tng_trajectory_t tng_data,
17801                  const int64_t frame_nr,
17802                  const float *forces)
17803 {
17804     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17805     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17806     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17807
17808     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
17809                                   TNG_TRAJ_FORCES, "FORCES",
17810                                   TNG_PARTICLE_BLOCK_DATA,
17811                                   TNG_GZIP_COMPRESSION));
17812 }
17813
17814 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
17815                 (tng_trajectory_t tng_data,
17816                  const int64_t frame_nr,
17817                  const double *forces)
17818 {
17819     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17820     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17821     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17822
17823     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
17824                                          TNG_TRAJ_FORCES, "FORCES",
17825                                          TNG_PARTICLE_BLOCK_DATA,
17826                                          TNG_GZIP_COMPRESSION));
17827 }
17828
17829 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
17830                 (tng_trajectory_t tng_data,
17831                  const int64_t frame_nr,
17832                  const float *box_shape)
17833 {
17834     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17835     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17836     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17837
17838     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
17839                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17840                                   TNG_NON_PARTICLE_BLOCK_DATA,
17841                                   TNG_GZIP_COMPRESSION));
17842 }
17843
17844 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
17845                 (tng_trajectory_t tng_data,
17846                  const int64_t frame_nr,
17847                  const double *box_shape)
17848 {
17849     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17850     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17851     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17852
17853     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
17854                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17855                                          TNG_NON_PARTICLE_BLOCK_DATA,
17856                                          TNG_GZIP_COMPRESSION));
17857 }
17858
17859 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
17860                 (tng_trajectory_t tng_data,
17861                  const int64_t frame_nr,
17862                  const double time,
17863                  const float *values,
17864                  const int64_t n_values_per_frame,
17865                  const int64_t block_id,
17866                  const char *block_name,
17867                  const char particle_dependency,
17868                  const char compression)
17869 {
17870     tng_trajectory_frame_set_t frame_set;
17871     tng_function_status stat;
17872
17873     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17874     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17875     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17876     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17877
17878     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
17879                                   block_id, block_name,
17880                                   particle_dependency,
17881                                   compression);
17882
17883     if(stat != TNG_SUCCESS)
17884     {
17885         return(stat);
17886     }
17887
17888     frame_set = &tng_data->current_trajectory_frame_set;
17889
17890     /* first_frame_time is -1 when it is not yet set. */
17891     if(frame_set->first_frame_time < -0.1)
17892     {
17893         if(frame_nr > frame_set->first_frame)
17894         {
17895             stat = tng_frame_set_first_frame_time_set(tng_data,
17896                                                       time -
17897                                                       (frame_nr -
17898                                                        frame_set->first_frame) *
17899                                                       tng_data->time_per_frame);
17900         }
17901         else
17902         {
17903             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17904         }
17905     }
17906     return(stat);
17907 }
17908
17909 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
17910                 (tng_trajectory_t tng_data,
17911                  const int64_t frame_nr,
17912                  const double time,
17913                  const double *values,
17914                  const int64_t n_values_per_frame,
17915                  const int64_t block_id,
17916                  const char *block_name,
17917                  const char particle_dependency,
17918                  const char compression)
17919 {
17920     tng_trajectory_frame_set_t frame_set;
17921     tng_function_status stat;
17922
17923     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17924     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17925     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17926     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17927
17928     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
17929                                          block_id, block_name,
17930                                          particle_dependency,
17931                                          compression);
17932
17933     if(stat != TNG_SUCCESS)
17934     {
17935         return(stat);
17936     }
17937
17938     frame_set = &tng_data->current_trajectory_frame_set;
17939
17940     /* first_frame_time is -1 when it is not yet set. */
17941     if(frame_set->first_frame_time < -0.1)
17942     {
17943         if(frame_nr > frame_set->first_frame)
17944         {
17945             stat = tng_frame_set_first_frame_time_set(tng_data,
17946                                                       time -
17947                                                       (frame_nr -
17948                                                        frame_set->first_frame) *
17949                                                       tng_data->time_per_frame);
17950         }
17951         else
17952         {
17953             stat = tng_frame_set_first_frame_time_set(tng_data, time);
17954         }
17955     }
17956     return(stat);
17957 }
17958
17959 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
17960                 (tng_trajectory_t tng_data,
17961                  const int64_t frame_nr,
17962                  const double time,
17963                  const float *positions)
17964 {
17965     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17966     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17967     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17968     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17969
17970     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
17971                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
17972                                             TNG_PARTICLE_BLOCK_DATA,
17973                                             TNG_TNG_COMPRESSION));
17974 }
17975
17976 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
17977                 (tng_trajectory_t tng_data,
17978                  const int64_t frame_nr,
17979                  const double time,
17980                  const double *positions)
17981 {
17982     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17983     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17984     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17985     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17986
17987     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17988                                                    positions, 3,
17989                                                    TNG_TRAJ_POSITIONS,
17990                                                    "POSITIONS",
17991                                                    TNG_PARTICLE_BLOCK_DATA,
17992                                                    TNG_TNG_COMPRESSION));
17993 }
17994
17995 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
17996                 (tng_trajectory_t tng_data,
17997                  const int64_t frame_nr,
17998                  const double time,
17999                  const float *velocities)
18000 {
18001     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18002     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18003     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18004     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18005
18006     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18007                                             velocities, 3,
18008                                             TNG_TRAJ_VELOCITIES,
18009                                             "VELOCITIES",
18010                                             TNG_PARTICLE_BLOCK_DATA,
18011                                             TNG_TNG_COMPRESSION));
18012 }
18013
18014 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18015                 (tng_trajectory_t tng_data,
18016                  const int64_t frame_nr,
18017                  const double time,
18018                  const double *velocities)
18019 {
18020     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18021     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18022     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18023     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18024
18025     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18026                                                    velocities, 3,
18027                                                    TNG_TRAJ_VELOCITIES,
18028                                                    "VELOCITIES",
18029                                                    TNG_PARTICLE_BLOCK_DATA,
18030                                                    TNG_TNG_COMPRESSION));
18031 }
18032
18033 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18034                 (tng_trajectory_t tng_data,
18035                  const int64_t frame_nr,
18036                  const double time,
18037                  const float *forces)
18038 {
18039     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18040     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18041     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18042     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18043
18044     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18045                                             3, TNG_TRAJ_FORCES, "FORCES",
18046                                             TNG_PARTICLE_BLOCK_DATA,
18047                                             TNG_GZIP_COMPRESSION));
18048 }
18049
18050 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18051                 (tng_trajectory_t tng_data,
18052                  const int64_t frame_nr,
18053                  const double time,
18054                  const double *forces)
18055 {
18056     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18057     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18058     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18059     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18060
18061     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18062                                                    forces, 3,
18063                                                    TNG_TRAJ_FORCES, "FORCES",
18064                                                    TNG_PARTICLE_BLOCK_DATA,
18065                                                    TNG_GZIP_COMPRESSION));
18066 }
18067
18068 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18069                 (tng_trajectory_t tng_data,
18070                  const int64_t frame_nr,
18071                  const double time,
18072                  const float *box_shape)
18073 {
18074     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18075     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18076     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18077     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18078
18079     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
18080                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18081                                             TNG_NON_PARTICLE_BLOCK_DATA,
18082                                             TNG_GZIP_COMPRESSION));
18083 }
18084
18085 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
18086                 (tng_trajectory_t tng_data,
18087                  const int64_t frame_nr,
18088                  const double time,
18089                  const double *box_shape)
18090 {
18091     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18092     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18093     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18094     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18095
18096     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
18097                                                    time, box_shape, 9,
18098                                                    TNG_TRAJ_BOX_SHAPE,
18099                                                    "BOX SHAPE",
18100                                                    TNG_NON_PARTICLE_BLOCK_DATA,
18101                                                    TNG_GZIP_COMPRESSION));
18102 }
18103
18104 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
18105                 (tng_trajectory_t tng_data,
18106                  const int64_t block_id,
18107                  char *codec_id,
18108                  float *factor)
18109 {
18110     tng_trajectory_frame_set_t frame_set;
18111     tng_particle_data_t p_data;
18112     tng_non_particle_data_t np_data;
18113     tng_function_status stat;
18114     int64_t i;
18115     int block_type = -1;
18116
18117     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18118     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
18119     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
18120
18121     frame_set = &tng_data->current_trajectory_frame_set;
18122
18123     stat = tng_particle_data_find(tng_data, block_id, &p_data);
18124     if(stat == TNG_SUCCESS)
18125     {
18126         block_type = TNG_PARTICLE_BLOCK_DATA;
18127     }
18128     else
18129     {
18130         stat = tng_data_find(tng_data, block_id, &np_data);
18131         if(stat == TNG_SUCCESS)
18132         {
18133             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18134         }
18135         else
18136         {
18137             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18138             if(stat != TNG_SUCCESS)
18139             {
18140                 return(stat);
18141             }
18142             stat = tng_particle_data_find(tng_data, block_id, &p_data);
18143             if(stat == TNG_SUCCESS)
18144             {
18145                 block_type = TNG_PARTICLE_BLOCK_DATA;
18146             }
18147             else
18148             {
18149                 stat = tng_data_find(tng_data, block_id, &np_data);
18150                 if(stat == TNG_SUCCESS)
18151                 {
18152                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18153                 }
18154                 else
18155                 {
18156                     return(stat);
18157                 }
18158             }
18159         }
18160     }
18161     if(block_type == TNG_PARTICLE_BLOCK_DATA)
18162     {
18163         if(p_data->last_retrieved_frame < 0)
18164         {
18165             i = p_data->first_frame_with_data;
18166         }
18167         else
18168         {
18169             i = p_data->last_retrieved_frame;
18170         }
18171     }
18172     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
18173     {
18174         if(np_data->last_retrieved_frame < 0)
18175         {
18176             i = np_data->first_frame_with_data;
18177         }
18178         else
18179         {
18180             i = np_data->last_retrieved_frame;
18181         }
18182     }
18183     else
18184     {
18185         return(TNG_FAILURE);
18186     }
18187     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
18188     {
18189         stat = tng_frame_set_of_frame_find(tng_data, i);
18190         if(stat != TNG_SUCCESS)
18191         {
18192             return(stat);
18193         }
18194         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18195         if(stat != TNG_SUCCESS)
18196         {
18197             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18198                 __FILE__, __LINE__);
18199             return(stat);
18200         }
18201     }
18202     if(block_type == TNG_PARTICLE_BLOCK_DATA)
18203     {
18204         *codec_id = p_data->codec_id;
18205         *factor   = p_data->compression_multiplier;
18206     }
18207     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
18208     {
18209         *codec_id = np_data->codec_id;
18210         *factor   = np_data->compression_multiplier;
18211     }
18212     return(TNG_SUCCESS);
18213 }
18214
18215 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
18216                 (tng_trajectory_t tng_data,
18217                  int64_t current_frame,
18218                  const int64_t n_requested_data_block_ids,
18219                  const int64_t *requested_data_block_ids,
18220                  int64_t *next_frame,
18221                  int64_t *n_data_blocks_in_next_frame,
18222                  int64_t **data_block_ids_in_next_frame)
18223 {
18224     tng_trajectory_frame_set_t frame_set;
18225     tng_function_status stat;
18226     tng_particle_data_t p_data;
18227     tng_non_particle_data_t np_data;
18228     tng_gen_block_t block;
18229     int64_t i, j, block_id, *temp;
18230     int64_t data_frame, frame_diff, min_diff;
18231     int64_t size, frame_set_file_pos;
18232     int found, read_all = 0;
18233     long file_pos;
18234
18235     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18236     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
18237     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
18238     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
18239
18240     if(n_requested_data_block_ids)
18241     {
18242         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.");
18243         size = sizeof(int64_t) * n_requested_data_block_ids;
18244         temp = realloc(*data_block_ids_in_next_frame, size);
18245         if(!temp)
18246         {
18247             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
18248                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
18249                     __FILE__, __LINE__);
18250             free(*data_block_ids_in_next_frame);
18251             *data_block_ids_in_next_frame = 0;
18252             return(TNG_CRITICAL);
18253         }
18254         *data_block_ids_in_next_frame = temp;
18255     }
18256
18257     frame_set = &tng_data->current_trajectory_frame_set;
18258
18259     current_frame += 1;
18260
18261     if(current_frame < frame_set->first_frame ||
18262        current_frame >= frame_set->first_frame + frame_set->n_frames)
18263     {
18264         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
18265         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
18266         if(stat != TNG_SUCCESS)
18267         {
18268             /* If the frame set search found the frame set after the starting
18269              * frame set there is a gap in the frame sets. So, even if the frame
18270              * was not found the next frame with data is still in the found
18271              * frame set. */
18272             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
18273                frame_set_file_pos)
18274             {
18275                 return(stat);
18276             }
18277             current_frame = frame_set->first_frame;
18278         }
18279     }
18280
18281     if(frame_set->n_particle_data_blocks <= 0 || frame_set->n_data_blocks <= 0)
18282     {
18283         tng_block_init(&block);
18284         file_pos = ftell(tng_data->input_file);
18285         /* Read all blocks until next frame set block */
18286         stat = tng_block_header_read(tng_data, block);
18287         while(file_pos < tng_data->input_file_len &&
18288             stat != TNG_CRITICAL &&
18289             block->id != TNG_TRAJECTORY_FRAME_SET)
18290         {
18291             stat = tng_block_read_next(tng_data, block,
18292                                        TNG_USE_HASH);
18293             if(stat != TNG_CRITICAL)
18294             {
18295                 file_pos = ftell(tng_data->input_file);
18296                 if(file_pos < tng_data->input_file_len)
18297                 {
18298                     stat = tng_block_header_read(tng_data, block);
18299                 }
18300             }
18301         }
18302         tng_block_destroy(&block);
18303         if(stat == TNG_CRITICAL)
18304         {
18305             fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
18306                     file_pos, __FILE__, __LINE__);
18307             return(stat);
18308         }
18309         read_all = 1;
18310     }
18311
18312     min_diff = -1;
18313
18314     *n_data_blocks_in_next_frame = 0;
18315
18316     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
18317     {
18318         p_data = &frame_set->tr_particle_data[i];
18319         block_id = p_data->block_id;
18320
18321         if(n_requested_data_block_ids > 0)
18322         {
18323             found = 0;
18324             for(j = 0; j < n_requested_data_block_ids; j++)
18325             {
18326                 if(block_id == requested_data_block_ids[j])
18327                 {
18328                     found = 1;
18329                     break;
18330                 }
18331             }
18332             if(!found)
18333             {
18334                 continue;
18335             }
18336         }
18337
18338         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
18339            p_data->last_retrieved_frame >=
18340            frame_set->first_frame + frame_set->n_frames))
18341         {
18342             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
18343                                                                       TNG_USE_HASH, block_id);
18344             if(stat == TNG_CRITICAL)
18345             {
18346                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18347                     __FILE__, __LINE__);
18348                 return(stat);
18349             }
18350             if(stat == TNG_FAILURE)
18351             {
18352                 continue;
18353             }
18354         }
18355         if(frame_set->first_frame != current_frame &&
18356            p_data->last_retrieved_frame >= 0)
18357         {
18358             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
18359         }
18360         else
18361         {
18362             data_frame = p_data->first_frame_with_data;
18363         }
18364         frame_diff = data_frame - current_frame;
18365         if(frame_diff < 0)
18366         {
18367             continue;
18368         }
18369         if(min_diff == -1 || frame_diff <= min_diff)
18370         {
18371             if(frame_diff < min_diff)
18372             {
18373                 *n_data_blocks_in_next_frame = 1;
18374             }
18375             else
18376             {
18377                 *n_data_blocks_in_next_frame += 1;
18378             }
18379             if(n_requested_data_block_ids <= 0)
18380             {
18381                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
18382                 temp = realloc(*data_block_ids_in_next_frame, size);
18383                 if(!temp)
18384                 {
18385                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
18386                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
18387                            __FILE__, __LINE__);
18388                     free(*data_block_ids_in_next_frame);
18389                     *data_block_ids_in_next_frame = 0;
18390                     return(TNG_CRITICAL);
18391                 }
18392                 *data_block_ids_in_next_frame = temp;
18393             }
18394             else
18395             {
18396                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
18397             }
18398             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
18399
18400             min_diff = frame_diff;
18401         }
18402     }
18403     for(i = 0; i < frame_set->n_data_blocks; i++)
18404     {
18405         np_data = &frame_set->tr_data[i];
18406         block_id = np_data->block_id;
18407
18408         if(n_requested_data_block_ids > 0)
18409         {
18410             found = 0;
18411             for(j = 0; j < n_requested_data_block_ids; j++)
18412             {
18413                 if(block_id == requested_data_block_ids[j])
18414                 {
18415                     found = 1;
18416                     break;
18417                 }
18418             }
18419             if(!found)
18420             {
18421                 continue;
18422             }
18423         }
18424
18425         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
18426            np_data->last_retrieved_frame >=
18427            frame_set->first_frame + frame_set->n_frames))
18428         {
18429             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
18430                                                                       TNG_USE_HASH, block_id);
18431             if(stat == TNG_CRITICAL)
18432             {
18433                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18434                     __FILE__, __LINE__);
18435                 return(stat);
18436             }
18437             if(stat == TNG_FAILURE)
18438             {
18439                 continue;
18440             }
18441         }
18442         if(frame_set->first_frame != current_frame &&
18443            np_data->last_retrieved_frame >= 0)
18444         {
18445             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
18446         }
18447         else
18448         {
18449             data_frame = np_data->first_frame_with_data;
18450         }
18451         frame_diff = data_frame - current_frame;
18452         if(frame_diff < 0)
18453         {
18454             continue;
18455         }
18456         if(min_diff == -1 || frame_diff <= min_diff)
18457         {
18458             if(frame_diff < min_diff)
18459             {
18460                 *n_data_blocks_in_next_frame = 1;
18461             }
18462             else
18463             {
18464                 *n_data_blocks_in_next_frame += 1;
18465             }
18466             if(n_requested_data_block_ids <= 0)
18467             {
18468                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
18469                 temp = realloc(*data_block_ids_in_next_frame, size);
18470                 if(!temp)
18471                 {
18472                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
18473                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
18474                            __FILE__, __LINE__);
18475                     free(*data_block_ids_in_next_frame);
18476                     *data_block_ids_in_next_frame = 0;
18477                     return(TNG_CRITICAL);
18478                 }
18479                 *data_block_ids_in_next_frame = temp;
18480             }
18481             else
18482             {
18483                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
18484             }
18485             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
18486
18487             min_diff = frame_diff;
18488         }
18489     }
18490     if(min_diff < 0)
18491     {
18492         return(TNG_FAILURE);
18493     }
18494     *next_frame = current_frame + min_diff;
18495
18496     return(TNG_SUCCESS);
18497 }
18498
18499 /*
18500 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
18501                 (tng_trajectory_t tng_data,
18502                  int64_t *n_data_blocks,
18503                  int64_t **data_block_ids,
18504                  char ***data_block_names,
18505                  int64_t **stride_lengths,
18506                  int64_t **n_values_per_frame,
18507                  char **block_types,
18508                  char **dependencies,
18509                  char **compressions)
18510 {
18511     tng_gen_block_t block;
18512     long orig_file_pos, file_pos;
18513
18514     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18515     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
18516     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
18517     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
18518     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
18519
18520     orig_file_pos = ftell(tng_data->input_file);
18521
18522     if(!tng_data->input_file_len)
18523     {
18524         fseek(tng_data->input_file, 0, SEEK_END);
18525         tng_data->input_file_len = ftell(tng_data->input_file);
18526     }
18527
18528     fseek(tng_data->input_file, 0, SEEK_SET);
18529     file_pos = 0;
18530
18531     *n_data_blocks = 0;
18532
18533     tng_block_init(&block);
18534
18535     while(file_pos < tng_data->input_file_len &&
18536           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
18537     {
18538         if(block->id > TNG_TRAJECTORY_FRAME_SET)
18539         {
18540
18541         }
18542         file_pos += (long)(block->block_contents_size + block->header_contents_size);
18543         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
18544     }
18545
18546     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
18547
18548     return(TNG_SUCCESS);
18549 }
18550 */
18551 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
18552                 (tng_trajectory_t tng_data,
18553                  const int64_t prev_frame)
18554 {
18555     tng_function_status stat;
18556     FILE *temp = tng_data->input_file;
18557
18558     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18559     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
18560
18561     tng_data->input_file = tng_data->output_file;
18562
18563     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
18564     if(stat != TNG_SUCCESS)
18565     {
18566         return(stat);
18567     }
18568
18569     tng_data->current_trajectory_frame_set_output_file_pos =
18570     tng_data->current_trajectory_frame_set_input_file_pos;
18571
18572     tng_data->input_file = temp;
18573
18574     return(TNG_SUCCESS);
18575 }