Bug fix in the TNG library to improve reading.
[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.5
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, "rb");
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, "wb+");
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     if(!*block_p)
737     {
738         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
739                sizeof(struct tng_gen_block), __FILE__, __LINE__);
740         return(TNG_CRITICAL);
741     }
742
743     block = *block_p;
744
745     block->id = -1;
746     /* Reset the md5_hash */
747     memcpy(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN);
748     block->name = 0;
749     block->block_version = TNG_VERSION;
750     block->header_contents = 0;
751     block->header_contents_size = 0;
752     block->block_contents = 0;
753     block->block_contents_size = 0;
754
755     return(TNG_SUCCESS);
756 }
757
758 /**
759  * @brief Clean up a file block container.
760  * @param block_p a pointer to the file block container to destroy.
761  * @details All allocated memory in the data structure is freed, as well as
762  * block_p itself.
763  * @return TNG_SUCCESS (0) if successful.
764  */
765 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
766 {
767     tng_gen_block_t block = *block_p;
768
769     if(!*block_p)
770     {
771         return(TNG_SUCCESS);
772     }
773
774 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
775     if(block->name)
776     {
777         free(block->name);
778         block->name = 0;
779     }
780     if(block->header_contents)
781     {
782         free(block->header_contents);
783         block->header_contents = 0;
784     }
785     if(block->block_contents)
786     {
787         free(block->block_contents);
788         block->block_contents = 0;
789     }
790
791     free(*block_p);
792     *block_p = 0;
793
794     return(TNG_SUCCESS);
795 }
796
797 /** Read the header of a data block, regardless of its type
798  * @param tng_data is a trajectory data container.
799  * @param block is a general block container.
800  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
801  * error has occured.
802  */
803 static tng_function_status tng_block_header_read
804                 (tng_trajectory_t tng_data, tng_gen_block_t block)
805 {
806     int len, offset = 0;
807
808     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
809
810     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
811     {
812         return(TNG_CRITICAL);
813     }
814
815     /* First read the header size to be able to read the whole header. */
816     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
817         1, tng_data->input_file) == 0)
818     {
819         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
820                __FILE__, __LINE__);
821         return(TNG_CRITICAL);
822     }
823
824     /* If this was the size of the general info block check the endianness */
825     if(ftell(tng_data->input_file) < 9)
826     {
827         /* File is little endian */
828         if ( *((const char*)&block->header_contents_size) != 0x00 &&
829              *((const char*)(&block->header_contents_size) + 7) == 0x00)
830         {
831             /* If the architecture endianness is little endian no byte swap
832              * will be needed. Otherwise use the functions to swap to little
833              * endian */
834             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
835             {
836                 tng_data->input_endianness_swap_func_32 = 0;
837             }
838             else
839             {
840                 tng_data->input_endianness_swap_func_32 =
841                 &tng_swap_byte_order_little_endian_32;
842             }
843             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
844             {
845                 tng_data->input_endianness_swap_func_64 = 0;
846             }
847             else
848             {
849                 tng_data->input_endianness_swap_func_64 =
850                 &tng_swap_byte_order_little_endian_64;
851             }
852         }
853         /* File is big endian */
854         else
855         {
856             /* If the architecture endianness is big endian no byte swap
857              * will be needed. Otherwise use the functions to swap to big
858              * endian */
859             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
860             {
861                 tng_data->input_endianness_swap_func_32 = 0;
862             }
863             else
864             {
865                 tng_data->input_endianness_swap_func_32 =
866                 &tng_swap_byte_order_big_endian_32;
867             }
868             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
869             {
870                 tng_data->input_endianness_swap_func_64 = 0;
871             }
872             else
873             {
874                 tng_data->input_endianness_swap_func_64 =
875                 &tng_swap_byte_order_big_endian_64;
876             }
877         }
878     }
879
880     if(tng_data->input_endianness_swap_func_64)
881     {
882         if(tng_data->input_endianness_swap_func_64(tng_data,
883                                                    &block->header_contents_size)
884             != TNG_SUCCESS)
885         {
886             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
887                     __FILE__, __LINE__);
888         }
889     }
890
891     /* Move the reading position to the beginning of the header. */
892     fseek(tng_data->input_file, -(long)sizeof(block->header_contents_size),
893           SEEK_CUR);
894
895     /* If there is already memory allocated for the contents free it (we do not
896      * know if the size is correct). */
897     if(block->header_contents)
898     {
899         free(block->header_contents);
900     }
901
902     block->header_contents = malloc(block->header_contents_size);
903     if(!block->header_contents)
904     {
905         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
906                block->header_contents_size, __FILE__, __LINE__);
907         return(TNG_CRITICAL);
908     }
909
910     /* Read the whole header into header_contents. This way it can be saved
911      * even if it cannot be interpreted
912      * for one reason or another. */
913     if(fread(block->header_contents, block->header_contents_size, 1,
914         tng_data->input_file) == 0)
915     {
916         fprintf(stderr, "TNG library: Cannot read header. %s: %d\n", __FILE__, __LINE__);
917         return(TNG_CRITICAL);
918     }
919
920     /* The header contents size has already been read. Skip ahead. */
921     offset = sizeof(block->header_contents_size);
922
923
924     /* Copy the respective parameters from the header contents block */
925     memcpy(&block->block_contents_size, block->header_contents+offset,
926            sizeof(block->block_contents_size));
927     if(tng_data->input_endianness_swap_func_64)
928     {
929         if(tng_data->input_endianness_swap_func_64(tng_data,
930                                                    &block->block_contents_size)
931             != TNG_SUCCESS)
932         {
933             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
934                     __FILE__, __LINE__);
935         }
936     }
937
938     offset += sizeof(block->block_contents_size);
939
940     memcpy(&block->id, block->header_contents+offset, sizeof(block->id));
941     if(tng_data->input_endianness_swap_func_64)
942     {
943         if(tng_data->input_endianness_swap_func_64(tng_data,
944                                                    &block->id)
945             != TNG_SUCCESS)
946         {
947             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
948                     __FILE__, __LINE__);
949         }
950     }
951
952     offset += sizeof(block->id);
953
954     memcpy(block->md5_hash, block->header_contents+offset, TNG_MD5_HASH_LEN);
955     offset += TNG_MD5_HASH_LEN;
956
957     if(block->name && strcmp(block->name, block->header_contents+offset) != 0)
958     {
959         free(block->name);
960         block->name = 0;
961     }
962     len = tng_min_i((int)strlen(block->header_contents+offset) + 1, TNG_MAX_STR_LEN);
963     if(!block->name)
964     {
965         block->name = malloc(len);
966         if(!block->name)
967         {
968             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
969                     __FILE__, __LINE__);
970             return(TNG_CRITICAL);
971         }
972         strncpy(block->name, block->header_contents+offset, len);
973     }
974     offset += len;
975
976     memcpy(&block->block_version, block->header_contents+offset,
977            sizeof(block->block_version));
978     if(tng_data->input_endianness_swap_func_64)
979     {
980         if(tng_data->input_endianness_swap_func_64(tng_data,
981                                                    &block->block_version)
982             != TNG_SUCCESS)
983         {
984             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
985                     __FILE__, __LINE__);
986         }
987     }
988
989     return(TNG_SUCCESS);
990 }
991
992 /** Write a whole block, both header and contents, regardless of it type
993  * @param tng_data is a trajectory data container.
994  * @param block is a general block container.
995  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
996  * has occurred or TNG_CRITICAL (2) if a major error has occured.
997  */
998 /* Disabled until it is used.*/
999 /*
1000 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1001 //                                                     tng_gen_block_t block)
1002 // {
1003 //     if(!block->header_contents)
1004 //     {
1005 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1006 //         return(TNG_FAILURE);
1007 //     }
1008 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1009 //                 tng_data->output_file) != 1)
1010 //     {
1011 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1012 //                 __FILE__, __LINE__);
1013 //         return(TNG_CRITICAL);
1014 //     }
1015 //
1016 //     if(!block->block_contents)
1017 //     {
1018 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1019 //                 __FILE__, __LINE__);
1020 //         return(TNG_FAILURE);
1021 //     }
1022 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1023 //                 tng_data->output_file) != 1)
1024 //     {
1025 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1026 //                 __FILE__, __LINE__);
1027 //         return(TNG_CRITICAL);
1028 //     }
1029 //     return(TNG_SUCCESS);
1030 // }
1031 */
1032
1033 static tng_function_status tng_reread_frame_set_at_file_pos
1034                 (tng_trajectory_t tng_data,
1035                  const int64_t pos)
1036 {
1037     tng_gen_block_t block;
1038     tng_function_status stat;
1039
1040     tng_block_init(&block);
1041
1042     fseek(tng_data->input_file, pos, SEEK_SET);
1043     if(pos > 0)
1044     {
1045         stat = tng_block_header_read(tng_data, block);
1046         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1047         {
1048             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
1049                     __FILE__, __LINE__);
1050             tng_block_destroy(&block);
1051             return(TNG_FAILURE);
1052         }
1053
1054         if(tng_block_read_next(tng_data, block,
1055                                TNG_SKIP_HASH) != TNG_SUCCESS)
1056         {
1057             tng_block_destroy(&block);
1058             return(TNG_CRITICAL);
1059         }
1060     }
1061
1062     tng_block_destroy(&block);
1063
1064     return(TNG_SUCCESS);
1065 }
1066
1067 /** Write the header of a data block, regardless of its type
1068  * @param tng_data is a trajectory data container.
1069  * @param block is a general block container.
1070  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1071  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1072  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1073  * error has occured.
1074  */
1075 static tng_function_status tng_block_header_write
1076                 (tng_trajectory_t tng_data,
1077                  tng_gen_block_t block,
1078                  const char hash_mode)
1079 {
1080     int name_len, offset = 0;
1081
1082     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
1083
1084     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1085     {
1086         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1087                __FILE__, __LINE__);
1088         return(TNG_CRITICAL);
1089     }
1090
1091     if(!block->name)
1092     {
1093         block->name = malloc(1);
1094         if(!block->name)
1095         {
1096             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1097                    __FILE__, __LINE__);
1098             return(TNG_CRITICAL);
1099         }
1100         block->name[0] = 0;
1101     }
1102
1103     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1104
1105     if(hash_mode == TNG_USE_HASH)
1106     {
1107         tng_block_md5_hash_generate(block);
1108     }
1109
1110     /* Calculate the size of the header to write */
1111     block->header_contents_size = sizeof(block->header_contents_size) +
1112                                   sizeof(block->block_contents_size) +
1113                                   sizeof(block->id) +
1114                                   sizeof(block->block_version) +
1115                                   TNG_MD5_HASH_LEN +
1116                                   name_len;
1117
1118     if(block->header_contents)
1119     {
1120         free(block->header_contents);
1121     }
1122
1123     block->header_contents = malloc(block->header_contents_size);
1124     if(!block->header_contents)
1125     {
1126         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1127                block->header_contents_size, __FILE__, __LINE__);
1128         return(TNG_CRITICAL);
1129     }
1130
1131     /* First copy all data into the header_contents block and finally write
1132      * the whole block at once. */
1133     memcpy(block->header_contents, &block->header_contents_size,
1134            sizeof(block->header_contents_size));
1135     if(tng_data->output_endianness_swap_func_64)
1136     {
1137         if(tng_data->output_endianness_swap_func_64(tng_data,
1138                                       (int64_t *)block->header_contents+offset)
1139             != TNG_SUCCESS)
1140         {
1141             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1142                     __FILE__, __LINE__);
1143         }
1144     }
1145     offset += sizeof(block->header_contents_size);
1146
1147     memcpy(block->header_contents+offset, &block->block_contents_size,
1148            sizeof(block->block_contents_size));
1149     if(tng_data->output_endianness_swap_func_64)
1150     {
1151         if(tng_data->output_endianness_swap_func_64(tng_data,
1152                                       (int64_t *)block->header_contents+offset)
1153             != TNG_SUCCESS)
1154         {
1155             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1156                     __FILE__, __LINE__);
1157         }
1158     }
1159     offset += sizeof(block->block_contents_size);
1160
1161     memcpy(block->header_contents+offset, &block->id, sizeof(block->id));
1162     if(tng_data->output_endianness_swap_func_64)
1163     {
1164         if(tng_data->output_endianness_swap_func_64(tng_data,
1165                                       (int64_t *)block->header_contents+offset)
1166             != TNG_SUCCESS)
1167         {
1168             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1169                     __FILE__, __LINE__);
1170         }
1171     }
1172     offset += sizeof(block->id);
1173
1174     memcpy(block->header_contents+offset, block->md5_hash, TNG_MD5_HASH_LEN);
1175     offset += TNG_MD5_HASH_LEN;
1176
1177     strncpy(block->header_contents+offset, block->name, name_len);
1178     offset += name_len;
1179
1180     memcpy(block->header_contents+offset, &block->block_version,
1181            sizeof(block->block_version));
1182     if(tng_data->output_endianness_swap_func_64)
1183     {
1184         if(tng_data->output_endianness_swap_func_64(tng_data,
1185                                       (int64_t *)block->header_contents+offset)
1186             != TNG_SUCCESS)
1187         {
1188             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1189                     __FILE__, __LINE__);
1190         }
1191     }
1192
1193     if(fwrite(block->header_contents, block->header_contents_size,
1194        1, tng_data->output_file) != 1)
1195     {
1196         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__);
1197         return(TNG_CRITICAL);
1198     }
1199     return(TNG_SUCCESS);
1200 }
1201
1202 /** Read a general info block. This is the first block of a TNG file.
1203  *  Populate the fields in tng_data.
1204  * @param tng_data is a trajectory data container.
1205  * @param block is a general block container.
1206  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1207  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
1208  * compared to the md5 hash of the read contents to ensure valid data.
1209  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1210  * error has occured.
1211  */
1212 static tng_function_status tng_general_info_block_read
1213                 (tng_trajectory_t tng_data, tng_gen_block_t block,
1214                  const char hash_mode)
1215 {
1216     int len, offset = 0;
1217     tng_bool same_hash;
1218
1219     void *temp;
1220
1221     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
1222
1223     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1224     {
1225         return(TNG_CRITICAL);
1226     }
1227
1228     temp = realloc(block->block_contents, block->block_contents_size);
1229     if(!temp)
1230     {
1231         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1232                block->block_contents_size, __FILE__, __LINE__);
1233         free(block->block_contents);
1234         block->block_contents = 0;
1235         return(TNG_CRITICAL);
1236     }
1237     block->block_contents = temp;
1238
1239     /* Read the whole block into block_contents to be able to write it to disk
1240      * even if it cannot be interpreted. */
1241     if(fread(block->block_contents, block->block_contents_size, 1,
1242              tng_data->input_file) == 0)
1243     {
1244         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1245         return(TNG_CRITICAL);
1246     }
1247
1248     /* FIXME: Does not check if the size of the contents matches the expected
1249      * size or if the contents can be read. */
1250
1251     if(hash_mode == TNG_USE_HASH)
1252     {
1253         tng_md5_hash_match_verify(block, &same_hash);
1254         if(same_hash != TNG_TRUE)
1255         {
1256             fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
1257                 "%s: %d\n",
1258                 __FILE__, __LINE__);
1259     /*         return(TNG_FAILURE); */
1260         }
1261     }
1262
1263     len = tng_min_i((int)strlen(block->block_contents) + 1, TNG_MAX_STR_LEN);
1264     temp = realloc(tng_data->first_program_name, len);
1265     if(!temp)
1266     {
1267         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1268                __FILE__, __LINE__);
1269         free(tng_data->first_program_name);
1270         tng_data->first_program_name = 0;
1271         return(TNG_CRITICAL);
1272     }
1273     tng_data->first_program_name = temp;
1274     strncpy(tng_data->first_program_name, block->block_contents, len);
1275     offset += len;
1276
1277     len = tng_min_i((int)strlen(block->block_contents + offset) + 1, TNG_MAX_STR_LEN);
1278     temp = realloc(tng_data->last_program_name, len);
1279     if(!temp)
1280     {
1281         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1282                __FILE__, __LINE__);
1283         free(tng_data->last_program_name);
1284         tng_data->last_program_name = 0;
1285         return(TNG_CRITICAL);
1286     }
1287     tng_data->last_program_name = temp;
1288     strncpy(tng_data->last_program_name, block->block_contents + offset, len);
1289     offset += len;
1290
1291     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1292     temp = realloc(tng_data->first_user_name, len);
1293     if(!temp)
1294     {
1295         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1296                __FILE__, __LINE__);
1297         free(tng_data->first_user_name);
1298         tng_data->first_user_name = 0;
1299         return(TNG_CRITICAL);
1300     }
1301     tng_data->first_user_name = temp;
1302     strncpy(tng_data->first_user_name, block->block_contents+offset, len);
1303     offset += len;
1304
1305     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1306     temp = realloc(tng_data->last_user_name, len);
1307     if(!temp)
1308     {
1309         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1310                __FILE__, __LINE__);
1311         free(tng_data->last_user_name);
1312         tng_data->last_user_name = 0;
1313         return(TNG_CRITICAL);
1314     }
1315     tng_data->last_user_name = temp;
1316     strncpy(tng_data->last_user_name, block->block_contents+offset, len);
1317     offset += len;
1318
1319     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1320     temp = realloc(tng_data->first_computer_name, len);
1321     if(!temp)
1322     {
1323         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1324                __FILE__, __LINE__);
1325         free(tng_data->first_computer_name);
1326         tng_data->first_computer_name = 0;
1327         return(TNG_CRITICAL);
1328     }
1329     tng_data->first_computer_name = temp;
1330     strncpy(tng_data->first_computer_name, block->block_contents+offset, len);
1331     offset += len;
1332
1333     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1334     temp = realloc(tng_data->last_computer_name, len);
1335     if(!temp)
1336     {
1337         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1338                __FILE__, __LINE__);
1339         free(tng_data->last_computer_name);
1340         tng_data->last_computer_name = 0;
1341         return(TNG_CRITICAL);
1342     }
1343     tng_data->last_computer_name = temp;
1344     strncpy(tng_data->last_computer_name, block->block_contents+offset, len);
1345     offset += len;
1346
1347     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1348     temp = realloc(tng_data->first_pgp_signature, len);
1349     if(!temp)
1350     {
1351         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1352                __FILE__, __LINE__);
1353         free(tng_data->first_pgp_signature);
1354         tng_data->first_pgp_signature = 0;
1355         return(TNG_CRITICAL);
1356     }
1357     tng_data->first_pgp_signature = temp;
1358     strncpy(tng_data->first_pgp_signature, block->block_contents+offset, len);
1359     offset += len;
1360
1361     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1362     temp = realloc(tng_data->last_pgp_signature, len);
1363     if(!temp)
1364     {
1365         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1366                __FILE__, __LINE__);
1367         free(tng_data->last_pgp_signature);
1368         tng_data->last_pgp_signature = 0;
1369         return(TNG_CRITICAL);
1370     }
1371     tng_data->last_pgp_signature = temp;
1372     strncpy(tng_data->last_pgp_signature, block->block_contents+offset, len);
1373     offset += len;
1374
1375     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
1376     temp = realloc(tng_data->forcefield_name, len);
1377     if(!temp)
1378     {
1379         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
1380                __FILE__, __LINE__);
1381         free(tng_data->forcefield_name);
1382         tng_data->forcefield_name = 0;
1383         return(TNG_CRITICAL);
1384     }
1385     tng_data->forcefield_name = temp;
1386     strncpy(tng_data->forcefield_name, block->block_contents+offset, len);
1387     offset += len;
1388
1389     memcpy(&tng_data->time, block->block_contents+offset,
1390            sizeof(tng_data->time));
1391     if(tng_data->input_endianness_swap_func_64)
1392     {
1393         if(tng_data->input_endianness_swap_func_64(tng_data,
1394                                                    &tng_data->time)
1395             != TNG_SUCCESS)
1396         {
1397             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1398                     __FILE__, __LINE__);
1399         }
1400     }
1401     offset += sizeof(tng_data->time);
1402
1403     memcpy(&tng_data->var_num_atoms_flag, block->block_contents+offset,
1404            sizeof(tng_data->var_num_atoms_flag));
1405     offset += sizeof(tng_data->var_num_atoms_flag);
1406
1407     memcpy(&tng_data->frame_set_n_frames, block->block_contents+offset,
1408            sizeof(tng_data->frame_set_n_frames));
1409     if(tng_data->input_endianness_swap_func_64)
1410     {
1411         if(tng_data->input_endianness_swap_func_64(tng_data,
1412                                                  &tng_data->frame_set_n_frames)
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->frame_set_n_frames);
1420
1421     memcpy(&tng_data->first_trajectory_frame_set_input_file_pos,
1422            block->block_contents+offset,
1423            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
1424     if(tng_data->input_endianness_swap_func_64)
1425     {
1426         if(tng_data->input_endianness_swap_func_64(tng_data,
1427                           &tng_data->first_trajectory_frame_set_input_file_pos)
1428             != TNG_SUCCESS)
1429         {
1430             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1431                     __FILE__, __LINE__);
1432         }
1433     }
1434     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
1435
1436     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
1437     tng_data->first_trajectory_frame_set_input_file_pos;
1438
1439
1440     memcpy(&tng_data->last_trajectory_frame_set_input_file_pos,
1441            block->block_contents+offset,
1442            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
1443     if(tng_data->input_endianness_swap_func_64)
1444     {
1445         if(tng_data->input_endianness_swap_func_64(tng_data,
1446                           &tng_data->last_trajectory_frame_set_input_file_pos)
1447             != TNG_SUCCESS)
1448         {
1449             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1450                     __FILE__, __LINE__);
1451         }
1452     }
1453     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
1454
1455     memcpy(&tng_data->medium_stride_length, block->block_contents+offset,
1456            sizeof(tng_data->medium_stride_length));
1457     if(tng_data->input_endianness_swap_func_64)
1458     {
1459         if(tng_data->input_endianness_swap_func_64(tng_data,
1460                                                &tng_data->medium_stride_length)
1461             != TNG_SUCCESS)
1462         {
1463             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1464                     __FILE__, __LINE__);
1465         }
1466     }
1467     offset += sizeof(tng_data->medium_stride_length);
1468
1469     memcpy(&tng_data->long_stride_length, block->block_contents+offset,
1470            sizeof(tng_data->long_stride_length));
1471     if(tng_data->input_endianness_swap_func_64)
1472     {
1473         if(tng_data->input_endianness_swap_func_64(tng_data,
1474                                                  &tng_data->long_stride_length)
1475             != TNG_SUCCESS)
1476         {
1477             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1478                     __FILE__, __LINE__);
1479         }
1480     }
1481     offset += sizeof(tng_data->long_stride_length);
1482
1483     if(block->block_version >= 3)
1484     {
1485         memcpy(&tng_data->distance_unit_exponential, block->block_contents+offset,
1486             sizeof(tng_data->distance_unit_exponential));
1487         if(tng_data->input_endianness_swap_func_64)
1488         {
1489             if(tng_data->input_endianness_swap_func_64(tng_data,
1490                                           &tng_data->distance_unit_exponential)
1491                 != TNG_SUCCESS)
1492             {
1493                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1494                         __FILE__, __LINE__);
1495             }
1496         }
1497     }
1498
1499     return(TNG_SUCCESS);
1500 }
1501
1502 /** Write a general info block. This is the first block of a TNG file.
1503  * @param tng_data is a trajectory data container.
1504  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1505  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1506  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1507  * error has occured.
1508  */
1509 static tng_function_status tng_general_info_block_write
1510                 (tng_trajectory_t tng_data,
1511                  const char hash_mode)
1512 {
1513     int first_program_name_len, first_user_name_len;
1514     int first_computer_name_len, first_pgp_signature_len;
1515     int last_program_name_len, last_user_name_len;
1516     int last_computer_name_len, last_pgp_signature_len;
1517     int forcefield_name_len, name_len;
1518     int offset = 0;
1519     tng_gen_block_t block;
1520
1521     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1522     {
1523         return(TNG_CRITICAL);
1524     }
1525
1526     fseek(tng_data->output_file, 0, SEEK_SET);
1527
1528     /* If the strings are unallocated allocate memory for just string
1529      * termination */
1530     if(!tng_data->first_program_name)
1531     {
1532         tng_data->first_program_name = malloc(1);
1533         if(!tng_data->first_program_name)
1534         {
1535             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1536                    __FILE__, __LINE__);
1537             return(TNG_CRITICAL);
1538         }
1539         tng_data->first_program_name[0] = 0;
1540     }
1541     if(!tng_data->last_program_name)
1542     {
1543         tng_data->last_program_name = malloc(1);
1544         if(!tng_data->last_program_name)
1545         {
1546             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1547                    __FILE__, __LINE__);
1548             return(TNG_CRITICAL);
1549         }
1550         tng_data->last_program_name[0] = 0;
1551     }
1552     if(!tng_data->first_user_name)
1553     {
1554         tng_data->first_user_name = malloc(1);
1555         if(!tng_data->first_user_name)
1556         {
1557             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1558                    __FILE__, __LINE__);
1559             return(TNG_CRITICAL);
1560         }
1561         tng_data->first_user_name[0] = 0;
1562     }
1563     if(!tng_data->last_user_name)
1564     {
1565         tng_data->last_user_name = malloc(1);
1566         if(!tng_data->last_user_name)
1567         {
1568             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1569                    __FILE__, __LINE__);
1570             return(TNG_CRITICAL);
1571         }
1572         tng_data->last_user_name[0] = 0;
1573     }
1574     if(!tng_data->first_computer_name)
1575     {
1576         tng_data->first_computer_name = malloc(1);
1577         if(!tng_data->first_computer_name)
1578         {
1579             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1580                    __FILE__, __LINE__);
1581             return(TNG_CRITICAL);
1582         }
1583         tng_data->first_computer_name[0] = 0;
1584     }
1585     if(!tng_data->last_computer_name)
1586     {
1587         tng_data->last_computer_name = malloc(1);
1588         if(!tng_data->last_computer_name)
1589         {
1590             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1591                    __FILE__, __LINE__);
1592             return(TNG_CRITICAL);
1593         }
1594         tng_data->last_computer_name[0] = 0;
1595     }
1596     if(!tng_data->first_pgp_signature)
1597     {
1598         tng_data->first_pgp_signature = malloc(1);
1599         if(!tng_data->first_pgp_signature)
1600         {
1601             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1602                    __FILE__, __LINE__);
1603             return(TNG_CRITICAL);
1604         }
1605         tng_data->first_pgp_signature[0] = 0;
1606     }
1607     if(!tng_data->last_pgp_signature)
1608     {
1609         tng_data->last_pgp_signature = malloc(1);
1610         if(!tng_data->last_pgp_signature)
1611         {
1612             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1613                    __FILE__, __LINE__);
1614             return(TNG_CRITICAL);
1615         }
1616         tng_data->last_pgp_signature[0] = 0;
1617     }
1618     if(!tng_data->forcefield_name)
1619     {
1620         tng_data->forcefield_name = malloc(1);
1621         if(!tng_data->forcefield_name)
1622         {
1623             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1624                    __FILE__, __LINE__);
1625             return(TNG_CRITICAL);
1626         }
1627         tng_data->forcefield_name[0] = 0;
1628     }
1629
1630     tng_block_init(&block);
1631
1632     name_len = (int)strlen("GENERAL INFO");
1633
1634     block->name = malloc(name_len + 1);
1635     if(!block->name)
1636     {
1637         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
1638                 name_len+1, __FILE__, __LINE__);
1639         tng_block_destroy(&block);
1640         return(TNG_CRITICAL);
1641     }
1642
1643     strcpy(block->name, "GENERAL INFO");
1644     block->id = TNG_GENERAL_INFO;
1645
1646     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
1647                            TNG_MAX_STR_LEN);
1648     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
1649                            TNG_MAX_STR_LEN);
1650     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
1651                         TNG_MAX_STR_LEN);
1652     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
1653                         TNG_MAX_STR_LEN);
1654     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
1655                             TNG_MAX_STR_LEN);
1656     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
1657                             TNG_MAX_STR_LEN);
1658     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
1659                             TNG_MAX_STR_LEN);
1660     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
1661                             TNG_MAX_STR_LEN);
1662     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
1663                               TNG_MAX_STR_LEN);
1664
1665     block->block_contents_size = sizeof(tng_data->time) +
1666                 sizeof(tng_data->var_num_atoms_flag) +
1667                 sizeof(tng_data->frame_set_n_frames) +
1668                 sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
1669                 sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
1670                 sizeof(tng_data->medium_stride_length) +
1671                 sizeof(tng_data->long_stride_length) +
1672                 sizeof(tng_data->distance_unit_exponential) +
1673                 first_program_name_len +
1674                 last_program_name_len +
1675                 first_user_name_len +
1676                 last_user_name_len +
1677                 first_computer_name_len +
1678                 last_computer_name_len +
1679                 first_pgp_signature_len +
1680                 last_pgp_signature_len +
1681                 forcefield_name_len;
1682
1683     if(block->block_contents)
1684     {
1685         free(block->block_contents);
1686     }
1687     block->block_contents = malloc(block->block_contents_size);
1688     if(!block->block_contents)
1689     {
1690         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1691                block->block_contents_size, __FILE__, __LINE__);
1692         tng_block_destroy(&block);
1693         return(TNG_CRITICAL);
1694     }
1695
1696     strncpy(block->block_contents, tng_data->first_program_name, first_program_name_len);
1697     offset += first_program_name_len;
1698
1699     strncpy(block->block_contents+offset, tng_data->last_program_name, last_program_name_len);
1700     offset += last_program_name_len;
1701
1702     strncpy(block->block_contents+offset, tng_data->first_user_name, first_user_name_len);
1703     offset += first_user_name_len;
1704
1705     strncpy(block->block_contents+offset, tng_data->last_user_name, last_user_name_len);
1706     offset += last_user_name_len;
1707
1708     strncpy(block->block_contents+offset, tng_data->first_computer_name,
1709             first_computer_name_len);
1710     offset += first_computer_name_len;
1711
1712     strncpy(block->block_contents+offset, tng_data->last_computer_name,
1713             last_computer_name_len);
1714     offset += last_computer_name_len;
1715
1716     strncpy(block->block_contents+offset, tng_data->first_pgp_signature,
1717             first_pgp_signature_len);
1718     offset += first_pgp_signature_len;
1719
1720     strncpy(block->block_contents+offset, tng_data->last_pgp_signature,
1721             last_pgp_signature_len);
1722     offset += last_pgp_signature_len;
1723
1724     strncpy(block->block_contents+offset, tng_data->forcefield_name,
1725             forcefield_name_len);
1726     offset += forcefield_name_len;
1727
1728     memcpy(block->block_contents+offset, &tng_data->time,
1729            sizeof(tng_data->time));
1730     if(tng_data->output_endianness_swap_func_64)
1731     {
1732         if(tng_data->output_endianness_swap_func_64(tng_data,
1733                                       (int64_t *)block->header_contents+offset)
1734             != TNG_SUCCESS)
1735         {
1736             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1737                     __FILE__, __LINE__);
1738         }
1739     }
1740     offset += sizeof(tng_data->time);
1741
1742     memcpy(block->block_contents+offset, &tng_data->var_num_atoms_flag,
1743            sizeof(tng_data->var_num_atoms_flag));
1744     offset += sizeof(tng_data->var_num_atoms_flag);
1745
1746     memcpy(block->block_contents+offset, &tng_data->frame_set_n_frames,
1747            sizeof(tng_data->frame_set_n_frames));
1748     if(tng_data->output_endianness_swap_func_64)
1749     {
1750         if(tng_data->output_endianness_swap_func_64(tng_data,
1751                                       (int64_t *)block->header_contents+offset)
1752             != TNG_SUCCESS)
1753         {
1754             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1755                     __FILE__, __LINE__);
1756         }
1757     }
1758     offset += sizeof(tng_data->frame_set_n_frames);
1759
1760     memcpy(block->block_contents+offset,
1761            &tng_data->first_trajectory_frame_set_input_file_pos,
1762            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
1763     if(tng_data->output_endianness_swap_func_64)
1764     {
1765         if(tng_data->output_endianness_swap_func_64(tng_data,
1766                                       (int64_t *)block->header_contents+offset)
1767             != TNG_SUCCESS)
1768         {
1769             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1770                     __FILE__, __LINE__);
1771         }
1772     }
1773     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
1774
1775     memcpy(block->block_contents+offset,
1776            &tng_data->last_trajectory_frame_set_input_file_pos,
1777            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
1778     if(tng_data->output_endianness_swap_func_64)
1779     {
1780         if(tng_data->output_endianness_swap_func_64(tng_data,
1781                                       (int64_t *)block->header_contents+offset)
1782             != TNG_SUCCESS)
1783         {
1784             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1785                     __FILE__, __LINE__);
1786         }
1787     }
1788     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
1789
1790     memcpy(block->block_contents+offset, &tng_data->medium_stride_length,
1791            sizeof(tng_data->medium_stride_length));
1792     if(tng_data->output_endianness_swap_func_64)
1793     {
1794         if(tng_data->output_endianness_swap_func_64(tng_data,
1795                                       (int64_t *)block->header_contents+offset)
1796             != TNG_SUCCESS)
1797         {
1798             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1799                     __FILE__, __LINE__);
1800         }
1801     }
1802     offset += sizeof(tng_data->medium_stride_length);
1803
1804     memcpy(block->block_contents+offset, &tng_data->long_stride_length,
1805            sizeof(tng_data->long_stride_length));
1806     if(tng_data->output_endianness_swap_func_64)
1807     {
1808         if(tng_data->output_endianness_swap_func_64(tng_data,
1809                                       (int64_t *)block->header_contents+offset)
1810             != TNG_SUCCESS)
1811         {
1812             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1813                     __FILE__, __LINE__);
1814         }
1815     }
1816     offset += sizeof(tng_data->long_stride_length);
1817
1818     memcpy(block->block_contents+offset, &tng_data->distance_unit_exponential,
1819            sizeof(tng_data->distance_unit_exponential));
1820     if(tng_data->output_endianness_swap_func_64)
1821     {
1822         if(tng_data->output_endianness_swap_func_64(tng_data,
1823                                       (int64_t *)block->header_contents+offset)
1824             != TNG_SUCCESS)
1825         {
1826             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1827                     __FILE__, __LINE__);
1828         }
1829     }
1830
1831     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
1832     {
1833         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
1834                tng_data->output_file_path, __FILE__, __LINE__);
1835         tng_block_destroy(&block);
1836         return(TNG_CRITICAL);
1837     }
1838
1839     if(fwrite(block->block_contents, block->block_contents_size, 1,
1840         tng_data->output_file) != 1)
1841     {
1842         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
1843         tng_block_destroy(&block);
1844         return(TNG_CRITICAL);
1845     }
1846
1847     tng_block_destroy(&block);
1848
1849     return(TNG_SUCCESS);
1850 }
1851
1852 /** Read the chain data of a molecules block.
1853  * @param tng_data is a trajectory data container.
1854  * @param block is a general block container.
1855  * @param chain is the chain data container.
1856  * @param offset is the offset of the block input and is updated when reading.
1857  * @return TNG_SUCCESS(0) is successful.
1858  */
1859 static tng_function_status tng_chain_data_read(tng_trajectory_t tng_data,
1860                                                tng_gen_block_t block,
1861                                                tng_chain_t chain,
1862                                                int *offset)
1863 {
1864     int len;
1865
1866     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1867
1868     memcpy(&chain->id, block->block_contents+*offset,
1869             sizeof(chain->id));
1870     if(tng_data->input_endianness_swap_func_64)
1871     {
1872         if(tng_data->input_endianness_swap_func_64(tng_data,
1873                                                    &chain->id)
1874             != TNG_SUCCESS)
1875         {
1876             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1877                     __FILE__, __LINE__);
1878         }
1879     }
1880     *offset += sizeof(chain->id);
1881
1882     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
1883             TNG_MAX_STR_LEN);
1884     chain->name = malloc(len);
1885     strncpy(chain->name,
1886             block->block_contents+*offset, len);
1887     *offset += len;
1888
1889     memcpy(&chain->n_residues, block->block_contents+*offset,
1890         sizeof(chain->n_residues));
1891     if(tng_data->input_endianness_swap_func_64)
1892     {
1893         if(tng_data->input_endianness_swap_func_64(tng_data,
1894                                                    &chain->n_residues)
1895             != TNG_SUCCESS)
1896         {
1897             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1898                     __FILE__, __LINE__);
1899         }
1900     }
1901     *offset += sizeof(chain->n_residues);
1902
1903     return(TNG_SUCCESS);
1904 }
1905
1906 /** Write the chain data of a molecules block.
1907  * @param tng_data is a trajectory data container.
1908  * @param block is a general block container.
1909  * @param chain is the chain data container.
1910  * @param offset is the offset of the block output and is updated when writing.
1911  * @return TNG_SUCCESS(0) is successful.
1912  */
1913 static tng_function_status tng_chain_data_write(tng_trajectory_t tng_data,
1914                                                 tng_gen_block_t block,
1915                                                 tng_chain_t chain,
1916                                                 int *offset)
1917 {
1918     int len;
1919
1920     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1921
1922     memcpy(block->block_contents+*offset, &chain->id, sizeof(chain->id));
1923     if(tng_data->output_endianness_swap_func_64)
1924     {
1925         if(tng_data->output_endianness_swap_func_64(tng_data,
1926                                     (int64_t *)block->header_contents+*offset)
1927             != TNG_SUCCESS)
1928         {
1929             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1930                     __FILE__, __LINE__);
1931         }
1932     }
1933     *offset += sizeof(chain->id);
1934
1935     len = tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
1936     strncpy(block->block_contents + *offset, chain->name, len);
1937     *offset += len;
1938
1939     memcpy(block->block_contents+*offset, &chain->n_residues,
1940         sizeof(chain->n_residues));
1941     if(tng_data->output_endianness_swap_func_64)
1942     {
1943         if(tng_data->output_endianness_swap_func_64(tng_data,
1944                                     (int64_t *)block->header_contents+*offset)
1945             != TNG_SUCCESS)
1946         {
1947             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1948                     __FILE__, __LINE__);
1949         }
1950     }
1951     *offset += sizeof(chain->n_residues);
1952
1953     return(TNG_SUCCESS);
1954 }
1955
1956 /** Read the residue data of a molecules block.
1957  * @param tng_data is a trajectory data container.
1958  * @param block is a general block container.
1959  * @param residue is the residue data container.
1960  * @param offset is the offset of the block input and is updated when reading.
1961  * @return TNG_SUCCESS(0) is successful.
1962  */
1963 static tng_function_status tng_residue_data_read(tng_trajectory_t tng_data,
1964                                                  tng_gen_block_t block,
1965                                                  tng_residue_t residue,
1966                                                  int *offset)
1967 {
1968     int len;
1969
1970     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
1971
1972     memcpy(&residue->id, block->block_contents+*offset,
1973         sizeof(residue->id));
1974     if(tng_data->input_endianness_swap_func_64)
1975     {
1976         if(tng_data->input_endianness_swap_func_64(tng_data,
1977                                                    &residue->id)
1978             != TNG_SUCCESS)
1979         {
1980             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1981                     __FILE__, __LINE__);
1982         }
1983     }
1984     *offset += sizeof(residue->id);
1985
1986     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
1987             TNG_MAX_STR_LEN);
1988     residue->name = malloc(len);
1989     strncpy(residue->name,
1990             block->block_contents+*offset, len);
1991     *offset += len;
1992
1993     memcpy(&residue->n_atoms, block->block_contents+*offset,
1994             sizeof(residue->n_atoms));
1995     if(tng_data->input_endianness_swap_func_64)
1996     {
1997         if(tng_data->input_endianness_swap_func_64(tng_data,
1998                                                    &residue->n_atoms)
1999             != TNG_SUCCESS)
2000         {
2001             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2002                     __FILE__, __LINE__);
2003         }
2004     }
2005     *offset += sizeof(residue->n_atoms);
2006
2007     return(TNG_SUCCESS);
2008 }
2009
2010 /** Write the residue data of a molecules block.
2011  * @param tng_data is a trajectory data container.
2012  * @param block is a general block container.
2013  * @param residue is the residue data container.
2014  * @param offset is the offset of the block output and is updated when writing.
2015  * @return TNG_SUCCESS(0) is successful.
2016  */
2017 static tng_function_status tng_residue_data_write(tng_trajectory_t tng_data,
2018                                                   tng_gen_block_t block,
2019                                                   tng_residue_t residue,
2020                                                   int *offset)
2021 {
2022     int len;
2023
2024     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2025
2026     memcpy(block->block_contents+*offset, &residue->id, sizeof(residue->id));
2027     if(tng_data->output_endianness_swap_func_64)
2028     {
2029         if(tng_data->output_endianness_swap_func_64(tng_data,
2030                                     (int64_t *)block->header_contents+*offset)
2031             != TNG_SUCCESS)
2032         {
2033             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2034                     __FILE__, __LINE__);
2035         }
2036     }
2037     *offset += sizeof(residue->id);
2038
2039     len = tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2040     strncpy(block->block_contents + *offset, residue->name, len);
2041     *offset += len;
2042
2043     memcpy(block->block_contents+*offset, &residue->n_atoms,
2044         sizeof(residue->n_atoms));
2045     if(tng_data->output_endianness_swap_func_64)
2046     {
2047         if(tng_data->output_endianness_swap_func_64(tng_data,
2048                                     (int64_t *)block->header_contents+*offset)
2049             != TNG_SUCCESS)
2050         {
2051             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2052                     __FILE__, __LINE__);
2053         }
2054     }
2055     *offset += sizeof(residue->n_atoms);
2056
2057     return(TNG_SUCCESS);
2058 }
2059
2060 /** Read the atom data of a molecules block.
2061  * @param tng_data is a trajectory data container.
2062  * @param block is a general block container.
2063  * @param atom is the atom data container.
2064  * @param offset is the offset of the block input and is updated when reading.
2065  * @return TNG_SUCCESS(0) is successful.
2066  */
2067 static tng_function_status tng_atom_data_read(tng_trajectory_t tng_data,
2068                                               tng_gen_block_t block,
2069                                               tng_atom_t atom,
2070                                               int *offset)
2071 {
2072     int len;
2073
2074     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2075
2076     memcpy(&atom->id, block->block_contents+*offset,
2077         sizeof(atom->id));
2078     if(tng_data->input_endianness_swap_func_64)
2079     {
2080         if(tng_data->input_endianness_swap_func_64(tng_data,
2081                                                     &atom->id)
2082             != TNG_SUCCESS)
2083         {
2084             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2085                     __FILE__, __LINE__);
2086         }
2087     }
2088     *offset += sizeof(atom->id);
2089
2090     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2091             TNG_MAX_STR_LEN);
2092     atom->name = malloc(len);
2093     strncpy(atom->name,
2094             block->block_contents+*offset, len);
2095     *offset += len;
2096
2097     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2098             TNG_MAX_STR_LEN);
2099     atom->atom_type = malloc(len);
2100     strncpy(atom->atom_type,
2101             block->block_contents+*offset, len);
2102     *offset += len;
2103
2104     return(TNG_SUCCESS);
2105 }
2106
2107 /** Write the atom data of a molecules block.
2108  * @param tng_data is a trajectory data container.
2109  * @param block is a general block container.
2110  * @param atom is the atom data container.
2111  * @param offset is the offset of the block output and is updated when writing.
2112  * @return TNG_SUCCESS(0) is successful.
2113  */
2114 static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data,
2115                                                tng_gen_block_t block,
2116                                                tng_atom_t atom,
2117                                                int *offset)
2118 {
2119     int len;
2120
2121     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2122
2123     memcpy(block->block_contents+*offset, &atom->id,
2124             sizeof(atom->id));
2125     if(tng_data->output_endianness_swap_func_64)
2126     {
2127         if(tng_data->output_endianness_swap_func_64(tng_data,
2128                                     (int64_t *)block->header_contents+*offset)
2129             != TNG_SUCCESS)
2130         {
2131             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2132                     __FILE__, __LINE__);
2133         }
2134     }
2135     *offset += sizeof(atom->id);
2136
2137     len = tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2138     strncpy(block->block_contents + *offset, atom->name, len);
2139     *offset += len;
2140
2141     len = tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2142     strncpy(block->block_contents + *offset, atom->atom_type, len);
2143     *offset += len;
2144
2145     return(TNG_SUCCESS);
2146 }
2147
2148 /** Read a molecules block. Contains chain, residue and atom data
2149  * @param tng_data is a trajectory data container.
2150  * @param block is a general block container.
2151  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2152  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2153  * compared to the md5 hash of the read contents to ensure valid data.
2154  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2155  * error has occured.
2156  */
2157 static tng_function_status tng_molecules_block_read
2158                 (tng_trajectory_t tng_data,
2159                  tng_gen_block_t block,
2160                  const char hash_mode)
2161 {
2162     int64_t i, j, k, l;
2163     int len, offset = 0;
2164     tng_molecule_t molecule;
2165     tng_chain_t chain;
2166     tng_residue_t residue;
2167     tng_atom_t atom;
2168     tng_bond_t bond;
2169     tng_bool same_hash;
2170
2171     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2172     {
2173         return(TNG_CRITICAL);
2174     }
2175
2176     if(block->block_contents)
2177     {
2178         free(block->block_contents);
2179     }
2180
2181     block->block_contents = malloc(block->block_contents_size);
2182     if(!block->block_contents)
2183     {
2184         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2185                block->block_contents_size, __FILE__, __LINE__);
2186         return(TNG_CRITICAL);
2187     }
2188
2189     /* Read the whole block into block_contents to be able to write it to disk
2190      * even if it cannot be interpreted. */
2191     if(fread(block->block_contents, block->block_contents_size, 1,
2192              tng_data->input_file) == 0)
2193     {
2194         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
2195     }
2196
2197     /* FIXME: Does not check if the size of the contents matches the expected
2198      * size or if the contents can be read. */
2199
2200     if(hash_mode == TNG_USE_HASH)
2201     {
2202         tng_md5_hash_match_verify(block, &same_hash);
2203         if(same_hash != TNG_TRUE)
2204         {
2205             fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
2206                 "%s: %d\n",
2207                 __FILE__, __LINE__);
2208         }
2209     }
2210
2211     if(tng_data->molecules)
2212     {
2213         for(i=tng_data->n_molecules; i--;)
2214         {
2215             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
2216         }
2217         free(tng_data->molecules);
2218         tng_data->molecules = 0;
2219         tng_data->n_molecules = 0;
2220     }
2221
2222     memcpy(&tng_data->n_molecules, block->block_contents,
2223            sizeof(tng_data->n_molecules));
2224     if(tng_data->input_endianness_swap_func_64)
2225     {
2226         if(tng_data->input_endianness_swap_func_64(tng_data,
2227                                                    &tng_data->n_molecules)
2228             != TNG_SUCCESS)
2229         {
2230             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2231                     __FILE__, __LINE__);
2232         }
2233     }
2234     offset += sizeof(tng_data->n_molecules);
2235
2236     if(tng_data->molecules)
2237     {
2238         free(tng_data->molecules);
2239     }
2240
2241     tng_data->n_particles = 0;
2242
2243     tng_data->molecules = malloc(tng_data->n_molecules *
2244                           sizeof(struct tng_molecule));
2245     if(!tng_data->molecules)
2246     {
2247         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2248                tng_data->n_molecules * sizeof(struct tng_molecule),
2249                __FILE__, __LINE__);
2250         return(TNG_CRITICAL);
2251     }
2252
2253     if(!tng_data->var_num_atoms_flag)
2254     {
2255         if(tng_data->molecule_cnt_list)
2256         {
2257             free(tng_data->molecule_cnt_list);
2258         }
2259         tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
2260                                       tng_data->n_molecules);
2261         if(!tng_data->molecule_cnt_list)
2262         {
2263             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2264                    tng_data->n_molecules * sizeof(struct tng_molecule),
2265                    __FILE__, __LINE__);
2266             return(TNG_CRITICAL);
2267         }
2268     }
2269
2270     /* Read each molecule from file */
2271     for(i=0; i < tng_data->n_molecules; i++)
2272     {
2273         molecule = &tng_data->molecules[i];
2274
2275         memcpy(&molecule->id, block->block_contents+offset,
2276                sizeof(molecule->id));
2277         if(tng_data->input_endianness_swap_func_64)
2278         {
2279             if(tng_data->input_endianness_swap_func_64(tng_data,
2280                                                        &molecule->id)
2281                 != TNG_SUCCESS)
2282             {
2283                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2284                         __FILE__, __LINE__);
2285             }
2286         }
2287         offset += sizeof(molecule->id);
2288
2289 /*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
2290         len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2291         molecule->name = malloc(len);
2292         strncpy(molecule->name, block->block_contents+offset, len);
2293         offset += len;
2294
2295         memcpy(&molecule->quaternary_str, block->block_contents+offset,
2296                sizeof(molecule->quaternary_str));
2297         if(tng_data->input_endianness_swap_func_64)
2298         {
2299             if(tng_data->input_endianness_swap_func_64(tng_data,
2300                                                      &molecule->quaternary_str)
2301                 != TNG_SUCCESS)
2302             {
2303                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2304                         __FILE__, __LINE__);
2305             }
2306         }
2307         offset += sizeof(molecule->quaternary_str);
2308
2309         if(!tng_data->var_num_atoms_flag)
2310         {
2311             memcpy(&tng_data->molecule_cnt_list[i],
2312                    block->block_contents+offset,
2313                    sizeof(int64_t));
2314             if(tng_data->input_endianness_swap_func_64)
2315             {
2316                 if(tng_data->input_endianness_swap_func_64(tng_data,
2317                                                &tng_data->molecule_cnt_list[i])
2318                     != TNG_SUCCESS)
2319                 {
2320                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2321                             __FILE__, __LINE__);
2322                 }
2323             }
2324             offset += sizeof(int64_t);
2325         }
2326
2327
2328         memcpy(&molecule->n_chains, block->block_contents+offset,
2329                sizeof(molecule->n_chains));
2330         if(tng_data->input_endianness_swap_func_64)
2331         {
2332             if(tng_data->input_endianness_swap_func_64(tng_data,
2333                                                        &molecule->n_chains)
2334                 != TNG_SUCCESS)
2335             {
2336                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2337                         __FILE__, __LINE__);
2338             }
2339         }
2340         offset += sizeof(molecule->n_chains);
2341
2342         memcpy(&molecule->n_residues, block->block_contents+offset,
2343                sizeof(molecule->n_residues));
2344         if(tng_data->input_endianness_swap_func_64)
2345         {
2346             if(tng_data->input_endianness_swap_func_64(tng_data,
2347                                                        &molecule->n_residues)
2348                 != TNG_SUCCESS)
2349             {
2350                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2351                         __FILE__, __LINE__);
2352             }
2353         }
2354         offset += sizeof(molecule->n_residues);
2355
2356         memcpy(&molecule->n_atoms, block->block_contents+offset,
2357                sizeof(molecule->n_atoms));
2358         if(tng_data->input_endianness_swap_func_64)
2359         {
2360             if(tng_data->input_endianness_swap_func_64(tng_data,
2361                                                        &molecule->n_atoms)
2362                 != TNG_SUCCESS)
2363             {
2364                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2365                         __FILE__, __LINE__);
2366             }
2367         }
2368         offset += sizeof(molecule->n_atoms);
2369
2370         tng_data->n_particles += molecule->n_atoms *
2371                                  tng_data->molecule_cnt_list[i];
2372
2373         if(molecule->n_chains > 0)
2374         {
2375             molecule->chains = malloc(molecule->n_chains *
2376                                     sizeof(struct tng_chain));
2377             if(!molecule->chains)
2378             {
2379                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2380                     molecule->n_chains * sizeof(struct tng_chain),
2381                     __FILE__, __LINE__);
2382                 return(TNG_CRITICAL);
2383             }
2384
2385             chain = molecule->chains;
2386         }
2387         else
2388         {
2389             chain = 0;
2390         }
2391
2392         if(molecule->n_residues > 0)
2393         {
2394             molecule->residues = malloc(molecule->n_residues *
2395                                 sizeof(struct tng_residue));
2396             if(!molecule->residues)
2397             {
2398                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2399                     molecule->n_residues * sizeof(struct tng_residue),
2400                     __FILE__, __LINE__);
2401                 if(molecule->chains)
2402                 {
2403                     free(molecule->chains);
2404                     molecule->chains = 0;
2405                 }
2406                 return(TNG_CRITICAL);
2407             }
2408
2409             residue = molecule->residues;
2410         }
2411         else
2412         {
2413             residue = 0;
2414         }
2415
2416         molecule->atoms = malloc(molecule->n_atoms *
2417                                  sizeof(struct tng_atom));
2418         if(!molecule->atoms)
2419         {
2420             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2421                    molecule->n_atoms * sizeof(struct tng_atom),
2422                    __FILE__, __LINE__);
2423             if(molecule->chains)
2424             {
2425                 free(molecule->chains);
2426                 molecule->chains = 0;
2427             }
2428             if(molecule->residues)
2429             {
2430                 free(molecule->residues);
2431                 molecule->residues = 0;
2432             }
2433             return(TNG_CRITICAL);
2434         }
2435
2436         atom = molecule->atoms;
2437
2438         if(molecule->n_chains > 0)
2439         {
2440             /* Read the chains of the molecule */
2441             for(j=molecule->n_chains; j--;)
2442             {
2443                 chain->molecule = molecule;
2444
2445                 tng_chain_data_read(tng_data, block, chain, &offset);
2446
2447                 chain->residues = molecule->residues;
2448                 residue = chain->residues;
2449
2450                 /* Read the residues of the chain */
2451                 for(k=chain->n_residues; k--;)
2452                 {
2453                     residue->chain = chain;
2454
2455                     tng_residue_data_read(tng_data, block, residue, &offset);
2456
2457                     residue->atoms_offset = atom - molecule->atoms;
2458                     /* Read the atoms of the residue */
2459                     for(l=residue->n_atoms; l--;)
2460                     {
2461                         atom->residue = residue;
2462
2463                         tng_atom_data_read(tng_data, block, atom, &offset);
2464
2465                         atom++;
2466                     }
2467                     residue++;
2468                 }
2469                 chain++;
2470             }
2471         }
2472         else
2473         {
2474             if(molecule->n_residues > 0)
2475             {
2476                 for(k=molecule->n_residues; k--;)
2477                 {
2478                     residue->chain = 0;
2479
2480                     tng_residue_data_read(tng_data, block, residue, &offset);
2481
2482                     residue->atoms_offset = atom - molecule->atoms;
2483                     /* Read the atoms of the residue */
2484                     for(l=residue->n_atoms; l--;)
2485                     {
2486                         atom->residue = residue;
2487
2488                         tng_atom_data_read(tng_data, block, atom, &offset);
2489
2490                         atom++;
2491                     }
2492                     residue++;
2493                 }
2494             }
2495             else
2496             {
2497                 for(l=molecule->n_atoms; l--;)
2498                 {
2499                     atom->residue = 0;
2500
2501                     tng_atom_data_read(tng_data, block, atom, &offset);
2502
2503                     atom++;
2504                 }
2505             }
2506         }
2507
2508         memcpy(&molecule->n_bonds, block->block_contents+offset,
2509                sizeof(molecule->n_bonds));
2510         if(tng_data->input_endianness_swap_func_64)
2511         {
2512             if(tng_data->input_endianness_swap_func_64(tng_data,
2513                                                        &molecule->n_bonds)
2514                 != TNG_SUCCESS)
2515             {
2516                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2517                         __FILE__, __LINE__);
2518             }
2519         }
2520         offset += sizeof(molecule->n_bonds);
2521
2522         if(molecule->n_bonds > 0)
2523         {
2524             tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
2525                                            sizeof(struct tng_bond));
2526             if(!molecule->bonds)
2527             {
2528                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2529                        molecule->n_bonds * sizeof(struct tng_bond),
2530                        __FILE__, __LINE__);
2531                 if(molecule->chains)
2532                 {
2533                     free(molecule->chains);
2534                     molecule->chains = 0;
2535                 }
2536                 if(molecule->residues)
2537                 {
2538                     free(molecule->residues);
2539                     molecule->residues = 0;
2540                 }
2541                 if(molecule->atoms)
2542                 {
2543                     free(molecule->atoms);
2544                     molecule->atoms = 0;
2545                 }
2546                 return(TNG_CRITICAL);
2547             }
2548
2549             bond = molecule->bonds;
2550
2551             for(j=molecule->n_bonds; j--;)
2552             {
2553                 memcpy(&bond->from_atom_id, block->block_contents+offset,
2554                     sizeof(bond->from_atom_id));
2555                 if(tng_data->input_endianness_swap_func_64)
2556                 {
2557                     if(tng_data->input_endianness_swap_func_64(tng_data,
2558                                                                &bond->from_atom_id)
2559                         != TNG_SUCCESS)
2560                     {
2561                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2562                                 __FILE__, __LINE__);
2563                     }
2564                 }
2565                 offset += sizeof(bond->from_atom_id);
2566
2567                 memcpy(&bond->to_atom_id, block->block_contents+offset,
2568                     sizeof(bond->to_atom_id));
2569                 if(tng_data->input_endianness_swap_func_64)
2570                 {
2571                     if(tng_data->input_endianness_swap_func_64(tng_data,
2572                                                                &bond->to_atom_id)
2573                         != TNG_SUCCESS)
2574                     {
2575                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2576                                 __FILE__, __LINE__);
2577                     }
2578                 }
2579                 offset += sizeof(bond->to_atom_id);
2580
2581                 bond++;
2582             }
2583         }
2584         else
2585         {
2586             molecule->bonds = 0;
2587         }
2588     }
2589
2590     return(TNG_SUCCESS);
2591 }
2592
2593 /** Write a molecules block.
2594  * @param tng_data is a trajectory data container.
2595  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2596  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2597  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2598  * error has occured.
2599  */
2600 static tng_function_status tng_molecules_block_write
2601                 (tng_trajectory_t tng_data,
2602                  const char hash_mode)
2603 {
2604     int len = 0, name_len, offset = 0;
2605     int64_t i, j, k, l;
2606     tng_molecule_t molecule;
2607     tng_chain_t chain;
2608     tng_residue_t residue;
2609     tng_atom_t atom;
2610     tng_bond_t bond;
2611     tng_gen_block_t block;
2612
2613     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2614     {
2615         return(TNG_CRITICAL);
2616     }
2617
2618     /* First predict the size of the block */
2619     for(i = 0; i < tng_data->n_molecules; i++)
2620     {
2621         molecule = &tng_data->molecules[i];
2622         if(!molecule->name)
2623         {
2624             molecule->name = malloc(1);
2625             if(!molecule->name)
2626             {
2627                 fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2628                        __FILE__, __LINE__);
2629                 return(TNG_CRITICAL);
2630             }
2631             molecule->name[0] = 0;
2632         }
2633         len += tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
2634
2635         chain = molecule->chains;
2636         for(j = molecule->n_chains; j--;)
2637         {
2638             len += sizeof(chain->id);
2639
2640             if(!chain->name)
2641             {
2642                 chain->name = malloc(1);
2643                 if(!chain->name)
2644                 {
2645                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2646                            __FILE__, __LINE__);
2647                     return(TNG_CRITICAL);
2648                 }
2649                 chain->name[0] = 0;
2650             }
2651             len += tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2652
2653             len += sizeof(chain->n_residues);
2654
2655             chain++;
2656         }
2657
2658         residue = molecule->residues;
2659         for(j = molecule->n_residues; j--;)
2660         {
2661             len += sizeof(residue->id);
2662
2663             if(!residue->name)
2664             {
2665                 residue->name = malloc(1);
2666                 if(!residue->name)
2667                 {
2668                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2669                            __FILE__, __LINE__);
2670                     return(TNG_CRITICAL);
2671                 }
2672                 residue->name[0] = 0;
2673             }
2674             len += tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2675
2676             len += sizeof(residue->n_atoms);
2677
2678             residue++;
2679         }
2680
2681         atom = molecule->atoms;
2682         for(j = molecule->n_atoms; j--;)
2683         {
2684             len += sizeof(atom->id);
2685             if(!atom->name)
2686             {
2687                 atom->name = malloc(1);
2688                 if(!atom->name)
2689                 {
2690                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2691                            __FILE__, __LINE__);
2692                     return(TNG_CRITICAL);
2693                 }
2694                 atom->name[0] = 0;
2695             }
2696             len += tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2697
2698             if(!atom->atom_type)
2699             {
2700                 atom->atom_type = malloc(1);
2701                 if(!atom->atom_type)
2702                 {
2703                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2704                            __FILE__, __LINE__);
2705                     return(TNG_CRITICAL);
2706                 }
2707                 atom->atom_type[0] = 0;
2708             }
2709             len += tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2710
2711             atom++;
2712         }
2713
2714         for(j = molecule->n_bonds; j--;)
2715         {
2716             len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
2717         }
2718     }
2719
2720     tng_block_init(&block);
2721
2722     name_len = (int)strlen("MOLECULES");
2723
2724     block->name = malloc(name_len + 1);
2725     if(!block->name)
2726     {
2727         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
2728                 name_len+1, __FILE__, __LINE__);
2729         tng_block_destroy(&block);
2730         return(TNG_CRITICAL);
2731     }
2732
2733     strcpy(block->name, "MOLECULES");
2734     block->id = TNG_MOLECULES;
2735
2736     block->block_contents_size = sizeof(tng_data->n_molecules) +
2737                                  (sizeof(molecule->id) +
2738                                  sizeof(molecule->quaternary_str) +
2739                                  sizeof(molecule->n_chains) +
2740                                  sizeof(molecule->n_residues) +
2741                                  sizeof(molecule->n_atoms) +
2742                                  sizeof(molecule->n_bonds)) *
2743                                  tng_data->n_molecules +
2744                                  len;
2745
2746     if(!tng_data->var_num_atoms_flag)
2747     {
2748         block->block_contents_size += tng_data->n_molecules * sizeof(int64_t);
2749     }
2750
2751     block->block_contents = malloc(block->block_contents_size);
2752     if(!block->block_contents)
2753     {
2754         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2755                block->block_contents_size, __FILE__, __LINE__);
2756         tng_block_destroy(&block);
2757         return(TNG_CRITICAL);
2758     }
2759
2760     memcpy(block->block_contents+offset, &tng_data->n_molecules,
2761            sizeof(tng_data->n_molecules));
2762     if(tng_data->output_endianness_swap_func_64)
2763     {
2764         if(tng_data->output_endianness_swap_func_64(tng_data,
2765                                       (int64_t *)block->header_contents+offset)
2766             != TNG_SUCCESS)
2767         {
2768             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2769                     __FILE__, __LINE__);
2770         }
2771     }
2772     offset += sizeof(tng_data->n_molecules);
2773
2774     for(i = 0; i < tng_data->n_molecules; i++)
2775     {
2776         molecule = &tng_data->molecules[i];
2777         memcpy(block->block_contents+offset, &molecule->id,
2778                sizeof(molecule->id));
2779         if(tng_data->output_endianness_swap_func_64)
2780         {
2781             if(tng_data->output_endianness_swap_func_64(tng_data,
2782                                         (int64_t *)block->header_contents+offset)
2783                 != TNG_SUCCESS)
2784             {
2785                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2786                         __FILE__, __LINE__);
2787             }
2788         }
2789         offset += sizeof(molecule->id);
2790
2791 /*         fprintf(stderr, "TNG library: Wrote id: %"PRId64" offset: %d\n", molecule->id, offset); */
2792         len = tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
2793         strncpy(block->block_contents + offset, molecule->name, len);
2794         offset += len;
2795
2796         memcpy(block->block_contents+offset, &molecule->quaternary_str,
2797                sizeof(molecule->quaternary_str));
2798         if(tng_data->output_endianness_swap_func_64)
2799         {
2800             if(tng_data->output_endianness_swap_func_64(tng_data,
2801                                         (int64_t *)block->header_contents+offset)
2802                 != TNG_SUCCESS)
2803             {
2804                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2805                         __FILE__, __LINE__);
2806             }
2807         }
2808         offset += sizeof(molecule->quaternary_str);
2809
2810         if(!tng_data->var_num_atoms_flag)
2811         {
2812             memcpy(block->block_contents+offset,
2813                    &tng_data->molecule_cnt_list[i], sizeof(int64_t));
2814             if(tng_data->output_endianness_swap_func_64)
2815             {
2816                 if(tng_data->output_endianness_swap_func_64(tng_data,
2817                                             (int64_t *)block->header_contents+offset)
2818                     != TNG_SUCCESS)
2819                 {
2820                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2821                             __FILE__, __LINE__);
2822                 }
2823             }
2824             offset += sizeof(int64_t);
2825         }
2826
2827         memcpy(block->block_contents+offset, &molecule->n_chains,
2828                sizeof(molecule->n_chains));
2829         if(tng_data->output_endianness_swap_func_64)
2830         {
2831             if(tng_data->output_endianness_swap_func_64(tng_data,
2832                                         (int64_t *)block->header_contents+offset)
2833                 != TNG_SUCCESS)
2834             {
2835                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2836                         __FILE__, __LINE__);
2837             }
2838         }
2839         offset += sizeof(molecule->n_chains);
2840
2841         memcpy(block->block_contents+offset, &molecule->n_residues,
2842                sizeof(molecule->n_residues));
2843         if(tng_data->output_endianness_swap_func_64)
2844         {
2845             if(tng_data->output_endianness_swap_func_64(tng_data,
2846                                         (int64_t *)block->header_contents+offset)
2847                 != TNG_SUCCESS)
2848             {
2849                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2850                         __FILE__, __LINE__);
2851             }
2852         }
2853         offset += sizeof(molecule->n_residues);
2854
2855         memcpy(block->block_contents+offset, &molecule->n_atoms,
2856                sizeof(molecule->n_atoms));
2857         if(tng_data->output_endianness_swap_func_64)
2858         {
2859             if(tng_data->output_endianness_swap_func_64(tng_data,
2860                                         (int64_t *)block->header_contents+offset)
2861                 != TNG_SUCCESS)
2862             {
2863                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2864                         __FILE__, __LINE__);
2865             }
2866         }
2867         offset += sizeof(molecule->n_atoms);
2868
2869         if(molecule->n_chains > 0)
2870         {
2871             chain = molecule->chains;
2872             for(j = molecule->n_chains; j--;)
2873             {
2874                 tng_chain_data_write(tng_data, block, chain, &offset);
2875
2876                 residue = chain->residues;
2877                 for(k = chain->n_residues; k--;)
2878                 {
2879                     tng_residue_data_write(tng_data, block, residue, &offset);
2880
2881                     atom = molecule->atoms + residue->atoms_offset;
2882                     for(l = residue->n_atoms; l--;)
2883                     {
2884                         tng_atom_data_write(tng_data, block, atom, &offset);
2885
2886                         atom++;
2887                     }
2888                     residue++;
2889                 }
2890                 chain++;
2891             }
2892         }
2893         else
2894         {
2895             if(molecule->n_residues > 0)
2896             {
2897                 residue = molecule->residues;
2898                 for(k = molecule->n_residues; k--;)
2899                 {
2900                     tng_residue_data_write(tng_data, block, residue, &offset);
2901
2902                     atom = molecule->atoms + residue->atoms_offset;
2903                     for(l = residue->n_atoms; l--;)
2904                     {
2905                         tng_atom_data_write(tng_data, block, atom, &offset);
2906
2907                         atom++;
2908                     }
2909                     residue++;
2910                 }
2911             }
2912             else
2913             {
2914                 atom = molecule->atoms;
2915                 for(l = molecule->n_atoms; l--;)
2916                 {
2917                     tng_atom_data_write(tng_data, block, atom, &offset);
2918
2919                     atom++;
2920                 }
2921             }
2922         }
2923
2924         memcpy(block->block_contents+offset, &molecule->n_bonds,
2925                sizeof(molecule->n_bonds));
2926         if(tng_data->output_endianness_swap_func_64)
2927         {
2928             if(tng_data->output_endianness_swap_func_64(tng_data,
2929                                         (int64_t *)block->header_contents+offset)
2930                 != TNG_SUCCESS)
2931             {
2932                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2933                         __FILE__, __LINE__);
2934             }
2935         }
2936         offset += sizeof(molecule->n_bonds);
2937
2938         bond = molecule->bonds;
2939         for(j = molecule->n_bonds; j--;)
2940         {
2941             memcpy(block->block_contents+offset, &bond->from_atom_id,
2942                    sizeof(bond->from_atom_id));
2943             if(tng_data->output_endianness_swap_func_64)
2944             {
2945                 if(tng_data->output_endianness_swap_func_64(tng_data,
2946                                             (int64_t *)block->header_contents+offset)
2947                     != TNG_SUCCESS)
2948                 {
2949                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2950                             __FILE__, __LINE__);
2951                 }
2952             }
2953             offset += sizeof(bond->from_atom_id);
2954
2955             memcpy(block->block_contents+offset, &bond->to_atom_id,
2956                    sizeof(bond->to_atom_id));
2957             if(tng_data->output_endianness_swap_func_64)
2958             {
2959                 if(tng_data->output_endianness_swap_func_64(tng_data,
2960                                             (int64_t *)block->header_contents+offset)
2961                     != TNG_SUCCESS)
2962                 {
2963                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2964                             __FILE__, __LINE__);
2965                 }
2966             }
2967             offset += sizeof(bond->to_atom_id);
2968
2969             bond++;
2970         }
2971     }
2972
2973     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
2974     {
2975         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2976                tng_data->output_file_path, __FILE__, __LINE__);
2977         tng_block_destroy(&block);
2978         return(TNG_CRITICAL);
2979     }
2980
2981     if(fwrite(block->block_contents, block->block_contents_size, 1,
2982               tng_data->output_file) != 1)
2983     {
2984         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
2985                __FILE__, __LINE__);
2986         tng_block_destroy(&block);
2987         return(TNG_CRITICAL);
2988     }
2989
2990     tng_block_destroy(&block);
2991
2992     return(TNG_SUCCESS);
2993 }
2994
2995 /** Read a frame set block. Update tng_data->current_trajectory_frame_set
2996  * @param tng_data is a trajectory data container.
2997  * @param block is a general block container.
2998  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2999  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3000  * compared to the md5 hash of the read contents to ensure valid data.
3001  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3002  * error has occured.
3003  */
3004 static tng_function_status tng_frame_set_block_read
3005                 (tng_trajectory_t tng_data,
3006                  tng_gen_block_t block,
3007                  const char hash_mode)
3008 {
3009     long file_pos;
3010     int offset = 0;
3011     int64_t i, prev_n_particles;
3012     tng_bool same_hash;
3013     tng_trajectory_frame_set_t frame_set =
3014     &tng_data->current_trajectory_frame_set;
3015
3016     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3017     {
3018         return(TNG_CRITICAL);
3019     }
3020
3021     if(block->block_contents)
3022     {
3023         free(block->block_contents);
3024     }
3025
3026     block->block_contents = malloc(block->block_contents_size);
3027     if(!block->block_contents)
3028     {
3029         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3030                block->block_contents_size, __FILE__, __LINE__);
3031         return(TNG_CRITICAL);
3032     }
3033
3034     /* Read the whole block into block_contents to be able to write it to
3035      * disk even if it cannot be interpreted. */
3036     if(fread(block->block_contents, block->block_contents_size, 1,
3037              tng_data->input_file) == 0)
3038     {
3039         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3040         return(TNG_CRITICAL);
3041     }
3042
3043     /* FIXME: Does not check if the size of the contents matches the expected
3044      * size or if the contents can be read. */
3045
3046     file_pos = (int64_t)ftell(tng_data->input_file) -
3047                (long)(block->block_contents_size + block->header_contents_size);
3048
3049     if(hash_mode == TNG_USE_HASH)
3050     {
3051         tng_md5_hash_match_verify(block, &same_hash);
3052         if(same_hash != TNG_TRUE)
3053         {
3054             fprintf(stderr, "TNG library: Frame set block contents corrupt. File pos %ld Hashes do not match. "
3055                 "%s: %d\n",
3056                 file_pos, __FILE__, __LINE__);
3057     /*         return(TNG_FAILURE); */
3058         }
3059     }
3060
3061     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3062
3063     tng_frame_set_particle_mapping_free(tng_data);
3064
3065     if(tng_data->first_trajectory_frame_set_input_file_pos <= 0)
3066     {
3067         tng_data->first_trajectory_frame_set_input_file_pos = file_pos;
3068     }
3069     /* FIXME: Should check the frame number instead of the file_pos, in case
3070      * frame sets are not in order */
3071     if(tng_data->last_trajectory_frame_set_input_file_pos < file_pos)
3072     {
3073         tng_data->last_trajectory_frame_set_input_file_pos = file_pos;
3074     }
3075
3076     memcpy(&frame_set->first_frame, block->block_contents,
3077            sizeof(frame_set->first_frame));
3078     if(tng_data->input_endianness_swap_func_64)
3079     {
3080         if(tng_data->input_endianness_swap_func_64(tng_data,
3081                                                    &frame_set->first_frame)
3082             != TNG_SUCCESS)
3083         {
3084             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3085                     __FILE__, __LINE__);
3086         }
3087     }
3088     offset += sizeof(frame_set->first_frame);
3089
3090     memcpy(&frame_set->n_frames, block->block_contents + offset,
3091            sizeof(frame_set->n_frames));
3092     if(tng_data->input_endianness_swap_func_64)
3093     {
3094         if(tng_data->input_endianness_swap_func_64(tng_data,
3095                                                    &frame_set->n_frames)
3096             != TNG_SUCCESS)
3097         {
3098             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3099                     __FILE__, __LINE__);
3100         }
3101     }
3102     offset += sizeof(frame_set->n_frames);
3103
3104     if(tng_data->var_num_atoms_flag)
3105     {
3106         prev_n_particles = frame_set->n_particles;
3107         frame_set->n_particles = 0;
3108         /* If the list of molecule counts has already been created assume that
3109          * it is of correct size. */
3110         if(!frame_set->molecule_cnt_list)
3111         {
3112                 frame_set->molecule_cnt_list =
3113                 malloc(sizeof(int64_t) * tng_data->n_molecules);
3114
3115                 if(!frame_set->molecule_cnt_list)
3116                 {
3117                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3118                            sizeof(int64_t) * tng_data->n_molecules,
3119                            __FILE__, __LINE__);
3120                     return(TNG_CRITICAL);
3121                 }
3122         }
3123         for(i = 0; i < tng_data->n_molecules; i++)
3124         {
3125             memcpy(&frame_set->molecule_cnt_list[i],
3126                    block->block_contents + offset,
3127                    sizeof(int64_t));
3128             if(tng_data->input_endianness_swap_func_64)
3129             {
3130                 if(tng_data->input_endianness_swap_func_64(tng_data,
3131                                               &frame_set->molecule_cnt_list[i])
3132                     != TNG_SUCCESS)
3133                 {
3134                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3135                             __FILE__, __LINE__);
3136                 }
3137             }
3138             offset += sizeof(int64_t);
3139             frame_set->n_particles += tng_data->molecules[i].n_atoms *
3140                                       frame_set->molecule_cnt_list[i];
3141         }
3142         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
3143         {
3144             /* FIXME: Particle dependent data memory management */
3145         }
3146     }
3147
3148     memcpy(&frame_set->next_frame_set_file_pos,
3149            block->block_contents + offset,
3150            sizeof(frame_set->next_frame_set_file_pos));
3151     if(tng_data->input_endianness_swap_func_64)
3152     {
3153         if(tng_data->input_endianness_swap_func_64(tng_data,
3154                                            &frame_set->next_frame_set_file_pos)
3155             != TNG_SUCCESS)
3156         {
3157             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3158                     __FILE__, __LINE__);
3159         }
3160     }
3161     offset += sizeof(frame_set->next_frame_set_file_pos);
3162
3163     memcpy(&frame_set->prev_frame_set_file_pos,
3164            block->block_contents + offset,
3165            sizeof(frame_set->prev_frame_set_file_pos));
3166     if(tng_data->input_endianness_swap_func_64)
3167     {
3168         if(tng_data->input_endianness_swap_func_64(tng_data,
3169                                            &frame_set->prev_frame_set_file_pos)
3170             != TNG_SUCCESS)
3171         {
3172             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3173                     __FILE__, __LINE__);
3174         }
3175     }
3176     offset += sizeof(frame_set->prev_frame_set_file_pos);
3177
3178     memcpy(&frame_set->medium_stride_next_frame_set_file_pos,
3179            block->block_contents + offset,
3180            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
3181     if(tng_data->input_endianness_swap_func_64)
3182     {
3183         if(tng_data->input_endianness_swap_func_64(tng_data,
3184                              &frame_set->medium_stride_next_frame_set_file_pos)
3185             != TNG_SUCCESS)
3186         {
3187             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3188                     __FILE__, __LINE__);
3189         }
3190     }
3191     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
3192
3193     memcpy(&frame_set->medium_stride_prev_frame_set_file_pos,
3194            block->block_contents + offset,
3195            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
3196     if(tng_data->input_endianness_swap_func_64)
3197     {
3198         if(tng_data->input_endianness_swap_func_64(tng_data,
3199                              &frame_set->medium_stride_prev_frame_set_file_pos)
3200             != TNG_SUCCESS)
3201         {
3202             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3203                     __FILE__, __LINE__);
3204         }
3205     }
3206     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
3207
3208     memcpy(&frame_set->long_stride_next_frame_set_file_pos,
3209            block->block_contents + offset,
3210            sizeof(frame_set->long_stride_next_frame_set_file_pos));
3211     if(tng_data->input_endianness_swap_func_64)
3212     {
3213         if(tng_data->input_endianness_swap_func_64(tng_data,
3214                                &frame_set->long_stride_next_frame_set_file_pos)
3215             != TNG_SUCCESS)
3216         {
3217             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3218                     __FILE__, __LINE__);
3219         }
3220     }
3221     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
3222
3223     memcpy(&frame_set->long_stride_prev_frame_set_file_pos,
3224            block->block_contents + offset,
3225            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
3226     if(tng_data->input_endianness_swap_func_64)
3227     {
3228         if(tng_data->input_endianness_swap_func_64(tng_data,
3229                                &frame_set->long_stride_prev_frame_set_file_pos)
3230             != TNG_SUCCESS)
3231         {
3232             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3233                     __FILE__, __LINE__);
3234         }
3235     }
3236     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
3237
3238     if(block->block_version >= 3)
3239     {
3240         memcpy(&frame_set->first_frame_time,
3241             block->block_contents + offset,
3242             sizeof(frame_set->first_frame_time));
3243         if(tng_data->input_endianness_swap_func_64)
3244         {
3245             if(tng_data->input_endianness_swap_func_64(tng_data,
3246                                 (int64_t *)&frame_set->first_frame_time)
3247                 != TNG_SUCCESS)
3248             {
3249                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3250                         __FILE__, __LINE__);
3251             }
3252         }
3253         offset += sizeof(frame_set->first_frame_time);
3254
3255         memcpy(&tng_data->time_per_frame,
3256             block->block_contents + offset,
3257             sizeof(tng_data->time_per_frame));
3258         if(tng_data->input_endianness_swap_func_64)
3259         {
3260             if(tng_data->input_endianness_swap_func_64(tng_data,
3261                                 (int64_t *)&tng_data->time_per_frame)
3262                 != TNG_SUCCESS)
3263             {
3264                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3265                         __FILE__, __LINE__);
3266             }
3267         }
3268     }
3269     else
3270     {
3271         frame_set->first_frame_time = -1;
3272         tng_data->time_per_frame = -1;
3273     }
3274
3275     frame_set->n_written_frames = frame_set->n_frames;
3276
3277     return(TNG_SUCCESS);
3278 }
3279
3280 /** Write tng_data->current_trajectory_frame_set to file
3281  * @param tng_data is a trajectory data container.
3282  * @param block is a general block container.
3283  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3284  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3285  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3286  * error has occured.
3287  */
3288 static tng_function_status tng_frame_set_block_write
3289                 (tng_trajectory_t tng_data,
3290                  tng_gen_block_t block,
3291                  const char hash_mode)
3292 {
3293     char *temp_name;
3294     int64_t i;
3295     int offset = 0;
3296     unsigned int name_len;
3297     tng_trajectory_frame_set_t frame_set =
3298     &tng_data->current_trajectory_frame_set;
3299
3300     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3301     {
3302         return(TNG_CRITICAL);
3303     }
3304
3305     name_len = (int)strlen("TRAJECTORY FRAME SET");
3306
3307     if(!block->name || strlen(block->name) < name_len)
3308     {
3309         temp_name = realloc(block->name, name_len + 1);
3310         if(!temp_name)
3311         {
3312             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3313                    name_len+1, __FILE__, __LINE__);
3314             free(block->name);
3315             block->name = 0;
3316             return(TNG_CRITICAL);
3317         }
3318         block->name = temp_name;
3319     }
3320     strcpy(block->name, "TRAJECTORY FRAME SET");
3321     block->id = TNG_TRAJECTORY_FRAME_SET;
3322
3323     block->block_contents_size = sizeof(int64_t) * 8;
3324     block->block_contents_size += sizeof(double) * 2;
3325
3326     if(tng_data->var_num_atoms_flag)
3327     {
3328         block->block_contents_size += sizeof(int64_t) * tng_data->n_molecules;
3329     }
3330
3331     if(block->block_contents)
3332     {
3333         free(block->block_contents);
3334     }
3335     block->block_contents = malloc(block->block_contents_size);
3336     if(!block->block_contents)
3337     {
3338         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3339                block->block_contents_size, __FILE__, __LINE__);
3340         return(TNG_CRITICAL);
3341     }
3342
3343     memcpy(block->block_contents, &frame_set->first_frame,
3344            sizeof(frame_set->first_frame));
3345     if(tng_data->output_endianness_swap_func_64)
3346     {
3347         if(tng_data->output_endianness_swap_func_64(tng_data,
3348                                       (int64_t *)block->header_contents+offset)
3349             != TNG_SUCCESS)
3350         {
3351             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3352                     __FILE__, __LINE__);
3353         }
3354     }
3355     offset += sizeof(frame_set->first_frame);
3356
3357     memcpy(block->block_contents+offset, &frame_set->n_frames,
3358            sizeof(frame_set->n_frames));
3359     if(tng_data->output_endianness_swap_func_64)
3360     {
3361         if(tng_data->output_endianness_swap_func_64(tng_data,
3362                                       (int64_t *)block->header_contents+offset)
3363             != TNG_SUCCESS)
3364         {
3365             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3366                     __FILE__, __LINE__);
3367         }
3368     }
3369     offset += sizeof(frame_set->n_frames);
3370
3371     if(tng_data->var_num_atoms_flag)
3372     {
3373         for(i = 0; i < tng_data->n_molecules; i++)
3374         {
3375             memcpy(block->block_contents+offset,
3376                    &frame_set->molecule_cnt_list[i],
3377                    sizeof(int64_t));
3378             if(tng_data->output_endianness_swap_func_64)
3379             {
3380                 if(tng_data->output_endianness_swap_func_64(tng_data,
3381                                             (int64_t *)block->header_contents+offset)
3382                     != TNG_SUCCESS)
3383                 {
3384                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3385                             __FILE__, __LINE__);
3386                 }
3387             }
3388             offset += sizeof(int64_t);
3389         }
3390     }
3391
3392
3393     memcpy(block->block_contents+offset, &frame_set->next_frame_set_file_pos,
3394            sizeof(frame_set->next_frame_set_file_pos));
3395     if(tng_data->output_endianness_swap_func_64)
3396     {
3397         if(tng_data->output_endianness_swap_func_64(tng_data,
3398                                       (int64_t *)block->header_contents+offset)
3399             != TNG_SUCCESS)
3400         {
3401             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3402                     __FILE__, __LINE__);
3403         }
3404     }
3405     offset += sizeof(frame_set->next_frame_set_file_pos);
3406
3407     memcpy(block->block_contents+offset, &frame_set->prev_frame_set_file_pos,
3408            sizeof(frame_set->prev_frame_set_file_pos));
3409     if(tng_data->output_endianness_swap_func_64)
3410     {
3411         if(tng_data->output_endianness_swap_func_64(tng_data,
3412                                       (int64_t *)block->header_contents+offset)
3413             != TNG_SUCCESS)
3414         {
3415             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3416                     __FILE__, __LINE__);
3417         }
3418     }
3419     offset += sizeof(frame_set->prev_frame_set_file_pos);
3420
3421     memcpy(block->block_contents+offset,
3422            &frame_set->medium_stride_next_frame_set_file_pos,
3423            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
3424     if(tng_data->output_endianness_swap_func_64)
3425     {
3426         if(tng_data->output_endianness_swap_func_64(tng_data,
3427                                       (int64_t *)block->header_contents+offset)
3428             != TNG_SUCCESS)
3429         {
3430             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3431                     __FILE__, __LINE__);
3432         }
3433     }
3434     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
3435
3436     memcpy(block->block_contents+offset,
3437            &frame_set->medium_stride_prev_frame_set_file_pos,
3438            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
3439     if(tng_data->output_endianness_swap_func_64)
3440     {
3441         if(tng_data->output_endianness_swap_func_64(tng_data,
3442                                       (int64_t *)block->header_contents+offset)
3443             != TNG_SUCCESS)
3444         {
3445             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3446                     __FILE__, __LINE__);
3447         }
3448     }
3449     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
3450
3451     memcpy(block->block_contents+offset,
3452            &frame_set->long_stride_next_frame_set_file_pos,
3453            sizeof(frame_set->long_stride_next_frame_set_file_pos));
3454     if(tng_data->output_endianness_swap_func_64)
3455     {
3456         if(tng_data->output_endianness_swap_func_64(tng_data,
3457                                       (int64_t *)block->header_contents+offset)
3458             != TNG_SUCCESS)
3459         {
3460             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3461                     __FILE__, __LINE__);
3462         }
3463     }
3464     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
3465
3466     memcpy(block->block_contents+offset,
3467            &frame_set->long_stride_prev_frame_set_file_pos,
3468            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
3469     if(tng_data->output_endianness_swap_func_64)
3470     {
3471         if(tng_data->output_endianness_swap_func_64(tng_data,
3472                                       (int64_t *)block->header_contents+offset)
3473             != TNG_SUCCESS)
3474         {
3475             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3476                     __FILE__, __LINE__);
3477         }
3478     }
3479     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
3480
3481     memcpy(block->block_contents+offset,
3482            &frame_set->first_frame_time,
3483            sizeof(frame_set->first_frame_time));
3484     if(tng_data->output_endianness_swap_func_64)
3485     {
3486         if(tng_data->output_endianness_swap_func_64(tng_data,
3487                                       (int64_t *)block->header_contents+offset)
3488             != TNG_SUCCESS)
3489         {
3490             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3491                     __FILE__, __LINE__);
3492         }
3493     }
3494     offset += sizeof(frame_set->first_frame_time);
3495
3496     memcpy(block->block_contents+offset,
3497            &tng_data->time_per_frame,
3498            sizeof(tng_data->time_per_frame));
3499     if(tng_data->output_endianness_swap_func_64)
3500     {
3501         if(tng_data->output_endianness_swap_func_64(tng_data,
3502                                       (int64_t *)block->header_contents+offset)
3503             != TNG_SUCCESS)
3504         {
3505             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3506                     __FILE__, __LINE__);
3507         }
3508     }
3509
3510     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3511     {
3512         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3513                tng_data->output_file_path, __FILE__, __LINE__);
3514         return(TNG_CRITICAL);
3515     }
3516
3517     if(fwrite(block->block_contents, block->block_contents_size, 1,
3518               tng_data->output_file) != 1)
3519     {
3520         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
3521         return(TNG_CRITICAL);
3522     }
3523
3524     return(TNG_SUCCESS);
3525 }
3526
3527
3528 /** Read an atom mappings block (translating between real atom indexes and how
3529  *  the atom info is written in this frame set).
3530  * @param tng_data is a trajectory data container.
3531  * @param block is a general block container.
3532  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3533  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3534  * compared to the md5 hash of the read contents to ensure valid data.
3535  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3536  * error has occured.
3537  */
3538 static tng_function_status tng_trajectory_mapping_block_read
3539                 (tng_trajectory_t tng_data,
3540                  tng_gen_block_t block,
3541                  const char hash_mode)
3542 {
3543     int64_t i;
3544     int offset = 0;
3545     tng_bool same_hash;
3546     tng_trajectory_frame_set_t frame_set =
3547     &tng_data->current_trajectory_frame_set;
3548
3549     tng_particle_mapping_t mapping, mappings;
3550
3551     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3552     {
3553         return(TNG_CRITICAL);
3554     }
3555
3556     if(block->block_contents)
3557     {
3558         free(block->block_contents);
3559     }
3560
3561     block->block_contents = malloc(block->block_contents_size);
3562     if(!block->block_contents)
3563     {
3564         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3565                block->block_contents_size, __FILE__, __LINE__);
3566         return(TNG_CRITICAL);
3567     }
3568
3569     /* Read the whole block into block_contents to be able to write it to disk
3570      *  even if it cannot be interpreted. */
3571     if(fread(block->block_contents, block->block_contents_size, 1,
3572         tng_data->input_file) == 0)
3573     {
3574         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3575         return(TNG_CRITICAL);
3576     }
3577
3578     /* FIXME: Does not check if the size of the contents matches the expected
3579      * size or if the contents can be read. */
3580
3581     if(hash_mode == TNG_USE_HASH)
3582     {
3583         tng_md5_hash_match_verify(block, &same_hash);
3584         if(same_hash != TNG_TRUE)
3585         {
3586             fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
3587                 "%s: %d\n",
3588                 __FILE__, __LINE__);
3589     /*         return(TNG_FAILURE); */
3590         }
3591     }
3592
3593     frame_set->n_mapping_blocks++;
3594     mappings = realloc(frame_set->mappings,
3595                        sizeof(struct tng_particle_mapping) *
3596                        frame_set->n_mapping_blocks);
3597     if(!mappings)
3598     {
3599         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3600                block->block_contents_size, __FILE__, __LINE__);
3601         free(frame_set->mappings);
3602         frame_set->mappings = 0;
3603         return(TNG_CRITICAL);
3604     }
3605     frame_set->mappings = mappings;
3606     mapping = &mappings[frame_set->n_mapping_blocks - 1];
3607
3608
3609     memcpy(&mapping->num_first_particle, block->block_contents+offset,
3610            sizeof(mapping->num_first_particle));
3611     if(tng_data->input_endianness_swap_func_64)
3612     {
3613         if(tng_data->input_endianness_swap_func_64(tng_data,
3614                                                    &mapping->num_first_particle)
3615             != TNG_SUCCESS)
3616         {
3617             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3618                     __FILE__, __LINE__);
3619         }
3620     }
3621     offset += sizeof(mapping->num_first_particle);
3622
3623     memcpy(&mapping->n_particles, block->block_contents+offset,
3624            sizeof(mapping->n_particles));
3625     if(tng_data->input_endianness_swap_func_64)
3626     {
3627         if(tng_data->input_endianness_swap_func_64(tng_data,
3628                                                    &mapping->n_particles)
3629             != TNG_SUCCESS)
3630         {
3631             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3632                     __FILE__, __LINE__);
3633         }
3634     }
3635     offset += sizeof(mapping->n_particles);
3636
3637     mapping->real_particle_numbers = malloc(mapping->n_particles *
3638                                             sizeof(int64_t));
3639     if(!mapping->real_particle_numbers)
3640     {
3641         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3642                 mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
3643         return(TNG_CRITICAL);
3644     }
3645
3646     /* If the byte order needs to be swapped the data must be read one value at
3647      * a time and swapped */
3648     if(tng_data->input_endianness_swap_func_64)
3649     {
3650         for(i = 0; i < mapping->n_particles; i++)
3651         {
3652             memcpy(&mapping->real_particle_numbers[i],
3653                     block->block_contents + offset,
3654                     sizeof(int64_t));
3655             if(tng_data->input_endianness_swap_func_64(tng_data,
3656                                             &mapping->real_particle_numbers[i])
3657                 != TNG_SUCCESS)
3658             {
3659                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3660                         __FILE__, __LINE__);
3661             }
3662             offset += sizeof(int64_t);
3663         }
3664     }
3665     /* Otherwise the data can be read all at once */
3666     else
3667     {
3668         memcpy(mapping->real_particle_numbers, block->block_contents + offset,
3669                mapping->n_particles * sizeof(int64_t));
3670     }
3671
3672
3673     return(TNG_SUCCESS);
3674 }
3675
3676 /** Write the atom mappings of the current trajectory frame set
3677  * @param tng_data is a trajectory data container.
3678  * @param block is a general block container.
3679  * @param mapping_block_nr is the index of the mapping block to write.
3680  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3681  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3682  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
3683  * has occurred or TNG_CRITICAL (2) if a major error has occured.
3684  */
3685 static tng_function_status tng_trajectory_mapping_block_write
3686                 (tng_trajectory_t tng_data,
3687                  tng_gen_block_t block,
3688                  int mapping_block_nr,
3689                  const char hash_mode)
3690 {
3691     char *temp_name;
3692     int i, offset = 0;
3693     unsigned int name_len;
3694     tng_particle_mapping_t mapping =
3695     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
3696
3697     if(mapping_block_nr >=
3698        tng_data->current_trajectory_frame_set.n_mapping_blocks)
3699     {
3700         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
3701                __FILE__, __LINE__);
3702         return(TNG_FAILURE);
3703     }
3704
3705     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3706     {
3707         return(TNG_CRITICAL);
3708     }
3709
3710     name_len = (int)strlen("PARTICLE MAPPING");
3711
3712     if(!block->name || strlen(block->name) < name_len)
3713     {
3714         temp_name = realloc(block->name, name_len + 1);
3715         if(!temp_name)
3716         {
3717             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3718                    name_len+1, __FILE__, __LINE__);
3719             free(block->name);
3720             block->name = 0;
3721             return(TNG_CRITICAL);
3722         }
3723         block->name = temp_name;
3724     }
3725     strcpy(block->name, "PARTICLE MAPPING");
3726     block->id = TNG_PARTICLE_MAPPING;
3727
3728     block->block_contents_size = sizeof(int64_t) * (2 + mapping->n_particles);
3729
3730     if(block->block_contents)
3731     {
3732         free(block->block_contents);
3733     }
3734     block->block_contents = malloc(block->block_contents_size);
3735     if(!block->block_contents)
3736     {
3737         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3738                block->block_contents_size, __FILE__, __LINE__);
3739         return(TNG_CRITICAL);
3740     }
3741
3742     memcpy(block->block_contents, &mapping->num_first_particle,
3743            sizeof(mapping->num_first_particle));
3744     if(tng_data->output_endianness_swap_func_64)
3745     {
3746         if(tng_data->output_endianness_swap_func_64(tng_data,
3747                                       (int64_t *)block->header_contents+offset)
3748             != TNG_SUCCESS)
3749         {
3750             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3751                     __FILE__, __LINE__);
3752         }
3753     }
3754     offset += sizeof(mapping->num_first_particle);
3755
3756     memcpy(block->block_contents+offset, &mapping->n_particles,
3757            sizeof(mapping->n_particles));
3758     if(tng_data->output_endianness_swap_func_64)
3759     {
3760         if(tng_data->output_endianness_swap_func_64(tng_data,
3761                                       (int64_t *)block->header_contents+offset)
3762             != TNG_SUCCESS)
3763         {
3764             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3765                     __FILE__, __LINE__);
3766         }
3767     }
3768     offset += sizeof(mapping->n_particles);
3769
3770     if(tng_data->output_endianness_swap_func_64)
3771     {
3772         for(i = 0; i < mapping->n_particles; i++)
3773         {
3774             memcpy(block->block_contents+offset, &mapping->real_particle_numbers[i],
3775                 sizeof(int64_t));
3776             if(tng_data->output_endianness_swap_func_64(tng_data,
3777                                         (int64_t *)block->header_contents+offset)
3778                 != TNG_SUCCESS)
3779             {
3780                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3781                         __FILE__, __LINE__);
3782             }
3783             offset += sizeof(int64_t);
3784         }
3785     }
3786     else
3787     {
3788         memcpy(block->block_contents+offset, mapping->real_particle_numbers,
3789                mapping->n_particles * sizeof(int64_t));
3790     }
3791
3792
3793     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3794     {
3795         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3796                tng_data->output_file_path, __FILE__, __LINE__);
3797         return(TNG_CRITICAL);
3798     }
3799
3800     if(fwrite(block->block_contents, block->block_contents_size, 1,
3801               tng_data->output_file) != 1)
3802     {
3803         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
3804         return(TNG_CRITICAL);
3805     }
3806
3807     return(TNG_SUCCESS);
3808 }
3809
3810 /** Prepare a block for storing particle data
3811  * @param tng_data is a trajectory data container.
3812  * @param block_type_flag specifies if this is a trajectory block or a
3813  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
3814  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3815  * error has occured.
3816  */
3817 static tng_function_status tng_particle_data_block_create
3818                 (tng_trajectory_t tng_data,
3819                  const char block_type_flag)
3820 {
3821     tng_trajectory_frame_set_t frame_set =
3822     &tng_data->current_trajectory_frame_set;
3823
3824     tng_particle_data_t data;
3825
3826     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
3827     {
3828         frame_set->n_particle_data_blocks++;
3829         data = realloc(frame_set->tr_particle_data,
3830                     sizeof(struct tng_particle_data) *
3831                     frame_set->n_particle_data_blocks);
3832         if(!data)
3833         {
3834             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
3835                 sizeof(struct tng_particle_data) *
3836                 frame_set->n_particle_data_blocks,
3837                 __FILE__, __LINE__);
3838             free(frame_set->tr_particle_data);
3839             frame_set->tr_particle_data = 0;
3840             return(TNG_CRITICAL);
3841         }
3842         frame_set->tr_particle_data = data;
3843     }
3844     else
3845     {
3846         tng_data->n_particle_data_blocks++;
3847         data = realloc(tng_data->non_tr_particle_data,
3848                         sizeof(struct tng_particle_data) *
3849                         tng_data->n_particle_data_blocks);
3850         if(!data)
3851         {
3852             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
3853                     sizeof(struct tng_particle_data) *
3854                     tng_data->n_particle_data_blocks,
3855                     __FILE__, __LINE__);
3856             free(tng_data->non_tr_particle_data);
3857             tng_data->non_tr_particle_data = 0;
3858             return(TNG_CRITICAL);
3859         }
3860         tng_data->non_tr_particle_data = data;
3861     }
3862
3863     return(TNG_SUCCESS);
3864 }
3865
3866 static tng_function_status tng_compress(tng_trajectory_t tng_data,
3867                                         tng_gen_block_t block,
3868                                         const int64_t n_frames,
3869                                         const int64_t n_particles,
3870                                         const char type,
3871                                         void *start_pos)
3872 {
3873     int nalgo;
3874     int new_len;
3875     int *alt_algo = 0;
3876     char *dest, *temp;
3877     int64_t algo_find_n_frames;
3878     unsigned long offset;
3879     float f_precision;
3880     double d_precision;
3881
3882     if(block->id != TNG_TRAJ_POSITIONS &&
3883        block->id != TNG_TRAJ_VELOCITIES)
3884     {
3885         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
3886                "TNG method. %s: %d\n", __FILE__, __LINE__);
3887         return(TNG_FAILURE);
3888     }
3889     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
3890     {
3891         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
3892         return(TNG_FAILURE);
3893     }
3894
3895     if(n_frames <= 0 || n_particles <= 0)
3896     {
3897         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
3898                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
3899         return(TNG_FAILURE);
3900     }
3901
3902     f_precision = 1/(float)tng_data->compression_precision;
3903     d_precision = 1/tng_data->compression_precision;
3904
3905     if(block->id == TNG_TRAJ_POSITIONS)
3906     {
3907         /* If there is only one frame in this frame set and there might be more
3908          * do not store the algorithm as the compression algorithm, but find
3909          * the best one without storing it */
3910         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
3911         {
3912             nalgo = tng_compress_nalgo();
3913             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
3914             if(type == TNG_FLOAT_DATA)
3915             {
3916                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
3917                                                         (int)n_frames,
3918                                                         f_precision,
3919                                                         0, alt_algo,
3920                                                         &new_len);
3921
3922             }
3923             else
3924             {
3925                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
3926                                            (int)n_frames,
3927                                            d_precision,
3928                                            0, alt_algo,
3929                                            &new_len);
3930             }
3931         }
3932         else if(!tng_data->compress_algo_pos)
3933         {
3934             if(n_frames > 10)
3935             {
3936                 algo_find_n_frames = 5;
3937             }
3938             else
3939             {
3940                 algo_find_n_frames = n_frames;
3941             }
3942
3943             nalgo = tng_compress_nalgo();
3944             tng_data->compress_algo_pos=malloc(nalgo *
3945                                            sizeof *tng_data->compress_algo_pos);
3946             if(type == TNG_FLOAT_DATA)
3947             {
3948                 dest = tng_compress_pos_float_find_algo(start_pos, (int)n_particles,
3949                                                         (int)algo_find_n_frames,
3950                                                         f_precision,
3951                                                         0, tng_data->
3952                                                         compress_algo_pos,
3953                                                         &new_len);
3954
3955                 if(algo_find_n_frames < n_frames)
3956                 {
3957                     dest = tng_compress_pos_float(start_pos, (int)n_particles,
3958                                                   (int)n_frames,
3959                                                   f_precision,
3960                                                   0, tng_data->compress_algo_pos,
3961                                                   &new_len);
3962                 }
3963             }
3964             else
3965             {
3966                 dest = tng_compress_pos_find_algo(start_pos, (int)n_particles,
3967                                            (int)algo_find_n_frames,
3968                                            d_precision,
3969                                            0, tng_data->
3970                                            compress_algo_pos,
3971                                            &new_len);
3972
3973                 if(algo_find_n_frames < n_frames)
3974                 {
3975                     dest = tng_compress_pos(start_pos, (int)n_particles,
3976                                             (int)n_frames,
3977                                             d_precision, 0,
3978                                             tng_data->compress_algo_pos,
3979                                             &new_len);
3980                 }
3981             }
3982         }
3983         else
3984         {
3985             if(type == TNG_FLOAT_DATA)
3986             {
3987                 dest = tng_compress_pos_float(start_pos, (int)n_particles,
3988                                               (int)n_frames,
3989                                               f_precision, 0,
3990                                               tng_data->compress_algo_pos, &new_len);
3991             }
3992             else
3993             {
3994                 dest = tng_compress_pos(start_pos, (int)n_particles,
3995                                         (int)n_frames,
3996                                         d_precision, 0,
3997                                         tng_data->compress_algo_pos,
3998                                         &new_len);
3999             }
4000         }
4001     }
4002     else if(block->id == TNG_TRAJ_VELOCITIES)
4003     {
4004         /* If there is only one frame in this frame set and there might be more
4005          * do not store the algorithm as the compression algorithm, but find
4006          * the best one without storing it */
4007         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4008         {
4009             nalgo = tng_compress_nalgo();
4010             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4011             if(type == TNG_FLOAT_DATA)
4012             {
4013                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4014                                                         (int)n_frames,
4015                                                         f_precision,
4016                                                         0, alt_algo,
4017                                                         &new_len);
4018
4019             }
4020             else
4021             {
4022                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4023                                                   (int)n_frames,
4024                                                   d_precision,
4025                                                   0, alt_algo,
4026                                                   &new_len);
4027             }
4028         }
4029         else if(!tng_data->compress_algo_vel)
4030         {
4031             if(n_frames > 10)
4032             {
4033                 algo_find_n_frames = 5;
4034             }
4035             else
4036             {
4037                 algo_find_n_frames = n_frames;
4038             }
4039
4040             nalgo = tng_compress_nalgo();
4041             tng_data->compress_algo_vel=malloc(nalgo *
4042                                            sizeof *tng_data->compress_algo_vel);
4043
4044             if(type == TNG_FLOAT_DATA)
4045             {
4046                 dest = tng_compress_vel_float_find_algo(start_pos, (int)n_particles,
4047                                                         (int)algo_find_n_frames,
4048                                                         f_precision,
4049                                                         0, tng_data->
4050                                                         compress_algo_vel,
4051                                                         &new_len);
4052                 if(algo_find_n_frames < n_frames)
4053                 {
4054                     dest = tng_compress_vel_float(start_pos, (int)n_particles,
4055                                                   (int)n_frames,
4056                                                   f_precision,
4057                                                   0, tng_data->compress_algo_vel,
4058                                                   &new_len);
4059                 }
4060             }
4061             else
4062             {
4063                 dest = tng_compress_vel_find_algo(start_pos, (int)n_particles,
4064                                                   (int)algo_find_n_frames,
4065                                                   d_precision,
4066                                                   0, tng_data->
4067                                                   compress_algo_vel,
4068                                                   &new_len);
4069                 if(algo_find_n_frames < n_frames)
4070                 {
4071                     dest = tng_compress_vel(start_pos, (int)n_particles,
4072                                             (int)n_frames,
4073                                             d_precision,
4074                                             0, tng_data->compress_algo_vel,
4075                                             &new_len);
4076                 }
4077             }
4078         }
4079         else
4080         {
4081             if(type == TNG_FLOAT_DATA)
4082             {
4083                 dest = tng_compress_vel_float(start_pos, (int)n_particles,
4084                                               (int)n_frames,
4085                                               f_precision,
4086                                               0, tng_data->
4087                                               compress_algo_vel,
4088                                               &new_len);
4089             }
4090             else
4091             {
4092                 dest = tng_compress_vel(start_pos, (int)n_particles,
4093                                         (int)n_frames,
4094                                         d_precision,
4095                                         0, tng_data->
4096                                         compress_algo_vel,
4097                                         &new_len);
4098             }
4099         }
4100     }
4101     else
4102     {
4103         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
4104         return(TNG_FAILURE);
4105     }
4106
4107     offset = (unsigned long)((char *)start_pos - block->block_contents);
4108
4109     if(alt_algo)
4110     {
4111         free(alt_algo);
4112     }
4113
4114     block->block_contents_size = new_len + offset;
4115
4116     temp = realloc(block->block_contents, block->block_contents_size);
4117     if(!temp)
4118     {
4119         free(block->block_contents);
4120         block->block_contents = 0;
4121         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4122                block->block_contents_size, __FILE__, __LINE__);
4123         return(TNG_CRITICAL);
4124     }
4125     block->block_contents = temp;
4126     if(dest)
4127     {
4128         memcpy(temp + offset, dest, new_len);
4129         free(dest);
4130     }
4131     else
4132     {
4133         fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
4134         return(TNG_FAILURE);
4135     }
4136
4137     return(TNG_SUCCESS);
4138 }
4139
4140 static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
4141                                           tng_gen_block_t block,
4142                                           const char type,
4143                                           void *start_pos,
4144                                           const unsigned long uncompressed_len)
4145 {
4146     char *temp;
4147     double *d_dest = 0;
4148     float *f_dest = 0;
4149     unsigned long offset;
4150     int result;
4151     (void)tng_data;
4152
4153     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
4154
4155     if(block->id != TNG_TRAJ_POSITIONS &&
4156        block->id != TNG_TRAJ_VELOCITIES)
4157     {
4158         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
4159                "TNG method.\n");
4160         return(TNG_FAILURE);
4161     }
4162     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4163     {
4164         fprintf(stderr, "TNG library: Data type not supported.\n");
4165         return(TNG_FAILURE);
4166     }
4167
4168     if(type == TNG_FLOAT_DATA)
4169     {
4170         f_dest = malloc(uncompressed_len);
4171         if(!f_dest)
4172         {
4173             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4174                 uncompressed_len, __FILE__, __LINE__);
4175             return(TNG_CRITICAL);
4176         }
4177         result = tng_compress_uncompress_float(start_pos, f_dest);
4178     }
4179     else
4180     {
4181         d_dest = malloc(uncompressed_len);
4182         if(!d_dest)
4183         {
4184             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4185                 uncompressed_len, __FILE__, __LINE__);
4186             return(TNG_CRITICAL);
4187         }
4188         result = tng_compress_uncompress(start_pos, d_dest);
4189     }
4190
4191     if(result == 1)
4192     {
4193         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
4194         return(TNG_FAILURE);
4195     }
4196
4197     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
4198
4199     block->block_contents_size = (int64_t)(uncompressed_len + offset);
4200
4201     temp = realloc(block->block_contents, uncompressed_len + offset);
4202     if(!temp)
4203     {
4204         free(block->block_contents);
4205         block->block_contents = 0;
4206         if(d_dest)
4207         {
4208             free(d_dest);
4209         }
4210         if(f_dest)
4211         {
4212             free(f_dest);
4213         }
4214         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4215                block->block_contents_size, __FILE__, __LINE__);
4216         return(TNG_CRITICAL);
4217     }
4218
4219     if(type == TNG_FLOAT_DATA)
4220     {
4221         memcpy(temp + offset, f_dest, uncompressed_len);
4222     }
4223     else
4224     {
4225         memcpy(temp + offset, d_dest, uncompressed_len);
4226     }
4227
4228     block->block_contents = temp;
4229
4230     if(d_dest)
4231     {
4232         free(d_dest);
4233     }
4234     if(f_dest)
4235     {
4236         free(f_dest);
4237     }
4238     return(TNG_SUCCESS);
4239 }
4240
4241 #ifdef USE_ZLIB
4242 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
4243                                              tng_gen_block_t block,
4244                                              void *start_pos, const int len)
4245 {
4246     Bytef *dest;
4247     char *temp;
4248     unsigned long max_len, stat, offset;
4249     (void)tng_data;
4250
4251     max_len = compressBound(len);
4252     dest = malloc(max_len);
4253     if(!dest)
4254     {
4255         fprintf(stderr, "TNG library: Cannot allocate memory (%ld bytes). %s: %d\n",
4256                max_len, __FILE__, __LINE__);
4257         return(TNG_CRITICAL);
4258     }
4259
4260     stat = compress(dest, &max_len, start_pos, len);
4261     if(stat != (unsigned long)Z_OK)
4262     {
4263         free(dest);
4264         if(stat == (unsigned long)Z_MEM_ERROR)
4265         {
4266             fprintf(stderr, "TNG library: Not enough memory. ");
4267         }
4268         else if(stat == (unsigned long)Z_BUF_ERROR)
4269         {
4270             fprintf(stderr, "TNG library: Destination buffer too small. ");
4271         }
4272         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
4273         return(TNG_FAILURE);
4274     }
4275
4276     offset = (char *)start_pos - block->block_contents;
4277
4278     block->block_contents_size = max_len + offset;
4279
4280     temp = realloc(block->block_contents, block->block_contents_size);
4281     if(!temp)
4282     {
4283         free(block->block_contents);
4284         free(dest);
4285         block->block_contents = 0;
4286         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4287                block->block_contents_size, __FILE__, __LINE__);
4288         return(TNG_CRITICAL);
4289     }
4290
4291     block->block_contents = temp;
4292
4293     memcpy(temp + offset, dest, max_len);
4294
4295     free(dest);
4296
4297     return(TNG_SUCCESS);
4298 }
4299
4300 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
4301                                                tng_gen_block_t block,
4302                                                void *start_pos,
4303                                                unsigned long uncompressed_len)
4304 {
4305     Bytef *dest;
4306     char *temp;
4307     unsigned long stat;
4308     int offset;
4309     (void)tng_data;
4310
4311     offset = (char *)start_pos - (char *)block->block_contents;
4312
4313     dest = malloc(uncompressed_len);
4314     if(!dest)
4315     {
4316         fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n",
4317                uncompressed_len, __FILE__, __LINE__);
4318         return(TNG_CRITICAL);
4319     }
4320
4321     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
4322                       block->block_contents_size - offset);
4323
4324     if(stat != Z_OK)
4325     {
4326         free(dest);
4327         if(stat == (unsigned long)Z_MEM_ERROR)
4328         {
4329             fprintf(stderr, "TNG library: Not enough memory. ");
4330         }
4331         else if(stat == (unsigned long)Z_BUF_ERROR)
4332         {
4333             fprintf(stderr, "TNG library: Destination buffer too small. ");
4334         }
4335         else if(stat == (unsigned long)Z_DATA_ERROR)
4336         {
4337             fprintf(stderr, "TNG library: Data corrupt. ");
4338         }
4339         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
4340                __LINE__);
4341         return(TNG_FAILURE);
4342     }
4343
4344
4345     block->block_contents_size = uncompressed_len + offset;
4346
4347     temp = realloc(block->block_contents, uncompressed_len + offset);
4348     if(!temp)
4349     {
4350         free(block->block_contents);
4351         block->block_contents = 0;
4352         free(dest);
4353         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4354                block->block_contents_size, __FILE__, __LINE__);
4355         return(TNG_CRITICAL);
4356     }
4357
4358     memcpy(temp + offset, dest, uncompressed_len);
4359
4360     block->block_contents = temp;
4361
4362     free(dest);
4363     return(TNG_SUCCESS);
4364 }
4365 #endif
4366
4367 /** Allocate memory for storing particle data.
4368  * The allocated block will be refered to by data->values.
4369  * @param tng_data is a trajectory data container.
4370  * @param data is the data struct, which will contain the allocated memory in
4371  * data->values.
4372  * @param n_frames is the number of frames of data to store.
4373  * @param n_particles is the number of particles with data.
4374  * @param n_values_per_frame is the number of data values per particle and
4375  * frame.
4376  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4377  * error has occured.
4378  */
4379 static tng_function_status tng_allocate_particle_data_mem
4380                 (tng_trajectory_t tng_data,
4381                  tng_particle_data_t data,
4382                  int64_t n_frames,
4383                  int64_t stride_length,
4384                  const int64_t n_particles,
4385                  const int64_t n_values_per_frame)
4386 {
4387     void ***values;
4388     int64_t i, j, k, size, frame_alloc;
4389     (void)tng_data;
4390
4391     if(n_particles == 0 || n_values_per_frame == 0)
4392     {
4393         return(TNG_FAILURE);
4394     }
4395
4396     if(data->strings && data->datatype == TNG_CHAR_DATA)
4397     {
4398         for(i = data->n_frames; i--;)
4399         {
4400             for(j = n_particles; j--;)
4401             {
4402                 for(k = data->n_values_per_frame; k--;)
4403                 {
4404                     if(data->strings[i][j][k])
4405                     {
4406                         free(data->strings[i][j][k]);
4407                     }
4408                 }
4409                 free(data->strings[i][j]);
4410             }
4411             free(data->strings[i]);
4412         }
4413         free(data->strings);
4414     }
4415     data->n_frames = n_frames;
4416     n_frames = tng_max_i64(1, n_frames);
4417     data->stride_length = tng_max_i64(1, stride_length);
4418     data->n_values_per_frame = n_values_per_frame;
4419     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
4420
4421     if(data->datatype == TNG_CHAR_DATA)
4422     {
4423         data->strings = malloc(sizeof(char ***) * frame_alloc);
4424         for(i = frame_alloc; i-- ;)
4425         {
4426             data->strings[i] = malloc(sizeof(char **) *
4427                                     n_particles);
4428             if(!data->strings[i])
4429             {
4430                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4431                     sizeof(union data_values *) * n_particles,
4432                     __FILE__, __LINE__);
4433                 return(TNG_CRITICAL);
4434             }
4435             for(j = n_particles; j--;)
4436             {
4437                 data->strings[i][j] = malloc(sizeof(char *) *
4438                                             n_values_per_frame);
4439                 if(!data->strings[i][j])
4440                 {
4441                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4442                         sizeof(union data_values) * n_values_per_frame,
4443                         __FILE__, __LINE__);
4444                     return(TNG_CRITICAL);
4445                 }
4446                 for(k = n_values_per_frame; k--;)
4447                 {
4448                     data->strings[i][j][k] = 0;
4449                 }
4450             }
4451         }
4452     }
4453     else
4454     {
4455         switch(data->datatype)
4456         {
4457         case TNG_INT_DATA:
4458             size = sizeof(int64_t);
4459             break;
4460         case TNG_FLOAT_DATA:
4461             size = sizeof(float);
4462             break;
4463         case TNG_DOUBLE_DATA:
4464         default:
4465             size = sizeof(double);
4466         }
4467
4468         values = realloc(data->values,
4469                          size * frame_alloc *
4470                          n_particles * n_values_per_frame);
4471         if(!values)
4472         {
4473             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4474                    size * frame_alloc *
4475                    n_particles * n_values_per_frame,
4476                    __FILE__, __LINE__);
4477             free(data->values);
4478             data->values = 0;
4479             return(TNG_CRITICAL);
4480         }
4481         data->values = values;
4482     }
4483     return(TNG_SUCCESS);
4484 }
4485
4486 static tng_function_status tng_particle_data_find
4487                 (tng_trajectory_t tng_data,
4488                  const int64_t id,
4489                  tng_particle_data_t *data)
4490 {
4491     int64_t block_index, i;
4492     tng_trajectory_frame_set_t frame_set = &tng_data->
4493                                            current_trajectory_frame_set;
4494     char block_type_flag;
4495
4496     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4497        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4498     {
4499         block_type_flag = TNG_TRAJECTORY_BLOCK;
4500     }
4501     else
4502     {
4503         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4504     }
4505
4506     block_index = -1;
4507     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4508     {
4509         for(i = frame_set->n_particle_data_blocks; i-- ;)
4510         {
4511             *data = &frame_set->tr_particle_data[i];
4512             if((*data)->block_id == id)
4513             {
4514                 block_index = i;
4515                 break;
4516             }
4517         }
4518     }
4519     else
4520     {
4521         for(i = tng_data->n_particle_data_blocks; i-- ;)
4522         {
4523             *data = &tng_data->non_tr_particle_data[i];
4524             if((*data)->block_id == id)
4525             {
4526                 block_index = i;
4527                 break;
4528             }
4529         }
4530     }
4531     if(block_index == -1)
4532     {
4533         return(TNG_FAILURE);
4534     }
4535     return(TNG_SUCCESS);
4536 }
4537
4538 static tng_function_status tng_data_find
4539                 (tng_trajectory_t tng_data,
4540                  const int64_t id,
4541                  tng_non_particle_data_t *data)
4542 {
4543     int64_t block_index, i;
4544     tng_trajectory_frame_set_t frame_set = &tng_data->
4545                                            current_trajectory_frame_set;
4546     char block_type_flag;
4547
4548     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4549        tng_data->current_trajectory_frame_set_output_file_pos > 0)
4550     {
4551         block_type_flag = TNG_TRAJECTORY_BLOCK;
4552     }
4553     else
4554     {
4555         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4556     }
4557
4558     block_index = -1;
4559     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4560     {
4561         for(i = frame_set->n_data_blocks; i-- ;)
4562         {
4563             *data = &frame_set->tr_data[i];
4564             if((*data)->block_id == id)
4565             {
4566                 block_index = i;
4567                 break;
4568             }
4569         }
4570         if(block_index == -1)
4571         {
4572             for(i = tng_data->n_data_blocks; i-- ;)
4573             {
4574                 *data = &tng_data->non_tr_data[i];
4575                 if((*data)->block_id == id)
4576                 {
4577                     block_index = i;
4578                     break;
4579                 }
4580             }
4581         }
4582     }
4583     else
4584     {
4585         for(i = tng_data->n_data_blocks; i-- ;)
4586         {
4587             *data = &tng_data->non_tr_data[i];
4588             if((*data)->block_id == id)
4589             {
4590                 block_index = i;
4591                 break;
4592             }
4593         }
4594     }
4595     if(block_index == -1)
4596     {
4597         return(TNG_FAILURE);
4598     }
4599     return(TNG_SUCCESS);
4600 }
4601
4602 /** Read the values of a particle data block
4603  * @param tng_data is a trajectory data container.
4604  * @param block is the block to store the data (should already contain
4605  * the block headers and the block contents).
4606  * @param offset is the reading offset to point at the place where the actual
4607  * values are stored, starting from the beginning of the block_contents. The
4608  * offset is changed during the reading.
4609  * @param datatype is the type of data of the data block (char, int, float or
4610  * double).
4611  * @param num_first_particle is the number of the first particle in the data
4612  * block. This should be the same as in the corresponding particle mapping
4613  * block.
4614  * @param n_particles is the number of particles in the data block. This should
4615  * be the same as in the corresponding particle mapping block.
4616  * @param first_frame_with_data is the frame number of the first frame with data
4617  * in this data block.
4618  * @param stride_length is the number of frames between each data entry.
4619  * @param n_frames is the number of frames in this data block.
4620  * @param n_values is the number of values per particle and frame stored in this
4621  * data block.
4622  * @param codec_id is the ID of the codec to compress the data.
4623  * @param multiplier is the multiplication factor applied to each data value
4624  * before compression. This factor is applied since some compression algorithms
4625  * work only on integers.
4626  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4627  * error has occured.
4628  */
4629 static tng_function_status tng_particle_data_read
4630                 (tng_trajectory_t tng_data,
4631                  tng_gen_block_t block,
4632                  int *offset,
4633                  const char datatype,
4634                  const int64_t num_first_particle,
4635                  const int64_t n_particles,
4636                  const int64_t first_frame_with_data,
4637                  const int64_t stride_length,
4638                  int64_t n_frames,
4639                  const int64_t n_values,
4640                  const int64_t codec_id,
4641                  const double multiplier)
4642 {
4643     int64_t i, j, k, tot_n_particles, n_frames_div;
4644     int size, len;
4645     unsigned long data_size;
4646     char ***first_dim_values, **second_dim_values;
4647     tng_particle_data_t data;
4648     tng_trajectory_frame_set_t frame_set =
4649     &tng_data->current_trajectory_frame_set;
4650     char block_type_flag;
4651
4652     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
4653
4654     switch(datatype)
4655     {
4656     case TNG_CHAR_DATA:
4657         size = 1;
4658         break;
4659     case TNG_INT_DATA:
4660         size = sizeof(int64_t);
4661         break;
4662     case TNG_FLOAT_DATA:
4663         size = sizeof(float);
4664         break;
4665     case TNG_DOUBLE_DATA:
4666     default:
4667         size = sizeof(double);
4668     }
4669
4670     /* If the block does not exist, create it */
4671     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
4672     {
4673         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
4674         {
4675             block_type_flag = TNG_TRAJECTORY_BLOCK;
4676         }
4677         else
4678         {
4679             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4680         }
4681
4682         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
4683            TNG_SUCCESS)
4684         {
4685             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
4686                    __FILE__, __LINE__);
4687             return(TNG_CRITICAL);
4688         }
4689         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4690         {
4691             data = &frame_set->tr_particle_data[frame_set->
4692                                                 n_particle_data_blocks - 1];
4693         }
4694         else
4695         {
4696             data = &tng_data->non_tr_particle_data[tng_data->
4697                                                    n_particle_data_blocks - 1];
4698         }
4699         data->block_id = block->id;
4700
4701         data->block_name = malloc(strlen(block->name) + 1);
4702         if(!data->block_name)
4703         {
4704             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4705                    (int)strlen(block->name)+1, __FILE__, __LINE__);
4706             return(TNG_CRITICAL);
4707         }
4708         strcpy(data->block_name, block->name);
4709
4710         data->datatype = datatype;
4711
4712         data->values = 0;
4713         /* FIXME: Memory leak from strings. */
4714         data->strings = 0;
4715         data->n_frames = 0;
4716         data->codec_id = codec_id;
4717         data->compression_multiplier = multiplier;
4718         data->last_retrieved_frame = -1;
4719     }
4720
4721     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
4722        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
4723        tng_data->var_num_atoms_flag)
4724     {
4725         tot_n_particles = frame_set->n_particles;
4726     }
4727     else
4728     {
4729         tot_n_particles = tng_data->n_particles;
4730     }
4731
4732     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
4733
4734     if(codec_id != TNG_UNCOMPRESSED)
4735     {
4736         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
4737         switch(codec_id)
4738         {
4739         case TNG_XTC_COMPRESSION:
4740             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
4741             break;
4742         case TNG_TNG_COMPRESSION:
4743 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
4744             if(tng_uncompress(tng_data, block, datatype,
4745                               block->block_contents + *offset,
4746                               data_size) != TNG_SUCCESS)
4747             {
4748                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
4749                        __FILE__, __LINE__);
4750                 return(TNG_CRITICAL);
4751             }
4752 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
4753             break;
4754 #ifdef USE_ZLIB
4755         case TNG_GZIP_COMPRESSION:
4756 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
4757             if(tng_gzip_uncompress(tng_data, block,
4758                                    block->block_contents + *offset,
4759                                    data_size) != TNG_SUCCESS)
4760             {
4761                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
4762                     __LINE__);
4763                 return(TNG_CRITICAL);
4764             }
4765 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
4766             break;
4767 #endif
4768         }
4769     }
4770     /* Allocate memory */
4771     if(!data->values || data->n_frames != n_frames ||
4772        data->n_values_per_frame != n_values)
4773     {
4774         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
4775                                           stride_length,
4776                                           tot_n_particles, n_values) !=
4777            TNG_SUCCESS)
4778         {
4779             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
4780                    __FILE__, __LINE__);
4781             return(TNG_CRITICAL);
4782         }
4783     }
4784
4785     data->first_frame_with_data = first_frame_with_data;
4786
4787     if(datatype == TNG_CHAR_DATA)
4788     {
4789         for(i = 0; i < n_frames_div; i++)
4790         {
4791             first_dim_values = data->strings[i];
4792             for(j = num_first_particle; j < num_first_particle + n_particles;
4793                 j++)
4794             {
4795                 second_dim_values = first_dim_values[j];
4796                 for(k = 0; k < n_values; k++)
4797                 {
4798                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
4799                               TNG_MAX_STR_LEN);
4800                     if(second_dim_values[k])
4801                     {
4802                         free(second_dim_values[k]);
4803                     }
4804                     second_dim_values[k] = malloc(len);
4805                     if(!second_dim_values[k])
4806                     {
4807                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4808                             len, __FILE__, __LINE__);
4809                         return(TNG_CRITICAL);
4810                     }
4811                     strncpy(second_dim_values[k],
4812                             block->block_contents+*offset, len);
4813                     *offset += len;
4814                 }
4815             }
4816         }
4817     }
4818     else
4819     {
4820         memcpy((char *)data->values + n_frames_div * size * n_values *
4821                num_first_particle,
4822                block->block_contents + *offset,
4823                block->block_contents_size - *offset);
4824         switch(datatype)
4825         {
4826         case TNG_FLOAT_DATA:
4827             if(tng_data->input_endianness_swap_func_32)
4828             {
4829                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
4830                 {
4831                     if(tng_data->input_endianness_swap_func_32(tng_data,
4832                         (int32_t *)((char *)data->values + i))
4833                         != TNG_SUCCESS)
4834                     {
4835                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4836                                 __FILE__, __LINE__);
4837                     }
4838                 }
4839             }
4840             break;
4841         case TNG_INT_DATA:
4842         case TNG_DOUBLE_DATA:
4843             if(tng_data->input_endianness_swap_func_64)
4844             {
4845                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
4846                 {
4847                     if(tng_data->input_endianness_swap_func_64(tng_data,
4848                         (int64_t *)((char *)data->values + i))
4849                         != TNG_SUCCESS)
4850                     {
4851                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4852                                 __FILE__, __LINE__);
4853                     }
4854                 }
4855             }
4856             break;
4857         case TNG_CHAR_DATA:
4858             break;
4859         }
4860     }
4861     return(TNG_SUCCESS);
4862 }
4863
4864 /** Write a particle data block
4865  * @param tng_data is a trajectory data container.
4866  * @param block is the block to store the data (should already contain
4867  * the block headers and the block contents).
4868  * @param block_index is the index number of the data block in the frame set.
4869  * @param mapping is the particle mapping that is relevant for the data block.
4870  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4871  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4872  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4873  * error has occured.
4874  */
4875 static tng_function_status tng_particle_data_block_write
4876                 (tng_trajectory_t tng_data,
4877                  tng_gen_block_t block,
4878                  const int64_t block_index,
4879                  const tng_particle_mapping_t mapping,
4880                  const char hash_mode)
4881 {
4882     int64_t n_particles, num_first_particle, n_frames, stride_length;
4883     int64_t frame_step, data_start_pos;
4884     int64_t i, j, k;
4885     int size;
4886     size_t len, offset = 0;
4887     char dependency, temp, *temp_name;
4888     double multiplier;
4889     char ***first_dim_values, **second_dim_values;
4890     tng_trajectory_frame_set_t frame_set;
4891     tng_function_status stat;
4892
4893     tng_particle_data_t data;
4894     char block_type_flag;
4895
4896     frame_set = &tng_data->current_trajectory_frame_set;
4897
4898     /* If we have already started writing frame sets it is too late to write
4899      * non-trajectory data blocks */
4900     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
4901     {
4902         block_type_flag = TNG_TRAJECTORY_BLOCK;
4903     }
4904     else
4905     {
4906         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4907     }
4908
4909     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4910     {
4911         return(TNG_CRITICAL);
4912     }
4913
4914     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4915     {
4916         data = &frame_set->tr_particle_data[block_index];
4917
4918         /* If this data block has not had any data added in this frame set
4919          * do not write it. */
4920         if(data->first_frame_with_data < frame_set->first_frame)
4921         {
4922             return(TNG_SUCCESS);
4923         }
4924
4925         stride_length = tng_max_i64(1, data->stride_length);
4926     }
4927     else
4928     {
4929         data = &tng_data->non_tr_particle_data[block_index];
4930         stride_length = 1;
4931     }
4932
4933     switch(data->datatype)
4934     {
4935     case TNG_CHAR_DATA:
4936         size = 1;
4937         break;
4938     case TNG_INT_DATA:
4939         size = sizeof(int64_t);
4940         break;
4941     case TNG_FLOAT_DATA:
4942         size = sizeof(float);
4943         break;
4944     case TNG_DOUBLE_DATA:
4945     default:
4946         size = sizeof(double);
4947     }
4948
4949     len = strlen(data->block_name) + 1;
4950
4951     if(!block->name || strlen(block->name) < len)
4952     {
4953         temp_name = realloc(block->name, len);
4954         if(!temp_name)
4955         {
4956             fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
4957                    __FILE__, __LINE__);
4958             free(block->name);
4959             block->name = 0;
4960             return(TNG_CRITICAL);
4961         }
4962         block->name = temp_name;
4963     }
4964     strncpy(block->name, data->block_name, len);
4965     block->id = data->block_id;
4966
4967     /* If writing frame independent data data->n_frames is 0, but n_frames
4968        is used for the loop writing the data (and reserving memory) and needs
4969        to be at least 1 */
4970     n_frames = tng_max_i64(1, data->n_frames);
4971
4972     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4973     {
4974         /* If the frame set is finished before writing the full number of frames
4975            make sure the data block is not longer than the frame set. */
4976         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
4977
4978         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
4979     }
4980
4981     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
4982                  n_frames / stride_length;
4983
4984     /* TNG compression will use compression precision to get integers from
4985      * floating point data. The compression multiplier stores that information
4986      * to be able to return the precision of the compressed data. */
4987     if(data->codec_id == TNG_TNG_COMPRESSION)
4988     {
4989         data->compression_multiplier = tng_data->compression_precision;
4990     }
4991     /* Uncompressed data blocks do not use compression multipliers at all.
4992      * GZip compression does not need it either. */
4993     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
4994     {
4995         data->compression_multiplier = 1.0;
4996     }
4997
4998     if(mapping && mapping->n_particles != 0)
4999     {
5000         n_particles = mapping->n_particles;
5001         num_first_particle = mapping->num_first_particle;
5002     }
5003     else
5004     {
5005         num_first_particle = 0;
5006         if(tng_data->var_num_atoms_flag)
5007         {
5008             n_particles = frame_set->n_particles;
5009         }
5010         else
5011         {
5012             n_particles = tng_data->n_particles;
5013         }
5014     }
5015
5016     block->block_contents_size = sizeof(char) * 2 +
5017                                  sizeof(data->n_values_per_frame) +
5018                                  sizeof(data->codec_id) +
5019                                  sizeof(num_first_particle) +
5020                                  sizeof(n_particles);
5021
5022     if(stride_length > 1)
5023     {
5024         block->block_contents_size += sizeof(data->first_frame_with_data) +
5025                                       sizeof(data->stride_length);
5026     }
5027
5028     if(data->codec_id != TNG_UNCOMPRESSED)
5029     {
5030         block->block_contents_size += sizeof(data->compression_multiplier);
5031     }
5032
5033     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
5034     {
5035         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
5036     }
5037     else
5038     {
5039         dependency = TNG_PARTICLE_DEPENDENT;
5040     }
5041     if(dependency & TNG_FRAME_DEPENDENT)
5042     {
5043         block->block_contents_size += sizeof(char);
5044     }
5045
5046     data_start_pos = block->block_contents_size;
5047
5048     if(data->datatype == TNG_CHAR_DATA)
5049     {
5050         for(i = n_frames; i--;)
5051         {
5052             first_dim_values = data->strings[i];
5053             for(j = num_first_particle; j < num_first_particle + n_particles;
5054                 j++)
5055             {
5056                 second_dim_values = first_dim_values[j];
5057                 for(k = data->n_values_per_frame; k--;)
5058                 {
5059                     block->block_contents_size +=
5060                     strlen(second_dim_values[k]) + 1;
5061                 }
5062             }
5063         }
5064     }
5065     else
5066     {
5067         block->block_contents_size += size * frame_step *
5068                                       n_particles * data->n_values_per_frame;
5069     }
5070
5071     if(block->block_contents)
5072     {
5073         free(block->block_contents);
5074     }
5075     block->block_contents = malloc(block->block_contents_size);
5076     if(!block->block_contents)
5077     {
5078         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5079                block->block_contents_size, __FILE__, __LINE__);
5080         return(TNG_CRITICAL);
5081     }
5082
5083
5084     memcpy(block->block_contents, &data->datatype, sizeof(char));
5085     offset += sizeof(char);
5086
5087     memcpy(block->block_contents+offset, &dependency, sizeof(char));
5088     offset += sizeof(char);
5089
5090     if(dependency & TNG_FRAME_DEPENDENT)
5091     {
5092         if(stride_length > 1)
5093         {
5094             temp = 1;
5095         }
5096         else
5097         {
5098             temp = 0;
5099         }
5100         memcpy(block->block_contents+offset, &temp, sizeof(char));
5101         offset += sizeof(char);
5102     }
5103
5104     memcpy(block->block_contents+offset, &data->n_values_per_frame,
5105            sizeof(data->n_values_per_frame));
5106     if(tng_data->output_endianness_swap_func_64)
5107     {
5108         if(tng_data->output_endianness_swap_func_64(tng_data,
5109            (int64_t *)block->header_contents+offset)
5110             != TNG_SUCCESS)
5111         {
5112             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5113                     __FILE__, __LINE__);
5114         }
5115     }
5116     offset += sizeof(data->n_values_per_frame);
5117
5118     memcpy(block->block_contents+offset, &data->codec_id,
5119            sizeof(data->codec_id));
5120     if(tng_data->output_endianness_swap_func_64)
5121     {
5122         if(tng_data->output_endianness_swap_func_64(tng_data,
5123            (int64_t *)block->header_contents+offset)
5124             != TNG_SUCCESS)
5125         {
5126             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5127                     __FILE__, __LINE__);
5128         }
5129     }
5130     offset += sizeof(data->codec_id);
5131
5132     if(data->codec_id != TNG_UNCOMPRESSED)
5133     {
5134         memcpy(block->block_contents+offset, &data->compression_multiplier,
5135                sizeof(data->compression_multiplier));
5136         if(tng_data->output_endianness_swap_func_64)
5137         {
5138             if(tng_data->output_endianness_swap_func_64(tng_data,
5139                (int64_t *)block->header_contents+offset)
5140                 != TNG_SUCCESS)
5141             {
5142                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5143                         __FILE__, __LINE__);
5144             }
5145         }
5146         offset += sizeof(data->compression_multiplier);
5147     }
5148
5149     if(data->n_frames > 0 && stride_length > 1)
5150     {
5151         /* FIXME: first_frame_with_data is not reliably set */
5152         if(data->first_frame_with_data == 0)
5153         {
5154             data->first_frame_with_data = frame_set->first_frame;
5155         }
5156         memcpy(block->block_contents+offset, &data->first_frame_with_data,
5157                sizeof(data->first_frame_with_data));
5158         if(tng_data->output_endianness_swap_func_64)
5159         {
5160             if(tng_data->output_endianness_swap_func_64(tng_data,
5161                (int64_t *)block->header_contents+offset)
5162                 != TNG_SUCCESS)
5163             {
5164                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5165                         __FILE__, __LINE__);
5166             }
5167         }
5168         offset += sizeof(data->first_frame_with_data);
5169
5170         memcpy(block->block_contents+offset, &stride_length,
5171                sizeof(stride_length));
5172         if(tng_data->output_endianness_swap_func_64)
5173         {
5174             if(tng_data->output_endianness_swap_func_64(tng_data,
5175                (int64_t *)block->header_contents+offset)
5176                 != TNG_SUCCESS)
5177             {
5178                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5179                         __FILE__, __LINE__);
5180             }
5181         }
5182         offset += sizeof(stride_length);
5183     }
5184
5185
5186     memcpy(block->block_contents+offset, &num_first_particle,
5187            sizeof(num_first_particle));
5188     if(tng_data->output_endianness_swap_func_64)
5189     {
5190         if(tng_data->output_endianness_swap_func_64(tng_data,
5191            (int64_t *)block->header_contents+offset)
5192             != TNG_SUCCESS)
5193         {
5194             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5195                     __FILE__, __LINE__);
5196         }
5197     }
5198     offset += sizeof(num_first_particle);
5199
5200     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
5201     if(tng_data->output_endianness_swap_func_64)
5202     {
5203         if(tng_data->output_endianness_swap_func_64(tng_data,
5204            (int64_t *)block->header_contents+offset)
5205             != TNG_SUCCESS)
5206         {
5207             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5208                     __FILE__, __LINE__);
5209         }
5210     }
5211     offset += sizeof(n_particles);
5212
5213     if(data->datatype == TNG_CHAR_DATA)
5214     {
5215         if(data->strings)
5216         {
5217             for(i = 0; i < frame_step; i++)
5218             {
5219                 first_dim_values = data->strings[i];
5220                 for(j = num_first_particle; j < num_first_particle + n_particles;
5221                     j++)
5222                 {
5223                     second_dim_values = first_dim_values[j];
5224                     for(k = 0; k < data->n_values_per_frame; k++)
5225                     {
5226                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
5227                         strncpy(block->block_contents+offset,
5228                                 second_dim_values[k], len);
5229                         offset += len;
5230                     }
5231                 }
5232             }
5233         }
5234     }
5235     else if(data->values)
5236     {
5237         memcpy(block->block_contents + offset, data->values,
5238                block->block_contents_size - offset);
5239
5240         switch(data->datatype)
5241         {
5242         case TNG_FLOAT_DATA:
5243             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
5244                data->codec_id == TNG_TNG_COMPRESSION)
5245             {
5246                 if(tng_data->input_endianness_swap_func_32)
5247                 {
5248                     for(i = offset; i < block->block_contents_size; i+=size)
5249                     {
5250                         if(tng_data->input_endianness_swap_func_32(tng_data,
5251                            (int32_t *)(block->block_contents + i))
5252                            != TNG_SUCCESS)
5253                         {
5254                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5255                                     __FILE__, __LINE__);
5256                         }
5257                     }
5258                 }
5259             }
5260             else
5261             {
5262                 multiplier = data->compression_multiplier;
5263                 if(fabs(multiplier - 1.0) > 0.00001 ||
5264                    tng_data->input_endianness_swap_func_32)
5265                 {
5266                     for(i = offset; i < block->block_contents_size; i+=size)
5267                     {
5268                         *(float *)(block->block_contents + i) *= (float)multiplier;
5269                         if(tng_data->input_endianness_swap_func_32 &&
5270                         tng_data->input_endianness_swap_func_32(tng_data,
5271                         (int32_t *)(block->block_contents + i))
5272                         != TNG_SUCCESS)
5273                         {
5274                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5275                                     __FILE__, __LINE__);
5276                         }
5277                     }
5278                 }
5279             }
5280             break;
5281         case TNG_INT_DATA:
5282             if(tng_data->input_endianness_swap_func_64)
5283             {
5284                 for(i = offset; i < block->block_contents_size; i+=size)
5285                 {
5286                     if(tng_data->input_endianness_swap_func_64(tng_data,
5287                        (int64_t *)(block->block_contents + i))
5288                        != TNG_SUCCESS)
5289                     {
5290                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5291                                 __FILE__, __LINE__);
5292                     }
5293                 }
5294             }
5295             break;
5296         case TNG_DOUBLE_DATA:
5297             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
5298                data->codec_id == TNG_TNG_COMPRESSION)
5299             {
5300                 if(tng_data->input_endianness_swap_func_64)
5301                 {
5302                     for(i = offset; i < block->block_contents_size; i+=size)
5303                     {
5304                         if(tng_data->input_endianness_swap_func_64(tng_data,
5305                            (int64_t *)(block->block_contents + i))
5306                            != TNG_SUCCESS)
5307                         {
5308                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5309                                     __FILE__, __LINE__);
5310                         }
5311                     }
5312                 }
5313             }
5314             else
5315             {
5316                 multiplier = data->compression_multiplier;
5317                 if(fabs(multiplier - 1.0) > 0.00001 ||
5318                    tng_data->input_endianness_swap_func_64)
5319                 {
5320                     for(i = offset; i < block->block_contents_size; i+=size)
5321                     {
5322                         *(double *)(block->block_contents + i) *= multiplier;
5323                         if(tng_data->input_endianness_swap_func_64 &&
5324                         tng_data->input_endianness_swap_func_64(tng_data,
5325                         (int64_t *)(block->block_contents + i))
5326                         != TNG_SUCCESS)
5327                         {
5328                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5329                                     __FILE__, __LINE__);
5330                         }
5331                     }
5332                 }
5333             }
5334             break;
5335         case TNG_CHAR_DATA:
5336             break;
5337         }
5338     }
5339     else
5340     {
5341         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
5342     }
5343
5344     frame_set->n_written_frames += frame_set->n_unwritten_frames;
5345     frame_set->n_unwritten_frames = 0;
5346
5347     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
5348     {
5349         switch(data->codec_id)
5350         {
5351         case TNG_XTC_COMPRESSION:
5352             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5353             data->codec_id = TNG_UNCOMPRESSED;
5354             break;
5355         case TNG_TNG_COMPRESSION:
5356             stat = tng_compress(tng_data, block, frame_step,
5357                                 n_particles, data->datatype,
5358                                 block->block_contents + data_start_pos);
5359             if(stat != TNG_SUCCESS)
5360             {
5361                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
5362                     __FILE__, __LINE__);
5363                 if(stat == TNG_CRITICAL)
5364                 {
5365                     return(TNG_CRITICAL);
5366                 }
5367                 /* Set the data again, but with no compression (to write only
5368                  * the relevant data) */
5369                 data->codec_id = TNG_UNCOMPRESSED;
5370                 stat = tng_particle_data_block_write(tng_data, block,
5371                                                      block_index, mapping,
5372                                                      hash_mode);
5373                 return(stat);
5374             }
5375             break;
5376 #ifdef USE_ZLIB
5377         case TNG_GZIP_COMPRESSION:
5378     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
5379             stat = tng_gzip_compress(tng_data, block,
5380                                      block->block_contents + data_start_pos,
5381                                      block->block_contents_size - data_start_pos);
5382             if(stat != TNG_SUCCESS)
5383             {
5384                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
5385                     __LINE__);
5386                 if(stat == TNG_CRITICAL)
5387                 {
5388                     return(TNG_CRITICAL);
5389                 }
5390                 /* Set the data again, but with no compression (to write only
5391                  * the relevant data) */
5392                 data->codec_id = TNG_UNCOMPRESSED;
5393                 stat = tng_particle_data_block_write(tng_data, block,
5394                                                      block_index, mapping,
5395                                                      hash_mode);
5396                 return(stat);
5397             }
5398     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
5399             break;
5400 #endif
5401         }
5402     }
5403
5404     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
5405     {
5406         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
5407                tng_data->output_file_path, __FILE__, __LINE__);
5408         return(TNG_CRITICAL);
5409     }
5410
5411     if(fwrite(block->block_contents, block->block_contents_size, 1,
5412         tng_data->output_file) != 1)
5413     {
5414         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
5415                 __LINE__);
5416         return(TNG_CRITICAL);
5417     }
5418
5419     return(TNG_SUCCESS);
5420 }
5421
5422 /* TEST: */
5423 /** Create a non-particle data block
5424  * @param tng_data is a trajectory data container.
5425  * @param block_type_flag specifies if this is a trajectory block or a
5426  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
5427  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5428  * error has occured.
5429  */
5430 static tng_function_status tng_data_block_create
5431                 (tng_trajectory_t tng_data,
5432                  const char block_type_flag)
5433 {
5434     tng_trajectory_frame_set_t frame_set =
5435     &tng_data->current_trajectory_frame_set;
5436
5437     tng_non_particle_data_t data;
5438
5439     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5440     {
5441         frame_set->n_data_blocks++;
5442         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
5443                        frame_set->n_data_blocks);
5444         if(!data)
5445         {
5446             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5447                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
5448                 __FILE__, __LINE__);
5449             free(frame_set->tr_data);
5450             frame_set->tr_data = 0;
5451             return(TNG_CRITICAL);
5452         }
5453         frame_set->tr_data = data;
5454     }
5455     else
5456     {
5457         tng_data->n_data_blocks++;
5458         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
5459                         tng_data->n_data_blocks);
5460         if(!data)
5461         {
5462             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5463                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
5464                 __FILE__, __LINE__);
5465             free(tng_data->non_tr_data);
5466             tng_data->non_tr_data = 0;
5467             return(TNG_CRITICAL);
5468         }
5469         tng_data->non_tr_data = data;
5470     }
5471
5472     return(TNG_SUCCESS);
5473 }
5474
5475 /* TEST: */
5476 /** Allocate memory for storing non-particle data.
5477  * The allocated block will be refered to by data->values.
5478  * @param tng_data is a trajectory data container.
5479  * @param data is the data struct, which will contain the allocated memory in
5480  * data->values.
5481  * @param n_frames is the number of frames of data to store.
5482  * @param n_values_per_frame is the number of data values per frame.
5483  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5484  * error has occured.
5485  */
5486 static tng_function_status tng_allocate_data_mem
5487                 (tng_trajectory_t tng_data,
5488                  tng_non_particle_data_t data,
5489                  int64_t n_frames,
5490                  int64_t stride_length,
5491                  const int64_t n_values_per_frame)
5492 {
5493     void **values;
5494     int64_t i, j, size, frame_alloc;
5495     (void)tng_data;
5496
5497     if(n_values_per_frame == 0)
5498     {
5499         return(TNG_FAILURE);
5500     }
5501
5502     if(data->strings && data->datatype == TNG_CHAR_DATA)
5503     {
5504         for(i = data->n_frames; i--;)
5505         {
5506             for(j = data->n_values_per_frame; j--;)
5507             {
5508                 if(data->strings[i][j])
5509                 {
5510                     free(data->strings[i][j]);
5511                     data->strings[i][j] = 0;
5512                 }
5513             }
5514             free(data->strings[i]);
5515             data->strings[i] = 0;
5516         }
5517         free(data->strings);
5518     }
5519     data->n_frames = n_frames;
5520     data->stride_length = tng_max_i64(1, stride_length);
5521     n_frames = tng_max_i64(1, n_frames);
5522     data->n_values_per_frame = n_values_per_frame;
5523     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5524
5525     if(data->datatype == TNG_CHAR_DATA)
5526     {
5527         data->strings = malloc(sizeof(char **) * frame_alloc);
5528         for(i = frame_alloc; i-- ;)
5529         {
5530             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
5531             if(!data->strings[i])
5532             {
5533                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5534                        n_values_per_frame,
5535                        __FILE__, __LINE__);
5536                 return(TNG_CRITICAL);
5537             }
5538             for(j = n_values_per_frame; j--;)
5539             {
5540                 data->strings[i][j] = 0;
5541             }
5542         }
5543     }
5544     else
5545     {
5546         switch(data->datatype)
5547         {
5548         case TNG_INT_DATA:
5549             size = sizeof(int64_t);
5550             break;
5551         case TNG_FLOAT_DATA:
5552             size = sizeof(float);
5553             break;
5554         case TNG_DOUBLE_DATA:
5555         default:
5556             size = sizeof(double);
5557         }
5558
5559         values = realloc(data->values,
5560                          size * frame_alloc *
5561                          n_values_per_frame);
5562         if(!values)
5563         {
5564             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5565                    size * frame_alloc *
5566                    n_values_per_frame,
5567                    __FILE__, __LINE__);
5568             free(data->values);
5569             data->values = 0;
5570             return(TNG_CRITICAL);
5571         }
5572         data->values = values;
5573     }
5574
5575     return(TNG_SUCCESS);
5576 }
5577
5578 /** Read the values of a non-particle data block
5579  * @param tng_data is a trajectory data container.
5580  * @param block is the block to store the data (should already contain
5581  * the block headers and the block contents).
5582  * @param offset is the reading offset to point at the place where the actual
5583  * values are stored, starting from the beginning of the block_contents. The
5584  * offset is changed during the reading.
5585  * @param datatype is the type of data of the data block (char, int, float or
5586  * double).
5587  * @param first_frame_with_data is the frame number of the first frame with data
5588  * in this data block.
5589  * @param stride_length is the number of frames between each data entry.
5590  * @param n_frames is the number of frames in this data block.
5591  * @param n_values is the number of values per frame stored in this data block.
5592  * @param codec_id is the ID of the codec to compress the data.
5593  * @param multiplier is the multiplication factor applied to each data value
5594  * before compression. This factor is applied since some compression algorithms
5595  * work only on integers.
5596  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5597  * error has occured.
5598  */
5599 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
5600                                          tng_gen_block_t block,
5601                                          int *offset,
5602                                          const char datatype,
5603                                          const int64_t first_frame_with_data,
5604                                          const int64_t stride_length,
5605                                          int64_t n_frames,
5606                                          const int64_t n_values,
5607                                          const int64_t codec_id,
5608                                          const double multiplier)
5609 {
5610     int64_t i, j, n_frames_div;
5611     int size, len;
5612 #ifdef USE_ZLIB
5613     unsigned long data_size;
5614 #endif
5615     tng_non_particle_data_t data;
5616     tng_trajectory_frame_set_t frame_set =
5617     &tng_data->current_trajectory_frame_set;
5618     char block_type_flag;
5619
5620     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5621
5622 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
5623
5624     switch(datatype)
5625     {
5626     case TNG_CHAR_DATA:
5627         size = 1;
5628         break;
5629     case TNG_INT_DATA:
5630         size = sizeof(int64_t);
5631         break;
5632     case TNG_FLOAT_DATA:
5633         size = sizeof(float);
5634         break;
5635     case TNG_DOUBLE_DATA:
5636     default:
5637         size = sizeof(double);
5638     }
5639
5640     /* If the block does not exist, create it */
5641     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5642     {
5643         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5644         {
5645             block_type_flag = TNG_TRAJECTORY_BLOCK;
5646         }
5647         else
5648         {
5649             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5650         }
5651
5652         if(tng_data_block_create(tng_data, block_type_flag) !=
5653             TNG_SUCCESS)
5654         {
5655             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5656                    __FILE__, __LINE__);
5657             return(TNG_CRITICAL);
5658         }
5659         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5660         {
5661             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
5662         }
5663         else
5664         {
5665             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
5666         }
5667         data->block_id = block->id;
5668
5669         data->block_name = malloc(strlen(block->name) + 1);
5670         if(!data->block_name)
5671         {
5672             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5673                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5674             return(TNG_CRITICAL);
5675         }
5676         strcpy(data->block_name, block->name);
5677
5678         data->datatype = datatype;
5679
5680         data->values = 0;
5681         /* FIXME: Memory leak from strings. */
5682         data->strings = 0;
5683         data->n_frames = 0;
5684         data->codec_id = codec_id;
5685         data->compression_multiplier = multiplier;
5686         data->last_retrieved_frame = -1;
5687     }
5688
5689     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5690
5691     if(codec_id != TNG_UNCOMPRESSED)
5692     {
5693         switch(codec_id)
5694         {
5695 #ifdef USE_ZLIB
5696         case TNG_GZIP_COMPRESSION:
5697             data_size = n_frames_div * size * n_values;
5698     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
5699             if(tng_gzip_uncompress(tng_data, block,
5700                                    block->block_contents + *offset,
5701                                    data_size) != TNG_SUCCESS)
5702             {
5703                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5704                     __LINE__);
5705                 return(TNG_CRITICAL);
5706             }
5707     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
5708             break;
5709 #endif
5710         }
5711     }
5712
5713     /* Allocate memory */
5714     if(!data->values || data->n_frames != n_frames ||
5715        data->n_values_per_frame != n_values)
5716     {
5717         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
5718                                  n_values) !=
5719            TNG_SUCCESS)
5720         {
5721             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
5722                    __FILE__, __LINE__);
5723             return(TNG_CRITICAL);
5724         }
5725     }
5726
5727     data->first_frame_with_data = first_frame_with_data;
5728
5729     if(datatype == TNG_CHAR_DATA)
5730     {
5731         for(i = 0; i < n_frames_div; i++)
5732         {
5733             for(j = 0; j < n_values; j++)
5734             {
5735                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5736                               TNG_MAX_STR_LEN);
5737                 if(data->strings[i][j])
5738                 {
5739                     free(data->strings[i][j]);
5740                 }
5741                 data->strings[i][j] = malloc(len);
5742                 if(!data->strings[i][j])
5743                 {
5744                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5745                            len, __FILE__, __LINE__);
5746                     return(TNG_CRITICAL);
5747                 }
5748                 strncpy(data->strings[i][j], block->block_contents+*offset,
5749                         len);
5750                 *offset += len;
5751             }
5752         }
5753     }
5754     else
5755     {
5756         memcpy(data->values, block->block_contents + *offset,
5757                block->block_contents_size - *offset);
5758         switch(datatype)
5759         {
5760         case TNG_FLOAT_DATA:
5761             if(tng_data->input_endianness_swap_func_32)
5762             {
5763                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5764                 {
5765                     if(tng_data->input_endianness_swap_func_32(tng_data,
5766                         (int32_t *)((char *)data->values + i))
5767                         != TNG_SUCCESS)
5768                     {
5769                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5770                                 __FILE__, __LINE__);
5771                     }
5772                 }
5773             }
5774             break;
5775         case TNG_INT_DATA:
5776         case TNG_DOUBLE_DATA:
5777             if(tng_data->input_endianness_swap_func_64)
5778             {
5779                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5780                 {
5781                     if(tng_data->input_endianness_swap_func_64(tng_data,
5782                         (int64_t *)((char *)data->values + i))
5783                         != TNG_SUCCESS)
5784                     {
5785                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5786                                 __FILE__, __LINE__);
5787                     }
5788                 }
5789             }
5790             break;
5791         case TNG_CHAR_DATA:
5792             break;
5793         }
5794     }
5795     return(TNG_SUCCESS);
5796 }
5797
5798 /** Write a non-particle data block
5799  * @param tng_data is a trajectory data container.
5800  * @param block is the block to store the data (should already contain
5801  * the block headers and the block contents).
5802  * @param block_index is the index number of the data block in the frame set.
5803  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5804  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5805  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5806  * error has occured.
5807  */
5808 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
5809                                                 tng_gen_block_t block,
5810                                                 const int64_t block_index,
5811                                                 const char hash_mode)
5812 {
5813     int64_t n_frames, stride_length, frame_step;
5814     int64_t i, j;
5815     int offset = 0, size;
5816     unsigned int len;
5817 #ifdef USE_ZLIB
5818     int data_start_pos;
5819     tng_function_status stat;
5820 #endif
5821     char temp, dependency, *temp_name;
5822     double multiplier;
5823     tng_trajectory_frame_set_t frame_set =
5824     &tng_data->current_trajectory_frame_set;
5825
5826     tng_non_particle_data_t data;
5827     char block_type_flag;
5828
5829     /* If we have already started writing frame sets it is too late to write
5830      * non-trajectory data blocks */
5831     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5832     {
5833         block_type_flag = TNG_TRAJECTORY_BLOCK;
5834     }
5835     else
5836     {
5837         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5838     }
5839
5840     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5841     {
5842         return(TNG_CRITICAL);
5843     }
5844
5845     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5846     {
5847         data = &frame_set->tr_data[block_index];
5848
5849         /* If this data block has not had any data added in this frame set
5850          * do not write it. */
5851         if(data->first_frame_with_data < frame_set->first_frame)
5852         {
5853             return(TNG_SUCCESS);
5854         }
5855
5856         stride_length = tng_max_i64(1, data->stride_length);
5857     }
5858     else
5859     {
5860         data = &tng_data->non_tr_data[block_index];
5861         stride_length = 1;
5862     }
5863
5864     switch(data->datatype)
5865     {
5866     case TNG_CHAR_DATA:
5867         size = 1;
5868         break;
5869     case TNG_INT_DATA:
5870         size = sizeof(int64_t);
5871         break;
5872     case TNG_FLOAT_DATA:
5873         size = sizeof(float);
5874         break;
5875     case TNG_DOUBLE_DATA:
5876     default:
5877         size = sizeof(double);
5878     }
5879
5880     len = (unsigned int)strlen(data->block_name) + 1;
5881
5882     if(!block->name || strlen(block->name) < len)
5883     {
5884         temp_name = realloc(block->name, len);
5885         if(!temp_name)
5886         {
5887             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
5888                    __FILE__, __LINE__);
5889             free(block->name);
5890             block->name = 0;
5891             return(TNG_CRITICAL);
5892         }
5893         block->name = temp_name;
5894     }
5895     strncpy(block->name, data->block_name, len);
5896     block->id = data->block_id;
5897
5898     /* If writing frame independent data data->n_frames is 0, but n_frames
5899        is used for the loop writing the data (and reserving memory) and needs
5900        to be at least 1 */
5901     n_frames = tng_max_i64(1, data->n_frames);
5902
5903     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5904     {
5905         /* If the frame set is finished before writing the full number of frames
5906            make sure the data block is not longer than the frame set. */
5907         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5908
5909         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5910     }
5911
5912     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
5913                  n_frames / stride_length;
5914
5915     /* TNG compression will use compression precision to get integers from
5916      * floating point data. The compression multiplier stores that information
5917      * to be able to return the precision of the compressed data. */
5918     if(data->codec_id == TNG_TNG_COMPRESSION)
5919     {
5920         data->compression_multiplier = tng_data->compression_precision;
5921     }
5922     /* Uncompressed data blocks do not use compression multipliers at all.
5923      * GZip compression does not need it either. */
5924     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
5925     {
5926         data->compression_multiplier = 1.0;
5927     }
5928
5929     block->block_contents_size = sizeof(char) * 2 +
5930                                  sizeof(data->n_values_per_frame) +
5931                                  sizeof(data->codec_id);
5932
5933     if(stride_length > 1)
5934     {
5935         block->block_contents_size += sizeof(data->first_frame_with_data) +
5936                                       sizeof(data->stride_length);
5937     }
5938
5939     if(data->codec_id != TNG_UNCOMPRESSED)
5940     {
5941         block->block_contents_size += sizeof(data->compression_multiplier);
5942     }
5943
5944     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
5945     {
5946         dependency = TNG_FRAME_DEPENDENT;
5947     }
5948     else
5949     {
5950         dependency = 0;
5951     }
5952     if(dependency & TNG_FRAME_DEPENDENT)
5953     {
5954         block->block_contents_size += sizeof(char);
5955     }
5956
5957 #ifdef USE_ZLIB
5958     data_start_pos = block->block_contents_size;
5959 #endif
5960
5961     if(data->datatype == TNG_CHAR_DATA)
5962     {
5963         for(i = n_frames; i--;)
5964         {
5965             for(j = data->n_values_per_frame; j--;)
5966             {
5967                 block->block_contents_size += strlen(data->strings[i][j]) + 1;
5968             }
5969         }
5970     }
5971     else
5972     {
5973         block->block_contents_size += size * frame_step *
5974         data->n_values_per_frame;
5975     }
5976
5977     if(block->block_contents)
5978     {
5979         free(block->block_contents);
5980     }
5981     block->block_contents = malloc(block->block_contents_size);
5982     if(!block->block_contents)
5983     {
5984         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5985                block->block_contents_size, __FILE__, __LINE__);
5986         return(TNG_CRITICAL);
5987     }
5988
5989
5990     memcpy(block->block_contents, &data->datatype, sizeof(char));
5991     offset += sizeof(char);
5992
5993     memcpy(block->block_contents+offset, &dependency, sizeof(char));
5994     offset += sizeof(char);
5995
5996     if(dependency & TNG_FRAME_DEPENDENT)
5997     {
5998         if(stride_length > 1)
5999         {
6000             temp = 1;
6001         }
6002         else
6003         {
6004             temp = 0;
6005         }
6006         memcpy(block->block_contents+offset, &temp, sizeof(char));
6007         offset += sizeof(char);
6008     }
6009
6010     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6011            sizeof(data->n_values_per_frame));
6012     if(tng_data->output_endianness_swap_func_64)
6013     {
6014         if(tng_data->output_endianness_swap_func_64(tng_data,
6015            (int64_t *)block->header_contents+offset)
6016             != TNG_SUCCESS)
6017         {
6018             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6019                     __FILE__, __LINE__);
6020         }
6021     }
6022     offset += sizeof(data->n_values_per_frame);
6023
6024     memcpy(block->block_contents+offset, &data->codec_id,
6025            sizeof(data->codec_id));
6026     if(tng_data->output_endianness_swap_func_64)
6027     {
6028         if(tng_data->output_endianness_swap_func_64(tng_data,
6029            (int64_t *)block->header_contents+offset)
6030             != TNG_SUCCESS)
6031         {
6032             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6033                     __FILE__, __LINE__);
6034         }
6035     }
6036     offset += sizeof(data->codec_id);
6037
6038     if(data->codec_id != TNG_UNCOMPRESSED)
6039     {
6040         memcpy(block->block_contents+offset, &data->compression_multiplier,
6041                sizeof(data->compression_multiplier));
6042         if(tng_data->output_endianness_swap_func_64)
6043         {
6044             if(tng_data->output_endianness_swap_func_64(tng_data,
6045             (int64_t *)block->header_contents+offset)
6046                 != TNG_SUCCESS)
6047             {
6048                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6049                         __FILE__, __LINE__);
6050             }
6051         }
6052         offset += sizeof(data->compression_multiplier);
6053     }
6054
6055     if(data->n_frames > 0 && stride_length > 1)
6056     {
6057         /* FIXME: first_frame_with_data is not reliably set */
6058         if(data->first_frame_with_data == 0)
6059         {
6060             data->first_frame_with_data = frame_set->first_frame;
6061         }
6062         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6063                sizeof(data->first_frame_with_data));
6064         if(tng_data->output_endianness_swap_func_64)
6065         {
6066             if(tng_data->output_endianness_swap_func_64(tng_data,
6067             (int64_t *)block->header_contents+offset)
6068                 != TNG_SUCCESS)
6069             {
6070                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6071                         __FILE__, __LINE__);
6072             }
6073         }
6074         offset += sizeof(data->first_frame_with_data);
6075
6076         memcpy(block->block_contents+offset, &stride_length,
6077                sizeof(data->stride_length));
6078         if(tng_data->output_endianness_swap_func_64)
6079         {
6080             if(tng_data->output_endianness_swap_func_64(tng_data,
6081             (int64_t *)block->header_contents+offset)
6082                 != TNG_SUCCESS)
6083             {
6084                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6085                         __FILE__, __LINE__);
6086             }
6087         }
6088         offset += sizeof(data->stride_length);
6089     }
6090
6091     if(data->datatype == TNG_CHAR_DATA)
6092     {
6093         if(data->strings)
6094         {
6095             for(i = 0; i < frame_step; i++)
6096             {
6097                 for(j = 0; j < data->n_values_per_frame; j++)
6098                 {
6099                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
6100                     strncpy(block->block_contents+offset, data->strings[i][j],
6101                             len);
6102                     offset += len;
6103                 }
6104             }
6105         }
6106     }
6107     else if(data->values)
6108     {
6109         memcpy(block->block_contents + offset, data->values,
6110                block->block_contents_size - offset);
6111         switch(data->datatype)
6112         {
6113         case TNG_FLOAT_DATA:
6114             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6115                data->codec_id == TNG_TNG_COMPRESSION)
6116             {
6117                 if(tng_data->input_endianness_swap_func_32)
6118                 {
6119                     for(i = offset; i < block->block_contents_size; i+=size)
6120                     {
6121                         if(tng_data->input_endianness_swap_func_32(tng_data,
6122                            (int32_t *)(block->block_contents + i))
6123                            != TNG_SUCCESS)
6124                         {
6125                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6126                                     __FILE__, __LINE__);
6127                         }
6128                     }
6129                 }
6130             }
6131             else
6132             {
6133                 multiplier = data->compression_multiplier;
6134                 if(fabs(multiplier - 1.0) > 0.00001 ||
6135                    tng_data->input_endianness_swap_func_32)
6136                 {
6137                     for(i = offset; block->block_contents_size; i+=size)
6138                     {
6139                         *(float *)(block->block_contents + i) *= (float)multiplier;
6140                         if(tng_data->input_endianness_swap_func_32 &&
6141                         tng_data->input_endianness_swap_func_32(tng_data,
6142                         (int32_t *)(block->block_contents + i))
6143                         != TNG_SUCCESS)
6144                         {
6145                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6146                                     __FILE__, __LINE__);
6147                         }
6148                     }
6149                 }
6150             }
6151             break;
6152         case TNG_INT_DATA:
6153             if(tng_data->input_endianness_swap_func_64)
6154             {
6155                 for(i = offset; i < block->block_contents_size; i+=size)
6156                 {
6157                     if(tng_data->input_endianness_swap_func_64(tng_data,
6158                        (int64_t *)(block->block_contents + i))
6159                        != TNG_SUCCESS)
6160                     {
6161                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6162                                 __FILE__, __LINE__);
6163                     }
6164                 }
6165             }
6166             break;
6167         case TNG_DOUBLE_DATA:
6168             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6169                data->codec_id == TNG_TNG_COMPRESSION)
6170             {
6171                 if(tng_data->input_endianness_swap_func_64)
6172                 {
6173                     for(i = offset; i < block->block_contents_size; i+=size)
6174                     {
6175                         if(tng_data->input_endianness_swap_func_64(tng_data,
6176                            (int64_t *)(block->block_contents + i))
6177                            != TNG_SUCCESS)
6178                         {
6179                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6180                                     __FILE__, __LINE__);
6181                         }
6182                     }
6183                 }
6184             }
6185             else
6186             {
6187                 multiplier = data->compression_multiplier;
6188                 if(fabs(multiplier - 1.0) > 0.00001 ||
6189                    tng_data->input_endianness_swap_func_64)
6190                 {
6191                     for(i = offset; i < block->block_contents_size; i+=size)
6192                     {
6193                         *(double *)(block->block_contents + i) *= multiplier;
6194                         if(tng_data->input_endianness_swap_func_64 &&
6195                         tng_data->input_endianness_swap_func_64(tng_data,
6196                         (int64_t *)(block->block_contents + i))
6197                         != TNG_SUCCESS)
6198                         {
6199                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6200                                     __FILE__, __LINE__);
6201                         }
6202                     }
6203                 }
6204             }
6205             break;
6206         case TNG_CHAR_DATA:
6207             break;
6208         }
6209     }
6210     else
6211     {
6212         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6213     }
6214
6215     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6216     frame_set->n_unwritten_frames = 0;
6217
6218     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6219     {
6220         switch(data->codec_id)
6221         {
6222 #ifdef USE_ZLIB
6223         case TNG_GZIP_COMPRESSION:
6224     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6225             stat = tng_gzip_compress(tng_data, block,
6226                                      block->block_contents + data_start_pos,
6227                                      block->block_contents_size - data_start_pos);
6228             if(stat != TNG_SUCCESS)
6229             {
6230                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6231                     __LINE__);
6232                 if(stat == TNG_CRITICAL)
6233                 {
6234                     return(TNG_CRITICAL);
6235                 }
6236                 data->codec_id = TNG_UNCOMPRESSED;
6237             }
6238     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6239             break;
6240 #endif
6241         }
6242     }
6243
6244     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6245     {
6246         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6247                tng_data->output_file_path, __FILE__, __LINE__);
6248         return(TNG_CRITICAL);
6249     }
6250
6251     if(fwrite(block->block_contents, block->block_contents_size, 1,
6252               tng_data->output_file) != 1)
6253     {
6254         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
6255                __FILE__, __LINE__);
6256         return(TNG_CRITICAL);
6257     }
6258
6259     return(TNG_SUCCESS);
6260 }
6261
6262 /** Read the meta information of a data block (particle or non-particle data).
6263  * @param tng_data is a trajectory data container.
6264  * @param block is the block to store the data (should already contain
6265  * the block headers).
6266  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6267  * error has occured.
6268  */
6269 static tng_function_status tng_data_block_meta_information_read
6270                 (tng_trajectory_t tng_data,
6271                  tng_gen_block_t block,
6272                  int *offset,
6273                  char *datatype,
6274                  char *dependency,
6275                  char *sparse_data,
6276                  int64_t *n_values,
6277                  int64_t *codec_id,
6278                  int64_t *first_frame_with_data,
6279                  int64_t *stride_length,
6280                  int64_t *n_frames,
6281                  int64_t *num_first_particle,
6282                  int64_t *block_n_particles,
6283                  double *multiplier)
6284 {
6285     int meta_size;
6286     char *contents;
6287
6288     if(block->block_contents)
6289     {
6290         contents = block->block_contents;
6291     }
6292     else
6293     {
6294         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
6295         contents = malloc(meta_size);
6296         if(!contents)
6297         {
6298             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6299                meta_size, __FILE__, __LINE__);
6300         }
6301
6302         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
6303         {
6304             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
6305             free(contents);
6306             return(TNG_CRITICAL);
6307         }
6308     }
6309
6310     memcpy(datatype, contents+*offset,
6311            sizeof(*datatype));
6312     *offset += sizeof(*datatype);
6313
6314     memcpy(dependency, contents+*offset,
6315            sizeof(*dependency));
6316     *offset += sizeof(*dependency);
6317
6318     if(*dependency & TNG_FRAME_DEPENDENT)
6319     {
6320         memcpy(sparse_data, contents+*offset,
6321                sizeof(*sparse_data));
6322         *offset += sizeof(*sparse_data);
6323     }
6324
6325     memcpy(n_values, contents+*offset,
6326         sizeof(*n_values));
6327     if(tng_data->input_endianness_swap_func_64)
6328     {
6329         if(tng_data->input_endianness_swap_func_64(tng_data,
6330                                                    n_values)
6331             != TNG_SUCCESS)
6332         {
6333             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6334                     __FILE__, __LINE__);
6335         }
6336     }
6337     *offset += sizeof(*n_values);
6338
6339     memcpy(codec_id, contents+*offset,
6340         sizeof(*codec_id));
6341     if(tng_data->input_endianness_swap_func_64)
6342     {
6343         if(tng_data->input_endianness_swap_func_64(tng_data,
6344                                                    codec_id)
6345             != TNG_SUCCESS)
6346         {
6347             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6348                     __FILE__, __LINE__);
6349         }
6350     }
6351     *offset += sizeof(*codec_id);
6352
6353     if(*codec_id != TNG_UNCOMPRESSED)
6354     {
6355         memcpy(multiplier, contents+*offset,
6356             sizeof(*multiplier));
6357         if(tng_data->input_endianness_swap_func_64)
6358         {
6359             if(tng_data->input_endianness_swap_func_64(tng_data,
6360                                                        (int64_t *) multiplier)
6361                 != TNG_SUCCESS)
6362             {
6363                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6364                         __FILE__, __LINE__);
6365             }
6366         }
6367         *offset += sizeof(*multiplier);
6368     }
6369     else
6370     {
6371         *multiplier = 1;
6372     }
6373
6374     if(*dependency & TNG_FRAME_DEPENDENT)
6375     {
6376         if(*sparse_data)
6377         {
6378             memcpy(first_frame_with_data, contents+*offset,
6379                 sizeof(*first_frame_with_data));
6380             if(tng_data->input_endianness_swap_func_64)
6381             {
6382                 if(tng_data->input_endianness_swap_func_64(tng_data,
6383                                                            first_frame_with_data)
6384                     != TNG_SUCCESS)
6385                 {
6386                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6387                             __FILE__, __LINE__);
6388                 }
6389             }
6390             *offset += sizeof(*first_frame_with_data);
6391
6392             memcpy(stride_length, contents+*offset,
6393                 sizeof(*stride_length));
6394             if(tng_data->input_endianness_swap_func_64)
6395             {
6396                 if(tng_data->input_endianness_swap_func_64(tng_data,
6397                                                            stride_length)
6398                     != TNG_SUCCESS)
6399                 {
6400                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6401                             __FILE__, __LINE__);
6402                 }
6403             }
6404             *offset += sizeof(*stride_length);
6405             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
6406                         (*first_frame_with_data -
6407                         tng_data->current_trajectory_frame_set.first_frame);
6408         }
6409         else
6410         {
6411             *first_frame_with_data = 0;
6412             *stride_length = 1;
6413             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
6414         }
6415     }
6416     else
6417     {
6418         *first_frame_with_data = 0;
6419         *stride_length = 1;
6420         *n_frames = 1;
6421     }
6422
6423     if (*dependency & TNG_PARTICLE_DEPENDENT)
6424     {
6425         memcpy(num_first_particle, contents+*offset,
6426                sizeof(*num_first_particle));
6427         if(tng_data->input_endianness_swap_func_64)
6428         {
6429             if(tng_data->input_endianness_swap_func_64(tng_data,
6430                                                        num_first_particle)
6431                 != TNG_SUCCESS)
6432             {
6433                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6434                         __FILE__, __LINE__);
6435             }
6436         }
6437         *offset += sizeof(*num_first_particle);
6438
6439         memcpy(block_n_particles, contents+*offset,
6440             sizeof(*block_n_particles));
6441         if(tng_data->input_endianness_swap_func_64)
6442         {
6443             if(tng_data->input_endianness_swap_func_64(tng_data,
6444                                                        block_n_particles)
6445                 != TNG_SUCCESS)
6446             {
6447                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6448                         __FILE__, __LINE__);
6449             }
6450         }
6451         *offset += sizeof(*block_n_particles);
6452     }
6453
6454     if(!block->block_contents)
6455     {
6456         free(contents);
6457     }
6458     return(TNG_SUCCESS);
6459 }
6460
6461 /** Read the contents of a data block (particle or non-particle data).
6462  * @param tng_data is a trajectory data container.
6463  * @param block is the block to store the data (should already contain
6464  * the block headers).
6465  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6466  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
6467  * compared to the md5 hash of the read contents to ensure valid data.
6468  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6469  * error has occured.
6470  */
6471 static tng_function_status tng_data_block_contents_read
6472                 (tng_trajectory_t tng_data,
6473                  tng_gen_block_t block,
6474                  const char hash_mode)
6475 {
6476     int64_t n_values, codec_id, n_frames, first_frame_with_data;
6477     int64_t stride_length, block_n_particles, num_first_particle;
6478     double multiplier;
6479     char datatype, dependency, sparse_data;
6480     int offset = 0;
6481     tng_bool same_hash;
6482
6483     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
6484     {
6485         return(TNG_CRITICAL);
6486     }
6487
6488     if(block->block_contents)
6489     {
6490         free(block->block_contents);
6491     }
6492
6493     block->block_contents = malloc(block->block_contents_size);
6494     if(!block->block_contents)
6495     {
6496         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6497                block->block_contents_size, __FILE__, __LINE__);
6498         return(TNG_CRITICAL);
6499     }
6500
6501     /* Read the whole block into block_contents to be able to write it to
6502      * disk even if it cannot be interpreted. */
6503     if(fread(block->block_contents, block->block_contents_size, 1,
6504              tng_data->input_file) == 0)
6505     {
6506         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
6507         return(TNG_CRITICAL);
6508     }
6509
6510     /* FIXME: Does not check if the size of the contents matches the expected
6511      * size or if the contents can be read. */
6512
6513     if(hash_mode == TNG_USE_HASH)
6514     {
6515         tng_md5_hash_match_verify(block, &same_hash);
6516         if(same_hash != TNG_TRUE)
6517         {
6518             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
6519                 block->name, __FILE__, __LINE__);
6520     /*         return(TNG_FAILURE); */
6521         }
6522     }
6523
6524     if(tng_data_block_meta_information_read(tng_data, block,
6525                                             &offset, &datatype,
6526                                             &dependency, &sparse_data,
6527                                             &n_values, &codec_id,
6528                                             &first_frame_with_data,
6529                                             &stride_length, &n_frames,
6530                                             &num_first_particle,
6531                                             &block_n_particles,
6532                                             &multiplier) == TNG_CRITICAL)
6533     {
6534         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
6535             block->name, __FILE__, __LINE__);
6536         return(TNG_CRITICAL);
6537     }
6538
6539     if (dependency & TNG_PARTICLE_DEPENDENT)
6540     {
6541         return(tng_particle_data_read(tng_data, block,
6542                                       &offset, datatype,
6543                                       num_first_particle,
6544                                       block_n_particles,
6545                                       first_frame_with_data,
6546                                       stride_length,
6547                                       n_frames, n_values,
6548                                       codec_id, multiplier));
6549     }
6550     else
6551     {
6552         return(tng_data_read(tng_data, block,
6553                              &offset, datatype,
6554                              first_frame_with_data,
6555                              stride_length,
6556                              n_frames, n_values,
6557                              codec_id, multiplier));
6558     }
6559 }
6560
6561 /** Update the md5 hash of a block already written to the file
6562  * @param tng_data is a trajectory data container.
6563  * @param block is the block, of which to update the md5 hash.
6564  * @param header_start_pos is the file position where the block header starts.
6565  * @param contents_start_pos is the file position where the block contents
6566  * start.
6567  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6568  * error has occured.
6569  */
6570 static tng_function_status tng_md5_hash_update(tng_trajectory_t tng_data,
6571                                                tng_gen_block_t block,
6572                                                const int64_t header_start_pos,
6573                                                const int64_t contents_start_pos)
6574 {
6575     if(block->block_contents)
6576     {
6577         free(block->block_contents);
6578     }
6579
6580     block->block_contents = malloc(block->block_contents_size);
6581     if(!block->block_contents)
6582     {
6583         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6584                block->block_contents_size, __FILE__, __LINE__);
6585         return(TNG_CRITICAL);
6586     }
6587
6588     fseek(tng_data->output_file, (long)contents_start_pos, SEEK_SET);
6589     if(fread(block->block_contents, block->block_contents_size, 1,
6590             tng_data->output_file) == 0)
6591     {
6592         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
6593         return(TNG_CRITICAL);
6594     }
6595
6596     tng_block_md5_hash_generate(block);
6597
6598     fseek(tng_data->output_file, (long)header_start_pos + 3 * sizeof(int64_t),
6599           SEEK_SET);
6600     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
6601
6602     return(TNG_SUCCESS);
6603 }
6604
6605 /** Update the frame set pointers in the file header (general info block),
6606  * already written to disk
6607  * @param tng_data is a trajectory data container.
6608  * @param hash_mode specifies whether to update the block md5 hash when
6609  * updating the pointers.
6610  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6611  * error has occured.
6612  */
6613 static tng_function_status tng_header_pointers_update
6614                 (tng_trajectory_t tng_data, const char hash_mode)
6615 {
6616     tng_gen_block_t block;
6617     FILE *temp = tng_data->input_file;
6618     int64_t output_file_pos, pos, contents_start_pos;
6619
6620     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6621     {
6622         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6623                __FILE__, __LINE__);
6624         return(TNG_CRITICAL);
6625     }
6626
6627     tng_data->input_file = tng_data->output_file;
6628
6629     tng_block_init(&block);
6630
6631     output_file_pos = ftell(tng_data->output_file);
6632     fseek(tng_data->output_file, 0, SEEK_SET);
6633
6634     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6635     {
6636         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
6637                __FILE__, __LINE__);
6638         tng_data->input_file = temp;
6639         tng_block_destroy(&block);
6640         return(TNG_CRITICAL);
6641     }
6642
6643     contents_start_pos = ftell(tng_data->output_file);
6644
6645     fseek(tng_data->output_file, (long)block->block_contents_size - 5 *
6646           sizeof(int64_t), SEEK_CUR);
6647
6648     tng_data->input_file = temp;
6649
6650     pos = tng_data->first_trajectory_frame_set_output_file_pos;
6651
6652     if(tng_data->input_endianness_swap_func_64)
6653     {
6654         if(tng_data->input_endianness_swap_func_64(tng_data,
6655                                                     &pos)
6656             != TNG_SUCCESS)
6657         {
6658             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6659                     __FILE__, __LINE__);
6660         }
6661     }
6662
6663     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6664     {
6665         tng_block_destroy(&block);
6666         return(TNG_CRITICAL);
6667     }
6668
6669     pos = tng_data->last_trajectory_frame_set_output_file_pos;
6670
6671     if(tng_data->input_endianness_swap_func_64)
6672     {
6673         if(tng_data->input_endianness_swap_func_64(tng_data,
6674                                                     &pos)
6675             != TNG_SUCCESS)
6676         {
6677             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6678                     __FILE__, __LINE__);
6679         }
6680     }
6681
6682     if(fwrite(&pos,
6683         sizeof(int64_t), 1, tng_data->output_file) != 1)
6684     {
6685         tng_block_destroy(&block);
6686         return(TNG_CRITICAL);
6687     }
6688
6689     if(hash_mode == TNG_USE_HASH)
6690     {
6691         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
6692     }
6693
6694     tng_block_destroy(&block);
6695
6696     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
6697
6698     return(TNG_SUCCESS);
6699 }
6700
6701 /** Update the frame set pointers in the current frame set block, already
6702  * written to disk. It also updates the pointers of the blocks pointing to
6703  * the current frame set block.
6704  * @param tng_data is a trajectory data container.
6705  * @param hash_mode specifies whether to update the block md5 hash when
6706  * updating the pointers.
6707  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6708  * error has occured.
6709  */
6710 static tng_function_status tng_frame_set_pointers_update
6711                 (tng_trajectory_t tng_data, const char hash_mode)
6712 {
6713     tng_gen_block_t block;
6714     tng_trajectory_frame_set_t frame_set;
6715     FILE *temp = tng_data->input_file;
6716     int64_t pos, output_file_pos, header_start_pos, contents_start_pos;
6717
6718     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6719     {
6720         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6721                __FILE__, __LINE__);
6722         return(TNG_CRITICAL);
6723     }
6724
6725     tng_block_init(&block);
6726     output_file_pos = ftell(tng_data->output_file);
6727
6728     tng_data->input_file = tng_data->output_file;
6729
6730     frame_set = &tng_data->current_trajectory_frame_set;
6731
6732     /* Update previous frame set */
6733     if(frame_set->prev_frame_set_file_pos != -1 &&
6734        frame_set->prev_frame_set_file_pos != 0)
6735     {
6736         fseek(tng_data->output_file, (long)frame_set->prev_frame_set_file_pos,
6737               SEEK_SET);
6738
6739         header_start_pos = frame_set->prev_frame_set_file_pos;
6740
6741         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6742         {
6743             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
6744                 __FILE__, __LINE__);
6745             tng_data->input_file = temp;
6746             tng_block_destroy(&block);
6747             return(TNG_CRITICAL);
6748         }
6749
6750         contents_start_pos = ftell(tng_data->output_file);
6751
6752         fseek(tng_data->output_file, (long)block->block_contents_size - (6 *
6753             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
6754
6755         pos = tng_data->current_trajectory_frame_set_output_file_pos;
6756
6757         if(tng_data->input_endianness_swap_func_64)
6758         {
6759             if(tng_data->input_endianness_swap_func_64(tng_data,
6760                                                         &pos)
6761                 != TNG_SUCCESS)
6762             {
6763                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6764                         __FILE__, __LINE__);
6765             }
6766         }
6767
6768         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6769         {
6770             tng_data->input_file = temp;
6771             tng_block_destroy(&block);
6772             return(TNG_CRITICAL);
6773         }
6774
6775         if(hash_mode == TNG_USE_HASH)
6776         {
6777             tng_md5_hash_update(tng_data, block, header_start_pos,
6778                                 contents_start_pos);
6779         }
6780         fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
6781     }
6782
6783     /* Update the frame set one medium stride step before */
6784     if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
6785        frame_set->medium_stride_prev_frame_set_file_pos != 0)
6786     {
6787         fseek(tng_data->output_file,
6788               (long)frame_set->medium_stride_prev_frame_set_file_pos,
6789               SEEK_SET);
6790
6791         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6792         {
6793             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6794                 __FILE__, __LINE__);
6795             tng_data->input_file = temp;
6796             tng_block_destroy(&block);
6797             return(TNG_CRITICAL);
6798         }
6799
6800         contents_start_pos = ftell(tng_data->output_file);
6801
6802         fseek(tng_data->output_file, (long)block->block_contents_size - (4 *
6803             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
6804
6805         pos = tng_data->current_trajectory_frame_set_output_file_pos;
6806
6807         if(tng_data->input_endianness_swap_func_64)
6808         {
6809             if(tng_data->input_endianness_swap_func_64(tng_data,
6810                                                         &pos)
6811                 != TNG_SUCCESS)
6812             {
6813                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6814                         __FILE__, __LINE__);
6815             }
6816         }
6817
6818         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6819         {
6820             tng_data->input_file = temp;
6821             tng_block_destroy(&block);
6822             return(TNG_CRITICAL);
6823         }
6824
6825         if(hash_mode == TNG_USE_HASH)
6826         {
6827             tng_md5_hash_update(tng_data, block,
6828                                 frame_set->medium_stride_prev_frame_set_file_pos,
6829                                 contents_start_pos);
6830         }
6831     }
6832
6833     /* Update the frame set one long stride step before */
6834     if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
6835        frame_set->long_stride_prev_frame_set_file_pos != 0)
6836     {
6837         fseek(tng_data->output_file,
6838               (long)frame_set->long_stride_prev_frame_set_file_pos,
6839               SEEK_SET);
6840
6841         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6842         {
6843             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6844                 __FILE__, __LINE__);
6845             tng_data->input_file = temp;
6846             tng_block_destroy(&block);
6847             return(TNG_CRITICAL);
6848         }
6849
6850         contents_start_pos = ftell(tng_data->output_file);
6851
6852         fseek(tng_data->output_file, (long)block->block_contents_size - (2 *
6853             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
6854
6855         pos = tng_data->current_trajectory_frame_set_output_file_pos;
6856
6857         if(tng_data->input_endianness_swap_func_64)
6858         {
6859             if(tng_data->input_endianness_swap_func_64(tng_data,
6860                                                         &pos)
6861                 != TNG_SUCCESS)
6862             {
6863                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6864                         __FILE__, __LINE__);
6865             }
6866         }
6867
6868         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
6869         {
6870             tng_data->input_file = temp;
6871             tng_block_destroy(&block);
6872             return(TNG_CRITICAL);
6873         }
6874
6875         if(hash_mode == TNG_USE_HASH)
6876         {
6877             tng_md5_hash_update(tng_data, block,
6878                                 frame_set->long_stride_prev_frame_set_file_pos,
6879                                 contents_start_pos);
6880         }
6881     }
6882
6883     fseek(tng_data->output_file, (long)output_file_pos, SEEK_SET);
6884
6885     tng_data->input_file = temp;
6886
6887     tng_block_destroy(&block);
6888
6889     return(TNG_SUCCESS);
6890 }
6891 /*
6892 // ** Move the blocks in a frame set so that there is no unused space between
6893 //  * them. This can only be done on the last frame set in the file and should
6894 //  * be done e.g. if the last frame set in the file has fewer frames than
6895 //  * default or after compressing data blocks in a frame set.
6896 //  * @param tng_data is a trajectory data container.
6897 //  * @details the current_trajectory_frame_set is the one that will be modified.
6898 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
6899 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
6900 //  * FIXME: This function is not finished!!!
6901 //  *
6902 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
6903 // {
6904 //     tng_gen_block_t block;
6905 //     tng_trajectory_frame_set_t frame_set;
6906 //     FILE *temp = tng_data->input_file;
6907 //     int64_t pos, contents_start_pos, output_file_len;
6908 //
6909 //     frame_set = &tng_data->current_trajectory_frame_set;
6910 //
6911 //     if(frame_set->n_written_frames == frame_set->n_frames)
6912 //     {
6913 //         return(TNG_SUCCESS);
6914 //     }
6915 //
6916 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
6917 //        tng_data->last_trajectory_frame_set_output_file_pos)
6918 //     {
6919 //     }
6920 //
6921 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6922 //     {
6923 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6924 //                __FILE__, __LINE__);
6925 //         return(TNG_CRITICAL);
6926 //     }
6927 //
6928 //     tng_block_init(&block);
6929 // //     output_file_pos = ftell(tng_data->output_file);
6930 //
6931 //     tng_data->input_file = tng_data->output_file;
6932 //
6933 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
6934 //
6935 //     fseek(tng_data->output_file, pos, SEEK_SET);
6936 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6937 //     {
6938 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6939 //             __FILE__, __LINE__);
6940 //         tng_data->input_file = temp;
6941 //         tng_block_destroy(&block);
6942 //         return(TNG_CRITICAL);
6943 //     }
6944 //
6945 //     contents_start_pos = ftell(tng_data->output_file);
6946 //
6947 //     fseek(tng_data->output_file, 0, SEEK_END);
6948 //     output_file_len = ftell(tng_data->output_file);
6949 //     pos = contents_start_pos + block->block_contents_size;
6950 //     fseek(tng_data->output_file, pos,
6951 //           SEEK_SET);
6952 //
6953 //     while(pos < output_file_len)
6954 //     {
6955 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6956 //         {
6957 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
6958 //                    __FILE__, __LINE__);
6959 //             tng_data->input_file = temp;
6960 //             tng_block_destroy(&block);
6961 //             return(TNG_CRITICAL);
6962 //         }
6963 //         pos += block->header_contents_size + block->block_contents_size;
6964 //         fseek(tng_data->output_file, pos, SEEK_SET);
6965 //     }
6966 //
6967 //     return(TNG_SUCCESS);
6968 // }
6969 */
6970 /** Finish writing the current frame set. Update the number of frames
6971  * and the hashes of the frame set and all its data blocks (if hash_mode
6972  * == TNG_USE_HASH).
6973  * @param tng_data is a trajectory data container.
6974  * @param hash_mode specifies whether to update the block md5 hash when
6975  * updating the pointers.
6976  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6977  * error has occured.
6978  */
6979 static tng_function_status tng_frame_set_finalize
6980                 (tng_trajectory_t tng_data, const char hash_mode)
6981 {
6982     tng_gen_block_t block;
6983     tng_trajectory_frame_set_t frame_set;
6984     FILE *temp = tng_data->input_file;
6985     int64_t pos, contents_start_pos, output_file_len;
6986
6987     frame_set = &tng_data->current_trajectory_frame_set;
6988
6989     if(frame_set->n_written_frames == frame_set->n_frames)
6990     {
6991         return(TNG_SUCCESS);
6992     }
6993
6994     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6995     {
6996         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6997                __FILE__, __LINE__);
6998         return(TNG_CRITICAL);
6999     }
7000
7001     tng_block_init(&block);
7002 /*     output_file_pos = ftell(tng_data->output_file); */
7003
7004     tng_data->input_file = tng_data->output_file;
7005
7006     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7007
7008     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7009
7010     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7011     {
7012         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7013             __FILE__, __LINE__);
7014         tng_data->input_file = temp;
7015         tng_block_destroy(&block);
7016         return(TNG_CRITICAL);
7017     }
7018
7019     contents_start_pos = ftell(tng_data->output_file);
7020
7021     fseek(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
7022     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
7023               1, tng_data->output_file) != 1)
7024     {
7025         tng_data->input_file = temp;
7026         tng_block_destroy(&block);
7027         return(TNG_CRITICAL);
7028     }
7029
7030
7031     if(hash_mode == TNG_USE_HASH)
7032     {
7033         tng_md5_hash_update(tng_data, block, pos,
7034                             pos + block->header_contents_size);
7035     }
7036
7037     fseek(tng_data->output_file, 0, SEEK_END);
7038     output_file_len = ftell(tng_data->output_file);
7039     pos = contents_start_pos + block->block_contents_size;
7040     fseek(tng_data->output_file, (long)pos, SEEK_SET);
7041
7042     while(pos < output_file_len)
7043     {
7044         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7045         {
7046             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7047                    __FILE__, __LINE__);
7048             tng_data->input_file = temp;
7049             tng_block_destroy(&block);
7050             return(TNG_CRITICAL);
7051         }
7052
7053         if(hash_mode == TNG_USE_HASH)
7054         {
7055             tng_md5_hash_update(tng_data, block, pos,
7056                                 pos + block->header_contents_size);
7057         }
7058         pos += block->header_contents_size + block->block_contents_size;
7059         fseek(tng_data->output_file, (long)pos, SEEK_SET);
7060     }
7061
7062     tng_data->input_file = temp;
7063     tng_block_destroy(&block);
7064     return(TNG_SUCCESS);
7065 }
7066
7067 /*
7068 // ** Sets the name of a file contents block
7069 //  * @param tng_data is a trajectory data container.
7070 //  * @param block is the block, of which to change names.
7071 //  * @param new_name is the new name of the block.
7072 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7073 //  * error has occured.
7074 //
7075 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7076 //                                               tng_gen_block_t block,
7077 //                                               const char *new_name)
7078 // {
7079 //     int len;
7080 //
7081 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7082 //
7083 //      * If the currently stored string length is not enough to store the new
7084 //      * string it is freed and reallocated. *
7085 //     if(block->name && strlen(block->name) < len)
7086 //     {
7087 //         free(block->name);
7088 //         block->name = 0;
7089 //     }
7090 //     if(!block->name)
7091 //     {
7092 //         block->name = malloc(len);
7093 //         if(!block->name)
7094 //         {
7095 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7096 //                    __FILE__, __LINE__);
7097 //             return(TNG_CRITICAL);
7098 //         }
7099 //     }
7100 //
7101 //     strncpy(block->name, new_name, len);
7102 //
7103 //     return(TNG_SUCCESS);
7104 // }
7105 */
7106
7107 tng_function_status tng_atom_residue_get(const tng_trajectory_t tng_data,
7108                                          const tng_atom_t atom,
7109                                          tng_residue_t *residue)
7110 {
7111     (void) tng_data;
7112
7113     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7114
7115     *residue = atom->residue;
7116
7117     return(TNG_SUCCESS);
7118 }
7119
7120 tng_function_status tng_atom_name_get(const tng_trajectory_t tng_data,
7121                                       const tng_atom_t atom,
7122                                       char *name,
7123                                       const int max_len)
7124 {
7125     (void) tng_data;
7126     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7127     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7128
7129     strncpy(name, atom->name, max_len - 1);
7130     name[max_len - 1] = 0;
7131
7132     if(strlen(atom->name) > (unsigned int)max_len - 1)
7133     {
7134         return(TNG_FAILURE);
7135     }
7136     return(TNG_SUCCESS);
7137 }
7138
7139 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7140                                       tng_atom_t atom,
7141                                       const char *new_name)
7142 {
7143     unsigned int len;
7144     (void)tng_data;
7145
7146     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7147     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7148
7149     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7150
7151     /* If the currently stored string length is not enough to store the new
7152      * string it is freed and reallocated. */
7153     if(atom->name && strlen(atom->name) < len)
7154     {
7155         free(atom->name);
7156         atom->name = 0;
7157     }
7158     if(!atom->name)
7159     {
7160         atom->name = malloc(len);
7161         if(!atom->name)
7162         {
7163             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7164                    __FILE__, __LINE__);
7165             return(TNG_CRITICAL);
7166         }
7167     }
7168
7169     strncpy(atom->name, new_name, len);
7170
7171     return(TNG_SUCCESS);
7172 }
7173
7174 tng_function_status tng_atom_type_get(const tng_trajectory_t tng_data,
7175                                       const tng_atom_t atom,
7176                                       char *type,
7177                                       const int max_len)
7178 {
7179     (void) tng_data;
7180     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7181     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7182
7183     strncpy(type, atom->atom_type, max_len - 1);
7184     type[max_len - 1] = 0;
7185
7186     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7187     {
7188         return(TNG_FAILURE);
7189     }
7190     return(TNG_SUCCESS);
7191 }
7192
7193 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7194                                       tng_atom_t atom,
7195                                       const char *new_type)
7196 {
7197     unsigned int len;
7198     (void)tng_data;
7199
7200     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7201     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7202
7203     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7204
7205     /* If the currently stored string length is not enough to store the new
7206      * string it is freed and reallocated. */
7207     if(atom->atom_type && strlen(atom->atom_type) < len)
7208     {
7209         free(atom->atom_type);
7210         atom->atom_type = 0;
7211     }
7212     if(!atom->atom_type)
7213     {
7214         atom->atom_type = malloc(len);
7215         if(!atom->atom_type)
7216         {
7217             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7218                    __FILE__, __LINE__);
7219             return(TNG_CRITICAL);
7220         }
7221     }
7222
7223     strncpy(atom->atom_type, new_type, len);
7224
7225     return(TNG_SUCCESS);
7226 }
7227
7228 /** Initialise an atom struct
7229  * @param atom is the atom to initialise.
7230  * @return TNG_SUCCESS (0) if successful.
7231  */
7232 static tng_function_status tng_atom_init(tng_atom_t atom)
7233 {
7234     atom->name = 0;
7235     atom->atom_type = 0;
7236
7237     return(TNG_SUCCESS);
7238 }
7239
7240 /** Free the memory in an atom struct
7241  * @param atom is the atom to destroy.
7242  * @return TNG_SUCCESS (0) if successful.
7243  */
7244 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7245 {
7246     if(atom->name)
7247     {
7248         free(atom->name);
7249         atom->name = 0;
7250     }
7251     if(atom->atom_type)
7252     {
7253         free(atom->atom_type);
7254         atom->atom_type = 0;
7255     }
7256
7257     return(TNG_SUCCESS);
7258 }
7259
7260 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7261                 (tng_trajectory_t tng_data,
7262                  const char *name,
7263                  tng_molecule_t *molecule)
7264 {
7265     int64_t id, i;
7266     tng_bool found_id = TNG_TRUE;
7267
7268     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7269     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7270
7271     /* Find an unused ID */
7272     id = 0;
7273     while(found_id)
7274     {
7275         found_id = TNG_FALSE;
7276         for(i = tng_data->n_molecules; i--;)
7277         {
7278             if(tng_data->molecules[i].id == id)
7279             {
7280                 found_id = TNG_TRUE;
7281                 i = 0;
7282             }
7283         }
7284         if(found_id)
7285         {
7286             id++;
7287         }
7288     }
7289
7290     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7291 }
7292
7293 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7294                 (tng_trajectory_t tng_data,
7295                  const char *name,
7296                  const int64_t id,
7297                  tng_molecule_t *molecule)
7298 {
7299     tng_molecule_t new_molecules;
7300     int64_t *new_molecule_cnt_list, i;
7301     tng_function_status stat = TNG_SUCCESS;
7302
7303     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7304     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7305
7306     new_molecules = realloc(tng_data->molecules,
7307                             sizeof(struct tng_molecule) *
7308                             (tng_data->n_molecules + 1));
7309
7310     if(!new_molecules)
7311     {
7312         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7313                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7314                __FILE__, __LINE__);
7315         free(tng_data->molecules);
7316         tng_data->molecules = 0;
7317         return(TNG_CRITICAL);
7318     }
7319
7320     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7321                                     sizeof(int64_t) *
7322                                     (tng_data->n_molecules + 1));
7323
7324     if(!new_molecule_cnt_list)
7325     {
7326         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7327                sizeof(int64_t) * (tng_data->n_molecules + 1),
7328                __FILE__, __LINE__);
7329         free(tng_data->molecule_cnt_list);
7330         tng_data->molecule_cnt_list = 0;
7331         free(new_molecules);
7332         return(TNG_CRITICAL);
7333     }
7334
7335     tng_data->molecules = new_molecules;
7336     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7337
7338     *molecule = &new_molecules[tng_data->n_molecules];
7339
7340     tng_molecule_init(tng_data, *molecule);
7341     tng_molecule_name_set(tng_data, *molecule, name);
7342
7343     /* FIXME: Should this be a function argument instead? */
7344     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7345
7346     for(i = tng_data->n_molecules; i--;)
7347     {
7348         if(tng_data->molecules[i].id == id)
7349         {
7350             stat = TNG_FAILURE;
7351             fprintf(stderr, "TNG library: Molecule ID %"PRId64" already in use. %s: %d\n", id,
7352                    __FILE__, __LINE__);
7353             break;
7354         }
7355     }
7356
7357     (*molecule)->id = id;
7358
7359     tng_data->n_molecules++;
7360
7361     return(stat);
7362 }
7363
7364 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
7365                 (tng_trajectory_t tng_data,
7366                  tng_molecule_t *molecule_p)
7367 {
7368     tng_bool found_id = TNG_TRUE;
7369     tng_molecule_t new_molecules, molecule;
7370     int64_t *new_molecule_cnt_list, i, id;
7371
7372     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7373
7374     /* Find an unused ID */
7375     id = 0;
7376     while(found_id)
7377     {
7378         found_id = TNG_FALSE;
7379         for(i = tng_data->n_molecules; i--;)
7380         {
7381             if(tng_data->molecules[i].id == id)
7382             {
7383                 found_id = TNG_TRUE;
7384                 i = 0;
7385             }
7386         }
7387         if(found_id)
7388         {
7389             id++;
7390         }
7391     }
7392
7393     new_molecules = realloc(tng_data->molecules,
7394                             sizeof(struct tng_molecule) *
7395                             (tng_data->n_molecules + 1));
7396
7397     if(!new_molecules)
7398     {
7399         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7400                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7401                __FILE__, __LINE__);
7402         free(tng_data->molecules);
7403         tng_data->molecules = 0;
7404         return(TNG_CRITICAL);
7405     }
7406
7407     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7408                                     sizeof(int64_t) *
7409                                     (tng_data->n_molecules + 1));
7410
7411     if(!new_molecule_cnt_list)
7412     {
7413         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7414                sizeof(int64_t) * (tng_data->n_molecules + 1),
7415                __FILE__, __LINE__);
7416         free(tng_data->molecule_cnt_list);
7417         tng_data->molecule_cnt_list = 0;
7418         free(new_molecules);
7419         return(TNG_CRITICAL);
7420     }
7421
7422     molecule = *molecule_p;
7423
7424     tng_data->molecules = new_molecules;
7425     tng_data->molecule_cnt_list = new_molecule_cnt_list;
7426
7427     new_molecules[tng_data->n_molecules] = *molecule;
7428
7429     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7430
7431     free(*molecule_p);
7432
7433     molecule = &new_molecules[tng_data->n_molecules];
7434
7435     *molecule_p = molecule;
7436
7437     molecule->id = id;
7438
7439     tng_data->n_molecules++;
7440
7441     return(TNG_SUCCESS);
7442 }
7443
7444 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
7445                                           const tng_molecule_t molecule,
7446                                           char *name,
7447                                           const int max_len)
7448 {
7449     (void) tng_data;
7450     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7451     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7452
7453     strncpy(name, molecule->name, max_len - 1);
7454     name[max_len - 1] = 0;
7455
7456     if(strlen(molecule->name) > (unsigned int)max_len - 1)
7457     {
7458         return(TNG_FAILURE);
7459     }
7460     return(TNG_SUCCESS);
7461 }
7462
7463 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
7464                 (tng_trajectory_t tng_data,
7465                  tng_molecule_t molecule,
7466                  const char *new_name)
7467 {
7468     unsigned int len;
7469     (void)tng_data;
7470
7471     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7472     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7473
7474     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7475
7476     /* If the currently stored string length is not enough to store the new
7477      * string it is freed and reallocated. */
7478     if(molecule->name && strlen(molecule->name) < len)
7479     {
7480         free(molecule->name);
7481         molecule->name = 0;
7482     }
7483     if(!molecule->name)
7484     {
7485         molecule->name = malloc(len);
7486         if(!molecule->name)
7487         {
7488             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7489                    __FILE__, __LINE__);
7490             return(TNG_CRITICAL);
7491         }
7492     }
7493
7494     strncpy(molecule->name, new_name, len);
7495
7496     return(TNG_SUCCESS);
7497 }
7498
7499 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
7500                 (const tng_trajectory_t tng_data,
7501                  const tng_molecule_t molecule,
7502                  int64_t *cnt)
7503 {
7504     int64_t i, index = -1;
7505
7506     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7507     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
7508
7509     for(i = tng_data->n_molecules; i--;)
7510     {
7511         if(&tng_data->molecules[i] == molecule)
7512         {
7513             index = i;
7514             i = 0;
7515         }
7516     }
7517     if(index == -1)
7518     {
7519         return(TNG_FAILURE);
7520     }
7521     *cnt = tng_data->molecule_cnt_list[index];
7522
7523     return(TNG_SUCCESS);
7524 }
7525
7526 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
7527                 (tng_trajectory_t tng_data,
7528                  tng_molecule_t molecule,
7529                  const int64_t cnt)
7530 {
7531     int64_t i, old_cnt, index = -1;
7532
7533     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7534
7535     for(i = tng_data->n_molecules; i--;)
7536     {
7537         if(&tng_data->molecules[i] == molecule)
7538         {
7539             index = i;
7540             i = 0;
7541         }
7542     }
7543     if(index == -1)
7544     {
7545         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
7546                __FILE__, __LINE__);
7547         return(TNG_FAILURE);
7548     }
7549     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
7550     {
7551         old_cnt = tng_data->molecule_cnt_list[index];
7552         tng_data->molecule_cnt_list[index] = cnt;
7553
7554         tng_data->n_particles += (cnt-old_cnt) *
7555                                  tng_data->molecules[index].n_atoms;
7556     }
7557     else
7558     {
7559         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
7560         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
7561
7562         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
7563                 tng_data->molecules[index].n_atoms;
7564     }
7565
7566     return(TNG_SUCCESS);
7567 }
7568
7569 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
7570                 (tng_trajectory_t tng_data,
7571                  const char *name,
7572                  int64_t nr,
7573                  tng_molecule_t *molecule)
7574 {
7575     int64_t i, n_molecules;
7576
7577     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7578     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7579     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7580
7581     n_molecules = tng_data->n_molecules;
7582
7583     for(i = 0; i < n_molecules; i++)
7584     {
7585         *molecule = &tng_data->molecules[i];
7586         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
7587         {
7588             if(nr == -1 || nr == (*molecule)->id)
7589             {
7590                 return(TNG_SUCCESS);
7591             }
7592         }
7593     }
7594
7595     *molecule = 0;
7596
7597     return(TNG_FAILURE);
7598 }
7599
7600 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
7601                 (tng_trajectory_t tng_data,
7602                  int64_t index,
7603                  tng_molecule_t *molecule)
7604 {
7605     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7606     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7607
7608     if(index >= tng_data->n_molecules)
7609     {
7610         *molecule = 0;
7611         return(TNG_FAILURE);
7612     }
7613     *molecule = &tng_data->molecules[index];
7614     return(TNG_SUCCESS);
7615 }
7616
7617 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
7618                                                                tng_trajectory_t tng_data_dest)
7619 {
7620     tng_molecule_t molecule, molecule_temp;
7621     tng_chain_t chain, chain_temp;
7622     tng_residue_t residue, residue_temp;
7623     tng_atom_t atom, atom_temp;
7624     tng_bond_t bond_temp;
7625     tng_function_status stat;
7626     int64_t i, j, k, l, *list_temp;
7627
7628     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
7629     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
7630
7631     for(i = 0; i < tng_data_dest->n_molecules; i++)
7632     {
7633         molecule = &tng_data_dest->molecules[i];
7634         tng_molecule_destroy(tng_data_dest, molecule);
7635     }
7636
7637     tng_data_dest->n_molecules = 0;
7638     tng_data_dest->n_particles = 0;
7639
7640     molecule_temp = realloc(tng_data_dest->molecules,
7641                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
7642     if(!molecule_temp)
7643     {
7644         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7645                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
7646                __FILE__, __LINE__);
7647         free(tng_data_dest->molecules);
7648         tng_data_dest->molecules = 0;
7649         return(TNG_CRITICAL);
7650     }
7651     list_temp = realloc(tng_data_dest->molecule_cnt_list,
7652                                      sizeof(int64_t) * tng_data_src->n_molecules);
7653     if(!list_temp)
7654     {
7655         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7656                sizeof(int64_t) * tng_data_src->n_molecules,
7657                __FILE__, __LINE__);
7658         free(tng_data_dest->molecule_cnt_list);
7659         tng_data_dest->molecule_cnt_list = 0;
7660         free(molecule_temp);
7661         return(TNG_CRITICAL);
7662     }
7663
7664     tng_data_dest->molecules = molecule_temp;
7665     tng_data_dest->molecule_cnt_list = list_temp;
7666
7667     for(i = 0; i < tng_data_src->n_molecules; i++)
7668     {
7669         molecule = &tng_data_src->molecules[i];
7670         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
7671                                      &molecule_temp);
7672         if(stat != TNG_SUCCESS)
7673         {
7674             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
7675                    __FILE__, __LINE__);
7676             return(stat);
7677         }
7678         molecule_temp->quaternary_str = molecule->quaternary_str;
7679         for(j = 0; j < molecule->n_chains; j++)
7680         {
7681             chain = &molecule->chains[j];
7682             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
7683                                                chain->name, chain->id,
7684                                                &chain_temp);
7685             if(stat != TNG_SUCCESS)
7686             {
7687                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
7688                        __FILE__, __LINE__);
7689                 return(stat);
7690             }
7691             for(k = 0; k < chain->n_residues; k++)
7692             {
7693                 residue = &chain->residues[k];
7694                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
7695                                                   residue->name, residue->id,
7696                                                   &residue_temp);
7697                 if(stat != TNG_SUCCESS)
7698                 {
7699                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
7700                            __FILE__, __LINE__);
7701                     return(stat);
7702                 }
7703                 for(l = 0; l < residue->n_atoms; l++)
7704                 {
7705                     atom = &molecule->atoms[residue->atoms_offset + l];
7706                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
7707                                                      atom->name, atom->atom_type,
7708                                                      atom->id, &atom_temp);
7709                     if(stat != TNG_SUCCESS)
7710                     {
7711                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
7712                            __FILE__, __LINE__);
7713                         return(stat);
7714                     }
7715                 }
7716             }
7717         }
7718         molecule_temp->n_bonds = molecule->n_bonds;
7719         bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
7720                             molecule->n_bonds);
7721         if(!bond_temp)
7722         {
7723             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7724                    sizeof(struct tng_bond) * molecule->n_bonds,
7725                    __FILE__, __LINE__);
7726             free(molecule_temp->bonds);
7727             molecule_temp->n_bonds = 0;
7728             return(TNG_CRITICAL);
7729         }
7730         molecule_temp->bonds = bond_temp;
7731         for(j = 0; j < molecule->n_bonds; j++)
7732         {
7733             molecule_temp->bonds[j] = molecule->bonds[j];
7734         }
7735         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
7736                                     tng_data_src->molecule_cnt_list[i]);
7737         if(stat != TNG_SUCCESS)
7738         {
7739             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
7740                    __FILE__, __LINE__);
7741             return(stat);
7742         }
7743     }
7744     return(TNG_SUCCESS);
7745 }
7746
7747 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
7748                 (const tng_trajectory_t tng_data,
7749                  const tng_molecule_t molecule,
7750                  int64_t *n)
7751 {
7752     (void) tng_data;
7753     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7754     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7755
7756     *n = molecule->n_chains;
7757
7758     return(TNG_SUCCESS);
7759 }
7760
7761 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
7762                 (tng_trajectory_t tng_data,
7763                  tng_molecule_t molecule,
7764                  int64_t index,
7765                  tng_chain_t *chain)
7766 {
7767     (void) tng_data;
7768     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7769     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7770
7771     if(index >= molecule->n_chains)
7772     {
7773         *chain = 0;
7774         return(TNG_FAILURE);
7775     }
7776     *chain = &molecule->chains[index];
7777     return(TNG_SUCCESS);
7778 }
7779
7780 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
7781                 (const tng_trajectory_t tng_data,
7782                  const tng_molecule_t molecule,
7783                  int64_t *n)
7784 {
7785     (void) tng_data;
7786     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7787     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7788
7789     *n = molecule->n_residues;
7790
7791     return(TNG_SUCCESS);
7792 }
7793
7794 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
7795                 (const tng_trajectory_t tng_data,
7796                  const tng_molecule_t molecule,
7797                  const int64_t index,
7798                  tng_residue_t *residue)
7799 {
7800     (void) tng_data;
7801     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7802     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7803
7804     if(index >= molecule->n_residues)
7805     {
7806         *residue = 0;
7807         return(TNG_FAILURE);
7808     }
7809     *residue = &molecule->residues[index];
7810     return(TNG_SUCCESS);
7811 }
7812
7813 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
7814                 (const tng_trajectory_t tng_data,
7815                  const tng_molecule_t molecule,
7816                  int64_t *n)
7817 {
7818     (void) tng_data;
7819     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7820     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7821
7822     *n = molecule->n_atoms;
7823
7824     return(TNG_SUCCESS);
7825 }
7826
7827 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
7828                 (const tng_trajectory_t tng_data,
7829                  const tng_molecule_t molecule,
7830                  const int64_t index,
7831                  tng_atom_t *atom)
7832 {
7833     (void) tng_data;
7834     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7835     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7836
7837     if(index >= molecule->n_atoms)
7838     {
7839         *atom = 0;
7840         return(TNG_FAILURE);
7841     }
7842     *atom = &molecule->atoms[index];
7843     return(TNG_SUCCESS);
7844 }
7845
7846 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
7847                 (tng_trajectory_t tng_data,
7848                  tng_molecule_t molecule,
7849                  const char *name,
7850                  int64_t nr,
7851                  tng_chain_t *chain)
7852 {
7853     int64_t i, n_chains;
7854     (void)tng_data;
7855
7856     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7857     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7858
7859     n_chains = molecule->n_chains;
7860
7861     for(i = 0; i < n_chains; i++)
7862     {
7863         *chain = &molecule->chains[i];
7864         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
7865         {
7866             if(nr == -1 || nr == (*chain)->id)
7867             {
7868                 return(TNG_SUCCESS);
7869             }
7870         }
7871     }
7872
7873     *chain = 0;
7874
7875     return(TNG_FAILURE);
7876 }
7877
7878 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
7879                 (tng_trajectory_t tng_data,
7880                  tng_molecule_t molecule,
7881                  const char *name,
7882                  tng_chain_t *chain)
7883 {
7884     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7885     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7886
7887     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
7888                                        molecule->n_chains + 1, chain));
7889 }
7890
7891 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
7892                 (tng_trajectory_t tng_data,
7893                  tng_molecule_t molecule,
7894                  const char *name,
7895                  const int64_t id,
7896                  tng_chain_t *chain)
7897 {
7898     int64_t i;
7899     tng_chain_t new_chains;
7900     tng_function_status stat = TNG_SUCCESS;
7901
7902     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7903     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7904
7905     new_chains = realloc(molecule->chains,
7906                          sizeof(struct tng_chain) *
7907                          (molecule->n_chains + 1));
7908
7909     if(!new_chains)
7910     {
7911         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7912                sizeof(struct tng_chain) * (molecule->n_chains + 1),
7913                __FILE__, __LINE__);
7914         free(molecule->chains);
7915         molecule->chains = 0;
7916         return(TNG_CRITICAL);
7917     }
7918
7919     molecule->chains = new_chains;
7920
7921     *chain = &new_chains[molecule->n_chains];
7922     (*chain)->name = 0;
7923
7924     tng_chain_name_set(tng_data, *chain, name);
7925
7926     (*chain)->molecule = molecule;
7927     (*chain)->n_residues = 0;
7928
7929     for(i = molecule->n_chains; i--;)
7930     {
7931         if(molecule->chains[i].id == id)
7932         {
7933             stat = TNG_FAILURE;
7934             fprintf(stderr, "TNG library: Chain ID already in use. %s: %d\n", __FILE__, __LINE__);
7935             break;
7936         }
7937     }
7938
7939     molecule->n_chains++;
7940
7941     (*chain)->id = id;
7942
7943     return(stat);
7944 }
7945
7946 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
7947                 (const tng_trajectory_t tng_data,
7948                  tng_molecule_t molecule,
7949                  const int64_t from_atom_id,
7950                  const int64_t to_atom_id,
7951                  tng_bond_t *bond)
7952 {
7953     int64_t i;
7954     tng_bond_t new_bonds;
7955     (void)tng_data;
7956
7957     for(i = 0; i < molecule->n_bonds; i++)
7958     {
7959         *bond = &molecule->bonds[i];
7960         /* Check if the bond already exists */
7961         if(((*bond)->from_atom_id == from_atom_id && (*bond)->to_atom_id == to_atom_id) ||
7962            ((*bond)->to_atom_id == from_atom_id && (*bond)->from_atom_id == to_atom_id))
7963         {
7964             return(TNG_SUCCESS);
7965         }
7966     }
7967
7968     new_bonds = realloc(molecule->bonds,
7969                         sizeof(struct tng_bond) *
7970                         (molecule->n_bonds + 1));
7971
7972     if(!new_bonds)
7973     {
7974         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7975                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
7976                __FILE__, __LINE__);
7977         *bond = 0;
7978         free(molecule->bonds);
7979         molecule->bonds = 0;
7980         return(TNG_CRITICAL);
7981     }
7982
7983     molecule->bonds = new_bonds;
7984
7985     *bond = &new_bonds[molecule->n_bonds];
7986
7987     (*bond)->from_atom_id = from_atom_id;
7988     (*bond)->to_atom_id = to_atom_id;
7989
7990     molecule->n_bonds++;
7991
7992     return(TNG_SUCCESS);
7993 }
7994
7995 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
7996                 (tng_trajectory_t tng_data,
7997                  tng_molecule_t molecule,
7998                  const char *name,
7999                  int64_t id,
8000                  tng_atom_t *atom)
8001 {
8002     int64_t i, n_atoms;
8003     (void)tng_data;
8004
8005     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8006
8007     n_atoms = molecule->n_atoms;
8008
8009     for(i = 0; i < n_atoms; i++)
8010     {
8011         *atom = &molecule->atoms[i];
8012         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
8013         {
8014             if(id == -1 || id == (*atom)->id)
8015             {
8016                 return(TNG_SUCCESS);
8017             }
8018         }
8019     }
8020
8021     *atom = 0;
8022
8023     return(TNG_FAILURE);
8024 }
8025
8026 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
8027                                        const tng_chain_t chain,
8028                                        char *name,
8029                                        const int max_len)
8030 {
8031     (void) tng_data;
8032     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8033     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8034
8035     strncpy(name, chain->name, max_len - 1);
8036     name[max_len - 1] = 0;
8037
8038     if(strlen(chain->name) > (unsigned int)max_len - 1)
8039     {
8040         return(TNG_FAILURE);
8041     }
8042     return(TNG_SUCCESS);
8043 }
8044
8045 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
8046                 (tng_trajectory_t tng_data,
8047                  tng_chain_t chain,
8048                  const char *new_name)
8049 {
8050     unsigned int len;
8051     (void)tng_data;
8052
8053     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8054
8055     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8056
8057     /* If the currently stored string length is not enough to store the new
8058      * string it is freed and reallocated. */
8059     if(chain->name && strlen(chain->name) < len)
8060     {
8061         free(chain->name);
8062         chain->name = 0;
8063     }
8064     if(!chain->name)
8065     {
8066         chain->name = malloc(len);
8067         if(!chain->name)
8068         {
8069             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8070                    __FILE__, __LINE__);
8071             return(TNG_CRITICAL);
8072         }
8073     }
8074
8075     strncpy(chain->name, new_name, len);
8076
8077     return(TNG_SUCCESS);
8078 }
8079
8080 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8081                 (const tng_trajectory_t tng_data,
8082                  const tng_chain_t chain,
8083                  int64_t *n)
8084 {
8085     (void) tng_data;
8086     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8087     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8088
8089     *n = chain->n_residues;
8090
8091     return(TNG_SUCCESS);
8092 }
8093
8094 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8095                 (const tng_trajectory_t tng_data,
8096                  const tng_chain_t chain,
8097                  const int64_t index,
8098                  tng_residue_t *residue)
8099 {
8100     (void) tng_data;
8101     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8102     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8103
8104     if(index >= chain->n_residues)
8105     {
8106         *residue = 0;
8107         return(TNG_FAILURE);
8108     }
8109     *residue = &chain->residues[index];
8110     return(TNG_SUCCESS);
8111 }
8112
8113 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8114                 (tng_trajectory_t tng_data,
8115                  tng_chain_t chain,
8116                  const char *name,
8117                  int64_t id,
8118                  tng_residue_t *residue)
8119 {
8120     int64_t i, n_residues;
8121     (void)tng_data;
8122
8123     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8124
8125     n_residues = chain->n_residues;
8126
8127     for(i = 0; i < n_residues; i++)
8128     {
8129         *residue = &chain->residues[i];
8130         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8131         {
8132             if(id == -1 || id == (*residue)->id)
8133             {
8134                 return(TNG_SUCCESS);
8135             }
8136         }
8137     }
8138
8139     *residue = 0;
8140
8141     return(TNG_FAILURE);
8142 }
8143
8144 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8145                 (tng_trajectory_t tng_data,
8146                  tng_chain_t chain,
8147                  const char *name,
8148                  tng_residue_t *residue)
8149 {
8150     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8151     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8152
8153     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8154                                       chain->n_residues + 1, residue));
8155 }
8156
8157 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8158                 (tng_trajectory_t tng_data,
8159                  tng_chain_t chain,
8160                  const char *name,
8161                  const int64_t id,
8162                  tng_residue_t *residue)
8163 {
8164     int64_t i, curr_index;
8165     tng_residue_t new_residues, temp_residue, last_residue;
8166     tng_molecule_t molecule = chain->molecule;
8167     tng_function_status stat = TNG_SUCCESS;
8168
8169     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8170     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8171
8172     if(chain->n_residues)
8173     {
8174         curr_index = chain->residues - molecule->residues;
8175     }
8176     else
8177     {
8178         curr_index = -1;
8179     }
8180
8181     new_residues = realloc(molecule->residues,
8182                            sizeof(struct tng_residue) *
8183                            (molecule->n_residues + 1));
8184
8185     if(!new_residues)
8186     {
8187         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8188                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8189                __FILE__, __LINE__);
8190         free(molecule->residues);
8191         molecule->residues = 0;
8192         return(TNG_CRITICAL);
8193     }
8194
8195     molecule->residues = new_residues;
8196
8197     if(curr_index != -1)
8198     {
8199         chain->residues = new_residues + curr_index;
8200         if(molecule->n_residues)
8201         {
8202             last_residue = &new_residues[molecule->n_residues - 1];
8203
8204             temp_residue = chain->residues + (chain->n_residues - 1);
8205             /* Make space in list of residues to add the new residues together with the other
8206             * residues of this chain */
8207             if(temp_residue != last_residue)
8208             {
8209                 ++temp_residue;
8210                 memmove(temp_residue + 1, temp_residue,
8211                         last_residue - temp_residue);
8212             }
8213         }
8214     }
8215     else
8216     {
8217         curr_index = molecule->n_residues;
8218     }
8219
8220     *residue = &molecule->residues[curr_index + chain->n_residues];
8221
8222     if(!chain->n_residues)
8223     {
8224         chain->residues = *residue;
8225     }
8226
8227     (*residue)->name = 0;
8228     tng_residue_name_set(tng_data, *residue, name);
8229
8230     (*residue)->chain = chain;
8231     (*residue)->n_atoms = 0;
8232     (*residue)->atoms_offset = 0;
8233
8234     for(i = chain->n_residues; i--;)
8235     {
8236         if(chain->residues[i].id == id)
8237         {
8238             stat = TNG_FAILURE;
8239             fprintf(stderr, "TNG library: Residue ID already in use. %s: %d\n", __FILE__, __LINE__);
8240             break;
8241         }
8242     }
8243
8244     chain->n_residues++;
8245     molecule->n_residues++;
8246
8247     (*residue)->id = id;
8248
8249     return(stat);
8250 }
8251
8252 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
8253                                          const tng_residue_t residue,
8254                                          char *name,
8255                                          const int max_len)
8256 {
8257     (void) tng_data;
8258     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8259     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8260
8261     strncpy(name, residue->name, max_len - 1);
8262     name[max_len - 1] = 0;
8263
8264     if(strlen(residue->name) > (unsigned int)max_len - 1)
8265     {
8266         return(TNG_FAILURE);
8267     }
8268     return(TNG_SUCCESS);
8269 }
8270
8271 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8272                                                            tng_residue_t residue,
8273                                                            const char *new_name)
8274 {
8275     unsigned int len;
8276     (void)tng_data;
8277
8278     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8279     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8280
8281     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8282
8283     /* If the currently stored string length is not enough to store the new
8284      * string it is freed and reallocated. */
8285     if(residue->name && strlen(residue->name) < len)
8286     {
8287         free(residue->name);
8288         residue->name = 0;
8289     }
8290     if(!residue->name)
8291     {
8292         residue->name = malloc(len);
8293         if(!residue->name)
8294         {
8295             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8296                    __FILE__, __LINE__);
8297             return(TNG_CRITICAL);
8298         }
8299     }
8300
8301     strncpy(residue->name, new_name, len);
8302
8303     return(TNG_SUCCESS);
8304 }
8305
8306 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8307                 (const tng_trajectory_t tng_data,
8308                  const tng_residue_t residue,
8309                  int64_t *n)
8310 {
8311     (void) tng_data;
8312     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8313     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8314
8315     *n = residue->n_atoms;
8316
8317     return(TNG_SUCCESS);
8318 }
8319
8320 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8321                 (const tng_trajectory_t tng_data,
8322                  const tng_residue_t residue,
8323                  const int64_t index,
8324                  tng_atom_t *atom)
8325 {
8326     tng_chain_t chain;
8327     tng_molecule_t molecule;
8328
8329     (void) tng_data;
8330     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8331     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8332
8333     if(index >= residue->n_atoms)
8334     {
8335         *atom = 0;
8336         return(TNG_FAILURE);
8337     }
8338     chain = residue->chain;
8339     molecule = chain->molecule;
8340
8341     if(index + residue->atoms_offset >= molecule->n_atoms)
8342     {
8343         *atom = 0;
8344         return(TNG_FAILURE);
8345     }
8346
8347     *atom = &molecule->atoms[residue->atoms_offset + index];
8348     return(TNG_SUCCESS);
8349 }
8350
8351 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
8352                 (tng_trajectory_t tng_data,
8353                  tng_residue_t residue,
8354                  const char *atom_name,
8355                  const char *atom_type,
8356                  tng_atom_t *atom)
8357 {
8358     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8359     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8360     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8361
8362     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
8363                                      residue->chain->molecule->n_atoms + 1,
8364                                      atom));
8365 }
8366
8367 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
8368                 (tng_trajectory_t tng_data,
8369                  tng_residue_t residue,
8370                  const char *atom_name,
8371                  const char *atom_type,
8372                  const int64_t id,
8373                  tng_atom_t *atom)
8374 {
8375     int64_t i;
8376     tng_atom_t new_atoms;
8377     tng_molecule_t molecule = residue->chain->molecule;
8378     tng_function_status stat = TNG_SUCCESS;
8379
8380     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8381     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8382     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8383
8384     if(!residue->n_atoms)
8385     {
8386         residue->atoms_offset = molecule->n_atoms;
8387     }
8388
8389     new_atoms = realloc(molecule->atoms,
8390                         sizeof(struct tng_atom) *
8391                         (molecule->n_atoms + 1));
8392
8393     if(!new_atoms)
8394     {
8395         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8396                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
8397                __FILE__, __LINE__);
8398         free(molecule->atoms);
8399         molecule->atoms = 0;
8400         return(TNG_CRITICAL);
8401     }
8402
8403     molecule->atoms = new_atoms;
8404
8405     *atom = &new_atoms[molecule->n_atoms];
8406
8407     tng_atom_init(*atom);
8408     tng_atom_name_set(tng_data, *atom, atom_name);
8409     tng_atom_type_set(tng_data, *atom, atom_type);
8410
8411     (*atom)->residue = residue;
8412
8413     for(i = molecule->n_atoms; i--;)
8414     {
8415         if(molecule->atoms[i].id == id)
8416         {
8417             stat = TNG_FAILURE;
8418             fprintf(stderr, "TNG library: Atom ID %"PRId64" already in use. %s: %d\n", id, __FILE__, __LINE__);
8419             break;
8420         }
8421     }
8422
8423     residue->n_atoms++;
8424     molecule->n_atoms++;
8425
8426     (*atom)->id = id;
8427
8428     return(stat);
8429 }
8430
8431 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
8432                                                          tng_molecule_t *molecule_p)
8433 {
8434     *molecule_p = malloc(sizeof(struct tng_molecule));
8435     if(!*molecule_p)
8436     {
8437         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
8438                sizeof(struct tng_molecule), __FILE__, __LINE__);
8439         return(TNG_CRITICAL);
8440     }
8441
8442     tng_molecule_init(tng_data, *molecule_p);
8443
8444     return(TNG_SUCCESS);
8445 }
8446
8447 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
8448                                                         tng_molecule_t *molecule_p)
8449 {
8450     if(!*molecule_p)
8451     {
8452         return(TNG_SUCCESS);
8453     }
8454
8455     tng_molecule_destroy(tng_data, *molecule_p);
8456
8457     free(*molecule_p);
8458     *molecule_p = 0;
8459
8460     return(TNG_SUCCESS);
8461 }
8462
8463 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
8464                                                         tng_molecule_t molecule)
8465 {
8466     (void)tng_data;
8467     molecule->quaternary_str = 1;
8468     molecule->name = 0;
8469     molecule->n_chains = 0;
8470     molecule->chains = 0;
8471     molecule->n_residues = 0;
8472     molecule->residues = 0;
8473     molecule->n_atoms = 0;
8474     molecule->atoms = 0;
8475     molecule->n_bonds = 0;
8476     molecule->bonds = 0;
8477
8478     return(TNG_SUCCESS);
8479 }
8480
8481 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
8482                                                            tng_molecule_t molecule)
8483 {
8484     int64_t i;
8485     (void)tng_data;
8486
8487     if(molecule->name)
8488     {
8489         free(molecule->name);
8490         molecule->name = 0;
8491     }
8492
8493     if(molecule->chains)
8494     {
8495         for(i = molecule->n_chains; i--;)
8496         {
8497             if(molecule->chains[i].name)
8498             {
8499                 free(molecule->chains[i].name);
8500                 molecule->chains[i].name = 0;
8501             }
8502         }
8503         free(molecule->chains);
8504         molecule->chains = 0;
8505     }
8506     molecule->n_chains = 0;
8507
8508     if(molecule->residues)
8509     {
8510         for(i = molecule->n_residues; i--;)
8511         {
8512             if(molecule->residues[i].name)
8513             {
8514                 free(molecule->residues[i].name);
8515                 molecule->residues[i].name = 0;
8516             }
8517         }
8518         free(molecule->residues);
8519         molecule->residues = 0;
8520     }
8521     molecule->n_residues = 0;
8522
8523     if(molecule->atoms)
8524     {
8525         for(i = molecule->n_atoms; i--;)
8526         {
8527             tng_atom_destroy(&molecule->atoms[i]);
8528         }
8529         free(molecule->atoms);
8530         molecule->atoms = 0;
8531     }
8532     molecule->n_atoms = 0;
8533
8534     if(molecule->bonds)
8535     {
8536         free(molecule->bonds);
8537         molecule->bonds = 0;
8538     }
8539     molecule->n_bonds = 0;
8540
8541     return(TNG_SUCCESS);
8542 }
8543
8544 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
8545                 (const tng_trajectory_t tng_data,
8546                  const int64_t nr,
8547                  char *name,
8548                  int max_len)
8549 {
8550     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8551     tng_molecule_t mol;
8552     tng_bool found = TNG_FALSE;
8553
8554     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8555     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8556
8557     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8558
8559     if(!molecule_cnt_list)
8560     {
8561         return(TNG_FAILURE);
8562     }
8563
8564     for(i = 0; i < tng_data->n_molecules; i++)
8565     {
8566         mol = &tng_data->molecules[i];
8567         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8568         {
8569             cnt += mol->n_atoms * molecule_cnt_list[i];
8570             continue;
8571         }
8572         found = TNG_TRUE;
8573         break;
8574     }
8575     if(!found)
8576     {
8577         return(TNG_FAILURE);
8578     }
8579
8580     strncpy(name, mol->name, max_len - 1);
8581     name[max_len - 1] = 0;
8582
8583     if(strlen(mol->name) > (unsigned int)max_len - 1)
8584     {
8585         return(TNG_FAILURE);
8586     }
8587     return(TNG_SUCCESS);
8588 }
8589
8590 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
8591                 (const tng_trajectory_t tng_data,
8592                  const int64_t nr,
8593                  int64_t *id)
8594 {
8595     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8596     tng_molecule_t mol;
8597     tng_bool found = TNG_FALSE;
8598
8599     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8600     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8601
8602     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8603
8604     if(!molecule_cnt_list)
8605     {
8606         return(TNG_FAILURE);
8607     }
8608
8609     for(i = 0; i < tng_data->n_molecules; i++)
8610     {
8611         mol = &tng_data->molecules[i];
8612         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8613         {
8614             cnt += mol->n_atoms * molecule_cnt_list[i];
8615             continue;
8616         }
8617         found = TNG_TRUE;
8618         break;
8619     }
8620     if(!found)
8621     {
8622         return(TNG_FAILURE);
8623     }
8624
8625     *id = mol->id;
8626
8627     return(TNG_SUCCESS);
8628 }
8629
8630 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
8631                 (const tng_trajectory_t tng_data,
8632                  int64_t *n_bonds,
8633                  int64_t **from_atoms,
8634                  int64_t **to_atoms)
8635 {
8636     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
8637     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
8638     tng_molecule_t mol;
8639     tng_bond_t bond;
8640
8641     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8642     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
8643     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
8644     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
8645
8646     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8647
8648     if(!molecule_cnt_list)
8649     {
8650         return(TNG_FAILURE);
8651     }
8652
8653     *n_bonds = 0;
8654     /* First count the total number of bonds to allocate memory */
8655     for(i = 0; i < tng_data->n_molecules; i++)
8656     {
8657         mol = &tng_data->molecules[i];
8658         mol_cnt = molecule_cnt_list[i];
8659         *n_bonds += mol_cnt * mol->n_bonds;
8660     }
8661     if(*n_bonds == 0)
8662     {
8663         return(TNG_SUCCESS);
8664     }
8665
8666     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
8667     if(!*from_atoms)
8668     {
8669         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8670                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
8671         return(TNG_CRITICAL);
8672     }
8673     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
8674     if(!*to_atoms)
8675     {
8676         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8677                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
8678         free(*from_atoms);
8679         *from_atoms = 0;
8680         return(TNG_CRITICAL);
8681     }
8682
8683     cnt = 0;
8684     for(i = 0; i < tng_data->n_molecules; i++)
8685     {
8686         mol = &tng_data->molecules[i];
8687         mol_cnt = molecule_cnt_list[i];
8688         for(j = 0; j < mol_cnt; j++)
8689         {
8690             for(k = 0; k < mol->n_bonds; k++)
8691             {
8692                 bond = &mol->bonds[k];
8693                 from_atom = atom_cnt + bond->from_atom_id;
8694                 to_atom = atom_cnt + bond->to_atom_id;
8695                 (*from_atoms)[cnt] = from_atom;
8696                 (*to_atoms)[cnt++] = to_atom;
8697             }
8698             atom_cnt += mol->n_atoms;
8699         }
8700     }
8701
8702     return(TNG_SUCCESS);
8703 }
8704
8705 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
8706                 (const tng_trajectory_t tng_data,
8707                  const int64_t nr,
8708                  char *name,
8709                  int max_len)
8710 {
8711     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8712     tng_molecule_t mol;
8713     tng_atom_t atom;
8714     tng_bool found = TNG_FALSE;
8715
8716     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8717     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8718
8719     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8720
8721     if(!molecule_cnt_list)
8722     {
8723         return(TNG_FAILURE);
8724     }
8725
8726     for(i = 0; i < tng_data->n_molecules; i++)
8727     {
8728         mol = &tng_data->molecules[i];
8729         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8730         {
8731             cnt += mol->n_atoms * molecule_cnt_list[i];
8732             continue;
8733         }
8734         atom = &mol->atoms[nr % mol->n_atoms];
8735         found = TNG_TRUE;
8736         break;
8737     }
8738     if(!found)
8739     {
8740         return(TNG_FAILURE);
8741     }
8742     if(!atom->residue || !atom->residue->chain)
8743     {
8744         return(TNG_FAILURE);
8745     }
8746
8747     strncpy(name, atom->residue->chain->name, max_len - 1);
8748     name[max_len - 1] = 0;
8749
8750     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
8751     {
8752         return(TNG_FAILURE);
8753     }
8754     return(TNG_SUCCESS);
8755 }
8756
8757 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
8758                 (const tng_trajectory_t tng_data,
8759                  const int64_t nr,
8760                  char *name,
8761                  int max_len)
8762 {
8763     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8764     tng_molecule_t mol;
8765     tng_atom_t atom;
8766     tng_bool found = TNG_FALSE;
8767
8768     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8769     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8770
8771     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8772
8773     if(!molecule_cnt_list)
8774     {
8775         return(TNG_FAILURE);
8776     }
8777
8778     for(i = 0; i < tng_data->n_molecules; i++)
8779     {
8780         mol = &tng_data->molecules[i];
8781         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8782         {
8783             cnt += mol->n_atoms * molecule_cnt_list[i];
8784             continue;
8785         }
8786         atom = &mol->atoms[nr % mol->n_atoms];
8787         found = TNG_TRUE;
8788         break;
8789     }
8790     if(!found)
8791     {
8792         return(TNG_FAILURE);
8793     }
8794     if(!atom->residue)
8795     {
8796         return(TNG_FAILURE);
8797     }
8798
8799     strncpy(name, atom->residue->name, max_len - 1);
8800     name[max_len - 1] = 0;
8801
8802     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
8803     {
8804         return(TNG_FAILURE);
8805     }
8806     return(TNG_SUCCESS);
8807 }
8808
8809 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
8810                 (const tng_trajectory_t tng_data,
8811                  const int64_t nr,
8812                  int64_t *id)
8813 {
8814     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8815     tng_molecule_t mol;
8816     tng_atom_t atom;
8817     tng_bool found = TNG_FALSE;
8818
8819     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8820     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8821
8822     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8823
8824     if(!molecule_cnt_list)
8825     {
8826         return(TNG_FAILURE);
8827     }
8828
8829     for(i = 0; i < tng_data->n_molecules; i++)
8830     {
8831         mol = &tng_data->molecules[i];
8832         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8833         {
8834             cnt += mol->n_atoms * molecule_cnt_list[i];
8835             continue;
8836         }
8837         atom = &mol->atoms[nr % mol->n_atoms];
8838         found = TNG_TRUE;
8839         break;
8840     }
8841     if(!found)
8842     {
8843         return(TNG_FAILURE);
8844     }
8845     if(!atom->residue)
8846     {
8847         return(TNG_FAILURE);
8848     }
8849
8850     *id = atom->residue->id;
8851
8852     return(TNG_SUCCESS);
8853 }
8854
8855 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
8856                 (const tng_trajectory_t tng_data,
8857                  const int64_t nr,
8858                  int64_t *id)
8859 {
8860     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
8861     tng_molecule_t mol;
8862     tng_atom_t atom;
8863     tng_bool found = TNG_FALSE;
8864
8865     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8866     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8867
8868     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8869
8870     if(!molecule_cnt_list)
8871     {
8872         return(TNG_FAILURE);
8873     }
8874
8875     for(i = 0; i < tng_data->n_molecules; i++)
8876     {
8877         mol = &tng_data->molecules[i];
8878         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8879         {
8880             cnt += mol->n_atoms * molecule_cnt_list[i];
8881             offset += mol->n_residues * molecule_cnt_list[i];
8882             continue;
8883         }
8884         atom = &mol->atoms[nr % mol->n_atoms];
8885         found = TNG_TRUE;
8886         break;
8887     }
8888     if(!found)
8889     {
8890         return(TNG_FAILURE);
8891     }
8892     if(!atom->residue)
8893     {
8894         return(TNG_FAILURE);
8895     }
8896
8897     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
8898
8899     *id = atom->residue->id + offset;
8900
8901     return(TNG_SUCCESS);
8902 }
8903
8904 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
8905                 (const tng_trajectory_t tng_data,
8906                  const int64_t nr,
8907                  char *name,
8908                  int max_len)
8909 {
8910     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8911     tng_molecule_t mol;
8912     tng_atom_t atom;
8913     tng_bool found = TNG_FALSE;
8914
8915     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8916     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8917
8918     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8919
8920     if(!molecule_cnt_list)
8921     {
8922         return(TNG_FAILURE);
8923     }
8924
8925     for(i = 0; i < tng_data->n_molecules; i++)
8926     {
8927         mol = &tng_data->molecules[i];
8928         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8929         {
8930             cnt += mol->n_atoms * molecule_cnt_list[i];
8931             continue;
8932         }
8933         atom = &mol->atoms[nr % mol->n_atoms];
8934         found = TNG_TRUE;
8935         break;
8936     }
8937     if(!found)
8938     {
8939         return(TNG_FAILURE);
8940     }
8941
8942     strncpy(name, atom->name, max_len - 1);
8943     name[max_len - 1] = 0;
8944
8945     if(strlen(atom->name) > (unsigned int)max_len - 1)
8946     {
8947         return(TNG_FAILURE);
8948     }
8949     return(TNG_SUCCESS);
8950 }
8951
8952 tng_function_status tng_atom_type_of_particle_nr_get
8953                 (const tng_trajectory_t tng_data,
8954                  const int64_t nr,
8955                  char *type,
8956                  int max_len)
8957 {
8958     int64_t cnt = 0, i, *molecule_cnt_list = 0;
8959     tng_molecule_t mol;
8960     tng_atom_t atom;
8961     tng_bool found = TNG_FALSE;
8962
8963     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8964     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
8965
8966     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8967
8968     if(!molecule_cnt_list)
8969     {
8970         return(TNG_FAILURE);
8971     }
8972
8973     for(i = 0; i < tng_data->n_molecules; i++)
8974     {
8975         mol = &tng_data->molecules[i];
8976         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8977         {
8978             cnt += mol->n_atoms * molecule_cnt_list[i];
8979             continue;
8980         }
8981         atom = &mol->atoms[nr % mol->n_atoms];
8982         found = TNG_TRUE;
8983         break;
8984     }
8985     if(!found)
8986     {
8987         return(TNG_FAILURE);
8988     }
8989
8990     strncpy(type, atom->atom_type, max_len - 1);
8991     type[max_len - 1] = 0;
8992
8993     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
8994     {
8995         return(TNG_FAILURE);
8996     }
8997     return(TNG_SUCCESS);
8998 }
8999
9000 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
9001                 (tng_trajectory_t tng_data,
9002                  const int64_t num_first_particle,
9003                  const int64_t n_particles,
9004                  const int64_t *mapping_table)
9005 {
9006     int64_t i;
9007     tng_particle_mapping_t mapping;
9008     tng_trajectory_frame_set_t frame_set;
9009
9010     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9011
9012     frame_set = &tng_data->current_trajectory_frame_set;
9013
9014     /* Sanity check of the particle ranges. Split into multiple if
9015      * statements for improved readability */
9016     for(i = 0; i < frame_set->n_mapping_blocks; i++)
9017     {
9018         mapping = &frame_set->mappings[i];
9019         if(num_first_particle >= mapping->num_first_particle &&
9020            num_first_particle < mapping->num_first_particle +
9021                                    mapping->n_particles)
9022         {
9023             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9024             return(TNG_FAILURE);
9025         }
9026         if(num_first_particle + n_particles >=
9027            mapping->num_first_particle &&
9028            num_first_particle + n_particles <
9029            mapping->num_first_particle + mapping->n_particles)
9030         {
9031             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9032             return(TNG_FAILURE);
9033         }
9034         if(mapping->num_first_particle >= num_first_particle &&
9035            mapping->num_first_particle < num_first_particle +
9036                                             n_particles)
9037         {
9038             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9039             return(TNG_FAILURE);
9040         }
9041         if(mapping->num_first_particle + mapping->n_particles >
9042            num_first_particle &&
9043            mapping->num_first_particle + mapping->n_particles <
9044            num_first_particle + n_particles)
9045         {
9046             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9047             return(TNG_FAILURE);
9048         }
9049     }
9050
9051     frame_set->n_mapping_blocks++;
9052
9053     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
9054                       frame_set->n_mapping_blocks);
9055
9056     if(!mapping)
9057     {
9058         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9059                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9060                __FILE__, __LINE__);
9061         free(frame_set->mappings);
9062         frame_set->mappings = 0;
9063         return(TNG_CRITICAL);
9064     }
9065     frame_set->mappings = mapping;
9066
9067     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9068     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9069
9070     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9071     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9072     {
9073         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9074                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9075         return(TNG_CRITICAL);
9076     }
9077
9078     for(i=0; i<n_particles; i++)
9079     {
9080         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9081     }
9082
9083     return(TNG_SUCCESS);
9084 }
9085
9086 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9087 {
9088     tng_trajectory_frame_set_t frame_set;
9089     tng_particle_mapping_t mapping;
9090     int64_t i;
9091
9092     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9093
9094     frame_set = &tng_data->current_trajectory_frame_set;
9095
9096     if(frame_set->n_mapping_blocks && frame_set->mappings)
9097     {
9098         for(i = frame_set->n_mapping_blocks; i--;)
9099         {
9100             mapping = &frame_set->mappings[i];
9101             if(mapping->real_particle_numbers)
9102             {
9103                 free(mapping->real_particle_numbers);
9104                 mapping->real_particle_numbers = 0;
9105             }
9106         }
9107         free(frame_set->mappings);
9108         frame_set->mappings = 0;
9109         frame_set->n_mapping_blocks = 0;
9110     }
9111
9112     return(TNG_SUCCESS);
9113 }
9114
9115 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9116 {
9117     time_t seconds;
9118     tng_trajectory_frame_set_t frame_set;
9119     tng_trajectory_t tng_data;
9120
9121     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9122     if(!*tng_data_p)
9123     {
9124         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9125                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9126         return(TNG_CRITICAL);
9127     }
9128
9129     tng_data = *tng_data_p;
9130
9131     frame_set = &tng_data->current_trajectory_frame_set;
9132
9133     tng_data->input_file_path = 0;
9134     tng_data->input_file = 0;
9135     tng_data->input_file_len = 0;
9136     tng_data->output_file_path = 0;
9137     tng_data->output_file = 0;
9138
9139     tng_data->first_program_name = 0;
9140     tng_data->first_user_name = 0;
9141     tng_data->first_computer_name = 0;
9142     tng_data->first_pgp_signature = 0;
9143     tng_data->last_program_name = 0;
9144     tng_data->last_user_name = 0;
9145     tng_data->last_computer_name = 0;
9146     tng_data->last_pgp_signature = 0;
9147     tng_data->forcefield_name = 0;
9148
9149     seconds = time(0);
9150     if ( seconds == -1)
9151     {
9152         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9153     }
9154     else
9155     {
9156         tng_data->time = seconds;
9157     }
9158
9159     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9160     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9161     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9162     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9163     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9164     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9165     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9166     tng_data->frame_set_n_frames = 100;
9167     tng_data->n_trajectory_frame_sets = 0;
9168     tng_data->n_trajectory_blocks = 0;
9169     tng_data->medium_stride_length = 100;
9170     tng_data->long_stride_length = 10000;
9171
9172     tng_data->time_per_frame = -1;
9173
9174     tng_data->n_particle_data_blocks = 0;
9175     tng_data->n_data_blocks = 0;
9176
9177     tng_data->non_tr_particle_data = 0;
9178     tng_data->non_tr_data = 0;
9179
9180     tng_data->compress_algo_pos = 0;
9181     tng_data->compress_algo_vel = 0;
9182     tng_data->compression_precision = 1000;
9183     tng_data->distance_unit_exponential = -9;
9184
9185     frame_set->first_frame = -1;
9186     frame_set->n_mapping_blocks = 0;
9187     frame_set->mappings = 0;
9188     frame_set->molecule_cnt_list = 0;
9189
9190     frame_set->n_particle_data_blocks = 0;
9191     frame_set->n_data_blocks = 0;
9192
9193     frame_set->tr_particle_data = 0;
9194     frame_set->tr_data = 0;
9195
9196     frame_set->n_written_frames = 0;
9197     frame_set->n_unwritten_frames = 0;
9198
9199     frame_set->next_frame_set_file_pos = -1;
9200     frame_set->prev_frame_set_file_pos = -1;
9201     frame_set->medium_stride_next_frame_set_file_pos = -1;
9202     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9203     frame_set->long_stride_next_frame_set_file_pos = -1;
9204     frame_set->long_stride_prev_frame_set_file_pos = -1;
9205
9206     frame_set->first_frame_time = -1;
9207
9208     tng_data->n_molecules = 0;
9209     tng_data->molecules = 0;
9210     tng_data->molecule_cnt_list = 0;
9211     tng_data->n_particles = 0;
9212
9213     {
9214       /* Check the endianness of the computer */
9215       static int32_t endianness_32 = 0x01234567;
9216       /* 0x01234567 */
9217       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9218         {
9219           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9220         }
9221
9222       /* 0x67452301 */
9223       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9224         {
9225           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9226
9227         }
9228
9229       /* 0x45670123 */
9230       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9231         {
9232           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9233         }
9234     }
9235     {
9236       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9237       /* 0x0123456789ABCDEF */
9238       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9239         {
9240           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9241         }
9242
9243       /* 0xEFCDAB8967452301 */
9244       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9245         {
9246           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9247         }
9248
9249       /* 0x89ABCDEF01234567 */
9250       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9251         {
9252           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9253         }
9254
9255       /* 0x45670123CDEF89AB */
9256       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9257         {
9258           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9259         }
9260
9261       /* 0x23016745AB89EFCD */
9262       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9263         {
9264           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9265         }
9266     }
9267
9268     /* By default do not swap the byte order, i.e. keep the byte order of the
9269      * architecture. The input file endianness will be set when reading the
9270      * header. The output endianness can be changed - before the file is
9271      * written. */
9272     tng_data->input_endianness_swap_func_32 = 0;
9273     tng_data->input_endianness_swap_func_64 = 0;
9274     tng_data->output_endianness_swap_func_32 = 0;
9275     tng_data->output_endianness_swap_func_64 = 0;
9276
9277     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9278     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9279     tng_data->current_trajectory_frame_set.n_frames = 0;
9280
9281     return(TNG_SUCCESS);
9282 }
9283
9284 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9285 {
9286     int64_t i, j, k, l;
9287     int64_t n_particles, n_values_per_frame;
9288     tng_trajectory_t tng_data = *tng_data_p;
9289     tng_trajectory_frame_set_t frame_set;
9290
9291     if(!*tng_data_p)
9292     {
9293         return(TNG_SUCCESS);
9294     }
9295
9296     frame_set = &tng_data->current_trajectory_frame_set;
9297
9298     if(tng_data->input_file_path)
9299     {
9300         free(tng_data->input_file_path);
9301         tng_data->input_file_path = 0;
9302     }
9303
9304     if(tng_data->input_file)
9305     {
9306         fclose(tng_data->input_file);
9307         tng_data->input_file = 0;
9308     }
9309
9310     if(tng_data->output_file_path)
9311     {
9312         free(tng_data->output_file_path);
9313         tng_data->output_file_path = 0;
9314     }
9315
9316     if(tng_data->output_file)
9317     {
9318         /* FIXME: Do not always write the hash */
9319         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9320         fclose(tng_data->output_file);
9321         tng_data->output_file = 0;
9322     }
9323
9324     if(tng_data->first_program_name)
9325     {
9326         free(tng_data->first_program_name);
9327         tng_data->first_program_name = 0;
9328     }
9329
9330     if(tng_data->last_program_name)
9331     {
9332         free(tng_data->last_program_name);
9333         tng_data->last_program_name = 0;
9334     }
9335
9336     if(tng_data->first_user_name)
9337     {
9338         free(tng_data->first_user_name);
9339         tng_data->first_user_name = 0;
9340     }
9341
9342     if(tng_data->last_user_name)
9343     {
9344         free(tng_data->last_user_name);
9345         tng_data->last_user_name = 0;
9346     }
9347
9348     if(tng_data->first_computer_name)
9349     {
9350         free(tng_data->first_computer_name);
9351         tng_data->first_computer_name = 0;
9352     }
9353
9354     if(tng_data->last_computer_name)
9355     {
9356         free(tng_data->last_computer_name);
9357         tng_data->last_computer_name = 0;
9358     }
9359
9360     if(tng_data->first_pgp_signature)
9361     {
9362         free(tng_data->first_pgp_signature);
9363         tng_data->first_pgp_signature = 0;
9364     }
9365
9366     if(tng_data->last_pgp_signature)
9367     {
9368         free(tng_data->last_pgp_signature);
9369         tng_data->last_pgp_signature = 0;
9370     }
9371
9372     if(tng_data->forcefield_name)
9373     {
9374         free(tng_data->forcefield_name);
9375         tng_data->forcefield_name = 0;
9376     }
9377
9378     tng_frame_set_particle_mapping_free(tng_data);
9379
9380     if(frame_set->molecule_cnt_list)
9381     {
9382         free(frame_set->molecule_cnt_list);
9383         frame_set->molecule_cnt_list = 0;
9384     }
9385
9386     if(tng_data->var_num_atoms_flag)
9387     {
9388         n_particles = frame_set->n_particles;
9389     }
9390     else
9391     {
9392         n_particles = tng_data->n_particles;
9393     }
9394
9395     if(tng_data->non_tr_particle_data)
9396     {
9397         for(i = tng_data->n_particle_data_blocks; i--; )
9398         {
9399             if(tng_data->non_tr_particle_data[i].values)
9400             {
9401                 free(tng_data->non_tr_particle_data[i].values);
9402                 tng_data->non_tr_particle_data[i].values = 0;
9403             }
9404
9405             if(tng_data->non_tr_particle_data[i].strings)
9406             {
9407                 n_values_per_frame = tng_data->non_tr_particle_data[i].
9408                                      n_values_per_frame;
9409                 if(tng_data->non_tr_particle_data[i].strings[0])
9410                 {
9411                     for(j = n_particles; j--;)
9412                     {
9413                         if(tng_data->non_tr_particle_data[i].strings[0][j])
9414                         {
9415                             for(k = n_values_per_frame; k--;)
9416                             {
9417                                 if(tng_data->non_tr_particle_data[i].
9418                                    strings[0][j][k])
9419                                 {
9420                                     free(tng_data->non_tr_particle_data[i].
9421                                          strings[0][j][k]);
9422                                     tng_data->non_tr_particle_data[i].
9423                                     strings[0][j][k] = 0;
9424                                 }
9425                             }
9426                             free(tng_data->non_tr_particle_data[i].
9427                                  strings[0][j]);
9428                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
9429                         }
9430                     }
9431                     free(tng_data->non_tr_particle_data[i].strings[0]);
9432                     tng_data->non_tr_particle_data[i].strings[0] = 0;
9433                 }
9434                 free(tng_data->non_tr_particle_data[i].strings);
9435                 tng_data->non_tr_particle_data[i].strings = 0;
9436             }
9437
9438             if(tng_data->non_tr_particle_data[i].block_name)
9439             {
9440                 free(tng_data->non_tr_particle_data[i].block_name);
9441                 tng_data->non_tr_particle_data[i].block_name = 0;
9442             }
9443         }
9444         free(tng_data->non_tr_particle_data);
9445         tng_data->non_tr_particle_data = 0;
9446     }
9447
9448     if(tng_data->non_tr_data)
9449     {
9450         for(i = tng_data->n_data_blocks; i--;)
9451         {
9452             if(tng_data->non_tr_data[i].values)
9453             {
9454                 free(tng_data->non_tr_data[i].values);
9455                 tng_data->non_tr_data[i].values = 0;
9456             }
9457
9458             if(tng_data->non_tr_data[i].strings)
9459             {
9460                 n_values_per_frame = tng_data->non_tr_data[i].
9461                                      n_values_per_frame;
9462                 if(tng_data->non_tr_data[i].strings[0])
9463                 {
9464                     for(j = n_values_per_frame; j--;)
9465                     {
9466                         if(tng_data->non_tr_data[i].strings[0][j])
9467                         {
9468                             free(tng_data->non_tr_data[i].strings[0][j]);
9469                             tng_data->non_tr_data[i].strings[0][j] = 0;
9470                         }
9471                     }
9472                     free(tng_data->non_tr_data[i].strings[0]);
9473                     tng_data->non_tr_data[i].strings[0] = 0;
9474                 }
9475                 free(tng_data->non_tr_data[i].strings);
9476                 tng_data->non_tr_data[i].strings = 0;
9477             }
9478
9479             if(tng_data->non_tr_data[i].block_name)
9480             {
9481                 free(tng_data->non_tr_data[i].block_name);
9482                 tng_data->non_tr_data[i].block_name = 0;
9483             }
9484         }
9485         free(tng_data->non_tr_data);
9486         tng_data->non_tr_data = 0;
9487     }
9488
9489     tng_data->n_particle_data_blocks = 0;
9490     tng_data->n_data_blocks = 0;
9491
9492     if(tng_data->compress_algo_pos)
9493     {
9494         free(tng_data->compress_algo_pos);
9495         tng_data->compress_algo_pos = 0;
9496     }
9497     if(tng_data->compress_algo_vel)
9498     {
9499         free(tng_data->compress_algo_vel);
9500         tng_data->compress_algo_vel = 0;
9501     }
9502
9503     if(frame_set->tr_particle_data)
9504     {
9505         for(i = frame_set->n_particle_data_blocks; i--; )
9506         {
9507             if(frame_set->tr_particle_data[i].values)
9508             {
9509                 free(frame_set->tr_particle_data[i].values);
9510                 frame_set->tr_particle_data[i].values = 0;
9511             }
9512
9513             if(frame_set->tr_particle_data[i].strings)
9514             {
9515                 n_values_per_frame = frame_set->tr_particle_data[i].
9516                                      n_values_per_frame;
9517                 for(j = frame_set->tr_particle_data[i].n_frames; j--;)
9518                 {
9519                     if(frame_set->tr_particle_data[i].strings[j])
9520                     {
9521                         for(k = n_particles; k--;)
9522                         {
9523                             if(frame_set->tr_particle_data[i].
9524                                 strings[j][k])
9525                             {
9526                                 for(l = n_values_per_frame; l--;)
9527                                 {
9528                                     if(frame_set->tr_particle_data[i].
9529                                         strings[j][k][l])
9530                                     {
9531                                         free(frame_set->tr_particle_data[i].
9532                                                 strings[j][k][l]);
9533                                         frame_set->tr_particle_data[i].
9534                                         strings[j][k][l] = 0;
9535                                     }
9536                                 }
9537                                 free(frame_set->tr_particle_data[i].
9538                                         strings[j][k]);
9539                                 frame_set->tr_particle_data[i].
9540                                 strings[j][k] = 0;
9541                             }
9542                         }
9543                         free(frame_set->tr_particle_data[i].strings[j]);
9544                         frame_set->tr_particle_data[i].strings[j] = 0;
9545                     }
9546                 }
9547                 free(frame_set->tr_particle_data[i].strings);
9548                 frame_set->tr_particle_data[i].strings = 0;
9549             }
9550
9551             if(frame_set->tr_particle_data[i].block_name)
9552             {
9553                 free(frame_set->tr_particle_data[i].block_name);
9554                 frame_set->tr_particle_data[i].block_name = 0;
9555             }
9556         }
9557         free(frame_set->tr_particle_data);
9558         frame_set->tr_particle_data = 0;
9559     }
9560
9561     if(frame_set->tr_data)
9562     {
9563         for(i = frame_set->n_data_blocks; i--;)
9564         {
9565             if(frame_set->tr_data[i].values)
9566             {
9567                 free(frame_set->tr_data[i].values);
9568                 frame_set->tr_data[i].values = 0;
9569             }
9570
9571             if(frame_set->tr_data[i].strings)
9572             {
9573                 n_values_per_frame = frame_set->tr_data[i].
9574                                      n_values_per_frame;
9575                 for(j = frame_set->tr_data[i].n_frames; j--;)
9576                 {
9577                     if(frame_set->tr_data[i].strings[j])
9578                     {
9579                         for(k = n_values_per_frame; k--;)
9580                         {
9581                             if(frame_set->tr_data[i].strings[j][k])
9582                             {
9583                                 free(frame_set->tr_data[i].strings[j][k]);
9584                                 frame_set->tr_data[i].strings[j][k] = 0;
9585                             }
9586                         }
9587                         free(frame_set->tr_data[i].strings[j]);
9588                         frame_set->tr_data[i].strings[j] = 0;
9589                     }
9590                 }
9591                 free(frame_set->tr_data[i].strings);
9592                 frame_set->tr_data[i].strings = 0;
9593             }
9594
9595             if(frame_set->tr_data[i].block_name)
9596             {
9597                 free(frame_set->tr_data[i].block_name);
9598                 frame_set->tr_data[i].block_name = 0;
9599             }
9600         }
9601         free(frame_set->tr_data);
9602         frame_set->tr_data = 0;
9603     }
9604
9605     frame_set->n_particle_data_blocks = 0;
9606     frame_set->n_data_blocks = 0;
9607
9608     if(tng_data->molecules)
9609     {
9610         for(i=tng_data->n_molecules; i--;)
9611         {
9612             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
9613         }
9614         free(tng_data->molecules);
9615         tng_data->molecules = 0;
9616         tng_data->n_molecules = 0;
9617     }
9618     if(tng_data->molecule_cnt_list)
9619     {
9620         free(tng_data->molecule_cnt_list);
9621         tng_data->molecule_cnt_list = 0;
9622     }
9623
9624     free(*tng_data_p);
9625     *tng_data_p = 0;
9626
9627     return(TNG_SUCCESS);
9628 }
9629
9630 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
9631                                                  tng_trajectory_t *dest_p)
9632 {
9633     tng_trajectory_frame_set_t frame_set;
9634     tng_trajectory_t dest;
9635
9636     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
9637
9638     *dest_p = malloc(sizeof(struct tng_trajectory));
9639     if(!*dest_p)
9640     {
9641         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9642                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9643         return(TNG_CRITICAL);
9644     }
9645
9646     dest = *dest_p;
9647
9648     frame_set = &dest->current_trajectory_frame_set;
9649
9650     dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
9651     if(!dest->input_file_path)
9652     {
9653         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
9654                (int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
9655         return(TNG_CRITICAL);
9656     }
9657     strcpy(dest->input_file_path, src->input_file_path);
9658     dest->input_file = 0;
9659     dest->input_file_len = src->input_file_len;
9660     dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
9661     if(!dest->output_file_path)
9662     {
9663         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
9664                (int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
9665         return(TNG_CRITICAL);
9666     }
9667     strcpy(dest->output_file_path, src->output_file_path);
9668     dest->output_file = 0;
9669
9670     dest->first_program_name = 0;
9671     dest->first_user_name = 0;
9672     dest->first_computer_name = 0;
9673     dest->first_pgp_signature = 0;
9674     dest->last_program_name = 0;
9675     dest->last_user_name = 0;
9676     dest->last_computer_name = 0;
9677     dest->last_pgp_signature = 0;
9678     dest->forcefield_name = 0;
9679
9680     dest->var_num_atoms_flag = src->var_num_atoms_flag;
9681     dest->first_trajectory_frame_set_input_file_pos =
9682     src->first_trajectory_frame_set_input_file_pos;
9683     dest->last_trajectory_frame_set_input_file_pos =
9684     src->last_trajectory_frame_set_input_file_pos;
9685     dest->current_trajectory_frame_set_input_file_pos =
9686     src->current_trajectory_frame_set_input_file_pos;
9687     dest->first_trajectory_frame_set_output_file_pos =
9688     src->first_trajectory_frame_set_output_file_pos;
9689     dest->last_trajectory_frame_set_output_file_pos =
9690     src->last_trajectory_frame_set_output_file_pos;
9691     dest->current_trajectory_frame_set_output_file_pos =
9692     src->current_trajectory_frame_set_output_file_pos;
9693     dest->frame_set_n_frames = src->frame_set_n_frames;
9694     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
9695     dest->n_trajectory_blocks = src->n_trajectory_blocks;
9696     dest->medium_stride_length = src->medium_stride_length;
9697     dest->long_stride_length = src->long_stride_length;
9698
9699     dest->time_per_frame = src->time_per_frame;
9700
9701     /* Currently the non trajectory data blocks are not copied since it
9702      * can lead to problems when freeing memory in a parallel block. */
9703     dest->n_particle_data_blocks = 0;
9704     dest->n_data_blocks = 0;
9705     dest->non_tr_particle_data = 0;
9706     dest->non_tr_data = 0;
9707
9708     dest->compress_algo_pos = 0;
9709     dest->compress_algo_vel = 0;
9710     dest->distance_unit_exponential = -9;
9711     dest->compression_precision = 1000;
9712
9713     frame_set->n_mapping_blocks = 0;
9714     frame_set->mappings = 0;
9715     frame_set->molecule_cnt_list = 0;
9716
9717     frame_set->n_particle_data_blocks = 0;
9718     frame_set->n_data_blocks = 0;
9719
9720     frame_set->tr_particle_data = 0;
9721     frame_set->tr_data = 0;
9722
9723     frame_set->next_frame_set_file_pos = -1;
9724     frame_set->prev_frame_set_file_pos = -1;
9725     frame_set->medium_stride_next_frame_set_file_pos = -1;
9726     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9727     frame_set->long_stride_next_frame_set_file_pos = -1;
9728     frame_set->long_stride_prev_frame_set_file_pos = -1;
9729     frame_set->first_frame = -1;
9730
9731     dest->n_molecules = 0;
9732     dest->molecules = 0;
9733     dest->molecule_cnt_list = 0;
9734     dest->n_particles = src->n_particles;
9735
9736     dest->endianness_32 = src->endianness_32;
9737     dest->endianness_64 = src->endianness_64;
9738     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
9739     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
9740     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
9741     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
9742
9743     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9744     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9745     dest->current_trajectory_frame_set.n_frames = 0;
9746
9747     return(TNG_SUCCESS);
9748 }
9749
9750 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
9751                                        char *file_name, const int max_len)
9752 {
9753     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9754     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9755
9756     strncpy(file_name, tng_data->input_file_path, max_len - 1);
9757     file_name[max_len - 1] = 0;
9758
9759     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
9760     {
9761         return(TNG_FAILURE);
9762     }
9763     return(TNG_SUCCESS);
9764 }
9765
9766 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
9767                                                          const char *file_name)
9768 {
9769     unsigned int len;
9770     char *temp;
9771
9772     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9773     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9774
9775
9776     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
9777                                            file_name) == 0)
9778     {
9779         return(TNG_SUCCESS);
9780     }
9781
9782     if(tng_data->input_file)
9783     {
9784         fclose(tng_data->input_file);
9785     }
9786
9787     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
9788     temp = realloc(tng_data->input_file_path, len);
9789     if(!temp)
9790     {
9791         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
9792                __FILE__, __LINE__);
9793         free(tng_data->input_file_path);
9794         tng_data->input_file_path = 0;
9795         return(TNG_CRITICAL);
9796     }
9797     tng_data->input_file_path = temp;
9798
9799     strncpy(tng_data->input_file_path, file_name, len);
9800
9801     return(tng_input_file_init(tng_data));
9802 }
9803
9804 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
9805                                        char *file_name, const int max_len)
9806 {
9807     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9808     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9809
9810     strncpy(file_name, tng_data->output_file_path, max_len - 1);
9811     file_name[max_len - 1] = 0;
9812
9813     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
9814     {
9815         return(TNG_FAILURE);
9816     }
9817     return(TNG_SUCCESS);
9818 }
9819
9820 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
9821                                                           const char *file_name)
9822 {
9823     int len;
9824     char *temp;
9825
9826     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9827     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9828
9829     if(tng_data->output_file_path &&
9830        strcmp(tng_data->output_file_path, file_name) == 0)
9831     {
9832         return(TNG_SUCCESS);
9833     }
9834
9835     if(tng_data->output_file)
9836     {
9837         fclose(tng_data->output_file);
9838     }
9839
9840     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
9841     temp = realloc(tng_data->output_file_path, len);
9842     if(!temp)
9843     {
9844         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
9845                __FILE__, __LINE__);
9846         free(tng_data->output_file_path);
9847         tng_data->output_file_path = 0;
9848         return(TNG_CRITICAL);
9849     }
9850     tng_data->output_file_path = temp;
9851
9852     strncpy(tng_data->output_file_path, file_name, len);
9853
9854     return(tng_output_file_init(tng_data));
9855 }
9856
9857 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
9858                 (tng_trajectory_t tng_data,
9859                  const char *file_name)
9860 {
9861     int len;
9862     char *temp;
9863
9864     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9865     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9866
9867     if(tng_data->output_file_path &&
9868        strcmp(tng_data->output_file_path, file_name) == 0)
9869     {
9870         return(TNG_SUCCESS);
9871     }
9872
9873     if(tng_data->output_file)
9874     {
9875         fclose(tng_data->output_file);
9876     }
9877
9878     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
9879     temp = realloc(tng_data->output_file_path, len);
9880     if(!temp)
9881     {
9882         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
9883                __FILE__, __LINE__);
9884         free(tng_data->output_file_path);
9885         tng_data->output_file_path = 0;
9886         return(TNG_CRITICAL);
9887     }
9888     tng_data->output_file_path = temp;
9889
9890     strncpy(tng_data->output_file_path, file_name, len);
9891
9892     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
9893     if(!tng_data->output_file)
9894     {
9895         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
9896                 tng_data->output_file_path, __FILE__, __LINE__);
9897         return(TNG_CRITICAL);
9898     }
9899
9900     return(TNG_SUCCESS);
9901 }
9902
9903 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
9904                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
9905 {
9906     tng_endianness_32 end_32;
9907     tng_endianness_64 end_64;
9908
9909     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9910     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
9911
9912     if(tng_data->output_endianness_swap_func_32)
9913     {
9914         /* If other endianness variants are added they must be added here as well */
9915         if(tng_data->output_endianness_swap_func_32 ==
9916            &tng_swap_byte_order_big_endian_32)
9917         {
9918             end_32 = TNG_BIG_ENDIAN_32;
9919         }
9920         else if(tng_data->output_endianness_swap_func_32 ==
9921                 &tng_swap_byte_order_little_endian_32)
9922         {
9923             end_32 = TNG_LITTLE_ENDIAN_32;
9924         }
9925         else
9926         {
9927             return(TNG_FAILURE);
9928         }
9929     }
9930     else
9931     {
9932         end_32 = (tng_endianness_32)tng_data->endianness_32;
9933     }
9934
9935     if(tng_data->output_endianness_swap_func_64)
9936     {
9937         /* If other endianness variants are added they must be added here as well */
9938         if(tng_data->output_endianness_swap_func_64 ==
9939            &tng_swap_byte_order_big_endian_64)
9940         {
9941             end_64 = TNG_BIG_ENDIAN_64;
9942         }
9943         else if(tng_data->output_endianness_swap_func_64 ==
9944                 &tng_swap_byte_order_little_endian_64)
9945         {
9946             end_64 = TNG_LITTLE_ENDIAN_64;
9947         }
9948         else
9949         {
9950             return(TNG_FAILURE);
9951         }
9952     }
9953     else
9954     {
9955         end_64 = (tng_endianness_64)tng_data->endianness_64;
9956     }
9957
9958     if((int)end_32 != (int)end_64)
9959     {
9960         return(TNG_FAILURE);
9961     }
9962
9963     if(end_32 == TNG_LITTLE_ENDIAN_32)
9964     {
9965         *endianness = TNG_LITTLE_ENDIAN;
9966     }
9967
9968     else if(end_32 == TNG_BIG_ENDIAN_32)
9969     {
9970         *endianness = TNG_BIG_ENDIAN;
9971     }
9972     else
9973     {
9974         return(TNG_FAILURE);
9975     }
9976
9977     return(TNG_SUCCESS);
9978 }
9979
9980 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
9981                 (tng_trajectory_t tng_data,
9982                  const tng_file_endianness endianness)
9983 {
9984     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9985
9986     /* Tne endianness cannot be changed if the data has already been written
9987      * to the output file. */
9988     if(ftell(tng_data->output_file) > 0)
9989     {
9990         return(TNG_FAILURE);
9991     }
9992
9993     if(endianness == TNG_BIG_ENDIAN)
9994     {
9995         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
9996         {
9997             tng_data->output_endianness_swap_func_32 = 0;
9998         }
9999         else
10000         {
10001             tng_data->output_endianness_swap_func_32 =
10002             &tng_swap_byte_order_big_endian_32;
10003         }
10004         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
10005         {
10006             tng_data->output_endianness_swap_func_64 = 0;
10007         }
10008         else
10009         {
10010             tng_data->output_endianness_swap_func_64 =
10011             &tng_swap_byte_order_big_endian_64;
10012         }
10013         return(TNG_SUCCESS);
10014     }
10015     else if(endianness == TNG_LITTLE_ENDIAN)
10016     {
10017         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
10018         {
10019             tng_data->output_endianness_swap_func_32 = 0;
10020         }
10021         else
10022         {
10023             tng_data->output_endianness_swap_func_32 =
10024             &tng_swap_byte_order_little_endian_32;
10025         }
10026         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
10027         {
10028             tng_data->output_endianness_swap_func_64 = 0;
10029         }
10030         else
10031         {
10032             tng_data->output_endianness_swap_func_64 =
10033             &tng_swap_byte_order_little_endian_64;
10034         }
10035         return(TNG_SUCCESS);
10036     }
10037
10038     /* If the specified endianness is neither big nor little endian return a
10039      * failure. */
10040     return(TNG_FAILURE);
10041 }
10042
10043 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
10044                     (const tng_trajectory_t tng_data,
10045                      char *name, const int max_len)
10046 {
10047     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10048     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10049
10050     strncpy(name, tng_data->first_program_name, max_len - 1);
10051     name[max_len - 1] = 0;
10052
10053     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
10054     {
10055         return(TNG_FAILURE);
10056     }
10057     return(TNG_SUCCESS);
10058 }
10059
10060 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
10061                                                                  const char *new_name)
10062 {
10063     unsigned int len;
10064
10065     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10066     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10067
10068     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10069
10070     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10071     {
10072         free(tng_data->first_program_name);
10073         tng_data->first_program_name = 0;
10074     }
10075     if(!tng_data->first_program_name)
10076     {
10077         tng_data->first_program_name = malloc(len);
10078         if(!tng_data->first_program_name)
10079         {
10080             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10081                    __FILE__, __LINE__);
10082             return(TNG_CRITICAL);
10083         }
10084     }
10085
10086     strncpy(tng_data->first_program_name, new_name, len);
10087
10088     return(TNG_SUCCESS);
10089 }
10090
10091 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10092                     (const tng_trajectory_t tng_data,
10093                      char *name, const int max_len)
10094 {
10095     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10096     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10097
10098     strncpy(name, tng_data->last_program_name, max_len - 1);
10099     name[max_len - 1] = 0;
10100
10101     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10102     {
10103         return(TNG_FAILURE);
10104     }
10105     return(TNG_SUCCESS);
10106 }
10107
10108 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10109                     (tng_trajectory_t tng_data,
10110                      const char *new_name)
10111 {
10112     unsigned int len;
10113
10114     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10115     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10116
10117     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10118
10119     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10120     {
10121         free(tng_data->last_program_name);
10122         tng_data->last_program_name = 0;
10123     }
10124     if(!tng_data->last_program_name)
10125     {
10126         tng_data->last_program_name = malloc(len);
10127         if(!tng_data->last_program_name)
10128         {
10129             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10130                    __FILE__, __LINE__);
10131             return(TNG_CRITICAL);
10132         }
10133     }
10134
10135     strncpy(tng_data->last_program_name, new_name, len);
10136
10137     return(TNG_SUCCESS);
10138 }
10139
10140 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10141                     (const tng_trajectory_t tng_data,
10142                      char *name, const int max_len)
10143 {
10144     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10145     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10146
10147     strncpy(name, tng_data->first_user_name, max_len - 1);
10148     name[max_len - 1] = 0;
10149
10150     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10151     {
10152         return(TNG_FAILURE);
10153     }
10154     return(TNG_SUCCESS);
10155 }
10156
10157 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10158                     (tng_trajectory_t tng_data,
10159                      const char *new_name)
10160 {
10161     unsigned int len;
10162
10163     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10164     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10165
10166     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10167
10168     /* If the currently stored string length is not enough to store the new
10169      * string it is freed and reallocated. */
10170     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10171     {
10172         free(tng_data->first_user_name);
10173         tng_data->first_user_name = 0;
10174     }
10175     if(!tng_data->first_user_name)
10176     {
10177         tng_data->first_user_name = malloc(len);
10178         if(!tng_data->first_user_name)
10179         {
10180             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10181                    __FILE__, __LINE__);
10182             return(TNG_CRITICAL);
10183         }
10184     }
10185
10186     strncpy(tng_data->first_user_name, new_name, len);
10187
10188     return(TNG_SUCCESS);
10189 }
10190
10191 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10192                     (const tng_trajectory_t tng_data,
10193                      char *name, const int max_len)
10194 {
10195     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10196     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10197
10198     strncpy(name, tng_data->last_user_name, max_len - 1);
10199     name[max_len - 1] = 0;
10200
10201     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10202     {
10203         return(TNG_FAILURE);
10204     }
10205     return(TNG_SUCCESS);
10206 }
10207
10208 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10209                     (tng_trajectory_t tng_data,
10210                      const char *new_name)
10211 {
10212     unsigned int len;
10213
10214     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10215     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10216
10217     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10218
10219     /* If the currently stored string length is not enough to store the new
10220      * string it is freed and reallocated. */
10221     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10222     {
10223         free(tng_data->last_user_name);
10224         tng_data->last_user_name = 0;
10225     }
10226     if(!tng_data->last_user_name)
10227     {
10228         tng_data->last_user_name = malloc(len);
10229         if(!tng_data->last_user_name)
10230         {
10231             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10232                    __FILE__, __LINE__);
10233             return(TNG_CRITICAL);
10234         }
10235     }
10236
10237     strncpy(tng_data->last_user_name, new_name, len);
10238
10239     return(TNG_SUCCESS);
10240 }
10241
10242 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10243                     (const tng_trajectory_t tng_data,
10244                      char *name, const int max_len)
10245 {
10246     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10247     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10248
10249     strncpy(name, tng_data->first_computer_name, max_len - 1);
10250     name[max_len - 1] = 0;
10251
10252     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10253     {
10254         return(TNG_FAILURE);
10255     }
10256     return(TNG_SUCCESS);
10257 }
10258
10259 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10260                     (tng_trajectory_t tng_data,
10261                      const char *new_name)
10262 {
10263     unsigned int len;
10264
10265     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10266     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10267
10268     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10269
10270     /* If the currently stored string length is not enough to store the new
10271      * string it is freed and reallocated. */
10272     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10273     {
10274         free(tng_data->first_computer_name);
10275         tng_data->first_computer_name = 0;
10276     }
10277     if(!tng_data->first_computer_name)
10278     {
10279         tng_data->first_computer_name = malloc(len);
10280         if(!tng_data->first_computer_name)
10281         {
10282             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10283                    __FILE__, __LINE__);
10284             return(TNG_CRITICAL);
10285         }
10286     }
10287
10288     strncpy(tng_data->first_computer_name, new_name, len);
10289
10290     return(TNG_SUCCESS);
10291 }
10292
10293 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10294                     (const tng_trajectory_t tng_data,
10295                      char *name, const int max_len)
10296 {
10297     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10298     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10299
10300     strncpy(name, tng_data->last_computer_name, max_len - 1);
10301     name[max_len - 1] = 0;
10302
10303     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10304     {
10305         return(TNG_FAILURE);
10306     }
10307     return(TNG_SUCCESS);
10308 }
10309
10310 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10311                     (tng_trajectory_t tng_data,
10312                      const char *new_name)
10313 {
10314     unsigned int len;
10315
10316     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10317     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10318
10319     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10320
10321     /* If the currently stored string length is not enough to store the new
10322      * string it is freed and reallocated. */
10323     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
10324         len)
10325     {
10326         free(tng_data->last_computer_name);
10327         tng_data->last_computer_name = 0;
10328     }
10329     if(!tng_data->last_computer_name)
10330     {
10331         tng_data->last_computer_name = malloc(len);
10332         if(!tng_data->last_computer_name)
10333         {
10334             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10335                    __FILE__, __LINE__);
10336             return(TNG_CRITICAL);
10337         }
10338     }
10339
10340     strncpy(tng_data->last_computer_name, new_name, len);
10341
10342     return(TNG_SUCCESS);
10343 }
10344
10345 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
10346                     (const tng_trajectory_t tng_data,
10347                      char *signature, const int max_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     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
10353     signature[max_len - 1] = 0;
10354
10355     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
10356     {
10357         return(TNG_FAILURE);
10358     }
10359     return(TNG_SUCCESS);
10360 }
10361
10362 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
10363                     (tng_trajectory_t tng_data,
10364                      const char *signature)
10365 {
10366     unsigned int len;
10367
10368     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10369     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10370
10371     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10372
10373     /* If the currently stored string length is not enough to store the new
10374      * string it is freed and reallocated. */
10375     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
10376         len)
10377     {
10378         free(tng_data->first_pgp_signature);
10379         tng_data->first_pgp_signature = 0;
10380     }
10381     if(!tng_data->first_pgp_signature)
10382     {
10383         tng_data->first_pgp_signature = malloc(len);
10384         if(!tng_data->first_pgp_signature)
10385         {
10386             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10387                    __FILE__, __LINE__);
10388             return(TNG_CRITICAL);
10389         }
10390     }
10391
10392     strncpy(tng_data->first_pgp_signature, signature, len);
10393
10394     return(TNG_SUCCESS);
10395 }
10396
10397 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
10398                     (const tng_trajectory_t tng_data,
10399                      char *signature, const int max_len)
10400 {
10401     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10402     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10403
10404     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
10405     signature[max_len - 1] = 0;
10406
10407     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
10408     {
10409         return(TNG_FAILURE);
10410     }
10411     return(TNG_SUCCESS);
10412 }
10413
10414 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
10415                     (tng_trajectory_t tng_data,
10416                      const char *signature)
10417 {
10418     unsigned int len;
10419
10420     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10421     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10422
10423     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
10424
10425     /* If the currently stored string length is not enough to store the new
10426      * string it is freed and reallocated. */
10427     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
10428         len)
10429     {
10430         free(tng_data->last_pgp_signature);
10431         tng_data->last_pgp_signature = 0;
10432     }
10433     if(!tng_data->last_pgp_signature)
10434     {
10435         tng_data->last_pgp_signature = malloc(len);
10436         if(!tng_data->last_pgp_signature)
10437         {
10438             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10439                    __FILE__, __LINE__);
10440             return(TNG_CRITICAL);
10441         }
10442     }
10443
10444     strncpy(tng_data->last_pgp_signature, signature, len);
10445
10446     return(TNG_SUCCESS);
10447 }
10448
10449 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
10450                     (const tng_trajectory_t tng_data,
10451                      char *name, const int max_len)
10452 {
10453     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10454     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10455
10456     strncpy(name, tng_data->forcefield_name, max_len - 1);
10457     name[max_len - 1] = 0;
10458
10459     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
10460     {
10461         return(TNG_FAILURE);
10462     }
10463     return(TNG_SUCCESS);
10464 }
10465
10466 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
10467                     (tng_trajectory_t tng_data,
10468                      const char *new_name)
10469 {
10470     unsigned int len;
10471
10472     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10473     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10474
10475     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10476
10477     /* If the currently stored string length is not enough to store the new
10478      * string it is freed and reallocated. */
10479     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
10480     {
10481         free(tng_data->forcefield_name);
10482         tng_data->forcefield_name = 0;
10483     }
10484     if(!tng_data->forcefield_name)
10485     {
10486         tng_data->forcefield_name = malloc(len);
10487         if(!tng_data->forcefield_name)
10488         {
10489             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10490                    __FILE__, __LINE__);
10491             return(TNG_CRITICAL);
10492         }
10493     }
10494
10495     strncpy(tng_data->forcefield_name, new_name, len);
10496
10497     return(TNG_SUCCESS);
10498 }
10499
10500 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
10501                     (const tng_trajectory_t tng_data,
10502                      int64_t *len)
10503 {
10504     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10505     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10506
10507     *len = tng_data->medium_stride_length;
10508
10509     return(TNG_SUCCESS);
10510 }
10511
10512 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
10513                     (tng_trajectory_t tng_data,
10514                      const int64_t len)
10515 {
10516     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10517
10518     if(len >= tng_data->long_stride_length)
10519     {
10520         return(TNG_FAILURE);
10521     }
10522     tng_data->medium_stride_length = len;
10523
10524     return(TNG_SUCCESS);
10525 }
10526
10527 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
10528                 (const tng_trajectory_t tng_data,
10529                  int64_t *len)
10530 {
10531     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10532     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10533
10534     *len = tng_data->long_stride_length;
10535
10536     return(TNG_SUCCESS);
10537 }
10538
10539 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
10540                 (tng_trajectory_t tng_data,
10541                  const int64_t len)
10542 {
10543     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10544
10545     if(len <= tng_data->medium_stride_length)
10546     {
10547         return(TNG_FAILURE);
10548     }
10549     tng_data->long_stride_length = len;
10550
10551     return(TNG_SUCCESS);
10552 }
10553
10554 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
10555                 (const tng_trajectory_t tng_data,
10556                  double *time)
10557 {
10558     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10559     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
10560
10561     *time = tng_data->time_per_frame;
10562
10563     return(TNG_SUCCESS);
10564 }
10565
10566 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
10567                 (tng_trajectory_t tng_data,
10568                  const double time)
10569 {
10570     tng_trajectory_frame_set_t frame_set;
10571
10572     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10573     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
10574
10575     if(fabs(time - tng_data->time_per_frame) < 0.00001)
10576     {
10577         return(TNG_SUCCESS);
10578     }
10579
10580     frame_set = &tng_data->current_trajectory_frame_set;
10581
10582     /* If the current frame set is not finished write it to disk before
10583        changing time per frame. */
10584     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
10585     {
10586         frame_set->n_frames = frame_set->n_unwritten_frames;
10587         tng_frame_set_write(tng_data, TNG_USE_HASH);
10588     }
10589     tng_data->time_per_frame = time;
10590
10591     return(TNG_SUCCESS);
10592 }
10593
10594 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
10595                     (const tng_trajectory_t tng_data,
10596                      int64_t *len)
10597 {
10598     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10599     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10600
10601     *len = tng_data->input_file_len;
10602
10603     return(TNG_SUCCESS);
10604 }
10605
10606 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
10607                     (const tng_trajectory_t tng_data,
10608                      int64_t *n)
10609 {
10610     tng_gen_block_t block;
10611     tng_function_status stat;
10612     long file_pos;
10613     int64_t last_file_pos, first_frame, n_frames;
10614
10615     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10616     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
10617     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10618
10619     file_pos = ftell(tng_data->input_file);
10620     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10621
10622     if(last_file_pos <= 0)
10623     {
10624         return(TNG_FAILURE);
10625     }
10626
10627     tng_block_init(&block);
10628     fseek(tng_data->input_file,
10629           (long)last_file_pos,
10630           SEEK_SET);
10631     /* Read block headers first to see that a frame set block is found. */
10632     stat = tng_block_header_read(tng_data, block);
10633     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10634     {
10635         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
10636                 __FILE__, __LINE__);
10637         tng_block_destroy(&block);
10638         return(TNG_FAILURE);
10639     }
10640     tng_block_destroy(&block);
10641
10642     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
10643     {
10644         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
10645                __FILE__, __LINE__);
10646         return(TNG_CRITICAL);
10647     }
10648     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
10649     {
10650         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
10651                __FILE__, __LINE__);
10652         return(TNG_CRITICAL);
10653     }
10654     fseek(tng_data->input_file, file_pos, SEEK_SET);
10655
10656     *n = first_frame + n_frames;
10657
10658     return(TNG_SUCCESS);
10659 }
10660
10661 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
10662                 (const tng_trajectory_t tng_data,
10663                  double *precision)
10664 {
10665     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10666
10667     *precision = tng_data->compression_precision;
10668
10669     return(TNG_SUCCESS);
10670 }
10671
10672 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
10673                 (tng_trajectory_t tng_data,
10674                  const double precision)
10675 {
10676     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10677
10678     tng_data->compression_precision = precision;
10679
10680     return(TNG_SUCCESS);
10681 }
10682
10683 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
10684                 (tng_trajectory_t tng_data,
10685                  const int64_t n)
10686 {
10687     tng_molecule_t mol;
10688     tng_chain_t chain;
10689     tng_residue_t res;
10690     tng_atom_t atom;
10691     tng_function_status stat;
10692     int64_t diff, n_mod, n_impl;
10693
10694     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
10695
10696     diff = n - tng_data->n_particles;
10697
10698     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
10699     if(stat == TNG_SUCCESS)
10700     {
10701         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
10702         {
10703             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
10704                     __FILE__, __LINE__);
10705             return(TNG_FAILURE);
10706         }
10707         diff -= n_impl * mol->n_atoms;
10708     }
10709
10710     if(diff == 0)
10711     {
10712         if(stat == TNG_SUCCESS)
10713         {
10714             stat = tng_molecule_cnt_set(tng_data, mol, 0);
10715             return(stat);
10716         }
10717         return(TNG_SUCCESS);
10718     }
10719     else if(diff < 0)
10720     {
10721         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
10722         fprintf(stderr, "particle count.\n");
10723         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10724                 __FILE__, __LINE__);
10725         /* FIXME: Should we set the count of all other molecules to 0 and add
10726          * implicit molecules? */
10727         return(TNG_FAILURE);
10728     }
10729     if(stat != TNG_SUCCESS)
10730     {
10731         stat = tng_molecule_add(tng_data,
10732                                 "TNG_IMPLICIT_MOL",
10733                                 &mol);
10734         if(stat != TNG_SUCCESS)
10735         {
10736             return(stat);
10737         }
10738         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
10739         if(stat != TNG_SUCCESS)
10740         {
10741             return(stat);
10742         }
10743         stat = tng_chain_residue_add(tng_data, chain, "", &res);
10744         if(stat != TNG_SUCCESS)
10745         {
10746             return(stat);
10747         }
10748         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
10749         if(stat != TNG_SUCCESS)
10750         {
10751             return(stat);
10752         }
10753     }
10754     else
10755     {
10756         if(mol->n_atoms > 1)
10757         {
10758             n_mod = diff % mol->n_atoms;
10759             if(n_mod != 0)
10760             {
10761                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
10762                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
10763                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10764                         __FILE__, __LINE__);
10765                 return(TNG_FAILURE);
10766             }
10767             diff /= mol->n_atoms;
10768         }
10769     }
10770     stat = tng_molecule_cnt_set(tng_data, mol, diff);
10771
10772     return(stat);
10773 }
10774
10775 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
10776                 (const tng_trajectory_t tng_data,
10777                  int64_t *n)
10778 {
10779     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10780     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10781
10782     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
10783     {
10784         *n = tng_data->n_particles;
10785     }
10786     else
10787     {
10788         *n = tng_data->current_trajectory_frame_set.n_particles;
10789     }
10790
10791     return(TNG_SUCCESS);
10792 }
10793
10794 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
10795                 (const tng_trajectory_t tng_data,
10796                  char *variable)
10797 {
10798     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10799     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
10800
10801     *variable = tng_data->var_num_atoms_flag;
10802
10803     return(TNG_SUCCESS);
10804 }
10805
10806 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
10807                     (const tng_trajectory_t tng_data,
10808                      int64_t *n)
10809 {
10810     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10811     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10812
10813     *n = tng_data->n_molecules;
10814
10815     return(TNG_SUCCESS);
10816 }
10817
10818 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
10819                     (const tng_trajectory_t tng_data,
10820                      int64_t *n)
10821 {
10822     int64_t *cnt_list = 0, cnt = 0, i;
10823
10824     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10825     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10826
10827     tng_molecule_cnt_list_get(tng_data, &cnt_list);
10828
10829     if(!cnt_list)
10830     {
10831         return(TNG_FAILURE);
10832     }
10833
10834     for(i = tng_data->n_molecules; i --;)
10835     {
10836         cnt += cnt_list[i];
10837     }
10838
10839     *n = cnt;
10840
10841     return(TNG_SUCCESS);
10842 }
10843
10844 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
10845                 (const tng_trajectory_t tng_data,
10846                  int64_t **mol_cnt_list)
10847 {
10848     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10849
10850     if(tng_data->var_num_atoms_flag)
10851     {
10852         *mol_cnt_list = tng_data->current_trajectory_frame_set.
10853                        molecule_cnt_list;
10854     }
10855     else
10856     {
10857         *mol_cnt_list = tng_data->molecule_cnt_list;
10858     }
10859     if(*mol_cnt_list == 0)
10860     {
10861         return(TNG_FAILURE);
10862     }
10863     return(TNG_SUCCESS);
10864 }
10865
10866 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
10867                 (const tng_trajectory_t tng_data,
10868                  int64_t *exp)
10869 {
10870     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10871     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
10872
10873     *exp = tng_data->distance_unit_exponential;
10874
10875     return(TNG_SUCCESS);
10876 }
10877
10878 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
10879                 (const tng_trajectory_t tng_data,
10880                  const int64_t exp)
10881 {
10882     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10883
10884     tng_data->distance_unit_exponential = exp;
10885
10886     return(TNG_SUCCESS);
10887 }
10888
10889 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
10890                 (const tng_trajectory_t tng_data,
10891                  int64_t *n)
10892 {
10893     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10894     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10895
10896     *n = tng_data->frame_set_n_frames;
10897
10898     return(TNG_SUCCESS);
10899 }
10900
10901 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
10902                 (const tng_trajectory_t tng_data,
10903                  const int64_t n)
10904 {
10905     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10906
10907     tng_data->frame_set_n_frames = n;
10908
10909     return(TNG_SUCCESS);
10910 }
10911
10912 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
10913                 (const tng_trajectory_t tng_data,
10914                  int64_t *n)
10915 {
10916     int64_t long_stride_length, medium_stride_length;
10917     long file_pos, orig_frame_set_file_pos;
10918     tng_trajectory_frame_set_t frame_set;
10919     struct tng_trajectory_frame_set   orig_frame_set;
10920     tng_gen_block_t block;
10921     tng_function_status stat;
10922     int64_t cnt = 0;
10923
10924     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10925     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10926
10927     orig_frame_set = tng_data->current_trajectory_frame_set;
10928
10929     frame_set = &tng_data->current_trajectory_frame_set;
10930
10931     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10932     file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
10933
10934     tng_block_init(&block);
10935     fseek(tng_data->input_file,
10936           file_pos,
10937           SEEK_SET);
10938     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10939     /* Read block headers first to see what block is found. */
10940     stat = tng_block_header_read(tng_data, block);
10941     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10942     {
10943         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n", file_pos,
10944                 __FILE__, __LINE__);
10945         tng_block_destroy(&block);
10946         return(TNG_CRITICAL);
10947     }
10948
10949     if(tng_block_read_next(tng_data, block,
10950                         TNG_SKIP_HASH) != TNG_SUCCESS)
10951     {
10952         tng_block_destroy(&block);
10953         return(TNG_CRITICAL);
10954     }
10955
10956     ++cnt;
10957
10958     long_stride_length = tng_data->long_stride_length;
10959     medium_stride_length = tng_data->medium_stride_length;
10960
10961     /* Take long steps forward until a long step forward would be too long or
10962      * the last frame set is found */
10963     file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
10964     while(file_pos > 0)
10965     {
10966         if(file_pos > 0)
10967         {
10968             cnt += long_stride_length;
10969             fseek(tng_data->input_file, file_pos, SEEK_SET);
10970             /* Read block headers first to see what block is found. */
10971             stat = tng_block_header_read(tng_data, block);
10972             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10973             {
10974                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
10975                        file_pos, __FILE__, __LINE__);
10976                 tng_block_destroy(&block);
10977                 return(TNG_CRITICAL);
10978             }
10979
10980             if(tng_block_read_next(tng_data, block,
10981                                 TNG_SKIP_HASH) != TNG_SUCCESS)
10982             {
10983                 tng_block_destroy(&block);
10984                 return(TNG_CRITICAL);
10985             }
10986         }
10987         file_pos = (long)frame_set->long_stride_next_frame_set_file_pos;
10988     }
10989
10990     /* Take medium steps forward until a medium step forward would be too long
10991      * or the last frame set is found */
10992     file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
10993     while(file_pos > 0)
10994     {
10995         if(file_pos > 0)
10996         {
10997             cnt += medium_stride_length;
10998             fseek(tng_data->input_file,
10999                   file_pos,
11000                   SEEK_SET);
11001             /* Read block headers first to see what block is found. */
11002             stat = tng_block_header_read(tng_data, block);
11003             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11004             {
11005                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11006                        file_pos, __FILE__, __LINE__);
11007                 tng_block_destroy(&block);
11008                 return(TNG_CRITICAL);
11009             }
11010
11011             if(tng_block_read_next(tng_data, block,
11012                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11013             {
11014                 tng_block_destroy(&block);
11015                 return(TNG_CRITICAL);
11016             }
11017         }
11018         file_pos = (long)frame_set->medium_stride_next_frame_set_file_pos;
11019     }
11020
11021     /* Take one step forward until the last frame set is found */
11022     file_pos = (long)frame_set->next_frame_set_file_pos;
11023     while(file_pos > 0)
11024     {
11025         if(file_pos > 0)
11026         {
11027             ++cnt;
11028             fseek(tng_data->input_file,
11029                   file_pos,
11030                   SEEK_SET);
11031             /* Read block headers first to see what block is found. */
11032             stat = tng_block_header_read(tng_data, block);
11033             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11034             {
11035                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
11036                        file_pos, __FILE__, __LINE__);
11037                 tng_block_destroy(&block);
11038                 return(TNG_CRITICAL);
11039             }
11040
11041             if(tng_block_read_next(tng_data, block,
11042                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11043             {
11044                 tng_block_destroy(&block);
11045                 return(TNG_CRITICAL);
11046             }
11047         }
11048         file_pos = (long)frame_set->next_frame_set_file_pos;
11049     }
11050
11051     tng_block_destroy(&block);
11052
11053     *n = tng_data->n_trajectory_frame_sets = cnt;
11054
11055     *frame_set = orig_frame_set;
11056
11057     fseek(tng_data->input_file,
11058           (long)tng_data->first_trajectory_frame_set_input_file_pos,
11059           SEEK_SET);
11060
11061     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
11062
11063     return(TNG_SUCCESS);
11064 }
11065
11066 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
11067                 (const tng_trajectory_t tng_data,
11068                  tng_trajectory_frame_set_t *frame_set_p)
11069 {
11070     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11071
11072     *frame_set_p = &tng_data->current_trajectory_frame_set;
11073
11074     return(TNG_SUCCESS);
11075 }
11076
11077 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11078                 (tng_trajectory_t tng_data,
11079                  const int64_t nr)
11080 {
11081     int64_t long_stride_length, medium_stride_length;
11082     int64_t file_pos, curr_nr = 0, n_frame_sets;
11083     tng_trajectory_frame_set_t frame_set;
11084     tng_gen_block_t block;
11085     tng_function_status stat;
11086
11087     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11088     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11089
11090     frame_set = &tng_data->current_trajectory_frame_set;
11091
11092     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11093
11094     if(stat != TNG_SUCCESS)
11095     {
11096         return(stat);
11097     }
11098
11099     if(nr >= n_frame_sets)
11100     {
11101         return(TNG_FAILURE);
11102     }
11103
11104     long_stride_length = tng_data->long_stride_length;
11105     medium_stride_length = tng_data->medium_stride_length;
11106
11107     /* FIXME: The frame set number of the current frame set is not stored */
11108
11109     if(nr < n_frame_sets - 1 - nr)
11110     {
11111         /* Start from the beginning */
11112         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11113     }
11114     else
11115     {
11116         /* Start from the end */
11117         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11118         curr_nr = n_frame_sets - 1;
11119     }
11120     if(file_pos <= 0)
11121     {
11122         return(TNG_FAILURE);
11123     }
11124
11125     tng_block_init(&block);
11126     fseek(tng_data->input_file,
11127           (long)file_pos,
11128           SEEK_SET);
11129     tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11130     /* Read block headers first to see what block is found. */
11131     stat = tng_block_header_read(tng_data, block);
11132     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11133     {
11134         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11135                 __FILE__, __LINE__);
11136         tng_block_destroy(&block);
11137         return(TNG_CRITICAL);
11138     }
11139
11140     if(tng_block_read_next(tng_data, block,
11141                         TNG_SKIP_HASH) != TNG_SUCCESS)
11142     {
11143         tng_block_destroy(&block);
11144         return(TNG_CRITICAL);
11145     }
11146
11147     if(curr_nr == nr)
11148     {
11149         tng_block_destroy(&block);
11150         return(TNG_SUCCESS);
11151     }
11152
11153     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11154
11155     /* Take long steps forward until a long step forward would be too long or
11156      * the right frame set is found */
11157     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11158     {
11159         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11160         if(file_pos > 0)
11161         {
11162             curr_nr += long_stride_length;
11163             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11164             /* Read block headers first to see what block is found. */
11165             stat = tng_block_header_read(tng_data, block);
11166             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11167             {
11168                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11169                        file_pos,  __FILE__, __LINE__);
11170                 tng_block_destroy(&block);
11171                 return(TNG_CRITICAL);
11172             }
11173
11174             if(tng_block_read_next(tng_data, block,
11175                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11176             {
11177                 tng_block_destroy(&block);
11178                 return(TNG_CRITICAL);
11179             }
11180             if(curr_nr == nr)
11181             {
11182                 tng_block_destroy(&block);
11183                 return(TNG_SUCCESS);
11184             }
11185         }
11186     }
11187
11188     /* Take medium steps forward until a medium step forward would be too long
11189      * or the right frame set is found */
11190     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11191     {
11192         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11193         if(file_pos > 0)
11194         {
11195             curr_nr += medium_stride_length;
11196             fseek(tng_data->input_file,
11197                   (long)file_pos,
11198                   SEEK_SET);
11199             /* Read block headers first to see what block is found. */
11200             stat = tng_block_header_read(tng_data, block);
11201             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11202             {
11203                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11204                        file_pos, __FILE__, __LINE__);
11205                 tng_block_destroy(&block);
11206                 return(TNG_CRITICAL);
11207             }
11208
11209             if(tng_block_read_next(tng_data, block,
11210                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11211             {
11212                 tng_block_destroy(&block);
11213                 return(TNG_CRITICAL);
11214             }
11215             if(curr_nr == nr)
11216             {
11217                 tng_block_destroy(&block);
11218                 return(TNG_SUCCESS);
11219             }
11220         }
11221     }
11222
11223     /* Take one step forward until the right frame set is found */
11224     while(file_pos > 0 && curr_nr < nr)
11225     {
11226         file_pos = frame_set->next_frame_set_file_pos;
11227
11228         if(file_pos > 0)
11229         {
11230             ++curr_nr;
11231             fseek(tng_data->input_file,
11232                   (long)file_pos,
11233                   SEEK_SET);
11234             /* Read block headers first to see what block is found. */
11235             stat = tng_block_header_read(tng_data, block);
11236             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11237             {
11238                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11239                        file_pos, __FILE__, __LINE__);
11240                 tng_block_destroy(&block);
11241                 return(TNG_CRITICAL);
11242             }
11243
11244             if(tng_block_read_next(tng_data, block,
11245                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11246             {
11247                 tng_block_destroy(&block);
11248                 return(TNG_CRITICAL);
11249             }
11250             if(curr_nr == nr)
11251             {
11252                 tng_block_destroy(&block);
11253                 return(TNG_SUCCESS);
11254             }
11255         }
11256     }
11257
11258     /* Take long steps backward until a long step backward would be too long
11259      * or the right frame set is found */
11260     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11261     {
11262         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11263         if(file_pos > 0)
11264         {
11265             curr_nr -= long_stride_length;
11266             fseek(tng_data->input_file,
11267                   (long)file_pos,
11268                   SEEK_SET);
11269             /* Read block headers first to see what block is found. */
11270             stat = tng_block_header_read(tng_data, block);
11271             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11272             {
11273                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11274                        file_pos, __FILE__, __LINE__);
11275                 tng_block_destroy(&block);
11276                 return(TNG_CRITICAL);
11277             }
11278
11279             if(tng_block_read_next(tng_data, block,
11280                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11281             {
11282                 tng_block_destroy(&block);
11283                 return(TNG_CRITICAL);
11284             }
11285             if(curr_nr == nr)
11286             {
11287                 tng_block_destroy(&block);
11288                 return(TNG_SUCCESS);
11289             }
11290         }
11291     }
11292
11293     /* Take medium steps backward until a medium step backward would be too long
11294      * or the right frame set is found */
11295     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11296     {
11297         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11298         if(file_pos > 0)
11299         {
11300             curr_nr -= medium_stride_length;
11301             fseek(tng_data->input_file,
11302                   (long)file_pos,
11303                   SEEK_SET);
11304             /* Read block headers first to see what block is found. */
11305             stat = tng_block_header_read(tng_data, block);
11306             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11307             {
11308                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11309                        file_pos, __FILE__, __LINE__);
11310                 tng_block_destroy(&block);
11311                 return(TNG_CRITICAL);
11312             }
11313
11314             if(tng_block_read_next(tng_data, block,
11315                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11316             {
11317                 tng_block_destroy(&block);
11318                 return(TNG_CRITICAL);
11319             }
11320             if(curr_nr == nr)
11321             {
11322                 tng_block_destroy(&block);
11323                 return(TNG_SUCCESS);
11324             }
11325         }
11326     }
11327
11328     /* Take one step backward until the right frame set is found */
11329     while(file_pos > 0 && curr_nr > nr)
11330     {
11331         file_pos = frame_set->prev_frame_set_file_pos;
11332         if(file_pos > 0)
11333         {
11334             --curr_nr;
11335             fseek(tng_data->input_file,
11336                   (long)file_pos,
11337                   SEEK_SET);
11338             /* Read block headers first to see what block is found. */
11339             stat = tng_block_header_read(tng_data, block);
11340             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11341             {
11342                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11343                        file_pos, __FILE__, __LINE__);
11344                 tng_block_destroy(&block);
11345                 return(TNG_CRITICAL);
11346             }
11347
11348             if(tng_block_read_next(tng_data, block,
11349                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11350             {
11351                 tng_block_destroy(&block);
11352                 return(TNG_CRITICAL);
11353             }
11354             if(curr_nr == nr)
11355             {
11356                 tng_block_destroy(&block);
11357                 return(TNG_SUCCESS);
11358             }
11359         }
11360     }
11361
11362     /* If for some reason the current frame set is not yet found,
11363      * take one step forward until the right frame set is found */
11364     while(file_pos > 0 && curr_nr < nr)
11365     {
11366         file_pos = frame_set->next_frame_set_file_pos;
11367         if(file_pos > 0)
11368         {
11369             ++curr_nr;
11370             fseek(tng_data->input_file,
11371                   (long)file_pos,
11372                   SEEK_SET);
11373             /* Read block headers first to see what block is found. */
11374             stat = tng_block_header_read(tng_data, block);
11375             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11376             {
11377                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11378                        file_pos, __FILE__, __LINE__);
11379                 tng_block_destroy(&block);
11380                 return(TNG_CRITICAL);
11381             }
11382
11383             if(tng_block_read_next(tng_data, block,
11384                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11385             {
11386                 tng_block_destroy(&block);
11387                 return(TNG_CRITICAL);
11388             }
11389             if(curr_nr == nr)
11390             {
11391                 tng_block_destroy(&block);
11392                 return(TNG_SUCCESS);
11393             }
11394         }
11395     }
11396
11397     tng_block_destroy(&block);
11398     return(TNG_FAILURE);
11399 }
11400
11401 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
11402                 (tng_trajectory_t tng_data,
11403                  const int64_t frame)
11404 {
11405     int64_t first_frame, last_frame, n_frames_per_frame_set;
11406     int64_t long_stride_length, medium_stride_length;
11407     int64_t file_pos, temp_frame, n_frames;
11408     tng_trajectory_frame_set_t frame_set;
11409     tng_gen_block_t block;
11410     tng_function_status stat;
11411
11412     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11413     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
11414
11415     frame_set = &tng_data->current_trajectory_frame_set;
11416
11417     tng_block_init(&block);
11418
11419     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
11420     {
11421         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11422         fseek(tng_data->input_file,
11423                 (long)file_pos,
11424                 SEEK_SET);
11425         tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
11426         /* Read block headers first to see what block is found. */
11427         stat = tng_block_header_read(tng_data, block);
11428         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11429         {
11430             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11431                     file_pos, __FILE__, __LINE__);
11432             tng_block_destroy(&block);
11433             return(TNG_CRITICAL);
11434         }
11435
11436         if(tng_block_read_next(tng_data, block,
11437                             TNG_SKIP_HASH) != TNG_SUCCESS)
11438         {
11439             tng_block_destroy(&block);
11440             return(TNG_CRITICAL);
11441         }
11442     }
11443
11444     first_frame = tng_max_i64(frame_set->first_frame, 0);
11445     last_frame = first_frame + frame_set->n_frames - 1;
11446     /* Is this the right frame set? */
11447     if(first_frame <= frame && frame <= last_frame)
11448     {
11449         tng_block_destroy(&block);
11450         return(TNG_SUCCESS);
11451     }
11452
11453     n_frames_per_frame_set = tng_data->frame_set_n_frames;
11454     long_stride_length = tng_data->long_stride_length;
11455     medium_stride_length = tng_data->medium_stride_length;
11456
11457     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
11458        TNG_SUCCESS)
11459     {
11460         if(temp_frame - first_frame > n_frames_per_frame_set)
11461         {
11462             n_frames_per_frame_set = temp_frame - first_frame;
11463         }
11464     }
11465
11466     tng_num_frames_get(tng_data, &n_frames);
11467
11468     if(frame >= n_frames)
11469     {
11470         tng_block_destroy(&block);
11471         return(TNG_FAILURE);
11472     }
11473
11474     if(first_frame - frame >= frame ||
11475        frame - last_frame >
11476        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
11477     {
11478         /* Start from the beginning */
11479         if(first_frame - frame >= frame)
11480         {
11481             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11482
11483             if(file_pos <= 0)
11484             {
11485                 tng_block_destroy(&block);
11486                 return(TNG_FAILURE);
11487             }
11488         }
11489         /* Start from the end */
11490         else if(frame - first_frame > (n_frames - 1) - frame)
11491         {
11492             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11493
11494             /* If the last frame set position is not set start from the current
11495              * frame set, since it will be closer than the first frame set. */
11496         }
11497         /* Start from current */
11498         else
11499         {
11500             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11501         }
11502
11503         if(file_pos > 0)
11504         {
11505             fseek(tng_data->input_file,
11506                   (long)file_pos,
11507                   SEEK_SET);
11508             tng_data->current_trajectory_frame_set_input_file_pos = (long)file_pos;
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     }
11527
11528     first_frame = tng_max_i64(frame_set->first_frame, 0);
11529     last_frame = first_frame + frame_set->n_frames - 1;
11530
11531     if(frame >= first_frame && frame <= last_frame)
11532     {
11533         tng_block_destroy(&block);
11534         return(TNG_SUCCESS);
11535     }
11536
11537     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11538
11539     /* Take long steps forward until a long step forward would be too long or
11540      * the right frame set is found */
11541     while(file_pos > 0 && first_frame + long_stride_length *
11542           n_frames_per_frame_set <= frame)
11543     {
11544         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11545         if(file_pos > 0)
11546         {
11547             fseek(tng_data->input_file, (long)file_pos, SEEK_SET);
11548             /* Read block headers first to see what block is found. */
11549             stat = tng_block_header_read(tng_data, block);
11550             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11551             {
11552                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11553                        file_pos, __FILE__, __LINE__);
11554                 tng_block_destroy(&block);
11555                 return(TNG_CRITICAL);
11556             }
11557
11558             if(tng_block_read_next(tng_data, block,
11559                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11560             {
11561                 tng_block_destroy(&block);
11562                 return(TNG_CRITICAL);
11563             }
11564         }
11565         first_frame = tng_max_i64(frame_set->first_frame, 0);
11566         last_frame = first_frame + frame_set->n_frames - 1;
11567         if(frame >= first_frame && frame <= last_frame)
11568         {
11569             tng_block_destroy(&block);
11570             return(TNG_SUCCESS);
11571         }
11572     }
11573
11574     /* Take medium steps forward until a medium step forward would be too long
11575      * or the right frame set is found */
11576     while(file_pos > 0 && first_frame + medium_stride_length *
11577           n_frames_per_frame_set <= frame)
11578     {
11579         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11580         if(file_pos > 0)
11581         {
11582             fseek(tng_data->input_file,
11583                   (long)file_pos,
11584                   SEEK_SET);
11585             /* Read block headers first to see what block is found. */
11586             stat = tng_block_header_read(tng_data, block);
11587             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11588             {
11589                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11590                        file_pos, __FILE__, __LINE__);
11591                 tng_block_destroy(&block);
11592                 return(TNG_CRITICAL);
11593             }
11594
11595             if(tng_block_read_next(tng_data, block,
11596                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11597             {
11598                 tng_block_destroy(&block);
11599                 return(TNG_CRITICAL);
11600             }
11601         }
11602         first_frame = tng_max_i64(frame_set->first_frame, 0);
11603         last_frame = first_frame + frame_set->n_frames - 1;
11604         if(frame >= first_frame && frame <= last_frame)
11605         {
11606             tng_block_destroy(&block);
11607             return(TNG_SUCCESS);
11608         }
11609     }
11610
11611     /* Take one step forward until the right frame set is found */
11612     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11613     {
11614         file_pos = frame_set->next_frame_set_file_pos;
11615         if(file_pos > 0)
11616         {
11617             fseek(tng_data->input_file,
11618                   (long)file_pos,
11619                   SEEK_SET);
11620             /* Read block headers first to see what block is found. */
11621             stat = tng_block_header_read(tng_data, block);
11622             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11623             {
11624                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11625                        file_pos, __FILE__, __LINE__);
11626                 tng_block_destroy(&block);
11627                 return(TNG_CRITICAL);
11628             }
11629
11630             if(tng_block_read_next(tng_data, block,
11631                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11632             {
11633                 tng_block_destroy(&block);
11634                 return(TNG_CRITICAL);
11635             }
11636         }
11637         first_frame = tng_max_i64(frame_set->first_frame, 0);
11638         last_frame = first_frame + frame_set->n_frames - 1;
11639         if(frame >= first_frame && frame <= last_frame)
11640         {
11641             tng_block_destroy(&block);
11642             return(TNG_SUCCESS);
11643         }
11644     }
11645
11646     /* Take long steps backward until a long step backward would be too long
11647      * or the right frame set is found */
11648     while(file_pos > 0 && first_frame - long_stride_length *
11649           n_frames_per_frame_set >= frame)
11650     {
11651         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11652         if(file_pos > 0)
11653         {
11654             fseek(tng_data->input_file,
11655                   (long)file_pos,
11656                   SEEK_SET);
11657             /* Read block headers first to see what block is found. */
11658             stat = tng_block_header_read(tng_data, block);
11659             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11660             {
11661                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11662                        file_pos, __FILE__, __LINE__);
11663                 tng_block_destroy(&block);
11664                 return(TNG_CRITICAL);
11665             }
11666
11667             if(tng_block_read_next(tng_data, block,
11668                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11669             {
11670                 tng_block_destroy(&block);
11671                 return(TNG_CRITICAL);
11672             }
11673         }
11674         first_frame = tng_max_i64(frame_set->first_frame, 0);
11675         last_frame = first_frame + frame_set->n_frames - 1;
11676         if(frame >= first_frame && frame <= last_frame)
11677         {
11678             tng_block_destroy(&block);
11679             return(TNG_SUCCESS);
11680         }
11681     }
11682
11683     /* Take medium steps backward until a medium step backward would be too long
11684      * or the right frame set is found */
11685     while(file_pos > 0 && first_frame - medium_stride_length *
11686           n_frames_per_frame_set >= frame)
11687     {
11688         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11689         if(file_pos > 0)
11690         {
11691             fseek(tng_data->input_file,
11692                   (long)file_pos,
11693                   SEEK_SET);
11694             /* Read block headers first to see what block is found. */
11695             stat = tng_block_header_read(tng_data, block);
11696             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11697             {
11698                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11699                        file_pos, __FILE__, __LINE__);
11700                 tng_block_destroy(&block);
11701                 return(TNG_CRITICAL);
11702             }
11703
11704             if(tng_block_read_next(tng_data, block,
11705                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11706             {
11707                 tng_block_destroy(&block);
11708                 return(TNG_CRITICAL);
11709             }
11710         }
11711         first_frame = tng_max_i64(frame_set->first_frame, 0);
11712         last_frame = first_frame + frame_set->n_frames - 1;
11713         if(frame >= first_frame && frame <= last_frame)
11714         {
11715             tng_block_destroy(&block);
11716             return(TNG_SUCCESS);
11717         }
11718     }
11719
11720     /* Take one step backward until the right frame set is found */
11721     while(file_pos > 0 && first_frame > frame && last_frame > frame)
11722     {
11723         file_pos = frame_set->prev_frame_set_file_pos;
11724         if(file_pos > 0)
11725         {
11726             fseek(tng_data->input_file,
11727                   (long)file_pos,
11728                   SEEK_SET);
11729             /* Read block headers first to see what block is found. */
11730             stat = tng_block_header_read(tng_data, block);
11731             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11732             {
11733                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11734                        file_pos, __FILE__, __LINE__);
11735                 tng_block_destroy(&block);
11736                 return(TNG_CRITICAL);
11737             }
11738
11739             if(tng_block_read_next(tng_data, block,
11740                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11741             {
11742                 tng_block_destroy(&block);
11743                 return(TNG_CRITICAL);
11744             }
11745         }
11746         first_frame = tng_max_i64(frame_set->first_frame, 0);
11747         last_frame = first_frame + frame_set->n_frames - 1;
11748         if(frame >= first_frame && frame <= last_frame)
11749         {
11750             tng_block_destroy(&block);
11751             return(TNG_SUCCESS);
11752         }
11753     }
11754
11755     /* If for some reason the current frame set is not yet found,
11756      * take one step forward until the right frame set is found */
11757     while(file_pos > 0 && first_frame < frame && last_frame < frame)
11758     {
11759         file_pos = frame_set->next_frame_set_file_pos;
11760         if(file_pos > 0)
11761         {
11762             fseek(tng_data->input_file,
11763                   (long)file_pos,
11764                   SEEK_SET);
11765             /* Read block headers first to see what block is found. */
11766             stat = tng_block_header_read(tng_data, block);
11767             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11768             {
11769                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11770                        file_pos, __FILE__, __LINE__);
11771                 tng_block_destroy(&block);
11772                 return(TNG_CRITICAL);
11773             }
11774
11775             if(tng_block_read_next(tng_data, block,
11776                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11777             {
11778                 tng_block_destroy(&block);
11779                 return(TNG_CRITICAL);
11780             }
11781         }
11782         first_frame = tng_max_i64(frame_set->first_frame, 0);
11783         last_frame = first_frame + frame_set->n_frames - 1;
11784         if(frame >= first_frame && frame <= last_frame)
11785         {
11786             tng_block_destroy(&block);
11787             return(TNG_SUCCESS);
11788         }
11789     }
11790
11791     tng_block_destroy(&block);
11792     return(TNG_FAILURE);
11793 }
11794
11795 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
11796                 (const tng_trajectory_t tng_data,
11797                  const tng_trajectory_frame_set_t frame_set,
11798                  int64_t *pos)
11799 {
11800     (void)tng_data;
11801
11802     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11803     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11804
11805     *pos = frame_set->next_frame_set_file_pos;
11806
11807     return(TNG_SUCCESS);
11808 }
11809
11810 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
11811                 (const tng_trajectory_t tng_data,
11812                  const tng_trajectory_frame_set_t frame_set,
11813                  int64_t *pos)
11814 {
11815     (void)tng_data;
11816
11817     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11818     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11819
11820     *pos = frame_set->prev_frame_set_file_pos;
11821
11822     return(TNG_SUCCESS);
11823 }
11824
11825 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
11826                 (const tng_trajectory_t tng_data,
11827                  const tng_trajectory_frame_set_t frame_set,
11828                  int64_t *first_frame,
11829                  int64_t *last_frame)
11830 {
11831     (void)tng_data;
11832
11833     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
11834     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
11835     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
11836
11837     *first_frame = frame_set->first_frame;
11838     *last_frame = *first_frame + frame_set->n_frames - 1;
11839
11840     return(TNG_SUCCESS);
11841 }
11842
11843 /** Translate from the particle numbering used in a frame set to the real
11844  *  particle numbering - used in the molecule description.
11845  * @param frame_set is the frame_set containing the mappings to use.
11846  * @param local is the index number of the atom in this frame set
11847  * @param real is set to the index of the atom in the molecular system.
11848  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11849  * cannot be found.
11850  */
11851 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
11852                 (const tng_trajectory_frame_set_t frame_set,
11853                  const int64_t local,
11854                  int64_t *real)
11855 {
11856     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
11857     tng_particle_mapping_t mapping;
11858     if(n_blocks <= 0)
11859     {
11860         *real = local;
11861         return(TNG_SUCCESS);
11862     }
11863     for(i = 0; i < n_blocks; i++)
11864     {
11865         mapping = &frame_set->mappings[i];
11866         first = mapping->num_first_particle;
11867         if(local < first ||
11868            local >= first + mapping->n_particles)
11869         {
11870             continue;
11871         }
11872         *real = mapping->real_particle_numbers[local-first];
11873         return(TNG_SUCCESS);
11874     }
11875     *real = local;
11876     return(TNG_FAILURE);
11877 }
11878
11879 /** Translate from the real particle numbering to the particle numbering
11880  *  used in a frame set.
11881  * @param frame_set is the frame_set containing the mappings to use.
11882  * @param real is the index number of the atom in the molecular system.
11883  * @param local is set to the index of the atom in this frame set.
11884  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11885  * cannot be found.
11886  */
11887 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
11888                 (const tng_trajectory_frame_set_t frame_set,
11889                  const int64_t real,
11890                  int64_t *local)
11891 {
11892     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
11893     tng_particle_mapping_t mapping;
11894     if(n_blocks <= 0)
11895     {
11896         *local = real;
11897         return(TNG_SUCCESS);
11898     }
11899     for(i = 0; i < n_blocks; i++)
11900     {
11901         mapping = &frame_set->mappings[i];
11902         for(j = mapping->n_particles; j--;)
11903         {
11904             if(mapping->real_particle_numbers[j] == real)
11905             {
11906                 *local = j;
11907                 return(TNG_SUCCESS);
11908             }
11909         }
11910     }
11911     return(TNG_FAILURE);
11912 }
11913 */
11914
11915 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
11916                 (tng_trajectory_t tng_data,
11917                  const char hash_mode)
11918 {
11919     int cnt = 0, prev_pos = 0;
11920     tng_gen_block_t block;
11921
11922     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11923
11924     tng_data->n_trajectory_frame_sets = 0;
11925
11926     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11927     {
11928         return(TNG_CRITICAL);
11929     }
11930
11931     if(!tng_data->input_file_len)
11932     {
11933         fseek(tng_data->input_file, 0, SEEK_END);
11934         tng_data->input_file_len = ftell(tng_data->input_file);
11935         fseek(tng_data->input_file, 0, SEEK_SET);
11936     }
11937
11938     tng_block_init(&block);
11939     /* Non trajectory blocks (they come before the trajectory
11940      * blocks in the file) */
11941     while (prev_pos < tng_data->input_file_len &&
11942            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11943            block->id != -1 &&
11944            block->id != TNG_TRAJECTORY_FRAME_SET)
11945     {
11946         if(tng_block_read_next(tng_data, block,
11947                                hash_mode) == TNG_SUCCESS)
11948         {
11949             cnt++;
11950         }
11951         prev_pos = ftell(tng_data->input_file);
11952     }
11953
11954     /* Go back if a trajectory block was encountered */
11955     if(block->id == TNG_TRAJECTORY_FRAME_SET)
11956     {
11957         fseek(tng_data->input_file, prev_pos, SEEK_SET);
11958     }
11959
11960     tng_block_destroy(&block);
11961
11962     return(TNG_SUCCESS);
11963 }
11964
11965 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
11966                 (tng_trajectory_t tng_data,
11967                  const char hash_mode)
11968 {
11969     int i;
11970     tng_gen_block_t data_block;
11971
11972     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11973
11974     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
11975     {
11976         return(TNG_CRITICAL);
11977     }
11978
11979     /* TODO: If there is already frame set data written to this file (e.g. when
11980      * appending to an already existing file we might need to move frame sets to
11981      * the end of the file. */
11982
11983     if(tng_general_info_block_write(tng_data, hash_mode)
11984        != TNG_SUCCESS)
11985     {
11986         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
11987                 tng_data->input_file_path, __FILE__, __LINE__);
11988         return(TNG_CRITICAL);
11989     }
11990
11991     if(tng_molecules_block_write(tng_data, hash_mode)
11992         != TNG_SUCCESS)
11993     {
11994         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
11995                 tng_data->input_file_path, __FILE__, __LINE__);
11996         return(TNG_CRITICAL);
11997     }
11998
11999     /* FIXME: Currently writing non-trajectory data blocks here.
12000      * Should perhaps be moved. */
12001     tng_block_init(&data_block);
12002     for(i = 0; i < tng_data->n_data_blocks; i++)
12003     {
12004         data_block->id = tng_data->non_tr_data[i].block_id;
12005         tng_data_block_write(tng_data, data_block,
12006                              i, hash_mode);
12007     }
12008
12009     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12010     {
12011         data_block->id = tng_data->non_tr_particle_data[i].block_id;
12012         tng_particle_data_block_write(tng_data, data_block,
12013                                       i, 0, hash_mode);
12014     }
12015
12016     tng_block_destroy(&data_block);
12017
12018     return(TNG_SUCCESS);
12019 }
12020
12021 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
12022                                         tng_gen_block_t block,
12023                                         const char hash_mode)
12024 {
12025     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12026     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
12027
12028     switch(block->id)
12029     {
12030     case TNG_TRAJECTORY_FRAME_SET:
12031         return(tng_frame_set_block_read(tng_data, block, hash_mode));
12032     case TNG_PARTICLE_MAPPING:
12033         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
12034     case TNG_GENERAL_INFO:
12035         return(tng_general_info_block_read(tng_data, block, hash_mode));
12036     case TNG_MOLECULES:
12037         return(tng_molecules_block_read(tng_data, block, hash_mode));
12038     default:
12039         if(block->id >= TNG_TRAJ_BOX_SHAPE)
12040         {
12041             return(tng_data_block_contents_read(tng_data, block, hash_mode));
12042         }
12043         else
12044         {
12045             /* Skip to the next block */
12046             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12047             return(TNG_FAILURE);
12048         }
12049     }
12050 }
12051
12052 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
12053                 (tng_trajectory_t tng_data,
12054                  const char hash_mode)
12055 {
12056     long file_pos;
12057     tng_gen_block_t block;
12058     tng_function_status stat;
12059
12060     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12061
12062     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12063     {
12064         return(TNG_CRITICAL);
12065     }
12066
12067     file_pos = ftell(tng_data->input_file);
12068
12069     tng_block_init(&block);
12070
12071     if(!tng_data->input_file_len)
12072     {
12073         fseek(tng_data->input_file, 0, SEEK_END);
12074         tng_data->input_file_len = ftell(tng_data->input_file);
12075         fseek(tng_data->input_file, file_pos, SEEK_SET);
12076     }
12077
12078     /* Read block headers first to see what block is found. */
12079     stat = tng_block_header_read(tng_data, block);
12080     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12081     {
12082         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12083                file_pos, __FILE__, __LINE__);
12084         tng_block_destroy(&block);
12085         return(TNG_CRITICAL);
12086     }
12087
12088     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12089
12090     if(tng_block_read_next(tng_data, block,
12091                            hash_mode) == TNG_SUCCESS)
12092     {
12093         tng_data->n_trajectory_frame_sets++;
12094         file_pos = ftell(tng_data->input_file);
12095         /* Read all blocks until next frame set block */
12096         stat = tng_block_header_read(tng_data, block);
12097         while(file_pos < tng_data->input_file_len &&
12098               stat != TNG_CRITICAL &&
12099               block->id != TNG_TRAJECTORY_FRAME_SET)
12100         {
12101             stat = tng_block_read_next(tng_data, block,
12102                                        hash_mode);
12103             if(stat != TNG_CRITICAL)
12104             {
12105                 file_pos = ftell(tng_data->input_file);
12106                 if(file_pos < tng_data->input_file_len)
12107                 {
12108                     stat = tng_block_header_read(tng_data, block);
12109                 }
12110             }
12111         }
12112         if(stat == TNG_CRITICAL)
12113         {
12114             fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12115                    file_pos, __FILE__, __LINE__);
12116             tng_block_destroy(&block);
12117             return(stat);
12118         }
12119
12120         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12121         {
12122             fseek(tng_data->input_file, file_pos, SEEK_SET);
12123         }
12124     }
12125
12126     tng_block_destroy(&block);
12127
12128     return(TNG_SUCCESS);
12129 }
12130
12131
12132 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12133                 (tng_trajectory_t tng_data,
12134                  const char hash_mode,
12135                  const int64_t block_id)
12136 {
12137     long file_pos;
12138     tng_gen_block_t block;
12139     tng_function_status stat;
12140     int found_flag = 1;
12141
12142     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12143
12144     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12145     {
12146         return(TNG_CRITICAL);
12147     }
12148
12149     file_pos = (long)tng_data->current_trajectory_frame_set_input_file_pos;
12150
12151     if(file_pos < 0)
12152     {
12153         /* No current frame set. This means that the first frame set must be
12154          * read */
12155         found_flag = 0;
12156         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12157     }
12158
12159     if(file_pos > 0)
12160     {
12161         fseek(tng_data->input_file,
12162               file_pos,
12163               SEEK_SET);
12164     }
12165     else
12166     {
12167         return(TNG_FAILURE);
12168     }
12169
12170     tng_block_init(&block);
12171
12172     if(!tng_data->input_file_len)
12173     {
12174         fseek(tng_data->input_file, 0, SEEK_END);
12175         tng_data->input_file_len = ftell(tng_data->input_file);
12176         fseek(tng_data->input_file, file_pos, SEEK_SET);
12177     }
12178
12179     /* Read block headers first to see what block is found. */
12180     stat = tng_block_header_read(tng_data, block);
12181     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12182     {
12183         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12184                file_pos, __FILE__, __LINE__);
12185         tng_block_destroy(&block);
12186         return(TNG_CRITICAL);
12187     }
12188     /* If the current frame set had already been read skip its block contents */
12189     if(found_flag)
12190     {
12191         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12192     }
12193     /* Otherwiese read the frame set block */
12194     else
12195     {
12196         stat = tng_block_read_next(tng_data, block,
12197                                    hash_mode);
12198         if(stat != TNG_SUCCESS)
12199         {
12200             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12201             tng_block_destroy(&block);
12202             return(stat);
12203         }
12204     }
12205     file_pos = ftell(tng_data->input_file);
12206
12207     found_flag = 0;
12208
12209     /* Read only blocks of the requested ID
12210         * until next frame set block */
12211     stat = tng_block_header_read(tng_data, block);
12212     while(file_pos < tng_data->input_file_len &&
12213             stat != TNG_CRITICAL &&
12214             block->id != TNG_TRAJECTORY_FRAME_SET)
12215     {
12216         if(block->id == block_id)
12217         {
12218             stat = tng_block_read_next(tng_data, block,
12219                                        hash_mode);
12220             if(stat != TNG_CRITICAL)
12221             {
12222                 file_pos = ftell(tng_data->input_file);
12223                 found_flag = 1;
12224                 if(file_pos < tng_data->input_file_len)
12225                 {
12226                     stat = tng_block_header_read(tng_data, block);
12227                 }
12228             }
12229         }
12230         else
12231         {
12232             file_pos += (long)(block->block_contents_size + block->header_contents_size);
12233             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
12234             if(file_pos < tng_data->input_file_len)
12235             {
12236                 stat = tng_block_header_read(tng_data, block);
12237             }
12238         }
12239     }
12240     if(stat == TNG_CRITICAL)
12241     {
12242         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12243                 file_pos, __FILE__, __LINE__);
12244         tng_block_destroy(&block);
12245         return(stat);
12246     }
12247
12248     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12249     {
12250         fseek(tng_data->input_file, file_pos, SEEK_SET);
12251     }
12252
12253     tng_block_destroy(&block);
12254
12255     if(found_flag)
12256     {
12257         return(TNG_SUCCESS);
12258     }
12259     else
12260     {
12261         return(TNG_FAILURE);
12262     }
12263 }
12264
12265 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
12266                 (tng_trajectory_t tng_data,
12267                  const char hash_mode)
12268 {
12269     long file_pos;
12270
12271     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12272
12273     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12274     {
12275         return(TNG_CRITICAL);
12276     }
12277
12278     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12279
12280     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12281     {
12282         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12283     }
12284
12285     if(file_pos > 0)
12286     {
12287         fseek(tng_data->input_file,
12288               file_pos,
12289               SEEK_SET);
12290     }
12291     else
12292     {
12293         return(TNG_FAILURE);
12294     }
12295
12296     return(tng_frame_set_read(tng_data, hash_mode));
12297 }
12298
12299 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
12300                 (tng_trajectory_t tng_data,
12301                  const char hash_mode,
12302                  const int64_t block_id)
12303 {
12304     long file_pos;
12305     tng_gen_block_t block;
12306     tng_function_status stat;
12307
12308     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12309
12310     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12311     {
12312         return(TNG_CRITICAL);
12313     }
12314
12315     file_pos = (long)tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12316
12317     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12318     {
12319         file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12320     }
12321
12322     if(file_pos > 0)
12323     {
12324         fseek(tng_data->input_file,
12325               file_pos,
12326               SEEK_SET);
12327     }
12328     else
12329     {
12330         return(TNG_FAILURE);
12331     }
12332
12333     tng_block_init(&block);
12334
12335     if(!tng_data->input_file_len)
12336     {
12337         fseek(tng_data->input_file, 0, SEEK_END);
12338         tng_data->input_file_len = ftell(tng_data->input_file);
12339         fseek(tng_data->input_file, file_pos, SEEK_SET);
12340     }
12341
12342     /* Read block headers first to see what block is found. */
12343     stat = tng_block_header_read(tng_data, block);
12344     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12345     {
12346         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12347                file_pos, __FILE__, __LINE__);
12348         tng_block_destroy(&block);
12349         return(TNG_CRITICAL);
12350     }
12351
12352     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12353
12354     if(tng_block_read_next(tng_data, block,
12355                            hash_mode) == TNG_SUCCESS)
12356     {
12357         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
12358     }
12359
12360     tng_block_destroy(&block);
12361
12362     return(stat);
12363 }
12364
12365 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
12366                                         const char hash_mode)
12367 {
12368     int i, j;
12369     tng_gen_block_t block;
12370     tng_trajectory_frame_set_t frame_set;
12371     tng_function_status stat;
12372
12373     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12374
12375     frame_set = &tng_data->current_trajectory_frame_set;
12376
12377     if(frame_set->n_written_frames == frame_set->n_frames)
12378     {
12379         return(TNG_SUCCESS);
12380     }
12381
12382     tng_data->current_trajectory_frame_set_output_file_pos =
12383     ftell(tng_data->output_file);
12384     tng_data->last_trajectory_frame_set_output_file_pos =
12385     tng_data->current_trajectory_frame_set_output_file_pos;
12386
12387     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
12388     {
12389         return(TNG_FAILURE);
12390     }
12391
12392     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
12393     {
12394         tng_data->first_trajectory_frame_set_output_file_pos =
12395         tng_data->current_trajectory_frame_set_output_file_pos;
12396     }
12397
12398     tng_block_init(&block);
12399
12400     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
12401     {
12402         tng_block_destroy(&block);
12403         return(TNG_FAILURE);
12404     }
12405
12406     /* Write non-particle data blocks */
12407     for(i = 0; i<frame_set->n_data_blocks; i++)
12408     {
12409         block->id = frame_set->tr_data[i].block_id;
12410         tng_data_block_write(tng_data, block, i, hash_mode);
12411     }
12412     /* Write the mapping blocks and particle data blocks*/
12413     if(frame_set->n_mapping_blocks)
12414     {
12415         for(i = 0; i < frame_set->n_mapping_blocks; i++)
12416         {
12417             block->id = TNG_PARTICLE_MAPPING;
12418             if(frame_set->mappings[i].n_particles > 0)
12419             {
12420                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
12421                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
12422                 {
12423                     block->id = frame_set->tr_particle_data[j].block_id;
12424                     tng_particle_data_block_write(tng_data, block,
12425                                                   j, &frame_set->mappings[i],
12426                                                   hash_mode);
12427                 }
12428             }
12429         }
12430     }
12431     else
12432     {
12433         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
12434         {
12435             block->id = frame_set->tr_particle_data[i].block_id;
12436             tng_particle_data_block_write(tng_data, block,
12437                                           i, 0, hash_mode);
12438         }
12439     }
12440
12441
12442     /* Update pointers in the general info block */
12443     stat = tng_header_pointers_update(tng_data, hash_mode);
12444
12445     if(stat == TNG_SUCCESS)
12446     {
12447         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
12448     }
12449
12450     tng_block_destroy(&block);
12451
12452     frame_set->n_unwritten_frames = 0;
12453
12454     fflush(tng_data->output_file);
12455
12456     return(stat);
12457 }
12458
12459 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
12460                 (tng_trajectory_t tng_data,
12461                  const char hash_mode)
12462 {
12463     tng_trajectory_frame_set_t frame_set;
12464
12465     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12466
12467     frame_set = &tng_data->current_trajectory_frame_set;
12468
12469     if(frame_set->n_unwritten_frames == 0)
12470     {
12471         return(TNG_SUCCESS);
12472     }
12473     frame_set->n_frames = frame_set->n_unwritten_frames;
12474
12475     return(tng_frame_set_write(tng_data, hash_mode));
12476 }
12477
12478 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
12479                 (tng_trajectory_t tng_data,
12480                  const int64_t first_frame,
12481                  const int64_t n_frames)
12482 {
12483     tng_gen_block_t block;
12484     tng_trajectory_frame_set_t frame_set;
12485     FILE *temp = tng_data->input_file;
12486     int64_t curr_pos;
12487
12488     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12489     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12490     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12491
12492     frame_set = &tng_data->current_trajectory_frame_set;
12493
12494     curr_pos = ftell(tng_data->output_file);
12495
12496     if(curr_pos <= 10)
12497     {
12498         tng_file_headers_write(tng_data, TNG_USE_HASH);
12499     }
12500
12501     /* Set pointer to previous frame set to the one that was loaded
12502      * before.
12503      * FIXME: This is a bit risky. If they are not added in order
12504      * it will be wrong. */
12505     if(tng_data->n_trajectory_frame_sets)
12506     {
12507         frame_set->prev_frame_set_file_pos =
12508         tng_data->current_trajectory_frame_set_output_file_pos;
12509     }
12510
12511     tng_data->current_trajectory_frame_set_output_file_pos =
12512     ftell(tng_data->output_file);
12513
12514     tng_data->n_trajectory_frame_sets++;
12515
12516     /* Set the medium range pointers */
12517     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
12518     {
12519         frame_set->medium_stride_prev_frame_set_file_pos =
12520         tng_data->first_trajectory_frame_set_output_file_pos;
12521     }
12522     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12523     {
12524         /* FIXME: Currently only working if the previous frame set has its
12525          * medium stride pointer already set. This might need some fixing. */
12526         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
12527            frame_set->medium_stride_prev_frame_set_file_pos != 0)
12528         {
12529             tng_block_init(&block);
12530             tng_data->input_file = tng_data->output_file;
12531
12532             curr_pos = ftell(tng_data->output_file);
12533             fseek(tng_data->output_file,
12534                   (long)frame_set->medium_stride_prev_frame_set_file_pos,
12535                   SEEK_SET);
12536
12537             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12538             {
12539                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12540                     __FILE__, __LINE__);
12541                 tng_data->input_file = temp;
12542                 tng_block_destroy(&block);
12543                 return(TNG_CRITICAL);
12544             }
12545
12546             /* Read the next frame set from the previous frame set and one
12547              * medium stride step back */
12548             fseek(tng_data->output_file, (long)block->block_contents_size - 6 *
12549                 sizeof(int64_t), SEEK_CUR);
12550             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
12551                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
12552                1, tng_data->output_file) == 0)
12553             {
12554                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12555                 tng_data->input_file = temp;
12556                 tng_block_destroy(&block);
12557                 return(TNG_CRITICAL);
12558             }
12559
12560             if(tng_data->input_endianness_swap_func_64)
12561             {
12562                 if(tng_data->input_endianness_swap_func_64(tng_data,
12563                    &frame_set->medium_stride_prev_frame_set_file_pos)
12564                     != TNG_SUCCESS)
12565                 {
12566                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12567                             __FILE__, __LINE__);
12568                 }
12569             }
12570
12571             tng_block_destroy(&block);
12572
12573             /* Set the long range pointers */
12574             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
12575             {
12576                 frame_set->long_stride_prev_frame_set_file_pos =
12577                 tng_data->first_trajectory_frame_set_output_file_pos;
12578             }
12579             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12580             {
12581                 /* FIXME: Currently only working if the previous frame set has its
12582                 * long stride pointer already set. This might need some fixing. */
12583                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
12584                 frame_set->long_stride_prev_frame_set_file_pos != 0)
12585                 {
12586                     tng_block_init(&block);
12587                     tng_data->input_file = tng_data->output_file;
12588
12589                     fseek(tng_data->output_file,
12590                           (long)frame_set->long_stride_prev_frame_set_file_pos,
12591                           SEEK_SET);
12592
12593                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12594                     {
12595                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12596                             __FILE__, __LINE__);
12597                         tng_data->input_file = temp;
12598                         tng_block_destroy(&block);
12599                         return(TNG_CRITICAL);
12600                     }
12601
12602                     /* Read the next frame set from the previous frame set and one
12603                     * long stride step back */
12604                     fseek(tng_data->output_file, (long)block->block_contents_size - 6 *
12605                           sizeof(int64_t), SEEK_CUR);
12606
12607                     tng_block_destroy(&block);
12608
12609                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
12610                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
12611                     1, tng_data->output_file) == 0)
12612                     {
12613                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12614                         tng_data->input_file = temp;
12615                         return(TNG_CRITICAL);
12616                     }
12617
12618                     if(tng_data->input_endianness_swap_func_64)
12619                     {
12620                         if(tng_data->input_endianness_swap_func_64(tng_data,
12621                            &frame_set->long_stride_prev_frame_set_file_pos)
12622                             != TNG_SUCCESS)
12623                         {
12624                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12625                                     __FILE__, __LINE__);
12626                         }
12627                     }
12628
12629                 }
12630             }
12631
12632             tng_data->input_file = temp;
12633             fseek(tng_data->output_file, (long)curr_pos, SEEK_SET);
12634         }
12635     }
12636
12637     frame_set->first_frame = first_frame;
12638     frame_set->n_frames = n_frames;
12639     frame_set->n_written_frames = 0;
12640     frame_set->n_unwritten_frames = 0;
12641     frame_set->first_frame_time = -1;
12642
12643     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
12644        tng_data->first_trajectory_frame_set_output_file_pos == 0)
12645     {
12646         tng_data->first_trajectory_frame_set_output_file_pos =
12647         tng_data->current_trajectory_frame_set_output_file_pos;
12648     }
12649     /* FIXME: Should check the frame number instead of the file_pos,
12650      * in case frame sets are not in order */
12651     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
12652        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
12653        tng_data->last_trajectory_frame_set_output_file_pos <
12654        tng_data->current_trajectory_frame_set_output_file_pos)
12655     {
12656         tng_data->last_trajectory_frame_set_output_file_pos =
12657         tng_data->current_trajectory_frame_set_output_file_pos;
12658     }
12659
12660     return(TNG_SUCCESS);
12661 }
12662
12663 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
12664                 (tng_trajectory_t tng_data,
12665                  const int64_t first_frame,
12666                  const int64_t n_frames,
12667                  const double first_frame_time)
12668 {
12669     tng_function_status stat;
12670
12671     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12672     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12673     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12674     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12675
12676
12677     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
12678     if(stat != TNG_SUCCESS)
12679     {
12680         return(stat);
12681     }
12682     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
12683
12684     return(stat);
12685 }
12686
12687 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
12688                 (tng_trajectory_t tng_data,
12689                  const double first_frame_time)
12690 {
12691     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12692     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12693
12694     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
12695
12696     return(TNG_SUCCESS);
12697 }
12698
12699 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
12700                 (const tng_trajectory_t tng_data,
12701                  int64_t *frame)
12702 {
12703     long file_pos, next_frame_set_file_pos;
12704     tng_gen_block_t block;
12705     tng_function_status stat;
12706
12707     tng_trajectory_frame_set_t frame_set;
12708
12709     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12710     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
12711     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
12712
12713     file_pos = ftell(tng_data->input_file);
12714
12715     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12716     {
12717         next_frame_set_file_pos = (long)tng_data->first_trajectory_frame_set_input_file_pos;
12718     }
12719     else
12720     {
12721         frame_set = &tng_data->current_trajectory_frame_set;
12722         next_frame_set_file_pos = (long)frame_set->next_frame_set_file_pos;
12723     }
12724
12725     if(next_frame_set_file_pos <= 0)
12726     {
12727         return(TNG_FAILURE);
12728     }
12729
12730     fseek(tng_data->input_file, (long)next_frame_set_file_pos, SEEK_SET);
12731     /* Read block headers first to see that a frame set block is found. */
12732     tng_block_init(&block);
12733     stat = tng_block_header_read(tng_data, block);
12734     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12735     {
12736         fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
12737                file_pos, __FILE__, __LINE__);
12738         return(TNG_CRITICAL);
12739     }
12740 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12741     {
12742         tng_block_read_next(tng_data, block, TNG_USE_HASH);
12743     }*/
12744     tng_block_destroy(&block);
12745
12746     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
12747     {
12748         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
12749                __FILE__, __LINE__);
12750         return(TNG_CRITICAL);
12751     }
12752     fseek(tng_data->input_file, file_pos, SEEK_SET);
12753
12754     return(TNG_SUCCESS);
12755 }
12756
12757 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
12758                 (tng_trajectory_t tng_data,
12759                  const int64_t id,
12760                  const char *block_name,
12761                  const char datatype,
12762                  const char block_type_flag,
12763                  int64_t n_frames,
12764                  const int64_t n_values_per_frame,
12765                  int64_t stride_length,
12766                  const int64_t codec_id,
12767                  void *new_data)
12768 {
12769     int i, j, size, len;
12770     tng_trajectory_frame_set_t frame_set;
12771     tng_non_particle_data_t data;
12772     char **first_dim_values;
12773     char *new_data_c=new_data;
12774     int64_t n_frames_div;
12775
12776     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12777     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
12778     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12779
12780     frame_set = &tng_data->current_trajectory_frame_set;
12781
12782     if(stride_length <= 0)
12783     {
12784         stride_length = 1;
12785     }
12786
12787     /* If the block does not exist, create it */
12788     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
12789     {
12790         if(tng_data_block_create(tng_data, block_type_flag) !=
12791             TNG_SUCCESS)
12792         {
12793             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
12794                    __FILE__, __LINE__);
12795             return(TNG_CRITICAL);
12796         }
12797         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12798         {
12799             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
12800         }
12801         else
12802         {
12803             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
12804         }
12805         data->block_id = id;
12806
12807         data->block_name = malloc(strlen(block_name) + 1);
12808         if(!data->block_name)
12809         {
12810             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12811                    (int)strlen(block_name)+1, __FILE__, __LINE__);
12812             return(TNG_CRITICAL);
12813         }
12814         strncpy(data->block_name, block_name, strlen(block_name) + 1);
12815
12816         data->values = 0;
12817         /* FIXME: Memory leak from strings. */
12818         data->strings = 0;
12819         data->last_retrieved_frame = -1;
12820     }
12821
12822     data->datatype = datatype;
12823     data->stride_length = tng_max_i64(stride_length, 1);
12824     data->n_values_per_frame = n_values_per_frame;
12825     data->n_frames = n_frames;
12826     data->codec_id = codec_id;
12827     data->compression_multiplier = 1.0;
12828     /* FIXME: This can cause problems. */
12829     data->first_frame_with_data = frame_set->first_frame;
12830
12831     switch(datatype)
12832     {
12833     case TNG_FLOAT_DATA:
12834         size = sizeof(float);
12835         break;
12836     case TNG_INT_DATA:
12837         size = sizeof(int64_t);
12838         break;
12839     case TNG_DOUBLE_DATA:
12840     default:
12841         size = sizeof(double);
12842         break;
12843     }
12844
12845     if(new_data_c)
12846     {
12847         /* Allocate memory */
12848         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
12849                                  n_values_per_frame) !=
12850         TNG_SUCCESS)
12851         {
12852             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
12853                 __FILE__, __LINE__);
12854             return(TNG_CRITICAL);
12855         }
12856
12857         if(n_frames > frame_set->n_unwritten_frames)
12858         {
12859             frame_set->n_unwritten_frames = n_frames;
12860         }
12861
12862         n_frames_div = (n_frames % stride_length) ?
12863                      n_frames / stride_length + 1:
12864                      n_frames / stride_length;
12865
12866         if(datatype == TNG_CHAR_DATA)
12867         {
12868             for(i = 0; i < n_frames_div; i++)
12869             {
12870                 first_dim_values = data->strings[i];
12871                 for(j = 0; j < n_values_per_frame; j++)
12872                 {
12873                     len = tng_min_i((int)strlen(new_data_c) + 1,
12874                                 TNG_MAX_STR_LEN);
12875                     if(first_dim_values[j])
12876                     {
12877                         free(first_dim_values[j]);
12878                     }
12879                     first_dim_values[j] = malloc(len);
12880                     if(!first_dim_values[j])
12881                     {
12882                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12883                             len, __FILE__, __LINE__);
12884                         return(TNG_CRITICAL);
12885                     }
12886                     strncpy(first_dim_values[j],
12887                             new_data_c, len);
12888                     new_data_c += len;
12889                 }
12890             }
12891         }
12892         else
12893         {
12894             memcpy(data->values, new_data, size * n_frames_div *
12895                    n_values_per_frame);
12896         }
12897     }
12898
12899     return(TNG_SUCCESS);
12900 }
12901
12902 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
12903                 (tng_trajectory_t tng_data,
12904                  const int64_t id,
12905                  const char *block_name,
12906                  const char datatype,
12907                  const char block_type_flag,
12908                  int64_t n_frames,
12909                  const int64_t n_values_per_frame,
12910                  int64_t stride_length,
12911                  const int64_t num_first_particle,
12912                  const int64_t n_particles,
12913                  const int64_t codec_id,
12914                  void *new_data)
12915 {
12916     int i, size, len;
12917     int64_t j, k;
12918     int64_t tot_n_particles, n_frames_div;
12919     char ***first_dim_values, **second_dim_values;
12920     tng_trajectory_frame_set_t frame_set;
12921     tng_particle_data_t data;
12922     char *new_data_c=new_data;
12923
12924     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12925     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
12926     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12927     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
12928     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
12929
12930
12931     frame_set = &tng_data->current_trajectory_frame_set;
12932
12933     if(stride_length <= 0)
12934     {
12935         stride_length = 1;
12936     }
12937
12938     /* If the block does not exist, create it */
12939     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
12940     {
12941         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
12942             TNG_SUCCESS)
12943         {
12944             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
12945                    __FILE__, __LINE__);
12946             return(TNG_CRITICAL);
12947         }
12948         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12949         {
12950             data = &frame_set->tr_particle_data[frame_set->
12951                                                 n_particle_data_blocks - 1];
12952         }
12953         else
12954         {
12955             data = &tng_data->non_tr_particle_data[tng_data->
12956                                                    n_particle_data_blocks - 1];
12957         }
12958         data->block_id = id;
12959
12960         data->block_name = malloc(strlen(block_name) + 1);
12961         if(!data->block_name)
12962         {
12963             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12964                    (int)strlen(block_name)+1, __FILE__, __LINE__);
12965             return(TNG_CRITICAL);
12966         }
12967         strncpy(data->block_name, block_name, strlen(block_name) + 1);
12968
12969         data->datatype = datatype;
12970
12971         data->values = 0;
12972         /* FIXME: Memory leak from strings. */
12973         data->strings = 0;
12974         data->last_retrieved_frame = -1;
12975     }
12976
12977     data->stride_length = tng_max_i64(stride_length, 1);
12978     data->n_values_per_frame = n_values_per_frame;
12979     data->n_frames = n_frames;
12980     data->codec_id = codec_id;
12981     data->compression_multiplier = 1.0;
12982     /* FIXME: This can cause problems. */
12983     data->first_frame_with_data = frame_set->first_frame;
12984
12985     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
12986     {
12987         tot_n_particles = frame_set->n_particles;
12988     }
12989     else
12990     {
12991         tot_n_particles = tng_data->n_particles;
12992     }
12993
12994     /* If data values are supplied add that data to the data block. */
12995     if(new_data_c)
12996     {
12997         /* Allocate memory */
12998         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
12999                                           stride_length, tot_n_particles,
13000                                           n_values_per_frame) !=
13001         TNG_SUCCESS)
13002         {
13003             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
13004                 __FILE__, __LINE__);
13005             return(TNG_CRITICAL);
13006         }
13007
13008         if(n_frames > frame_set->n_unwritten_frames)
13009         {
13010             frame_set->n_unwritten_frames = n_frames;
13011         }
13012
13013         n_frames_div = (n_frames % stride_length) ?
13014                      n_frames / stride_length + 1:
13015                      n_frames / stride_length;
13016
13017         if(datatype == TNG_CHAR_DATA)
13018         {
13019             for(i = 0; i < n_frames_div; i++)
13020             {
13021                 first_dim_values = data->strings[i];
13022                 for(j = num_first_particle; j < num_first_particle + n_particles;
13023                     j++)
13024                 {
13025                     second_dim_values = first_dim_values[j];
13026                     for(k = 0; k < n_values_per_frame; k++)
13027                     {
13028                         len = tng_min_i((int)strlen(new_data_c) + 1,
13029                                 TNG_MAX_STR_LEN);
13030                         if(second_dim_values[k])
13031                         {
13032                             free(second_dim_values[k]);
13033                         }
13034                         second_dim_values[k] = malloc(len);
13035                         if(!second_dim_values[k])
13036                         {
13037                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13038                                 len, __FILE__, __LINE__);
13039                             return(TNG_CRITICAL);
13040                         }
13041                         strncpy(second_dim_values[k],
13042                                 new_data_c, len);
13043                         new_data_c += len;
13044                     }
13045                 }
13046             }
13047         }
13048         else
13049         {
13050             switch(datatype)
13051             {
13052             case TNG_INT_DATA:
13053                 size = sizeof(int64_t);
13054                 break;
13055             case TNG_FLOAT_DATA:
13056                 size = sizeof(float);
13057                 break;
13058             case TNG_DOUBLE_DATA:
13059             default:
13060                 size = sizeof(double);
13061             }
13062
13063             memcpy(data->values, new_data, size * n_frames_div *
13064                    n_particles * n_values_per_frame);
13065         }
13066     }
13067
13068     return(TNG_SUCCESS);
13069 }
13070
13071 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
13072                 (tng_trajectory_t tng_data,
13073                  int64_t block_id,
13074                  char *name,
13075                  int max_len)
13076 {
13077     int64_t i;
13078     tng_trajectory_frame_set_t frame_set;
13079     tng_function_status stat;
13080     tng_particle_data_t p_data;
13081     tng_non_particle_data_t np_data;
13082     int block_type = -1;
13083
13084     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13085     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13086
13087     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13088     {
13089         p_data = &tng_data->non_tr_particle_data[i];
13090         if(p_data->block_id == block_id)
13091         {
13092             strncpy(name, p_data->block_name, max_len);
13093             name[max_len - 1] = '\0';
13094             return(TNG_SUCCESS);
13095         }
13096     }
13097     for(i = 0; i < tng_data->n_data_blocks; i++)
13098     {
13099         np_data = &tng_data->non_tr_data[i];
13100         if(np_data->block_id == block_id)
13101         {
13102             strncpy(name, np_data->block_name, max_len);
13103             name[max_len - 1] = '\0';
13104             return(TNG_SUCCESS);
13105         }
13106     }
13107
13108     frame_set = &tng_data->current_trajectory_frame_set;
13109
13110     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13111     if(stat == TNG_SUCCESS)
13112     {
13113         block_type = TNG_PARTICLE_BLOCK_DATA;
13114     }
13115     else
13116     {
13117         stat = tng_data_find(tng_data, block_id, &np_data);
13118         if(stat == TNG_SUCCESS)
13119         {
13120             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13121         }
13122         else
13123         {
13124             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13125             if(stat != TNG_SUCCESS)
13126             {
13127                 return(stat);
13128             }
13129             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13130             if(stat == TNG_SUCCESS)
13131             {
13132                 block_type = TNG_PARTICLE_BLOCK_DATA;
13133             }
13134             else
13135             {
13136                 stat = tng_data_find(tng_data, block_id, &np_data);
13137                 if(stat == TNG_SUCCESS)
13138                 {
13139                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13140                 }
13141             }
13142         }
13143     }
13144     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13145     {
13146         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13147         {
13148             p_data = &frame_set->tr_particle_data[i];
13149             if(p_data->block_id == block_id)
13150             {
13151                 strncpy(name, p_data->block_name, max_len);
13152                 name[max_len - 1] = '\0';
13153                 return(TNG_SUCCESS);
13154             }
13155         }
13156     }
13157     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13158     {
13159         for(i = 0; i < frame_set->n_data_blocks; i++)
13160         {
13161             np_data = &frame_set->tr_data[i];
13162             if(np_data->block_id == block_id)
13163             {
13164                 strncpy(name, np_data->block_name, max_len);
13165                 name[max_len - 1] = '\0';
13166                 return(TNG_SUCCESS);
13167             }
13168         }
13169     }
13170
13171     return(TNG_FAILURE);
13172 }
13173
13174 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13175                 (const tng_trajectory_t tng_data,
13176                  int64_t block_id,
13177                  int *block_dependency)
13178 {
13179     int64_t i;
13180     tng_function_status stat;
13181     tng_particle_data_t p_data;
13182     tng_non_particle_data_t np_data;
13183
13184     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13185     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13186
13187     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13188     {
13189         p_data = &tng_data->non_tr_particle_data[i];
13190         if(p_data->block_id == block_id)
13191         {
13192             *block_dependency = TNG_PARTICLE_DEPENDENT;
13193             return(TNG_SUCCESS);
13194         }
13195     }
13196     for(i = 0; i < tng_data->n_data_blocks; i++)
13197     {
13198         np_data = &tng_data->non_tr_data[i];
13199         if(np_data->block_id == block_id)
13200         {
13201             *block_dependency = 0;
13202             return(TNG_SUCCESS);
13203         }
13204     }
13205
13206     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13207     if(stat == TNG_SUCCESS)
13208     {
13209         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13210         return(TNG_SUCCESS);
13211     }
13212     else
13213     {
13214         stat = tng_data_find(tng_data, block_id, &np_data);
13215         if(stat == TNG_SUCCESS)
13216         {
13217             *block_dependency = TNG_FRAME_DEPENDENT;
13218             return(TNG_SUCCESS);
13219         }
13220         else
13221         {
13222             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13223             if(stat != TNG_SUCCESS)
13224             {
13225                 return(stat);
13226             }
13227             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13228             if(stat == TNG_SUCCESS)
13229             {
13230                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13231                 return(TNG_SUCCESS);
13232             }
13233             else
13234             {
13235                 stat = tng_data_find(tng_data, block_id, &np_data);
13236                 if(stat == TNG_SUCCESS)
13237                 {
13238                     *block_dependency = TNG_FRAME_DEPENDENT;
13239                     return(TNG_SUCCESS);
13240                 }
13241             }
13242         }
13243     }
13244
13245     return(TNG_FAILURE);
13246 }
13247
13248 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
13249                 (const tng_trajectory_t tng_data,
13250                  int64_t block_id,
13251                  int64_t *n_values_per_frame)
13252 {
13253     int64_t i;
13254     tng_function_status stat;
13255     tng_particle_data_t p_data;
13256     tng_non_particle_data_t np_data;
13257
13258     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13259     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
13260
13261     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13262     {
13263         p_data = &tng_data->non_tr_particle_data[i];
13264         if(p_data->block_id == block_id)
13265         {
13266             *n_values_per_frame = p_data->n_values_per_frame;
13267             return(TNG_SUCCESS);
13268         }
13269     }
13270     for(i = 0; i < tng_data->n_data_blocks; i++)
13271     {
13272         np_data = &tng_data->non_tr_data[i];
13273         if(np_data->block_id == block_id)
13274         {
13275             *n_values_per_frame = np_data->n_values_per_frame;
13276             return(TNG_SUCCESS);
13277         }
13278     }
13279
13280     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13281     if(stat == TNG_SUCCESS)
13282     {
13283         *n_values_per_frame = p_data->n_values_per_frame;
13284         return(TNG_SUCCESS);
13285     }
13286     else
13287     {
13288         stat = tng_data_find(tng_data, block_id, &np_data);
13289         if(stat == TNG_SUCCESS)
13290         {
13291             *n_values_per_frame = np_data->n_values_per_frame;
13292             return(TNG_SUCCESS);
13293         }
13294         else
13295         {
13296             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13297             if(stat != TNG_SUCCESS)
13298             {
13299                 return(stat);
13300             }
13301             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13302             if(stat == TNG_SUCCESS)
13303             {
13304                 *n_values_per_frame = p_data->n_values_per_frame;
13305                 return(TNG_SUCCESS);
13306             }
13307             else
13308             {
13309                 stat = tng_data_find(tng_data, block_id, &np_data);
13310                 if(stat == TNG_SUCCESS)
13311                 {
13312                     *n_values_per_frame = np_data->n_values_per_frame;
13313                     return(TNG_SUCCESS);
13314                 }
13315             }
13316         }
13317     }
13318
13319     return(TNG_FAILURE);
13320 }
13321
13322 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
13323                 (tng_trajectory_t tng_data,
13324                  const int64_t frame_nr,
13325                  const int64_t block_id,
13326                  const void *values,
13327                  const char hash_mode)
13328 {
13329     int64_t header_pos, file_pos;
13330     int64_t output_file_len, n_values_per_frame, size, contents_size;
13331     int64_t header_size, temp_first, temp_last;
13332     int64_t i, last_frame;
13333     long temp_current;
13334     tng_gen_block_t block;
13335     tng_trajectory_frame_set_t frame_set;
13336     FILE *temp = tng_data->input_file;
13337     struct tng_non_particle_data data;
13338     tng_function_status stat;
13339     char dependency, sparse_data, datatype;
13340     void *copy;
13341
13342     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13343     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13344     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13345
13346     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13347     {
13348         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13349                __FILE__, __LINE__);
13350         return(TNG_CRITICAL);
13351     }
13352
13353     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13354     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13355     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13356     tng_data->first_trajectory_frame_set_input_file_pos =
13357     tng_data->first_trajectory_frame_set_output_file_pos;
13358     tng_data->last_trajectory_frame_set_input_file_pos =
13359     tng_data->last_trajectory_frame_set_output_file_pos;
13360     tng_data->current_trajectory_frame_set_input_file_pos =
13361     tng_data->current_trajectory_frame_set_output_file_pos;
13362
13363     tng_data->input_file = tng_data->output_file;
13364
13365     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13366
13367     frame_set = &tng_data->current_trajectory_frame_set;
13368
13369     if(stat != TNG_SUCCESS)
13370     {
13371         last_frame = frame_set->first_frame +
13372                      frame_set->n_frames - 1;
13373         /* If the wanted frame would be in the frame set after the last
13374             * frame set create a new frame set. */
13375         if(stat == TNG_FAILURE &&
13376             last_frame < frame_nr)
13377 /*           (last_frame < frame_nr &&
13378             tng_data->current_trajectory_frame_set.first_frame +
13379             tng_data->frame_set_n_frames >= frame_nr))*/
13380         {
13381             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13382             {
13383                 last_frame = frame_nr - 1;
13384             }
13385             tng_frame_set_new(tng_data,
13386                               last_frame+1,
13387                               tng_data->frame_set_n_frames);
13388             file_pos = ftell(tng_data->output_file);
13389             fseek(tng_data->output_file, 0, SEEK_END);
13390             output_file_len = ftell(tng_data->output_file);
13391             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13392
13393             /* Read mapping blocks from the last frame set */
13394             tng_block_init(&block);
13395
13396             stat = tng_block_header_read(tng_data, block);
13397             while(file_pos < output_file_len &&
13398                   stat != TNG_CRITICAL &&
13399                   block->id != TNG_TRAJECTORY_FRAME_SET)
13400             {
13401                 if(block->id == TNG_PARTICLE_MAPPING)
13402                 {
13403                     tng_trajectory_mapping_block_read(tng_data, block,
13404                                                       hash_mode);
13405                 }
13406                 else
13407                 {
13408                     fseek(tng_data->output_file, (long)block->block_contents_size,
13409                         SEEK_CUR);
13410                 }
13411                 file_pos = ftell(tng_data->output_file);
13412                 if(file_pos < output_file_len)
13413                 {
13414                     stat = tng_block_header_read(tng_data, block);
13415                 }
13416             }
13417
13418             tng_block_destroy(&block);
13419             /* Write the frame set to disk */
13420             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13421             {
13422                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13423                 return(TNG_CRITICAL);
13424             }
13425         }
13426         else
13427         {
13428             tng_data->input_file = temp;
13429             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13430             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13431             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13432             return(stat);
13433         }
13434     }
13435
13436     tng_block_init(&block);
13437
13438     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13439
13440     fseek(tng_data->output_file, 0, SEEK_END);
13441     output_file_len = ftell(tng_data->output_file);
13442     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13443
13444     /* Read past the frame set block first */
13445     stat = tng_block_header_read(tng_data, block);
13446     if(stat == TNG_CRITICAL)
13447     {
13448         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13449                file_pos, __FILE__, __LINE__);
13450         tng_block_destroy(&block);
13451         tng_data->input_file = temp;
13452
13453         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13454         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13455         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13456         return(stat);
13457     }
13458     fseek(tng_data->output_file, (long)block->block_contents_size,
13459             SEEK_CUR);
13460
13461     /* Read all block headers until next frame set block or
13462      * until the wanted block id is found */
13463     stat = tng_block_header_read(tng_data, block);
13464     while(file_pos < output_file_len &&
13465             stat != TNG_CRITICAL &&
13466             block->id != block_id &&
13467             block->id != TNG_TRAJECTORY_FRAME_SET)
13468     {
13469         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
13470         file_pos = ftell(tng_data->output_file);
13471         if(file_pos < output_file_len)
13472         {
13473             stat = tng_block_header_read(tng_data, block);
13474         }
13475     }
13476     if(stat == TNG_CRITICAL)
13477     {
13478         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13479                file_pos, __FILE__, __LINE__);
13480         tng_block_destroy(&block);
13481         tng_data->input_file = temp;
13482         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13483         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13484         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13485         return(stat);
13486     }
13487
13488     contents_size = block->block_contents_size;
13489     header_size = block->header_contents_size;
13490
13491     header_pos = ftell(tng_data->output_file) - header_size;
13492     frame_set = &tng_data->current_trajectory_frame_set;
13493
13494     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
13495     {
13496         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13497         tng_block_destroy(&block);
13498         return(TNG_CRITICAL);
13499     }
13500     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
13501     {
13502         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13503         tng_block_destroy(&block);
13504         return(TNG_CRITICAL);
13505     }
13506     data.datatype = datatype;
13507
13508     if(!(dependency & TNG_FRAME_DEPENDENT) ||
13509        (dependency & TNG_PARTICLE_DEPENDENT))
13510     {
13511         tng_block_destroy(&block);
13512         tng_data->input_file = temp;
13513
13514         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13515         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13516         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13517         return(TNG_FAILURE);
13518     }
13519
13520     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
13521     {
13522         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13523         tng_block_destroy(&block);
13524         return(TNG_CRITICAL);
13525     }
13526
13527     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
13528              tng_data->input_file) == 0)
13529     {
13530         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13531         tng_block_destroy(&block);
13532         return(TNG_CRITICAL);
13533     }
13534     if(tng_data->output_endianness_swap_func_64)
13535     {
13536         if(tng_data->output_endianness_swap_func_64(tng_data,
13537             &data.n_values_per_frame)
13538             != TNG_SUCCESS)
13539         {
13540             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13541                     __FILE__, __LINE__);
13542         }
13543     }
13544
13545     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
13546              tng_data->input_file) == 0)
13547     {
13548         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13549         tng_block_destroy(&block);
13550         return(TNG_CRITICAL);
13551     }
13552     if(tng_data->output_endianness_swap_func_64)
13553     {
13554         if(tng_data->output_endianness_swap_func_64(tng_data,
13555             &data.codec_id)
13556             != TNG_SUCCESS)
13557         {
13558             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13559                     __FILE__, __LINE__);
13560         }
13561     }
13562
13563     if(data.codec_id != TNG_UNCOMPRESSED)
13564     {
13565         if(fread(&data.compression_multiplier,
13566                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
13567             == 0)
13568         {
13569             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13570             tng_block_destroy(&block);
13571             return(TNG_CRITICAL);
13572         }
13573         if(tng_data->output_endianness_swap_func_64)
13574         {
13575             if(tng_data->output_endianness_swap_func_64(tng_data,
13576                 (int64_t *)&data.compression_multiplier)
13577                 != TNG_SUCCESS)
13578             {
13579                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13580                         __FILE__, __LINE__);
13581             }
13582         }
13583     }
13584     else
13585     {
13586         data.compression_multiplier = 1;
13587     }
13588
13589     if(sparse_data)
13590     {
13591         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
13592                  1, tng_data->input_file) == 0)
13593         {
13594             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13595             tng_block_destroy(&block);
13596             return(TNG_CRITICAL);
13597         }
13598         if(tng_data->output_endianness_swap_func_64)
13599         {
13600             if(tng_data->output_endianness_swap_func_64(tng_data,
13601                 &data.first_frame_with_data)
13602                 != TNG_SUCCESS)
13603             {
13604                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13605                         __FILE__, __LINE__);
13606             }
13607         }
13608
13609         if(fread(&data.stride_length, sizeof(data.stride_length),
13610                  1, tng_data->input_file) == 0)
13611         {
13612             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13613             tng_block_destroy(&block);
13614             return(TNG_CRITICAL);
13615         }
13616         if(tng_data->output_endianness_swap_func_64)
13617         {
13618             if(tng_data->output_endianness_swap_func_64(tng_data,
13619                 &data.stride_length)
13620                 != TNG_SUCCESS)
13621             {
13622                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13623                         __FILE__, __LINE__);
13624             }
13625         }
13626     }
13627     else
13628     {
13629         data.first_frame_with_data = 0;
13630         data.stride_length = 1;
13631     }
13632     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
13633
13634     tng_data->input_file = temp;
13635
13636     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13637     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13638     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13639
13640     switch(data.datatype)
13641     {
13642         case(TNG_INT_DATA):
13643             size = sizeof(int64_t);
13644             break;
13645         case(TNG_FLOAT_DATA):
13646             size = sizeof(float);
13647             break;
13648         case(TNG_DOUBLE_DATA):
13649             size = sizeof(double);
13650             break;
13651         default:
13652             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
13653                    __LINE__);
13654             tng_block_destroy(&block);
13655             return(TNG_FAILURE);
13656     }
13657
13658     n_values_per_frame = data.n_values_per_frame;
13659
13660     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
13661                                data.first_frame_with_data)) /
13662                 data.stride_length;
13663     file_pos *= size * n_values_per_frame;
13664
13665     if(file_pos > contents_size)
13666     {
13667         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
13668                __LINE__);
13669         tng_block_destroy(&block);
13670         return(TNG_FAILURE);
13671     }
13672
13673     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
13674
13675     /* If the endianness is not big endian the data needs to be swapped */
13676     if((data.datatype == TNG_INT_DATA ||
13677         data.datatype == TNG_DOUBLE_DATA) &&
13678        tng_data->output_endianness_swap_func_64)
13679     {
13680         copy = malloc(n_values_per_frame * size);
13681         memcpy(copy, values, n_values_per_frame * size);
13682         for(i = 0; i < n_values_per_frame; i++)
13683         {
13684             if(tng_data->output_endianness_swap_func_64(tng_data,
13685                 (int64_t *)copy+i)
13686                 != TNG_SUCCESS)
13687             {
13688                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13689                         __FILE__, __LINE__);
13690             }
13691         }
13692         fwrite(copy, n_values_per_frame, size,
13693                tng_data->output_file);
13694         free(copy);
13695     }
13696     else if(data.datatype == TNG_FLOAT_DATA &&
13697             tng_data->output_endianness_swap_func_32)
13698     {
13699         copy = malloc(n_values_per_frame * size);
13700         memcpy(copy, values, n_values_per_frame * size);
13701         for(i = 0; i < n_values_per_frame; i++)
13702         {
13703             if(tng_data->output_endianness_swap_func_32(tng_data,
13704                 (int32_t *)copy+i)
13705                 != TNG_SUCCESS)
13706             {
13707                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13708                         __FILE__, __LINE__);
13709             }
13710         }
13711         fwrite(copy, n_values_per_frame, size,
13712                tng_data->output_file);
13713         free(copy);
13714     }
13715
13716     else
13717     {
13718         fwrite(values, n_values_per_frame, size, tng_data->output_file);
13719     }
13720
13721     fflush(tng_data->output_file);
13722
13723     /* Update the number of written frames in the frame set. */
13724     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
13725     {
13726         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
13727     }
13728
13729     /* If the last frame has been written update the hash */
13730     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
13731        data.first_frame_with_data) >=
13732        frame_set->n_frames)
13733     {
13734         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
13735                             header_size);
13736     }
13737
13738     tng_block_destroy(&block);
13739
13740     return(TNG_SUCCESS);
13741 }
13742
13743 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
13744                 (tng_trajectory_t tng_data,
13745                  const int64_t frame_nr,
13746                  const int64_t block_id,
13747                  const int64_t val_first_particle,
13748                  const int64_t val_n_particles,
13749                  const void *values,
13750                  const char hash_mode)
13751 {
13752     int64_t header_pos, file_pos, tot_n_particles;
13753     int64_t output_file_len, n_values_per_frame, size, contents_size;
13754     int64_t header_size, temp_first, temp_last;
13755     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
13756     int64_t i, last_frame;
13757     long temp_current;
13758     tng_gen_block_t block;
13759     tng_trajectory_frame_set_t frame_set;
13760     FILE *temp = tng_data->input_file;
13761     struct tng_particle_data data;
13762     tng_function_status stat;
13763     tng_particle_mapping_t mapping;
13764     char dependency, sparse_data, datatype;
13765     void *copy;
13766
13767     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13768     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13769     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13770     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
13771     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
13772
13773     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13774     {
13775         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13776                __FILE__, __LINE__);
13777         return(TNG_CRITICAL);
13778     }
13779
13780     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13781     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13782     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13783     tng_data->first_trajectory_frame_set_input_file_pos =
13784     tng_data->first_trajectory_frame_set_output_file_pos;
13785     tng_data->last_trajectory_frame_set_input_file_pos =
13786     tng_data->last_trajectory_frame_set_output_file_pos;
13787     tng_data->current_trajectory_frame_set_input_file_pos =
13788     tng_data->current_trajectory_frame_set_output_file_pos;
13789
13790     tng_data->input_file = tng_data->output_file;
13791
13792     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13793
13794     frame_set = &tng_data->current_trajectory_frame_set;
13795
13796     if(stat != TNG_SUCCESS)
13797     {
13798         last_frame = frame_set->first_frame +
13799                      frame_set->n_frames - 1;
13800 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
13801                   last_frame); */
13802         /* If the wanted frame would be in the frame set after the last
13803          * frame set create a new frame set. */
13804         if(stat == TNG_FAILURE &&
13805            (last_frame < frame_nr &&
13806             last_frame + tng_data->frame_set_n_frames >= frame_nr))
13807         {
13808             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13809             {
13810                 last_frame = frame_nr - 1;
13811             }
13812             tng_frame_set_new(tng_data,
13813                               last_frame+1,
13814                               tng_data->frame_set_n_frames);
13815
13816             file_pos = ftell(tng_data->output_file);
13817             fseek(tng_data->output_file, 0, SEEK_END);
13818             output_file_len = ftell(tng_data->output_file);
13819             fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13820
13821             /* Read mapping blocks from the last frame set */
13822             tng_block_init(&block);
13823
13824             stat = tng_block_header_read(tng_data, block);
13825             while(file_pos < output_file_len &&
13826                   stat != TNG_CRITICAL &&
13827                   block->id != TNG_TRAJECTORY_FRAME_SET)
13828             {
13829                 if(block->id == TNG_PARTICLE_MAPPING)
13830                 {
13831                     tng_trajectory_mapping_block_read(tng_data, block,
13832                                                       hash_mode);
13833                 }
13834                 else
13835                 {
13836                     fseek(tng_data->output_file, (long)block->block_contents_size,
13837                         SEEK_CUR);
13838                 }
13839                 file_pos = ftell(tng_data->output_file);
13840                 if(file_pos < output_file_len)
13841                 {
13842                     stat = tng_block_header_read(tng_data, block);
13843                 }
13844             }
13845
13846             tng_block_destroy(&block);
13847             /* Write the frame set to disk */
13848             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13849             {
13850                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13851                 exit(1);
13852             }
13853         }
13854         else
13855         {
13856             tng_data->input_file = temp;
13857             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13858             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13859             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13860             return(stat);
13861         }
13862     }
13863
13864
13865     tng_block_init(&block);
13866
13867     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13868
13869     fseek(tng_data->output_file, 0, SEEK_END);
13870     output_file_len = ftell(tng_data->output_file);
13871     fseek(tng_data->output_file, (long)file_pos, SEEK_SET);
13872
13873     /* Read past the frame set block first */
13874     stat = tng_block_header_read(tng_data, block);
13875     if(stat == TNG_CRITICAL)
13876     {
13877         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13878                file_pos, __FILE__, __LINE__);
13879         tng_block_destroy(&block);
13880         tng_data->input_file = temp;
13881
13882         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13883         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13884         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13885         return(stat);
13886     }
13887     fseek(tng_data->output_file, (long)block->block_contents_size,
13888             SEEK_CUR);
13889
13890     if(tng_data->var_num_atoms_flag)
13891     {
13892         tot_n_particles = frame_set->n_particles;
13893     }
13894     else
13895     {
13896         tot_n_particles = tng_data->n_particles;
13897     }
13898
13899     if(val_n_particles < tot_n_particles)
13900     {
13901         mapping_block_end_pos = -1;
13902         /* Read all mapping blocks to find the right place to put the data */
13903         stat = tng_block_header_read(tng_data, block);
13904         while(file_pos < output_file_len &&
13905                 stat != TNG_CRITICAL &&
13906                 block->id != TNG_TRAJECTORY_FRAME_SET)
13907         {
13908             if(block->id == TNG_PARTICLE_MAPPING)
13909             {
13910                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
13911             }
13912             else
13913             {
13914                 fseek(tng_data->output_file, (long)block->block_contents_size,
13915                       SEEK_CUR);
13916             }
13917             file_pos = ftell(tng_data->output_file);
13918             if(block->id == TNG_PARTICLE_MAPPING)
13919             {
13920                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
13921                 if(val_first_particle >= mapping->num_first_particle &&
13922                    val_first_particle < mapping->num_first_particle +
13923                    mapping->n_particles &&
13924                    val_first_particle + val_n_particles <=
13925                    mapping->num_first_particle + mapping->n_particles)
13926                 {
13927                     mapping_block_end_pos = file_pos;
13928                 }
13929             }
13930             if(file_pos < output_file_len)
13931             {
13932                 stat = tng_block_header_read(tng_data, block);
13933             }
13934         }
13935         if(stat == TNG_CRITICAL)
13936         {
13937             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13938                    file_pos, __FILE__, __LINE__);
13939             tng_block_destroy(&block);
13940             tng_data->input_file = temp;
13941
13942             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13943             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13944             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13945             return(stat);
13946         }
13947         if(mapping_block_end_pos < 0)
13948         {
13949             tng_block_destroy(&block);
13950             tng_data->input_file = temp;
13951
13952             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13953             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13954             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13955             return(TNG_FAILURE);
13956         }
13957         fseek(tng_data->output_file, (long)mapping_block_end_pos, SEEK_SET);
13958     }
13959
13960     /* Read all block headers until next frame set block or
13961      * until the wanted block id is found */
13962     stat = tng_block_header_read(tng_data, block);
13963     while(file_pos < output_file_len &&
13964             stat != TNG_CRITICAL &&
13965             block->id != block_id &&
13966             block->id != TNG_PARTICLE_MAPPING &&
13967             block->id != TNG_TRAJECTORY_FRAME_SET)
13968     {
13969         fseek(tng_data->output_file, (long)block->block_contents_size, SEEK_CUR);
13970         file_pos = ftell(tng_data->output_file);
13971         if(file_pos < output_file_len)
13972         {
13973             stat = tng_block_header_read(tng_data, block);
13974         }
13975     }
13976     if(stat == TNG_CRITICAL)
13977     {
13978         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13979                 file_pos, __FILE__, __LINE__);
13980         tng_block_destroy(&block);
13981         tng_data->input_file = temp;
13982
13983         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13984         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13985         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13986         return(stat);
13987     }
13988
13989     contents_size = block->block_contents_size;
13990     header_size = block->header_contents_size;
13991
13992     header_pos = ftell(tng_data->output_file) - header_size;
13993     frame_set = &tng_data->current_trajectory_frame_set;
13994
13995     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
13996     {
13997         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
13998         tng_block_destroy(&block);
13999         return(TNG_CRITICAL);
14000     }
14001
14002     data.datatype = datatype;
14003
14004     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14005     {
14006         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14007         tng_block_destroy(&block);
14008         return(TNG_CRITICAL);
14009     }
14010
14011     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14012        !(dependency & TNG_PARTICLE_DEPENDENT))
14013     {
14014         tng_block_destroy(&block);
14015         tng_data->input_file = temp;
14016
14017         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14018         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14019         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14020         return(TNG_FAILURE);
14021     }
14022
14023     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14024     {
14025         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14026         tng_block_destroy(&block);
14027         return(TNG_CRITICAL);
14028     }
14029
14030     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14031              tng_data->input_file) == 0)
14032     {
14033         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14034         tng_block_destroy(&block);
14035         return(TNG_CRITICAL);
14036     }
14037     if(tng_data->output_endianness_swap_func_64)
14038     {
14039         if(tng_data->output_endianness_swap_func_64(tng_data,
14040             &data.n_values_per_frame)
14041             != TNG_SUCCESS)
14042         {
14043             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14044                     __FILE__, __LINE__);
14045         }
14046     }
14047
14048     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14049              tng_data->input_file) == 0)
14050     {
14051         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14052         tng_block_destroy(&block);
14053         return(TNG_CRITICAL);
14054     }
14055     if(tng_data->output_endianness_swap_func_64)
14056     {
14057         if(tng_data->output_endianness_swap_func_64(tng_data,
14058             &data.codec_id)
14059             != TNG_SUCCESS)
14060         {
14061             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14062                     __FILE__, __LINE__);
14063         }
14064     }
14065
14066     if(data.codec_id != TNG_UNCOMPRESSED)
14067     {
14068         if(fread(&data.compression_multiplier,
14069                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14070             == 0)
14071         {
14072             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14073             tng_block_destroy(&block);
14074             return(TNG_CRITICAL);
14075         }
14076
14077         if(tng_data->output_endianness_swap_func_64)
14078         {
14079             if(tng_data->output_endianness_swap_func_64(tng_data,
14080                (int64_t *)&data.compression_multiplier)
14081                 != TNG_SUCCESS)
14082             {
14083                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14084                         __FILE__, __LINE__);
14085             }
14086         }
14087     }
14088     else
14089     {
14090         data.compression_multiplier = 1;
14091     }
14092
14093     if(sparse_data)
14094     {
14095         if(fread(&data.first_frame_with_data,
14096                  sizeof(data.first_frame_with_data),
14097                  1, tng_data->input_file) == 0)
14098         {
14099             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14100             tng_block_destroy(&block);
14101             return(TNG_CRITICAL);
14102         }
14103         if(tng_data->output_endianness_swap_func_64)
14104         {
14105             if(tng_data->output_endianness_swap_func_64(tng_data,
14106                 &data.first_frame_with_data)
14107                 != TNG_SUCCESS)
14108             {
14109                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14110                         __FILE__, __LINE__);
14111             }
14112         }
14113
14114         if(fread(&data.stride_length, sizeof(data.stride_length),
14115                  1, tng_data->input_file) == 0)
14116         {
14117             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14118             tng_block_destroy(&block);
14119             return(TNG_CRITICAL);
14120         }
14121         if(tng_data->output_endianness_swap_func_64)
14122         {
14123             if(tng_data->output_endianness_swap_func_64(tng_data,
14124                 &data.stride_length)
14125                 != TNG_SUCCESS)
14126             {
14127                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14128                         __FILE__, __LINE__);
14129             }
14130         }
14131     }
14132     else
14133     {
14134         data.first_frame_with_data = 0;
14135         data.stride_length = 1;
14136     }
14137     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14138
14139     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14140              tng_data->input_file) == 0)
14141     {
14142         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14143         tng_block_destroy(&block);
14144         return(TNG_CRITICAL);
14145     }
14146     if(tng_data->output_endianness_swap_func_64)
14147     {
14148         if(tng_data->output_endianness_swap_func_64(tng_data,
14149             &num_first_particle)
14150             != TNG_SUCCESS)
14151         {
14152             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14153                     __FILE__, __LINE__);
14154         }
14155     }
14156
14157     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14158              tng_data->input_file) == 0)
14159     {
14160         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14161         tng_block_destroy(&block);
14162         return(TNG_CRITICAL);
14163     }
14164     if(tng_data->output_endianness_swap_func_64)
14165     {
14166         if(tng_data->output_endianness_swap_func_64(tng_data,
14167             &block_n_particles)
14168             != TNG_SUCCESS)
14169         {
14170             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14171                     __FILE__, __LINE__);
14172         }
14173     }
14174
14175
14176     tng_data->input_file = temp;
14177
14178     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14179     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14180     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14181
14182
14183     switch(data.datatype)
14184     {
14185         case(TNG_INT_DATA):
14186             size = sizeof(int64_t);
14187             break;
14188         case(TNG_FLOAT_DATA):
14189             size = sizeof(float);
14190             break;
14191         case(TNG_DOUBLE_DATA):
14192             size = sizeof(double);
14193             break;
14194         default:
14195             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14196                    __LINE__);
14197             tng_block_destroy(&block);
14198             return(TNG_FAILURE);
14199     }
14200
14201     n_values_per_frame = data.n_values_per_frame;
14202
14203     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14204                                data.first_frame_with_data)) /
14205                 data.stride_length;
14206     file_pos *= block_n_particles * size * n_values_per_frame;
14207
14208     if(file_pos > contents_size)
14209     {
14210         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14211                __LINE__);
14212         tng_block_destroy(&block);
14213         return(TNG_FAILURE);
14214     }
14215
14216     fseek(tng_data->output_file, (long)file_pos, SEEK_CUR);
14217
14218     /* If the endianness is not big endian the data needs to be swapped */
14219     if((data.datatype == TNG_INT_DATA ||
14220         data.datatype == TNG_DOUBLE_DATA) &&
14221        tng_data->output_endianness_swap_func_64)
14222     {
14223         copy = malloc(val_n_particles * n_values_per_frame * size);
14224         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14225         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14226         {
14227             if(tng_data->output_endianness_swap_func_64(tng_data,
14228                 (int64_t *) copy+i)
14229                 != TNG_SUCCESS)
14230             {
14231                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14232                         __FILE__, __LINE__);
14233             }
14234         }
14235         fwrite(copy, val_n_particles * n_values_per_frame, size,
14236                tng_data->output_file);
14237         free(copy);
14238     }
14239     else if(data.datatype == TNG_FLOAT_DATA &&
14240        tng_data->output_endianness_swap_func_32)
14241     {
14242         copy = malloc(val_n_particles * n_values_per_frame * size);
14243         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14244         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14245         {
14246             if(tng_data->output_endianness_swap_func_32(tng_data,
14247                 (int32_t *) copy+i)
14248                 != TNG_SUCCESS)
14249             {
14250                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14251                         __FILE__, __LINE__);
14252             }
14253         }
14254         fwrite(copy, val_n_particles * n_values_per_frame, size,
14255                tng_data->output_file);
14256         free(copy);
14257     }
14258
14259     else
14260     {
14261         fwrite(values, val_n_particles * n_values_per_frame, size,
14262                tng_data->output_file);
14263     }
14264     fflush(tng_data->output_file);
14265
14266     /* Update the number of written frames in the frame set. */
14267     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14268     {
14269         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14270     }
14271
14272     /* If the last frame has been written update the hash */
14273     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14274        data.first_frame_with_data) >=
14275        frame_set->n_frames)
14276     {
14277         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14278                             header_size);
14279     }
14280
14281     tng_block_destroy(&block);
14282     return(TNG_SUCCESS);
14283 }
14284
14285 static tng_function_status tng_data_values_alloc
14286                 (const tng_trajectory_t tng_data,
14287                  union data_values ***values,
14288                  const int64_t n_frames,
14289                  const int64_t n_values_per_frame,
14290                  const char type)
14291 {
14292     int64_t i;
14293     tng_function_status stat;
14294
14295     if(n_frames <= 0 || n_values_per_frame <= 0)
14296     {
14297         return(TNG_FAILURE);
14298     }
14299
14300     if(*values)
14301     {
14302         stat = tng_data_values_free(tng_data, *values, n_frames,
14303                                     n_values_per_frame,
14304                                     type);
14305         if(stat != TNG_SUCCESS)
14306         {
14307             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
14308                    __FILE__, __LINE__);
14309             return(stat);
14310         }
14311     }
14312     *values = malloc(sizeof(union data_values *) * n_frames);
14313     if(!*values)
14314     {
14315         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14316                sizeof(union data_values **) * n_frames,
14317                __FILE__, __LINE__);
14318         return(TNG_CRITICAL);
14319
14320     }
14321
14322     for(i = n_frames; i--;)
14323     {
14324         (*values)[i] = malloc(sizeof(union data_values) *
14325                            n_values_per_frame);
14326         if(!(*values)[i])
14327         {
14328             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14329                    sizeof(union data_values) * n_values_per_frame,
14330                    __FILE__, __LINE__);
14331             free(values);
14332             values = 0;
14333             return(TNG_CRITICAL);
14334         }
14335     }
14336     return(TNG_SUCCESS);
14337 }
14338
14339 /* FIXME: This needs ***values */
14340 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
14341                 (const tng_trajectory_t tng_data,
14342                  union data_values **values,
14343                  const int64_t n_frames,
14344                  const int64_t n_values_per_frame,
14345                  const char type)
14346 {
14347     int64_t i, j;
14348     (void)tng_data;
14349
14350     if(values)
14351     {
14352         for(i = 0; i < n_frames; i++)
14353         {
14354             if(values[i])
14355             {
14356                 if(type == TNG_CHAR_DATA)
14357                 {
14358                     for(j = n_values_per_frame; j--;)
14359                     {
14360                         if(values[i][j].c)
14361                         {
14362                             free(values[i][j].c);
14363                             values[i][j].c = 0;
14364                         }
14365                     }
14366                 }
14367                 free(values[i]);
14368                 values[i] = 0;
14369             }
14370         }
14371         free(values);
14372         values = 0;
14373     }
14374
14375     return(TNG_SUCCESS);
14376 }
14377
14378 static tng_function_status tng_particle_data_values_alloc
14379                 (const tng_trajectory_t tng_data,
14380                  union data_values ****values,
14381                  const int64_t n_frames,
14382                  const int64_t n_particles,
14383                  const int64_t n_values_per_frame,
14384                  const char type)
14385 {
14386     int64_t i, j;
14387     tng_function_status stat;
14388
14389     if(n_particles == 0 || n_values_per_frame == 0)
14390     {
14391         return(TNG_FAILURE);
14392     }
14393
14394     if(*values)
14395     {
14396         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
14397                                              n_particles, n_values_per_frame,
14398                                              type);
14399         if(stat != TNG_SUCCESS)
14400         {
14401             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
14402                    __FILE__, __LINE__);
14403             return(stat);
14404         }
14405     }
14406     *values = malloc(sizeof(union data_values **) * n_frames);
14407     if(!*values)
14408     {
14409         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14410                sizeof(union data_values **) * n_frames,
14411                __FILE__, __LINE__);
14412         return(TNG_CRITICAL);
14413
14414     }
14415
14416     for(i = n_frames; i--;)
14417     {
14418         (*values)[i] = malloc(sizeof(union data_values *) *
14419                            n_particles);
14420         if(!(*values)[i])
14421         {
14422             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14423                    sizeof(union data_values *) * n_particles,
14424                    __FILE__, __LINE__);
14425             free(*values);
14426             *values = 0;
14427             return(TNG_CRITICAL);
14428         }
14429         for(j = n_particles; j--;)
14430         {
14431             (*values)[i][j] = malloc(sizeof(union data_values) *
14432                                   n_values_per_frame);
14433             if(!(*values)[i][j])
14434             {
14435                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14436                     sizeof(union data_values *) * n_particles,
14437                     __FILE__, __LINE__);
14438                 tng_particle_data_values_free(tng_data, *values, n_frames,
14439                                               n_particles, n_values_per_frame,
14440                                               type);
14441                 *values = 0;
14442                 return(TNG_CRITICAL);
14443             }
14444         }
14445     }
14446     return(TNG_SUCCESS);
14447 }
14448
14449 /* FIXME: This needs ****values */
14450 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
14451                 (const tng_trajectory_t tng_data,
14452                  union data_values ***values,
14453                  const int64_t n_frames,
14454                  const int64_t n_particles,
14455                  const int64_t n_values_per_frame,
14456                  const char type)
14457 {
14458     int64_t i, j, k;
14459     (void)tng_data;
14460
14461     if(values)
14462     {
14463         for(i = 0; i < n_frames; i++)
14464         {
14465             if(values[i])
14466             {
14467                 for(j = 0; j < n_particles; j++)
14468                 {
14469                     if(type == TNG_CHAR_DATA)
14470                     {
14471                         for(k = n_values_per_frame; k--;)
14472                         {
14473                             if(values[i][j][k].c)
14474                             {
14475                                 free(values[i][j][k].c);
14476                                 values[i][j][k].c = 0;
14477                             }
14478                         }
14479                     }
14480                     free(values[i][j]);
14481                     values[i][j] = 0;
14482                 }
14483                 free(values[i]);
14484                 values[i] = 0;
14485             }
14486         }
14487         free(values);
14488         values = 0;
14489     }
14490
14491     return(TNG_SUCCESS);
14492 }
14493
14494
14495 tng_function_status DECLSPECDLLEXPORT tng_data_get
14496                 (tng_trajectory_t tng_data,
14497                  const int64_t block_id,
14498                  union data_values ***values,
14499                  int64_t *n_frames,
14500                  int64_t *n_values_per_frame,
14501                  char *type)
14502 {
14503     int64_t i, j, file_pos, block_index;
14504     int size;
14505     size_t len;
14506     tng_non_particle_data_t data;
14507     tng_trajectory_frame_set_t frame_set;
14508     tng_gen_block_t block;
14509     tng_function_status stat;
14510
14511     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14512     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14513     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14514     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14515
14516     frame_set = &tng_data->current_trajectory_frame_set;
14517
14518     block_index = -1;
14519     data = 0;
14520
14521     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
14522     {
14523         tng_block_init(&block);
14524         file_pos = ftell(tng_data->input_file);
14525         /* Read all blocks until next frame set block */
14526         stat = tng_block_header_read(tng_data, block);
14527         while(file_pos < tng_data->input_file_len &&
14528                 stat != TNG_CRITICAL &&
14529                 block->id != TNG_TRAJECTORY_FRAME_SET)
14530         {
14531             /* Use hash by default */
14532             stat = tng_block_read_next(tng_data, block,
14533                                     TNG_USE_HASH);
14534             if(stat != TNG_CRITICAL)
14535             {
14536                 file_pos = ftell(tng_data->input_file);
14537                 if(file_pos < tng_data->input_file_len)
14538                 {
14539                     stat = tng_block_header_read(tng_data, block);
14540                 }
14541             }
14542         }
14543         tng_block_destroy(&block);
14544         if(stat == TNG_CRITICAL)
14545         {
14546             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14547                     file_pos, __FILE__, __LINE__);
14548             return(stat);
14549         }
14550
14551         for(i = frame_set->n_data_blocks; i-- ;)
14552         {
14553             data = &frame_set->tr_data[i];
14554             if(data->block_id == block_id)
14555             {
14556                 block_index = i;
14557                 break;
14558             }
14559         }
14560         if(block_index < 0)
14561         {
14562             return(TNG_FAILURE);
14563         }
14564     }
14565
14566     *n_frames = tng_max_i64(1, data->n_frames);
14567     *n_values_per_frame = data->n_values_per_frame;
14568     *type = data->datatype;
14569
14570     if(*values == 0)
14571     {
14572         if(tng_data_values_alloc(tng_data, values, *n_frames,
14573                                  *n_values_per_frame,
14574                                  *type)
14575         != TNG_SUCCESS)
14576         {
14577             return(TNG_CRITICAL);
14578         }
14579     }
14580
14581     switch(*type)
14582     {
14583     case TNG_CHAR_DATA:
14584         for(i=*n_frames; i--;)
14585         {
14586             for(j=*n_values_per_frame; j--;)
14587             {
14588                 len = strlen(data->strings[i][j]) + 1;
14589                 (*values)[i][j].c = malloc(len);
14590                 strncpy((*values)[i][j].c, data->strings[i][j], len);
14591             }
14592         }
14593         break;
14594     case TNG_INT_DATA:
14595         size = sizeof(int);
14596         for(i=*n_frames; i--;)
14597         {
14598             for(j=*n_values_per_frame; j--;)
14599             {
14600                 (*values)[i][j].i = *(int *)((char *)data->values + size *
14601                                              (i*(*n_values_per_frame) + j));
14602             }
14603         }
14604         break;
14605     case TNG_FLOAT_DATA:
14606         size = sizeof(float);
14607         for(i=*n_frames; i--;)
14608         {
14609             for(j=*n_values_per_frame; j--;)
14610             {
14611                 (*values)[i][j].f = *(float *)((char *)data->values + size *
14612                                                (i*(*n_values_per_frame) + j));
14613             }
14614         }
14615         break;
14616     case TNG_DOUBLE_DATA:
14617     default:
14618         size = sizeof(double);
14619         for(i=*n_frames; i--;)
14620         {
14621             for(j=*n_values_per_frame; j--;)
14622             {
14623                 (*values)[i][j].d = *(double *)((char *)data->values + size *
14624                                                 (i*(*n_values_per_frame) + j));
14625             }
14626         }
14627     }
14628
14629     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14630
14631     return(TNG_SUCCESS);
14632 }
14633
14634 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
14635                                         const int64_t block_id,
14636                                         void **values,
14637                                         int64_t *n_frames,
14638                                         int64_t *stride_length,
14639                                         int64_t *n_values_per_frame,
14640                                         char *type)
14641 {
14642     int64_t file_pos, data_size, n_frames_div, block_index;
14643     int i, size;
14644     tng_non_particle_data_t data;
14645     tng_trajectory_frame_set_t frame_set;
14646     tng_gen_block_t block;
14647     void *temp;
14648     tng_function_status stat;
14649
14650     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14651     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14652     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14653     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14654     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14655
14656     frame_set = &tng_data->current_trajectory_frame_set;
14657
14658     block_index = -1;
14659     data = 0;
14660
14661     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
14662     {
14663         tng_block_init(&block);
14664         file_pos = ftell(tng_data->input_file);
14665         /* Read all blocks until next frame set block */
14666         stat = tng_block_header_read(tng_data, block);
14667         while(file_pos < tng_data->input_file_len &&
14668                 stat != TNG_CRITICAL &&
14669                 block->id != TNG_TRAJECTORY_FRAME_SET)
14670         {
14671             /* Use hash by default */
14672             stat = tng_block_read_next(tng_data, block,
14673                                     TNG_USE_HASH);
14674             if(stat != TNG_CRITICAL)
14675             {
14676                 file_pos = ftell(tng_data->input_file);
14677                 if(file_pos < tng_data->input_file_len)
14678                 {
14679                     stat = tng_block_header_read(tng_data, block);
14680                 }
14681             }
14682         }
14683         tng_block_destroy(&block);
14684         if(stat == TNG_CRITICAL)
14685         {
14686             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14687                     file_pos, __FILE__, __LINE__);
14688             return(stat);
14689         }
14690
14691         for(i = frame_set->n_data_blocks; i-- ;)
14692         {
14693             data = &frame_set->tr_data[i];
14694             if(data->block_id == block_id)
14695             {
14696                 block_index = i;
14697                 break;
14698             }
14699         }
14700         if(block_index < 0)
14701         {
14702             return(TNG_FAILURE);
14703         }
14704     }
14705
14706     *type = data->datatype;
14707
14708     switch(*type)
14709     {
14710     case TNG_CHAR_DATA:
14711         return(TNG_FAILURE);
14712     case TNG_INT_DATA:
14713         size = sizeof(int64_t);
14714         break;
14715     case TNG_FLOAT_DATA:
14716         size = sizeof(float);
14717         break;
14718     case TNG_DOUBLE_DATA:
14719     default:
14720         size = sizeof(double);
14721     }
14722
14723     *n_frames = data->n_frames;
14724     *n_values_per_frame = data->n_values_per_frame;
14725     *stride_length = data->stride_length;
14726     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
14727                    *n_frames / *stride_length;
14728
14729     data_size = n_frames_div * size *
14730                 *n_values_per_frame;
14731
14732     temp = realloc(*values, data_size);
14733     if(!temp)
14734     {
14735         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
14736                data_size, __FILE__, __LINE__);
14737         free(*values);
14738         *values = 0;
14739         return(TNG_CRITICAL);
14740     }
14741
14742     *values = temp;
14743
14744     memcpy(*values, data->values, data_size);
14745
14746     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14747
14748     return(TNG_SUCCESS);
14749 }
14750
14751 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
14752                 (tng_trajectory_t tng_data,
14753                  const int64_t block_id,
14754                  const int64_t start_frame_nr,
14755                  const int64_t end_frame_nr,
14756                  const char hash_mode,
14757                  union data_values ***values,
14758                  int64_t *n_values_per_frame,
14759                  char *type)
14760 {
14761     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
14762     int64_t block_index;
14763     int size;
14764     size_t len;
14765     tng_non_particle_data_t data;
14766     tng_trajectory_frame_set_t frame_set;
14767     tng_gen_block_t block;
14768     tng_function_status stat;
14769
14770     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14771     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
14772     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14773     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14774
14775     block_index = -1;
14776
14777     frame_set = &tng_data->current_trajectory_frame_set;
14778     first_frame = frame_set->first_frame;
14779
14780     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14781     if(stat != TNG_SUCCESS)
14782     {
14783         return(stat);
14784     }
14785
14786
14787     /* Do not re-read the frame set. */
14788     if(first_frame != frame_set->first_frame ||
14789        frame_set->n_data_blocks <= 0)
14790     {
14791         tng_block_init(&block);
14792         file_pos = ftell(tng_data->input_file);
14793         /* Read all blocks until next frame set block */
14794         stat = tng_block_header_read(tng_data, block);
14795         while(file_pos < tng_data->input_file_len &&
14796             stat != TNG_CRITICAL &&
14797             block->id != TNG_TRAJECTORY_FRAME_SET)
14798         {
14799             stat = tng_block_read_next(tng_data, block,
14800                                     hash_mode);
14801             if(stat != TNG_CRITICAL)
14802             {
14803                 file_pos = ftell(tng_data->input_file);
14804                 if(file_pos < tng_data->input_file_len)
14805                 {
14806                     stat = tng_block_header_read(tng_data, block);
14807                 }
14808             }
14809         }
14810         tng_block_destroy(&block);
14811         if(stat == TNG_CRITICAL)
14812         {
14813             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14814                     file_pos, __FILE__, __LINE__);
14815             return(stat);
14816         }
14817     }
14818
14819
14820     /* See if there is a data block of this ID.
14821      * Start checking the last read frame set */
14822     for(i = frame_set->n_data_blocks; i-- ;)
14823     {
14824         data = &frame_set->tr_data[i];
14825         if(data->block_id == block_id)
14826         {
14827             block_index = i;
14828             break;
14829         }
14830     }
14831
14832     if(block_index < 0)
14833     {
14834         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
14835                 block_id, __FILE__, __LINE__);
14836         return(TNG_FAILURE);
14837     }
14838
14839     n_frames = end_frame_nr - start_frame_nr + 1;
14840     *n_values_per_frame = data->n_values_per_frame;
14841     *type = data->datatype;
14842
14843     if(*values == 0)
14844     {
14845         if(tng_data_values_alloc(tng_data, values, n_frames,
14846                                  *n_values_per_frame,
14847                                  *type) != TNG_SUCCESS)
14848         {
14849             return(TNG_CRITICAL);
14850         }
14851     }
14852
14853     current_frame_pos = start_frame_nr - frame_set->first_frame;
14854     /* It's not very elegant to reuse so much of the code in the different case
14855      * statements, but it's unnecessarily slow to have the switch-case block
14856      * inside the for loops. */
14857     switch(*type)
14858     {
14859     case TNG_CHAR_DATA:
14860         for(i=0; i<n_frames; i++)
14861         {
14862             if(current_frame_pos == frame_set->n_frames)
14863             {
14864                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14865                 if(stat != TNG_SUCCESS)
14866                 {
14867                     return(stat);
14868                 }
14869                 current_frame_pos = 0;
14870             }
14871             for(j=*n_values_per_frame; j--;)
14872             {
14873                 len = strlen(data->strings[current_frame_pos][j]) + 1;
14874                 (*values)[i][j].c = malloc(len);
14875                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
14876             }
14877             current_frame_pos++;
14878         }
14879         break;
14880     case TNG_INT_DATA:
14881         size = sizeof(int);
14882         for(i=0; i<n_frames; i++)
14883         {
14884             if(current_frame_pos == frame_set->n_frames)
14885             {
14886                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14887                 if(stat != TNG_SUCCESS)
14888                 {
14889                     return(stat);
14890                 }
14891                 current_frame_pos = 0;
14892             }
14893             for(j=*n_values_per_frame; j--;)
14894             {
14895                 (*values)[i][j].i = *(int *)((char *)data->values + size *
14896                                             (current_frame_pos *
14897                                              (*n_values_per_frame) + j));
14898             }
14899             current_frame_pos++;
14900         }
14901         break;
14902     case TNG_FLOAT_DATA:
14903         size = sizeof(float);
14904         for(i=0; i<n_frames; i++)
14905         {
14906             if(current_frame_pos == frame_set->n_frames)
14907             {
14908                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14909                 if(stat != TNG_SUCCESS)
14910                 {
14911                     return(stat);
14912                 }
14913                 current_frame_pos = 0;
14914             }
14915             for(j=*n_values_per_frame; j--;)
14916             {
14917                 (*values)[i][j].f = *(float *)((char *)data->values + size *
14918                                                (current_frame_pos *
14919                                                 (*n_values_per_frame) + j));
14920             }
14921             current_frame_pos++;
14922         }
14923         break;
14924     case TNG_DOUBLE_DATA:
14925     default:
14926         size = sizeof(double);
14927         for(i=0; i<n_frames; i++)
14928         {
14929             if(current_frame_pos == frame_set->n_frames)
14930             {
14931                 stat = tng_frame_set_read_next(tng_data, hash_mode);
14932                 if(stat != TNG_SUCCESS)
14933                 {
14934                     return(stat);
14935                 }
14936                 current_frame_pos = 0;
14937             }
14938             for(j=*n_values_per_frame; j--;)
14939             {
14940                 (*values)[i][j].d = *(double *)((char *)data->values + size *
14941                                                 (current_frame_pos *
14942                                                  (*n_values_per_frame) + j));
14943             }
14944             current_frame_pos++;
14945         }
14946     }
14947
14948     data->last_retrieved_frame = end_frame_nr;
14949
14950     return(TNG_SUCCESS);
14951 }
14952
14953 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
14954                 (tng_trajectory_t tng_data,
14955                  const int64_t block_id,
14956                  const int64_t start_frame_nr,
14957                  const int64_t end_frame_nr,
14958                  const char hash_mode,
14959                  void **values,
14960                  int64_t *stride_length,
14961                  int64_t *n_values_per_frame,
14962                  char *type)
14963 {
14964     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
14965     int64_t file_pos, current_frame_pos, data_size, frame_size;
14966     int64_t last_frame_pos;
14967     int size;
14968     tng_trajectory_frame_set_t frame_set;
14969     tng_non_particle_data_t np_data;
14970     tng_gen_block_t block;
14971     void *current_values = 0, *temp;
14972     tng_function_status stat;
14973
14974     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14975     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
14976     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14977     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14978     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14979
14980     frame_set = &tng_data->current_trajectory_frame_set;
14981     first_frame = frame_set->first_frame;
14982
14983     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14984     if(stat != TNG_SUCCESS)
14985     {
14986         return(stat);
14987     }
14988
14989     /* Do not re-read the frame set and only need the requested block. */
14990     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
14991     stat = tng_data_find(tng_data, block_id, &np_data);
14992     if(first_frame != frame_set->first_frame ||
14993        stat != TNG_SUCCESS)
14994     {
14995         tng_block_init(&block);
14996         if(stat != TNG_SUCCESS)
14997         {
14998             fseek(tng_data->input_file,
14999                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
15000                   SEEK_SET);
15001             stat = tng_block_header_read(tng_data, block);
15002             if(stat != TNG_SUCCESS)
15003             {
15004                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15005                         __FILE__, __LINE__);
15006                 return(stat);
15007             }
15008
15009             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15010         }
15011         file_pos = ftell(tng_data->input_file);
15012         /* Read until next frame set block */
15013         stat = tng_block_header_read(tng_data, block);
15014         while(file_pos < tng_data->input_file_len &&
15015             stat != TNG_CRITICAL &&
15016             block->id != TNG_TRAJECTORY_FRAME_SET)
15017         {
15018             if(block->id == block_id)
15019             {
15020                 stat = tng_block_read_next(tng_data, block,
15021                                         hash_mode);
15022                 if(stat != TNG_CRITICAL)
15023                 {
15024                     file_pos = ftell(tng_data->input_file);
15025                     if(file_pos < tng_data->input_file_len)
15026                     {
15027                         stat = tng_block_header_read(tng_data, block);
15028                     }
15029                 }
15030             }
15031             else
15032             {
15033                 file_pos += block->block_contents_size + block->header_contents_size;
15034                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15035                 if(file_pos < tng_data->input_file_len)
15036                 {
15037                     stat = tng_block_header_read(tng_data, block);
15038                 }
15039             }
15040         }
15041         tng_block_destroy(&block);
15042         if(stat == TNG_CRITICAL)
15043         {
15044             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15045                     file_pos, __FILE__, __LINE__);
15046             return(stat);
15047         }
15048     }
15049
15050     stat = tng_data_find(tng_data, block_id, &np_data);
15051     if(stat != TNG_SUCCESS)
15052     {
15053         return(stat);
15054     }
15055
15056     stat = tng_data_vector_get(tng_data, block_id, &current_values,
15057                                &n_frames, stride_length,
15058                                n_values_per_frame, type);
15059
15060     if(stat != TNG_SUCCESS)
15061     {
15062         if(current_values)
15063         {
15064             free(current_values);
15065         }
15066         return(stat);
15067     }
15068
15069     if(n_frames == 1 && n_frames < frame_set->n_frames)
15070     {
15071         tot_n_frames = 1;
15072     }
15073     else
15074     {
15075         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15076     }
15077
15078     switch(*type)
15079     {
15080     case TNG_CHAR_DATA:
15081         return(TNG_FAILURE);
15082     case TNG_INT_DATA:
15083         size = sizeof(int64_t);
15084         break;
15085     case TNG_FLOAT_DATA:
15086         size = sizeof(float);
15087         break;
15088     case TNG_DOUBLE_DATA:
15089     default:
15090         size = sizeof(double);
15091     }
15092
15093     n_frames_div = (tot_n_frames % *stride_length) ?
15094                  tot_n_frames / *stride_length + 1:
15095                  tot_n_frames / *stride_length;
15096     data_size = n_frames_div * size * (*n_values_per_frame);
15097
15098 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15099               size, n_frames_div, data_size);
15100 */
15101     temp = realloc(*values, data_size);
15102     if(!temp)
15103     {
15104         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15105                data_size, __FILE__, __LINE__);
15106         free(*values);
15107         *values = 0;
15108         return(TNG_CRITICAL);
15109     }
15110
15111     *values = temp;
15112
15113     if( n_frames == 1 && n_frames < frame_set->n_frames)
15114     {
15115         memcpy(*values, current_values, size * (*n_values_per_frame));
15116     }
15117     else
15118     {
15119         current_frame_pos = start_frame_nr - frame_set->first_frame;
15120
15121         frame_size = size * (*n_values_per_frame);
15122
15123         last_frame_pos = tng_min_i64(n_frames,
15124                                      end_frame_nr - start_frame_nr);
15125
15126         n_frames_div = current_frame_pos / *stride_length;
15127         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15128                        last_frame_pos / *stride_length + 1:
15129                        last_frame_pos / *stride_length;
15130         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15131
15132         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15133                n_frames_div_2 * frame_size);
15134
15135         current_frame_pos += n_frames - current_frame_pos;
15136
15137         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15138         {
15139             stat = tng_frame_set_read_next(tng_data, hash_mode);
15140             if(stat != TNG_SUCCESS)
15141             {
15142                 if(current_values)
15143                 {
15144                     free(current_values);
15145                 }
15146                 free(*values);
15147                 *values = 0;
15148                 return(stat);
15149             }
15150
15151             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15152                                     &n_frames, stride_length,
15153                                     n_values_per_frame, type);
15154
15155             if(stat != TNG_SUCCESS)
15156             {
15157                 if(current_values)
15158                 {
15159                     free(current_values);
15160                 }
15161                 free(*values);
15162                 *values = 0;
15163                 return(stat);
15164             }
15165
15166             last_frame_pos = tng_min_i64(n_frames,
15167                                          end_frame_nr - current_frame_pos);
15168
15169             n_frames_div = current_frame_pos / *stride_length;
15170             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15171                            last_frame_pos / *stride_length + 1:
15172                            last_frame_pos / *stride_length;
15173             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15174
15175             memcpy(((char *)*values) + n_frames_div * frame_size,
15176                    current_values,
15177                    n_frames_div_2 * frame_size);
15178
15179             current_frame_pos += n_frames;
15180         }
15181     }
15182
15183     if(current_values)
15184     {
15185         free(current_values);
15186     }
15187
15188     np_data->last_retrieved_frame = end_frame_nr;
15189
15190     return(TNG_SUCCESS);
15191 }
15192
15193 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15194                 (tng_trajectory_t tng_data,
15195                  const int64_t block_id,
15196                  union data_values ****values,
15197                  int64_t *n_frames,
15198                  int64_t *n_particles,
15199                  int64_t *n_values_per_frame,
15200                  char *type)
15201 {
15202     int64_t i, j, k, mapping, file_pos, i_step, block_index;
15203     int size;
15204     size_t len;
15205     tng_particle_data_t data;
15206     tng_trajectory_frame_set_t frame_set;
15207     tng_gen_block_t block;
15208     char block_type_flag;
15209     tng_function_status stat;
15210
15211     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15212     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15213     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15214     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15215     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15216
15217     frame_set = &tng_data->current_trajectory_frame_set;
15218
15219     block_index = -1;
15220     data = 0;
15221
15222     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15223     {
15224         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15225         {
15226             block_type_flag = TNG_TRAJECTORY_BLOCK;
15227         }
15228         else
15229         {
15230             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15231         }
15232
15233         tng_block_init(&block);
15234         file_pos = ftell(tng_data->input_file);
15235         /* Read all blocks until next frame set block */
15236         stat = tng_block_header_read(tng_data, block);
15237         while(file_pos < tng_data->input_file_len &&
15238                 stat != TNG_CRITICAL &&
15239                 block->id != TNG_TRAJECTORY_FRAME_SET)
15240         {
15241             /* Use hash by default */
15242             stat = tng_block_read_next(tng_data, block,
15243                                     TNG_USE_HASH);
15244             if(stat != TNG_CRITICAL)
15245             {
15246                 file_pos = ftell(tng_data->input_file);
15247                 if(file_pos < tng_data->input_file_len)
15248                 {
15249                     stat = tng_block_header_read(tng_data, block);
15250                 }
15251             }
15252         }
15253         tng_block_destroy(&block);
15254         if(stat == TNG_CRITICAL)
15255         {
15256             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15257                     file_pos, __FILE__, __LINE__);
15258             return(stat);
15259         }
15260
15261         for(i = frame_set->n_particle_data_blocks; i-- ;)
15262         {
15263             data = &frame_set->tr_particle_data[i];
15264             if(data->block_id == block_id)
15265             {
15266                 block_index = i;
15267                 block_type_flag = TNG_TRAJECTORY_BLOCK;
15268                 break;
15269             }
15270         }
15271         if(block_index < 0)
15272         {
15273             return(TNG_FAILURE);
15274         }
15275     }
15276     else
15277     {
15278         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15279         {
15280             block_type_flag = TNG_TRAJECTORY_BLOCK;
15281         }
15282         else
15283         {
15284             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15285         }
15286     }
15287
15288     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15289        tng_data->var_num_atoms_flag)
15290     {
15291         *n_particles = frame_set->n_particles;
15292     }
15293     else
15294     {
15295         *n_particles = tng_data->n_particles;
15296     }
15297
15298     *n_frames = tng_max_i64(1, data->n_frames);
15299     *n_values_per_frame = data->n_values_per_frame;
15300     *type = data->datatype;
15301
15302     if(*values == 0)
15303     {
15304         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
15305                                          *n_particles, *n_values_per_frame,
15306                                          *type)
15307             != TNG_SUCCESS)
15308         {
15309             return(TNG_CRITICAL);
15310         }
15311     }
15312
15313     /* It's not very elegant to reuse so much of the code in the different case
15314      * statements, but it's unnecessarily slow to have the switch-case block
15315      * inside the for loops. */
15316     switch(*type)
15317     {
15318     case TNG_CHAR_DATA:
15319         for(i=*n_frames; i--;)
15320         {
15321             for(j=*n_particles; j--;)
15322             {
15323                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15324                 for(k=*n_values_per_frame; k--;)
15325                 {
15326                     len = strlen(data->strings[i][j][k]) + 1;
15327                     (*values)[i][mapping][k].c = malloc(len);
15328                     strncpy((*values)[i][mapping][k].c,
15329                             data->strings[i][j][k], len);
15330                 }
15331             }
15332         }
15333         break;
15334     case TNG_INT_DATA:
15335         size = sizeof(int);
15336         i_step = (*n_particles) * (*n_values_per_frame);
15337         for(i=*n_frames; i--;)
15338         {
15339             for(j=*n_particles; j--;)
15340             {
15341                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15342                 for(k=*n_values_per_frame; k--;)
15343                 {
15344                     (*values)[i][mapping][k].i = *(int *)
15345                                                  ((char *)data->values + size *
15346                                                  (i * i_step + j *
15347                                                   (*n_values_per_frame) + k));
15348                 }
15349             }
15350         }
15351         break;
15352     case TNG_FLOAT_DATA:
15353         size = sizeof(float);
15354         i_step = (*n_particles) * (*n_values_per_frame);
15355         for(i=*n_frames; i--;)
15356         {
15357             for(j=*n_particles; j--;)
15358             {
15359                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15360                 for(k=*n_values_per_frame; k--;)
15361                 {
15362                     (*values)[i][mapping][k].f = *(float *)
15363                                                  ((char *)data->values + size *
15364                                                  (i * i_step + j *
15365                                                   (*n_values_per_frame) + k));
15366                 }
15367             }
15368         }
15369         break;
15370     case TNG_DOUBLE_DATA:
15371     default:
15372         size = sizeof(double);
15373         i_step = (*n_particles) * (*n_values_per_frame);
15374         for(i=*n_frames; i--;)
15375         {
15376             for(j=*n_particles; j--;)
15377             {
15378                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15379                 for(k=*n_values_per_frame; k--;)
15380                 {
15381                     (*values)[i][mapping][k].d = *(double *)
15382                                                  ((char *)data->values + size *
15383                                                  (i * i_step + j *
15384                                                   (*n_values_per_frame) + k));
15385                 }
15386             }
15387         }
15388     }
15389
15390     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15391
15392     return(TNG_SUCCESS);
15393 }
15394
15395 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
15396                 (tng_trajectory_t tng_data,
15397                  const int64_t block_id,
15398                  void **values,
15399                  int64_t *n_frames,
15400                  int64_t *stride_length,
15401                  int64_t *n_particles,
15402                  int64_t *n_values_per_frame,
15403                  char *type)
15404 {
15405     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
15406     int64_t block_index;
15407     int size;
15408     tng_particle_data_t data;
15409     tng_trajectory_frame_set_t frame_set;
15410     tng_gen_block_t block;
15411     void *temp;
15412     char block_type_flag;
15413     tng_function_status stat;
15414
15415     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15416     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15417     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15418     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15419     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15420
15421     frame_set = &tng_data->current_trajectory_frame_set;
15422
15423     block_index = -1;
15424     data = 0;
15425
15426     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15427     {
15428         tng_block_init(&block);
15429         file_pos = ftell(tng_data->input_file);
15430         /* Read all blocks until next frame set block */
15431         stat = tng_block_header_read(tng_data, block);
15432         while(file_pos < tng_data->input_file_len &&
15433                 stat != TNG_CRITICAL &&
15434                 block->id != TNG_TRAJECTORY_FRAME_SET)
15435         {
15436             /* Use hash by default */
15437             stat = tng_block_read_next(tng_data, block,
15438                                     TNG_USE_HASH);
15439             if(stat != TNG_CRITICAL)
15440             {
15441                 file_pos = ftell(tng_data->input_file);
15442                 if(file_pos < tng_data->input_file_len)
15443                 {
15444                     stat = tng_block_header_read(tng_data, block);
15445                 }
15446             }
15447         }
15448         tng_block_destroy(&block);
15449         if(stat == TNG_CRITICAL)
15450         {
15451             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15452                     file_pos, __FILE__, __LINE__);
15453             return(stat);
15454         }
15455
15456         for(i = frame_set->n_particle_data_blocks; i-- ;)
15457         {
15458             data = &frame_set->tr_particle_data[i];
15459             if(data->block_id == block_id)
15460             {
15461                 block_index = i;
15462                 break;
15463             }
15464         }
15465         if(block_index < 0)
15466         {
15467             return(TNG_FAILURE);
15468         }
15469     }
15470
15471     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15472     {
15473         block_type_flag = TNG_TRAJECTORY_BLOCK;
15474     }
15475     else
15476     {
15477         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
15478     }
15479
15480    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15481       tng_data->var_num_atoms_flag)
15482     {
15483         *n_particles = frame_set->n_particles;
15484     }
15485     else
15486     {
15487         *n_particles = tng_data->n_particles;
15488     }
15489
15490     *type = data->datatype;
15491
15492     switch(*type)
15493     {
15494     case TNG_CHAR_DATA:
15495         return(TNG_FAILURE);
15496     case TNG_INT_DATA:
15497         size = sizeof(int64_t);
15498         break;
15499     case TNG_FLOAT_DATA:
15500         size = sizeof(float);
15501         break;
15502     case TNG_DOUBLE_DATA:
15503     default:
15504         size = sizeof(double);
15505     }
15506
15507     *n_frames = tng_max_i64(1, data->n_frames);
15508     *n_values_per_frame = data->n_values_per_frame;
15509     *stride_length = data->stride_length;
15510
15511     n_frames_div = (*n_frames % *stride_length) ?
15512                    *n_frames / *stride_length + 1:
15513                    *n_frames / *stride_length;
15514
15515     data_size = n_frames_div * size * (*n_particles) *
15516                 (*n_values_per_frame);
15517
15518     temp = realloc(*values, data_size);
15519     if(!temp)
15520     {
15521         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15522                data_size, __FILE__, __LINE__);
15523         free(*values);
15524         *values = 0;
15525         return(TNG_CRITICAL);
15526     }
15527
15528     *values = temp;
15529
15530     if(frame_set->n_mapping_blocks <= 0)
15531     {
15532         memcpy(*values, data->values, data_size);
15533     }
15534     else
15535     {
15536         i_step = (*n_particles) * (*n_values_per_frame);
15537         for(i = *n_frames; i--;)
15538         {
15539             for(j = *n_particles; j--;)
15540             {
15541                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15542                 memcpy(((char *)*values) + size * (i * i_step + mapping *
15543                        (*n_values_per_frame)),
15544                        (char *)data->values + size *
15545                        (i * i_step + j * (*n_values_per_frame)),
15546                        size * (*n_values_per_frame));
15547             }
15548         }
15549     }
15550
15551     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15552
15553     return(TNG_SUCCESS);
15554 }
15555
15556 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
15557                 (tng_trajectory_t tng_data,
15558                  const int64_t block_id,
15559                  const int64_t start_frame_nr,
15560                  const int64_t end_frame_nr,
15561                  const char hash_mode,
15562                  union data_values ****values,
15563                  int64_t *n_particles,
15564                  int64_t *n_values_per_frame,
15565                  char *type)
15566 {
15567     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
15568     int64_t first_frame, block_index;
15569     int size;
15570     size_t len;
15571     tng_particle_data_t data;
15572     tng_trajectory_frame_set_t frame_set;
15573     tng_gen_block_t block;
15574     char block_type_flag;
15575     tng_function_status stat;
15576
15577     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15578     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15579     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15580     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15581     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15582
15583     block_index = -1;
15584
15585     frame_set = &tng_data->current_trajectory_frame_set;
15586     first_frame = frame_set->first_frame;
15587
15588     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15589     if(stat != TNG_SUCCESS)
15590     {
15591         return(stat);
15592     }
15593
15594     /* Do not re-read the frame set. */
15595     if(first_frame != frame_set->first_frame ||
15596        frame_set->n_particle_data_blocks <= 0)
15597     {
15598         tng_block_init(&block);
15599         file_pos = ftell(tng_data->input_file);
15600         /* Read all blocks until next frame set block */
15601         stat = tng_block_header_read(tng_data, block);
15602         while(file_pos < tng_data->input_file_len &&
15603                 stat != TNG_CRITICAL &&
15604                 block->id != TNG_TRAJECTORY_FRAME_SET)
15605         {
15606             stat = tng_block_read_next(tng_data, block,
15607                                     hash_mode);
15608             if(stat != TNG_CRITICAL)
15609             {
15610                 file_pos = ftell(tng_data->input_file);
15611                 if(file_pos < tng_data->input_file_len)
15612                 {
15613                     stat = tng_block_header_read(tng_data, block);
15614                 }
15615             }
15616         }
15617         tng_block_destroy(&block);
15618         if(stat == TNG_CRITICAL)
15619         {
15620             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15621                     file_pos, __FILE__, __LINE__);
15622             return(stat);
15623         }
15624     }
15625
15626     /* See if there is already a data block of this ID.
15627      * Start checking the last read frame set */
15628     for(i = frame_set->n_particle_data_blocks; i-- ;)
15629     {
15630         data = &frame_set->tr_particle_data[i];
15631         if(data->block_id == block_id)
15632         {
15633             block_index = i;
15634             block_type_flag = TNG_TRAJECTORY_BLOCK;
15635             break;
15636         }
15637     }
15638
15639     if(block_index < 0)
15640     {
15641         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
15642                 block_id, __FILE__, __LINE__);
15643         return(TNG_FAILURE);
15644     }
15645
15646     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
15647        tng_data->var_num_atoms_flag)
15648     {
15649         *n_particles = frame_set->n_particles;
15650     }
15651     else
15652     {
15653         *n_particles = tng_data->n_particles;
15654     }
15655
15656     n_frames = end_frame_nr - start_frame_nr + 1;
15657     *n_values_per_frame = data->n_values_per_frame;
15658     *type = data->datatype;
15659
15660     if(*values == 0)
15661     {
15662         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
15663                                          *n_particles, *n_values_per_frame,
15664                                          *type)
15665             != TNG_SUCCESS)
15666         {
15667             return(TNG_CRITICAL);
15668         }
15669     }
15670
15671     current_frame_pos = start_frame_nr - frame_set->first_frame;
15672     /* It's not very elegant to reuse so much of the code in the different case
15673      * statements, but it's unnecessarily slow to have the switch-case block
15674      * inside the for loops. */
15675     switch(*type)
15676     {
15677     case TNG_CHAR_DATA:
15678         for(i=0; i<n_frames; i++)
15679         {
15680             if(current_frame_pos == frame_set->n_frames)
15681             {
15682                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15683                 if(stat != TNG_SUCCESS)
15684                 {
15685                     return(stat);
15686                 }
15687                 current_frame_pos = 0;
15688             }
15689             for(j=*n_particles; j--;)
15690             {
15691                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15692                 for(k=*n_values_per_frame; k--;)
15693                 {
15694                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
15695                     (*values)[i][mapping][k].c = malloc(len);
15696                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
15697                 }
15698             }
15699             current_frame_pos++;
15700         }
15701         break;
15702     case TNG_INT_DATA:
15703         size = sizeof(int);
15704         i_step = (*n_particles) * (*n_values_per_frame);
15705         for(i=0; i<n_frames; i++)
15706         {
15707             if(current_frame_pos == frame_set->n_frames)
15708             {
15709                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15710                 if(stat != TNG_SUCCESS)
15711                 {
15712                     return(stat);
15713                 }
15714                 current_frame_pos = 0;
15715             }
15716             for(j=*n_particles; j--;)
15717             {
15718                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15719                 for(k=*n_values_per_frame; k--;)
15720                 {
15721                     (*values)[i][mapping][k].i = *(int *)
15722                                                  ((char *)data->values + size *
15723                                                   (current_frame_pos *
15724                                                    i_step + j *
15725                                                    (*n_values_per_frame) + k));
15726                 }
15727             }
15728             current_frame_pos++;
15729         }
15730         break;
15731     case TNG_FLOAT_DATA:
15732         size = sizeof(float);
15733         i_step = (*n_particles) * (*n_values_per_frame);
15734         for(i=0; i<n_frames; i++)
15735         {
15736             if(current_frame_pos == frame_set->n_frames)
15737             {
15738                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15739                 if(stat != TNG_SUCCESS)
15740                 {
15741                     return(stat);
15742                 }
15743                 current_frame_pos = 0;
15744             }
15745             for(j=*n_particles; j--;)
15746             {
15747                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15748                 for(k=*n_values_per_frame; k--;)
15749                 {
15750                     (*values)[i][mapping][k].f = *(float *)
15751                                                  ((char *)data->values + size *
15752                                                   (current_frame_pos *
15753                                                    i_step + j *
15754                                                    (*n_values_per_frame) + k));
15755                 }
15756             }
15757             current_frame_pos++;
15758         }
15759         break;
15760     case TNG_DOUBLE_DATA:
15761     default:
15762         size = sizeof(double);
15763         i_step = (*n_particles) * (*n_values_per_frame);
15764         for(i=0; i<n_frames; i++)
15765         {
15766             if(current_frame_pos == frame_set->n_frames)
15767             {
15768                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15769                 if(stat != TNG_SUCCESS)
15770                 {
15771                     return(stat);
15772                 }
15773                 current_frame_pos = 0;
15774             }
15775             for(j=*n_particles; j--;)
15776             {
15777                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
15778                 for(k=*n_values_per_frame; k--;)
15779                 {
15780                     (*values)[i][mapping][k].d = *(double *)
15781                                                  ((char *)data->values + size *
15782                                                   (current_frame_pos *
15783                                                    i_step + j *
15784                                                    (*n_values_per_frame) + k));
15785                 }
15786             }
15787             current_frame_pos++;
15788         }
15789     }
15790
15791     data->last_retrieved_frame = end_frame_nr;
15792
15793     return(TNG_SUCCESS);
15794 }
15795
15796 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
15797                 (tng_trajectory_t tng_data,
15798                  const int64_t block_id,
15799                  const int64_t start_frame_nr,
15800                  const int64_t end_frame_nr,
15801                  const char hash_mode,
15802                  void **values,
15803                  int64_t *n_particles,
15804                  int64_t *stride_length,
15805                  int64_t *n_values_per_frame,
15806                  char *type)
15807 {
15808     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15809     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
15810     int size;
15811     tng_trajectory_frame_set_t frame_set;
15812     tng_particle_data_t p_data;
15813     tng_gen_block_t block;
15814     void *current_values = 0, *temp;
15815     tng_function_status stat;
15816
15817     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15818     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15819     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15820     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15821     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15822     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15823
15824     frame_set = &tng_data->current_trajectory_frame_set;
15825     first_frame = frame_set->first_frame;
15826
15827     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15828     if(stat != TNG_SUCCESS)
15829     {
15830         return(stat);
15831     }
15832
15833     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
15834     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
15835     stat = tng_particle_data_find(tng_data, block_id, &p_data);
15836     if(first_frame != frame_set->first_frame ||
15837        stat != TNG_SUCCESS)
15838     {
15839         tng_block_init(&block);
15840         if(stat != TNG_SUCCESS)
15841         {
15842             fseek(tng_data->input_file,
15843                   (long)tng_data->current_trajectory_frame_set_input_file_pos,
15844                   SEEK_SET);
15845             stat = tng_block_header_read(tng_data, block);
15846             if(stat != TNG_SUCCESS)
15847             {
15848                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15849                         __FILE__, __LINE__);
15850                 return(stat);
15851             }
15852
15853             fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15854         }
15855         file_pos = ftell(tng_data->input_file);
15856         /* Read until next frame set block */
15857         stat = tng_block_header_read(tng_data, block);
15858         while(file_pos < tng_data->input_file_len &&
15859             stat != TNG_CRITICAL &&
15860             block->id != TNG_TRAJECTORY_FRAME_SET)
15861         {
15862             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
15863             {
15864                 stat = tng_block_read_next(tng_data, block,
15865                                         hash_mode);
15866                 if(stat != TNG_CRITICAL)
15867                 {
15868                     file_pos = ftell(tng_data->input_file);
15869                     if(file_pos < tng_data->input_file_len)
15870                     {
15871                         stat = tng_block_header_read(tng_data, block);
15872                     }
15873                 }
15874             }
15875             else
15876             {
15877                 file_pos += block->block_contents_size + block->header_contents_size;
15878                 fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
15879                 if(file_pos < tng_data->input_file_len)
15880                 {
15881                     stat = tng_block_header_read(tng_data, block);
15882                 }
15883             }
15884         }
15885         tng_block_destroy(&block);
15886         if(stat == TNG_CRITICAL)
15887         {
15888             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15889                     file_pos, __FILE__, __LINE__);
15890             return(stat);
15891         }
15892     }
15893     stat = tng_particle_data_find(tng_data, block_id, &p_data);
15894     if(stat != TNG_SUCCESS)
15895     {
15896         return(stat);
15897     }
15898
15899     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
15900                                         &n_frames, stride_length, n_particles,
15901                                         n_values_per_frame, type);
15902
15903     if(stat != TNG_SUCCESS || *n_particles == 0)
15904     {
15905         if(current_values)
15906         {
15907             free(current_values);
15908         }
15909         return(stat);
15910     }
15911
15912     if(n_frames == 1 && n_frames < frame_set->n_frames)
15913     {
15914         tot_n_frames = 1;
15915     }
15916     else
15917     {
15918         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15919     }
15920
15921     switch(*type)
15922     {
15923     case TNG_CHAR_DATA:
15924         return(TNG_FAILURE);
15925     case TNG_INT_DATA:
15926         size = sizeof(int64_t);
15927         break;
15928     case TNG_FLOAT_DATA:
15929         size = sizeof(float);
15930         break;
15931     case TNG_DOUBLE_DATA:
15932     default:
15933         size = sizeof(double);
15934     }
15935
15936     n_frames_div = (tot_n_frames % *stride_length) ?
15937                  tot_n_frames / *stride_length + 1:
15938                  tot_n_frames / *stride_length;
15939
15940     data_size = n_frames_div * size * (*n_particles) *
15941                 (*n_values_per_frame);
15942
15943     temp = realloc(*values, data_size);
15944     if(!temp)
15945     {
15946         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15947                data_size, __FILE__, __LINE__);
15948         free(*values);
15949         *values = 0;
15950         return(TNG_CRITICAL);
15951     }
15952
15953     *values = temp;
15954
15955     if( n_frames == 1 && n_frames < frame_set->n_frames)
15956     {
15957         memcpy(*values, current_values, size * (*n_particles) *
15958                (*n_values_per_frame));
15959     }
15960     else
15961     {
15962         current_frame_pos = start_frame_nr - frame_set->first_frame;
15963
15964         frame_size = size * (*n_particles) * (*n_values_per_frame);
15965
15966         last_frame_pos = tng_min_i64(n_frames,
15967                                      end_frame_nr - start_frame_nr);
15968
15969         n_frames_div = current_frame_pos / *stride_length;
15970         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15971                        last_frame_pos / *stride_length + 1:
15972                        last_frame_pos / *stride_length;
15973         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
15974
15975         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15976                n_frames_div_2 * frame_size);
15977
15978         current_frame_pos += n_frames - current_frame_pos;
15979
15980         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15981         {
15982             stat = tng_frame_set_read_next(tng_data, hash_mode);
15983             if(stat != TNG_SUCCESS)
15984             {
15985                 if(current_values)
15986                 {
15987                     free(current_values);
15988                 }
15989                 free(*values);
15990                 *values = 0;
15991                 return(stat);
15992             }
15993
15994             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
15995                                                 &n_frames, stride_length, n_particles,
15996                                                 n_values_per_frame, type);
15997
15998             if(stat != TNG_SUCCESS)
15999             {
16000                 if(current_values)
16001                 {
16002                     free(current_values);
16003                 }
16004                 free(*values);
16005                 *values = 0;
16006                 return(stat);
16007             }
16008
16009             last_frame_pos = tng_min_i64(n_frames,
16010                                          end_frame_nr - current_frame_pos);
16011
16012             n_frames_div = current_frame_pos / *stride_length;
16013             n_frames_div_2 = (last_frame_pos % *stride_length) ?
16014                            last_frame_pos / *stride_length + 1:
16015                            last_frame_pos / *stride_length;
16016             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
16017
16018             memcpy(((char *)*values) + n_frames_div * frame_size,
16019                    current_values,
16020                    n_frames_div_2 * frame_size);
16021
16022             current_frame_pos += n_frames;
16023         }
16024     }
16025
16026     if(current_values)
16027     {
16028         free(current_values);
16029     }
16030
16031     p_data->last_retrieved_frame = end_frame_nr;
16032
16033     return(TNG_SUCCESS);
16034 }
16035
16036 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
16037                 (const tng_trajectory_t tng_data,
16038                  const int64_t block_id,
16039                  int64_t frame,
16040                  int64_t *stride_length)
16041 {
16042     tng_function_status stat;
16043     tng_non_particle_data_t np_data;
16044     tng_particle_data_t p_data;
16045     long orig_file_pos, file_pos;
16046     int is_particle_data;
16047
16048     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
16049     {
16050         frame = 0;
16051     }
16052
16053     if(frame >= 0)
16054     {
16055         stat = tng_frame_set_of_frame_find(tng_data, frame);
16056         if(stat != TNG_SUCCESS)
16057         {
16058             return(stat);
16059         }
16060     }
16061     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
16062     stat = tng_data_find(tng_data, block_id, &np_data);
16063     if(stat != TNG_SUCCESS)
16064     {
16065         stat = tng_particle_data_find(tng_data, block_id, &p_data);
16066         if(stat != TNG_SUCCESS)
16067         {
16068             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16069             /* If no specific frame was required read until this data block is found */
16070             if(frame < 0)
16071             {
16072                 file_pos = ftell(tng_data->input_file);
16073                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16074                 {
16075                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16076                     file_pos = ftell(tng_data->input_file);
16077                 }
16078             }
16079             if(stat != TNG_SUCCESS)
16080             {
16081                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16082
16083                 return(stat);
16084             }
16085             stat = tng_data_find(tng_data, block_id, &np_data);
16086             if(stat != TNG_SUCCESS)
16087             {
16088                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16089                 if(stat != TNG_SUCCESS)
16090                 {
16091                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16092
16093                     return(stat);
16094                 }
16095                 else
16096                 {
16097                     is_particle_data = 1;
16098                 }
16099             }
16100             else
16101             {
16102                 is_particle_data = 0;
16103             }
16104         }
16105         else
16106         {
16107             is_particle_data = 1;
16108         }
16109     }
16110     else
16111     {
16112         is_particle_data = 0;
16113     }
16114     if(is_particle_data)
16115     {
16116         *stride_length = p_data->stride_length;
16117     }
16118     else
16119     {
16120         *stride_length = np_data->stride_length;
16121     }
16122     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16123
16124     return(TNG_SUCCESS);
16125 }
16126
16127 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16128                 (const tng_trajectory_t tng_data,
16129                  char *time)
16130 {
16131     struct tm *time_data;
16132     time_t secs;
16133
16134     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16135     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16136
16137     secs = tng_data->time;
16138
16139     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16140     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16141              "%4d-%02d-%02d %02d:%02d:%02d",
16142              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16143              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16144
16145     return(TNG_SUCCESS);
16146 }
16147
16148
16149 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16150                 (const char *filename,
16151                  const char mode,
16152                  tng_trajectory_t *tng_data_p)
16153 {
16154     tng_function_status stat;
16155
16156     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16157
16158     if(mode != 'r' && mode != 'w' && mode != 'a')
16159     {
16160         return(TNG_FAILURE);
16161     }
16162
16163     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16164     {
16165         tng_trajectory_destroy(tng_data_p);
16166         return(TNG_CRITICAL);
16167     }
16168
16169     if(mode == 'r' || mode == 'a')
16170     {
16171         tng_input_file_set(*tng_data_p, filename);
16172
16173         /* Read the file headers */
16174         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16175
16176         tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16177     }
16178
16179     if(mode == 'w')
16180     {
16181         tng_output_file_set(*tng_data_p, filename);
16182     }
16183     else if(mode == 'a')
16184     {
16185         fseek((*tng_data_p)->input_file,
16186                 (long)(*tng_data_p)->last_trajectory_frame_set_input_file_pos,
16187                 SEEK_SET);
16188
16189         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
16190         if(stat != TNG_SUCCESS)
16191         {
16192             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
16193                    __FILE__, __LINE__);
16194         }
16195
16196         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
16197         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
16198         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
16199         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
16200         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
16201         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
16202         (*tng_data_p)->first_trajectory_frame_set_input_file_pos = -1;
16203         (*tng_data_p)->last_trajectory_frame_set_input_file_pos = -1;
16204         (*tng_data_p)->current_trajectory_frame_set_input_file_pos = -1;
16205         if((*tng_data_p)->input_file)
16206         {
16207             fclose((*tng_data_p)->input_file);
16208             (*tng_data_p)->input_file = 0;
16209         }
16210         if((*tng_data_p)->input_file_path)
16211         {
16212             free((*tng_data_p)->input_file_path);
16213             (*tng_data_p)->input_file_path = 0;
16214         }
16215         tng_output_append_file_set(*tng_data_p, filename);
16216
16217         fseek((*tng_data_p)->output_file, 0, SEEK_END);
16218     }
16219
16220     return(TNG_SUCCESS);
16221 }
16222
16223 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
16224                 (tng_trajectory_t *tng_data_p)
16225 {
16226     tng_trajectory_frame_set_t frame_set;
16227
16228     if(tng_data_p == 0)
16229     {
16230         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
16231                __FILE__, __LINE__);
16232         return(TNG_FAILURE);
16233     }
16234
16235     if(*tng_data_p == 0)
16236     {
16237         return(TNG_SUCCESS);
16238     }
16239
16240     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
16241
16242     if(frame_set->n_unwritten_frames > 0)
16243     {
16244         frame_set->n_frames = frame_set->n_unwritten_frames;
16245         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
16246     }
16247
16248     return(tng_trajectory_destroy(tng_data_p));
16249 }
16250
16251 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
16252                 (tng_trajectory_t tng_data,
16253                  const int64_t frame_nr,
16254                  double *time)
16255 {
16256     int64_t first_frame;
16257     tng_trajectory_frame_set_t frame_set;
16258     tng_function_status stat;
16259
16260     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16261     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16262
16263     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
16264     if(stat != TNG_SUCCESS)
16265     {
16266         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
16267                frame_nr, __FILE__, __LINE__);
16268         return(stat);
16269     }
16270
16271     frame_set = &tng_data->current_trajectory_frame_set;
16272     first_frame = frame_set->first_frame;
16273
16274     if(tng_data->time_per_frame <= 0)
16275     {
16276         return(TNG_FAILURE);
16277     }
16278
16279     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
16280
16281     return(TNG_SUCCESS);
16282 }
16283
16284 /*
16285 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
16286                 (tng_trajectory_t tng_data,
16287                  int64_t *n_mols,
16288                  int64_t **molecule_cnt_list,
16289                  tng_molecule_t *mols)
16290 {
16291     tng_trajectory_frame_set_t frame_set;
16292
16293     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16294     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
16295
16296     *n_mols = tng_data->n_molecules;
16297
16298     frame_set = &tng_data->current_trajectory_frame_set;
16299     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
16300     {
16301         *molecule_cnt_list = frame_set->molecule_cnt_list;
16302     }
16303     else
16304     {
16305         *molecule_cnt_list = tng_data->molecule_cnt_list;
16306     }
16307
16308     *mols = tng_data->molecules;
16309
16310     return(TNG_SUCCESS);
16311 }
16312 */
16313 /*
16314 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
16315                 (tng_trajectory_t tng_data,
16316                  const char *name,
16317                  const int64_t cnt,
16318                  tng_molecule_t *mol)
16319 {
16320     tng_function_status stat;
16321
16322     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
16323     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
16324
16325     stat = tng_molecule_add(tng_data, name, mol);
16326     if(stat != TNG_SUCCESS)
16327     {
16328         return(stat);
16329     }
16330     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
16331
16332     return(stat);
16333 }
16334 */
16335 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
16336                 (tng_trajectory_t tng_data,
16337                  const tng_molecule_t mol,
16338                  int64_t *n_particles,
16339                  char ***names,
16340                  char ***types,
16341                  char ***res_names,
16342                  int64_t **res_ids,
16343                  char ***chain_names,
16344                  int64_t **chain_ids)
16345 {
16346     tng_atom_t atom;
16347     tng_residue_t res;
16348     tng_chain_t chain;
16349     int64_t i;
16350     (void)tng_data;
16351
16352     *n_particles = mol->n_atoms;
16353
16354     *names = malloc(sizeof(char *) * *n_particles);
16355     *types = malloc(sizeof(char *) * *n_particles);
16356     *res_names = malloc(sizeof(char *) * *n_particles);
16357     *chain_names = malloc(sizeof(char *) * *n_particles);
16358     *res_ids = malloc(sizeof(int64_t) * *n_particles);
16359     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
16360
16361     for(i = 0; i < *n_particles; i++)
16362     {
16363         atom = &mol->atoms[i];
16364         res = atom->residue;
16365         chain = res->chain;
16366         (*names)[i] = malloc(strlen(atom->name));
16367         strcpy(*names[i], atom->name);
16368         (*types)[i] = malloc(strlen(atom->atom_type));
16369         strcpy(*types[i], atom->atom_type);
16370         (*res_names)[i] = malloc(strlen(res->name));
16371         strcpy(*res_names[i], res->name);
16372         (*chain_names)[i] = malloc(strlen(chain->name));
16373         strcpy(*chain_names[i], chain->name);
16374         (*res_ids)[i] = res->id;
16375         (*chain_ids)[i] = chain->id;
16376     }
16377
16378     return(TNG_SUCCESS);
16379 }
16380
16381 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
16382                 (tng_trajectory_t tng_data,
16383                  tng_molecule_t mol,
16384                  const int64_t n_particles,
16385                  const char **names,
16386                  const char **types,
16387                  const char **res_names,
16388                  const int64_t *res_ids,
16389                  const char **chain_names,
16390                  const int64_t *chain_ids)
16391 {
16392     int64_t i;
16393     tng_chain_t chain;
16394     tng_residue_t residue;
16395     tng_atom_t atom;
16396     tng_function_status stat;
16397
16398     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16399     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
16400     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
16401     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
16402     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
16403     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
16404     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
16405
16406     for(i = 0; i < n_particles; i++)
16407     {
16408         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
16409            &chain) == TNG_FAILURE)
16410         {
16411             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
16412                                           &chain);
16413             if(stat != TNG_SUCCESS)
16414             {
16415                 return(stat);
16416             }
16417         }
16418         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
16419            &residue) == TNG_FAILURE)
16420         {
16421             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
16422                                          &residue);
16423             if(stat != TNG_SUCCESS)
16424             {
16425                 return(stat);
16426             }
16427         }
16428         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
16429         if(stat != TNG_SUCCESS)
16430         {
16431             return(stat);
16432         }
16433     }
16434     return(TNG_SUCCESS);
16435 }
16436
16437 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
16438                 (tng_trajectory_t tng_data,
16439                  float **positions, int64_t *stride_length)
16440 {
16441     int64_t n_frames, n_particles, n_values_per_frame;
16442     char type;
16443     tng_function_status stat;
16444
16445     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16446     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16447     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16448
16449     stat = tng_num_frames_get(tng_data, &n_frames);
16450     if(stat != TNG_SUCCESS)
16451     {
16452         return(stat);
16453     }
16454
16455     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
16456                                                  0, n_frames - 1, TNG_USE_HASH,
16457                                                  (void **)positions,
16458                                                  &n_particles,
16459                                                  stride_length,
16460                                                  &n_values_per_frame,
16461                                                  &type);
16462
16463     return(stat);
16464 }
16465
16466 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
16467                 (tng_trajectory_t tng_data,
16468                  float **velocities, int64_t *stride_length)
16469 {
16470     int64_t n_frames, n_particles, n_values_per_frame;
16471     char type;
16472     tng_function_status stat;
16473
16474     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16475     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16476     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16477
16478     stat = tng_num_frames_get(tng_data, &n_frames);
16479     if(stat != TNG_SUCCESS)
16480     {
16481         return(stat);
16482     }
16483
16484     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
16485                                                  0, n_frames - 1, TNG_USE_HASH,
16486                                                  (void **)velocities,
16487                                                  &n_particles,
16488                                                  stride_length,
16489                                                  &n_values_per_frame,
16490                                                  &type);
16491
16492     return(stat);
16493 }
16494
16495 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
16496                 (tng_trajectory_t tng_data,
16497                  float **forces, int64_t *stride_length)
16498 {
16499     int64_t n_frames, n_particles, n_values_per_frame;
16500     char type;
16501     tng_function_status stat;
16502
16503     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16504     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
16505     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16506
16507     stat = tng_num_frames_get(tng_data, &n_frames);
16508     if(stat != TNG_SUCCESS)
16509     {
16510         return(stat);
16511     }
16512
16513     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16514                                                  0, n_frames - 1, TNG_USE_HASH,
16515                                                  (void **)forces,
16516                                                  &n_particles,
16517                                                  stride_length,
16518                                                  &n_values_per_frame,
16519                                                  &type);
16520
16521     return(stat);
16522 }
16523
16524 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
16525                 (tng_trajectory_t tng_data,
16526                  float **box_shape,
16527                  int64_t *stride_length)
16528 {
16529     int64_t n_frames, n_values_per_frame;
16530     char type;
16531     tng_function_status stat;
16532
16533     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16534     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16535     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16536
16537     stat = tng_num_frames_get(tng_data, &n_frames);
16538     if(stat != TNG_SUCCESS)
16539     {
16540         return(stat);
16541     }
16542
16543     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16544                                         0, n_frames - 1, TNG_USE_HASH,
16545                                         (void **)box_shape,
16546                                         stride_length,
16547                                         &n_values_per_frame,
16548                                         &type);
16549
16550     return(stat);
16551 }
16552
16553 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
16554                 (tng_trajectory_t tng_data,
16555                  const int64_t block_id,
16556                  void **values,
16557                  char *data_type,
16558                  int64_t *retrieved_frame_number,
16559                  double *retrieved_time)
16560 {
16561     tng_trajectory_frame_set_t frame_set;
16562     tng_particle_data_t data = 0;
16563     tng_function_status stat;
16564     int size;
16565     int64_t i, data_size, n_particles;
16566     void *temp;
16567     long file_pos;
16568
16569     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16570     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
16571     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
16572     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
16573     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
16574
16575     frame_set = &tng_data->current_trajectory_frame_set;
16576
16577     stat = tng_particle_data_find(tng_data, block_id, &data);
16578     if(stat != TNG_SUCCESS)
16579     {
16580         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16581         file_pos = ftell(tng_data->input_file);
16582         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16583         {
16584             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16585             file_pos = ftell(tng_data->input_file);
16586         }
16587         if(stat != TNG_SUCCESS)
16588         {
16589             return(stat);
16590         }
16591         stat = tng_particle_data_find(tng_data, block_id, &data);
16592         if(stat != TNG_SUCCESS)
16593         {
16594             return(stat);
16595         }
16596     }
16597     if(data->last_retrieved_frame < 0)
16598     {
16599         fseek(tng_data->input_file,
16600               (long)tng_data->first_trajectory_frame_set_input_file_pos,
16601               SEEK_SET);
16602         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
16603         if(stat != TNG_SUCCESS)
16604         {
16605             return(stat);
16606         }
16607         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16608         if(stat != TNG_SUCCESS)
16609         {
16610             return(stat);
16611         }
16612
16613         i = data->first_frame_with_data;
16614     }
16615     else
16616     {
16617         if(data->n_frames == 1)
16618         {
16619             i = data->last_retrieved_frame + 1;
16620         }
16621         else
16622         {
16623             i = data->last_retrieved_frame + data->stride_length;
16624         }
16625         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
16626         {
16627             stat = tng_frame_set_of_frame_find(tng_data, i);
16628             if(stat != TNG_SUCCESS)
16629             {
16630                 /* If the frame set search found the frame set after the starting
16631                  * frame set there is a gap in the frame sets. So, even if the frame
16632                  * was not found the next frame with data is still in the found
16633                  * frame set. */
16634                 if(stat == TNG_CRITICAL)
16635                 {
16636                     return(stat);
16637                 }
16638                 i = frame_set->first_frame;
16639             }
16640         }
16641         if(data->last_retrieved_frame < frame_set->first_frame)
16642         {
16643             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16644             if(stat != TNG_SUCCESS)
16645             {
16646                 return(stat);
16647             }
16648         }
16649     }
16650     data->last_retrieved_frame = i;
16651     *retrieved_frame_number = i;
16652     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
16653     {
16654         *retrieved_time = frame_set->first_frame_time +
16655                         (i - frame_set->first_frame) *
16656                         tng_data->time_per_frame;
16657     }
16658     else
16659     {
16660         *retrieved_time = 0;
16661     }
16662
16663     if(data->stride_length > 1)
16664     {
16665         i = (i - data->first_frame_with_data) / data->stride_length;
16666     }
16667     else
16668     {
16669         i = (i - frame_set->first_frame);
16670     }
16671
16672     tng_num_particles_get(tng_data, &n_particles);
16673
16674     *data_type = data->datatype;
16675
16676     switch(*data_type)
16677     {
16678     case TNG_CHAR_DATA:
16679         return(TNG_FAILURE);
16680     case TNG_INT_DATA:
16681         size = sizeof(int64_t);
16682         break;
16683     case TNG_FLOAT_DATA:
16684         size = sizeof(float);
16685         break;
16686     case TNG_DOUBLE_DATA:
16687     default:
16688         size = sizeof(double);
16689     }
16690
16691     data_size = size * n_particles * data->n_values_per_frame;
16692
16693 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
16694 //            i, data_size, size, n_particles, data->n_values_per_frame);
16695
16696     temp = realloc(*values, data_size);
16697     if(!temp)
16698     {
16699         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16700                data_size, __FILE__, __LINE__);
16701         free(*values);
16702         *values = 0;
16703         return(TNG_CRITICAL);
16704     }
16705
16706     *values = temp;
16707
16708     memcpy(*values, (char *)data->values + i * data_size, data_size);
16709
16710     return(TNG_SUCCESS);
16711 }
16712
16713 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
16714                 (tng_trajectory_t tng_data,
16715                  const int64_t block_id,
16716                  void **values,
16717                  char *data_type,
16718                  int64_t *retrieved_frame_number,
16719                  double *retrieved_time)
16720 {
16721     tng_trajectory_frame_set_t frame_set;
16722     tng_non_particle_data_t data = 0;
16723     tng_function_status stat;
16724     int size;
16725     int64_t i, data_size;
16726     void *temp;
16727     long file_pos;
16728
16729     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16730     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
16731     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
16732     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
16733     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
16734
16735     frame_set = &tng_data->current_trajectory_frame_set;
16736
16737     stat = tng_data_find(tng_data, block_id, &data);
16738     if(stat != TNG_SUCCESS)
16739     {
16740         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16741         file_pos = ftell(tng_data->input_file);
16742         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16743         {
16744             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16745             file_pos = ftell(tng_data->input_file);
16746         }
16747         if(stat != TNG_SUCCESS)
16748         {
16749             return(stat);
16750         }
16751         stat = tng_data_find(tng_data, block_id, &data);
16752         if(stat != TNG_SUCCESS)
16753         {
16754             return(stat);
16755         }
16756     }
16757     if(data->last_retrieved_frame < 0)
16758     {
16759         fseek(tng_data->input_file,
16760                 (long)tng_data->first_trajectory_frame_set_input_file_pos,
16761                 SEEK_SET);
16762         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
16763         if(stat != TNG_SUCCESS)
16764         {
16765             return(stat);
16766         }
16767         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16768         if(stat != TNG_SUCCESS)
16769         {
16770             return(stat);
16771         }
16772
16773         i = data->first_frame_with_data;
16774     }
16775     else
16776     {
16777         if(data->n_frames == 1)
16778         {
16779             i = data->last_retrieved_frame + 1;
16780         }
16781         else
16782         {
16783             i = data->last_retrieved_frame + data->stride_length;
16784         }
16785         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
16786         {
16787             stat = tng_frame_set_of_frame_find(tng_data, i);
16788             if(stat != TNG_SUCCESS)
16789             {
16790                 /* If the frame set search found the frame set after the starting
16791                  * frame set there is a gap in the frame sets. So, even if the frame
16792                  * was not found the next frame with data is still in the found
16793                  * frame set. */
16794                 if(stat == TNG_CRITICAL)
16795                 {
16796                     return(stat);
16797                 }
16798                 i = frame_set->first_frame;
16799             }
16800         }
16801         if(data->last_retrieved_frame < frame_set->first_frame)
16802         {
16803             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16804             if(stat != TNG_SUCCESS)
16805             {
16806                 return(stat);
16807             }
16808         }
16809     }
16810     data->last_retrieved_frame = i;
16811     *retrieved_frame_number = i;
16812     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
16813     {
16814         *retrieved_time = frame_set->first_frame_time +
16815                         (i - frame_set->first_frame) *
16816                         tng_data->time_per_frame;
16817     }
16818     else
16819     {
16820         *retrieved_time = 0;
16821     }
16822
16823     if(data->stride_length > 1)
16824     {
16825         i = (i - data->first_frame_with_data) / data->stride_length;
16826     }
16827     else
16828     {
16829         i = (i - frame_set->first_frame);
16830     }
16831
16832     *data_type = data->datatype;
16833
16834     switch(*data_type)
16835     {
16836     case TNG_CHAR_DATA:
16837         return(TNG_FAILURE);
16838     case TNG_INT_DATA:
16839         size = sizeof(int64_t);
16840         break;
16841     case TNG_FLOAT_DATA:
16842         size = sizeof(float);
16843         break;
16844     case TNG_DOUBLE_DATA:
16845     default:
16846         size = sizeof(double);
16847     }
16848
16849     data_size = size * data->n_values_per_frame;
16850
16851     temp = realloc(*values, data_size);
16852     if(!temp)
16853     {
16854         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16855                data_size, __FILE__, __LINE__);
16856         free(*values);
16857         *values = 0;
16858         return(TNG_CRITICAL);
16859     }
16860
16861     *values = temp;
16862
16863     memcpy(*values, (char *)data->values + i * data_size, data_size);
16864
16865     return(TNG_SUCCESS);
16866 }
16867
16868 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
16869                 (tng_trajectory_t tng_data,
16870                  const int64_t first_frame,
16871                  const int64_t last_frame,
16872                  float **positions,
16873                  int64_t *stride_length)
16874 {
16875     int64_t n_particles, n_values_per_frame;
16876     char type;
16877     tng_function_status stat;
16878
16879     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16880     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16881     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16882     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16883
16884     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
16885                                                  first_frame, last_frame,
16886                                                  TNG_USE_HASH,
16887                                                  (void **)positions,
16888                                                  &n_particles,
16889                                                  stride_length,
16890                                                  &n_values_per_frame,
16891                                                  &type);
16892
16893     return(stat);
16894 }
16895
16896 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
16897                 (tng_trajectory_t tng_data,
16898                  const int64_t first_frame,
16899                  const int64_t last_frame,
16900                  float **velocities,
16901                  int64_t *stride_length)
16902 {
16903     int64_t n_particles, n_values_per_frame;
16904     char type;
16905     tng_function_status stat;
16906
16907     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16908     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16909     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16910     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16911
16912     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
16913                                                  first_frame, last_frame,
16914                                                  TNG_USE_HASH,
16915                                                  (void **)velocities,
16916                                                  &n_particles,
16917                                                  stride_length,
16918                                                  &n_values_per_frame,
16919                                                  &type);
16920
16921     return(stat);
16922 }
16923
16924 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
16925                 (tng_trajectory_t tng_data,
16926                  const int64_t first_frame,
16927                  const int64_t last_frame,
16928                  float **forces,
16929                  int64_t *stride_length)
16930 {
16931     int64_t n_particles, n_values_per_frame;
16932     char type;
16933     tng_function_status stat;
16934
16935     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16936     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
16937     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16938     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16939
16940     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16941                                                  first_frame, last_frame,
16942                                                  TNG_USE_HASH,
16943                                                  (void **)forces,
16944                                                  &n_particles,
16945                                                  stride_length,
16946                                                  &n_values_per_frame,
16947                                                  &type);
16948
16949     return(stat);
16950 }
16951
16952 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
16953                 (tng_trajectory_t tng_data,
16954                  const int64_t first_frame,
16955                  const int64_t last_frame,
16956                  float **box_shape,
16957                  int64_t *stride_length)
16958 {
16959     int64_t n_values_per_frame;
16960     char type;
16961     tng_function_status stat;
16962
16963     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16964     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16965     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16966     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16967
16968     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16969                                         first_frame, last_frame,
16970                                         TNG_USE_HASH,
16971                                         (void **)box_shape,
16972                                         stride_length,
16973                                         &n_values_per_frame,
16974                                         &type);
16975
16976     return(stat);
16977 }
16978
16979 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
16980                 (tng_trajectory_t tng_data,
16981                  const int64_t i,
16982                  const int64_t n_values_per_frame,
16983                  const int64_t block_id,
16984                  const char *block_name,
16985                  const char particle_dependency,
16986                  const char compression)
16987 {
16988     tng_trajectory_frame_set_t frame_set;
16989     tng_particle_data_t p_data;
16990     tng_non_particle_data_t np_data;
16991     int64_t n_particles, n_frames;
16992     tng_function_status stat;
16993
16994     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16995     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16996
16997     if(i <= 0)
16998     {
16999         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17000                i, __FILE__, __LINE__);
17001         return(TNG_FAILURE);
17002     }
17003
17004     frame_set = &tng_data->current_trajectory_frame_set;
17005
17006     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17007     {
17008         n_frames = tng_data->frame_set_n_frames;
17009
17010         stat = tng_frame_set_new(tng_data, 0, n_frames);
17011         if(stat != TNG_SUCCESS)
17012         {
17013             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17014                 __LINE__);
17015             return(stat);
17016         }
17017     }
17018     else
17019     {
17020         n_frames = frame_set->n_frames;
17021     }
17022
17023     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17024     {
17025         tng_num_particles_get(tng_data, &n_particles);
17026         if(n_particles <= 0)
17027         {
17028             return(TNG_FAILURE);
17029         }
17030
17031         if(tng_particle_data_find(tng_data, block_id, &p_data)
17032         != TNG_SUCCESS)
17033         {
17034             stat = tng_particle_data_block_add(tng_data, block_id,
17035                                                block_name,
17036                                                TNG_FLOAT_DATA,
17037                                                TNG_TRAJECTORY_BLOCK,
17038                                                n_frames, n_values_per_frame, i,
17039                                                0, n_particles,
17040                                                compression, 0);
17041             if(stat != TNG_SUCCESS)
17042             {
17043                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17044                        __FILE__, __LINE__);
17045                 return(stat);
17046             }
17047             p_data = &frame_set->tr_particle_data[frame_set->
17048                                                   n_particle_data_blocks - 1];
17049             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17050                                                   i, n_particles,
17051                                                   n_values_per_frame);
17052             if(stat != TNG_SUCCESS)
17053             {
17054                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17055                        __FILE__, __LINE__);
17056                 return(stat);
17057             }
17058         }
17059         else
17060         {
17061             if(p_data->stride_length != i)
17062             {
17063                 p_data->stride_length = i;
17064                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17065                                                       i, n_particles,
17066                                                       n_values_per_frame);
17067                 if(stat != TNG_SUCCESS)
17068                 {
17069                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17070                            __FILE__, __LINE__);
17071                     return(stat);
17072                 }
17073             }
17074         }
17075     }
17076     else
17077     {
17078         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17079         {
17080             stat = tng_data_block_add(tng_data, block_id, block_name,
17081                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
17082                                       n_frames, n_values_per_frame,
17083                                       i, compression, 0);
17084             if(stat != TNG_SUCCESS)
17085             {
17086                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17087                        __FILE__, __LINE__);
17088                 return(stat);
17089             }
17090             np_data = &frame_set->tr_data[frame_set->
17091                                           n_data_blocks - 1];
17092             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17093                                          i, n_values_per_frame);
17094             if(stat != TNG_SUCCESS)
17095             {
17096                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17097                        __FILE__, __LINE__);
17098                 return(stat);
17099             }
17100         }
17101         else
17102         {
17103             if(np_data->stride_length != i)
17104             {
17105                 np_data->stride_length = i;
17106                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17107                                              i, n_values_per_frame);
17108                 if(stat != TNG_SUCCESS)
17109                 {
17110                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17111                            __FILE__, __LINE__);
17112                     return(stat);
17113                 }
17114             }
17115         }
17116     }
17117
17118     return(TNG_SUCCESS);
17119 }
17120
17121 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17122                 (tng_trajectory_t tng_data,
17123                  const int64_t i,
17124                  const int64_t n_values_per_frame,
17125                  const int64_t block_id,
17126                  const char *block_name,
17127                  const char particle_dependency,
17128                  const char compression)
17129 {
17130     tng_trajectory_frame_set_t frame_set;
17131     tng_particle_data_t p_data;
17132     tng_non_particle_data_t np_data;
17133     int64_t n_particles, n_frames;
17134     tng_function_status stat;
17135
17136     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17137     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17138
17139     if(i <= 0)
17140     {
17141         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17142                i, __FILE__, __LINE__);
17143         return(TNG_FAILURE);
17144     }
17145
17146     frame_set = &tng_data->current_trajectory_frame_set;
17147
17148     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17149     {
17150         n_frames = tng_data->frame_set_n_frames;
17151
17152         stat = tng_frame_set_new(tng_data, 0, n_frames);
17153         if(stat != TNG_SUCCESS)
17154         {
17155             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17156                 __LINE__);
17157             return(stat);
17158         }
17159     }
17160     else
17161     {
17162         n_frames = frame_set->n_frames;
17163     }
17164
17165     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17166     {
17167         tng_num_particles_get(tng_data, &n_particles);
17168
17169         if(n_particles <= 0)
17170         {
17171             return(TNG_FAILURE);
17172         }
17173
17174         if(tng_particle_data_find(tng_data, block_id, &p_data)
17175         != TNG_SUCCESS)
17176         {
17177             stat = tng_particle_data_block_add(tng_data, block_id,
17178                                             block_name,
17179                                             TNG_DOUBLE_DATA,
17180                                             TNG_TRAJECTORY_BLOCK,
17181                                             n_frames, n_values_per_frame, i,
17182                                             0, n_particles,
17183                                             compression, 0);
17184             if(stat != TNG_SUCCESS)
17185             {
17186                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17187                        __FILE__, __LINE__);
17188                 return(stat);
17189             }
17190             p_data = &frame_set->tr_particle_data[frame_set->
17191                                                   n_particle_data_blocks - 1];
17192             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17193                                                   i, n_particles,
17194                                                   n_values_per_frame);
17195             if(stat != TNG_SUCCESS)
17196             {
17197                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17198                        __FILE__, __LINE__);
17199                 return(stat);
17200             }
17201         }
17202         else
17203         {
17204             p_data->stride_length = i;
17205         }
17206     }
17207     else
17208     {
17209         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17210         {
17211             stat = tng_data_block_add(tng_data, block_id, block_name,
17212                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
17213                                       n_frames, n_values_per_frame,
17214                                       i, compression, 0);
17215             if(stat != TNG_SUCCESS)
17216             {
17217                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17218                        __FILE__, __LINE__);
17219                 return(stat);
17220             }
17221             np_data = &frame_set->tr_data[frame_set->
17222                                           n_data_blocks - 1];
17223             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17224                                          i, n_values_per_frame);
17225             if(stat != TNG_SUCCESS)
17226             {
17227                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17228                        __FILE__, __LINE__);
17229                 return(stat);
17230             }
17231         }
17232         else
17233         {
17234             np_data->stride_length = i;
17235         }
17236     }
17237
17238     return(TNG_SUCCESS);
17239 }
17240
17241 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
17242                 (tng_trajectory_t tng_data,
17243                  const int64_t i,
17244                  const int64_t n_values_per_frame,
17245                  const int64_t block_id,
17246                  const char *block_name,
17247                  const char particle_dependency,
17248                  const char compression)
17249 {
17250     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
17251            "See documentation. %s: %d", __FILE__, __LINE__);
17252     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
17253                                                block_id, block_name,
17254                                                particle_dependency,
17255                                                compression));
17256 }
17257 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
17258                 (tng_trajectory_t tng_data,
17259                  const int64_t i)
17260 {
17261     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17262     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17263
17264     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17265                                                TNG_TRAJ_POSITIONS,
17266                                                "POSITIONS",
17267                                                TNG_PARTICLE_BLOCK_DATA,
17268                                                TNG_TNG_COMPRESSION));
17269 }
17270
17271 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_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_double_set(tng_data, i, 3,
17279                                                       TNG_TRAJ_POSITIONS,
17280                                                       "POSITIONS",
17281                                                       TNG_PARTICLE_BLOCK_DATA,
17282                                                       TNG_TNG_COMPRESSION));
17283 }
17284
17285 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
17286                 (tng_trajectory_t tng_data,
17287                  const int64_t i)
17288 {
17289     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
17290            "See documentation. %s: %d", __FILE__, __LINE__);
17291     return(tng_util_pos_write_interval_set(tng_data, i));
17292 }
17293
17294 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
17295                 (tng_trajectory_t tng_data,
17296                  const int64_t i)
17297 {
17298     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17299     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17300
17301     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17302                                                TNG_TRAJ_VELOCITIES,
17303                                                "VELOCITIES",
17304                                                TNG_PARTICLE_BLOCK_DATA,
17305                                                TNG_TNG_COMPRESSION));
17306 }
17307
17308 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
17309                 (tng_trajectory_t tng_data,
17310                  const int64_t i)
17311 {
17312     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17313     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17314
17315     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
17316                                                       TNG_TRAJ_VELOCITIES,
17317                                                       "VELOCITIES",
17318                                                       TNG_PARTICLE_BLOCK_DATA,
17319                                                       TNG_TNG_COMPRESSION));
17320 }
17321
17322 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
17323                 (tng_trajectory_t tng_data,
17324                  const int64_t i)
17325 {
17326     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
17327            "See documentation. %s: %d", __FILE__, __LINE__);
17328     return(tng_util_vel_write_interval_set(tng_data, i));
17329 }
17330
17331 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
17332                 (tng_trajectory_t tng_data,
17333                  const int64_t i)
17334 {
17335     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17336     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17337
17338     return(tng_util_generic_write_interval_set(tng_data, i, 3,
17339                                                TNG_TRAJ_FORCES,
17340                                                "FORCES",
17341                                                TNG_PARTICLE_BLOCK_DATA,
17342                                                TNG_GZIP_COMPRESSION));
17343 }
17344
17345 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
17346                 (tng_trajectory_t tng_data,
17347                  const int64_t i)
17348 {
17349     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17350     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17351
17352     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
17353                                                       TNG_TRAJ_FORCES,
17354                                                       "FORCES",
17355                                                       TNG_PARTICLE_BLOCK_DATA,
17356                                                       TNG_GZIP_COMPRESSION));
17357 }
17358
17359 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
17360                 (tng_trajectory_t tng_data,
17361                  const int64_t i)
17362 {
17363     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
17364            "See documentation. %s: %d", __FILE__, __LINE__);
17365     return(tng_util_force_write_interval_set(tng_data, i));
17366 }
17367
17368 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
17369                 (tng_trajectory_t tng_data,
17370                  const int64_t i)
17371 {
17372     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17373     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17374
17375     return(tng_util_generic_write_interval_set(tng_data, i, 9,
17376                                                TNG_TRAJ_BOX_SHAPE,
17377                                                "BOX SHAPE",
17378                                                TNG_NON_PARTICLE_BLOCK_DATA,
17379                                                TNG_GZIP_COMPRESSION));
17380 }
17381
17382 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
17383                 (tng_trajectory_t tng_data,
17384                  const int64_t i)
17385 {
17386     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17387     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
17388
17389     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
17390                                                       TNG_TRAJ_BOX_SHAPE,
17391                                                       "BOX SHAPE",
17392                                                       TNG_NON_PARTICLE_BLOCK_DATA,
17393                                                       TNG_GZIP_COMPRESSION));
17394 }
17395
17396 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
17397                 (tng_trajectory_t tng_data,
17398                  const int64_t i)
17399 {
17400     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
17401            "See documentation. %s: %d", __FILE__, __LINE__);
17402     return(tng_util_box_shape_write_interval_set(tng_data, i));
17403 }
17404
17405 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
17406                 (tng_trajectory_t tng_data,
17407                  const int64_t frame_nr,
17408                  const float *values,
17409                  const int64_t n_values_per_frame,
17410                  const int64_t block_id,
17411                  const char *block_name,
17412                  const char particle_dependency,
17413                  const char compression)
17414 {
17415     tng_trajectory_frame_set_t frame_set;
17416     tng_particle_data_t p_data;
17417     tng_non_particle_data_t np_data;
17418     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
17419     int64_t last_frame;
17420     int is_first_frame_flag = 0;
17421     char block_type_flag;
17422     tng_function_status stat;
17423
17424     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17425     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17426     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17427
17428     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17429     {
17430         tng_num_particles_get(tng_data, &n_particles);
17431         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
17432     }
17433
17434     if(values == 0)
17435     {
17436         return(TNG_FAILURE);
17437     }
17438
17439     frame_set = &tng_data->current_trajectory_frame_set;
17440
17441     if(frame_nr < 0)
17442     {
17443         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
17444         n_frames = stride_length = 1;
17445     }
17446     else
17447     {
17448         block_type_flag = TNG_TRAJECTORY_BLOCK;
17449
17450         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17451         {
17452             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
17453             if(stat != TNG_SUCCESS)
17454             {
17455                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17456                     __LINE__);
17457                 return(stat);
17458             }
17459         }
17460         last_frame = frame_set->first_frame +
17461                      frame_set->n_frames - 1;
17462         if(frame_nr > last_frame)
17463         {
17464             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
17465             if(stat != TNG_SUCCESS)
17466             {
17467                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
17468                     __LINE__);
17469                 return(stat);
17470             }
17471             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
17472             {
17473                 last_frame = frame_nr - 1;
17474             }
17475             stat = tng_frame_set_new(tng_data, last_frame + 1,
17476                                      tng_data->frame_set_n_frames);
17477             if(stat != TNG_SUCCESS)
17478             {
17479                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17480                     __LINE__);
17481                 return(stat);
17482             }
17483         }
17484         if(frame_set->n_unwritten_frames == 0)
17485         {
17486             is_first_frame_flag = 1;
17487         }
17488         frame_set->n_unwritten_frames = frame_nr -
17489                                         frame_set->first_frame + 1;
17490
17491         n_frames = frame_set->n_frames;
17492     }
17493
17494     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17495     {
17496         if(tng_particle_data_find(tng_data, block_id, &p_data)
17497         != TNG_SUCCESS)
17498         {
17499             stat = tng_particle_data_block_add(tng_data, block_id,
17500                                                block_name,
17501                                                TNG_FLOAT_DATA,
17502                                                block_type_flag,
17503                                                n_frames, n_values_per_frame,
17504                                                stride_length,
17505                                                0, n_particles,
17506                                                compression, 0);
17507             if(stat != TNG_SUCCESS)
17508             {
17509                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17510                        __FILE__, __LINE__);
17511                 return(stat);
17512             }
17513             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17514             {
17515                 p_data = &frame_set->tr_particle_data[frame_set->
17516                                                     n_particle_data_blocks - 1];
17517             }
17518             else
17519             {
17520                 p_data = &tng_data->non_tr_particle_data[tng_data->
17521                                                     n_particle_data_blocks - 1];
17522             }
17523             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17524                                                   stride_length, n_particles,
17525                                                   n_values_per_frame);
17526             if(stat != TNG_SUCCESS)
17527             {
17528                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17529                        __FILE__, __LINE__);
17530                 return(stat);
17531             }
17532         }
17533
17534         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17535         {
17536             stride_length = p_data->stride_length;
17537
17538             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
17539             {
17540                 p_data->first_frame_with_data = frame_nr;
17541                 frame_pos = 0;
17542             }
17543             else
17544             {
17545                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17546             }
17547
17548             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
17549                    n_values_per_frame, values, sizeof(float) *
17550                    n_particles * n_values_per_frame);
17551         }
17552         else
17553         {
17554             memcpy(p_data->values, values, sizeof(float) * n_particles *
17555                    n_values_per_frame);
17556         }
17557     }
17558     else
17559     {
17560         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17561         {
17562             stat = tng_data_block_add(tng_data, block_id, block_name,
17563                                       TNG_FLOAT_DATA, block_type_flag,
17564                                       n_frames, n_values_per_frame,
17565                                       stride_length, compression, 0);
17566             if(stat != TNG_SUCCESS)
17567             {
17568                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17569                        __FILE__, __LINE__);
17570                 return(stat);
17571             }
17572             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17573             {
17574                 np_data = &frame_set->tr_data[frame_set->
17575                                               n_data_blocks - 1];
17576             }
17577             else
17578             {
17579                 np_data = &tng_data->non_tr_data[tng_data->
17580                                                  n_data_blocks - 1];
17581             }
17582             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17583                                          stride_length, n_values_per_frame);
17584             if(stat != TNG_SUCCESS)
17585             {
17586                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17587                        __FILE__, __LINE__);
17588                 return(stat);
17589             }
17590         }
17591
17592         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17593         {
17594             stride_length = np_data->stride_length;
17595
17596             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
17597             {
17598                 np_data->first_frame_with_data = frame_nr;
17599                 frame_pos = 0;
17600             }
17601             else
17602             {
17603                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17604             }
17605
17606             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
17607                    n_values_per_frame, values, sizeof(float) *
17608                    n_values_per_frame);
17609         }
17610         else
17611         {
17612             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
17613         }
17614     }
17615
17616     return(TNG_SUCCESS);
17617 }
17618
17619 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
17620                 (tng_trajectory_t tng_data,
17621                  const int64_t frame_nr,
17622                  const double *values,
17623                  const int64_t n_values_per_frame,
17624                  const int64_t block_id,
17625                  const char *block_name,
17626                  const char particle_dependency,
17627                  const char compression)
17628 {
17629     tng_trajectory_frame_set_t frame_set;
17630     tng_particle_data_t p_data;
17631     tng_non_particle_data_t np_data;
17632     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
17633     int64_t last_frame;
17634     int is_first_frame_flag = 0;
17635     char block_type_flag;
17636     tng_function_status stat;
17637
17638     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17639     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17640     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17641
17642     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17643     {
17644         tng_num_particles_get(tng_data, &n_particles);
17645         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
17646     }
17647
17648     if(values == 0)
17649     {
17650         return(TNG_FAILURE);
17651     }
17652
17653     frame_set = &tng_data->current_trajectory_frame_set;
17654
17655     if(frame_nr < 0)
17656     {
17657         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
17658         n_frames = stride_length = 1;
17659     }
17660     else
17661     {
17662         block_type_flag = TNG_TRAJECTORY_BLOCK;
17663
17664         n_frames = tng_data->frame_set_n_frames;
17665
17666         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17667         {
17668             stat = tng_frame_set_new(tng_data, 0, n_frames);
17669             if(stat != TNG_SUCCESS)
17670             {
17671                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17672                     __LINE__);
17673                 return(stat);
17674             }
17675         }
17676         else
17677         {
17678             n_frames = frame_set->n_frames;
17679         }
17680         last_frame = frame_set->first_frame +
17681                      frame_set->n_frames - 1;
17682         if(frame_nr > last_frame)
17683         {
17684             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
17685             if(stat != TNG_SUCCESS)
17686             {
17687                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
17688                     __LINE__);
17689                 return(stat);
17690             }
17691             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
17692             {
17693                 last_frame = frame_nr - 1;
17694             }
17695             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
17696             if(stat != TNG_SUCCESS)
17697             {
17698                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17699                     __LINE__);
17700                 return(stat);
17701             }
17702         }
17703         if(frame_set->n_unwritten_frames == 0)
17704         {
17705             is_first_frame_flag = 1;
17706         }
17707         frame_set->n_unwritten_frames = frame_nr -
17708                                         frame_set->first_frame + 1;
17709     }
17710
17711     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17712     {
17713         if(tng_particle_data_find(tng_data, block_id, &p_data)
17714         != TNG_SUCCESS)
17715         {
17716             stat = tng_particle_data_block_add(tng_data, block_id,
17717                                             block_name,
17718                                             TNG_DOUBLE_DATA,
17719                                             block_type_flag,
17720                                             n_frames, n_values_per_frame,
17721                                             stride_length,
17722                                             0, n_particles,
17723                                             compression, 0);
17724             if(stat != TNG_SUCCESS)
17725             {
17726                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17727                        __FILE__, __LINE__);
17728                 return(stat);
17729             }
17730             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17731             {
17732                 p_data = &frame_set->tr_particle_data[frame_set->
17733                                                     n_particle_data_blocks - 1];
17734             }
17735             else
17736             {
17737                 p_data = &tng_data->non_tr_particle_data[tng_data->
17738                                                     n_particle_data_blocks - 1];
17739             }
17740             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17741                                                   stride_length, n_particles,
17742                                                   n_values_per_frame);
17743             if(stat != TNG_SUCCESS)
17744             {
17745                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17746                        __FILE__, __LINE__);
17747                 return(stat);
17748             }
17749         }
17750
17751         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17752         {
17753             stride_length = p_data->stride_length;
17754
17755             if(is_first_frame_flag)
17756             {
17757                 p_data->first_frame_with_data = frame_nr;
17758                 frame_pos = 0;
17759             }
17760             else
17761             {
17762                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17763             }
17764
17765             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
17766                    n_values_per_frame, values, sizeof(double) *
17767                    n_particles * n_values_per_frame);
17768         }
17769         else
17770         {
17771             memcpy(p_data->values, values, sizeof(double) * n_particles *
17772                    n_values_per_frame);
17773         }
17774     }
17775     else
17776     {
17777         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17778         {
17779             stat = tng_data_block_add(tng_data, block_id, block_name,
17780                                       TNG_DOUBLE_DATA, block_type_flag,
17781                                       n_frames, n_values_per_frame,
17782                                       stride_length, compression, 0);
17783             if(stat != TNG_SUCCESS)
17784             {
17785                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17786                        __FILE__, __LINE__);
17787                 return(stat);
17788             }
17789             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17790             {
17791                 np_data = &frame_set->tr_data[frame_set->
17792                                               n_data_blocks - 1];
17793             }
17794             else
17795             {
17796                 np_data = &tng_data->non_tr_data[tng_data->
17797                                                  n_data_blocks - 1];
17798             }
17799             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17800                                          stride_length, n_values_per_frame);
17801             if(stat != TNG_SUCCESS)
17802             {
17803                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17804                        __FILE__, __LINE__);
17805                 return(stat);
17806             }
17807         }
17808
17809         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
17810         {
17811             stride_length = np_data->stride_length;
17812
17813             if(is_first_frame_flag)
17814             {
17815                 np_data->first_frame_with_data = frame_nr;
17816                 frame_pos = 0;
17817             }
17818             else
17819             {
17820                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
17821             }
17822
17823             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
17824                    n_values_per_frame, values, sizeof(double) *
17825                    n_values_per_frame);
17826         }
17827         else
17828         {
17829             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
17830         }
17831     }
17832
17833     return(TNG_SUCCESS);
17834 }
17835
17836 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
17837                 (tng_trajectory_t tng_data,
17838                  const int64_t frame_nr,
17839                  const float *positions)
17840 {
17841     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17842     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17843     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17844
17845     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
17846                                   TNG_TRAJ_POSITIONS, "POSITIONS",
17847                                   TNG_PARTICLE_BLOCK_DATA,
17848                                   TNG_TNG_COMPRESSION));
17849 }
17850
17851 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
17852                 (tng_trajectory_t tng_data,
17853                  const int64_t frame_nr,
17854                  const double *positions)
17855 {
17856     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17857     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17858     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17859
17860     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
17861                                          TNG_TRAJ_POSITIONS, "POSITIONS",
17862                                          TNG_PARTICLE_BLOCK_DATA,
17863                                          TNG_TNG_COMPRESSION));
17864 }
17865
17866 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
17867                 (tng_trajectory_t tng_data,
17868                  const int64_t frame_nr,
17869                  const float *velocities)
17870 {
17871     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17872     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17873     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17874
17875     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
17876                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
17877                                   TNG_PARTICLE_BLOCK_DATA,
17878                                   TNG_TNG_COMPRESSION));
17879 }
17880
17881 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
17882                 (tng_trajectory_t tng_data,
17883                  const int64_t frame_nr,
17884                  const double *velocities)
17885 {
17886     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17887     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17888     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17889
17890     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
17891                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
17892                                          TNG_PARTICLE_BLOCK_DATA,
17893                                          TNG_TNG_COMPRESSION));
17894 }
17895
17896 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
17897                 (tng_trajectory_t tng_data,
17898                  const int64_t frame_nr,
17899                  const float *forces)
17900 {
17901     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17902     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17903     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17904
17905     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
17906                                   TNG_TRAJ_FORCES, "FORCES",
17907                                   TNG_PARTICLE_BLOCK_DATA,
17908                                   TNG_GZIP_COMPRESSION));
17909 }
17910
17911 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
17912                 (tng_trajectory_t tng_data,
17913                  const int64_t frame_nr,
17914                  const double *forces)
17915 {
17916     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17917     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17918     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17919
17920     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
17921                                          TNG_TRAJ_FORCES, "FORCES",
17922                                          TNG_PARTICLE_BLOCK_DATA,
17923                                          TNG_GZIP_COMPRESSION));
17924 }
17925
17926 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
17927                 (tng_trajectory_t tng_data,
17928                  const int64_t frame_nr,
17929                  const float *box_shape)
17930 {
17931     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17932     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17933     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17934
17935     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
17936                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17937                                   TNG_NON_PARTICLE_BLOCK_DATA,
17938                                   TNG_GZIP_COMPRESSION));
17939 }
17940
17941 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
17942                 (tng_trajectory_t tng_data,
17943                  const int64_t frame_nr,
17944                  const double *box_shape)
17945 {
17946     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17947     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17948     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17949
17950     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
17951                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17952                                          TNG_NON_PARTICLE_BLOCK_DATA,
17953                                          TNG_GZIP_COMPRESSION));
17954 }
17955
17956 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
17957                 (tng_trajectory_t tng_data,
17958                  const int64_t frame_nr,
17959                  const double time,
17960                  const float *values,
17961                  const int64_t n_values_per_frame,
17962                  const int64_t block_id,
17963                  const char *block_name,
17964                  const char particle_dependency,
17965                  const char compression)
17966 {
17967     tng_trajectory_frame_set_t frame_set;
17968     tng_function_status stat;
17969
17970     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17971     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17972     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17973     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17974
17975     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
17976                                   block_id, block_name,
17977                                   particle_dependency,
17978                                   compression);
17979
17980     if(stat != TNG_SUCCESS)
17981     {
17982         return(stat);
17983     }
17984
17985     frame_set = &tng_data->current_trajectory_frame_set;
17986
17987     /* first_frame_time is -1 when it is not yet set. */
17988     if(frame_set->first_frame_time < -0.1)
17989     {
17990         if(frame_nr > frame_set->first_frame)
17991         {
17992             stat = tng_frame_set_first_frame_time_set(tng_data,
17993                                                       time -
17994                                                       (frame_nr -
17995                                                        frame_set->first_frame) *
17996                                                       tng_data->time_per_frame);
17997         }
17998         else
17999         {
18000             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18001         }
18002     }
18003     return(stat);
18004 }
18005
18006 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
18007                 (tng_trajectory_t tng_data,
18008                  const int64_t frame_nr,
18009                  const double time,
18010                  const double *values,
18011                  const int64_t n_values_per_frame,
18012                  const int64_t block_id,
18013                  const char *block_name,
18014                  const char particle_dependency,
18015                  const char compression)
18016 {
18017     tng_trajectory_frame_set_t frame_set;
18018     tng_function_status stat;
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(values, "TNG library: values must not be a NULL pointer");
18024
18025     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
18026                                          block_id, block_name,
18027                                          particle_dependency,
18028                                          compression);
18029
18030     if(stat != TNG_SUCCESS)
18031     {
18032         return(stat);
18033     }
18034
18035     frame_set = &tng_data->current_trajectory_frame_set;
18036
18037     /* first_frame_time is -1 when it is not yet set. */
18038     if(frame_set->first_frame_time < -0.1)
18039     {
18040         if(frame_nr > frame_set->first_frame)
18041         {
18042             stat = tng_frame_set_first_frame_time_set(tng_data,
18043                                                       time -
18044                                                       (frame_nr -
18045                                                        frame_set->first_frame) *
18046                                                       tng_data->time_per_frame);
18047         }
18048         else
18049         {
18050             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18051         }
18052     }
18053     return(stat);
18054 }
18055
18056 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
18057                 (tng_trajectory_t tng_data,
18058                  const int64_t frame_nr,
18059                  const double time,
18060                  const float *positions)
18061 {
18062     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18063     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18064     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18065     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18066
18067     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
18068                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
18069                                             TNG_PARTICLE_BLOCK_DATA,
18070                                             TNG_TNG_COMPRESSION));
18071 }
18072
18073 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
18074                 (tng_trajectory_t tng_data,
18075                  const int64_t frame_nr,
18076                  const double time,
18077                  const double *positions)
18078 {
18079     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18080     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18081     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18082     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18083
18084     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18085                                                    positions, 3,
18086                                                    TNG_TRAJ_POSITIONS,
18087                                                    "POSITIONS",
18088                                                    TNG_PARTICLE_BLOCK_DATA,
18089                                                    TNG_TNG_COMPRESSION));
18090 }
18091
18092 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
18093                 (tng_trajectory_t tng_data,
18094                  const int64_t frame_nr,
18095                  const double time,
18096                  const float *velocities)
18097 {
18098     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18099     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18100     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18101     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18102
18103     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18104                                             velocities, 3,
18105                                             TNG_TRAJ_VELOCITIES,
18106                                             "VELOCITIES",
18107                                             TNG_PARTICLE_BLOCK_DATA,
18108                                             TNG_TNG_COMPRESSION));
18109 }
18110
18111 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18112                 (tng_trajectory_t tng_data,
18113                  const int64_t frame_nr,
18114                  const double time,
18115                  const double *velocities)
18116 {
18117     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18118     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18119     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18120     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18121
18122     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18123                                                    velocities, 3,
18124                                                    TNG_TRAJ_VELOCITIES,
18125                                                    "VELOCITIES",
18126                                                    TNG_PARTICLE_BLOCK_DATA,
18127                                                    TNG_TNG_COMPRESSION));
18128 }
18129
18130 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18131                 (tng_trajectory_t tng_data,
18132                  const int64_t frame_nr,
18133                  const double time,
18134                  const float *forces)
18135 {
18136     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18137     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18138     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18139     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18140
18141     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18142                                             3, TNG_TRAJ_FORCES, "FORCES",
18143                                             TNG_PARTICLE_BLOCK_DATA,
18144                                             TNG_GZIP_COMPRESSION));
18145 }
18146
18147 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18148                 (tng_trajectory_t tng_data,
18149                  const int64_t frame_nr,
18150                  const double time,
18151                  const double *forces)
18152 {
18153     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18154     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18155     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18156     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18157
18158     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18159                                                    forces, 3,
18160                                                    TNG_TRAJ_FORCES, "FORCES",
18161                                                    TNG_PARTICLE_BLOCK_DATA,
18162                                                    TNG_GZIP_COMPRESSION));
18163 }
18164
18165 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18166                 (tng_trajectory_t tng_data,
18167                  const int64_t frame_nr,
18168                  const double time,
18169                  const float *box_shape)
18170 {
18171     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18172     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18173     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18174     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18175
18176     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
18177                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18178                                             TNG_NON_PARTICLE_BLOCK_DATA,
18179                                             TNG_GZIP_COMPRESSION));
18180 }
18181
18182 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
18183                 (tng_trajectory_t tng_data,
18184                  const int64_t frame_nr,
18185                  const double time,
18186                  const double *box_shape)
18187 {
18188     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18189     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18190     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18191     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18192
18193     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
18194                                                    time, box_shape, 9,
18195                                                    TNG_TRAJ_BOX_SHAPE,
18196                                                    "BOX SHAPE",
18197                                                    TNG_NON_PARTICLE_BLOCK_DATA,
18198                                                    TNG_GZIP_COMPRESSION));
18199 }
18200
18201 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
18202                 (tng_trajectory_t tng_data,
18203                  const int64_t block_id,
18204                  int64_t *codec_id,
18205                  float *factor)
18206 {
18207     tng_trajectory_frame_set_t frame_set;
18208     tng_particle_data_t p_data = 0;
18209     tng_non_particle_data_t np_data = 0;
18210     tng_function_status stat;
18211     int64_t i;
18212     int block_type = -1;
18213
18214     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18215     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
18216     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
18217
18218     frame_set = &tng_data->current_trajectory_frame_set;
18219
18220     stat = tng_particle_data_find(tng_data, block_id, &p_data);
18221     if(stat == TNG_SUCCESS)
18222     {
18223         block_type = TNG_PARTICLE_BLOCK_DATA;
18224     }
18225     else
18226     {
18227         stat = tng_data_find(tng_data, block_id, &np_data);
18228         if(stat == TNG_SUCCESS)
18229         {
18230             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18231         }
18232         else
18233         {
18234             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18235             if(stat != TNG_SUCCESS)
18236             {
18237                 return(stat);
18238             }
18239             stat = tng_particle_data_find(tng_data, block_id, &p_data);
18240             if(stat == TNG_SUCCESS)
18241             {
18242                 block_type = TNG_PARTICLE_BLOCK_DATA;
18243             }
18244             else
18245             {
18246                 stat = tng_data_find(tng_data, block_id, &np_data);
18247                 if(stat == TNG_SUCCESS)
18248                 {
18249                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
18250                 }
18251                 else
18252                 {
18253                     return(stat);
18254                 }
18255             }
18256         }
18257     }
18258     if(block_type == TNG_PARTICLE_BLOCK_DATA)
18259     {
18260         if(p_data->last_retrieved_frame < 0)
18261         {
18262             i = p_data->first_frame_with_data;
18263         }
18264         else
18265         {
18266             i = p_data->last_retrieved_frame;
18267         }
18268     }
18269     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
18270     {
18271         if(np_data->last_retrieved_frame < 0)
18272         {
18273             i = np_data->first_frame_with_data;
18274         }
18275         else
18276         {
18277             i = np_data->last_retrieved_frame;
18278         }
18279     }
18280     else
18281     {
18282         return(TNG_FAILURE);
18283     }
18284     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
18285     {
18286         stat = tng_frame_set_of_frame_find(tng_data, i);
18287         if(stat != TNG_SUCCESS)
18288         {
18289             return(stat);
18290         }
18291         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
18292         if(stat != TNG_SUCCESS)
18293         {
18294             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18295                 __FILE__, __LINE__);
18296             return(stat);
18297         }
18298     }
18299     if(block_type == TNG_PARTICLE_BLOCK_DATA)
18300     {
18301         *codec_id = p_data->codec_id;
18302         *factor   = (float)p_data->compression_multiplier;
18303     }
18304     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
18305     {
18306         *codec_id = np_data->codec_id;
18307         *factor   = (float)np_data->compression_multiplier;
18308     }
18309     return(TNG_SUCCESS);
18310 }
18311
18312 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
18313                 (tng_trajectory_t tng_data,
18314                  int64_t current_frame,
18315                  const int64_t n_requested_data_block_ids,
18316                  const int64_t *requested_data_block_ids,
18317                  int64_t *next_frame,
18318                  int64_t *n_data_blocks_in_next_frame,
18319                  int64_t **data_block_ids_in_next_frame)
18320 {
18321     tng_trajectory_frame_set_t frame_set;
18322     tng_function_status stat;
18323     tng_particle_data_t p_data;
18324     tng_non_particle_data_t np_data;
18325     tng_gen_block_t block;
18326     int64_t i, j, block_id, *temp;
18327     int64_t data_frame, frame_diff, min_diff;
18328     int64_t size, frame_set_file_pos;
18329     int found, read_all = 0;
18330     long file_pos;
18331
18332     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18333     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
18334     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
18335     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
18336
18337     if(n_requested_data_block_ids)
18338     {
18339         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.");
18340         size = sizeof(int64_t) * n_requested_data_block_ids;
18341         temp = realloc(*data_block_ids_in_next_frame, size);
18342         if(!temp)
18343         {
18344             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
18345                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
18346                     __FILE__, __LINE__);
18347             free(*data_block_ids_in_next_frame);
18348             *data_block_ids_in_next_frame = 0;
18349             return(TNG_CRITICAL);
18350         }
18351         *data_block_ids_in_next_frame = temp;
18352     }
18353
18354     frame_set = &tng_data->current_trajectory_frame_set;
18355
18356     current_frame += 1;
18357
18358     if(current_frame < frame_set->first_frame ||
18359        current_frame >= frame_set->first_frame + frame_set->n_frames)
18360     {
18361         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
18362         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
18363         if(stat != TNG_SUCCESS)
18364         {
18365             /* If the frame set search found the frame set after the starting
18366              * frame set there is a gap in the frame sets. So, even if the frame
18367              * was not found the next frame with data is still in the found
18368              * frame set. */
18369             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
18370                frame_set_file_pos)
18371             {
18372                 return(stat);
18373             }
18374             current_frame = frame_set->first_frame;
18375         }
18376     }
18377
18378     /* If no data blocks have been found in the frame set check what data blocks
18379      * are present. If they have already been found do not read them again. */
18380     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
18381     {
18382         file_pos = ftell(tng_data->input_file);
18383         /* Read all blocks until next frame set block */
18384         if(file_pos < tng_data->input_file_len)
18385         {
18386             tng_block_init(&block);
18387             stat = tng_block_header_read(tng_data, block);
18388             while(file_pos < tng_data->input_file_len &&
18389                 stat != TNG_CRITICAL &&
18390                 block->id != TNG_TRAJECTORY_FRAME_SET)
18391             {
18392                 stat = tng_block_read_next(tng_data, block,
18393                                         TNG_USE_HASH);
18394                 if(stat != TNG_CRITICAL)
18395                 {
18396                     file_pos = ftell(tng_data->input_file);
18397                     if(file_pos < tng_data->input_file_len)
18398                     {
18399                         stat = tng_block_header_read(tng_data, block);
18400                     }
18401                 }
18402             }
18403             tng_block_destroy(&block);
18404             if(stat == TNG_CRITICAL)
18405             {
18406                 fprintf(stderr, "TNG library: Cannot read block header at pos %ld. %s: %d\n",
18407                         file_pos, __FILE__, __LINE__);
18408                 return(stat);
18409             }
18410         }
18411         read_all = 1;
18412     }
18413
18414     min_diff = -1;
18415
18416     *n_data_blocks_in_next_frame = 0;
18417
18418     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
18419     {
18420         p_data = &frame_set->tr_particle_data[i];
18421         block_id = p_data->block_id;
18422
18423         if(n_requested_data_block_ids > 0)
18424         {
18425             found = 0;
18426             for(j = 0; j < n_requested_data_block_ids; j++)
18427             {
18428                 if(block_id == requested_data_block_ids[j])
18429                 {
18430                     found = 1;
18431                     break;
18432                 }
18433             }
18434             if(!found)
18435             {
18436                 continue;
18437             }
18438         }
18439
18440         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
18441            p_data->last_retrieved_frame >=
18442            frame_set->first_frame + frame_set->n_frames))
18443         {
18444             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
18445                                                                       TNG_USE_HASH, block_id);
18446             if(stat == TNG_CRITICAL)
18447             {
18448                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18449                     __FILE__, __LINE__);
18450                 return(stat);
18451             }
18452             if(stat == TNG_FAILURE)
18453             {
18454                 continue;
18455             }
18456         }
18457         if(frame_set->first_frame != current_frame &&
18458            p_data->last_retrieved_frame >= 0)
18459         {
18460             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
18461         }
18462         else
18463         {
18464             data_frame = p_data->first_frame_with_data;
18465         }
18466         frame_diff = data_frame - current_frame;
18467         if(frame_diff < 0)
18468         {
18469             continue;
18470         }
18471         if(min_diff == -1 || frame_diff <= min_diff)
18472         {
18473             if(frame_diff < min_diff)
18474             {
18475                 *n_data_blocks_in_next_frame = 1;
18476             }
18477             else
18478             {
18479                 *n_data_blocks_in_next_frame += 1;
18480             }
18481             if(n_requested_data_block_ids <= 0)
18482             {
18483                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
18484                 temp = realloc(*data_block_ids_in_next_frame, size);
18485                 if(!temp)
18486                 {
18487                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
18488                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
18489                            __FILE__, __LINE__);
18490                     free(*data_block_ids_in_next_frame);
18491                     *data_block_ids_in_next_frame = 0;
18492                     return(TNG_CRITICAL);
18493                 }
18494                 *data_block_ids_in_next_frame = temp;
18495             }
18496             else
18497             {
18498                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
18499             }
18500             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
18501
18502             min_diff = frame_diff;
18503         }
18504     }
18505     for(i = 0; i < frame_set->n_data_blocks; i++)
18506     {
18507         np_data = &frame_set->tr_data[i];
18508         block_id = np_data->block_id;
18509
18510         if(n_requested_data_block_ids > 0)
18511         {
18512             found = 0;
18513             for(j = 0; j < n_requested_data_block_ids; j++)
18514             {
18515                 if(block_id == requested_data_block_ids[j])
18516                 {
18517                     found = 1;
18518                     break;
18519                 }
18520             }
18521             if(!found)
18522             {
18523                 continue;
18524             }
18525         }
18526
18527         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
18528            np_data->last_retrieved_frame >=
18529            frame_set->first_frame + frame_set->n_frames))
18530         {
18531             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
18532                                                                       TNG_USE_HASH, block_id);
18533             if(stat == TNG_CRITICAL)
18534             {
18535                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
18536                     __FILE__, __LINE__);
18537                 return(stat);
18538             }
18539             if(stat == TNG_FAILURE)
18540             {
18541                 continue;
18542             }
18543         }
18544         if(frame_set->first_frame != current_frame &&
18545            np_data->last_retrieved_frame >= 0)
18546         {
18547             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
18548         }
18549         else
18550         {
18551             data_frame = np_data->first_frame_with_data;
18552         }
18553         frame_diff = data_frame - current_frame;
18554         if(frame_diff < 0)
18555         {
18556             continue;
18557         }
18558         if(min_diff == -1 || frame_diff <= min_diff)
18559         {
18560             if(frame_diff < min_diff)
18561             {
18562                 *n_data_blocks_in_next_frame = 1;
18563             }
18564             else
18565             {
18566                 *n_data_blocks_in_next_frame += 1;
18567             }
18568             if(n_requested_data_block_ids <= 0)
18569             {
18570                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
18571                 temp = realloc(*data_block_ids_in_next_frame, size);
18572                 if(!temp)
18573                 {
18574                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
18575                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
18576                            __FILE__, __LINE__);
18577                     free(*data_block_ids_in_next_frame);
18578                     *data_block_ids_in_next_frame = 0;
18579                     return(TNG_CRITICAL);
18580                 }
18581                 *data_block_ids_in_next_frame = temp;
18582             }
18583             else
18584             {
18585                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
18586             }
18587             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
18588
18589             min_diff = frame_diff;
18590         }
18591     }
18592     if(min_diff < 0)
18593     {
18594         return(TNG_FAILURE);
18595     }
18596     *next_frame = current_frame + min_diff;
18597
18598     return(TNG_SUCCESS);
18599 }
18600
18601 /*
18602 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
18603                 (tng_trajectory_t tng_data,
18604                  int64_t *n_data_blocks,
18605                  int64_t **data_block_ids,
18606                  char ***data_block_names,
18607                  int64_t **stride_lengths,
18608                  int64_t **n_values_per_frame,
18609                  char **block_types,
18610                  char **dependencies,
18611                  char **compressions)
18612 {
18613     tng_gen_block_t block;
18614     long orig_file_pos, file_pos;
18615
18616     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18617     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
18618     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
18619     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
18620     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
18621
18622     orig_file_pos = ftell(tng_data->input_file);
18623
18624     if(!tng_data->input_file_len)
18625     {
18626         fseek(tng_data->input_file, 0, SEEK_END);
18627         tng_data->input_file_len = ftell(tng_data->input_file);
18628     }
18629
18630     fseek(tng_data->input_file, 0, SEEK_SET);
18631     file_pos = 0;
18632
18633     *n_data_blocks = 0;
18634
18635     tng_block_init(&block);
18636
18637     while(file_pos < tng_data->input_file_len &&
18638           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
18639     {
18640         if(block->id > TNG_TRAJECTORY_FRAME_SET)
18641         {
18642
18643         }
18644         file_pos += (long)(block->block_contents_size + block->header_contents_size);
18645         fseek(tng_data->input_file, (long)block->block_contents_size, SEEK_CUR);
18646     }
18647
18648     fseek(tng_data->input_file, orig_file_pos, SEEK_SET);
18649
18650     return(TNG_SUCCESS);
18651 }
18652 */
18653 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
18654                 (tng_trajectory_t tng_data,
18655                  const int64_t prev_frame)
18656 {
18657     tng_function_status stat;
18658     FILE *temp = tng_data->input_file;
18659
18660     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18661     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
18662
18663     tng_data->input_file = tng_data->output_file;
18664
18665     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
18666     if(stat != TNG_SUCCESS)
18667     {
18668         return(stat);
18669     }
18670
18671     tng_data->current_trajectory_frame_set_output_file_pos =
18672     tng_data->current_trajectory_frame_set_input_file_pos;
18673
18674     tng_data->input_file = temp;
18675
18676     return(TNG_SUCCESS);
18677 }